From 2c109f21994a72e9b91c24c422e540b921e84f66 Mon Sep 17 00:00:00 2001 From: Mads Ynddal Date: Tue, 26 Sep 2023 12:34:23 +0200 Subject: [PATCH 0001/1077] simpletrace: add __all__ to define public interface It was unclear what was the supported public interface. I.e. when refactoring the code, what functions/classes are important to retain. Reviewed-by: Stefan Hajnoczi Signed-off-by: Mads Ynddal Message-id: 20230926103436.25700-2-mads@ynddal.dk Signed-off-by: Stefan Hajnoczi --- scripts/simpletrace.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/scripts/simpletrace.py b/scripts/simpletrace.py index 1f6d1ae1f3..b221d9a241 100755 --- a/scripts/simpletrace.py +++ b/scripts/simpletrace.py @@ -14,6 +14,8 @@ import inspect from tracetool import read_events, Event from tracetool.backend.simple import is_string +__all__ = ['Analyzer', 'process', 'run'] + header_event_id = 0xffffffffffffffff header_magic = 0xf2b177cb0aa429b4 dropped_event_id = 0xfffffffffffffffe From 8405ec6ab6a05b8c84f7be1130a7891d1a874624 Mon Sep 17 00:00:00 2001 From: Mads Ynddal Date: Tue, 26 Sep 2023 12:34:24 +0200 Subject: [PATCH 0002/1077] simpletrace: annotate magic constants from QEMU code It wasn't clear where the constants and structs came from, so I added comments to help. Reviewed-by: Stefan Hajnoczi Signed-off-by: Mads Ynddal Message-id: 20230926103436.25700-3-mads@ynddal.dk Signed-off-by: Stefan Hajnoczi --- scripts/simpletrace.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/scripts/simpletrace.py b/scripts/simpletrace.py index b221d9a241..5c230a1b74 100755 --- a/scripts/simpletrace.py +++ b/scripts/simpletrace.py @@ -16,6 +16,11 @@ from tracetool.backend.simple import is_string __all__ = ['Analyzer', 'process', 'run'] +# This is the binary format that the QEMU "simple" trace backend +# emits. There is no specification documentation because the format is +# not guaranteed to be stable. Trace files must be parsed with the +# same trace-events-all file and the same simpletrace.py file that +# QEMU was built with. header_event_id = 0xffffffffffffffff header_magic = 0xf2b177cb0aa429b4 dropped_event_id = 0xfffffffffffffffe From f7bd4f0237ec394198940f5b81cbde280c5b5c01 Mon Sep 17 00:00:00 2001 From: Mads Ynddal Date: Tue, 26 Sep 2023 12:34:25 +0200 Subject: [PATCH 0003/1077] simpletrace: improve parsing of sys.argv; fix files never closed. The arguments extracted from `sys.argv` named and unpacked to make it clear what the arguments are and what they're used for. The two input files were opened, but never explicitly closed. File usage changed to use `with` statement to take care of this. At the same time, ownership of the file-object is moved up to `run` function. Added option to process to support file-like objects. Reviewed-by: Stefan Hajnoczi Signed-off-by: Mads Ynddal Message-id: 20230926103436.25700-4-mads@ynddal.dk Signed-off-by: Stefan Hajnoczi --- scripts/simpletrace.py | 48 +++++++++++++++++++++++++++++------------- 1 file changed, 33 insertions(+), 15 deletions(-) diff --git a/scripts/simpletrace.py b/scripts/simpletrace.py index 5c230a1b74..283b5918a1 100755 --- a/scripts/simpletrace.py +++ b/scripts/simpletrace.py @@ -9,6 +9,7 @@ # # For help see docs/devel/tracing.rst +import sys import struct import inspect from tracetool import read_events, Event @@ -51,7 +52,6 @@ def get_record(edict, idtoname, rechdr, fobj): try: event = edict[name] except KeyError as e: - import sys sys.stderr.write('%s event is logged but is not declared ' \ 'in the trace events file, try using ' \ 'trace-events-all instead.\n' % str(e)) @@ -172,11 +172,28 @@ class Analyzer(object): pass def process(events, log, analyzer, read_header=True): - """Invoke an analyzer on each event in a log.""" + """Invoke an analyzer on each event in a log. + Args: + events (file-object or list or str): events list or file-like object or file path as str to read event data from + log (file-object or str): file-like object or file path as str to read log data from + analyzer (Analyzer): Instance of Analyzer to interpret the event data + read_header (bool, optional): Whether to read header data from the log data. Defaults to True. + """ + if isinstance(events, str): - events = read_events(open(events, 'r'), events) + with open(events, 'r') as f: + events_list = read_events(f, events) + elif isinstance(events, list): + # Treat as a list of events already produced by tracetool.read_events + events_list = events + else: + # Treat as an already opened file-object + events_list = read_events(events, events.name) + + close_log = False if isinstance(log, str): log = open(log, 'rb') + close_log = True if read_header: read_trace_header(log) @@ -187,12 +204,12 @@ def process(events, log, analyzer, read_header=True): edict = {"dropped": dropped_event} idtoname = {dropped_event_id: "dropped"} - for event in events: + for event in events_list: edict[event.name] = event # If there is no header assume event ID mapping matches events list if not read_header: - for event_id, event in enumerate(events): + for event_id, event in enumerate(events_list): idtoname[event_id] = event.name def build_fn(analyzer, event): @@ -225,24 +242,25 @@ def process(events, log, analyzer, read_header=True): fn_cache[event_num](event, rec) analyzer.end() + if close_log: + log.close() + def run(analyzer): """Execute an analyzer on a trace file given on the command-line. This function is useful as a driver for simple analysis scripts. More advanced scripts will want to call process() instead.""" - import sys - read_header = True - if len(sys.argv) == 4 and sys.argv[1] == '--no-header': - read_header = False - del sys.argv[1] - elif len(sys.argv) != 3: - sys.stderr.write('usage: %s [--no-header] ' \ - '\n' % sys.argv[0]) + try: + # NOTE: See built-in `argparse` module for a more robust cli interface + *no_header, trace_event_path, trace_file_path = sys.argv[1:] + assert no_header == [] or no_header == ['--no-header'], 'Invalid no-header argument' + except (AssertionError, ValueError): + sys.stderr.write(f'usage: {sys.argv[0]} [--no-header] \n') sys.exit(1) - events = read_events(open(sys.argv[1], 'r'), sys.argv[1]) - process(events, sys.argv[2], analyzer, read_header=read_header) + with open(trace_event_path, 'r') as events_fobj, open(trace_file_path, 'rb') as log_fobj: + process(events_fobj, log_fobj, analyzer, read_header=not no_header) if __name__ == '__main__': class Formatter(Analyzer): From 3b71b61e9f50cad73958a87216dba7b22b851318 Mon Sep 17 00:00:00 2001 From: Mads Ynddal Date: Tue, 26 Sep 2023 12:34:26 +0200 Subject: [PATCH 0004/1077] simpletrace: changed naming of edict and idtoname to improve readability MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Readability is subjective, but I've expanded the naming of the variables and arguments, to help with understanding for new eyes on the code. Signed-off-by: Mads Ynddal Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Stefan Hajnoczi Message-id: 20230926103436.25700-5-mads@ynddal.dk Signed-off-by: Stefan Hajnoczi --- scripts/simpletrace.py | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/scripts/simpletrace.py b/scripts/simpletrace.py index 283b5918a1..09511f624d 100755 --- a/scripts/simpletrace.py +++ b/scripts/simpletrace.py @@ -40,17 +40,17 @@ def read_header(fobj, hfmt): return None return struct.unpack(hfmt, hdr) -def get_record(edict, idtoname, rechdr, fobj): +def get_record(event_mapping, event_id_to_name, rechdr, fobj): """Deserialize a trace record from a file into a tuple (name, timestamp, pid, arg1, ..., arg6).""" if rechdr is None: return None if rechdr[0] != dropped_event_id: event_id = rechdr[0] - name = idtoname[event_id] + name = event_id_to_name[event_id] rec = (name, rechdr[1], rechdr[3]) try: - event = edict[name] + event = event_mapping[name] except KeyError as e: sys.stderr.write('%s event is logged but is not declared ' \ 'in the trace events file, try using ' \ @@ -79,10 +79,10 @@ def get_mapping(fobj): return (event_id, name) -def read_record(edict, idtoname, fobj): +def read_record(event_mapping, event_id_to_name, fobj): """Deserialize a trace record from a file into a tuple (event_num, timestamp, pid, arg1, ..., arg6).""" rechdr = read_header(fobj, rec_header_fmt) - return get_record(edict, idtoname, rechdr, fobj) + return get_record(event_mapping, event_id_to_name, rechdr, fobj) def read_trace_header(fobj): """Read and verify trace file header""" @@ -103,14 +103,14 @@ def read_trace_header(fobj): raise ValueError('Log format %d not supported with this QEMU release!' % log_version) -def read_trace_records(edict, idtoname, fobj): +def read_trace_records(event_mapping, event_id_to_name, fobj): """Deserialize trace records from a file, yielding record tuples (event_num, timestamp, pid, arg1, ..., arg6). - Note that `idtoname` is modified if the file contains mapping records. + Note that `event_id_to_name` is modified if the file contains mapping records. Args: - edict (str -> Event): events dict, indexed by name - idtoname (int -> str): event names dict, indexed by event ID + event_mapping (str -> Event): events dict, indexed by name + event_id_to_name (int -> str): event names dict, indexed by event ID fobj (file): input file """ @@ -122,9 +122,9 @@ def read_trace_records(edict, idtoname, fobj): (rectype, ) = struct.unpack('=Q', t) if rectype == record_type_mapping: event_id, name = get_mapping(fobj) - idtoname[event_id] = name + event_id_to_name[event_id] = name else: - rec = read_record(edict, idtoname, fobj) + rec = read_record(event_mapping, event_id_to_name, fobj) yield rec @@ -201,16 +201,16 @@ def process(events, log, analyzer, read_header=True): frameinfo = inspect.getframeinfo(inspect.currentframe()) dropped_event = Event.build("Dropped_Event(uint64_t num_events_dropped)", frameinfo.lineno + 1, frameinfo.filename) - edict = {"dropped": dropped_event} - idtoname = {dropped_event_id: "dropped"} + event_mapping = {"dropped": dropped_event} + event_id_to_name = {dropped_event_id: "dropped"} for event in events_list: - edict[event.name] = event + event_mapping[event.name] = event # If there is no header assume event ID mapping matches events list if not read_header: for event_id, event in enumerate(events_list): - idtoname[event_id] = event.name + event_id_to_name[event_id] = event.name def build_fn(analyzer, event): if isinstance(event, str): @@ -234,9 +234,9 @@ def process(events, log, analyzer, read_header=True): analyzer.begin() fn_cache = {} - for rec in read_trace_records(edict, idtoname, log): + for rec in read_trace_records(event_mapping, event_id_to_name, log): event_num = rec[0] - event = edict[event_num] + event = event_mapping[event_num] if event_num not in fn_cache: fn_cache[event_num] = build_fn(analyzer, event) fn_cache[event_num](event, rec) From ce96eb334dc0a3a7f570f422e8a578495f34e4f2 Mon Sep 17 00:00:00 2001 From: Mads Ynddal Date: Tue, 26 Sep 2023 12:34:27 +0200 Subject: [PATCH 0005/1077] simpletrace: update code for Python 3.11 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The call to `getargspec` was deprecated and in Python 3.11 it has been removed in favor of `getfullargspec`. `getfullargspec` is compatible with QEMU's requirement of at least Python version 3.6. Reviewed-by: Stefan Hajnoczi Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Mads Ynddal Message-id: 20230926103436.25700-6-mads@ynddal.dk Signed-off-by: Stefan Hajnoczi --- scripts/simpletrace.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/simpletrace.py b/scripts/simpletrace.py index 09511f624d..971b2a0f6a 100755 --- a/scripts/simpletrace.py +++ b/scripts/simpletrace.py @@ -221,7 +221,7 @@ def process(events, log, analyzer, read_header=True): return analyzer.catchall event_argcount = len(event.args) - fn_argcount = len(inspect.getargspec(fn)[0]) - 1 + fn_argcount = len(inspect.getfullargspec(fn)[0]) - 1 if fn_argcount == event_argcount + 1: # Include timestamp as first argument return lambda _, rec: fn(*(rec[1:2] + rec[3:3 + event_argcount])) From d1f9259014317baa3bce7db7d4c2e927341e3cae Mon Sep 17 00:00:00 2001 From: Mads Ynddal Date: Tue, 26 Sep 2023 12:34:28 +0200 Subject: [PATCH 0006/1077] simpletrace: improved error handling on struct unpack MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit A failed call to `read_header` wouldn't be handled the same for the two different code paths (one path would try to use `None` as a list). Changed to raise exception to be handled centrally. This also allows for easier unpacking, as errors has been filtered out. Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Stefan Hajnoczi Signed-off-by: Mads Ynddal Message-id: 20230926103436.25700-7-mads@ynddal.dk Signed-off-by: Stefan Hajnoczi --- scripts/simpletrace.py | 39 +++++++++++++++------------------------ 1 file changed, 15 insertions(+), 24 deletions(-) diff --git a/scripts/simpletrace.py b/scripts/simpletrace.py index 971b2a0f6a..8aea0d169b 100755 --- a/scripts/simpletrace.py +++ b/scripts/simpletrace.py @@ -37,26 +37,24 @@ def read_header(fobj, hfmt): hlen = struct.calcsize(hfmt) hdr = fobj.read(hlen) if len(hdr) != hlen: - return None + raise ValueError('Error reading header. Wrong filetype provided?') return struct.unpack(hfmt, hdr) def get_record(event_mapping, event_id_to_name, rechdr, fobj): """Deserialize a trace record from a file into a tuple (name, timestamp, pid, arg1, ..., arg6).""" - if rechdr is None: - return None - if rechdr[0] != dropped_event_id: - event_id = rechdr[0] + event_id, timestamp_ns, length, pid = rechdr + if event_id != dropped_event_id: name = event_id_to_name[event_id] - rec = (name, rechdr[1], rechdr[3]) try: event = event_mapping[name] except KeyError as e: - sys.stderr.write('%s event is logged but is not declared ' \ + sys.stderr.write(f'{e} event is logged but is not declared ' \ 'in the trace events file, try using ' \ - 'trace-events-all instead.\n' % str(e)) + 'trace-events-all instead.\n') sys.exit(1) + rec = (name, timestamp_ns, pid) for type, name in event.args: if is_string(type): l = fobj.read(4) @@ -67,9 +65,8 @@ def get_record(event_mapping, event_id_to_name, rechdr, fobj): (value,) = struct.unpack('=Q', fobj.read(8)) rec = rec + (value,) else: - rec = ("dropped", rechdr[1], rechdr[3]) - (value,) = struct.unpack('=Q', fobj.read(8)) - rec = rec + (value,) + (dropped_count,) = struct.unpack('=Q', fobj.read(8)) + rec = ("dropped", timestamp_ns, pid, dropped_count) return rec def get_mapping(fobj): @@ -86,22 +83,16 @@ def read_record(event_mapping, event_id_to_name, fobj): def read_trace_header(fobj): """Read and verify trace file header""" - header = read_header(fobj, log_header_fmt) - if header is None: - raise ValueError('Not a valid trace file!') - if header[0] != header_event_id: - raise ValueError('Not a valid trace file, header id %d != %d' % - (header[0], header_event_id)) - if header[1] != header_magic: - raise ValueError('Not a valid trace file, header magic %d != %d' % - (header[1], header_magic)) + _header_event_id, _header_magic, log_version = read_header(fobj, log_header_fmt) + if _header_event_id != header_event_id: + raise ValueError(f'Not a valid trace file, header id {_header_event_id} != {header_event_id}') + if _header_magic != header_magic: + raise ValueError(f'Not a valid trace file, header magic {_header_magic} != {header_magic}') - log_version = header[2] if log_version not in [0, 2, 3, 4]: - raise ValueError('Unknown version of tracelog format!') + raise ValueError(f'Unknown version {log_version} of tracelog format!') if log_version != 4: - raise ValueError('Log format %d not supported with this QEMU release!' - % log_version) + raise ValueError(f'Log format {log_version} not supported with this QEMU release!') def read_trace_records(event_mapping, event_id_to_name, fobj): """Deserialize trace records from a file, yielding record tuples (event_num, timestamp, pid, arg1, ..., arg6). From 1990fb98934d8e114ac73b0ca649bf4820ca896a Mon Sep 17 00:00:00 2001 From: Mads Ynddal Date: Tue, 26 Sep 2023 12:34:29 +0200 Subject: [PATCH 0007/1077] simpletrace: define exception and add handling MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Define `SimpleException` to differentiate our exceptions from generic exceptions (IOError, etc.). Adapted simpletrace to support this and output to stderr. Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Stefan Hajnoczi Signed-off-by: Mads Ynddal Message-id: 20230926103436.25700-8-mads@ynddal.dk Signed-off-by: Stefan Hajnoczi --- scripts/simpletrace.py | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/scripts/simpletrace.py b/scripts/simpletrace.py index 8aea0d169b..229b10aa99 100755 --- a/scripts/simpletrace.py +++ b/scripts/simpletrace.py @@ -32,12 +32,15 @@ record_type_event = 1 log_header_fmt = '=QQQ' rec_header_fmt = '=QQII' +class SimpleException(Exception): + pass + def read_header(fobj, hfmt): '''Read a trace record header''' hlen = struct.calcsize(hfmt) hdr = fobj.read(hlen) if len(hdr) != hlen: - raise ValueError('Error reading header. Wrong filetype provided?') + raise SimpleException('Error reading header. Wrong filetype provided?') return struct.unpack(hfmt, hdr) def get_record(event_mapping, event_id_to_name, rechdr, fobj): @@ -49,10 +52,10 @@ def get_record(event_mapping, event_id_to_name, rechdr, fobj): try: event = event_mapping[name] except KeyError as e: - sys.stderr.write(f'{e} event is logged but is not declared ' \ - 'in the trace events file, try using ' \ - 'trace-events-all instead.\n') - sys.exit(1) + raise SimpleException( + f'{e} event is logged but is not declared in the trace events' + 'file, try using trace-events-all instead.' + ) rec = (name, timestamp_ns, pid) for type, name in event.args: @@ -247,8 +250,7 @@ def run(analyzer): *no_header, trace_event_path, trace_file_path = sys.argv[1:] assert no_header == [] or no_header == ['--no-header'], 'Invalid no-header argument' except (AssertionError, ValueError): - sys.stderr.write(f'usage: {sys.argv[0]} [--no-header] \n') - sys.exit(1) + raise SimpleException(f'usage: {sys.argv[0]} [--no-header] \n') with open(trace_event_path, 'r') as events_fobj, open(trace_file_path, 'rb') as log_fobj: process(events_fobj, log_fobj, analyzer, read_header=not no_header) @@ -276,4 +278,8 @@ if __name__ == '__main__': i += 1 print(' '.join(fields)) - run(Formatter()) + try: + run(Formatter()) + except SimpleException as e: + sys.stderr.write(str(e) + "\n") + sys.exit(1) From 87617b9ae63c4675460244d067e246b362dc3867 Mon Sep 17 00:00:00 2001 From: Mads Ynddal Date: Tue, 26 Sep 2023 12:34:30 +0200 Subject: [PATCH 0008/1077] simpletrace: made Analyzer into context-manager Instead of explicitly calling `begin` and `end`, we can change the class to use the context-manager paradigm. This is mostly a styling choice, used in modern Python code. But it also allows for more advanced analyzers to handle exceptions gracefully in the `__exit__` method (not demonstrated here). Reviewed-by: Stefan Hajnoczi Signed-off-by: Mads Ynddal Message-id: 20230926103436.25700-9-mads@ynddal.dk Signed-off-by: Stefan Hajnoczi --- scripts/simpletrace.py | 31 ++++++++++++++++++++----------- 1 file changed, 20 insertions(+), 11 deletions(-) diff --git a/scripts/simpletrace.py b/scripts/simpletrace.py index 229b10aa99..7f514d1577 100755 --- a/scripts/simpletrace.py +++ b/scripts/simpletrace.py @@ -122,12 +122,13 @@ def read_trace_records(event_mapping, event_id_to_name, fobj): yield rec -class Analyzer(object): +class Analyzer: """A trace file analyzer which processes trace records. An analyzer can be passed to run() or process(). The begin() method is invoked, then each trace record is processed, and finally the end() method - is invoked. + is invoked. When Analyzer is used as a context-manager (using the `with` + statement), begin() and end() are called automatically. If a method matching a trace event name exists, it is invoked to process that trace record. Otherwise the catchall() method is invoked. @@ -165,6 +166,15 @@ class Analyzer(object): """Called at the end of the trace.""" pass + def __enter__(self): + self.begin() + return self + + def __exit__(self, exc_type, exc_val, exc_tb): + if exc_type is None: + self.end() + return False + def process(events, log, analyzer, read_header=True): """Invoke an analyzer on each event in a log. Args: @@ -226,15 +236,14 @@ def process(events, log, analyzer, read_header=True): # Just arguments, no timestamp or pid return lambda _, rec: fn(*rec[3:3 + event_argcount]) - analyzer.begin() - fn_cache = {} - for rec in read_trace_records(event_mapping, event_id_to_name, log): - event_num = rec[0] - event = event_mapping[event_num] - if event_num not in fn_cache: - fn_cache[event_num] = build_fn(analyzer, event) - fn_cache[event_num](event, rec) - analyzer.end() + with analyzer: + fn_cache = {} + for rec in read_trace_records(event_mapping, event_id_to_name, log): + event_num = rec[0] + event = event_mapping[event_num] + if event_num not in fn_cache: + fn_cache[event_num] = build_fn(analyzer, event) + fn_cache[event_num](event, rec) if close_log: log.close() From 6f53641a980df2d1b38503b10bfda9236fa075b4 Mon Sep 17 00:00:00 2001 From: Mads Ynddal Date: Tue, 26 Sep 2023 12:34:31 +0200 Subject: [PATCH 0009/1077] simpletrace: refactor to separate responsibilities Moved event_mapping and event_id_to_name down one level in the function call-stack to keep variable instantiation and usage closer (`process` and `run` has no use of the variables; `read_trace_records` does). Instead of passing event_mapping and event_id_to_name to the bottom of the call-stack, we move their use to `read_trace_records`. This separates responsibility and ownership of the information. `read_record` now just reads the arguments from the file-object by knowning the total number of bytes. Parsing it to specific arguments is moved up to `read_trace_records`. Special handling of dropped events removed, as they can be handled by the general code. Reviewed-by: Stefan Hajnoczi Signed-off-by: Mads Ynddal Message-id: 20230926103436.25700-10-mads@ynddal.dk Signed-off-by: Stefan Hajnoczi --- scripts/simpletrace.py | 115 +++++++++++++++++++---------------------- 1 file changed, 53 insertions(+), 62 deletions(-) diff --git a/scripts/simpletrace.py b/scripts/simpletrace.py index 7f514d1577..0826aef283 100755 --- a/scripts/simpletrace.py +++ b/scripts/simpletrace.py @@ -31,6 +31,7 @@ record_type_event = 1 log_header_fmt = '=QQQ' rec_header_fmt = '=QQII' +rec_header_fmt_len = struct.calcsize(rec_header_fmt) class SimpleException(Exception): pass @@ -43,35 +44,6 @@ def read_header(fobj, hfmt): raise SimpleException('Error reading header. Wrong filetype provided?') return struct.unpack(hfmt, hdr) -def get_record(event_mapping, event_id_to_name, rechdr, fobj): - """Deserialize a trace record from a file into a tuple - (name, timestamp, pid, arg1, ..., arg6).""" - event_id, timestamp_ns, length, pid = rechdr - if event_id != dropped_event_id: - name = event_id_to_name[event_id] - try: - event = event_mapping[name] - except KeyError as e: - raise SimpleException( - f'{e} event is logged but is not declared in the trace events' - 'file, try using trace-events-all instead.' - ) - - rec = (name, timestamp_ns, pid) - for type, name in event.args: - if is_string(type): - l = fobj.read(4) - (len,) = struct.unpack('=L', l) - s = fobj.read(len) - rec = rec + (s,) - else: - (value,) = struct.unpack('=Q', fobj.read(8)) - rec = rec + (value,) - else: - (dropped_count,) = struct.unpack('=Q', fobj.read(8)) - rec = ("dropped", timestamp_ns, pid, dropped_count) - return rec - def get_mapping(fobj): (event_id, ) = struct.unpack('=Q', fobj.read(8)) (len, ) = struct.unpack('=L', fobj.read(4)) @@ -79,10 +51,11 @@ def get_mapping(fobj): return (event_id, name) -def read_record(event_mapping, event_id_to_name, fobj): - """Deserialize a trace record from a file into a tuple (event_num, timestamp, pid, arg1, ..., arg6).""" - rechdr = read_header(fobj, rec_header_fmt) - return get_record(event_mapping, event_id_to_name, rechdr, fobj) +def read_record(fobj): + """Deserialize a trace record from a file into a tuple (event_num, timestamp, pid, args).""" + event_id, timestamp_ns, record_length, record_pid = read_header(fobj, rec_header_fmt) + args_payload = fobj.read(record_length - rec_header_fmt_len) + return (event_id, timestamp_ns, record_pid, args_payload) def read_trace_header(fobj): """Read and verify trace file header""" @@ -97,17 +70,28 @@ def read_trace_header(fobj): if log_version != 4: raise ValueError(f'Log format {log_version} not supported with this QEMU release!') -def read_trace_records(event_mapping, event_id_to_name, fobj): - """Deserialize trace records from a file, yielding record tuples (event_num, timestamp, pid, arg1, ..., arg6). - - Note that `event_id_to_name` is modified if the file contains mapping records. +def read_trace_records(events, fobj, read_header): + """Deserialize trace records from a file, yielding record tuples (event, event_num, timestamp, pid, arg1, ..., arg6). Args: event_mapping (str -> Event): events dict, indexed by name - event_id_to_name (int -> str): event names dict, indexed by event ID fobj (file): input file + read_header (bool): whether headers were read from fobj """ + frameinfo = inspect.getframeinfo(inspect.currentframe()) + dropped_event = Event.build("Dropped_Event(uint64_t num_events_dropped)", + frameinfo.lineno + 1, frameinfo.filename) + + event_mapping = {e.name: e for e in events} + event_mapping["dropped"] = dropped_event + event_id_to_name = {dropped_event_id: "dropped"} + + # If there is no header assume event ID mapping matches events list + if not read_header: + for event_id, event in enumerate(events): + event_id_to_name[event_id] = event.name + while True: t = fobj.read(8) if len(t) == 0: @@ -115,12 +99,35 @@ def read_trace_records(event_mapping, event_id_to_name, fobj): (rectype, ) = struct.unpack('=Q', t) if rectype == record_type_mapping: - event_id, name = get_mapping(fobj) - event_id_to_name[event_id] = name + event_id, event_name = get_mapping(fobj) + event_id_to_name[event_id] = event_name else: - rec = read_record(event_mapping, event_id_to_name, fobj) + event_id, timestamp_ns, pid, args_payload = read_record(fobj) + event_name = event_id_to_name[event_id] - yield rec + try: + event = event_mapping[event_name] + except KeyError as e: + raise SimpleException( + f'{e} event is logged but is not declared in the trace events' + 'file, try using trace-events-all instead.' + ) + + offset = 0 + args = [] + for type, _ in event.args: + if is_string(type): + (length,) = struct.unpack_from('=L', args_payload, offset=offset) + offset += 4 + s = args_payload[offset:offset+length] + offset += length + args.append(s) + else: + (value,) = struct.unpack_from('=Q', args_payload, offset=offset) + offset += 8 + args.append(value) + + yield (event_mapping[event_name], event_name, timestamp_ns, pid) + tuple(args) class Analyzer: """A trace file analyzer which processes trace records. @@ -202,20 +209,6 @@ def process(events, log, analyzer, read_header=True): if read_header: read_trace_header(log) - frameinfo = inspect.getframeinfo(inspect.currentframe()) - dropped_event = Event.build("Dropped_Event(uint64_t num_events_dropped)", - frameinfo.lineno + 1, frameinfo.filename) - event_mapping = {"dropped": dropped_event} - event_id_to_name = {dropped_event_id: "dropped"} - - for event in events_list: - event_mapping[event.name] = event - - # If there is no header assume event ID mapping matches events list - if not read_header: - for event_id, event in enumerate(events_list): - event_id_to_name[event_id] = event.name - def build_fn(analyzer, event): if isinstance(event, str): return analyzer.catchall @@ -238,12 +231,10 @@ def process(events, log, analyzer, read_header=True): with analyzer: fn_cache = {} - for rec in read_trace_records(event_mapping, event_id_to_name, log): - event_num = rec[0] - event = event_mapping[event_num] - if event_num not in fn_cache: - fn_cache[event_num] = build_fn(analyzer, event) - fn_cache[event_num](event, rec) + for event, event_id, timestamp_ns, record_pid, *rec_args in read_trace_records(events, log, read_header): + if event_id not in fn_cache: + fn_cache[event_id] = build_fn(analyzer, event) + fn_cache[event_id](event, (event_id, timestamp_ns, record_pid, *rec_args)) if close_log: log.close() From b78234e65cad8c4899a2cfcc5e5cd8d33fce1b95 Mon Sep 17 00:00:00 2001 From: Mads Ynddal Date: Tue, 26 Sep 2023 12:34:32 +0200 Subject: [PATCH 0010/1077] simpletrace: move logic of process into internal function To avoid duplicate code depending on input types and to better handle open/close of log with a context-manager, we move the logic of process into _process. Reviewed-by: Stefan Hajnoczi Signed-off-by: Mads Ynddal Message-id: 20230926103436.25700-11-mads@ynddal.dk Signed-off-by: Stefan Hajnoczi --- scripts/simpletrace.py | 26 ++++++++++++++++++-------- 1 file changed, 18 insertions(+), 8 deletions(-) diff --git a/scripts/simpletrace.py b/scripts/simpletrace.py index 0826aef283..6969fdd59a 100755 --- a/scripts/simpletrace.py +++ b/scripts/simpletrace.py @@ -201,13 +201,26 @@ def process(events, log, analyzer, read_header=True): # Treat as an already opened file-object events_list = read_events(events, events.name) - close_log = False if isinstance(log, str): - log = open(log, 'rb') - close_log = True + with open(log, 'rb') as log_fobj: + _process(events_list, log_fobj, analyzer, read_header) + else: + # Treat `log` as an already opened file-object. We will not close it, + # as we do not own it. + _process(events_list, log, analyzer, read_header) + +def _process(events, log_fobj, analyzer, read_header=True): + """Internal function for processing + + Args: + events (list): list of events already produced by tracetool.read_events + log_fobj (file): file-object to read log data from + analyzer (Analyzer): the Analyzer to interpret the event data + read_header (bool, optional): Whether to read header data from the log data. Defaults to True. + """ if read_header: - read_trace_header(log) + read_trace_header(log_fobj) def build_fn(analyzer, event): if isinstance(event, str): @@ -231,14 +244,11 @@ def process(events, log, analyzer, read_header=True): with analyzer: fn_cache = {} - for event, event_id, timestamp_ns, record_pid, *rec_args in read_trace_records(events, log, read_header): + for event, event_id, timestamp_ns, record_pid, *rec_args in read_trace_records(events, log_fobj, read_header): if event_id not in fn_cache: fn_cache[event_id] = build_fn(analyzer, event) fn_cache[event_id](event, (event_id, timestamp_ns, record_pid, *rec_args)) - if close_log: - log.close() - def run(analyzer): """Execute an analyzer on a trace file given on the command-line. From d1f89c23bd93e40e180d4fc727e691a698a6d522 Mon Sep 17 00:00:00 2001 From: Mads Ynddal Date: Tue, 26 Sep 2023 12:34:33 +0200 Subject: [PATCH 0011/1077] simpletrace: move event processing to Analyzer class MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Moved event processing to the Analyzer class to separate specific analyzer logic (like caching and function signatures) from the _process function. This allows for new types of Analyzer-based subclasses without changing the core code. Note, that the fn_cache is important for performance in cases where the analyzer is branching away from the catch-all a lot. The cache has no measurable performance penalty. Reviewed-by: Stefan Hajnoczi Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Mads Ynddal Message-id: 20230926103436.25700-12-mads@ynddal.dk Signed-off-by: Stefan Hajnoczi --- scripts/simpletrace.py | 60 +++++++++++++++++++++++++----------------- 1 file changed, 36 insertions(+), 24 deletions(-) diff --git a/scripts/simpletrace.py b/scripts/simpletrace.py index 6969fdd59a..4136d00600 100755 --- a/scripts/simpletrace.py +++ b/scripts/simpletrace.py @@ -169,6 +169,35 @@ class Analyzer: """Called if no specific method for processing a trace event has been found.""" pass + def _build_fn(self, event): + fn = getattr(self, event.name, None) + if fn is None: + # Return early to avoid costly call to inspect.getfullargspec + return self.catchall + + event_argcount = len(event.args) + fn_argcount = len(inspect.getfullargspec(fn)[0]) - 1 + if fn_argcount == event_argcount + 1: + # Include timestamp as first argument + return lambda _, rec: fn(*(rec[1:2] + rec[3:3 + event_argcount])) + elif fn_argcount == event_argcount + 2: + # Include timestamp and pid + return lambda _, rec: fn(*rec[1:3 + event_argcount]) + else: + # Just arguments, no timestamp or pid + return lambda _, rec: fn(*rec[3:3 + event_argcount]) + + def _process_event(self, rec_args, *, event, event_id, timestamp_ns, pid, **kwargs): + if not hasattr(self, '_fn_cache'): + # NOTE: Cannot depend on downstream subclasses to have + # super().__init__() because of legacy. + self._fn_cache = {} + + rec = (event_id, timestamp_ns, pid, *rec_args) + if event_id not in self._fn_cache: + self._fn_cache[event_id] = self._build_fn(event) + self._fn_cache[event_id](event, rec) + def end(self): """Called at the end of the trace.""" pass @@ -222,32 +251,15 @@ def _process(events, log_fobj, analyzer, read_header=True): if read_header: read_trace_header(log_fobj) - def build_fn(analyzer, event): - if isinstance(event, str): - return analyzer.catchall - - fn = getattr(analyzer, event.name, None) - if fn is None: - return analyzer.catchall - - event_argcount = len(event.args) - fn_argcount = len(inspect.getfullargspec(fn)[0]) - 1 - if fn_argcount == event_argcount + 1: - # Include timestamp as first argument - return lambda _, rec: fn(*(rec[1:2] + rec[3:3 + event_argcount])) - elif fn_argcount == event_argcount + 2: - # Include timestamp and pid - return lambda _, rec: fn(*rec[1:3 + event_argcount]) - else: - # Just arguments, no timestamp or pid - return lambda _, rec: fn(*rec[3:3 + event_argcount]) - with analyzer: - fn_cache = {} for event, event_id, timestamp_ns, record_pid, *rec_args in read_trace_records(events, log_fobj, read_header): - if event_id not in fn_cache: - fn_cache[event_id] = build_fn(analyzer, event) - fn_cache[event_id](event, (event_id, timestamp_ns, record_pid, *rec_args)) + analyzer._process_event( + rec_args, + event=event, + event_id=event_id, + timestamp_ns=timestamp_ns, + pid=record_pid, + ) def run(analyzer): """Execute an analyzer on a trace file given on the command-line. From 3470fef15a7bff730b00633346d28b889027a609 Mon Sep 17 00:00:00 2001 From: Mads Ynddal Date: Tue, 26 Sep 2023 12:34:34 +0200 Subject: [PATCH 0012/1077] simpletrace: added simplified Analyzer2 class By moving the dynamic argument construction to keyword-arguments, we can remove all of the specialized handling, and streamline it. If a tracing method wants to access these, they can define the kwargs, or ignore it be placing `**kwargs` at the end of the function's arguments list. Added deprecation warning to Analyzer class to make users aware of the Analyzer2 class. No removal date is planned. Signed-off-by: Mads Ynddal Message-id: 20230926103436.25700-13-mads@ynddal.dk Signed-off-by: Stefan Hajnoczi --- scripts/simpletrace.py | 94 ++++++++++++++++++++++++++++++++---------- 1 file changed, 73 insertions(+), 21 deletions(-) diff --git a/scripts/simpletrace.py b/scripts/simpletrace.py index 4136d00600..cef81b0707 100755 --- a/scripts/simpletrace.py +++ b/scripts/simpletrace.py @@ -12,10 +12,11 @@ import sys import struct import inspect +import warnings from tracetool import read_events, Event from tracetool.backend.simple import is_string -__all__ = ['Analyzer', 'process', 'run'] +__all__ = ['Analyzer', 'Analyzer2', 'process', 'run'] # This is the binary format that the QEMU "simple" trace backend # emits. There is no specification documentation because the format is @@ -130,7 +131,9 @@ def read_trace_records(events, fobj, read_header): yield (event_mapping[event_name], event_name, timestamp_ns, pid) + tuple(args) class Analyzer: - """A trace file analyzer which processes trace records. + """[Deprecated. Refer to Analyzer2 instead.] + + A trace file analyzer which processes trace records. An analyzer can be passed to run() or process(). The begin() method is invoked, then each trace record is processed, and finally the end() method @@ -188,6 +191,11 @@ class Analyzer: return lambda _, rec: fn(*rec[3:3 + event_argcount]) def _process_event(self, rec_args, *, event, event_id, timestamp_ns, pid, **kwargs): + warnings.warn( + "Use of deprecated Analyzer class. Refer to Analyzer2 instead.", + DeprecationWarning, + ) + if not hasattr(self, '_fn_cache'): # NOTE: Cannot depend on downstream subclasses to have # super().__init__() because of legacy. @@ -211,6 +219,56 @@ class Analyzer: self.end() return False +class Analyzer2(Analyzer): + """A trace file analyzer which processes trace records. + + An analyzer can be passed to run() or process(). The begin() method is + invoked, then each trace record is processed, and finally the end() method + is invoked. When Analyzer is used as a context-manager (using the `with` + statement), begin() and end() are called automatically. + + If a method matching a trace event name exists, it is invoked to process + that trace record. Otherwise the catchall() method is invoked. + + The methods are called with a set of keyword-arguments. These can be ignored + using `**kwargs` or defined like any keyword-argument. + + The following keyword-arguments are available, but make sure to have an + **kwargs to allow for unmatched arguments in the future: + event: Event object of current trace + event_id: The id of the event in the current trace file + timestamp_ns: The timestamp in nanoseconds of the trace + pid: The process id recorded for the given trace + + Example: + The following method handles the runstate_set(int new_state) trace event:: + + def runstate_set(self, new_state, **kwargs): + ... + + The method can also explicitly take a timestamp keyword-argument with the + trace event arguments:: + + def runstate_set(self, new_state, *, timestamp_ns, **kwargs): + ... + + Timestamps have the uint64_t type and are in nanoseconds. + + The pid can be included in addition to the timestamp and is useful when + dealing with traces from multiple processes: + + def runstate_set(self, new_state, *, timestamp_ns, pid, **kwargs): + ... + """ + + def catchall(self, *rec_args, event, timestamp_ns, pid, event_id, **kwargs): + """Called if no specific method for processing a trace event has been found.""" + pass + + def _process_event(self, rec_args, *, event, **kwargs): + fn = getattr(self, event.name, self.catchall) + fn(*rec_args, event=event, **kwargs) + def process(events, log, analyzer, read_header=True): """Invoke an analyzer on each event in a log. Args: @@ -278,30 +336,24 @@ def run(analyzer): process(events_fobj, log_fobj, analyzer, read_header=not no_header) if __name__ == '__main__': - class Formatter(Analyzer): + class Formatter2(Analyzer2): def __init__(self): - self.last_timestamp = None + self.last_timestamp_ns = None - def catchall(self, event, rec): - timestamp = rec[1] - if self.last_timestamp is None: - self.last_timestamp = timestamp - delta_ns = timestamp - self.last_timestamp - self.last_timestamp = timestamp + def catchall(self, *rec_args, event, timestamp_ns, pid, event_id): + if self.last_timestamp_ns is None: + self.last_timestamp_ns = timestamp_ns + delta_ns = timestamp_ns - self.last_timestamp_ns + self.last_timestamp_ns = timestamp_ns - fields = [event.name, '%0.3f' % (delta_ns / 1000.0), - 'pid=%d' % rec[2]] - i = 3 - for type, name in event.args: - if is_string(type): - fields.append('%s=%s' % (name, rec[i])) - else: - fields.append('%s=0x%x' % (name, rec[i])) - i += 1 - print(' '.join(fields)) + fields = [ + f'{name}={r}' if is_string(type) else f'{name}=0x{r:x}' + for r, (type, name) in zip(rec_args, event.args) + ] + print(f'{event.name} {delta_ns / 1000:0.3f} {pid=} ' + ' '.join(fields)) try: - run(Formatter()) + run(Formatter2()) except SimpleException as e: sys.stderr.write(str(e) + "\n") sys.exit(1) From 84197267d1620405c664f6d4510288d0fd3a8837 Mon Sep 17 00:00:00 2001 From: Mads Ynddal Date: Tue, 26 Sep 2023 12:34:35 +0200 Subject: [PATCH 0013/1077] MAINTAINERS: add maintainer of simpletrace.py MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In my work to refactor simpletrace.py, I noticed that there's no maintainer of it, and has the status of "odd fixes". I'm using it from time to time, so I'd like to maintain the script. I've added myself as reviewer under "Tracing" to be informed of changes that might affect simpletrace.py. Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Mads Ynddal Message-id: 20230926103436.25700-14-mads@ynddal.dk Signed-off-by: Stefan Hajnoczi --- MAINTAINERS | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/MAINTAINERS b/MAINTAINERS index 355b1960ce..81625f036b 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -3170,6 +3170,7 @@ F: stubs/ Tracing M: Stefan Hajnoczi +R: Mads Ynddal S: Maintained F: trace/ F: trace-events @@ -3182,6 +3183,11 @@ F: docs/tools/qemu-trace-stap.rst F: docs/devel/tracing.rst T: git https://github.com/stefanha/qemu.git tracing +Simpletrace +M: Mads Ynddal +S: Maintained +F: scripts/simpletrace.py + TPM M: Stefan Berger S: Maintained From ff014701ab0f09fdbf37b4c39334790f9b298253 Mon Sep 17 00:00:00 2001 From: Mads Ynddal Date: Tue, 26 Sep 2023 12:34:36 +0200 Subject: [PATCH 0014/1077] scripts/analyse-locks-simpletrace.py: changed iteritems() to items() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Python 3 removed `dict.iteritems()` in favor of `dict.items()`. This means the script currently doesn't work on Python 3. Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Stefan Hajnoczi Signed-off-by: Mads Ynddal Message-id: 20230926103436.25700-15-mads@ynddal.dk Signed-off-by: Stefan Hajnoczi --- scripts/analyse-locks-simpletrace.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/analyse-locks-simpletrace.py b/scripts/analyse-locks-simpletrace.py index 63c11f4fce..d650dd7140 100755 --- a/scripts/analyse-locks-simpletrace.py +++ b/scripts/analyse-locks-simpletrace.py @@ -75,7 +75,7 @@ if __name__ == '__main__': (analyser.locks, analyser.locked, analyser.unlocks)) # Now dump the individual lock stats - for key, val in sorted(analyser.mutex_records.iteritems(), + for key, val in sorted(analyser.mutex_records.items(), key=lambda k_v: k_v[1]["locks"]): print ("Lock: %#x locks: %d, locked: %d, unlocked: %d" % (key, val["locks"], val["locked"], val["unlocked"])) From d97fa9a00d5b333c8642670b7b55f9101d495dce Mon Sep 17 00:00:00 2001 From: Bastian Koppelmann Date: Wed, 27 Sep 2023 11:10:00 +0200 Subject: [PATCH 0015/1077] tests/tcg/tricore: Bump cpu to tc37x we don't want to exclude ISA v1.6.2 insns from our tests. Acked-by: Richard Henderson Signed-off-by: Bastian Koppelmann Message-Id: <20230828112651.522058-2-kbastian@mail.uni-paderborn.de> --- tests/tcg/tricore/Makefile.softmmu-target | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/tcg/tricore/Makefile.softmmu-target b/tests/tcg/tricore/Makefile.softmmu-target index 2ec0bd3622..d556201b07 100644 --- a/tests/tcg/tricore/Makefile.softmmu-target +++ b/tests/tcg/tricore/Makefile.softmmu-target @@ -25,7 +25,7 @@ TESTS += test_muls.asm.tst TESTS += test_boot_to_main.c.tst TESTS += test_context_save_areas.c.tst -QEMU_OPTS += -M tricore_testboard -cpu tc27x -nographic -kernel +QEMU_OPTS += -M tricore_testboard -cpu tc37x -nographic -kernel %.pS: $(ASM_TESTS_PATH)/%.S $(CC) -E -o $@ $< From 3e2a5107c52f5bf7ed68f4b468cff5be456f1097 Mon Sep 17 00:00:00 2001 From: Bastian Koppelmann Date: Mon, 28 Aug 2023 13:26:42 +0200 Subject: [PATCH 0016/1077] target/tricore: Implement CRCN insn reported in https://gitlab.com/qemu-project/qemu/-/issues/1667 Reviewed-by: Richard Henderson Signed-off-by: Bastian Koppelmann Message-ID: <20230828112651.522058-3-kbastian@mail.uni-paderborn.de> --- target/tricore/helper.h | 1 + target/tricore/op_helper.c | 63 +++++++++++++++++++++++ target/tricore/translate.c | 8 +++ target/tricore/tricore-opcodes.h | 1 + tests/tcg/tricore/Makefile.softmmu-target | 1 + tests/tcg/tricore/asm/test_crcn.S | 9 ++++ 6 files changed, 83 insertions(+) create mode 100644 tests/tcg/tricore/asm/test_crcn.S diff --git a/target/tricore/helper.h b/target/tricore/helper.h index 31d71eac7a..190645413a 100644 --- a/target/tricore/helper.h +++ b/target/tricore/helper.h @@ -134,6 +134,7 @@ DEF_HELPER_FLAGS_5(mulr_h, TCG_CALL_NO_RWG_SE, i32, i32, i32, i32, i32, i32) DEF_HELPER_FLAGS_2(crc32b, TCG_CALL_NO_RWG_SE, i32, i32, i32) DEF_HELPER_FLAGS_2(crc32_be, TCG_CALL_NO_RWG_SE, i32, i32, i32) DEF_HELPER_FLAGS_2(crc32_le, TCG_CALL_NO_RWG_SE, i32, i32, i32) +DEF_HELPER_FLAGS_3(crcn, TCG_CALL_NO_RWG_SE, i32, i32, i32, i32) DEF_HELPER_FLAGS_2(shuffle, TCG_CALL_NO_RWG_SE, i32, i32, i32) /* CSA */ DEF_HELPER_2(call, void, env, i32) diff --git a/target/tricore/op_helper.c b/target/tricore/op_helper.c index 89be1ed648..0cf8eb50bd 100644 --- a/target/tricore/op_helper.c +++ b/target/tricore/op_helper.c @@ -2308,6 +2308,69 @@ uint32_t helper_crc32_le(uint32_t arg0, uint32_t arg1) return crc32(arg1, buf, 4); } +static uint32_t crc_div(uint32_t crc_in, uint32_t data, uint32_t gen, + uint32_t n, uint32_t m) +{ + uint32_t i; + + data = data << n; + for (i = 0; i < m; i++) { + if (crc_in & (1u << (n - 1))) { + crc_in <<= 1; + if (data & (1u << (m - 1))) { + crc_in++; + } + crc_in ^= gen; + } else { + crc_in <<= 1; + if (data & (1u << (m - 1))) { + crc_in++; + } + } + data <<= 1; + } + + return crc_in; +} + +uint32_t helper_crcn(uint32_t arg0, uint32_t arg1, uint32_t arg2) +{ + uint32_t crc_out, crc_in; + uint32_t n = extract32(arg0, 12, 4) + 1; + uint32_t gen = extract32(arg0, 16, n); + uint32_t inv = extract32(arg0, 9, 1); + uint32_t le = extract32(arg0, 8, 1); + uint32_t m = extract32(arg0, 0, 3) + 1; + uint32_t data = extract32(arg1, 0, m); + uint32_t seed = extract32(arg2, 0, n); + + if (le == 1) { + if (m == 0) { + data = 0; + } else { + data = revbit32(data) >> (32 - m); + } + } + + if (inv == 1) { + seed = ~seed; + } + + if (m > n) { + crc_in = (data >> (m - n)) ^ seed; + } else { + crc_in = (data << (n - m)) ^ seed; + } + + crc_out = crc_div(crc_in, data, gen, n, m); + + if (inv) { + crc_out = ~crc_out; + } + + return extract32(crc_out, 0, n); +} + uint32_t helper_shuffle(uint32_t arg0, uint32_t arg1) { uint32_t resb; diff --git a/target/tricore/translate.c b/target/tricore/translate.c index 6ae5ccbf72..4e7e18f985 100644 --- a/target/tricore/translate.c +++ b/target/tricore/translate.c @@ -6669,6 +6669,14 @@ static void decode_rrr_divide(DisasContext *ctx) gen_helper_pack(cpu_gpr_d[r4], cpu_PSW_C, cpu_gpr_d[r3], cpu_gpr_d[r3+1], cpu_gpr_d[r1]); break; + case OPC2_32_RRR_CRCN: + if (has_feature(ctx, TRICORE_FEATURE_162)) { + gen_helper_crcn(cpu_gpr_d[r4], cpu_gpr_d[r1], cpu_gpr_d[r2], + cpu_gpr_d[r3]); + } else { + generate_trap(ctx, TRAPC_INSN_ERR, TIN2_IOPC); + } + break; case OPC2_32_RRR_ADD_F: gen_helper_fadd(cpu_gpr_d[r4], cpu_env, cpu_gpr_d[r1], cpu_gpr_d[r3]); break; diff --git a/target/tricore/tricore-opcodes.h b/target/tricore/tricore-opcodes.h index bc62b73173..f070571665 100644 --- a/target/tricore/tricore-opcodes.h +++ b/target/tricore/tricore-opcodes.h @@ -1247,6 +1247,7 @@ enum { OPC2_32_RRR_SUB_F = 0x03, OPC2_32_RRR_MADD_F = 0x06, OPC2_32_RRR_MSUB_F = 0x07, + OPC2_32_RRR_CRCN = 0x01, /* 1.6.2 up */ }; /* * RRR1 Format diff --git a/tests/tcg/tricore/Makefile.softmmu-target b/tests/tcg/tricore/Makefile.softmmu-target index d556201b07..b8d9b33933 100644 --- a/tests/tcg/tricore/Makefile.softmmu-target +++ b/tests/tcg/tricore/Makefile.softmmu-target @@ -9,6 +9,7 @@ CFLAGS = -mtc162 -c -I$(TESTS_PATH) TESTS += test_abs.asm.tst TESTS += test_bmerge.asm.tst TESTS += test_clz.asm.tst +TESTS += test_crcn.asm.tst TESTS += test_dextr.asm.tst TESTS += test_dvstep.asm.tst TESTS += test_fadd.asm.tst diff --git a/tests/tcg/tricore/asm/test_crcn.S b/tests/tcg/tricore/asm/test_crcn.S new file mode 100644 index 0000000000..51a22722a3 --- /dev/null +++ b/tests/tcg/tricore/asm/test_crcn.S @@ -0,0 +1,9 @@ +#include "macros.h" +.text +.global _start +_start: +# insn num result rs1 rs2 rs3 +# | | | | | | + TEST_D_DDD(crcn, 1, 0x00002bed, 0x0, 0xa10ddeed, 0x0) + + TEST_PASSFAIL From ce64babdf60fb9a7de8bcac637243a10db1a3b26 Mon Sep 17 00:00:00 2001 From: Bastian Koppelmann Date: Mon, 28 Aug 2023 13:26:43 +0200 Subject: [PATCH 0017/1077] target/tricore: Correctly handle FPU RM from PSW when we reconstructed PSW using psw_read(), we were trying to clear the cached USB bits out of env->PSW. The mask was wrong and we would clear PSW.RM as well. when we write the PSW using psw_write() we update the rounding modes in env->fp_status for softfloat. The order of bits used by TriCore is not the one used by softfloat. Reviewed-by: Richard Henderson Signed-off-by: Bastian Koppelmann Message-ID: <20230828112651.522058-4-kbastian@mail.uni-paderborn.de> --- target/tricore/helper.c | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/target/tricore/helper.c b/target/tricore/helper.c index 6d076ac36f..e615c3d6d4 100644 --- a/target/tricore/helper.c +++ b/target/tricore/helper.c @@ -120,7 +120,21 @@ void tricore_cpu_list(void) void fpu_set_state(CPUTriCoreState *env) { - set_float_rounding_mode(env->PSW & MASK_PSW_FPU_RM, &env->fp_status); + switch (extract32(env->PSW, 24, 2)) { + case 0: + set_float_rounding_mode(float_round_nearest_even, &env->fp_status); + break; + case 1: + set_float_rounding_mode(float_round_up, &env->fp_status); + break; + case 2: + set_float_rounding_mode(float_round_down, &env->fp_status); + break; + case 3: + set_float_rounding_mode(float_round_to_zero, &env->fp_status); + break; + } + set_flush_inputs_to_zero(1, &env->fp_status); set_flush_to_zero(1, &env->fp_status); set_default_nan_mode(1, &env->fp_status); @@ -129,7 +143,7 @@ void fpu_set_state(CPUTriCoreState *env) uint32_t psw_read(CPUTriCoreState *env) { /* clear all USB bits */ - env->PSW &= 0x6ffffff; + env->PSW &= 0x7ffffff; /* now set them from the cache */ env->PSW |= ((env->PSW_USB_C != 0) << 31); env->PSW |= ((env->PSW_USB_V & (1 << 31)) >> 1); From 2bdbe35632fc1f5f83054427085f59d28f45660f Mon Sep 17 00:00:00 2001 From: Bastian Koppelmann Date: Mon, 28 Aug 2023 13:26:44 +0200 Subject: [PATCH 0018/1077] target/tricore: Implement FTOU insn Reviewed-by: Richard Henderson Signed-off-by: Bastian Koppelmann Message-ID: <20230828112651.522058-5-kbastian@mail.uni-paderborn.de> --- target/tricore/fpu_helper.c | 32 +++++++++++++++++++++++ target/tricore/helper.h | 1 + target/tricore/translate.c | 3 +++ tests/tcg/tricore/Makefile.softmmu-target | 1 + tests/tcg/tricore/asm/test_ftou.S | 12 +++++++++ 5 files changed, 49 insertions(+) create mode 100644 tests/tcg/tricore/asm/test_ftou.S diff --git a/target/tricore/fpu_helper.c b/target/tricore/fpu_helper.c index cb7ee7dd35..3aefeb776e 100644 --- a/target/tricore/fpu_helper.c +++ b/target/tricore/fpu_helper.c @@ -429,6 +429,38 @@ uint32_t helper_ftoiz(CPUTriCoreState *env, uint32_t arg) return result; } +uint32_t helper_ftou(CPUTriCoreState *env, uint32_t arg) +{ + float32 f_arg = make_float32(arg); + uint32_t result; + int32_t flags = 0; + + result = float32_to_uint32(f_arg, &env->fp_status); + + flags = f_get_excp_flags(env); + if (flags & float_flag_invalid) { + flags &= ~float_flag_inexact; + if (float32_is_any_nan(f_arg)) { + result = 0; + } + /* + * we need to check arg < 0.0 before rounding as TriCore needs to raise + * float_flag_invalid as well. For instance, when we have a negative + * exponent and sign, softfloat would only raise float_flat_inexact. + */ + } else if (float32_lt_quiet(f_arg, 0, &env->fp_status)) { + flags = float_flag_invalid; + result = 0; + } + + if (flags) { + f_update_psw_flags(env, flags); + } else { + env->FPU_FS = 0; + } + return result; +} + uint32_t helper_ftouz(CPUTriCoreState *env, uint32_t arg) { float32 f_arg = make_float32(arg); diff --git a/target/tricore/helper.h b/target/tricore/helper.h index 190645413a..827fbaa692 100644 --- a/target/tricore/helper.h +++ b/target/tricore/helper.h @@ -114,6 +114,7 @@ DEF_HELPER_2(ftoi, i32, env, i32) DEF_HELPER_2(itof, i32, env, i32) DEF_HELPER_2(utof, i32, env, i32) DEF_HELPER_2(ftoiz, i32, env, i32) +DEF_HELPER_2(ftou, i32, env, i32) DEF_HELPER_2(ftouz, i32, env, i32) DEF_HELPER_2(updfl, void, env, i32) /* dvinit */ diff --git a/target/tricore/translate.c b/target/tricore/translate.c index 4e7e18f985..382ecf4775 100644 --- a/target/tricore/translate.c +++ b/target/tricore/translate.c @@ -6269,6 +6269,9 @@ static void decode_rr_divide(DisasContext *ctx) case OPC2_32_RR_ITOF: gen_helper_itof(cpu_gpr_d[r3], cpu_env, cpu_gpr_d[r1]); break; + case OPC2_32_RR_FTOU: + gen_helper_ftou(cpu_gpr_d[r3], cpu_env, cpu_gpr_d[r1]); + break; case OPC2_32_RR_FTOUZ: gen_helper_ftouz(cpu_gpr_d[r3], cpu_env, cpu_gpr_d[r1]); break; diff --git a/tests/tcg/tricore/Makefile.softmmu-target b/tests/tcg/tricore/Makefile.softmmu-target index b8d9b33933..91ae129a83 100644 --- a/tests/tcg/tricore/Makefile.softmmu-target +++ b/tests/tcg/tricore/Makefile.softmmu-target @@ -15,6 +15,7 @@ TESTS += test_dvstep.asm.tst TESTS += test_fadd.asm.tst TESTS += test_fmul.asm.tst TESTS += test_ftoi.asm.tst +TESTS += test_ftou.asm.tst TESTS += test_imask.asm.tst TESTS += test_insert.asm.tst TESTS += test_ld_bu.asm.tst diff --git a/tests/tcg/tricore/asm/test_ftou.S b/tests/tcg/tricore/asm/test_ftou.S new file mode 100644 index 0000000000..10f106ad62 --- /dev/null +++ b/tests/tcg/tricore/asm/test_ftou.S @@ -0,0 +1,12 @@ +#include "macros.h" +.text +.global _start +_start: + TEST_D_D(ftou, 1, 0x00000000, 0x1733f6c2) + TEST_D_D(ftou, 2, 0x00000000, 0x2c9d9cdc) + TEST_D_D(ftou, 3, 0xffffffff, 0x56eb7395) + TEST_D_D(ftou, 4, 0x79900800, 0x4ef32010) + TEST_D_D(ftou, 5, 0x0353f510, 0x4c54fd44) + + TEST_PASSFAIL + From e43692bce684b76480df66473a9b3bec7a7d312a Mon Sep 17 00:00:00 2001 From: Bastian Koppelmann Date: Mon, 28 Aug 2023 13:26:45 +0200 Subject: [PATCH 0019/1077] target/tricore: Clarify special case for FTOUZ insn this is not something other ISAs do, so clarify it with a comment. Reviewed-by: Richard Henderson Signed-off-by: Bastian Koppelmann Message-ID: <20230828112651.522058-6-kbastian@mail.uni-paderborn.de> --- target/tricore/fpu_helper.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/target/tricore/fpu_helper.c b/target/tricore/fpu_helper.c index 3aefeb776e..d0c474c5f3 100644 --- a/target/tricore/fpu_helper.c +++ b/target/tricore/fpu_helper.c @@ -475,6 +475,11 @@ uint32_t helper_ftouz(CPUTriCoreState *env, uint32_t arg) if (float32_is_any_nan(f_arg)) { result = 0; } + /* + * we need to check arg < 0.0 before rounding as TriCore needs to raise + * float_flag_invalid as well. For instance, when we have a negative + * exponent and sign, softfloat would only raise float_flat_inexact. + */ } else if (float32_lt_quiet(f_arg, 0, &env->fp_status)) { flags = float_flag_invalid; result = 0; From 815061b9da88a3a9a90fae58b5a778632e0cc2df Mon Sep 17 00:00:00 2001 From: Bastian Koppelmann Date: Mon, 28 Aug 2023 13:26:46 +0200 Subject: [PATCH 0020/1077] target/tricore: Implement ftohp insn reported in https://gitlab.com/qemu-project/qemu/-/issues/1667 Reviewed-by: Richard Henderson Signed-off-by: Bastian Koppelmann Message-ID: <20230828112651.522058-7-kbastian@mail.uni-paderborn.de> --- target/tricore/fpu_helper.c | 38 +++++++++++++++++++++++ target/tricore/helper.c | 1 + target/tricore/helper.h | 1 + target/tricore/translate.c | 7 +++++ target/tricore/tricore-opcodes.h | 1 + tests/tcg/tricore/Makefile.softmmu-target | 1 + tests/tcg/tricore/asm/test_ftohp.S | 14 +++++++++ 7 files changed, 63 insertions(+) create mode 100644 tests/tcg/tricore/asm/test_ftohp.S diff --git a/target/tricore/fpu_helper.c b/target/tricore/fpu_helper.c index d0c474c5f3..848c4a40a0 100644 --- a/target/tricore/fpu_helper.c +++ b/target/tricore/fpu_helper.c @@ -373,6 +373,44 @@ uint32_t helper_ftoi(CPUTriCoreState *env, uint32_t arg) return (uint32_t)result; } +uint32_t helper_ftohp(CPUTriCoreState *env, uint32_t arg) +{ + float32 f_arg = make_float32(arg); + uint32_t result = 0; + int32_t flags = 0; + + /* + * if we have any NAN we need to move the top 2 and lower 8 input mantissa + * bits to the top 2 and lower 8 output mantissa bits respectively. + * Softfloat on the other hand uses the top 10 mantissa bits. + */ + if (float32_is_any_nan(f_arg)) { + if (float32_is_signaling_nan(f_arg, &env->fp_status)) { + flags |= float_flag_invalid; + } + result = float16_set_sign(result, arg >> 31); + result = deposit32(result, 10, 5, 0x1f); + result = deposit32(result, 8, 2, extract32(arg, 21, 2)); + result = deposit32(result, 0, 8, extract32(arg, 0, 8)); + if (extract32(result, 0, 10) == 0) { + result |= (1 << 8); + } + } else { + set_flush_to_zero(0, &env->fp_status); + result = float32_to_float16(f_arg, true, &env->fp_status); + set_flush_to_zero(1, &env->fp_status); + flags = f_get_excp_flags(env); + } + + if (flags) { + f_update_psw_flags(env, flags); + } else { + env->FPU_FS = 0; + } + + return result; +} + uint32_t helper_itof(CPUTriCoreState *env, uint32_t arg) { float32 f_result; diff --git a/target/tricore/helper.c b/target/tricore/helper.c index e615c3d6d4..7e5da3cb23 100644 --- a/target/tricore/helper.c +++ b/target/tricore/helper.c @@ -137,6 +137,7 @@ void fpu_set_state(CPUTriCoreState *env) set_flush_inputs_to_zero(1, &env->fp_status); set_flush_to_zero(1, &env->fp_status); + set_float_detect_tininess(float_tininess_before_rounding, &env->fp_status); set_default_nan_mode(1, &env->fp_status); } diff --git a/target/tricore/helper.h b/target/tricore/helper.h index 827fbaa692..dcc5a492b3 100644 --- a/target/tricore/helper.h +++ b/target/tricore/helper.h @@ -111,6 +111,7 @@ DEF_HELPER_4(fmsub, i32, env, i32, i32, i32) DEF_HELPER_3(fcmp, i32, env, i32, i32) DEF_HELPER_2(qseed, i32, env, i32) DEF_HELPER_2(ftoi, i32, env, i32) +DEF_HELPER_2(ftohp, i32, env, i32) DEF_HELPER_2(itof, i32, env, i32) DEF_HELPER_2(utof, i32, env, i32) DEF_HELPER_2(ftoiz, i32, env, i32) diff --git a/target/tricore/translate.c b/target/tricore/translate.c index 382ecf4775..d76b6475f1 100644 --- a/target/tricore/translate.c +++ b/target/tricore/translate.c @@ -6260,6 +6260,13 @@ static void decode_rr_divide(DisasContext *ctx) case OPC2_32_RR_DIV_F: gen_helper_fdiv(cpu_gpr_d[r3], cpu_env, cpu_gpr_d[r1], cpu_gpr_d[r2]); break; + case OPC2_32_RR_FTOHP: + if (has_feature(ctx, TRICORE_FEATURE_162)) { + gen_helper_ftohp(cpu_gpr_d[r3], cpu_env, cpu_gpr_d[r1]); + } else { + generate_trap(ctx, TRAPC_INSN_ERR, TIN2_IOPC); + } + break; case OPC2_32_RR_CMP_F: gen_helper_fcmp(cpu_gpr_d[r3], cpu_env, cpu_gpr_d[r1], cpu_gpr_d[r2]); break; diff --git a/target/tricore/tricore-opcodes.h b/target/tricore/tricore-opcodes.h index f070571665..29e655a667 100644 --- a/target/tricore/tricore-opcodes.h +++ b/target/tricore/tricore-opcodes.h @@ -1152,6 +1152,7 @@ enum { OPC2_32_RR_ITOF = 0x14, OPC2_32_RR_CMP_F = 0x00, OPC2_32_RR_FTOIZ = 0x13, + OPC2_32_RR_FTOHP = 0x25, /* 1.6.2 only */ OPC2_32_RR_FTOQ31 = 0x11, OPC2_32_RR_FTOQ31Z = 0x18, OPC2_32_RR_FTOU = 0x12, diff --git a/tests/tcg/tricore/Makefile.softmmu-target b/tests/tcg/tricore/Makefile.softmmu-target index 91ae129a83..fc545d45ae 100644 --- a/tests/tcg/tricore/Makefile.softmmu-target +++ b/tests/tcg/tricore/Makefile.softmmu-target @@ -14,6 +14,7 @@ TESTS += test_dextr.asm.tst TESTS += test_dvstep.asm.tst TESTS += test_fadd.asm.tst TESTS += test_fmul.asm.tst +TESTS += test_ftohp.asm.tst TESTS += test_ftoi.asm.tst TESTS += test_ftou.asm.tst TESTS += test_imask.asm.tst diff --git a/tests/tcg/tricore/asm/test_ftohp.S b/tests/tcg/tricore/asm/test_ftohp.S new file mode 100644 index 0000000000..9e23141c1e --- /dev/null +++ b/tests/tcg/tricore/asm/test_ftohp.S @@ -0,0 +1,14 @@ +#include "macros.h" +.text +.global _start +_start: + TEST_D_D(ftohp, 1, 0xffff, 0xffffffff) + TEST_D_D(ftohp, 2, 0xfc00, 0xff800000) + TEST_D_D(ftohp, 3, 0x7c00, 0x7f800000) + TEST_D_D(ftohp, 4, 0x0, 0x0) + TEST_D_D(ftohp, 5, 0x5, 0x34a43580) + + #TEST_D_D_PSW(ftohp, 6, 0x400, 0x8c000b80, 0x387fee74) + + TEST_PASSFAIL + From 5e0e06d9a2ce13d5b9832f0dddeaf5e2f4f70591 Mon Sep 17 00:00:00 2001 From: Bastian Koppelmann Date: Mon, 28 Aug 2023 13:26:47 +0200 Subject: [PATCH 0021/1077] target/tricore: Implement hptof insn Reviewed-by: Richard Henderson Resolves: https://gitlab.com/qemu-project/qemu/-/issues/1667 Signed-off-by: Bastian Koppelmann Message-ID: <20230828112651.522058-8-kbastian@mail.uni-paderborn.de> --- target/tricore/fpu_helper.c | 36 +++++++++++++++++++++++ target/tricore/helper.h | 1 + target/tricore/translate.c | 7 +++++ target/tricore/tricore-opcodes.h | 1 + tests/tcg/tricore/Makefile.softmmu-target | 1 + tests/tcg/tricore/asm/test_hptof.S | 12 ++++++++ 6 files changed, 58 insertions(+) create mode 100644 tests/tcg/tricore/asm/test_hptof.S diff --git a/target/tricore/fpu_helper.c b/target/tricore/fpu_helper.c index 848c4a40a0..5d38aea143 100644 --- a/target/tricore/fpu_helper.c +++ b/target/tricore/fpu_helper.c @@ -373,6 +373,42 @@ uint32_t helper_ftoi(CPUTriCoreState *env, uint32_t arg) return (uint32_t)result; } +uint32_t helper_hptof(CPUTriCoreState *env, uint32_t arg) +{ + float16 f_arg = make_float16(arg); + uint32_t result = 0; + int32_t flags = 0; + + /* + * if we have any NAN we need to move the top 2 and lower 8 input mantissa + * bits to the top 2 and lower 8 output mantissa bits respectively. + * Softfloat on the other hand uses the top 10 mantissa bits. + */ + if (float16_is_any_nan(f_arg)) { + if (float16_is_signaling_nan(f_arg, &env->fp_status)) { + flags |= float_flag_invalid; + } + result = 0; + result = float32_set_sign(result, f_arg >> 15); + result = deposit32(result, 23, 8, 0xff); + result = deposit32(result, 21, 2, extract32(f_arg, 8, 2)); + result = deposit32(result, 0, 8, extract32(f_arg, 0, 8)); + } else { + set_flush_inputs_to_zero(0, &env->fp_status); + result = float16_to_float32(f_arg, true, &env->fp_status); + set_flush_inputs_to_zero(1, &env->fp_status); + flags = f_get_excp_flags(env); + } + + if (flags) { + f_update_psw_flags(env, flags); + } else { + env->FPU_FS = 0; + } + + return result; +} + uint32_t helper_ftohp(CPUTriCoreState *env, uint32_t arg) { float32 f_arg = make_float32(arg); diff --git a/target/tricore/helper.h b/target/tricore/helper.h index dcc5a492b3..1d97d078b0 100644 --- a/target/tricore/helper.h +++ b/target/tricore/helper.h @@ -112,6 +112,7 @@ DEF_HELPER_3(fcmp, i32, env, i32, i32) DEF_HELPER_2(qseed, i32, env, i32) DEF_HELPER_2(ftoi, i32, env, i32) DEF_HELPER_2(ftohp, i32, env, i32) +DEF_HELPER_2(hptof, i32, env, i32) DEF_HELPER_2(itof, i32, env, i32) DEF_HELPER_2(utof, i32, env, i32) DEF_HELPER_2(ftoiz, i32, env, i32) diff --git a/target/tricore/translate.c b/target/tricore/translate.c index d76b6475f1..c9823ee32a 100644 --- a/target/tricore/translate.c +++ b/target/tricore/translate.c @@ -6267,6 +6267,13 @@ static void decode_rr_divide(DisasContext *ctx) generate_trap(ctx, TRAPC_INSN_ERR, TIN2_IOPC); } break; + case OPC2_32_RR_HPTOF: + if (has_feature(ctx, TRICORE_FEATURE_162)) { + gen_helper_hptof(cpu_gpr_d[r3], cpu_env, cpu_gpr_d[r1]); + } else { + generate_trap(ctx, TRAPC_INSN_ERR, TIN2_IOPC); + } + break; case OPC2_32_RR_CMP_F: gen_helper_fcmp(cpu_gpr_d[r3], cpu_env, cpu_gpr_d[r1], cpu_gpr_d[r2]); break; diff --git a/target/tricore/tricore-opcodes.h b/target/tricore/tricore-opcodes.h index 29e655a667..60d2402b6e 100644 --- a/target/tricore/tricore-opcodes.h +++ b/target/tricore/tricore-opcodes.h @@ -1153,6 +1153,7 @@ enum { OPC2_32_RR_CMP_F = 0x00, OPC2_32_RR_FTOIZ = 0x13, OPC2_32_RR_FTOHP = 0x25, /* 1.6.2 only */ + OPC2_32_RR_HPTOF = 0x24, /* 1.6.2 only */ OPC2_32_RR_FTOQ31 = 0x11, OPC2_32_RR_FTOQ31Z = 0x18, OPC2_32_RR_FTOU = 0x12, diff --git a/tests/tcg/tricore/Makefile.softmmu-target b/tests/tcg/tricore/Makefile.softmmu-target index fc545d45ae..258aeb40ae 100644 --- a/tests/tcg/tricore/Makefile.softmmu-target +++ b/tests/tcg/tricore/Makefile.softmmu-target @@ -17,6 +17,7 @@ TESTS += test_fmul.asm.tst TESTS += test_ftohp.asm.tst TESTS += test_ftoi.asm.tst TESTS += test_ftou.asm.tst +TESTS += test_hptof.asm.tst TESTS += test_imask.asm.tst TESTS += test_insert.asm.tst TESTS += test_ld_bu.asm.tst diff --git a/tests/tcg/tricore/asm/test_hptof.S b/tests/tcg/tricore/asm/test_hptof.S new file mode 100644 index 0000000000..8adc5e5273 --- /dev/null +++ b/tests/tcg/tricore/asm/test_hptof.S @@ -0,0 +1,12 @@ +#include "macros.h" +.text +.global _start +_start: + TEST_D_D(hptof, 1, 0xba190000, 0xcc0e90c8) + TEST_D_D(hptof, 2, 0x3eaea000, 0x8be23575) + TEST_D_D(hptof, 3, 0xc33b8000, 0xcc48d9dc) + TEST_D_D(hptof, 4, 0x43e2a000, 0xaef95f15) + TEST_D_D(hptof, 5, 0x3d55e000, 0x04932aaf) + + TEST_PASSFAIL + From 23fa6f56b33f8fddf86ba4d027fb7d3081440cd9 Mon Sep 17 00:00:00 2001 From: Bastian Koppelmann Date: Mon, 28 Aug 2023 13:26:48 +0200 Subject: [PATCH 0022/1077] target/tricore: Fix RCPW/RRPW_INSERT insns for width = 0 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit we would crash if width was 0 for these insns, as tcg_gen_deposit() is undefined for that case. For TriCore, width = 0 is a mov from the src reg to the dst reg, so we special case this here. Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Richard Henderson Signed-off-by: Bastian Koppelmann Message-ID: <20230828112651.522058-9-kbastian@mail.uni-paderborn.de> --- target/tricore/translate.c | 10 ++++++++-- tests/tcg/tricore/asm/macros.h | 15 +++++++++++++++ tests/tcg/tricore/asm/test_insert.S | 9 +++++++++ 3 files changed, 32 insertions(+), 2 deletions(-) diff --git a/target/tricore/translate.c b/target/tricore/translate.c index c9823ee32a..3f950ae33b 100644 --- a/target/tricore/translate.c +++ b/target/tricore/translate.c @@ -5310,8 +5310,11 @@ static void decode_rcpw_insert(DisasContext *ctx) } break; case OPC2_32_RCPW_INSERT: + /* tcg_gen_deposit_tl() does not handle the case of width = 0 */ + if (width == 0) { + tcg_gen_mov_tl(cpu_gpr_d[r2], cpu_gpr_d[r1]); /* if pos + width > 32 undefined result */ - if (pos + width <= 32) { + } else if (pos + width <= 32) { temp = tcg_constant_i32(const4); tcg_gen_deposit_tl(cpu_gpr_d[r2], cpu_gpr_d[r1], temp, pos, width); } @@ -6571,7 +6574,10 @@ static void decode_rrpw_extract_insert(DisasContext *ctx) break; case OPC2_32_RRPW_INSERT: - if (pos + width <= 32) { + /* tcg_gen_deposit_tl() does not handle the case of width = 0 */ + if (width == 0) { + tcg_gen_mov_tl(cpu_gpr_d[r3], cpu_gpr_d[r1]); + } else if (pos + width <= 32) { tcg_gen_deposit_tl(cpu_gpr_d[r3], cpu_gpr_d[r1], cpu_gpr_d[r2], pos, width); } diff --git a/tests/tcg/tricore/asm/macros.h b/tests/tcg/tricore/asm/macros.h index b5087b5c97..51f6191ef2 100644 --- a/tests/tcg/tricore/asm/macros.h +++ b/tests/tcg/tricore/asm/macros.h @@ -161,6 +161,21 @@ test_ ## num: \ insn DREG_CALC_RESULT, DREG_RS1, imm1, DREG_RS2, imm2; \ ) +#define TEST_D_DDII(insn, num, result, rs1, rs2, imm1, imm2) \ + TEST_CASE(num, DREG_CALC_RESULT, result, \ + LI(DREG_RS1, rs1); \ + LI(DREG_RS2, rs2); \ + rstv; \ + insn DREG_CALC_RESULT, DREG_RS1, DREG_RS2, imm1, imm2; \ + ) + +#define TEST_D_DIII(insn, num, result, rs1, imm1, imm2, imm3)\ + TEST_CASE(num, DREG_CALC_RESULT, result, \ + LI(DREG_RS1, rs1); \ + rstv; \ + insn DREG_CALC_RESULT, DREG_RS1, imm1, imm2, imm3; \ + ) + #define TEST_E_ED(insn, num, res_hi, res_lo, rs1_hi, rs1_lo, rs2) \ TEST_CASE_E(num, res_lo, res_hi, \ LI(EREG_RS1_LO, rs1_lo); \ diff --git a/tests/tcg/tricore/asm/test_insert.S b/tests/tcg/tricore/asm/test_insert.S index d5fd2237e1..3978810121 100644 --- a/tests/tcg/tricore/asm/test_insert.S +++ b/tests/tcg/tricore/asm/test_insert.S @@ -6,4 +6,13 @@ _start: # | | | | | | | TEST_D_DIDI(insert, 1, 0x7fffffff, 0xffffffff, 0xa, 0x10, 0x8) +# insn num result rs1 imm1 imm2 imm3 +# | | | | | | | + TEST_D_DIII(insert, 2, 0xd38fe370, 0xd38fe370, 0x4, 0x4 , 0x0) + TEST_D_DIII(insert, 3, 0xd38fe374, 0xd38fe370, 0x4, 0x0 , 0x4) + +# insn num result rs1 rs2 pos width +# | | | | | | | + TEST_D_DDII(insert, 4, 0x03c1e53c, 0x03c1e53c, 0x45821385, 0x7 ,0x0) + TEST_PASSFAIL From 222ff2d3581e46731fe19644dfc4c4f36f39ac03 Mon Sep 17 00:00:00 2001 From: Bastian Koppelmann Date: Mon, 28 Aug 2023 13:26:49 +0200 Subject: [PATCH 0023/1077] target/tricore: Swap src and dst reg for RCRR_INSERT Acked-by: Richard Henderson Signed-off-by: Bastian Koppelmann Message-ID: <20230828112651.522058-10-kbastian@mail.uni-paderborn.de> --- target/tricore/translate.c | 8 ++++---- tests/tcg/tricore/asm/macros.h | 9 +++++++++ tests/tcg/tricore/asm/test_insert.S | 5 +++++ 3 files changed, 18 insertions(+), 4 deletions(-) diff --git a/target/tricore/translate.c b/target/tricore/translate.c index 3f950ae33b..7aba7b067c 100644 --- a/target/tricore/translate.c +++ b/target/tricore/translate.c @@ -8223,12 +8223,12 @@ static void decode_32Bit_opc(DisasContext *ctx) temp2 = tcg_temp_new(); /* width*/ temp3 = tcg_temp_new(); /* pos */ - CHECK_REG_PAIR(r3); + CHECK_REG_PAIR(r2); - tcg_gen_andi_tl(temp2, cpu_gpr_d[r3+1], 0x1f); - tcg_gen_andi_tl(temp3, cpu_gpr_d[r3], 0x1f); + tcg_gen_andi_tl(temp2, cpu_gpr_d[r2 + 1], 0x1f); + tcg_gen_andi_tl(temp3, cpu_gpr_d[r2], 0x1f); - gen_insert(cpu_gpr_d[r2], cpu_gpr_d[r1], temp, temp2, temp3); + gen_insert(cpu_gpr_d[r3], cpu_gpr_d[r1], temp, temp2, temp3); break; /* RCRW Format */ case OPCM_32_RCRW_MASK_INSERT: diff --git a/tests/tcg/tricore/asm/macros.h b/tests/tcg/tricore/asm/macros.h index 51f6191ef2..17e696bef5 100644 --- a/tests/tcg/tricore/asm/macros.h +++ b/tests/tcg/tricore/asm/macros.h @@ -169,6 +169,15 @@ test_ ## num: \ insn DREG_CALC_RESULT, DREG_RS1, DREG_RS2, imm1, imm2; \ ) +#define TEST_D_DIE(insn, num, result, rs1, imm1, rs2_lo, rs2_hi)\ + TEST_CASE(num, DREG_CALC_RESULT, result, \ + LI(DREG_RS1, rs1); \ + LI(EREG_RS2_LO, rs2_lo); \ + LI(EREG_RS2_HI, rs2_hi); \ + rstv; \ + insn DREG_CALC_RESULT, DREG_RS1, imm1, EREG_RS2; \ + ) + #define TEST_D_DIII(insn, num, result, rs1, imm1, imm2, imm3)\ TEST_CASE(num, DREG_CALC_RESULT, result, \ LI(DREG_RS1, rs1); \ diff --git a/tests/tcg/tricore/asm/test_insert.S b/tests/tcg/tricore/asm/test_insert.S index 3978810121..223d7ce796 100644 --- a/tests/tcg/tricore/asm/test_insert.S +++ b/tests/tcg/tricore/asm/test_insert.S @@ -15,4 +15,9 @@ _start: # | | | | | | | TEST_D_DDII(insert, 4, 0x03c1e53c, 0x03c1e53c, 0x45821385, 0x7 ,0x0) +# insn num result rs1 imm1 rs2_h rs2_l +# | | | | | | | + TEST_D_DIE(insert, 5, 0xe30c308d, 0xe30c308d ,0x3 , 0x00000000 ,0x00000000) + TEST_D_DIE(insert, 6, 0x669b0120, 0x669b2820 ,0x2 , 0x5530a1c7 ,0x3a2b0f67) + TEST_PASSFAIL From 1f22db19533c6e8b01274d12c161c063083e2fba Mon Sep 17 00:00:00 2001 From: Bastian Koppelmann Date: Mon, 28 Aug 2023 13:26:50 +0200 Subject: [PATCH 0024/1077] target/tricore: Replace cpu_*_code with translator_* Reviewed-by: Richard Henderson Signed-off-by: Bastian Koppelmann Message-ID: <20230828112651.522058-11-kbastian@mail.uni-paderborn.de> --- target/tricore/translate.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/target/tricore/translate.c b/target/tricore/translate.c index 7aba7b067c..2107d1fdd4 100644 --- a/target/tricore/translate.c +++ b/target/tricore/translate.c @@ -8398,7 +8398,7 @@ static bool insn_crosses_page(CPUTriCoreState *env, DisasContext *ctx) * 4 bytes from the page boundary, so we cross the page if the first * 16 bits indicate that this is a 32 bit insn. */ - uint16_t insn = cpu_lduw_code(env, ctx->base.pc_next); + uint16_t insn = translator_lduw(env, &ctx->base, ctx->base.pc_next); return !tricore_insn_is_16bit(insn); } @@ -8411,14 +8411,15 @@ static void tricore_tr_translate_insn(DisasContextBase *dcbase, CPUState *cpu) uint16_t insn_lo; bool is_16bit; - insn_lo = cpu_lduw_code(env, ctx->base.pc_next); + insn_lo = translator_lduw(env, &ctx->base, ctx->base.pc_next); is_16bit = tricore_insn_is_16bit(insn_lo); if (is_16bit) { ctx->opcode = insn_lo; ctx->pc_succ_insn = ctx->base.pc_next + 2; decode_16Bit_opc(ctx); } else { - uint32_t insn_hi = cpu_lduw_code(env, ctx->base.pc_next + 2); + uint32_t insn_hi = translator_lduw(env, &ctx->base, + ctx->base.pc_next + 2); ctx->opcode = insn_hi << 16 | insn_lo; ctx->pc_succ_insn = ctx->base.pc_next + 4; decode_32Bit_opc(ctx); From 4f79db4750cbabed18f11cd791c5e5222a711fd5 Mon Sep 17 00:00:00 2001 From: Bastian Koppelmann Date: Mon, 28 Aug 2023 13:26:51 +0200 Subject: [PATCH 0025/1077] target/tricore: Fix FTOUZ being ISA v1.3.1 up Reviewed-by: Richard Henderson Signed-off-by: Bastian Koppelmann Message-ID: <20230828112651.522058-12-kbastian@mail.uni-paderborn.de> --- target/tricore/translate.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/target/tricore/translate.c b/target/tricore/translate.c index 2107d1fdd4..7b53307eff 100644 --- a/target/tricore/translate.c +++ b/target/tricore/translate.c @@ -6290,7 +6290,11 @@ static void decode_rr_divide(DisasContext *ctx) gen_helper_ftou(cpu_gpr_d[r3], cpu_env, cpu_gpr_d[r1]); break; case OPC2_32_RR_FTOUZ: - gen_helper_ftouz(cpu_gpr_d[r3], cpu_env, cpu_gpr_d[r1]); + if (has_feature(ctx, TRICORE_FEATURE_131)) { + gen_helper_ftouz(cpu_gpr_d[r3], cpu_env, cpu_gpr_d[r1]); + } else { + generate_trap(ctx, TRAPC_INSN_ERR, TIN2_IOPC); + } break; case OPC2_32_RR_UPDFL: gen_helper_updfl(cpu_env, cpu_gpr_d[r1]); From 8c3cf3f2bdf072b5ead13db81f1e6d879cd09bb6 Mon Sep 17 00:00:00 2001 From: Bastian Koppelmann Date: Wed, 13 Sep 2023 12:53:17 +0200 Subject: [PATCH 0026/1077] tests/tcg/tricore: Extended and non-extened regs now match RSx for d regs and e regs now use the same numbering. This makes sure that mixing d and e registers in an insn test will not overwrite data between registers. Signed-off-by: Bastian Koppelmann Message-ID: <20230913105326.40832-2-kbastian@mail.uni-paderborn.de> --- tests/tcg/tricore/asm/macros.h | 38 +++++++++++++++++----------------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/tests/tcg/tricore/asm/macros.h b/tests/tcg/tricore/asm/macros.h index 17e696bef5..0f349dbf1e 100644 --- a/tests/tcg/tricore/asm/macros.h +++ b/tests/tcg/tricore/asm/macros.h @@ -12,31 +12,31 @@ #define TESTDEV_ADDR 0xf0000000 /* Register definitions */ #define DREG_RS1 %d0 -#define DREG_RS2 %d1 -#define DREG_RS3 %d2 -#define DREG_CALC_RESULT %d3 -#define DREG_CALC_PSW %d4 -#define DREG_CORRECT_PSW %d5 -#define DREG_TEMP_LI %d10 -#define DREG_TEMP %d11 -#define DREG_TEST_NUM %d14 -#define DREG_CORRECT_RESULT %d15 -#define DREG_CORRECT_RESULT_2 %d13 +#define DREG_RS2 %d2 +#define DREG_RS3 %d4 +#define DREG_CALC_RESULT %d5 +#define DREG_CALC_PSW %d6 +#define DREG_CORRECT_PSW %d7 +#define DREG_TEMP_LI %d13 +#define DREG_TEMP %d14 +#define DREG_TEST_NUM %d8 +#define DREG_CORRECT_RESULT %d9 +#define DREG_CORRECT_RESULT_2 %d10 #define AREG_ADDR %a0 #define AREG_CORRECT_RESULT %a3 #define DREG_DEV_ADDR %a15 -#define EREG_RS1 %e6 -#define EREG_RS1_LO %d6 -#define EREG_RS1_HI %d7 -#define EREG_RS2 %e8 -#define EREG_RS2_LO %d8 -#define EREG_RS2_HI %d9 -#define EREG_CALC_RESULT %e8 -#define EREG_CALC_RESULT_HI %d9 -#define EREG_CALC_RESULT_LO %d8 +#define EREG_RS1 %e0 +#define EREG_RS1_LO %d0 +#define EREG_RS1_HI %d1 +#define EREG_RS2 %e2 +#define EREG_RS2_LO %d2 +#define EREG_RS2_HI %d3 +#define EREG_CALC_RESULT %e6 +#define EREG_CALC_RESULT_LO %d6 +#define EREG_CALC_RESULT_HI %d7 #define EREG_CORRECT_RESULT_LO %d0 #define EREG_CORRECT_RESULT_HI %d1 From f47a90dacca8f74210a2675bdde7ab3856872b94 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Thu, 14 Sep 2023 07:39:07 -0700 Subject: [PATCH 0027/1077] accel/tcg: Avoid load of icount_decr if unused MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit With CF_NOIRQ and without !CF_USE_ICOUNT, the load isn't used. Avoid emitting it. Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Richard Henderson --- accel/tcg/translator.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/accel/tcg/translator.c b/accel/tcg/translator.c index 1a6a5448c8..a3983019a5 100644 --- a/accel/tcg/translator.c +++ b/accel/tcg/translator.c @@ -49,12 +49,15 @@ bool translator_io_start(DisasContextBase *db) static TCGOp *gen_tb_start(uint32_t cflags) { - TCGv_i32 count = tcg_temp_new_i32(); + TCGv_i32 count = NULL; TCGOp *icount_start_insn = NULL; - tcg_gen_ld_i32(count, cpu_env, - offsetof(ArchCPU, neg.icount_decr.u32) - - offsetof(ArchCPU, env)); + if ((cflags & CF_USE_ICOUNT) || !(cflags & CF_NOIRQ)) { + count = tcg_temp_new_i32(); + tcg_gen_ld_i32(count, cpu_env, + offsetof(ArchCPU, neg.icount_decr.u32) - + offsetof(ArchCPU, env)); + } if (cflags & CF_USE_ICOUNT) { /* From 5d97e94638100fd3e5b8d76ab30e1066cd4b1823 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Thu, 14 Sep 2023 07:48:39 -0700 Subject: [PATCH 0028/1077] accel/tcg: Hoist CF_MEMI_ONLY check outside translation loop MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The condition checked is loop invariant; check it only once. Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Richard Henderson --- accel/tcg/translator.c | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/accel/tcg/translator.c b/accel/tcg/translator.c index a3983019a5..b6ab9f3d33 100644 --- a/accel/tcg/translator.c +++ b/accel/tcg/translator.c @@ -158,7 +158,13 @@ void translator_loop(CPUState *cpu, TranslationBlock *tb, int *max_insns, ops->tb_start(db, cpu); tcg_debug_assert(db->is_jmp == DISAS_NEXT); /* no early exit */ - plugin_enabled = plugin_gen_tb_start(cpu, db, cflags & CF_MEMI_ONLY); + if (cflags & CF_MEMI_ONLY) { + /* We should only see CF_MEMI_ONLY for io_recompile. */ + assert(cflags & CF_LAST_IO); + plugin_enabled = plugin_gen_tb_start(cpu, db, true); + } else { + plugin_enabled = plugin_gen_tb_start(cpu, db, false); + } while (true) { *max_insns = ++db->num_insns; @@ -176,12 +182,8 @@ void translator_loop(CPUState *cpu, TranslationBlock *tb, int *max_insns, if (db->num_insns == db->max_insns && (cflags & CF_LAST_IO)) { /* Accept I/O on the last instruction. */ gen_io_start(); - ops->translate_insn(db, cpu); - } else { - /* we should only see CF_MEMI_ONLY for io_recompile */ - tcg_debug_assert(!(cflags & CF_MEMI_ONLY)); - ops->translate_insn(db, cpu); } + ops->translate_insn(db, cpu); /* * We can't instrument after instructions that change control From 0ca41ccf1c555f97873b8e02a47390fd6af4b18f Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Thu, 14 Sep 2023 08:06:14 -0700 Subject: [PATCH 0029/1077] accel/tcg: Track current value of can_do_io in the TB MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Simplify translator_io_start by recording the current known value of can_do_io within DisasContextBase. Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Richard Henderson --- accel/tcg/translator.c | 31 ++++++++++++++----------------- include/exec/translator.h | 2 ++ 2 files changed, 16 insertions(+), 17 deletions(-) diff --git a/accel/tcg/translator.c b/accel/tcg/translator.c index b6ab9f3d33..850d82e26f 100644 --- a/accel/tcg/translator.c +++ b/accel/tcg/translator.c @@ -16,11 +16,14 @@ #include "tcg/tcg-op-common.h" #include "internal.h" -static void gen_io_start(void) +static void set_can_do_io(DisasContextBase *db, bool val) { - tcg_gen_st_i32(tcg_constant_i32(1), cpu_env, - offsetof(ArchCPU, parent_obj.can_do_io) - - offsetof(ArchCPU, env)); + if (db->saved_can_do_io != val) { + db->saved_can_do_io = val; + tcg_gen_st_i32(tcg_constant_i32(val), cpu_env, + offsetof(ArchCPU, parent_obj.can_do_io) - + offsetof(ArchCPU, env)); + } } bool translator_io_start(DisasContextBase *db) @@ -30,12 +33,8 @@ bool translator_io_start(DisasContextBase *db) if (!(cflags & CF_USE_ICOUNT)) { return false; } - if (db->num_insns == db->max_insns && (cflags & CF_LAST_IO)) { - /* Already started in translator_loop. */ - return true; - } - gen_io_start(); + set_can_do_io(db, true); /* * Ensure that this instruction will be the last in the TB. @@ -47,7 +46,7 @@ bool translator_io_start(DisasContextBase *db) return true; } -static TCGOp *gen_tb_start(uint32_t cflags) +static TCGOp *gen_tb_start(DisasContextBase *db, uint32_t cflags) { TCGv_i32 count = NULL; TCGOp *icount_start_insn = NULL; @@ -91,12 +90,9 @@ static TCGOp *gen_tb_start(uint32_t cflags) * cpu->can_do_io is cleared automatically here at the beginning of * each translation block. The cost is minimal and only paid for * -icount, plus it would be very easy to forget doing it in the - * translator. Doing it here means we don't need a gen_io_end() to - * go with gen_io_start(). + * translator. */ - tcg_gen_st_i32(tcg_constant_i32(0), cpu_env, - offsetof(ArchCPU, parent_obj.can_do_io) - - offsetof(ArchCPU, env)); + set_can_do_io(db, false); } return icount_start_insn; @@ -147,6 +143,7 @@ void translator_loop(CPUState *cpu, TranslationBlock *tb, int *max_insns, db->num_insns = 0; db->max_insns = *max_insns; db->singlestep_enabled = cflags & CF_SINGLE_STEP; + db->saved_can_do_io = -1; db->host_addr[0] = host_pc; db->host_addr[1] = NULL; @@ -154,7 +151,7 @@ void translator_loop(CPUState *cpu, TranslationBlock *tb, int *max_insns, tcg_debug_assert(db->is_jmp == DISAS_NEXT); /* no early exit */ /* Start translating. */ - icount_start_insn = gen_tb_start(cflags); + icount_start_insn = gen_tb_start(db, cflags); ops->tb_start(db, cpu); tcg_debug_assert(db->is_jmp == DISAS_NEXT); /* no early exit */ @@ -181,7 +178,7 @@ void translator_loop(CPUState *cpu, TranslationBlock *tb, int *max_insns, the next instruction. */ if (db->num_insns == db->max_insns && (cflags & CF_LAST_IO)) { /* Accept I/O on the last instruction. */ - gen_io_start(); + set_can_do_io(db, true); } ops->translate_insn(db, cpu); diff --git a/include/exec/translator.h b/include/exec/translator.h index 4e17c4f401..9d9e980819 100644 --- a/include/exec/translator.h +++ b/include/exec/translator.h @@ -72,6 +72,7 @@ typedef enum DisasJumpType { * @num_insns: Number of translated instructions (including current). * @max_insns: Maximum number of instructions to be translated in this TB. * @singlestep_enabled: "Hardware" single stepping enabled. + * @saved_can_do_io: Known value of cpu->neg.can_do_io, or -1 for unknown. * * Architecture-agnostic disassembly context. */ @@ -83,6 +84,7 @@ typedef struct DisasContextBase { int num_insns; int max_insns; bool singlestep_enabled; + int8_t saved_can_do_io; void *host_addr[2]; } DisasContextBase; From a2f99d484c54adda13e62bf75ba512618a3fe470 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Thu, 14 Sep 2023 08:26:47 -0700 Subject: [PATCH 0030/1077] accel/tcg: Improve setting of can_do_io at start of TB MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Initialize can_do_io to true if this the TB has CF_LAST_IO and will consist of a single instruction. This avoids a set to 0 followed immediately by a set to 1. Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Richard Henderson --- accel/tcg/translator.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/accel/tcg/translator.c b/accel/tcg/translator.c index 850d82e26f..dd507cd471 100644 --- a/accel/tcg/translator.c +++ b/accel/tcg/translator.c @@ -87,12 +87,12 @@ static TCGOp *gen_tb_start(DisasContextBase *db, uint32_t cflags) offsetof(ArchCPU, neg.icount_decr.u16.low) - offsetof(ArchCPU, env)); /* - * cpu->can_do_io is cleared automatically here at the beginning of + * cpu->can_do_io is set automatically here at the beginning of * each translation block. The cost is minimal and only paid for * -icount, plus it would be very easy to forget doing it in the * translator. */ - set_can_do_io(db, false); + set_can_do_io(db, db->max_insns == 1 && (cflags & CF_LAST_IO)); } return icount_start_insn; From 200c1f904f46c209cb022e711a48b89e46512902 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Thu, 14 Sep 2023 08:36:11 -0700 Subject: [PATCH 0031/1077] accel/tcg: Always set CF_LAST_IO with CF_NOIRQ MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Without this we can get see loops through cpu_io_recompile, in which the cpu makes no progress. Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Richard Henderson --- accel/tcg/cpu-exec.c | 2 +- accel/tcg/tb-maint.c | 6 ++++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/accel/tcg/cpu-exec.c b/accel/tcg/cpu-exec.c index e2c494e75e..c724e8b6f1 100644 --- a/accel/tcg/cpu-exec.c +++ b/accel/tcg/cpu-exec.c @@ -720,7 +720,7 @@ static inline bool cpu_handle_exception(CPUState *cpu, int *ret) && cpu_neg(cpu)->icount_decr.u16.low + cpu->icount_extra == 0) { /* Execute just one insn to trigger exception pending in the log */ cpu->cflags_next_tb = (curr_cflags(cpu) & ~CF_USE_ICOUNT) - | CF_NOIRQ | 1; + | CF_LAST_IO | CF_NOIRQ | 1; } #endif return false; diff --git a/accel/tcg/tb-maint.c b/accel/tcg/tb-maint.c index 32ae8af61c..0c3e227409 100644 --- a/accel/tcg/tb-maint.c +++ b/accel/tcg/tb-maint.c @@ -1083,7 +1083,8 @@ bool tb_invalidate_phys_page_unwind(tb_page_addr_t addr, uintptr_t pc) if (current_tb_modified) { /* Force execution of one insn next time. */ CPUState *cpu = current_cpu; - cpu->cflags_next_tb = 1 | CF_NOIRQ | curr_cflags(current_cpu); + cpu->cflags_next_tb = + 1 | CF_LAST_IO | CF_NOIRQ | curr_cflags(current_cpu); return true; } return false; @@ -1153,7 +1154,8 @@ tb_invalidate_phys_page_range__locked(struct page_collection *pages, if (current_tb_modified) { page_collection_unlock(pages); /* Force execution of one insn next time. */ - current_cpu->cflags_next_tb = 1 | CF_NOIRQ | curr_cflags(current_cpu); + current_cpu->cflags_next_tb = + 1 | CF_LAST_IO | CF_NOIRQ | curr_cflags(current_cpu); mmap_unlock(); cpu_loop_exit_noexc(current_cpu); } From 18a536f1f8d6222e562f59179e837fdfd8b92718 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Tue, 12 Sep 2023 19:08:11 -0700 Subject: [PATCH 0032/1077] accel/tcg: Always require can_do_io MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Require i/o as the last insn of a TranslationBlock always, not only with icount. This is required for i/o that alters the address space, such as a pci config space write. Resolves: https://gitlab.com/qemu-project/qemu/-/issues/1866 Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Richard Henderson --- accel/tcg/translator.c | 20 +++++++------------- target/mips/tcg/translate.c | 1 - 2 files changed, 7 insertions(+), 14 deletions(-) diff --git a/accel/tcg/translator.c b/accel/tcg/translator.c index dd507cd471..358214d526 100644 --- a/accel/tcg/translator.c +++ b/accel/tcg/translator.c @@ -28,12 +28,6 @@ static void set_can_do_io(DisasContextBase *db, bool val) bool translator_io_start(DisasContextBase *db) { - uint32_t cflags = tb_cflags(db->tb); - - if (!(cflags & CF_USE_ICOUNT)) { - return false; - } - set_can_do_io(db, true); /* @@ -86,15 +80,15 @@ static TCGOp *gen_tb_start(DisasContextBase *db, uint32_t cflags) tcg_gen_st16_i32(count, cpu_env, offsetof(ArchCPU, neg.icount_decr.u16.low) - offsetof(ArchCPU, env)); - /* - * cpu->can_do_io is set automatically here at the beginning of - * each translation block. The cost is minimal and only paid for - * -icount, plus it would be very easy to forget doing it in the - * translator. - */ - set_can_do_io(db, db->max_insns == 1 && (cflags & CF_LAST_IO)); } + /* + * cpu->can_do_io is set automatically here at the beginning of + * each translation block. The cost is minimal, plus it would be + * very easy to forget doing it in the translator. + */ + set_can_do_io(db, db->max_insns == 1 && (cflags & CF_LAST_IO)); + return icount_start_insn; } diff --git a/target/mips/tcg/translate.c b/target/mips/tcg/translate.c index 9bb40f1849..593fc80458 100644 --- a/target/mips/tcg/translate.c +++ b/target/mips/tcg/translate.c @@ -11212,7 +11212,6 @@ static void gen_branch(DisasContext *ctx, int insn_bytes) /* Branches completion */ clear_branch_hflags(ctx); ctx->base.is_jmp = DISAS_NORETURN; - /* FIXME: Need to clear can_do_io. */ switch (proc_hflags & MIPS_HFLAG_BMASK_BASE) { case MIPS_HFLAG_FBNSLOT: gen_goto_tb(ctx, 0, ctx->base.pc_next + insn_bytes); From bbde656263d80429b51017b077d9b4064ba13b01 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Thu, 21 Sep 2023 14:13:06 +0200 Subject: [PATCH 0033/1077] migration/rdma: Fix save_page method to fail on polling error qemu_rdma_save_page() reports polling error with error_report(), then succeeds anyway. This is because the variable holding the polling status *shadows* the variable the function returns. The latter remains zero. Broken since day one, and duplicated more recently. Fixes: 2da776db4846 (rdma: core logic) Fixes: b390afd8c50b (migration/rdma: Fix out of order wrid) Signed-off-by: Markus Armbruster Reviewed-by: Eric Blake Reviewed-by: Peter Xu Reviewed-by: Li Zhijian Message-ID: <20230921121312.1301864-2-armbru@redhat.com> --- migration/rdma.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/migration/rdma.c b/migration/rdma.c index a2a3db35b1..3915d1d7c9 100644 --- a/migration/rdma.c +++ b/migration/rdma.c @@ -3282,7 +3282,8 @@ static size_t qemu_rdma_save_page(QEMUFile *f, */ while (1) { uint64_t wr_id, wr_id_in; - int ret = qemu_rdma_poll(rdma, rdma->recv_cq, &wr_id_in, NULL); + ret = qemu_rdma_poll(rdma, rdma->recv_cq, &wr_id_in, NULL); + if (ret < 0) { error_report("rdma migration: polling error! %d", ret); goto err; @@ -3297,7 +3298,8 @@ static size_t qemu_rdma_save_page(QEMUFile *f, while (1) { uint64_t wr_id, wr_id_in; - int ret = qemu_rdma_poll(rdma, rdma->send_cq, &wr_id_in, NULL); + ret = qemu_rdma_poll(rdma, rdma->send_cq, &wr_id_in, NULL); + if (ret < 0) { error_report("rdma migration: polling error! %d", ret); goto err; From 7f3de3f02f0bd0eaa3ba4506f9a60c1c35865e93 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Thu, 21 Sep 2023 14:13:07 +0200 Subject: [PATCH 0034/1077] migration: Clean up local variable shadowing Local variables shadowing other local variables or parameters make the code needlessly hard to understand. Tracked down with -Wshadow=local. Clean up: delete inner declarations when they are actually redundant, else rename variables. Signed-off-by: Markus Armbruster Reviewed-by: Peter Xu Reviewed-by: Li Zhijian Message-ID: <20230921121312.1301864-3-armbru@redhat.com> --- migration/block.c | 4 ++-- migration/ram.c | 8 +++----- migration/rdma.c | 8 +++++--- migration/vmstate.c | 2 +- 4 files changed, 11 insertions(+), 11 deletions(-) diff --git a/migration/block.c b/migration/block.c index 86c2256a2b..eb6aafeb9e 100644 --- a/migration/block.c +++ b/migration/block.c @@ -440,8 +440,8 @@ static int init_blk_migration(QEMUFile *f) /* Can only insert new BDSes now because doing so while iterating block * devices may end up in a deadlock (iterating the new BDSes, too). */ for (i = 0; i < num_bs; i++) { - BlkMigDevState *bmds = bmds_bs[i].bmds; - BlockDriverState *bs = bmds_bs[i].bs; + bmds = bmds_bs[i].bmds; + bs = bmds_bs[i].bs; if (bmds) { ret = blk_insert_bs(bmds->blk, bs, &local_err); diff --git a/migration/ram.c b/migration/ram.c index 9040d66e61..0c202f8109 100644 --- a/migration/ram.c +++ b/migration/ram.c @@ -3517,8 +3517,6 @@ int colo_init_ram_cache(void) * we use the same name 'ram_bitmap' as for migration. */ if (ram_bytes_total()) { - RAMBlock *block; - RAMBLOCK_FOREACH_NOT_IGNORED(block) { unsigned long pages = block->max_length >> TARGET_PAGE_BITS; block->bmap = bitmap_new(pages); @@ -3998,12 +3996,12 @@ static int ram_load_precopy(QEMUFile *f) } } if (migrate_ignore_shared()) { - hwaddr addr = qemu_get_be64(f); + hwaddr addr2 = qemu_get_be64(f); if (migrate_ram_is_ignored(block) && - block->mr->addr != addr) { + block->mr->addr != addr2) { error_report("Mismatched GPAs for block %s " "%" PRId64 "!= %" PRId64, - id, (uint64_t)addr, + id, (uint64_t)addr2, (uint64_t)block->mr->addr); ret = -EINVAL; } diff --git a/migration/rdma.c b/migration/rdma.c index 3915d1d7c9..c78ddfcb74 100644 --- a/migration/rdma.c +++ b/migration/rdma.c @@ -1902,9 +1902,11 @@ static int qemu_rdma_exchange_send(RDMAContext *rdma, RDMAControlHeader *head, * by waiting for a READY message. */ if (rdma->control_ready_expected) { - RDMAControlHeader resp; - ret = qemu_rdma_exchange_get_response(rdma, - &resp, RDMA_CONTROL_READY, RDMA_WRID_READY); + RDMAControlHeader resp_ignored; + + ret = qemu_rdma_exchange_get_response(rdma, &resp_ignored, + RDMA_CONTROL_READY, + RDMA_WRID_READY); if (ret < 0) { return ret; } diff --git a/migration/vmstate.c b/migration/vmstate.c index 31842c3afb..438ea77cfa 100644 --- a/migration/vmstate.c +++ b/migration/vmstate.c @@ -97,7 +97,7 @@ int vmstate_load_state(QEMUFile *f, const VMStateDescription *vmsd, return -EINVAL; } if (vmsd->pre_load) { - int ret = vmsd->pre_load(opaque); + ret = vmsd->pre_load(opaque); if (ret) { return ret; } From e33e66b1b3655d98aadebf7e22eae18077698401 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Thu, 21 Sep 2023 14:13:08 +0200 Subject: [PATCH 0035/1077] ui: Clean up local variable shadowing Local variables shadowing other local variables or parameters make the code needlessly hard to understand. Tracked down with -Wshadow=local. Clean up: delete inner declarations when they are actually redundant, else rename variables. Signed-off-by: Markus Armbruster Reviewed-by: Peter Maydell Message-ID: <20230921121312.1301864-4-armbru@redhat.com> --- ui/gtk.c | 14 +++++++------- ui/spice-display.c | 9 +++++---- ui/vnc-enc-zrle.c.inc | 9 ++++----- ui/vnc-palette.c | 2 -- ui/vnc.c | 12 ++++++------ 5 files changed, 22 insertions(+), 24 deletions(-) diff --git a/ui/gtk.c b/ui/gtk.c index e09f97a86b..3373427c9b 100644 --- a/ui/gtk.c +++ b/ui/gtk.c @@ -930,8 +930,8 @@ static gboolean gd_motion_event(GtkWidget *widget, GdkEventMotion *motion, GdkMonitor *monitor = gdk_display_get_monitor_at_window(dpy, win); GdkRectangle geometry; - int x = (int)motion->x_root; - int y = (int)motion->y_root; + int xr = (int)motion->x_root; + int yr = (int)motion->y_root; gdk_monitor_get_geometry(monitor, &geometry); @@ -942,13 +942,13 @@ static gboolean gd_motion_event(GtkWidget *widget, GdkEventMotion *motion, * may still be only half way across the screen. Without * this warp, the server pointer would thus appear to hit * an invisible wall */ - if (x <= geometry.x || x - geometry.x >= geometry.width - 1 || - y <= geometry.y || y - geometry.y >= geometry.height - 1) { + if (xr <= geometry.x || xr - geometry.x >= geometry.width - 1 || + yr <= geometry.y || yr - geometry.y >= geometry.height - 1) { GdkDevice *dev = gdk_event_get_device((GdkEvent *)motion); - x = geometry.x + geometry.width / 2; - y = geometry.y + geometry.height / 2; + xr = geometry.x + geometry.width / 2; + yr = geometry.y + geometry.height / 2; - gdk_device_warp(dev, screen, x, y); + gdk_device_warp(dev, screen, xr, yr); s->last_set = FALSE; return FALSE; } diff --git a/ui/spice-display.c b/ui/spice-display.c index 5cc47bd668..6eb98a5a5c 100644 --- a/ui/spice-display.c +++ b/ui/spice-display.c @@ -1081,15 +1081,16 @@ static void qemu_spice_gl_update(DisplayChangeListener *dcl, } if (render_cursor) { - int x, y; + int ptr_x, ptr_y; + qemu_mutex_lock(&ssd->lock); - x = ssd->ptr_x; - y = ssd->ptr_y; + ptr_x = ssd->ptr_x; + ptr_y = ssd->ptr_y; qemu_mutex_unlock(&ssd->lock); egl_texture_blit(ssd->gls, &ssd->blit_fb, &ssd->guest_fb, !y_0_top); egl_texture_blend(ssd->gls, &ssd->blit_fb, &ssd->cursor_fb, - !y_0_top, x, y, 1.0, 1.0); + !y_0_top, ptr_x, ptr_y, 1.0, 1.0); glFlush(); } diff --git a/ui/vnc-enc-zrle.c.inc b/ui/vnc-enc-zrle.c.inc index a8ca37d05e..2ef7501d52 100644 --- a/ui/vnc-enc-zrle.c.inc +++ b/ui/vnc-enc-zrle.c.inc @@ -153,11 +153,12 @@ static void ZRLE_ENCODE_TILE(VncState *vs, ZRLE_PIXEL *data, int w, int h, } if (use_rle) { - ZRLE_PIXEL *ptr = data; - ZRLE_PIXEL *end = ptr + w * h; ZRLE_PIXEL *run_start; ZRLE_PIXEL pix; + ptr = data; + end = ptr + w * h; + while (ptr < end) { int len; int index = 0; @@ -198,7 +199,7 @@ static void ZRLE_ENCODE_TILE(VncState *vs, ZRLE_PIXEL *data, int w, int h, } } else if (use_palette) { /* no RLE */ int bppp; - ZRLE_PIXEL *ptr = data; + ptr = data; /* packed pixels */ @@ -241,8 +242,6 @@ static void ZRLE_ENCODE_TILE(VncState *vs, ZRLE_PIXEL *data, int w, int h, #endif { #ifdef ZRLE_COMPACT_PIXEL - ZRLE_PIXEL *ptr; - for (ptr = data; ptr < data + w * h; ptr++) { ZRLE_WRITE_PIXEL(vs, *ptr); } diff --git a/ui/vnc-palette.c b/ui/vnc-palette.c index dc7c0ba997..4e88c412f0 100644 --- a/ui/vnc-palette.c +++ b/ui/vnc-palette.c @@ -86,8 +86,6 @@ int palette_put(VncPalette *palette, uint32_t color) return 0; } if (!entry) { - VncPaletteEntry *entry; - entry = &palette->pool[palette->size]; entry->color = color; entry->idx = idx; diff --git a/ui/vnc.c b/ui/vnc.c index c302bb07a5..523eb1f5b0 100644 --- a/ui/vnc.c +++ b/ui/vnc.c @@ -1584,15 +1584,15 @@ static void vnc_jobs_bh(void *opaque) */ static int vnc_client_read(VncState *vs) { - size_t ret; + size_t sz; #ifdef CONFIG_VNC_SASL if (vs->sasl.conn && vs->sasl.runSSF) - ret = vnc_client_read_sasl(vs); + sz = vnc_client_read_sasl(vs); else #endif /* CONFIG_VNC_SASL */ - ret = vnc_client_read_plain(vs); - if (!ret) { + sz = vnc_client_read_plain(vs); + if (!sz) { if (vs->disconnecting) { vnc_disconnect_finish(vs); return -1; @@ -3118,8 +3118,8 @@ static int vnc_refresh_server_surface(VncDisplay *vd) cmp_bytes = MIN(VNC_DIRTY_PIXELS_PER_BIT * VNC_SERVER_FB_BYTES, server_stride); if (vd->guest.format != VNC_SERVER_FB_FORMAT) { - int width = pixman_image_get_width(vd->server); - tmpbuf = qemu_pixman_linebuf_create(VNC_SERVER_FB_FORMAT, width); + int w = pixman_image_get_width(vd->server); + tmpbuf = qemu_pixman_linebuf_create(VNC_SERVER_FB_FORMAT, w); } else { int guest_bpp = PIXMAN_FORMAT_BPP(pixman_image_get_format(vd->guest.fb)); From 6a0f7ff7dd2034fb167557f0444e1f1851dbd654 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Thu, 21 Sep 2023 14:13:09 +0200 Subject: [PATCH 0036/1077] block/dirty-bitmap: Clean up local variable shadowing Local variables shadowing other local variables or parameters make the code needlessly hard to understand. Tracked down with -Wshadow=local. Clean up: rename both the pair of parameters and the pair of local variables. While there, move the local variables to function scope. Suggested-by: Kevin Wolf Signed-off-by: Markus Armbruster Reviewed-by: Kevin Wolf Message-ID: <20230921121312.1301864-5-armbru@redhat.com> --- block/monitor/bitmap-qmp-cmds.c | 19 ++++++++++--------- block/qcow2-bitmap.c | 3 +-- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/block/monitor/bitmap-qmp-cmds.c b/block/monitor/bitmap-qmp-cmds.c index 55f778f5af..70d01a3776 100644 --- a/block/monitor/bitmap-qmp-cmds.c +++ b/block/monitor/bitmap-qmp-cmds.c @@ -258,37 +258,38 @@ void qmp_block_dirty_bitmap_disable(const char *node, const char *name, bdrv_disable_dirty_bitmap(bitmap); } -BdrvDirtyBitmap *block_dirty_bitmap_merge(const char *node, const char *target, +BdrvDirtyBitmap *block_dirty_bitmap_merge(const char *dst_node, + const char *dst_bitmap, BlockDirtyBitmapOrStrList *bms, HBitmap **backup, Error **errp) { BlockDriverState *bs; BdrvDirtyBitmap *dst, *src; BlockDirtyBitmapOrStrList *lst; + const char *src_node, *src_bitmap; HBitmap *local_backup = NULL; GLOBAL_STATE_CODE(); - dst = block_dirty_bitmap_lookup(node, target, &bs, errp); + dst = block_dirty_bitmap_lookup(dst_node, dst_bitmap, &bs, errp); if (!dst) { return NULL; } for (lst = bms; lst; lst = lst->next) { switch (lst->value->type) { - const char *name, *node; case QTYPE_QSTRING: - name = lst->value->u.local; - src = bdrv_find_dirty_bitmap(bs, name); + src_bitmap = lst->value->u.local; + src = bdrv_find_dirty_bitmap(bs, src_bitmap); if (!src) { - error_setg(errp, "Dirty bitmap '%s' not found", name); + error_setg(errp, "Dirty bitmap '%s' not found", src_bitmap); goto fail; } break; case QTYPE_QDICT: - node = lst->value->u.external.node; - name = lst->value->u.external.name; - src = block_dirty_bitmap_lookup(node, name, NULL, errp); + src_node = lst->value->u.external.node; + src_bitmap = lst->value->u.external.name; + src = block_dirty_bitmap_lookup(src_node, src_bitmap, NULL, errp); if (!src) { goto fail; } diff --git a/block/qcow2-bitmap.c b/block/qcow2-bitmap.c index 037fa2d435..ffd5cd3b23 100644 --- a/block/qcow2-bitmap.c +++ b/block/qcow2-bitmap.c @@ -1555,7 +1555,6 @@ bool qcow2_store_persistent_dirty_bitmaps(BlockDriverState *bs, FOR_EACH_DIRTY_BITMAP(bs, bitmap) { const char *name = bdrv_dirty_bitmap_name(bitmap); uint32_t granularity = bdrv_dirty_bitmap_granularity(bitmap); - Qcow2Bitmap *bm; if (!bdrv_dirty_bitmap_get_persistence(bitmap) || bdrv_dirty_bitmap_inconsistent(bitmap)) { @@ -1625,7 +1624,7 @@ bool qcow2_store_persistent_dirty_bitmaps(BlockDriverState *bs, /* allocate clusters and store bitmaps */ QSIMPLEQ_FOREACH(bm, bm_list, entry) { - BdrvDirtyBitmap *bitmap = bm->dirty_bitmap; + bitmap = bm->dirty_bitmap; if (bitmap == NULL || bdrv_dirty_bitmap_readonly(bitmap)) { continue; From d25b99c72b0178ce0e0c766b07011102dbbacf6a Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Thu, 21 Sep 2023 14:13:10 +0200 Subject: [PATCH 0037/1077] block/vdi: Clean up local variable shadowing Local variables shadowing other local variables or parameters make the code needlessly hard to understand. Tracked down with -Wshadow=local. Clean up: delete inner declarations when they are actually redundant, else rename variables. Signed-off-by: Markus Armbruster Reviewed-by: Stefan Hajnoczi Reviewed-by: Kevin Wolf Message-ID: <20230921121312.1301864-6-armbru@redhat.com> --- block/vdi.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/block/vdi.c b/block/vdi.c index 6c35309e04..934e1b849b 100644 --- a/block/vdi.c +++ b/block/vdi.c @@ -634,7 +634,6 @@ vdi_co_pwritev(BlockDriverState *bs, int64_t offset, int64_t bytes, bmap_entry = le32_to_cpu(s->bmap[block_index]); if (!VDI_IS_ALLOCATED(bmap_entry)) { /* Allocate new block and write to it. */ - uint64_t data_offset; qemu_co_rwlock_upgrade(&s->bmap_lock); bmap_entry = le32_to_cpu(s->bmap[block_index]); if (VDI_IS_ALLOCATED(bmap_entry)) { @@ -700,7 +699,7 @@ nonallocating_write: /* One or more new blocks were allocated. */ VdiHeader *header; uint8_t *base; - uint64_t offset; + uint64_t bmap_offset; uint32_t n_sectors; g_free(block); @@ -723,11 +722,11 @@ nonallocating_write: bmap_first /= (SECTOR_SIZE / sizeof(uint32_t)); bmap_last /= (SECTOR_SIZE / sizeof(uint32_t)); n_sectors = bmap_last - bmap_first + 1; - offset = s->bmap_sector + bmap_first; + bmap_offset = s->bmap_sector + bmap_first; base = ((uint8_t *)&s->bmap[0]) + bmap_first * SECTOR_SIZE; logout("will write %u block map sectors starting from entry %u\n", n_sectors, bmap_first); - ret = bdrv_co_pwrite(bs->file, offset * SECTOR_SIZE, + ret = bdrv_co_pwrite(bs->file, bmap_offset * SECTOR_SIZE, n_sectors * SECTOR_SIZE, base, 0); } From fb2575f95411644abe7f0606594035b63a5132ad Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Thu, 21 Sep 2023 14:13:11 +0200 Subject: [PATCH 0038/1077] block: Clean up local variable shadowing Local variables shadowing other local variables or parameters make the code needlessly hard to understand. Tracked down with -Wshadow=local. Clean up: delete inner declarations when they are actually redundant, else rename variables. Signed-off-by: Markus Armbruster Reviewed-by: Stefan Hajnoczi Acked-by: Anthony PERARD Acked-by: Ilya Dryomov Reviewed-by: Kevin Wolf Message-ID: <20230921121312.1301864-7-armbru@redhat.com> --- block.c | 9 +++++---- block/rbd.c | 2 +- block/stream.c | 1 - block/vvfat.c | 35 ++++++++++++++++++----------------- hw/block/xen-block.c | 6 +++--- 5 files changed, 27 insertions(+), 26 deletions(-) diff --git a/block.c b/block.c index e7f349b25c..af04c8ac6f 100644 --- a/block.c +++ b/block.c @@ -3072,18 +3072,19 @@ bdrv_attach_child_common(BlockDriverState *child_bs, &local_err); if (ret < 0 && child_class->change_aio_ctx) { - Transaction *tran = tran_new(); + Transaction *aio_ctx_tran = tran_new(); GHashTable *visited = g_hash_table_new(NULL, NULL); bool ret_child; g_hash_table_add(visited, new_child); ret_child = child_class->change_aio_ctx(new_child, child_ctx, - visited, tran, NULL); + visited, aio_ctx_tran, + NULL); if (ret_child == true) { error_free(local_err); ret = 0; } - tran_finalize(tran, ret_child == true ? 0 : -1); + tran_finalize(aio_ctx_tran, ret_child == true ? 0 : -1); g_hash_table_destroy(visited); } @@ -6208,12 +6209,12 @@ void bdrv_iterate_format(void (*it)(void *opaque, const char *name), QLIST_FOREACH(drv, &bdrv_drivers, list) { if (drv->format_name) { bool found = false; - int i = count; if (use_bdrv_whitelist && !bdrv_is_whitelisted(drv, read_only)) { continue; } + i = count; while (formats && i && !found) { found = !strcmp(formats[--i], drv->format_name); } diff --git a/block/rbd.c b/block/rbd.c index 978671411e..472ca05cba 100644 --- a/block/rbd.c +++ b/block/rbd.c @@ -1290,7 +1290,7 @@ static int coroutine_fn qemu_rbd_start_co(BlockDriverState *bs, * operations that exceed the current size. */ if (offset + bytes > s->image_size) { - int r = qemu_rbd_resize(bs, offset + bytes); + r = qemu_rbd_resize(bs, offset + bytes); if (r < 0) { return r; } diff --git a/block/stream.c b/block/stream.c index e4da214f1f..133cb72fb4 100644 --- a/block/stream.c +++ b/block/stream.c @@ -292,7 +292,6 @@ void stream_start(const char *job_id, BlockDriverState *bs, /* Make sure that the image is opened in read-write mode */ bs_read_only = bdrv_is_read_only(bs); if (bs_read_only) { - int ret; /* Hold the chain during reopen */ if (bdrv_freeze_backing_chain(bs, above_base, errp) < 0) { return; diff --git a/block/vvfat.c b/block/vvfat.c index 0ddc91fc09..856b479c91 100644 --- a/block/vvfat.c +++ b/block/vvfat.c @@ -777,7 +777,6 @@ static int read_directory(BDRVVVFATState* s, int mapping_index) while((entry=readdir(dir))) { unsigned int length=strlen(dirname)+2+strlen(entry->d_name); char* buffer; - direntry_t* direntry; struct stat st; int is_dot=!strcmp(entry->d_name,"."); int is_dotdot=!strcmp(entry->d_name,".."); @@ -857,7 +856,7 @@ static int read_directory(BDRVVVFATState* s, int mapping_index) /* fill with zeroes up to the end of the cluster */ while(s->directory.next%(0x10*s->sectors_per_cluster)) { - direntry_t* direntry=array_get_next(&(s->directory)); + direntry = array_get_next(&(s->directory)); memset(direntry,0,sizeof(direntry_t)); } @@ -1962,24 +1961,24 @@ get_cluster_count_for_direntry(BDRVVVFATState* s, direntry_t* direntry, const ch * This is horribly inefficient, but that is okay, since * it is rarely executed, if at all. */ - int64_t offset = cluster2sector(s, cluster_num); + int64_t offs = cluster2sector(s, cluster_num); vvfat_close_current_file(s); for (i = 0; i < s->sectors_per_cluster; i++) { int res; res = bdrv_is_allocated(s->qcow->bs, - (offset + i) * BDRV_SECTOR_SIZE, + (offs + i) * BDRV_SECTOR_SIZE, BDRV_SECTOR_SIZE, NULL); if (res < 0) { return -1; } if (!res) { - res = vvfat_read(s->bs, offset, s->cluster_buffer, 1); + res = vvfat_read(s->bs, offs, s->cluster_buffer, 1); if (res) { return -1; } - res = bdrv_co_pwrite(s->qcow, offset * BDRV_SECTOR_SIZE, + res = bdrv_co_pwrite(s->qcow, offs * BDRV_SECTOR_SIZE, BDRV_SECTOR_SIZE, s->cluster_buffer, 0); if (res < 0) { @@ -2467,8 +2466,9 @@ commit_direntries(BDRVVVFATState* s, int dir_index, int parent_mapping_index) for (c = first_cluster; !fat_eof(s, c); c = modified_fat_get(s, c)) { direntry_t *first_direntry; - void* direntry = array_get(&(s->directory), current_dir_index); - int ret = vvfat_read(s->bs, cluster2sector(s, c), direntry, + + direntry = array_get(&(s->directory), current_dir_index); + ret = vvfat_read(s->bs, cluster2sector(s, c), (uint8_t *)direntry, s->sectors_per_cluster); if (ret) return ret; @@ -2690,12 +2690,12 @@ static int handle_renames_and_mkdirs(BDRVVVFATState* s) direntry_t* direntry = array_get(&(s->directory), mapping->info.dir.first_dir_index); uint32_t c = mapping->begin; - int i = 0; + int j = 0; /* recurse */ while (!fat_eof(s, c)) { do { - direntry_t* d = direntry + i; + direntry_t *d = direntry + j; if (is_file(d) || (is_directory(d) && !is_dot(d))) { int l; @@ -2716,8 +2716,8 @@ static int handle_renames_and_mkdirs(BDRVVVFATState* s) schedule_rename(s, m->begin, new_path); } - i++; - } while((i % (0x10 * s->sectors_per_cluster)) != 0); + j++; + } while (j % (0x10 * s->sectors_per_cluster) != 0); c = fat_get(s, c); } } @@ -2804,16 +2804,16 @@ static int coroutine_fn GRAPH_RDLOCK handle_commits(BDRVVVFATState* s) int begin = commit->param.new_file.first_cluster; mapping_t* mapping = find_mapping_for_cluster(s, begin); direntry_t* entry; - int i; + int j; /* find direntry */ - for (i = 0; i < s->directory.next; i++) { - entry = array_get(&(s->directory), i); + for (j = 0; j < s->directory.next; j++) { + entry = array_get(&(s->directory), j); if (is_file(entry) && begin_of_direntry(entry) == begin) break; } - if (i >= s->directory.next) { + if (j >= s->directory.next) { fail = -6; continue; } @@ -2833,8 +2833,9 @@ static int coroutine_fn GRAPH_RDLOCK handle_commits(BDRVVVFATState* s) mapping->mode = MODE_NORMAL; mapping->info.file.offset = 0; - if (commit_one_file(s, i, 0)) + if (commit_one_file(s, j, 0)) { fail = -7; + } break; } diff --git a/hw/block/xen-block.c b/hw/block/xen-block.c index 3906b9058b..a07cd7eb5d 100644 --- a/hw/block/xen-block.c +++ b/hw/block/xen-block.c @@ -369,7 +369,7 @@ static void xen_block_get_vdev(Object *obj, Visitor *v, const char *name, case XEN_BLOCK_VDEV_TYPE_XVD: case XEN_BLOCK_VDEV_TYPE_HD: case XEN_BLOCK_VDEV_TYPE_SD: { - char *name = disk_to_vbd_name(vdev->disk); + char *vbd_name = disk_to_vbd_name(vdev->disk); str = g_strdup_printf("%s%s%lu", (vdev->type == XEN_BLOCK_VDEV_TYPE_XVD) ? @@ -377,8 +377,8 @@ static void xen_block_get_vdev(Object *obj, Visitor *v, const char *name, (vdev->type == XEN_BLOCK_VDEV_TYPE_HD) ? "hd" : "sd", - name, vdev->partition); - g_free(name); + vbd_name, vdev->partition); + g_free(vbd_name); break; } default: From bb71846325e23d884ca4ff1bcc95aaead0131a5a Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Thu, 21 Sep 2023 14:13:12 +0200 Subject: [PATCH 0039/1077] qobject atomics osdep: Make a few macros more hygienic MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Variables declared in macros can shadow other variables. Much of the time, this is harmless, e.g.: #define _FDT(exp) \ do { \ int ret = (exp); \ if (ret < 0) { \ error_report("error creating device tree: %s: %s", \ #exp, fdt_strerror(ret)); \ exit(1); \ } \ } while (0) Harmless shadowing in h_client_architecture_support(): target_ulong ret; [...] ret = do_client_architecture_support(cpu, spapr, vec, fdt_bufsize); if (ret == H_SUCCESS) { _FDT((fdt_pack(spapr->fdt_blob))); [...] } return ret; However, we can get in trouble when the shadowed variable is used in a macro argument: #define QOBJECT(obj) ({ \ typeof(obj) o = (obj); \ o ? container_of(&(o)->base, QObject, base) : NULL; \ }) QOBJECT(o) expands into ({ ---> typeof(o) o = (o); o ? container_of(&(o)->base, QObject, base) : NULL; }) Unintended variable name capture at --->. We'd be saved by -Winit-self. But I could certainly construct more elaborate death traps that don't trigger it. To reduce the risk of trapping ourselves, we use variable names in macros that no sane person would use elsewhere. Here's our actual definition of QOBJECT(): #define QOBJECT(obj) ({ \ typeof(obj) _obj = (obj); \ _obj ? container_of(&(_obj)->base, QObject, base) : NULL; \ }) Works well enough until we nest macro calls. For instance, with #define qobject_ref(obj) ({ \ typeof(obj) _obj = (obj); \ qobject_ref_impl(QOBJECT(_obj)); \ _obj; \ }) the expression qobject_ref(obj) expands into ({ typeof(obj) _obj = (obj); qobject_ref_impl( ({ ---> typeof(_obj) _obj = (_obj); _obj ? container_of(&(_obj)->base, QObject, base) : NULL; })); _obj; }) Unintended variable name capture at --->. The only reliable way to prevent unintended variable name capture is -Wshadow. One blocker for enabling it is shadowing hiding in function-like macros like qdict_put(dict, "name", qobject_ref(...)) qdict_put() wraps its last argument in QOBJECT(), and the last argument here contains another QOBJECT(). Use dark preprocessor sorcery to make the macros that give us this problem use different variable names on every call. Signed-off-by: Markus Armbruster Reviewed-by: Eric Blake Message-ID: <20230921121312.1301864-8-armbru@redhat.com> Reviewed-by: Philippe Mathieu-Daudé --- include/qapi/qmp/qobject.h | 10 ++++++++-- include/qemu/atomic.h | 17 ++++++++++++----- include/qemu/compiler.h | 3 +++ include/qemu/osdep.h | 27 ++++++++++++++++++++------- 4 files changed, 43 insertions(+), 14 deletions(-) diff --git a/include/qapi/qmp/qobject.h b/include/qapi/qmp/qobject.h index 9003b71fd3..89b97d88bc 100644 --- a/include/qapi/qmp/qobject.h +++ b/include/qapi/qmp/qobject.h @@ -45,10 +45,16 @@ struct QObject { struct QObjectBase_ base; }; -#define QOBJECT(obj) ({ \ +/* + * Preprocessor sorcery ahead: use a different identifier for the + * local variable in each expansion, so we can nest macro calls + * without shadowing variables. + */ +#define QOBJECT_INTERNAL(obj, _obj) ({ \ typeof(obj) _obj = (obj); \ - _obj ? container_of(&(_obj)->base, QObject, base) : NULL; \ + _obj ? container_of(&_obj->base, QObject, base) : NULL; \ }) +#define QOBJECT(obj) QOBJECT_INTERNAL((obj), MAKE_IDENTFIER(_obj)) /* Required for qobject_to() */ #define QTYPE_CAST_TO_QNull QTYPE_QNULL diff --git a/include/qemu/atomic.h b/include/qemu/atomic.h index d95612f7a0..f1d3d1702a 100644 --- a/include/qemu/atomic.h +++ b/include/qemu/atomic.h @@ -157,13 +157,20 @@ smp_read_barrier_depends(); #endif -#define qatomic_rcu_read(ptr) \ - ({ \ +/* + * Preprocessor sorcery ahead: use a different identifier for the + * local variable in each expansion, so we can nest macro calls + * without shadowing variables. + */ +#define qatomic_rcu_read_internal(ptr, _val) \ + ({ \ qemu_build_assert(sizeof(*ptr) <= ATOMIC_REG_SIZE); \ - typeof_strip_qual(*ptr) _val; \ - qatomic_rcu_read__nocheck(ptr, &_val); \ - _val; \ + typeof_strip_qual(*ptr) _val; \ + qatomic_rcu_read__nocheck(ptr, &_val); \ + _val; \ }) +#define qatomic_rcu_read(ptr) \ + qatomic_rcu_read_internal((ptr), MAKE_IDENTFIER(_val)) #define qatomic_rcu_set(ptr, i) do { \ qemu_build_assert(sizeof(*ptr) <= ATOMIC_REG_SIZE); \ diff --git a/include/qemu/compiler.h b/include/qemu/compiler.h index 7fda29b445..7f1bbbf05f 100644 --- a/include/qemu/compiler.h +++ b/include/qemu/compiler.h @@ -37,6 +37,9 @@ #define tostring(s) #s #endif +/* Expands into an identifier stemN, where N is another number each time */ +#define MAKE_IDENTFIER(stem) glue(stem, __COUNTER__) + #ifndef likely #define likely(x) __builtin_expect(!!(x), 1) #define unlikely(x) __builtin_expect(!!(x), 0) diff --git a/include/qemu/osdep.h b/include/qemu/osdep.h index e4a4eb2d61..18b940db75 100644 --- a/include/qemu/osdep.h +++ b/include/qemu/osdep.h @@ -383,19 +383,28 @@ void QEMU_ERROR("code path is reachable") * determined by the pre-processor instead of the compiler, you'll * have to open-code it. Sadly, Coverity is severely confused by the * constant variants, so we have to dumb things down there. + * + * Preprocessor sorcery ahead: use different identifiers for the local + * variables in each expansion, so we can nest macro calls without + * shadowing variables. */ -#undef MIN -#define MIN(a, b) \ +#define MIN_INTERNAL(a, b, _a, _b) \ ({ \ typeof(1 ? (a) : (b)) _a = (a), _b = (b); \ _a < _b ? _a : _b; \ }) -#undef MAX -#define MAX(a, b) \ +#undef MIN +#define MIN(a, b) \ + MIN_INTERNAL((a), (b), MAKE_IDENTFIER(_a), MAKE_IDENTFIER(_b)) + +#define MAX_INTERNAL(a, b, _a, _b) \ ({ \ typeof(1 ? (a) : (b)) _a = (a), _b = (b); \ _a > _b ? _a : _b; \ }) +#undef MAX +#define MAX(a, b) \ + MAX_INTERNAL((a), (b), MAKE_IDENTFIER(_a), MAKE_IDENTFIER(_b)) #ifdef __COVERITY__ # define MIN_CONST(a, b) ((a) < (b) ? (a) : (b)) @@ -416,14 +425,18 @@ void QEMU_ERROR("code path is reachable") /* * Minimum function that returns zero only if both values are zero. * Intended for use with unsigned values only. + * + * Preprocessor sorcery ahead: use different identifiers for the local + * variables in each expansion, so we can nest macro calls without + * shadowing variables. */ -#ifndef MIN_NON_ZERO -#define MIN_NON_ZERO(a, b) \ +#define MIN_NON_ZERO_INTERNAL(a, b, _a, _b) \ ({ \ typeof(1 ? (a) : (b)) _a = (a), _b = (b); \ _a == 0 ? _b : (_b == 0 || _b > _a) ? _a : _b; \ }) -#endif +#define MIN_NON_ZERO(a, b) \ + MIN_NON_ZERO_INTERNAL((a), (b), MAKE_IDENTFIER(_a), MAKE_IDENTFIER(_b)) /* * Round number down to multiple. Safe when m is not a power of 2 (see From 6d559996447e544e93e036fc4c87f2f64defef5e Mon Sep 17 00:00:00 2001 From: Bastian Koppelmann Date: Wed, 13 Sep 2023 12:53:18 +0200 Subject: [PATCH 0040/1077] hw/tricore: Log failing test in testdevice Signed-off-by: Bastian Koppelmann Message-ID: <20230913105326.40832-3-kbastian@mail.uni-paderborn.de> --- hw/tricore/tricore_testdevice.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/hw/tricore/tricore_testdevice.c b/hw/tricore/tricore_testdevice.c index a1563aa568..9028d970b0 100644 --- a/hw/tricore/tricore_testdevice.c +++ b/hw/tricore/tricore_testdevice.c @@ -16,6 +16,7 @@ */ #include "qemu/osdep.h" +#include "qemu/log.h" #include "hw/sysbus.h" #include "hw/qdev-properties.h" #include "hw/tricore/tricore_testdevice.h" @@ -23,6 +24,9 @@ static void tricore_testdevice_write(void *opaque, hwaddr offset, uint64_t value, unsigned size) { + if (value != 0) { + qemu_log_mask(LOG_GUEST_ERROR, "Test %" PRIu64 " failed!\n", value); + } exit(value); } From 76bc63d7eda821e0a82e0ba0a5ad1ad5c52c8d5f Mon Sep 17 00:00:00 2001 From: Bastian Koppelmann Date: Wed, 13 Sep 2023 12:53:19 +0200 Subject: [PATCH 0041/1077] tests/tcg: Reset result register after each test some insns use the result register implicitly as an input. Thus, we could end up with data from the previous insn spilling over. Signed-off-by: Bastian Koppelmann Message-ID: <20230913105326.40832-4-kbastian@mail.uni-paderborn.de> --- tests/tcg/tricore/asm/macros.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/tcg/tricore/asm/macros.h b/tests/tcg/tricore/asm/macros.h index 0f349dbf1e..e831f73721 100644 --- a/tests/tcg/tricore/asm/macros.h +++ b/tests/tcg/tricore/asm/macros.h @@ -46,7 +46,8 @@ test_ ## num: \ code; \ LI(DREG_CORRECT_RESULT, correct) \ mov DREG_TEST_NUM, num; \ - jne testreg, DREG_CORRECT_RESULT, fail \ + jne testreg, DREG_CORRECT_RESULT, fail; \ + mov testreg, 0 #define TEST_CASE_E(num, correct_lo, correct_hi, code...) \ test_ ## num: \ From 824b2cb39c3c7dfa93f50d99d8bbd0c6d217ce24 Mon Sep 17 00:00:00 2001 From: Bastian Koppelmann Date: Wed, 13 Sep 2023 12:53:25 +0200 Subject: [PATCH 0042/1077] target/tricore: Remove CSFRs from cpu.h these are already defined in 'csfr.h.inc'. We don't need to duplicate these registers. Signed-off-by: Bastian Koppelmann Message-ID: <20230913105326.40832-10-kbastian@mail.uni-paderborn.de> --- target/tricore/cpu.h | 141 +++---------------------------------------- 1 file changed, 8 insertions(+), 133 deletions(-) diff --git a/target/tricore/cpu.h b/target/tricore/cpu.h index 3708405be8..1cace96b01 100644 --- a/target/tricore/cpu.h +++ b/target/tricore/cpu.h @@ -30,150 +30,25 @@ typedef struct CPUArchState { /* GPR Register */ uint32_t gpr_a[16]; uint32_t gpr_d[16]; - /* CSFR Register */ - uint32_t PCXI; /* Frequently accessed PSW_USB bits are stored separately for efficiency. This contains all the other bits. Use psw_{read,write} to access the whole PSW. */ uint32_t PSW; - - /* PSW flag cache for faster execution - */ + /* PSW flag cache for faster execution */ uint32_t PSW_USB_C; uint32_t PSW_USB_V; /* Only if bit 31 set, then flag is set */ uint32_t PSW_USB_SV; /* Only if bit 31 set, then flag is set */ uint32_t PSW_USB_AV; /* Only if bit 31 set, then flag is set. */ uint32_t PSW_USB_SAV; /* Only if bit 31 set, then flag is set. */ - uint32_t PC; - uint32_t SYSCON; - uint32_t CPU_ID; - uint32_t CORE_ID; - uint32_t BIV; - uint32_t BTV; - uint32_t ISP; - uint32_t ICR; - uint32_t FCX; - uint32_t LCX; - uint32_t COMPAT; +#define R(ADDR, NAME, FEATURE) uint32_t NAME; +#define A(ADDR, NAME, FEATURE) uint32_t NAME; +#define E(ADDR, NAME, FEATURE) uint32_t NAME; +#include "csfr.h.inc" +#undef R +#undef A +#undef E - /* Mem Protection Register */ - uint32_t DPR0_0L; - uint32_t DPR0_0U; - uint32_t DPR0_1L; - uint32_t DPR0_1U; - uint32_t DPR0_2L; - uint32_t DPR0_2U; - uint32_t DPR0_3L; - uint32_t DPR0_3U; - - uint32_t DPR1_0L; - uint32_t DPR1_0U; - uint32_t DPR1_1L; - uint32_t DPR1_1U; - uint32_t DPR1_2L; - uint32_t DPR1_2U; - uint32_t DPR1_3L; - uint32_t DPR1_3U; - - uint32_t DPR2_0L; - uint32_t DPR2_0U; - uint32_t DPR2_1L; - uint32_t DPR2_1U; - uint32_t DPR2_2L; - uint32_t DPR2_2U; - uint32_t DPR2_3L; - uint32_t DPR2_3U; - - uint32_t DPR3_0L; - uint32_t DPR3_0U; - uint32_t DPR3_1L; - uint32_t DPR3_1U; - uint32_t DPR3_2L; - uint32_t DPR3_2U; - uint32_t DPR3_3L; - uint32_t DPR3_3U; - - uint32_t CPR0_0L; - uint32_t CPR0_0U; - uint32_t CPR0_1L; - uint32_t CPR0_1U; - uint32_t CPR0_2L; - uint32_t CPR0_2U; - uint32_t CPR0_3L; - uint32_t CPR0_3U; - - uint32_t CPR1_0L; - uint32_t CPR1_0U; - uint32_t CPR1_1L; - uint32_t CPR1_1U; - uint32_t CPR1_2L; - uint32_t CPR1_2U; - uint32_t CPR1_3L; - uint32_t CPR1_3U; - - uint32_t CPR2_0L; - uint32_t CPR2_0U; - uint32_t CPR2_1L; - uint32_t CPR2_1U; - uint32_t CPR2_2L; - uint32_t CPR2_2U; - uint32_t CPR2_3L; - uint32_t CPR2_3U; - - uint32_t CPR3_0L; - uint32_t CPR3_0U; - uint32_t CPR3_1L; - uint32_t CPR3_1U; - uint32_t CPR3_2L; - uint32_t CPR3_2U; - uint32_t CPR3_3L; - uint32_t CPR3_3U; - - uint32_t DPM0; - uint32_t DPM1; - uint32_t DPM2; - uint32_t DPM3; - - uint32_t CPM0; - uint32_t CPM1; - uint32_t CPM2; - uint32_t CPM3; - - /* Memory Management Registers */ - uint32_t MMU_CON; - uint32_t MMU_ASI; - uint32_t MMU_TVA; - uint32_t MMU_TPA; - uint32_t MMU_TPX; - uint32_t MMU_TFA; - /* {1.3.1 only */ - uint32_t BMACON; - uint32_t SMACON; - uint32_t DIEAR; - uint32_t DIETR; - uint32_t CCDIER; - uint32_t MIECON; - uint32_t PIEAR; - uint32_t PIETR; - uint32_t CCPIER; - /*} */ - /* Debug Registers */ - uint32_t DBGSR; - uint32_t EXEVT; - uint32_t CREVT; - uint32_t SWEVT; - uint32_t TR0EVT; - uint32_t TR1EVT; - uint32_t DMS; - uint32_t DCX; - uint32_t DBGTCR; - uint32_t CCTRL; - uint32_t CCNT; - uint32_t ICNT; - uint32_t M1CNT; - uint32_t M2CNT; - uint32_t M3CNT; /* Floating Point Registers */ float_status fp_status; From ceada000846b0cd81c578b1da9f76d0c59536654 Mon Sep 17 00:00:00 2001 From: Bastian Koppelmann Date: Wed, 13 Sep 2023 12:53:26 +0200 Subject: [PATCH 0043/1077] target/tricore: Change effective address (ea) to target_ulong as this is an effective address and those cannot be signed, it should not be a signed integer. Signed-off-by: Bastian Koppelmann Message-ID: <20230913105326.40832-11-kbastian@mail.uni-paderborn.de> --- target/tricore/op_helper.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/target/tricore/op_helper.c b/target/tricore/op_helper.c index 0cf8eb50bd..ba9c4444b3 100644 --- a/target/tricore/op_helper.c +++ b/target/tricore/op_helper.c @@ -2458,7 +2458,7 @@ static bool cdc_zero(target_ulong *psw) return count == 0; } -static void save_context_upper(CPUTriCoreState *env, int ea) +static void save_context_upper(CPUTriCoreState *env, target_ulong ea) { cpu_stl_data(env, ea, env->PCXI); cpu_stl_data(env, ea+4, psw_read(env)); @@ -2478,7 +2478,7 @@ static void save_context_upper(CPUTriCoreState *env, int ea) cpu_stl_data(env, ea+60, env->gpr_d[15]); } -static void save_context_lower(CPUTriCoreState *env, int ea) +static void save_context_lower(CPUTriCoreState *env, target_ulong ea) { cpu_stl_data(env, ea, env->PCXI); cpu_stl_data(env, ea+4, env->gpr_a[11]); @@ -2498,7 +2498,7 @@ static void save_context_lower(CPUTriCoreState *env, int ea) cpu_stl_data(env, ea+60, env->gpr_d[7]); } -static void restore_context_upper(CPUTriCoreState *env, int ea, +static void restore_context_upper(CPUTriCoreState *env, target_ulong ea, target_ulong *new_PCXI, target_ulong *new_PSW) { *new_PCXI = cpu_ldl_data(env, ea); @@ -2519,7 +2519,7 @@ static void restore_context_upper(CPUTriCoreState *env, int ea, env->gpr_d[15] = cpu_ldl_data(env, ea+60); } -static void restore_context_lower(CPUTriCoreState *env, int ea, +static void restore_context_lower(CPUTriCoreState *env, target_ulong ea, target_ulong *ra, target_ulong *pcxi) { *pcxi = cpu_ldl_data(env, ea); @@ -2763,26 +2763,26 @@ void helper_rfm(CPUTriCoreState *env) } } -void helper_ldlcx(CPUTriCoreState *env, uint32_t ea) +void helper_ldlcx(CPUTriCoreState *env, target_ulong ea) { uint32_t dummy; /* insn doesn't load PCXI and RA */ restore_context_lower(env, ea, &dummy, &dummy); } -void helper_lducx(CPUTriCoreState *env, uint32_t ea) +void helper_lducx(CPUTriCoreState *env, target_ulong ea) { uint32_t dummy; /* insn doesn't load PCXI and PSW */ restore_context_upper(env, ea, &dummy, &dummy); } -void helper_stlcx(CPUTriCoreState *env, uint32_t ea) +void helper_stlcx(CPUTriCoreState *env, target_ulong ea) { save_context_lower(env, ea); } -void helper_stucx(CPUTriCoreState *env, uint32_t ea) +void helper_stucx(CPUTriCoreState *env, target_ulong ea) { save_context_upper(env, ea); } From 35ed01ba5448208695ada5fa20a13c0a4689a1c1 Mon Sep 17 00:00:00 2001 From: Fabiano Rosas Date: Tue, 26 Sep 2023 16:25:02 -0300 Subject: [PATCH 0044/1077] optionrom: Remove build-id section Our linker script for optionroms specifies only the placement of the .text section, leaving the linker free to place the remaining sections at arbitrary places in the file. Since at least binutils 2.39, the .note.gnu.build-id section is now being placed at the start of the file, which causes label addresses to be shifted. For linuxboot_dma.bin that means that the PnP header (among others) will not be found when determining the type of ROM at optionrom_setup(): (0x1c is the label _pnph, where the magic "PnP" is) $ xxd /usr/share/qemu/linuxboot_dma.bin | grep "PnP" 00000010: 0000 0000 0000 0000 0000 1c00 2450 6e50 ............$PnP $ xxd pc-bios/optionrom/linuxboot_dma.bin | grep "PnP" 00000010: 0000 0000 0000 0000 0000 4c00 2450 6e50 ............$PnP ^bad Using a freshly built linuxboot_dma.bin ROM results in a broken boot: SeaBIOS (version rel-1.16.2-0-gea1b7a073390-prebuilt.qemu.org) Booting from Hard Disk... Boot failed: could not read the boot disk Booting from Floppy... Boot failed: could not read the boot disk No bootable device. We're not using the build-id section, so pass the --build-id=none option to the linker to remove it entirely. Note: In theory, this same issue could happen with any other section. The ideal solution would be to have all unused sections discarded in the linker script. However that would be a larger change, specially for the pvh rom which uses the .bss and COMMON sections so I'm addressing only the immediate issue here. Reported-by: Vasiliy Ulyanov Signed-off-by: Fabiano Rosas Reviewed-by: Thomas Huth Message-ID: <20230926192502.15986-1-farosas@suse.de> Cc: stable@vger.kernel.org Signed-off-by: Paolo Bonzini --- pc-bios/optionrom/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pc-bios/optionrom/Makefile b/pc-bios/optionrom/Makefile index b1fff0ba6c..30d07026c7 100644 --- a/pc-bios/optionrom/Makefile +++ b/pc-bios/optionrom/Makefile @@ -36,7 +36,7 @@ config-cc.mak: Makefile $(call cc-option,-Wno-array-bounds)) 3> config-cc.mak -include config-cc.mak -override LDFLAGS = -nostdlib -Wl,-T,$(SRC_DIR)/flat.lds +override LDFLAGS = -nostdlib -Wl,--build-id=none,-T,$(SRC_DIR)/flat.lds pvh.img: pvh.o pvh_main.o From 7191f24c7fcfbc1216d09214122582f4f9d699db Mon Sep 17 00:00:00 2001 From: Akihiko Odaki Date: Thu, 1 Dec 2022 19:27:28 +0900 Subject: [PATCH 0045/1077] accel/kvm/kvm-all: Handle register access errors A register access error typically means something seriously wrong happened so that anything bad can happen after that and recovery is impossible. Even failing one register access is catastorophic as architecture-specific code are not written so that it torelates such failures. Make sure the VM stop and nothing worse happens if such an error occurs. Signed-off-by: Akihiko Odaki Message-ID: <20221201102728.69751-1-akihiko.odaki@daynix.com> Signed-off-by: Paolo Bonzini --- accel/kvm/kvm-all.c | 32 ++++++++++++++++++++++++++++---- 1 file changed, 28 insertions(+), 4 deletions(-) diff --git a/accel/kvm/kvm-all.c b/accel/kvm/kvm-all.c index ff1578bb32..72e1d1141c 100644 --- a/accel/kvm/kvm-all.c +++ b/accel/kvm/kvm-all.c @@ -2851,7 +2851,13 @@ bool kvm_cpu_check_are_resettable(void) static void do_kvm_cpu_synchronize_state(CPUState *cpu, run_on_cpu_data arg) { if (!cpu->vcpu_dirty) { - kvm_arch_get_registers(cpu); + int ret = kvm_arch_get_registers(cpu); + if (ret) { + error_report("Failed to get registers: %s", strerror(-ret)); + cpu_dump_state(cpu, stderr, CPU_DUMP_CODE); + vm_stop(RUN_STATE_INTERNAL_ERROR); + } + cpu->vcpu_dirty = true; } } @@ -2865,7 +2871,13 @@ void kvm_cpu_synchronize_state(CPUState *cpu) static void do_kvm_cpu_synchronize_post_reset(CPUState *cpu, run_on_cpu_data arg) { - kvm_arch_put_registers(cpu, KVM_PUT_RESET_STATE); + int ret = kvm_arch_put_registers(cpu, KVM_PUT_RESET_STATE); + if (ret) { + error_report("Failed to put registers after reset: %s", strerror(-ret)); + cpu_dump_state(cpu, stderr, CPU_DUMP_CODE); + vm_stop(RUN_STATE_INTERNAL_ERROR); + } + cpu->vcpu_dirty = false; } @@ -2876,7 +2888,12 @@ void kvm_cpu_synchronize_post_reset(CPUState *cpu) static void do_kvm_cpu_synchronize_post_init(CPUState *cpu, run_on_cpu_data arg) { - kvm_arch_put_registers(cpu, KVM_PUT_FULL_STATE); + int ret = kvm_arch_put_registers(cpu, KVM_PUT_FULL_STATE); + if (ret) { + error_report("Failed to put registers after init: %s", strerror(-ret)); + exit(1); + } + cpu->vcpu_dirty = false; } @@ -2969,7 +2986,14 @@ int kvm_cpu_exec(CPUState *cpu) MemTxAttrs attrs; if (cpu->vcpu_dirty) { - kvm_arch_put_registers(cpu, KVM_PUT_RUNTIME_STATE); + ret = kvm_arch_put_registers(cpu, KVM_PUT_RUNTIME_STATE); + if (ret) { + error_report("Failed to put registers after init: %s", + strerror(-ret)); + ret = -1; + break; + } + cpu->vcpu_dirty = false; } From fa4ec9ffda74dc5970ae5a104588dba0ffb49c9f Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Fri, 22 Sep 2023 11:52:11 +0200 Subject: [PATCH 0046/1077] e1000: remove old compatibility code This code is not needed anymore in the supported machine types. Signed-off-by: Paolo Bonzini --- hw/net/e1000.c | 79 +++++++++++++++++--------------------------------- 1 file changed, 27 insertions(+), 52 deletions(-) diff --git a/hw/net/e1000.c b/hw/net/e1000.c index 093c2d4531..548bcabcbb 100644 --- a/hw/net/e1000.c +++ b/hw/net/e1000.c @@ -127,13 +127,9 @@ struct E1000State_st { QEMUTimer *flush_queue_timer; /* Compatibility flags for migration to/from qemu 1.3.0 and older */ -#define E1000_FLAG_AUTONEG_BIT 0 -#define E1000_FLAG_MIT_BIT 1 #define E1000_FLAG_MAC_BIT 2 #define E1000_FLAG_TSO_BIT 3 #define E1000_FLAG_VET_BIT 4 -#define E1000_FLAG_AUTONEG (1 << E1000_FLAG_AUTONEG_BIT) -#define E1000_FLAG_MIT (1 << E1000_FLAG_MIT_BIT) #define E1000_FLAG_MAC (1 << E1000_FLAG_MAC_BIT) #define E1000_FLAG_TSO (1 << E1000_FLAG_TSO_BIT) #define E1000_FLAG_VET (1 << E1000_FLAG_VET_BIT) @@ -180,7 +176,7 @@ e1000_autoneg_done(E1000State *s) static bool have_autoneg(E1000State *s) { - return chkflag(AUTONEG) && (s->phy_reg[MII_BMCR] & MII_BMCR_AUTOEN); + return (s->phy_reg[MII_BMCR] & MII_BMCR_AUTOEN); } static void @@ -308,35 +304,34 @@ set_interrupt_cause(E1000State *s, int index, uint32_t val) if (s->mit_timer_on) { return; } - if (chkflag(MIT)) { - /* Compute the next mitigation delay according to pending - * interrupts and the current values of RADV (provided - * RDTR!=0), TADV and ITR. - * Then rearm the timer. - */ - mit_delay = 0; - if (s->mit_ide && - (pending_ints & (E1000_ICR_TXQE | E1000_ICR_TXDW))) { - mit_update_delay(&mit_delay, s->mac_reg[TADV] * 4); - } - if (s->mac_reg[RDTR] && (pending_ints & E1000_ICS_RXT0)) { - mit_update_delay(&mit_delay, s->mac_reg[RADV] * 4); - } - mit_update_delay(&mit_delay, s->mac_reg[ITR]); - /* - * According to e1000 SPEC, the Ethernet controller guarantees - * a maximum observable interrupt rate of 7813 interrupts/sec. - * Thus if mit_delay < 500 then the delay should be set to the - * minimum delay possible which is 500. - */ - mit_delay = (mit_delay < 500) ? 500 : mit_delay; - - s->mit_timer_on = 1; - timer_mod(s->mit_timer, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + - mit_delay * 256); - s->mit_ide = 0; + /* Compute the next mitigation delay according to pending + * interrupts and the current values of RADV (provided + * RDTR!=0), TADV and ITR. + * Then rearm the timer. + */ + mit_delay = 0; + if (s->mit_ide && + (pending_ints & (E1000_ICR_TXQE | E1000_ICR_TXDW))) { + mit_update_delay(&mit_delay, s->mac_reg[TADV] * 4); } + if (s->mac_reg[RDTR] && (pending_ints & E1000_ICS_RXT0)) { + mit_update_delay(&mit_delay, s->mac_reg[RADV] * 4); + } + mit_update_delay(&mit_delay, s->mac_reg[ITR]); + + /* + * According to e1000 SPEC, the Ethernet controller guarantees + * a maximum observable interrupt rate of 7813 interrupts/sec. + * Thus if mit_delay < 500 then the delay should be set to the + * minimum delay possible which is 500. + */ + mit_delay = (mit_delay < 500) ? 500 : mit_delay; + + s->mit_timer_on = 1; + timer_mod(s->mit_timer, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + + mit_delay * 256); + s->mit_ide = 0; } s->mit_irq_level = (pending_ints != 0); @@ -1223,9 +1218,6 @@ enum { MAC_ACCESS_PARTIAL = 1, MAC_ACCESS_FLAG_NEEDED = 2 }; * n - flag needed * p - partially implenented */ static const uint8_t mac_reg_access[0x8000] = { - [RDTR] = markflag(MIT), [TADV] = markflag(MIT), - [RADV] = markflag(MIT), [ITR] = markflag(MIT), - [IPAV] = markflag(MAC), [WUC] = markflag(MAC), [IP6AT] = markflag(MAC), [IP4AT] = markflag(MAC), [FFVT] = markflag(MAC), [WUPM] = markflag(MAC), @@ -1394,11 +1386,6 @@ static int e1000_post_load(void *opaque, int version_id) E1000State *s = opaque; NetClientState *nc = qemu_get_queue(s->nic); - if (!chkflag(MIT)) { - s->mac_reg[ITR] = s->mac_reg[RDTR] = s->mac_reg[RADV] = - s->mac_reg[TADV] = 0; - s->mit_irq_level = false; - } s->mit_ide = 0; s->mit_timer_on = true; timer_mod(s->mit_timer, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + 1); @@ -1432,13 +1419,6 @@ static int e1000_tx_tso_post_load(void *opaque, int version_id) return 0; } -static bool e1000_mit_state_needed(void *opaque) -{ - E1000State *s = opaque; - - return chkflag(MIT); -} - static bool e1000_full_mac_needed(void *opaque) { E1000State *s = opaque; @@ -1457,7 +1437,6 @@ static const VMStateDescription vmstate_e1000_mit_state = { .name = "e1000/mit_state", .version_id = 1, .minimum_version_id = 1, - .needed = e1000_mit_state_needed, .fields = (VMStateField[]) { VMSTATE_UINT32(mac_reg[RDTR], E1000State), VMSTATE_UINT32(mac_reg[RADV], E1000State), @@ -1699,10 +1678,6 @@ static void pci_e1000_realize(PCIDevice *pci_dev, Error **errp) static Property e1000_properties[] = { DEFINE_NIC_PROPERTIES(E1000State, conf), - DEFINE_PROP_BIT("autonegotiation", E1000State, - compat_flags, E1000_FLAG_AUTONEG_BIT, true), - DEFINE_PROP_BIT("mitigation", E1000State, - compat_flags, E1000_FLAG_MIT_BIT, true), DEFINE_PROP_BIT("extra_mac_registers", E1000State, compat_flags, E1000_FLAG_MAC_BIT, true), DEFINE_PROP_BIT("migrate_tso_props", E1000State, From 946f7c0903c44ad2ace5bb6bf187d66c30548520 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Fri, 22 Sep 2023 11:54:02 +0200 Subject: [PATCH 0047/1077] pc: remove short_root_bus property The property was only used on QEMU 1.6 machine types. Signed-off-by: Paolo Bonzini --- hw/pci-host/i440fx.c | 8 -------- hw/pci-host/q35.c | 7 ------- include/hw/pci-host/q35.h | 1 - 3 files changed, 16 deletions(-) diff --git a/hw/pci-host/i440fx.c b/hw/pci-host/i440fx.c index 62d6287681..653cc3f149 100644 --- a/hw/pci-host/i440fx.c +++ b/hw/pci-host/i440fx.c @@ -56,7 +56,6 @@ struct I440FXState { uint64_t above_4g_mem_size; uint64_t pci_hole64_size; bool pci_hole64_fix; - uint32_t short_root_bus; char *pci_type; }; @@ -351,19 +350,12 @@ static const TypeInfo i440fx_info = { static const char *i440fx_pcihost_root_bus_path(PCIHostState *host_bridge, PCIBus *rootbus) { - I440FXState *s = I440FX_PCI_HOST_BRIDGE(host_bridge); - - /* For backwards compat with old device paths */ - if (s->short_root_bus) { - return "0000"; - } return "0000:00"; } static Property i440fx_props[] = { DEFINE_PROP_SIZE(PCI_HOST_PROP_PCI_HOLE64_SIZE, I440FXState, pci_hole64_size, I440FX_PCI_HOST_HOLE64_SIZE_DEFAULT), - DEFINE_PROP_UINT32("short_root_bus", I440FXState, short_root_bus, 0), DEFINE_PROP_SIZE(PCI_HOST_BELOW_4G_MEM_SIZE, I440FXState, below_4g_mem_size, 0), DEFINE_PROP_SIZE(PCI_HOST_ABOVE_4G_MEM_SIZE, I440FXState, diff --git a/hw/pci-host/q35.c b/hw/pci-host/q35.c index 91c46df9ae..08534bc7cc 100644 --- a/hw/pci-host/q35.c +++ b/hw/pci-host/q35.c @@ -73,12 +73,6 @@ static void q35_host_realize(DeviceState *dev, Error **errp) static const char *q35_host_root_bus_path(PCIHostState *host_bridge, PCIBus *rootbus) { - Q35PCIHost *s = Q35_HOST_DEVICE(host_bridge); - - /* For backwards compat with old device paths */ - if (s->mch.short_root_bus) { - return "0000"; - } return "0000:00"; } @@ -181,7 +175,6 @@ static Property q35_host_props[] = { MCH_HOST_BRIDGE_PCIEXBAR_DEFAULT), DEFINE_PROP_SIZE(PCI_HOST_PROP_PCI_HOLE64_SIZE, Q35PCIHost, mch.pci_hole64_size, Q35_PCI_HOST_HOLE64_SIZE_DEFAULT), - DEFINE_PROP_UINT32("short_root_bus", Q35PCIHost, mch.short_root_bus, 0), DEFINE_PROP_SIZE(PCI_HOST_BELOW_4G_MEM_SIZE, Q35PCIHost, mch.below_4g_mem_size, 0), DEFINE_PROP_SIZE(PCI_HOST_ABOVE_4G_MEM_SIZE, Q35PCIHost, diff --git a/include/hw/pci-host/q35.h b/include/hw/pci-host/q35.h index 1d98bbfe0d..bafcbe6752 100644 --- a/include/hw/pci-host/q35.h +++ b/include/hw/pci-host/q35.h @@ -54,7 +54,6 @@ struct MCHPCIState { uint64_t below_4g_mem_size; uint64_t above_4g_mem_size; uint64_t pci_hole64_size; - uint32_t short_root_bus; uint16_t ext_tseg_mbytes; }; From f0df613b98901a2a9184a76f332a853391a73fa8 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Tue, 26 Sep 2023 12:31:40 +0200 Subject: [PATCH 0048/1077] make-release: do not ship dtc sources A new enough libfdt is included in all of Debian 11, Ubuntu 20.04 and MSYS2. It has also been included for several minor releases in Fedora and openSUSE Leap, as well as in CentOS. Therefore there is no need anymore to ship the sources together with the QEMU tarballs. Keep the wrap file so that it can be used with --enable-download, but do not ship the sources anymore with either archive-source.sh or make-release. Signed-off-by: Paolo Bonzini --- meson.build | 3 +++ scripts/archive-source.sh | 2 +- scripts/make-release | 2 +- 3 files changed, 5 insertions(+), 2 deletions(-) diff --git a/meson.build b/meson.build index 5139db2ff7..81430ce234 100644 --- a/meson.build +++ b/meson.build @@ -3070,6 +3070,9 @@ if fdt_required.length() > 0 or fdt_opt == 'enabled' endif if fdt_opt in ['enabled', 'auto', 'system'] + if get_option('wrap_mode') == 'nodownload' + fdt_opt = 'system' + endif fdt = cc.find_library('fdt', required: fdt_opt == 'system') if fdt.found() and cc.links(''' #include diff --git a/scripts/archive-source.sh b/scripts/archive-source.sh index 4899630491..65af8063e4 100755 --- a/scripts/archive-source.sh +++ b/scripts/archive-source.sh @@ -26,7 +26,7 @@ sub_file="${sub_tdir}/submodule.tar" # independent of what the developer currently has initialized # in their checkout, because the build environment is completely # different to the host OS. -subprojects="dtc keycodemapdb libvfio-user berkeley-softfloat-3 berkeley-testfloat-3" +subprojects="keycodemapdb libvfio-user berkeley-softfloat-3 berkeley-testfloat-3" sub_deinit="" function cleanup() { diff --git a/scripts/make-release b/scripts/make-release index c5db87b3f9..9c570b87f4 100755 --- a/scripts/make-release +++ b/scripts/make-release @@ -17,7 +17,7 @@ if [ $# -ne 2 ]; then fi # Only include wraps that are invoked with subproject() -SUBPROJECTS="dtc libvfio-user keycodemapdb berkeley-softfloat-3 berkeley-testfloat-3" +SUBPROJECTS="libvfio-user keycodemapdb berkeley-softfloat-3 berkeley-testfloat-3" src="$1" version="$2" From 4c545a05abe8859c6e0f64079abe6495fd58d7a8 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Wed, 27 Sep 2023 15:48:31 +0200 Subject: [PATCH 0049/1077] meson: clean up static_library keyword arguments These are either built because they are dependencies of other targets, or not needed at all because they are used via extract_objects(). Mark them as "build_by_default: false"; if applicable, mark them as "fa" so that -Wl,--whole-archive does not interact with the linker script used for fuzzing. (The "fa" hack is brittle; updating to Meson 1.1 would allow using declare_dependency(objects: ...) instead). Resolves: https://gitlab.com/qemu-project/qemu/-/issues/1044 Signed-off-by: Paolo Bonzini --- gdbstub/meson.build | 4 ++-- meson.build | 11 +++++++---- tcg/meson.build | 4 ++-- 3 files changed, 11 insertions(+), 8 deletions(-) diff --git a/gdbstub/meson.build b/gdbstub/meson.build index 9500b9dc4e..a5a1f4e433 100644 --- a/gdbstub/meson.build +++ b/gdbstub/meson.build @@ -21,12 +21,12 @@ libgdb_user = static_library('gdb_user', gdb_user_ss.sources() + genh, name_suffix: 'fa', c_args: '-DCONFIG_USER_ONLY', - build_by_default: have_user) + build_by_default: false) libgdb_softmmu = static_library('gdb_softmmu', gdb_system_ss.sources() + genh, name_suffix: 'fa', - build_by_default: have_system) + build_by_default: false) gdb_user = declare_dependency(link_whole: libgdb_user) user_ss.add(gdb_user) diff --git a/meson.build b/meson.build index 81430ce234..21a1bc03f8 100644 --- a/meson.build +++ b/meson.build @@ -3180,7 +3180,6 @@ foreach d : hx_headers input: files(d[0]), output: d[1], capture: true, - build_by_default: true, # to be removed when added to a target command: [hxtool, '-h', '@INPUT0@']) endforeach genh += hxdep @@ -3366,12 +3365,15 @@ endif qom_ss = qom_ss.apply(config_targetos, strict: false) libqom = static_library('qom', qom_ss.sources() + genh, dependencies: [qom_ss.dependencies()], - name_suffix: 'fa') + name_suffix: 'fa', + build_by_default: false) qom = declare_dependency(link_whole: libqom) event_loop_base = files('event-loop-base.c') -event_loop_base = static_library('event-loop-base', sources: event_loop_base + genh, - build_by_default: true) +event_loop_base = static_library('event-loop-base', + sources: event_loop_base + genh, + name_suffix: 'fa', + build_by_default: false) event_loop_base = declare_dependency(link_whole: event_loop_base, dependencies: [qom]) @@ -3380,6 +3382,7 @@ stub_ss = stub_ss.apply(config_all, strict: false) util_ss.add_all(trace_ss) util_ss = util_ss.apply(config_all, strict: false) libqemuutil = static_library('qemuutil', + build_by_default: false, sources: util_ss.sources() + stub_ss.sources() + genh, dependencies: [util_ss.dependencies(), libm, threads, glib, socket, malloc, pixman]) qemuutil = declare_dependency(link_with: libqemuutil, diff --git a/tcg/meson.build b/tcg/meson.build index 0014dca7d4..4be4a616ca 100644 --- a/tcg/meson.build +++ b/tcg/meson.build @@ -28,7 +28,7 @@ libtcg_user = static_library('tcg_user', tcg_ss.sources() + genh, name_suffix: 'fa', c_args: '-DCONFIG_USER_ONLY', - build_by_default: have_user) + build_by_default: false) tcg_user = declare_dependency(link_with: libtcg_user, dependencies: tcg_ss.dependencies()) @@ -38,7 +38,7 @@ libtcg_softmmu = static_library('tcg_softmmu', tcg_ss.sources() + genh, name_suffix: 'fa', c_args: '-DCONFIG_SOFTMMU', - build_by_default: have_system) + build_by_default: false) tcg_softmmu = declare_dependency(link_with: libtcg_softmmu, dependencies: tcg_ss.dependencies()) From 9a239c6eae68e0bfb989f9ebb2907e04f98fde99 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Mon, 4 Sep 2023 18:12:13 +0200 Subject: [PATCH 0050/1077] tcg: Clean up local variable shadowing MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fix: tcg/tcg.c:2551:27: error: declaration shadows a local variable [-Werror,-Wshadow] MemOp op = get_memop(oi); ^ tcg/tcg.c:2437:12: note: previous declaration is here TCGOp *op; ^ accel/tcg/tb-maint.c:245:18: error: declaration shadows a local variable [-Werror,-Wshadow] for (int i = 0; i < V_L2_SIZE; i++) { ^ accel/tcg/tb-maint.c:210:9: note: previous declaration is here int i; ^ Reviewed-by: Richard Henderson Signed-off-by: Philippe Mathieu-Daudé Message-ID: <20230904161235.84651-2-philmd@linaro.org> Signed-off-by: Markus Armbruster --- accel/tcg/tb-maint.c | 3 +-- tcg/tcg.c | 16 ++++++++-------- 2 files changed, 9 insertions(+), 10 deletions(-) diff --git a/accel/tcg/tb-maint.c b/accel/tcg/tb-maint.c index 32ae8af61c..8c71cebabd 100644 --- a/accel/tcg/tb-maint.c +++ b/accel/tcg/tb-maint.c @@ -207,13 +207,12 @@ static PageDesc *page_find_alloc(tb_page_addr_t index, bool alloc) { PageDesc *pd; void **lp; - int i; /* Level 1. Always allocated. */ lp = l1_map + ((index >> v_l1_shift) & (v_l1_size - 1)); /* Level 2..N-1. */ - for (i = v_l2_levels; i > 0; i--) { + for (int i = v_l2_levels; i > 0; i--) { void **p = qatomic_rcu_read(lp); if (p == NULL) { diff --git a/tcg/tcg.c b/tcg/tcg.c index 604fa9bf3e..ea94d0fbff 100644 --- a/tcg/tcg.c +++ b/tcg/tcg.c @@ -2549,21 +2549,21 @@ static void tcg_dump_ops(TCGContext *s, FILE *f, bool have_prefs) { const char *s_al, *s_op, *s_at; MemOpIdx oi = op->args[k++]; - MemOp op = get_memop(oi); + MemOp mop = get_memop(oi); unsigned ix = get_mmuidx(oi); - s_al = alignment_name[(op & MO_AMASK) >> MO_ASHIFT]; - s_op = ldst_name[op & (MO_BSWAP | MO_SSIZE)]; - s_at = atom_name[(op & MO_ATOM_MASK) >> MO_ATOM_SHIFT]; - op &= ~(MO_AMASK | MO_BSWAP | MO_SSIZE | MO_ATOM_MASK); + s_al = alignment_name[(mop & MO_AMASK) >> MO_ASHIFT]; + s_op = ldst_name[mop & (MO_BSWAP | MO_SSIZE)]; + s_at = atom_name[(mop & MO_ATOM_MASK) >> MO_ATOM_SHIFT]; + mop &= ~(MO_AMASK | MO_BSWAP | MO_SSIZE | MO_ATOM_MASK); /* If all fields are accounted for, print symbolically. */ - if (!op && s_al && s_op && s_at) { + if (!mop && s_al && s_op && s_at) { col += ne_fprintf(f, ",%s%s%s,%u", s_at, s_al, s_op, ix); } else { - op = get_memop(oi); - col += ne_fprintf(f, ",$0x%x,%u", op, ix); + mop = get_memop(oi); + col += ne_fprintf(f, ",$0x%x,%u", mop, ix); } i = 1; } From d54deb2a0723d696bc4e95265d6ccb4236cb0cf4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Mon, 4 Sep 2023 18:12:14 +0200 Subject: [PATCH 0051/1077] target/arm/tcg: Clean up local variable shadowing MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fix: target/arm/tcg/translate-m-nocp.c: In function ‘gen_M_fp_sysreg_read’: target/arm/tcg/translate-m-nocp.c:509:18: warning: declaration of ‘tmp’ shadows a previous local [-Wshadow=compatible-local] 509 | TCGv_i32 tmp = load_cpu_field(v7m.fpdscr[M_REG_NS]); | ^~~ target/arm/tcg/translate-m-nocp.c:433:14: note: shadowed declaration is here 433 | TCGv_i32 tmp; | ^~~ --- target/arm/tcg/mve_helper.c: In function ‘helper_mve_vqshlsb’: target/arm/tcg/mve_helper.c:1259:19: warning: declaration of ‘r’ shadows a previous local [-Wshadow=compatible-local] 1259 | typeof(N) r = FN(N, (int8_t)(M), sizeof(N) * 8, ROUND, &su32); \ | ^ target/arm/tcg/mve_helper.c:1267:5: note: in expansion of macro ‘WRAP_QRSHL_HELPER’ 1267 | WRAP_QRSHL_HELPER(do_sqrshl_bhs, N, M, false, satp) | ^~~~~~~~~~~~~~~~~ target/arm/tcg/mve_helper.c:927:22: note: in expansion of macro ‘DO_SQSHL_OP’ 927 | TYPE r = FN(n[H##ESIZE(e)], m[H##ESIZE(e)], &sat); \ | ^~ target/arm/tcg/mve_helper.c:945:5: note: in expansion of macro ‘DO_2OP_SAT’ 945 | DO_2OP_SAT(OP##b, 1, int8_t, FN) \ | ^~~~~~~~~~ target/arm/tcg/mve_helper.c:1277:1: note: in expansion of macro ‘DO_2OP_SAT_S’ 1277 | DO_2OP_SAT_S(vqshls, DO_SQSHL_OP) | ^~~~~~~~~~~~ --- target/arm/tcg/mve_helper.c: In function ‘do_sqrshl48_d’: target/arm/tcg/mve_helper.c:2463:17: warning: declaration of ‘extval’ shadows a previous local [-Wshadow=compatible-local] 2463 | int64_t extval = sextract64(src << shift, 0, 48); | ^~~~~~ target/arm/tcg/mve_helper.c:2443:18: note: shadowed declaration is here 2443 | int64_t val, extval; | ^~~~~~ --- target/arm/tcg/mve_helper.c: In function ‘do_uqrshl48_d’: target/arm/tcg/mve_helper.c:2495:18: warning: declaration of ‘extval’ shadows a previous local [-Wshadow=compatible-local] 2495 | uint64_t extval = extract64(src << shift, 0, 48); | ^~~~~~ target/arm/tcg/mve_helper.c:2479:19: note: shadowed declaration is here 2479 | uint64_t val, extval; | ^~~~~~ Signed-off-by: Philippe Mathieu-Daudé Message-ID: <20230904161235.84651-3-philmd@linaro.org> Reviewed-by: Peter Maydell Signed-off-by: Markus Armbruster --- target/arm/tcg/mve_helper.c | 16 ++++++++-------- target/arm/tcg/translate-m-nocp.c | 2 +- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/target/arm/tcg/mve_helper.c b/target/arm/tcg/mve_helper.c index c666a96ba1..8b99736aad 100644 --- a/target/arm/tcg/mve_helper.c +++ b/target/arm/tcg/mve_helper.c @@ -925,8 +925,8 @@ DO_1OP_IMM(vorri, DO_ORRI) bool qc = false; \ for (e = 0; e < 16 / ESIZE; e++, mask >>= ESIZE) { \ bool sat = false; \ - TYPE r = FN(n[H##ESIZE(e)], m[H##ESIZE(e)], &sat); \ - mergemask(&d[H##ESIZE(e)], r, mask); \ + TYPE r_ = FN(n[H##ESIZE(e)], m[H##ESIZE(e)], &sat); \ + mergemask(&d[H##ESIZE(e)], r_, mask); \ qc |= sat & mask & 1; \ } \ if (qc) { \ @@ -1250,11 +1250,11 @@ DO_2OP_SAT(vqsubsw, 4, int32_t, DO_SQSUB_W) #define WRAP_QRSHL_HELPER(FN, N, M, ROUND, satp) \ ({ \ uint32_t su32 = 0; \ - typeof(N) r = FN(N, (int8_t)(M), sizeof(N) * 8, ROUND, &su32); \ + typeof(N) qrshl_ret = FN(N, (int8_t)(M), sizeof(N) * 8, ROUND, &su32); \ if (su32) { \ *satp = true; \ } \ - r; \ + qrshl_ret; \ }) #define DO_SQSHL_OP(N, M, satp) \ @@ -1292,12 +1292,12 @@ DO_2OP_SAT_U(vqrshlu, DO_UQRSHL_OP) for (e = 0; e < 16 / ESIZE; e++, mask >>= ESIZE) { \ bool sat = false; \ if ((e & 1) == XCHG) { \ - TYPE r = FN(n[H##ESIZE(e)], \ + TYPE vqdmladh_ret = FN(n[H##ESIZE(e)], \ m[H##ESIZE(e - XCHG)], \ n[H##ESIZE(e + (1 - 2 * XCHG))], \ m[H##ESIZE(e + (1 - XCHG))], \ ROUND, &sat); \ - mergemask(&d[H##ESIZE(e)], r, mask); \ + mergemask(&d[H##ESIZE(e)], vqdmladh_ret, mask); \ qc |= sat & mask & 1; \ } \ } \ @@ -2454,7 +2454,7 @@ static inline int64_t do_sqrshl48_d(int64_t src, int64_t shift, return extval; } } else if (shift < 48) { - int64_t extval = sextract64(src << shift, 0, 48); + extval = sextract64(src << shift, 0, 48); if (!sat || src == (extval >> shift)) { return extval; } @@ -2486,7 +2486,7 @@ static inline uint64_t do_uqrshl48_d(uint64_t src, int64_t shift, return extval; } } else if (shift < 48) { - uint64_t extval = extract64(src << shift, 0, 48); + extval = extract64(src << shift, 0, 48); if (!sat || src == (extval >> shift)) { return extval; } diff --git a/target/arm/tcg/translate-m-nocp.c b/target/arm/tcg/translate-m-nocp.c index 33f6478bb9..42308c4db5 100644 --- a/target/arm/tcg/translate-m-nocp.c +++ b/target/arm/tcg/translate-m-nocp.c @@ -506,7 +506,7 @@ static bool gen_M_fp_sysreg_read(DisasContext *s, int regno, gen_branch_fpInactive(s, TCG_COND_EQ, lab_active); /* fpInactive case: reads as FPDSCR_NS */ - TCGv_i32 tmp = load_cpu_field(v7m.fpdscr[M_REG_NS]); + tmp = load_cpu_field(v7m.fpdscr[M_REG_NS]); storefn(s, opaque, tmp, true); lab_end = gen_new_label(); tcg_gen_br(lab_end); From 5a3d2c3562a9b35443fb4121ba6efff9d6cdbb91 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Mon, 4 Sep 2023 18:12:15 +0200 Subject: [PATCH 0052/1077] target/arm/hvf: Clean up local variable shadowing MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Per Peter Maydell analysis [*]: The hvf_vcpu_exec() function is not documented, but in practice its caller expects it to return either EXCP_DEBUG (for "this was a guest debug exception you need to deal with") or something else (presumably the intention being 0 for OK). The hvf_sysreg_read() and hvf_sysreg_write() functions are also not documented, but they return 0 on success, or 1 for a completely unrecognized sysreg where we've raised the UNDEF exception (but not if we raised an UNDEF exception for an unrecognized GIC sysreg -- I think this is a bug). We use this return value to decide whether we need to advance the PC past the insn or not. It's not the same as the return value we want to return from hvf_vcpu_exec(). Retain the variable as locally scoped but give it a name that doesn't clash with the other function-scoped variable. This fixes: target/arm/hvf/hvf.c:1936:13: error: declaration shadows a local variable [-Werror,-Wshadow] int ret = 0; ^ target/arm/hvf/hvf.c:1807:9: note: previous declaration is here int ret; ^ [*] https://lore.kernel.org/qemu-devel/CAFEAcA_e+fU6JKtS+W63wr9cCJ6btu_hT_ydZWOwC0kBkDYYYQ@mail.gmail.com/ Signed-off-by: Philippe Mathieu-Daudé Message-ID: <20230904161235.84651-4-philmd@linaro.org> Reviewed-by: Peter Maydell Signed-off-by: Markus Armbruster --- target/arm/hvf/hvf.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/target/arm/hvf/hvf.c b/target/arm/hvf/hvf.c index 546c0e817f..757e13b0f9 100644 --- a/target/arm/hvf/hvf.c +++ b/target/arm/hvf/hvf.c @@ -1934,16 +1934,16 @@ int hvf_vcpu_exec(CPUState *cpu) uint32_t rt = (syndrome >> 5) & 0x1f; uint32_t reg = syndrome & SYSREG_MASK; uint64_t val; - int ret = 0; + int sysreg_ret = 0; if (isread) { - ret = hvf_sysreg_read(cpu, reg, rt); + sysreg_ret = hvf_sysreg_read(cpu, reg, rt); } else { val = hvf_get_reg(cpu, rt); - ret = hvf_sysreg_write(cpu, reg, val); + sysreg_ret = hvf_sysreg_write(cpu, reg, val); } - advance_pc = !ret; + advance_pc = !sysreg_ret; break; } case EC_WFX_TRAP: From 92e0ef7d907a7b39d942732a29c04446a4ef5cac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Mon, 4 Sep 2023 18:12:16 +0200 Subject: [PATCH 0053/1077] target/mips: Clean up local variable shadowing MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fix: target/mips/tcg/nanomips_translate.c.inc:4410:33: error: declaration shadows a local variable [-Werror,-Wshadow] int32_t imm = extract32(ctx->opcode, 1, 13) | ^ target/mips/tcg/nanomips_translate.c.inc:3577:9: note: previous declaration is here int imm; ^ target/mips/tcg/translate.c:15578:19: error: declaration shadows a local variable [-Werror,-Wshadow] for (unsigned i = 1; i < 32; i++) { ^ target/mips/tcg/translate.c:15567:9: note: previous declaration is here int i; ^ target/mips/tcg/msa_helper.c:7478:13: error: declaration shadows a local variable [-Werror,-Wshadow] MSA_FLOAT_MAXOP(pwx->w[0], min, pws->w[0], pws->w[0], 32); ^ target/mips/tcg/msa_helper.c:7434:23: note: expanded from macro 'MSA_FLOAT_MAXOP' float_status *status = &env->active_tc.msa_fp_status; ^ Signed-off-by: Philippe Mathieu-Daudé Message-ID: <20230904161235.84651-5-philmd@linaro.org> Signed-off-by: Markus Armbruster --- target/mips/tcg/msa_helper.c | 8 ++++---- target/mips/tcg/nanomips_translate.c.inc | 6 +++--- target/mips/tcg/translate.c | 8 +++----- 3 files changed, 10 insertions(+), 12 deletions(-) diff --git a/target/mips/tcg/msa_helper.c b/target/mips/tcg/msa_helper.c index c314a74397..7a8dbada5d 100644 --- a/target/mips/tcg/msa_helper.c +++ b/target/mips/tcg/msa_helper.c @@ -7432,15 +7432,15 @@ void helper_msa_ftq_df(CPUMIPSState *env, uint32_t df, uint32_t wd, #define MSA_FLOAT_MAXOP(DEST, OP, ARG1, ARG2, BITS) \ do { \ - float_status *status = &env->active_tc.msa_fp_status; \ + float_status *status_ = &env->active_tc.msa_fp_status; \ int c; \ \ - set_float_exception_flags(0, status); \ - DEST = float ## BITS ## _ ## OP(ARG1, ARG2, status); \ + set_float_exception_flags(0, status_); \ + DEST = float ## BITS ## _ ## OP(ARG1, ARG2, status_); \ c = update_msacsr(env, 0, 0); \ \ if (get_enabled_exceptions(env, c)) { \ - DEST = ((FLOAT_SNAN ## BITS(status) >> 6) << 6) | c; \ + DEST = ((FLOAT_SNAN ## BITS(status_) >> 6) << 6) | c; \ } \ } while (0) diff --git a/target/mips/tcg/nanomips_translate.c.inc b/target/mips/tcg/nanomips_translate.c.inc index a98dde0d2e..d81a7c2d11 100644 --- a/target/mips/tcg/nanomips_translate.c.inc +++ b/target/mips/tcg/nanomips_translate.c.inc @@ -4407,8 +4407,8 @@ static int decode_nanomips_32_48_opc(CPUMIPSState *env, DisasContext *ctx) case NM_BPOSGE32C: check_dsp_r3(ctx); { - int32_t imm = extract32(ctx->opcode, 1, 13) | - extract32(ctx->opcode, 0, 1) << 13; + imm = extract32(ctx->opcode, 1, 13) + | extract32(ctx->opcode, 0, 1) << 13; gen_compute_branch_nm(ctx, OPC_BPOSGE32, 4, -1, -2, imm << 1); @@ -4635,7 +4635,7 @@ static int decode_isa_nanomips(CPUMIPSState *env, DisasContext *ctx) break; case NM_LI16: { - int imm = extract32(ctx->opcode, 0, 7); + imm = extract32(ctx->opcode, 0, 7); imm = (imm == 0x7f ? -1 : imm); if (rt != 0) { tcg_gen_movi_tl(cpu_gpr[rt], imm); diff --git a/target/mips/tcg/translate.c b/target/mips/tcg/translate.c index 9bb40f1849..26d741d960 100644 --- a/target/mips/tcg/translate.c +++ b/target/mips/tcg/translate.c @@ -15564,10 +15564,8 @@ void gen_intermediate_code(CPUState *cs, TranslationBlock *tb, int *max_insns, void mips_tcg_init(void) { - int i; - cpu_gpr[0] = NULL; - for (i = 1; i < 32; i++) + for (unsigned i = 1; i < 32; i++) cpu_gpr[i] = tcg_global_mem_new(cpu_env, offsetof(CPUMIPSState, active_tc.gpr[i]), @@ -15584,7 +15582,7 @@ void mips_tcg_init(void) rname); } #endif /* !TARGET_MIPS64 */ - for (i = 0; i < 32; i++) { + for (unsigned i = 0; i < 32; i++) { int off = offsetof(CPUMIPSState, active_fpu.fpr[i].wr.d[0]); fpu_f64[i] = tcg_global_mem_new_i64(cpu_env, off, fregnames[i]); @@ -15592,7 +15590,7 @@ void mips_tcg_init(void) msa_translate_init(); cpu_PC = tcg_global_mem_new(cpu_env, offsetof(CPUMIPSState, active_tc.PC), "PC"); - for (i = 0; i < MIPS_DSP_ACC; i++) { + for (unsigned i = 0; i < MIPS_DSP_ACC; i++) { cpu_HI[i] = tcg_global_mem_new(cpu_env, offsetof(CPUMIPSState, active_tc.HI[i]), regnames_HI[i]); From 574d57254596d328d1a3c419e138e69369f2a98b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Mon, 4 Sep 2023 18:12:17 +0200 Subject: [PATCH 0054/1077] target/m68k: Clean up local variable shadowing MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fix: target/m68k/translate.c:828:18: error: declaration shadows a local variable [-Werror,-Wshadow] TCGv tmp = tcg_temp_new(); ^ target/m68k/translate.c:801:15: note: previous declaration is here TCGv reg, tmp, result; ^ Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Peter Maydell Message-ID: <20230904161235.84651-6-philmd@linaro.org> Signed-off-by: Markus Armbruster --- target/m68k/translate.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/target/m68k/translate.c b/target/m68k/translate.c index 9e224fe796..15c9ddf427 100644 --- a/target/m68k/translate.c +++ b/target/m68k/translate.c @@ -824,7 +824,7 @@ static TCGv gen_ea_mode(CPUM68KState *env, DisasContext *s, int mode, int reg0, reg = get_areg(s, reg0); result = gen_ldst(s, opsize, reg, val, what, index); if (what == EA_STORE || !addrp) { - TCGv tmp = tcg_temp_new(); + tmp = tcg_temp_new(); if (reg0 == 7 && opsize == OS_BYTE && m68k_feature(s->env, M68K_FEATURE_M68K)) { tcg_gen_addi_i32(tmp, reg, 2); From 81b8056a41eabff08e243c80b628fc18bfac2b73 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Mon, 4 Sep 2023 18:12:18 +0200 Subject: [PATCH 0055/1077] target/tricore: Clean up local variable shadowing MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fix: target/tricore/translate.c:5016:18: warning: declaration of ‘temp’ shadows a previous local [-Wshadow=compatible-local] 5016 | TCGv temp = tcg_constant_i32(const9); | ^~~~ target/tricore/translate.c:4958:10: note: shadowed declaration is here 4958 | TCGv temp; | ^~~~ Signed-off-by: Philippe Mathieu-Daudé Message-ID: <20230904161235.84651-7-philmd@linaro.org> Reviewed-by: Bastian Koppelmann Signed-off-by: Markus Armbruster --- target/tricore/translate.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/target/tricore/translate.c b/target/tricore/translate.c index 6ae5ccbf72..9ca211b2a8 100644 --- a/target/tricore/translate.c +++ b/target/tricore/translate.c @@ -4962,8 +4962,6 @@ static void decode_rc_logical_shift(DisasContext *ctx) const9 = MASK_OP_RC_CONST9(ctx->opcode); op2 = MASK_OP_RC_OP2(ctx->opcode); - temp = tcg_temp_new(); - switch (op2) { case OPC2_32_RC_AND: tcg_gen_andi_tl(cpu_gpr_d[r2], cpu_gpr_d[r1], const9); @@ -4972,10 +4970,12 @@ static void decode_rc_logical_shift(DisasContext *ctx) tcg_gen_andi_tl(cpu_gpr_d[r2], cpu_gpr_d[r1], ~const9); break; case OPC2_32_RC_NAND: + temp = tcg_temp_new(); tcg_gen_movi_tl(temp, const9); tcg_gen_nand_tl(cpu_gpr_d[r2], cpu_gpr_d[r1], temp); break; case OPC2_32_RC_NOR: + temp = tcg_temp_new(); tcg_gen_movi_tl(temp, const9); tcg_gen_nor_tl(cpu_gpr_d[r2], cpu_gpr_d[r1], temp); break; @@ -5013,7 +5013,7 @@ static void decode_rc_logical_shift(DisasContext *ctx) break; case OPC2_32_RC_SHUFFLE: if (has_feature(ctx, TRICORE_FEATURE_162)) { - TCGv temp = tcg_constant_i32(const9); + temp = tcg_constant_i32(const9); gen_helper_shuffle(cpu_gpr_d[r2], cpu_gpr_d[r1], temp); } else { generate_trap(ctx, TRAPC_INSN_ERR, TIN2_IOPC); From 807e4d1d2155b7cf4d18bf4e0a73c4e7023f0d57 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Mon, 4 Sep 2023 18:12:19 +0200 Subject: [PATCH 0056/1077] hw/arm/armv7m: Clean up local variable shadowing MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fix: hw/arm/armv7m.c: In function ‘armv7m_realize’: hw/arm/armv7m.c:520:27: warning: declaration of ‘sbd’ shadows a previous local [-Wshadow=compatible-local] 520 | SysBusDevice *sbd = SYS_BUS_DEVICE(&s->bitband[i]); | ^~~ hw/arm/armv7m.c:278:19: note: shadowed declaration is here 278 | SysBusDevice *sbd; | ^~~ --- hw/arm/armsse.c: In function ‘armsse_realize’: hw/arm/armsse.c:1471:27: warning: declaration of ‘mr’ shadows a previous local [-Wshadow=compatible-local] 1471 | MemoryRegion *mr; | ^~ hw/arm/armsse.c:917:19: note: shadowed declaration is here 917 | MemoryRegion *mr; | ^~ --- hw/arm/armsse.c:1608:22: warning: declaration of ‘dev_splitter’ shadows a previous local [-Wshadow=compatible-local] 1608 | DeviceState *dev_splitter = DEVICE(splitter); | ^~~~~~~~~~~~ hw/arm/armsse.c:923:18: note: shadowed declaration is here 923 | DeviceState *dev_splitter; | ^~~~~~~~~~~~ Signed-off-by: Philippe Mathieu-Daudé Message-ID: <20230904161235.84651-8-philmd@linaro.org> Reviewed-by: Peter Maydell Signed-off-by: Markus Armbruster --- hw/arm/armsse.c | 16 ++++++---------- hw/arm/armv7m.c | 2 +- 2 files changed, 7 insertions(+), 11 deletions(-) diff --git a/hw/arm/armsse.c b/hw/arm/armsse.c index 11cd08b6c1..31acbf7347 100644 --- a/hw/arm/armsse.c +++ b/hw/arm/armsse.c @@ -1468,7 +1468,6 @@ static void armsse_realize(DeviceState *dev, Error **errp) if (info->has_cachectrl) { for (i = 0; i < info->num_cpus; i++) { char *name = g_strdup_printf("cachectrl%d", i); - MemoryRegion *mr; qdev_prop_set_string(DEVICE(&s->cachectrl[i]), "name", name); g_free(name); @@ -1484,7 +1483,6 @@ static void armsse_realize(DeviceState *dev, Error **errp) if (info->has_cpusecctrl) { for (i = 0; i < info->num_cpus; i++) { char *name = g_strdup_printf("CPUSECCTRL%d", i); - MemoryRegion *mr; qdev_prop_set_string(DEVICE(&s->cpusecctrl[i]), "name", name); g_free(name); @@ -1499,7 +1497,6 @@ static void armsse_realize(DeviceState *dev, Error **errp) } if (info->has_cpuid) { for (i = 0; i < info->num_cpus; i++) { - MemoryRegion *mr; qdev_prop_set_uint32(DEVICE(&s->cpuid[i]), "CPUID", i); if (!sysbus_realize(SYS_BUS_DEVICE(&s->cpuid[i]), errp)) { @@ -1512,7 +1509,6 @@ static void armsse_realize(DeviceState *dev, Error **errp) } if (info->has_cpu_pwrctrl) { for (i = 0; i < info->num_cpus; i++) { - MemoryRegion *mr; if (!sysbus_realize(SYS_BUS_DEVICE(&s->cpu_pwrctrl[i]), errp)) { return; @@ -1605,7 +1601,7 @@ static void armsse_realize(DeviceState *dev, Error **errp) /* Wire up the splitters for the MPC IRQs */ for (i = 0; i < IOTS_NUM_EXP_MPC + info->sram_banks; i++) { SplitIRQ *splitter = &s->mpc_irq_splitter[i]; - DeviceState *dev_splitter = DEVICE(splitter); + DeviceState *devs = DEVICE(splitter); if (!object_property_set_int(OBJECT(splitter), "num-lines", 2, errp)) { @@ -1617,22 +1613,22 @@ static void armsse_realize(DeviceState *dev, Error **errp) if (i < IOTS_NUM_EXP_MPC) { /* Splitter input is from GPIO input line */ - s->mpcexp_status_in[i] = qdev_get_gpio_in(dev_splitter, 0); - qdev_connect_gpio_out(dev_splitter, 0, + s->mpcexp_status_in[i] = qdev_get_gpio_in(devs, 0); + qdev_connect_gpio_out(devs, 0, qdev_get_gpio_in_named(dev_secctl, "mpcexp_status", i)); } else { /* Splitter input is from our own MPC */ qdev_connect_gpio_out_named(DEVICE(&s->mpc[i - IOTS_NUM_EXP_MPC]), "irq", 0, - qdev_get_gpio_in(dev_splitter, 0)); - qdev_connect_gpio_out(dev_splitter, 0, + qdev_get_gpio_in(devs, 0)); + qdev_connect_gpio_out(devs, 0, qdev_get_gpio_in_named(dev_secctl, "mpc_status", i - IOTS_NUM_EXP_MPC)); } - qdev_connect_gpio_out(dev_splitter, 1, + qdev_connect_gpio_out(devs, 1, qdev_get_gpio_in(DEVICE(&s->mpc_irq_orgate), i)); } /* Create GPIO inputs which will pass the line state for our diff --git a/hw/arm/armv7m.c b/hw/arm/armv7m.c index bf173b10b8..1f78e18872 100644 --- a/hw/arm/armv7m.c +++ b/hw/arm/armv7m.c @@ -517,7 +517,7 @@ static void armv7m_realize(DeviceState *dev, Error **errp) for (i = 0; i < ARRAY_SIZE(s->bitband); i++) { if (s->enable_bitband) { Object *obj = OBJECT(&s->bitband[i]); - SysBusDevice *sbd = SYS_BUS_DEVICE(&s->bitband[i]); + sbd = SYS_BUS_DEVICE(&s->bitband[i]); if (!object_property_set_int(obj, "base", bitband_input_addr[i], errp)) { From c7f14e4898bb4fcaa1420434bf4331e2843946fd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Mon, 4 Sep 2023 18:12:20 +0200 Subject: [PATCH 0057/1077] hw/arm/virt: Clean up local variable shadowing MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fix: hw/arm/virt.c:821:22: error: declaration shadows a local variable [-Werror,-Wshadow] qemu_irq irq = qdev_get_gpio_in(vms->gic, ^ hw/arm/virt.c:803:13: note: previous declaration is here int irq; ^ Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Peter Maydell Message-ID: <20230904161235.84651-9-philmd@linaro.org> Signed-off-by: Markus Armbruster --- hw/arm/virt.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/hw/arm/virt.c b/hw/arm/virt.c index 8ad78b23c2..15e74249f9 100644 --- a/hw/arm/virt.c +++ b/hw/arm/virt.c @@ -801,7 +801,6 @@ static void create_gic(VirtMachineState *vms, MemoryRegion *mem) for (i = 0; i < smp_cpus; i++) { DeviceState *cpudev = DEVICE(qemu_get_cpu(i)); int ppibase = NUM_IRQS + i * GIC_INTERNAL + GIC_NR_SGIS; - int irq; /* Mapping from the output timer irq lines from the CPU to the * GIC PPI inputs we use for the virt board. */ @@ -812,7 +811,7 @@ static void create_gic(VirtMachineState *vms, MemoryRegion *mem) [GTIMER_SEC] = ARCH_TIMER_S_EL1_IRQ, }; - for (irq = 0; irq < ARRAY_SIZE(timer_irq); irq++) { + for (unsigned irq = 0; irq < ARRAY_SIZE(timer_irq); irq++) { qdev_connect_gpio_out(cpudev, irq, qdev_get_gpio_in(vms->gic, ppibase + timer_irq[irq])); From 2f6037a2359fb653704ff240fb552bd77537f9ec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Mon, 4 Sep 2023 18:12:21 +0200 Subject: [PATCH 0058/1077] hw/arm/allwinner: Clean up local variable shadowing MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fix: hw/arm/allwinner-r40.c:412:14: error: declaration shadows a local variable [-Werror,-Wshadow] for (int i = 0; i < AW_R40_NUM_MMCS; i++) { ^ hw/arm/allwinner-r40.c:299:14: note: previous declaration is here unsigned i; ^ Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Peter Maydell Message-ID: <20230904161235.84651-10-philmd@linaro.org> Signed-off-by: Markus Armbruster --- hw/arm/allwinner-r40.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/hw/arm/allwinner-r40.c b/hw/arm/allwinner-r40.c index 7d29eb224f..a0d367c60d 100644 --- a/hw/arm/allwinner-r40.c +++ b/hw/arm/allwinner-r40.c @@ -296,10 +296,9 @@ static void allwinner_r40_realize(DeviceState *dev, Error **errp) { const char *r40_nic_models[] = { "gmac", "emac", NULL }; AwR40State *s = AW_R40(dev); - unsigned i; /* CPUs */ - for (i = 0; i < AW_R40_NUM_CPUS; i++) { + for (unsigned i = 0; i < AW_R40_NUM_CPUS; i++) { /* * Disable secondary CPUs. Guest EL3 firmware will start @@ -335,7 +334,7 @@ static void allwinner_r40_realize(DeviceState *dev, Error **errp) * maintenance interrupt signal to the appropriate GIC PPI inputs, * and the GIC's IRQ/FIQ/VIRQ/VFIQ interrupt outputs to the CPU's inputs. */ - for (i = 0; i < AW_R40_NUM_CPUS; i++) { + for (unsigned i = 0; i < AW_R40_NUM_CPUS; i++) { DeviceState *cpudev = DEVICE(&s->cpus[i]); int ppibase = AW_R40_GIC_NUM_SPI + i * GIC_INTERNAL + GIC_NR_SGIS; int irq; @@ -494,7 +493,7 @@ static void allwinner_r40_realize(DeviceState *dev, Error **errp) qdev_get_gpio_in(DEVICE(&s->gic), AW_R40_GIC_SPI_EMAC)); /* Unimplemented devices */ - for (i = 0; i < ARRAY_SIZE(r40_unimplemented); i++) { + for (unsigned i = 0; i < ARRAY_SIZE(r40_unimplemented); i++) { create_unimplemented_device(r40_unimplemented[i].device_name, r40_unimplemented[i].base, r40_unimplemented[i].size); From 5f87dddbc2aaa126a6c1334115a5ec9bd33fb62a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Mon, 4 Sep 2023 18:12:24 +0200 Subject: [PATCH 0059/1077] hw/m68k: Clean up local variable shadowing MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fix: hw/m68k/virt.c:263:13: error: declaration shadows a local variable [-Werror,-Wshadow] BOOTINFOSTR(param_ptr, BI_COMMAND_LINE, ^ hw/m68k/bootinfo.h:47:13: note: expanded from macro 'BOOTINFOSTR' int i; \ ^ hw/m68k/virt.c:130:9: note: previous declaration is here int i; ^ Signed-off-by: Philippe Mathieu-Daudé Message-ID: <20230904161235.84651-13-philmd@linaro.org> Reviewed-by: Thomas Huth Signed-off-by: Markus Armbruster --- hw/m68k/bootinfo.h | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/hw/m68k/bootinfo.h b/hw/m68k/bootinfo.h index a3d37e3c80..0e6e3eea87 100644 --- a/hw/m68k/bootinfo.h +++ b/hw/m68k/bootinfo.h @@ -44,15 +44,14 @@ #define BOOTINFOSTR(base, id, string) \ do { \ - int i; \ stw_p(base, id); \ base += 2; \ stw_p(base, \ (sizeof(struct bi_record) + strlen(string) + \ 1 /* null termination */ + 3 /* padding */) & ~3); \ base += 2; \ - for (i = 0; string[i]; i++) { \ - stb_p(base++, string[i]); \ + for (unsigned i_ = 0; string[i_]; i_++) { \ + stb_p(base++, string[i_]); \ } \ stb_p(base++, 0); \ base = QEMU_ALIGN_PTR_UP(base, 4); \ @@ -60,7 +59,6 @@ #define BOOTINFODATA(base, id, data, len) \ do { \ - int i; \ stw_p(base, id); \ base += 2; \ stw_p(base, \ @@ -69,8 +67,8 @@ base += 2; \ stw_p(base, len); \ base += 2; \ - for (i = 0; i < len; ++i) { \ - stb_p(base++, data[i]); \ + for (unsigned i_ = 0; i_ < len; ++i_) { \ + stb_p(base++, data[i_]); \ } \ base = QEMU_ALIGN_PTR_UP(base, 4); \ } while (0) From 4705c8e5a2d0e62a276ce21e6b15bff0e7e42bdf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Mon, 4 Sep 2023 18:12:25 +0200 Subject: [PATCH 0060/1077] hw/microblaze: Clean up local variable shadowing MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fix: hw/microblaze/petalogix_ml605_mmu.c: In function ‘petalogix_ml605_init’: hw/microblaze/petalogix_ml605_mmu.c:186:24: warning: declaration of ‘dinfo’ shadows a previous local [-Wshadow=compatible-local] 186 | DriveInfo *dinfo = drive_get(IF_MTD, 0, i); | ^~~~~ hw/microblaze/petalogix_ml605_mmu.c:78:16: note: shadowed declaration is here 78 | DriveInfo *dinfo; | ^~~~~ Signed-off-by: Philippe Mathieu-Daudé Message-ID: <20230904161235.84651-14-philmd@linaro.org> Signed-off-by: Markus Armbruster --- hw/microblaze/petalogix_ml605_mmu.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/microblaze/petalogix_ml605_mmu.c b/hw/microblaze/petalogix_ml605_mmu.c index ea0fb68cf0..fb7889cf67 100644 --- a/hw/microblaze/petalogix_ml605_mmu.c +++ b/hw/microblaze/petalogix_ml605_mmu.c @@ -183,7 +183,7 @@ petalogix_ml605_init(MachineState *machine) spi = (SSIBus *)qdev_get_child_bus(dev, "spi"); for (i = 0; i < NUM_SPI_FLASHES; i++) { - DriveInfo *dinfo = drive_get(IF_MTD, 0, i); + dinfo = drive_get(IF_MTD, 0, i); qemu_irq cs_line; dev = qdev_new("n25q128"); From 09e24b10de02b19d193d85645c19a68b98263bef Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Mon, 4 Sep 2023 18:12:26 +0200 Subject: [PATCH 0061/1077] hw/nios2: Clean up local variable shadowing MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fix: hw/nios2/10m50_devboard.c: In function ‘nios2_10m50_ghrd_init’: hw/nios2/10m50_devboard.c:101:22: warning: declaration of ‘dev’ shadows a previous local [-Wshadow=compatible-local] 101 | DeviceState *dev = qdev_new(TYPE_NIOS2_VIC); | ^~~ hw/nios2/10m50_devboard.c:60:18: note: shadowed declaration is here 60 | DeviceState *dev; | ^~~ hw/nios2/10m50_devboard.c:110:18: warning: declaration of ‘i’ shadows a previous local [-Wshadow=compatible-local] 110 | for (int i = 0; i < 32; i++) { | ^ hw/nios2/10m50_devboard.c:67:9: note: shadowed declaration is here 67 | int i; | ^ Signed-off-by: Philippe Mathieu-Daudé Message-ID: <20230904161235.84651-15-philmd@linaro.org> Signed-off-by: Markus Armbruster --- hw/nios2/10m50_devboard.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/hw/nios2/10m50_devboard.c b/hw/nios2/10m50_devboard.c index 91383fb097..952a0dc33e 100644 --- a/hw/nios2/10m50_devboard.c +++ b/hw/nios2/10m50_devboard.c @@ -98,7 +98,7 @@ static void nios2_10m50_ghrd_init(MachineState *machine) qdev_realize_and_unref(DEVICE(cpu), NULL, &error_fatal); if (nms->vic) { - DeviceState *dev = qdev_new(TYPE_NIOS2_VIC); + dev = qdev_new(TYPE_NIOS2_VIC); MemoryRegion *dev_mr; qemu_irq cpu_irq; @@ -107,7 +107,7 @@ static void nios2_10m50_ghrd_init(MachineState *machine) cpu_irq = qdev_get_gpio_in_named(DEVICE(cpu), "EIC", 0); sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, cpu_irq); - for (int i = 0; i < 32; i++) { + for (i = 0; i < 32; i++) { irq[i] = qdev_get_gpio_in(dev, i); } From 1728593a82cdd8ffcd2a5a759fb301c71ae4c251 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Mon, 4 Sep 2023 18:12:27 +0200 Subject: [PATCH 0062/1077] net/eth: Clean up local variable shadowing MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fix: net/eth.c:435:20: error: declaration shadows a local variable [-Werror,-Wshadow] size_t input_size = iov_size(pkt, pkt_frags); ^ net/eth.c:413:16: note: previous declaration is here size_t input_size = iov_size(pkt, pkt_frags); ^ Suggested-by: Akihiko Odaki Signed-off-by: Philippe Mathieu-Daudé Message-ID: <20230904161235.84651-16-philmd@linaro.org> Reviewed-by: Eric Blake Reviewed-by: Akihiko Odaki Signed-off-by: Markus Armbruster --- net/eth.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/net/eth.c b/net/eth.c index 649e66bb1f..3f680cc033 100644 --- a/net/eth.c +++ b/net/eth.c @@ -432,8 +432,6 @@ _eth_get_rss_ex_src_addr(const struct iovec *pkt, int pkt_frags, } if (opthdr.type == IP6_OPT_HOME) { - size_t input_size = iov_size(pkt, pkt_frags); - if (input_size < opt_offset + sizeof(opthdr)) { return false; } From 5f6d4f79af6eb4b0eed9cb3272073841514ca989 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Mon, 4 Sep 2023 18:12:28 +0200 Subject: [PATCH 0063/1077] crypto/cipher-gnutls.c: Clean up local variable shadowing MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fix: In file included from crypto/cipher.c:140: crypto/cipher-gnutls.c.inc: In function ‘qcrypto_gnutls_cipher_encrypt’: crypto/cipher-gnutls.c.inc:116:17: warning: declaration of ‘err’ shadows a previous local [-Wshadow=compatible-local] 116 | int err = gnutls_cipher_init(&handle, ctx->galg, &gkey, NULL); | ^~~ crypto/cipher-gnutls.c.inc:94:9: note: shadowed declaration is here 94 | int err; | ^~~ --- crypto/cipher-gnutls.c.inc: In function ‘qcrypto_gnutls_cipher_decrypt’: crypto/cipher-gnutls.c.inc:177:17: warning: declaration of ‘err’ shadows a previous local [-Wshadow=compatible-local] 177 | int err = gnutls_cipher_init(&handle, ctx->galg, &gkey, NULL); | ^~~ crypto/cipher-gnutls.c.inc:154:9: note: shadowed declaration is here 154 | int err; | ^~~ Signed-off-by: Philippe Mathieu-Daudé Message-ID: <20230904161235.84651-17-philmd@linaro.org> Reviewed-by: Daniel P. Berrangé Signed-off-by: Markus Armbruster --- crypto/cipher-gnutls.c.inc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/crypto/cipher-gnutls.c.inc b/crypto/cipher-gnutls.c.inc index 501e4e07a5..d3e231c13c 100644 --- a/crypto/cipher-gnutls.c.inc +++ b/crypto/cipher-gnutls.c.inc @@ -113,7 +113,7 @@ qcrypto_gnutls_cipher_encrypt(QCryptoCipher *cipher, while (len) { gnutls_cipher_hd_t handle; gnutls_datum_t gkey = { (unsigned char *)ctx->key, ctx->nkey }; - int err = gnutls_cipher_init(&handle, ctx->galg, &gkey, NULL); + err = gnutls_cipher_init(&handle, ctx->galg, &gkey, NULL); if (err != 0) { error_setg(errp, "Cannot initialize cipher: %s", gnutls_strerror(err)); @@ -174,7 +174,7 @@ qcrypto_gnutls_cipher_decrypt(QCryptoCipher *cipher, while (len) { gnutls_cipher_hd_t handle; gnutls_datum_t gkey = { (unsigned char *)ctx->key, ctx->nkey }; - int err = gnutls_cipher_init(&handle, ctx->galg, &gkey, NULL); + err = gnutls_cipher_init(&handle, ctx->galg, &gkey, NULL); if (err != 0) { error_setg(errp, "Cannot initialize cipher: %s", gnutls_strerror(err)); From fbf58f2141f670c1e4fc63be36e8a45330ab1e3d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Mon, 4 Sep 2023 18:12:29 +0200 Subject: [PATCH 0064/1077] util/vhost-user-server: Clean up local variable shadowing MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fix: util/vhost-user-server.c: In function ‘set_watch’: util/vhost-user-server.c:274:20: warning: declaration of ‘vu_fd_watch’ shadows a previous local [-Wshadow=compatible-local] 274 | VuFdWatch *vu_fd_watch = g_new0(VuFdWatch, 1); | ^~~~~~~~~~~ util/vhost-user-server.c:271:16: note: shadowed declaration is here 271 | VuFdWatch *vu_fd_watch = find_vu_fd_watch(server, fd); | ^~~~~~~~~~~ Signed-off-by: Philippe Mathieu-Daudé Message-ID: <20230904161235.84651-18-philmd@linaro.org> Reviewed-by: Michael S. Tsirkin Signed-off-by: Markus Armbruster --- util/vhost-user-server.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/util/vhost-user-server.c b/util/vhost-user-server.c index b4b6bf30a2..5ccc6d24a0 100644 --- a/util/vhost-user-server.c +++ b/util/vhost-user-server.c @@ -278,7 +278,7 @@ set_watch(VuDev *vu_dev, int fd, int vu_evt, VuFdWatch *vu_fd_watch = find_vu_fd_watch(server, fd); if (!vu_fd_watch) { - VuFdWatch *vu_fd_watch = g_new0(VuFdWatch, 1); + vu_fd_watch = g_new0(VuFdWatch, 1); QTAILQ_INSERT_TAIL(&server->vu_fd_watches, vu_fd_watch, next); From 7f087a323768585bb6063a1ee05a03a52b6a0b8f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Mon, 4 Sep 2023 18:12:31 +0200 Subject: [PATCH 0065/1077] linux-user/strace: Clean up local variable shadowing MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fix: linux-user/strace.c: In function ‘print_sockaddr’: linux-user/strace.c:370:17: warning: declaration of ‘i’ shadows a previous local [-Wshadow=compatible-local] 370 | int i; | ^ linux-user/strace.c:361:9: note: shadowed declaration is here 361 | int i; | ^ Signed-off-by: Philippe Mathieu-Daudé Message-ID: <20230904161235.84651-20-philmd@linaro.org> Signed-off-by: Markus Armbruster --- linux-user/strace.c | 1 - 1 file changed, 1 deletion(-) diff --git a/linux-user/strace.c b/linux-user/strace.c index e0ab8046ec..cf26e55264 100644 --- a/linux-user/strace.c +++ b/linux-user/strace.c @@ -367,7 +367,6 @@ print_sockaddr(abi_ulong addr, abi_long addrlen, int last) switch (sa_family) { case AF_UNIX: { struct target_sockaddr_un *un = (struct target_sockaddr_un *)sa; - int i; qemu_log("{sun_family=AF_UNIX,sun_path=\""); for (i = 0; i < addrlen - offsetof(struct target_sockaddr_un, sun_path) && From 720d6bcdbb9fd6781025f245c8d02ce179a2fc86 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Mon, 4 Sep 2023 18:12:32 +0200 Subject: [PATCH 0066/1077] sysemu/device_tree: Clean up local variable shadowing MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fix: hw/mips/boston.c:472:5: error: declaration shadows a local variable [-Werror,-Wshadow] qemu_fdt_setprop_cells(fdt, name, "reg", reg_base, reg_size); ^ include/sysemu/device_tree.h:129:13: note: expanded from macro 'qemu_fdt_setprop_cells' int i; ^ hw/mips/boston.c:461:9: note: previous declaration is here int i; ^ Signed-off-by: Philippe Mathieu-Daudé Message-ID: <20230904161235.84651-21-philmd@linaro.org> Reviewed-by: Markus Armbruster Signed-off-by: Markus Armbruster --- include/sysemu/device_tree.h | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/include/sysemu/device_tree.h b/include/sysemu/device_tree.h index ca5339beae..8eab395934 100644 --- a/include/sysemu/device_tree.h +++ b/include/sysemu/device_tree.h @@ -126,10 +126,8 @@ int qemu_fdt_add_path(void *fdt, const char *path); #define qemu_fdt_setprop_cells(fdt, node_path, property, ...) \ do { \ uint32_t qdt_tmp[] = { __VA_ARGS__ }; \ - int i; \ - \ - for (i = 0; i < ARRAY_SIZE(qdt_tmp); i++) { \ - qdt_tmp[i] = cpu_to_be32(qdt_tmp[i]); \ + for (unsigned i_ = 0; i_ < ARRAY_SIZE(qdt_tmp); i_++) { \ + qdt_tmp[i_] = cpu_to_be32(qdt_tmp[i_]); \ } \ qemu_fdt_setprop(fdt, node_path, property, qdt_tmp, \ sizeof(qdt_tmp)); \ From 083f450f659c0d34766d80a99878d2a1e5f8f495 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Mon, 4 Sep 2023 18:12:33 +0200 Subject: [PATCH 0067/1077] softmmu/memory: Clean up local variable shadowing MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fix: softmmu/memory.c: In function ‘mtree_print_mr’: softmmu/memory.c:3236:27: warning: declaration of ‘ml’ shadows a previous local [-Wshadow=compatible-local] 3236 | MemoryRegionList *ml; | ^~ softmmu/memory.c:3213:32: note: shadowed declaration is here 3213 | MemoryRegionList *new_ml, *ml, *next_ml; | ^~ Signed-off-by: Philippe Mathieu-Daudé Message-ID: <20230904161235.84651-22-philmd@linaro.org> Reviewed-by: Peter Xu Signed-off-by: Markus Armbruster --- softmmu/memory.c | 1 - 1 file changed, 1 deletion(-) diff --git a/softmmu/memory.c b/softmmu/memory.c index c0383a163d..234bd7b116 100644 --- a/softmmu/memory.c +++ b/softmmu/memory.c @@ -3245,7 +3245,6 @@ static void mtree_print_mr(const MemoryRegion *mr, unsigned int level, } if (mr->alias) { - MemoryRegionList *ml; bool found = false; /* check if the alias is already in the queue */ From 6ba9b60a93d4f4df70205cbeb6c547a863f3c170 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Mon, 4 Sep 2023 18:12:34 +0200 Subject: [PATCH 0068/1077] softmmu/physmem: Clean up local variable shadowing MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fix: softmmu/physmem.c: In function ‘cpu_physical_memory_snapshot_and_clear_dirty’: softmmu/physmem.c:916:27: warning: declaration of ‘offset’ shadows a parameter [-Wshadow=compatible-local] 916 | unsigned long offset = page % DIRTY_MEMORY_BLOCK_SIZE; | ^~~~~~ softmmu/physmem.c:892:31: note: shadowed declaration is here 892 | (MemoryRegion *mr, hwaddr offset, hwaddr length, unsigned client) | ~~~~~~~^~~~~~ Signed-off-by: Philippe Mathieu-Daudé Message-ID: <20230904161235.84651-23-philmd@linaro.org> Reviewed-by: Daniel P. Berrangé Reviewed-by: Peter Xu Signed-off-by: Markus Armbruster --- softmmu/physmem.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/softmmu/physmem.c b/softmmu/physmem.c index 4f6ca653b3..309653c722 100644 --- a/softmmu/physmem.c +++ b/softmmu/physmem.c @@ -913,16 +913,16 @@ DirtyBitmapSnapshot *cpu_physical_memory_snapshot_and_clear_dirty while (page < end) { unsigned long idx = page / DIRTY_MEMORY_BLOCK_SIZE; - unsigned long offset = page % DIRTY_MEMORY_BLOCK_SIZE; + unsigned long ofs = page % DIRTY_MEMORY_BLOCK_SIZE; unsigned long num = MIN(end - page, - DIRTY_MEMORY_BLOCK_SIZE - offset); + DIRTY_MEMORY_BLOCK_SIZE - ofs); - assert(QEMU_IS_ALIGNED(offset, (1 << BITS_PER_LEVEL))); + assert(QEMU_IS_ALIGNED(ofs, (1 << BITS_PER_LEVEL))); assert(QEMU_IS_ALIGNED(num, (1 << BITS_PER_LEVEL))); - offset >>= BITS_PER_LEVEL; + ofs >>= BITS_PER_LEVEL; bitmap_copy_and_clear_atomic(snap->dirty + dest, - blocks->blocks[idx] + offset, + blocks->blocks[idx] + ofs, num); page += num; dest += num >> BITS_PER_LEVEL; From 5e0528a72570e95945eac841b0871f0cbba777b8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Mon, 4 Sep 2023 18:28:22 +0200 Subject: [PATCH 0069/1077] hw/core/machine: Clean up local variable shadowing MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fix: hw/core/machine.c: In function ‘machine_initfn’: hw/core/machine.c:1081:17: warning: declaration of ‘obj’ shadows a parameter [-Wshadow=compatible-local] 1081 | Object *obj = OBJECT(ms); | ^~~ hw/core/machine.c:1065:36: note: shadowed declaration is here 1065 | static void machine_initfn(Object *obj) | ~~~~~~~~^~~ Signed-off-by: Philippe Mathieu-Daudé Message-ID: <20230904162824.85385-2-philmd@linaro.org> Reviewed-by: Peter Maydell Signed-off-by: Markus Armbruster --- hw/core/machine.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/hw/core/machine.c b/hw/core/machine.c index cb38b8cf4c..a232ae0bcd 100644 --- a/hw/core/machine.c +++ b/hw/core/machine.c @@ -1082,8 +1082,6 @@ static void machine_initfn(Object *obj) ms->maxram_size = mc->default_ram_size; if (mc->nvdimm_supported) { - Object *obj = OBJECT(ms); - ms->nvdimms_state = g_new0(NVDIMMState, 1); object_property_add_bool(obj, "nvdimm", machine_get_nvdimm, machine_set_nvdimm); From 1cc0c5dd38884a7c54bc806bb0ae182db275faf0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Mon, 4 Sep 2023 18:28:23 +0200 Subject: [PATCH 0070/1077] hw/intc/openpic: Clean up local variable shadowing MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fix: hw/intc/openpic.c: In function ‘openpic_gbl_write’: hw/intc/openpic.c:614:17: warning: declaration of ‘idx’ shadows a previous local [-Wshadow=compatible-local] 614 | int idx; | ^~~ hw/intc/openpic.c:568:9: note: shadowed declaration is here 568 | int idx; | ^~~ Signed-off-by: Philippe Mathieu-Daudé Message-ID: <20230904162824.85385-3-philmd@linaro.org> Reviewed-by: Peter Maydell Signed-off-by: Markus Armbruster --- hw/intc/openpic.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/hw/intc/openpic.c b/hw/intc/openpic.c index c757adbe53..a6f91d4bcd 100644 --- a/hw/intc/openpic.c +++ b/hw/intc/openpic.c @@ -610,11 +610,8 @@ static void openpic_gbl_write(void *opaque, hwaddr addr, uint64_t val, case 0x10B0: case 0x10C0: case 0x10D0: - { - int idx; - idx = (addr - 0x10A0) >> 4; - write_IRQreg_ivpr(opp, opp->irq_ipi0 + idx, val); - } + idx = (addr - 0x10A0) >> 4; + write_IRQreg_ivpr(opp, opp->irq_ipi0 + idx, val); break; case 0x10E0: /* SPVE */ opp->spve = val & opp->vector_mask; From 90231ce1a355ce07b71f9b82446a40ac866585de Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Le=20Goater?= Date: Mon, 18 Sep 2023 16:58:43 +0200 Subject: [PATCH 0071/1077] hw/ppc: Clean up local variable shadowing in _FDT helper routine MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit this fixes numerous warnings of this type : In file included from ../hw/ppc/spapr_pci.c:43: ../hw/ppc/spapr_pci.c: In function ‘spapr_dt_phb’: ../include/hw/ppc/fdt.h:18:13: warning: declaration of ‘ret’ shadows a previous local [-Wshadow=compatible-local] 18 | int ret = (exp); \ | ^~~ ../hw/ppc/spapr_pci.c:2355:5: note: in expansion of macro ‘_FDT’ 2355 | _FDT(bus_off = fdt_add_subnode(fdt, 0, phb->dtbusname)); | ^~~~ ../hw/ppc/spapr_pci.c:2311:24: note: shadowed declaration is here 2311 | int bus_off, i, j, ret; | ^~~ Signed-off-by: Cédric Le Goater Message-ID: <20230918145850.241074-2-clg@kaod.org> Reviewed-by: Harsh Prateek Bora Signed-off-by: Markus Armbruster --- include/hw/ppc/fdt.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/include/hw/ppc/fdt.h b/include/hw/ppc/fdt.h index a8cd85069f..b56ac2a8cb 100644 --- a/include/hw/ppc/fdt.h +++ b/include/hw/ppc/fdt.h @@ -15,10 +15,10 @@ #define _FDT(exp) \ do { \ - int ret = (exp); \ - if (ret < 0) { \ - error_report("error creating device tree: %s: %s", \ - #exp, fdt_strerror(ret)); \ + int _ret = (exp); \ + if (_ret < 0) { \ + error_report("error creating device tree: %s: %s", \ + #exp, fdt_strerror(_ret)); \ exit(1); \ } \ } while (0) From 694616d68455eaa14f860e7a2bbe41043e8340d7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Le=20Goater?= Date: Mon, 18 Sep 2023 16:58:44 +0200 Subject: [PATCH 0072/1077] pnv/psi: Clean up local variable shadowing MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit to fix : ../hw/ppc/pnv_psi.c: In function ‘pnv_psi_p9_mmio_write’: ../hw/ppc/pnv_psi.c:741:24: warning: declaration of ‘addr’ shadows a parameter [-Wshadow=compatible-local] 741 | hwaddr addr = val & ~(PSIHB9_ESB_CI_VALID | PSIHB10_ESB_CI_64K); | ^~~~ ../hw/ppc/pnv_psi.c:702:56: note: shadowed declaration is here 702 | static void pnv_psi_p9_mmio_write(void *opaque, hwaddr addr, | ~~~~~~~^~~~ Signed-off-by: Cédric Le Goater Message-ID: <20230918145850.241074-3-clg@kaod.org> Reviewed-by: Harsh Prateek Bora Signed-off-by: Markus Armbruster --- hw/ppc/pnv_psi.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/hw/ppc/pnv_psi.c b/hw/ppc/pnv_psi.c index daaa2f0575..26460d210d 100644 --- a/hw/ppc/pnv_psi.c +++ b/hw/ppc/pnv_psi.c @@ -738,8 +738,9 @@ static void pnv_psi_p9_mmio_write(void *opaque, hwaddr addr, } } else { if (!(psi->regs[reg] & PSIHB9_ESB_CI_VALID)) { - hwaddr addr = val & ~(PSIHB9_ESB_CI_VALID | PSIHB10_ESB_CI_64K); - memory_region_add_subregion(sysmem, addr, + hwaddr esb_addr = + val & ~(PSIHB9_ESB_CI_VALID | PSIHB10_ESB_CI_64K); + memory_region_add_subregion(sysmem, esb_addr, &psi9->source.esb_mmio); } } From bd87a59f52c85e504323c3dbdacc84e2cefce8d1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Le=20Goater?= Date: Mon, 18 Sep 2023 16:58:45 +0200 Subject: [PATCH 0073/1077] spapr: Clean up local variable shadowing in spapr_dt_cpus() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Introduce a helper routine defining one CPU device node to fix this warning : ../hw/ppc/spapr.c: In function ‘spapr_dt_cpus’: ../hw/ppc/spapr.c:812:19: warning: declaration of ‘cs’ shadows a previous local [-Wshadow=compatible-local] 812 | CPUState *cs = rev[i]; | ^~ ../hw/ppc/spapr.c:786:15: note: shadowed declaration is here 786 | CPUState *cs; | ^~ Signed-off-by: Cédric Le Goater Message-ID: <20230918145850.241074-4-clg@kaod.org> Reviewed-by: Harsh Prateek Bora Signed-off-by: Markus Armbruster --- hw/ppc/spapr.c | 36 +++++++++++++++++++++--------------- 1 file changed, 21 insertions(+), 15 deletions(-) diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c index 1f1aa2a6d4..612dbdf356 100644 --- a/hw/ppc/spapr.c +++ b/hw/ppc/spapr.c @@ -780,6 +780,26 @@ static void spapr_dt_cpu(CPUState *cs, void *fdt, int offset, pcc->lrg_decr_bits))); } +static void spapr_dt_one_cpu(void *fdt, SpaprMachineState *spapr, CPUState *cs, + int cpus_offset) +{ + PowerPCCPU *cpu = POWERPC_CPU(cs); + int index = spapr_get_vcpu_id(cpu); + DeviceClass *dc = DEVICE_GET_CLASS(cs); + g_autofree char *nodename = NULL; + int offset; + + if (!spapr_is_thread0_in_vcore(spapr, cpu)) { + return; + } + + nodename = g_strdup_printf("%s@%x", dc->fw_name, index); + offset = fdt_add_subnode(fdt, cpus_offset, nodename); + _FDT(offset); + spapr_dt_cpu(cs, fdt, offset, spapr); +} + + static void spapr_dt_cpus(void *fdt, SpaprMachineState *spapr) { CPUState **rev; @@ -809,21 +829,7 @@ static void spapr_dt_cpus(void *fdt, SpaprMachineState *spapr) } for (i = n_cpus - 1; i >= 0; i--) { - CPUState *cs = rev[i]; - PowerPCCPU *cpu = POWERPC_CPU(cs); - int index = spapr_get_vcpu_id(cpu); - DeviceClass *dc = DEVICE_GET_CLASS(cs); - g_autofree char *nodename = NULL; - int offset; - - if (!spapr_is_thread0_in_vcore(spapr, cpu)) { - continue; - } - - nodename = g_strdup_printf("%s@%x", dc->fw_name, index); - offset = fdt_add_subnode(fdt, cpus_offset, nodename); - _FDT(offset); - spapr_dt_cpu(cs, fdt, offset, spapr); + spapr_dt_one_cpu(fdt, spapr, rev[i], cpus_offset); } g_free(rev); From c0b648d9e9747f44fc3c4503b3a06741b0d6e4a8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Le=20Goater?= Date: Mon, 18 Sep 2023 16:58:46 +0200 Subject: [PATCH 0074/1077] spapr: Clean up local variable shadowing in spapr_init_cpus() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Remove extra 'i' variable to fix this warning : ../hw/ppc/spapr.c: In function ‘spapr_init_cpus’: ../hw/ppc/spapr.c:2668:13: warning: declaration of ‘i’ shadows a previous local [-Wshadow=compatible-local] 2668 | int i; | ^ ../hw/ppc/spapr.c:2645:9: note: shadowed declaration is here 2645 | int i; | ^ Signed-off-by: Cédric Le Goater Message-ID: <20230918145850.241074-5-clg@kaod.org> Reviewed-by: Harsh Prateek Bora Signed-off-by: Markus Armbruster --- hw/ppc/spapr.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c index 612dbdf356..4fe82e490a 100644 --- a/hw/ppc/spapr.c +++ b/hw/ppc/spapr.c @@ -2665,8 +2665,6 @@ static void spapr_init_cpus(SpaprMachineState *spapr) } if (smc->pre_2_10_has_unused_icps) { - int i; - for (i = 0; i < spapr_max_server_number(spapr); i++) { /* Dummy entries get deregistered when real ICPState objects * are registered during CPU core hotplug. From 01a78f23cbaf15359a051b45c1df05269d5aa4d5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Le=20Goater?= Date: Mon, 18 Sep 2023 16:58:47 +0200 Subject: [PATCH 0075/1077] spapr: Clean up local variable shadowing in spapr_get_fw_dev_path() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Rename PCIDevice variable to avoid this warning : ../hw/ppc/spapr.c: In function ‘spapr_get_fw_dev_path’: ../hw/ppc/spapr.c:3217:20: warning: declaration of ‘pcidev’ shadows a previous local [-Wshadow=compatible-local] 3217 | PCIDevice *pcidev = CAST(PCIDevice, dev, TYPE_PCI_DEVICE); | ^~~~~~ ../hw/ppc/spapr.c:3147:16: note: shadowed declaration is here 3147 | PCIDevice *pcidev = CAST(PCIDevice, dev, TYPE_PCI_DEVICE); | ^~~~~~ Signed-off-by: Cédric Le Goater Message-ID: <20230918145850.241074-6-clg@kaod.org> Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Markus Armbruster --- hw/ppc/spapr.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c index 4fe82e490a..d4230d3647 100644 --- a/hw/ppc/spapr.c +++ b/hw/ppc/spapr.c @@ -3214,8 +3214,8 @@ static char *spapr_get_fw_dev_path(FWPathProvider *p, BusState *bus, if (g_str_equal("pci-bridge", qdev_fw_name(dev))) { /* SLOF uses "pci" instead of "pci-bridge" for PCI bridges */ - PCIDevice *pcidev = CAST(PCIDevice, dev, TYPE_PCI_DEVICE); - return g_strdup_printf("pci@%x", PCI_SLOT(pcidev->devfn)); + PCIDevice *pdev = CAST(PCIDevice, dev, TYPE_PCI_DEVICE); + return g_strdup_printf("pci@%x", PCI_SLOT(pdev->devfn)); } if (pcidev) { From bea3d6e745fe34ca51780b623b10675ed1975b58 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Le=20Goater?= Date: Mon, 18 Sep 2023 16:58:48 +0200 Subject: [PATCH 0076/1077] spapr/drc: Clean up local variable shadowing in rtas_ibm_configure_connector() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Remove extra 'drc_index' variable to avoid this warning : ../hw/ppc/spapr_drc.c: In function ‘rtas_ibm_configure_connector’: ../hw/ppc/spapr_drc.c:1240:26: warning: declaration of ‘drc_index’ shadows a previous local [-Wshadow=compatible-local] 1240 | uint32_t drc_index = spapr_drc_index(drc); | ^~~~~~~~~ ../hw/ppc/spapr_drc.c:1155:14: note: shadowed declaration is here 1155 | uint32_t drc_index; | ^~~~~~~~~ Signed-off-by: Cédric Le Goater Message-ID: <20230918145850.241074-7-clg@kaod.org> Reviewed-by: Harsh Prateek Bora Signed-off-by: Markus Armbruster --- hw/ppc/spapr_drc.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/hw/ppc/spapr_drc.c b/hw/ppc/spapr_drc.c index b5c400a94d..843e318312 100644 --- a/hw/ppc/spapr_drc.c +++ b/hw/ppc/spapr_drc.c @@ -1237,8 +1237,6 @@ static void rtas_ibm_configure_connector(PowerPCCPU *cpu, case FDT_END_NODE: drc->ccs_depth--; if (drc->ccs_depth == 0) { - uint32_t drc_index = spapr_drc_index(drc); - /* done sending the device tree, move to configured state */ trace_spapr_drc_set_configured(drc_index); drc->state = drck->ready_state; From 15675f2318142f8fbfd17b161604fb4f5e9f420e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Le=20Goater?= Date: Mon, 18 Sep 2023 16:58:49 +0200 Subject: [PATCH 0077/1077] spapr/pci: Clean up local variable shadowing in spapr_phb_realize() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Rename SysBusDevice variable to avoid this warning : ../hw/ppc/spapr_pci.c: In function ‘spapr_phb_realize’: ../hw/ppc/spapr_pci.c:1872:24: warning: declaration of ‘s’ shadows a previous local [-Wshadow=local] 1872 | SpaprPhbState *s; | ^ ../hw/ppc/spapr_pci.c:1829:19: note: shadowed declaration is here 1829 | SysBusDevice *s = SYS_BUS_DEVICE(dev); | ^ Signed-off-by: Cédric Le Goater Message-ID: <20230918145850.241074-8-clg@kaod.org> Reviewed-by: Harsh Prateek Bora Signed-off-by: Markus Armbruster --- hw/ppc/spapr_pci.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/hw/ppc/spapr_pci.c b/hw/ppc/spapr_pci.c index ce14959317..370c5a90f2 100644 --- a/hw/ppc/spapr_pci.c +++ b/hw/ppc/spapr_pci.c @@ -1826,9 +1826,9 @@ static void spapr_phb_realize(DeviceState *dev, Error **errp) (SpaprMachineState *) object_dynamic_cast(qdev_get_machine(), TYPE_SPAPR_MACHINE); SpaprMachineClass *smc = spapr ? SPAPR_MACHINE_GET_CLASS(spapr) : NULL; - SysBusDevice *s = SYS_BUS_DEVICE(dev); - SpaprPhbState *sphb = SPAPR_PCI_HOST_BRIDGE(s); - PCIHostState *phb = PCI_HOST_BRIDGE(s); + SysBusDevice *sbd = SYS_BUS_DEVICE(dev); + SpaprPhbState *sphb = SPAPR_PCI_HOST_BRIDGE(sbd); + PCIHostState *phb = PCI_HOST_BRIDGE(sbd); MachineState *ms = MACHINE(spapr); char *namebuf; int i; From 8cf52ff5c727519791eb897410f31c4ad27300cc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Le=20Goater?= Date: Mon, 18 Sep 2023 16:58:50 +0200 Subject: [PATCH 0078/1077] spapr/drc: Clean up local variable shadowing in prop_get_fdt() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Rename 'name' variable to avoid this warning : ../hw/ppc/spapr_drc.c: In function ‘prop_get_fdt’: ../hw/ppc/spapr_drc.c:344:21: warning: declaration of ‘name’ shadows a parameter [-Wshadow=compatible-local] 344 | const char *name = NULL; | ^~~~ ../hw/ppc/spapr_drc.c:325:63: note: shadowed declaration is here 325 | static void prop_get_fdt(Object *obj, Visitor *v, const char *name, | ~~~~~~~~~~~~^~~~ Signed-off-by: Cédric Le Goater Message-ID: <20230918145850.241074-9-clg@kaod.org> Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Harsh Prateek Bora Signed-off-by: Markus Armbruster --- hw/ppc/spapr_drc.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/hw/ppc/spapr_drc.c b/hw/ppc/spapr_drc.c index 843e318312..2b99d3b4b1 100644 --- a/hw/ppc/spapr_drc.c +++ b/hw/ppc/spapr_drc.c @@ -341,7 +341,7 @@ static void prop_get_fdt(Object *obj, Visitor *v, const char *name, fdt_depth = 0; do { - const char *name = NULL; + const char *dt_name = NULL; const struct fdt_property *prop = NULL; int prop_len = 0, name_len = 0; uint32_t tag; @@ -351,8 +351,8 @@ static void prop_get_fdt(Object *obj, Visitor *v, const char *name, switch (tag) { case FDT_BEGIN_NODE: fdt_depth++; - name = fdt_get_name(fdt, fdt_offset, &name_len); - if (!visit_start_struct(v, name, NULL, 0, errp)) { + dt_name = fdt_get_name(fdt, fdt_offset, &name_len); + if (!visit_start_struct(v, dt_name, NULL, 0, errp)) { return; } break; @@ -369,8 +369,8 @@ static void prop_get_fdt(Object *obj, Visitor *v, const char *name, case FDT_PROP: { int i; prop = fdt_get_property_by_offset(fdt, fdt_offset, &prop_len); - name = fdt_string(fdt, fdt32_to_cpu(prop->nameoff)); - if (!visit_start_list(v, name, NULL, 0, errp)) { + dt_name = fdt_string(fdt, fdt32_to_cpu(prop->nameoff)); + if (!visit_start_list(v, dt_name, NULL, 0, errp)) { return; } for (i = 0; i < prop_len; i++) { From d8573092a49b3133530ceee35846a54e600f8a73 Mon Sep 17 00:00:00 2001 From: Alberto Garcia Date: Fri, 22 Sep 2023 12:57:42 +0200 Subject: [PATCH 0079/1077] test-throttle: don't shadow 'index' variable in do_test_accounting() Fixes build with -Wshadow=local Signed-off-by: Alberto Garcia Message-ID: <20230922105742.81317-1-berto@igalia.com> Reviewed-by: Markus Armbruster Signed-off-by: Markus Armbruster --- tests/unit/test-throttle.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/unit/test-throttle.c b/tests/unit/test-throttle.c index cb587e33e7..ac35d65d19 100644 --- a/tests/unit/test-throttle.c +++ b/tests/unit/test-throttle.c @@ -625,7 +625,7 @@ static bool do_test_accounting(bool is_ops, /* are we testing bps or ops */ throttle_config_init(&cfg); for (i = 0; i < 3; i++) { - BucketType index = to_test[is_ops][i]; + index = to_test[is_ops][i]; cfg.buckets[index].avg = avg; } From 7b393b71424ba105f2b1c5f2c49f8d8710ad00eb Mon Sep 17 00:00:00 2001 From: Ani Sinha Date: Fri, 22 Sep 2023 18:12:02 +0530 Subject: [PATCH 0080/1077] hw/acpi: changes towards enabling -Wshadow=local Code changes in acpi that addresses all compiler complaints coming from enabling -Wshadow flags. Enabling -Wshadow catches cases of local variables shadowing other local variables or parameters. These makes the code confusing and/or adds bugs that are difficult to catch. See also Subject: Help wanted for enabling -Wshadow=local Message-Id: <87r0mqlf9x.fsf@pond.sub.org> https://lore.kernel.org/qemu-devel/87r0mqlf9x.fsf@pond.sub.org The code is tested to build with and without the flag turned on. CC: Markus Armbruster CC: Philippe Mathieu-Daude CC: mst@redhat.com CC: imammedo@redhat.com Signed-off-by: Ani Sinha Message-ID: <20230922124203.127110-1-anisinha@redhat.com> Reviewed-by: Michael S. Tsirkin [Commit message tweaked] Signed-off-by: Markus Armbruster --- hw/acpi/cpu_hotplug.c | 25 +++++++++++++------------ hw/i386/acpi-build.c | 24 ++++++++++++------------ hw/smbios/smbios.c | 37 +++++++++++++++++++------------------ 3 files changed, 44 insertions(+), 42 deletions(-) diff --git a/hw/acpi/cpu_hotplug.c b/hw/acpi/cpu_hotplug.c index ff14c3f410..634bbecb31 100644 --- a/hw/acpi/cpu_hotplug.c +++ b/hw/acpi/cpu_hotplug.c @@ -265,26 +265,27 @@ void build_legacy_cpu_hotplug_aml(Aml *ctx, MachineState *machine, /* build Processor object for each processor */ for (i = 0; i < apic_ids->len; i++) { - int apic_id = apic_ids->cpus[i].arch_id; + int cpu_apic_id = apic_ids->cpus[i].arch_id; - assert(apic_id < ACPI_CPU_HOTPLUG_ID_LIMIT); + assert(cpu_apic_id < ACPI_CPU_HOTPLUG_ID_LIMIT); - dev = aml_processor(i, 0, 0, "CP%.02X", apic_id); + dev = aml_processor(i, 0, 0, "CP%.02X", cpu_apic_id); method = aml_method("_MAT", 0, AML_NOTSERIALIZED); aml_append(method, - aml_return(aml_call2(CPU_MAT_METHOD, aml_int(apic_id), aml_int(i)) + aml_return(aml_call2(CPU_MAT_METHOD, + aml_int(cpu_apic_id), aml_int(i)) )); aml_append(dev, method); method = aml_method("_STA", 0, AML_NOTSERIALIZED); aml_append(method, - aml_return(aml_call1(CPU_STATUS_METHOD, aml_int(apic_id)))); + aml_return(aml_call1(CPU_STATUS_METHOD, aml_int(cpu_apic_id)))); aml_append(dev, method); method = aml_method("_EJ0", 1, AML_NOTSERIALIZED); aml_append(method, - aml_return(aml_call2(CPU_EJECT_METHOD, aml_int(apic_id), + aml_return(aml_call2(CPU_EJECT_METHOD, aml_int(cpu_apic_id), aml_arg(0))) ); aml_append(dev, method); @@ -298,11 +299,11 @@ void build_legacy_cpu_hotplug_aml(Aml *ctx, MachineState *machine, /* Arg0 = APIC ID */ method = aml_method(AML_NOTIFY_METHOD, 2, AML_NOTSERIALIZED); for (i = 0; i < apic_ids->len; i++) { - int apic_id = apic_ids->cpus[i].arch_id; + int cpu_apic_id = apic_ids->cpus[i].arch_id; - if_ctx = aml_if(aml_equal(aml_arg(0), aml_int(apic_id))); + if_ctx = aml_if(aml_equal(aml_arg(0), aml_int(cpu_apic_id))); aml_append(if_ctx, - aml_notify(aml_name("CP%.02X", apic_id), aml_arg(1)) + aml_notify(aml_name("CP%.02X", cpu_apic_id), aml_arg(1)) ); aml_append(method, if_ctx); } @@ -319,13 +320,13 @@ void build_legacy_cpu_hotplug_aml(Aml *ctx, MachineState *machine, aml_varpackage(x86ms->apic_id_limit); for (i = 0, apic_idx = 0; i < apic_ids->len; i++) { - int apic_id = apic_ids->cpus[i].arch_id; + int cpu_apic_id = apic_ids->cpus[i].arch_id; - for (; apic_idx < apic_id; apic_idx++) { + for (; apic_idx < cpu_apic_id; apic_idx++) { aml_append(pkg, aml_int(0)); } aml_append(pkg, aml_int(apic_ids->cpus[i].cpu ? 1 : 0)); - apic_idx = apic_id + 1; + apic_idx = cpu_apic_id + 1; } aml_append(sb_scope, aml_name_decl(CPU_ON_BITMAP, pkg)); aml_append(ctx, sb_scope); diff --git a/hw/i386/acpi-build.c b/hw/i386/acpi-build.c index 4d2d40bab5..95199c8900 100644 --- a/hw/i386/acpi-build.c +++ b/hw/i386/acpi-build.c @@ -1585,12 +1585,12 @@ build_dsdt(GArray *table_data, BIOSLinker *linker, aml_append(dev, aml_name_decl("_UID", aml_int(bus_num))); aml_append(dev, aml_name_decl("_BBN", aml_int(bus_num))); if (pci_bus_is_cxl(bus)) { - struct Aml *pkg = aml_package(2); + struct Aml *aml_pkg = aml_package(2); aml_append(dev, aml_name_decl("_HID", aml_string("ACPI0016"))); - aml_append(pkg, aml_eisaid("PNP0A08")); - aml_append(pkg, aml_eisaid("PNP0A03")); - aml_append(dev, aml_name_decl("_CID", pkg)); + aml_append(aml_pkg, aml_eisaid("PNP0A08")); + aml_append(aml_pkg, aml_eisaid("PNP0A03")); + aml_append(dev, aml_name_decl("_CID", aml_pkg)); build_cxl_osc_method(dev); } else if (pci_bus_is_express(bus)) { aml_append(dev, aml_name_decl("_HID", aml_eisaid("PNP0A08"))); @@ -1783,14 +1783,14 @@ build_dsdt(GArray *table_data, BIOSLinker *linker, Object *pci_host = acpi_get_i386_pci_host(); if (pci_host) { - PCIBus *bus = PCI_HOST_BRIDGE(pci_host)->bus; - Aml *scope = aml_scope("PCI0"); + PCIBus *pbus = PCI_HOST_BRIDGE(pci_host)->bus; + Aml *ascope = aml_scope("PCI0"); /* Scan all PCI buses. Generate tables to support hotplug. */ - build_append_pci_bus_devices(scope, bus); - if (object_property_find(OBJECT(bus), ACPI_PCIHP_PROP_BSEL)) { - build_append_pcihp_slots(scope, bus); + build_append_pci_bus_devices(ascope, pbus); + if (object_property_find(OBJECT(pbus), ACPI_PCIHP_PROP_BSEL)) { + build_append_pcihp_slots(ascope, pbus); } - aml_append(sb_scope, scope); + aml_append(sb_scope, ascope); } } @@ -1842,10 +1842,10 @@ build_dsdt(GArray *table_data, BIOSLinker *linker, bool has_pcnt; Object *pci_host = acpi_get_i386_pci_host(); - PCIBus *bus = PCI_HOST_BRIDGE(pci_host)->bus; + PCIBus *b = PCI_HOST_BRIDGE(pci_host)->bus; scope = aml_scope("\\_SB.PCI0"); - has_pcnt = build_append_notfication_callback(scope, bus); + has_pcnt = build_append_notfication_callback(scope, b); if (has_pcnt) { aml_append(dsdt, scope); } diff --git a/hw/smbios/smbios.c b/hw/smbios/smbios.c index b753705856..2a90601ac5 100644 --- a/hw/smbios/smbios.c +++ b/hw/smbios/smbios.c @@ -1423,13 +1423,14 @@ void smbios_entry_add(QemuOpts *opts, Error **errp) if (!qemu_opts_validate(opts, qemu_smbios_type8_opts, errp)) { return; } - struct type8_instance *t; - t = g_new0(struct type8_instance, 1); - save_opt(&t->internal_reference, opts, "internal_reference"); - save_opt(&t->external_reference, opts, "external_reference"); - t->connector_type = qemu_opt_get_number(opts, "connector_type", 0); - t->port_type = qemu_opt_get_number(opts, "port_type", 0); - QTAILQ_INSERT_TAIL(&type8, t, next); + struct type8_instance *t8_i; + t8_i = g_new0(struct type8_instance, 1); + save_opt(&t8_i->internal_reference, opts, "internal_reference"); + save_opt(&t8_i->external_reference, opts, "external_reference"); + t8_i->connector_type = qemu_opt_get_number(opts, + "connector_type", 0); + t8_i->port_type = qemu_opt_get_number(opts, "port_type", 0); + QTAILQ_INSERT_TAIL(&type8, t8_i, next); return; case 11: if (!qemu_opts_validate(opts, qemu_smbios_type11_opts, errp)) { @@ -1452,27 +1453,27 @@ void smbios_entry_add(QemuOpts *opts, Error **errp) type17.speed = qemu_opt_get_number(opts, "speed", 0); return; case 41: { - struct type41_instance *t; + struct type41_instance *t41_i; Error *local_err = NULL; if (!qemu_opts_validate(opts, qemu_smbios_type41_opts, errp)) { return; } - t = g_new0(struct type41_instance, 1); - save_opt(&t->designation, opts, "designation"); - t->kind = qapi_enum_parse(&type41_kind_lookup, - qemu_opt_get(opts, "kind"), - 0, &local_err) + 1; - t->kind |= 0x80; /* enabled */ + t41_i = g_new0(struct type41_instance, 1); + save_opt(&t41_i->designation, opts, "designation"); + t41_i->kind = qapi_enum_parse(&type41_kind_lookup, + qemu_opt_get(opts, "kind"), + 0, &local_err) + 1; + t41_i->kind |= 0x80; /* enabled */ if (local_err != NULL) { error_propagate(errp, local_err); - g_free(t); + g_free(t41_i); return; } - t->instance = qemu_opt_get_number(opts, "instance", 1); - save_opt(&t->pcidev, opts, "pcidev"); + t41_i->instance = qemu_opt_get_number(opts, "instance", 1); + save_opt(&t41_i->pcidev, opts, "pcidev"); - QTAILQ_INSERT_TAIL(&type41, t, next); + QTAILQ_INSERT_TAIL(&type41, t41_i, next); return; } default: From 33b3b4aded2eb56d505d563e4788e0654a7e9f2b Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Fri, 22 Sep 2023 16:29:41 +0100 Subject: [PATCH 0081/1077] hw/intc/arm_gicv3_its: Avoid shadowing variable in do_process_its_cmd() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Avoid shadowing a local variable in do_process_its_cmd(): ../../hw/intc/arm_gicv3_its.c:548:17: warning: declaration of ‘ite’ shadows a previous local [-Wshadow=compatible-local] 548 | ITEntry ite = {}; | ^~~ ../../hw/intc/arm_gicv3_its.c:518:13: note: shadowed declaration is here 518 | ITEntry ite; | ^~~ Signed-off-by: Peter Maydell Message-ID: <20230922152944.3583438-2-peter.maydell@linaro.org> Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Eric Auger Signed-off-by: Markus Armbruster --- hw/intc/arm_gicv3_its.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/hw/intc/arm_gicv3_its.c b/hw/intc/arm_gicv3_its.c index 5f552b4d37..52e9aca9c6 100644 --- a/hw/intc/arm_gicv3_its.c +++ b/hw/intc/arm_gicv3_its.c @@ -545,10 +545,10 @@ static ItsCmdResult do_process_its_cmd(GICv3ITSState *s, uint32_t devid, } if (cmdres == CMD_CONTINUE_OK && cmd == DISCARD) { - ITEntry ite = {}; + ITEntry i = {}; /* remove mapping from interrupt translation table */ - ite.valid = false; - return update_ite(s, eventid, &dte, &ite) ? CMD_CONTINUE_OK : CMD_STALL; + i.valid = false; + return update_ite(s, eventid, &dte, &i) ? CMD_CONTINUE_OK : CMD_STALL; } return CMD_CONTINUE_OK; } From b2e7e2048bbe7a82b921d9ca71da9aec1668fcfe Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Fri, 22 Sep 2023 16:29:42 +0100 Subject: [PATCH 0082/1077] hw/misc/arm_sysctl.c: Avoid shadowing local variable MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Avoid shadowing a local variable in arm_sysctl_write(): ../../hw/misc/arm_sysctl.c: In function ‘arm_sysctl_write’: ../../hw/misc/arm_sysctl.c:537:26: warning: declaration of ‘val’ shadows a parameter [-Wshadow=local] 537 | uint32_t val; | ^~~ ../../hw/misc/arm_sysctl.c:388:39: note: shadowed declaration is here 388 | uint64_t val, unsigned size) | ~~~~~~~~~^~~ Signed-off-by: Peter Maydell Message-ID: <20230922152944.3583438-3-peter.maydell@linaro.org> Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Eric Auger Signed-off-by: Markus Armbruster --- hw/misc/arm_sysctl.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/hw/misc/arm_sysctl.c b/hw/misc/arm_sysctl.c index 42d4693854..3e4f4b0524 100644 --- a/hw/misc/arm_sysctl.c +++ b/hw/misc/arm_sysctl.c @@ -534,12 +534,12 @@ static void arm_sysctl_write(void *opaque, hwaddr offset, s->sys_cfgstat |= 2; /* error */ } } else { - uint32_t val; + uint32_t data; if (!vexpress_cfgctrl_read(s, dcc, function, site, position, - device, &val)) { + device, &data)) { s->sys_cfgstat |= 2; /* error */ } else { - s->sys_cfgdata = val; + s->sys_cfgdata = data; } } } From 9e2135ee93ad84119642787e3fb8264b6d1c7ef5 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Fri, 22 Sep 2023 16:29:43 +0100 Subject: [PATCH 0083/1077] hw/arm/smmuv3.c: Avoid shadowing variable MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Avoid shadowing a variable in smmuv3_notify_iova(): ../../hw/arm/smmuv3.c: In function ‘smmuv3_notify_iova’: ../../hw/arm/smmuv3.c:1043:23: warning: declaration of ‘event’ shadows a previous local [-Wshadow=local] 1043 | SMMUEventInfo event = {.inval_ste_allowed = true}; | ^~~~~ ../../hw/arm/smmuv3.c:1038:19: note: shadowed declaration is here 1038 | IOMMUTLBEvent event; | ^~~~~ Signed-off-by: Peter Maydell Message-ID: <20230922152944.3583438-4-peter.maydell@linaro.org> Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Eric Auger Signed-off-by: Markus Armbruster --- hw/arm/smmuv3.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/hw/arm/smmuv3.c b/hw/arm/smmuv3.c index 1e9be8e89a..6f2b2bd45f 100644 --- a/hw/arm/smmuv3.c +++ b/hw/arm/smmuv3.c @@ -1040,8 +1040,8 @@ static void smmuv3_notify_iova(IOMMUMemoryRegion *mr, SMMUv3State *s = sdev->smmu; if (!tg) { - SMMUEventInfo event = {.inval_ste_allowed = true}; - SMMUTransCfg *cfg = smmuv3_get_config(sdev, &event); + SMMUEventInfo eventinfo = {.inval_ste_allowed = true}; + SMMUTransCfg *cfg = smmuv3_get_config(sdev, &eventinfo); SMMUTransTableInfo *tt; if (!cfg) { From 84abccdd39d6c011971a2a41e7b64f7084e28da8 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Fri, 22 Sep 2023 16:29:44 +0100 Subject: [PATCH 0084/1077] hw/arm/smmuv3-internal.h: Don't use locals in statement macros MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The STE_CTXPTR() and STE_S2TTB() macros both extract two halves of an address from fields in the STE and combine them into a single value to return. The current code for this uses a GCC statement expression. There are two problems with this: (1) The type chosen for the variable in the statement expr is 'unsigned long', which might not be 64 bits (2) the name chosen for the variable causes -Wshadow warnings because it's the same as a variable in use at the callsite: In file included from ../../hw/arm/smmuv3.c:34: ../../hw/arm/smmuv3.c: In function ‘smmu_get_cd’: ../../hw/arm/smmuv3-internal.h:538:23: warning: declaration of ‘addr’ shadows a previous local [-Wshadow=compatible-local] 538 | unsigned long addr; \ | ^~~~ ../../hw/arm/smmuv3.c:339:23: note: in expansion of macro ‘STE_CTXPTR’ 339 | dma_addr_t addr = STE_CTXPTR(ste); | ^~~~~~~~~~ ../../hw/arm/smmuv3.c:339:16: note: shadowed declaration is here 339 | dma_addr_t addr = STE_CTXPTR(ste); | ^~~~ Sidestep both of these problems by just using a single expression rather than a statement expr. For CMD_ADDR, we got the type of the variable right but still run into -Wshadow problems: In file included from ../../hw/arm/smmuv3.c:34: ../../hw/arm/smmuv3.c: In function ‘smmuv3_range_inval’: ../../hw/arm/smmuv3-internal.h:334:22: warning: declaration of ‘addr’ shadows a previous local [-Wshadow=compatible-local] 334 | uint64_t addr = high << 32 | (low << 12); \ | ^~~~ ../../hw/arm/smmuv3.c:1104:28: note: in expansion of macro ‘CMD_ADDR’ 1104 | dma_addr_t end, addr = CMD_ADDR(cmd); | ^~~~~~~~ ../../hw/arm/smmuv3.c:1104:21: note: shadowed declaration is here 1104 | dma_addr_t end, addr = CMD_ADDR(cmd); | ^~~~ so convert it too. CD_TTB has neither problem, but it is the only other macro in the file that uses this pattern, so we convert it also for consistency's sake. We use extract64() rather than extract32() to avoid having to explicitly cast the result to uint64_t. Signed-off-by: Peter Maydell Message-ID: <20230922152944.3583438-5-peter.maydell@linaro.org> Reviewed-by: Eric Auger Signed-off-by: Markus Armbruster --- hw/arm/smmuv3-internal.h | 41 +++++++++++++--------------------------- 1 file changed, 13 insertions(+), 28 deletions(-) diff --git a/hw/arm/smmuv3-internal.h b/hw/arm/smmuv3-internal.h index 6d1c1edab7..648c2e37a2 100644 --- a/hw/arm/smmuv3-internal.h +++ b/hw/arm/smmuv3-internal.h @@ -328,12 +328,9 @@ enum { /* Command completion notification */ #define CMD_TTL(x) extract32((x)->word[2], 8 , 2) #define CMD_TG(x) extract32((x)->word[2], 10, 2) #define CMD_STE_RANGE(x) extract32((x)->word[2], 0 , 5) -#define CMD_ADDR(x) ({ \ - uint64_t high = (uint64_t)(x)->word[3]; \ - uint64_t low = extract32((x)->word[2], 12, 20); \ - uint64_t addr = high << 32 | (low << 12); \ - addr; \ - }) +#define CMD_ADDR(x) \ + (((uint64_t)((x)->word[3]) << 32) | \ + ((extract64((x)->word[2], 12, 20)) << 12)) #define SMMU_FEATURE_2LVL_STE (1 << 0) @@ -533,21 +530,13 @@ typedef struct CD { #define STE_S2S(x) extract32((x)->word[5], 25, 1) #define STE_S2R(x) extract32((x)->word[5], 26, 1) -#define STE_CTXPTR(x) \ - ({ \ - unsigned long addr; \ - addr = (uint64_t)extract32((x)->word[1], 0, 16) << 32; \ - addr |= (uint64_t)((x)->word[0] & 0xffffffc0); \ - addr; \ - }) +#define STE_CTXPTR(x) \ + ((extract64((x)->word[1], 0, 16) << 32) | \ + ((x)->word[0] & 0xffffffc0)) -#define STE_S2TTB(x) \ - ({ \ - unsigned long addr; \ - addr = (uint64_t)extract32((x)->word[7], 0, 16) << 32; \ - addr |= (uint64_t)((x)->word[6] & 0xfffffff0); \ - addr; \ - }) +#define STE_S2TTB(x) \ + ((extract64((x)->word[7], 0, 16) << 32) | \ + ((x)->word[6] & 0xfffffff0)) static inline int oas2bits(int oas_field) { @@ -585,14 +574,10 @@ static inline int pa_range(STE *ste) #define CD_VALID(x) extract32((x)->word[0], 31, 1) #define CD_ASID(x) extract32((x)->word[1], 16, 16) -#define CD_TTB(x, sel) \ - ({ \ - uint64_t hi, lo; \ - hi = extract32((x)->word[(sel) * 2 + 3], 0, 19); \ - hi <<= 32; \ - lo = (x)->word[(sel) * 2 + 2] & ~0xfULL; \ - hi | lo; \ - }) +#define CD_TTB(x, sel) \ + ((extract64((x)->word[(sel) * 2 + 3], 0, 19) << 32) | \ + ((x)->word[(sel) * 2 + 2] & ~0xfULL)) + #define CD_HAD(x, sel) extract32((x)->word[(sel) * 2 + 2], 1, 1) #define CD_TSZ(x, sel) extract32((x)->word[0], (16 * (sel)) + 0, 6) From ce6c368d96ed88c2c8505c825b771e8632e84a88 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Le=20Goater?= Date: Fri, 22 Sep 2023 17:59:21 +0200 Subject: [PATCH 0085/1077] aspeed/i2c: Clean up local variable shadowing MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Remove superfluous local 'data' variable and use the one define at the top of the routine. This fixes : ../hw/i2c/aspeed_i2c.c: In function ‘aspeed_i2c_bus_recv’: ../hw/i2c/aspeed_i2c.c:315:17: warning: declaration of ‘data’ shadows a previous local [-Wshadow=compatible-local] 315 | uint8_t data; | ^~~~ ../hw/i2c/aspeed_i2c.c:288:13: note: shadowed declaration is here 288 | uint8_t data; | ^~~~ Signed-off-by: Cédric Le Goater Message-ID: <20230922155924.1172019-2-clg@kaod.org> Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Joel Stanley Signed-off-by: Markus Armbruster --- hw/i2c/aspeed_i2c.c | 1 - 1 file changed, 1 deletion(-) diff --git a/hw/i2c/aspeed_i2c.c b/hw/i2c/aspeed_i2c.c index 7275d40749..1037c22b2f 100644 --- a/hw/i2c/aspeed_i2c.c +++ b/hw/i2c/aspeed_i2c.c @@ -312,7 +312,6 @@ static void aspeed_i2c_bus_recv(AspeedI2CBus *bus) SHARED_ARRAY_FIELD_DP32(bus->regs, reg_pool_ctrl, RX_COUNT, i & 0xff); SHARED_ARRAY_FIELD_DP32(bus->regs, reg_cmd, RX_BUFF_EN, 0); } else if (SHARED_ARRAY_FIELD_EX32(bus->regs, reg_cmd, RX_DMA_EN)) { - uint8_t data; /* In new mode, clear how many bytes we RXed */ if (aspeed_i2c_is_new_mode(bus->controller)) { ARRAY_FIELD_DP32(bus->regs, I2CM_DMA_LEN_STS, RX_LEN, 0); From e8874c06a7da70a59c7c7ac2cf0c3612cbc82f6d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Le=20Goater?= Date: Fri, 22 Sep 2023 17:59:22 +0200 Subject: [PATCH 0086/1077] aspeed: Clean up local variable shadowing MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Remove superfluous local 'irq' variables and use the one define at the top of the routine. This fixes warnings in aspeed_soc_ast2600_realize() such as : ../hw/arm/aspeed_ast2600.c: In function ‘aspeed_soc_ast2600_realize’: ../hw/arm/aspeed_ast2600.c:420:18: warning: declaration of ‘irq’ shadows a previous local [-Wshadow=compatible-local] 420 | qemu_irq irq = aspeed_soc_get_irq(s, ASPEED_DEV_TIMER1 + i); | ^~~ ../hw/arm/aspeed_ast2600.c:312:14: note: shadowed declaration is here 312 | qemu_irq irq; | ^~~ Signed-off-by: Cédric Le Goater Message-ID: <20230922155924.1172019-3-clg@kaod.org> Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Markus Armbruster --- hw/arm/aspeed_ast2600.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/hw/arm/aspeed_ast2600.c b/hw/arm/aspeed_ast2600.c index a8b3a8065a..e122e1c32d 100644 --- a/hw/arm/aspeed_ast2600.c +++ b/hw/arm/aspeed_ast2600.c @@ -388,7 +388,7 @@ static void aspeed_soc_ast2600_realize(DeviceState *dev, Error **errp) aspeed_mmio_map(s, SYS_BUS_DEVICE(&s->timerctrl), 0, sc->memmap[ASPEED_DEV_TIMER1]); for (i = 0; i < ASPEED_TIMER_NR_TIMERS; i++) { - qemu_irq irq = aspeed_soc_get_irq(s, ASPEED_DEV_TIMER1 + i); + irq = aspeed_soc_get_irq(s, ASPEED_DEV_TIMER1 + i); sysbus_connect_irq(SYS_BUS_DEVICE(&s->timerctrl), i, irq); } @@ -413,8 +413,8 @@ static void aspeed_soc_ast2600_realize(DeviceState *dev, Error **errp) } aspeed_mmio_map(s, SYS_BUS_DEVICE(&s->i2c), 0, sc->memmap[ASPEED_DEV_I2C]); for (i = 0; i < ASPEED_I2C_GET_CLASS(&s->i2c)->num_busses; i++) { - qemu_irq irq = qdev_get_gpio_in(DEVICE(&s->a7mpcore), - sc->irqmap[ASPEED_DEV_I2C] + i); + irq = qdev_get_gpio_in(DEVICE(&s->a7mpcore), + sc->irqmap[ASPEED_DEV_I2C] + i); /* The AST2600 I2C controller has one IRQ per bus. */ sysbus_connect_irq(SYS_BUS_DEVICE(&s->i2c.busses[i]), 0, irq); } @@ -611,8 +611,8 @@ static void aspeed_soc_ast2600_realize(DeviceState *dev, Error **errp) } aspeed_mmio_map(s, SYS_BUS_DEVICE(&s->i3c), 0, sc->memmap[ASPEED_DEV_I3C]); for (i = 0; i < ASPEED_I3C_NR_DEVICES; i++) { - qemu_irq irq = qdev_get_gpio_in(DEVICE(&s->a7mpcore), - sc->irqmap[ASPEED_DEV_I3C] + i); + irq = qdev_get_gpio_in(DEVICE(&s->a7mpcore), + sc->irqmap[ASPEED_DEV_I3C] + i); /* The AST2600 I3C controller has one IRQ per bus. */ sysbus_connect_irq(SYS_BUS_DEVICE(&s->i3c.devices[i]), 0, irq); } From e407513d285b96594a2710c9b37dff7ce9632f3e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Le=20Goater?= Date: Fri, 22 Sep 2023 17:59:23 +0200 Subject: [PATCH 0087/1077] aspeed/i3c: Rename variable shadowing a local MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit to fix warning : ../hw/i3c/aspeed_i3c.c: In function ‘aspeed_i3c_realize’: ../hw/i3c/aspeed_i3c.c:1959:17: warning: declaration of ‘dev’ shadows a parameter [-Wshadow=local] 1959 | Object *dev = OBJECT(&s->devices[i]); | ^~~ ../hw/i3c/aspeed_i3c.c:1942:45: note: shadowed declaration is here 1942 | static void aspeed_i3c_realize(DeviceState *dev, Error **errp) | ~~~~~~~~~~~~~^~~ Signed-off-by: Cédric Le Goater Message-ID: <20230922155924.1172019-4-clg@kaod.org> Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Andrew Jeffery Signed-off-by: Markus Armbruster --- hw/misc/aspeed_i3c.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/hw/misc/aspeed_i3c.c b/hw/misc/aspeed_i3c.c index f54f5da522..d1ff617671 100644 --- a/hw/misc/aspeed_i3c.c +++ b/hw/misc/aspeed_i3c.c @@ -296,13 +296,13 @@ static void aspeed_i3c_realize(DeviceState *dev, Error **errp) memory_region_add_subregion(&s->iomem_container, 0x0, &s->iomem); for (i = 0; i < ASPEED_I3C_NR_DEVICES; ++i) { - Object *dev = OBJECT(&s->devices[i]); + Object *i3c_dev = OBJECT(&s->devices[i]); - if (!object_property_set_uint(dev, "device-id", i, errp)) { + if (!object_property_set_uint(i3c_dev, "device-id", i, errp)) { return; } - if (!sysbus_realize(SYS_BUS_DEVICE(dev), errp)) { + if (!sysbus_realize(SYS_BUS_DEVICE(i3c_dev), errp)) { return; } From 62fcc4e872cf01350e4dd395c60c5c726121417f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Le=20Goater?= Date: Fri, 22 Sep 2023 17:59:24 +0200 Subject: [PATCH 0088/1077] aspeed/timer: Clean up local variable shadowing MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit 8137355e850f ("aspeed/timer: Fix behaviour running Linux") introduced a MAX() expression to calculate the next timer deadline : return calculate_time(t, MAX(MAX(t->match[0], t->match[1]), 0)); The second MAX() is not necessary since the compared values are an unsigned and 0. Simply remove it and fix warning : ../hw/timer/aspeed_timer.c: In function ‘calculate_next’: ../include/qemu/osdep.h:396:31: warning: declaration of ‘_a’ shadows a previous local [-Wshadow=compatible-local] 396 | typeof(1 ? (a) : (b)) _a = (a), _b = (b); \ | ^~ ../hw/timer/aspeed_timer.c:170:12: note: in expansion of macro ‘MAX’ 170 | next = MAX(MAX(calculate_match(t, 0), calculate_match(t, 1)), 0); | ^~~ ../hw/timer/aspeed_timer.c:170:16: note: in expansion of macro ‘MAX’ 170 | next = MAX(MAX(calculate_match(t, 0), calculate_match(t, 1)), 0); | ^~~ /home/legoater/work/qemu/qemu-aspeed.git/include/qemu/osdep.h:396:31: note: shadowed declaration is here 396 | typeof(1 ? (a) : (b)) _a = (a), _b = (b); \ | ^~ ../hw/timer/aspeed_timer.c:170:12: note: in expansion of macro ‘MAX’ 170 | next = MAX(MAX(calculate_match(t, 0), calculate_match(t, 1)), 0); | ^~~ Cc: Joel Stanley Cc: Andrew Jeffery Signed-off-by: Cédric Le Goater Message-ID: <20230922155924.1172019-5-clg@kaod.org> Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Markus Armbruster --- hw/timer/aspeed_timer.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/timer/aspeed_timer.c b/hw/timer/aspeed_timer.c index 9c20b3d6ad..72161f07bb 100644 --- a/hw/timer/aspeed_timer.c +++ b/hw/timer/aspeed_timer.c @@ -167,7 +167,7 @@ static uint64_t calculate_next(struct AspeedTimer *t) qemu_set_irq(t->irq, t->level); } - next = MAX(MAX(calculate_match(t, 0), calculate_match(t, 1)), 0); + next = MAX(calculate_match(t, 0), calculate_match(t, 1)); t->start = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); return calculate_time(t, next); From a082739eb390d2aad679b5efa9afc40cfa2a496d Mon Sep 17 00:00:00 2001 From: Peter Xu Date: Fri, 22 Sep 2023 12:04:10 -0400 Subject: [PATCH 0089/1077] intel_iommu: Fix shadow local variables on "size" MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This patch fixes the warning of shadowed local variable: ../hw/i386/intel_iommu.c: In function ‘vtd_address_space_unmap’: ../hw/i386/intel_iommu.c:3773:18: warning: declaration of ‘size’ shadows a previous local [-Wshadow=compatible-local] 3773 | uint64_t size = mask + 1; | ^~~~ ../hw/i386/intel_iommu.c:3747:12: note: shadowed declaration is here 3747 | hwaddr size, remain; | ^~~~ Cc: Jason Wang Cc: Eric Auger Cc: Michael S. Tsirkin Cc: Markus Armbruster Signed-off-by: Peter Xu Message-ID: <20230922160410.138786-1-peterx@redhat.com> Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Michael S. Tsirkin Signed-off-by: Markus Armbruster --- hw/i386/intel_iommu.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/hw/i386/intel_iommu.c b/hw/i386/intel_iommu.c index c0ce896668..2c832ab68b 100644 --- a/hw/i386/intel_iommu.c +++ b/hw/i386/intel_iommu.c @@ -3744,7 +3744,7 @@ VTDAddressSpace *vtd_find_add_as(IntelIOMMUState *s, PCIBus *bus, /* Unmap the whole range in the notifier's scope. */ static void vtd_address_space_unmap(VTDAddressSpace *as, IOMMUNotifier *n) { - hwaddr size, remain; + hwaddr total, remain; hwaddr start = n->start; hwaddr end = n->end; IntelIOMMUState *s = as->iommu_state; @@ -3765,7 +3765,7 @@ static void vtd_address_space_unmap(VTDAddressSpace *as, IOMMUNotifier *n) } assert(start <= end); - size = remain = end - start + 1; + total = remain = end - start + 1; while (remain >= VTD_PAGE_SIZE) { IOMMUTLBEvent event; @@ -3793,10 +3793,10 @@ static void vtd_address_space_unmap(VTDAddressSpace *as, IOMMUNotifier *n) trace_vtd_as_unmap_whole(pci_bus_num(as->bus), VTD_PCI_SLOT(as->devfn), VTD_PCI_FUNC(as->devfn), - n->start, size); + n->start, total); map.iova = n->start; - map.size = size - 1; /* Inclusive */ + map.size = total - 1; /* Inclusive */ iova_tree_remove(as->iova_tree, map); } From 3cc9fe177f412494f084923149338c51dd232b9b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20P=2E=20Berrang=C3=A9?= Date: Fri, 22 Sep 2023 17:06:43 +0100 Subject: [PATCH 0090/1077] crypto: remove shadowed 'ret' variable MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Both instances of 'ret' are used to store a gnutls API return code. Signed-off-by: Daniel P. Berrangé Message-ID: <20230922160644.438631-2-berrange@redhat.com> Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Markus Armbruster --- crypto/tls-cipher-suites.c | 1 - 1 file changed, 1 deletion(-) diff --git a/crypto/tls-cipher-suites.c b/crypto/tls-cipher-suites.c index 5e4f597464..d0df4badc0 100644 --- a/crypto/tls-cipher-suites.c +++ b/crypto/tls-cipher-suites.c @@ -52,7 +52,6 @@ GByteArray *qcrypto_tls_cipher_suites_get_data(QCryptoTLSCipherSuites *obj, byte_array = g_byte_array_new(); for (i = 0;; i++) { - int ret; unsigned idx; const char *name; IANA_TLS_CIPHER cipher; From 0d57919acf27ca343981f69cec33463887e0a716 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20P=2E=20Berrang=C3=A9?= Date: Fri, 22 Sep 2023 17:06:44 +0100 Subject: [PATCH 0091/1077] seccomp: avoid shadowing of 'action' variable MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This is confusing as one 'action' variable is used for storing a SCMP_ enum value, while the other 'action' variable is used for storing a SECCOMP_ enum value. Signed-off-by: Daniel P. Berrangé Message-ID: <20230922160644.438631-3-berrange@redhat.com> Reviewed-by: Markus Armbruster Signed-off-by: Markus Armbruster --- softmmu/qemu-seccomp.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/softmmu/qemu-seccomp.c b/softmmu/qemu-seccomp.c index d66a2a1226..4d7439e7f7 100644 --- a/softmmu/qemu-seccomp.c +++ b/softmmu/qemu-seccomp.c @@ -283,9 +283,9 @@ static uint32_t qemu_seccomp_update_action(uint32_t action) if (action == SCMP_ACT_TRAP) { static int kill_process = -1; if (kill_process == -1) { - uint32_t action = SECCOMP_RET_KILL_PROCESS; + uint32_t testaction = SECCOMP_RET_KILL_PROCESS; - if (qemu_seccomp(SECCOMP_GET_ACTION_AVAIL, 0, &action) == 0) { + if (qemu_seccomp(SECCOMP_GET_ACTION_AVAIL, 0, &testaction) == 0) { kill_process = 1; } else { kill_process = 0; From e161785c05c8a96962a0ea87a3abefe158d8b035 Mon Sep 17 00:00:00 2001 From: Eric Blake Date: Fri, 22 Sep 2023 15:50:20 -0500 Subject: [PATCH 0092/1077] qemu-nbd: changes towards enabling -Wshadow=local MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Address all compiler complaints from -Wshadow in qemu-nbd. Several instances of 'int ret' became shadows when commit 4fbec260 added 'ret' at a higher scope in main. More interesting was the 'void *ret' capturing the result of a pthread; where we were conceptually doing '(void*)(intptr_t)EXIT_FAILURE != NULL' which just feels wrong (even though it happens to compile correctly), so it was worth a better cleanup. Signed-off-by: Eric Blake Message-ID: <20230922205019.2755352-2-eblake@redhat.com> Reviewed-by: Daniel P. Berrangé Signed-off-by: Markus Armbruster --- qemu-nbd.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/qemu-nbd.c b/qemu-nbd.c index 70aa3c487a..54faa87a0c 100644 --- a/qemu-nbd.c +++ b/qemu-nbd.c @@ -939,7 +939,6 @@ int main(int argc, char **argv) g_autoptr(GError) err = NULL; int stderr_fd[2]; pid_t pid; - int ret; if (!g_unix_open_pipe(stderr_fd, FD_CLOEXEC, &err)) { error_report("Error setting up communication pipe: %s", @@ -1172,7 +1171,6 @@ int main(int argc, char **argv) if (opts.device) { #if HAVE_NBD_DEVICE - int ret; ret = pthread_create(&client_thread, NULL, nbd_client_thread, &opts); if (ret != 0) { error_report("Failed to create client thread: %s", strerror(ret)); @@ -1219,9 +1217,10 @@ int main(int argc, char **argv) qemu_opts_del(sn_opts); if (opts.device) { - void *ret; - pthread_join(client_thread, &ret); - exit(ret != NULL); + void *result; + pthread_join(client_thread, &result); + ret = (intptr_t)result; + exit(ret); } else { exit(EXIT_SUCCESS); } From 010f5557ab1d5d14c3ffc023387289c68b889cc9 Mon Sep 17 00:00:00 2001 From: Alistair Francis Date: Mon, 25 Sep 2023 14:30:20 +1000 Subject: [PATCH 0093/1077] hw/riscv: opentitan: Fixup local variables shadowing Local variables shadowing other local variables or parameters make the code needlessly hard to understand. Bugs love to hide in such code. Evidence: "[PATCH v3 1/7] migration/rdma: Fix save_page method to fail on polling error". This patch removes the local variable shadowing. Tested by adding: --extra-cflags='-Wshadow=local -Wno-error=shadow=local -Wno-error=shadow=compatible-local' To configure Signed-off-by: Alistair Francis Message-ID: <20230925043023.71448-2-alistair.francis@wdc.com> Reviewed-by: Daniel Henrique Barboza Signed-off-by: Markus Armbruster --- hw/riscv/opentitan.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/riscv/opentitan.c b/hw/riscv/opentitan.c index 6a2fcc4ade..436503f1ba 100644 --- a/hw/riscv/opentitan.c +++ b/hw/riscv/opentitan.c @@ -227,7 +227,7 @@ static void lowrisc_ibex_soc_realize(DeviceState *dev_soc, Error **errp) IRQ_M_TIMER)); /* SPI-Hosts */ - for (int i = 0; i < OPENTITAN_NUM_SPI_HOSTS; ++i) { + for (i = 0; i < OPENTITAN_NUM_SPI_HOSTS; ++i) { dev = DEVICE(&(s->spi_host[i])); if (!sysbus_realize(SYS_BUS_DEVICE(&s->spi_host[i]), errp)) { return; From 29332994d8ebcbfad0748017c5151ed69e119212 Mon Sep 17 00:00:00 2001 From: Alistair Francis Date: Mon, 25 Sep 2023 14:30:21 +1000 Subject: [PATCH 0094/1077] target/riscv: cpu: Fixup local variables shadowing Local variables shadowing other local variables or parameters make the code needlessly hard to understand. Bugs love to hide in such code. Evidence: "[PATCH v3 1/7] migration/rdma: Fix save_page method to fail on polling error". This patch removes the local variable shadowing. Tested by adding: --extra-cflags='-Wshadow=local -Wno-error=shadow=local -Wno-error=shadow=compatible-local' To configure Signed-off-by: Alistair Francis Message-ID: <20230925043023.71448-3-alistair.francis@wdc.com> Reviewed-by: Daniel Henrique Barboza Signed-off-by: Markus Armbruster --- target/riscv/cpu.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c index f227c7664e..4140899c52 100644 --- a/target/riscv/cpu.c +++ b/target/riscv/cpu.c @@ -704,7 +704,7 @@ static void riscv_cpu_dump_state(CPUState *cs, FILE *f, int flags) CSR_MPMMASK, }; - for (int i = 0; i < ARRAY_SIZE(dump_csrs); ++i) { + for (i = 0; i < ARRAY_SIZE(dump_csrs); ++i) { int csrno = dump_csrs[i]; target_ulong val = 0; RISCVException res = riscv_csrrw_debug(env, csrno, &val, 0, 0); @@ -747,7 +747,7 @@ static void riscv_cpu_dump_state(CPUState *cs, FILE *f, int flags) CSR_VTYPE, CSR_VLENB, }; - for (int i = 0; i < ARRAY_SIZE(dump_rvv_csrs); ++i) { + for (i = 0; i < ARRAY_SIZE(dump_rvv_csrs); ++i) { int csrno = dump_rvv_csrs[i]; target_ulong val = 0; RISCVException res = riscv_csrrw_debug(env, csrno, &val, 0, 0); From f3f65c4022c4af793eecf8be9872510f83f98740 Mon Sep 17 00:00:00 2001 From: Alistair Francis Date: Mon, 25 Sep 2023 14:30:22 +1000 Subject: [PATCH 0095/1077] target/riscv: vector_helper: Fixup local variables shadowing Local variables shadowing other local variables or parameters make the code needlessly hard to understand. Bugs love to hide in such code. Evidence: "[PATCH v3 1/7] migration/rdma: Fix save_page method to fail on polling error". This patch removes the local variable shadowing. Tested by adding: --extra-cflags='-Wshadow=local -Wno-error=shadow=local -Wno-error=shadow=compatible-local' To configure Signed-off-by: Alistair Francis Message-ID: <20230925043023.71448-4-alistair.francis@wdc.com> Reviewed-by: Daniel Henrique Barboza Signed-off-by: Markus Armbruster --- target/riscv/vector_helper.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/target/riscv/vector_helper.c b/target/riscv/vector_helper.c index 3fb05cc3d6..cba02c1320 100644 --- a/target/riscv/vector_helper.c +++ b/target/riscv/vector_helper.c @@ -516,7 +516,7 @@ ProbeSuccess: k++; continue; } - target_ulong addr = base + ((i * nf + k) << log2_esz); + addr = base + ((i * nf + k) << log2_esz); ldst_elem(env, adjust_addr(env, addr), i + k * max_elems, vd, ra); k++; } @@ -4791,9 +4791,10 @@ void HELPER(NAME)(void *vd, void *v0, target_ulong s1, void *vs2, \ uint32_t total_elems = vext_get_total_elems(env, desc, esz); \ uint32_t vta = vext_vta(desc); \ uint32_t vma = vext_vma(desc); \ - target_ulong i_max, i; \ + target_ulong i_max, i_min, i; \ \ - i_max = MAX(MIN(s1 < vlmax ? vlmax - s1 : 0, vl), env->vstart); \ + i_min = MIN(s1 < vlmax ? vlmax - s1 : 0, vl); \ + i_max = MAX(i_min, env->vstart); \ for (i = env->vstart; i < i_max; ++i) { \ if (!vm && !vext_elem_mask(v0, i)) { \ /* set masked-off elements to 1s */ \ From 5567fa825ab9bdc4688308bea7816e2f969b65c3 Mon Sep 17 00:00:00 2001 From: Alistair Francis Date: Mon, 25 Sep 2023 14:30:23 +1000 Subject: [PATCH 0096/1077] softmmu/device_tree: Fixup local variables shadowing Local variables shadowing other local variables or parameters make the code needlessly hard to understand. Bugs love to hide in such code. Evidence: "[PATCH v3 1/7] migration/rdma: Fix save_page method to fail on polling error". This patch removes the local variable shadowing. Tested by adding: --extra-cflags='-Wshadow=local -Wno-error=shadow=local -Wno-error=shadow=compatible-local' To configure Signed-off-by: Alistair Francis Message-ID: <20230925043023.71448-5-alistair.francis@wdc.com> Reviewed-by: Daniel Henrique Barboza Signed-off-by: Markus Armbruster --- softmmu/device_tree.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/softmmu/device_tree.c b/softmmu/device_tree.c index 30aa3aea9f..eb5166ca36 100644 --- a/softmmu/device_tree.c +++ b/softmmu/device_tree.c @@ -418,9 +418,9 @@ int qemu_fdt_setprop_string_array(void *fdt, const char *node_path, } p = str = g_malloc0(total_len); for (i = 0; i < len; i++) { - int len = strlen(array[i]) + 1; - pstrcpy(p, len, array[i]); - p += len; + int offset = strlen(array[i]) + 1; + pstrcpy(p, offset, array[i]); + p += offset; } ret = qemu_fdt_setprop(fdt, node_path, prop, str, total_len); From f193d0bde70e1be004cc4aba5aaf3ac9c459d156 Mon Sep 17 00:00:00 2001 From: Klaus Jensen Date: Mon, 25 Sep 2023 08:05:05 +0200 Subject: [PATCH 0097/1077] hw/nvme: Clean up local variable shadowing in nvme_ns_init() Fix local variable shadowing in nvme_ns_init(). Reported-by: Markus Armbruster Signed-off-by: Klaus Jensen Message-ID: <20230925-fix-local-shadowing-v1-1-3a1172132377@samsung.com> Reviewed-by: Jesper Wendel Devantier Signed-off-by: Markus Armbruster --- hw/nvme/ns.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/hw/nvme/ns.c b/hw/nvme/ns.c index 44aba8f4d9..0eabcf5cf5 100644 --- a/hw/nvme/ns.c +++ b/hw/nvme/ns.c @@ -107,7 +107,7 @@ static int nvme_ns_init(NvmeNamespace *ns, Error **errp) ns->pif = ns->params.pif; - static const NvmeLBAF lbaf[16] = { + static const NvmeLBAF defaults[16] = { [0] = { .ds = 9 }, [1] = { .ds = 9, .ms = 8 }, [2] = { .ds = 9, .ms = 16 }, @@ -120,7 +120,7 @@ static int nvme_ns_init(NvmeNamespace *ns, Error **errp) ns->nlbaf = 8; - memcpy(&id_ns->lbaf, &lbaf, sizeof(lbaf)); + memcpy(&id_ns->lbaf, &defaults, sizeof(defaults)); for (i = 0; i < ns->nlbaf; i++) { NvmeLBAF *lbaf = &id_ns->lbaf[i]; From 4dba9141f97e66fdd920df37c4aa7b2ffe0d6a4a Mon Sep 17 00:00:00 2001 From: Laurent Vivier Date: Mon, 25 Sep 2023 10:44:55 +0200 Subject: [PATCH 0098/1077] disas/m68k: clean up local variable shadowing MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fix following warnings .../disas/m68k.c: In function ‘print_insn_arg’: .../disas/m68k.c:1635:13: warning: declaration of ‘val’ shadows a previous local [-Wshadow=compatible-local] 1635 | int val = fetch_arg (buffer, place, 5, info); | ^~~ .../disas/m68k.c:1093:7: note: shadowed declaration is here 1093 | int val = 0; | ^~~ Signed-off-by: Laurent Vivier Message-ID: <20230925084455.395150-1-laurent@vivier.eu> Reviewed-by: Thomas Huth Signed-off-by: Markus Armbruster --- disas/m68k.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/disas/m68k.c b/disas/m68k.c index aefaecfbd6..1f16e295ab 100644 --- a/disas/m68k.c +++ b/disas/m68k.c @@ -1632,10 +1632,10 @@ print_insn_arg (const char *d, case '2': case '3': { - int val = fetch_arg (buffer, place, 5, info); + int reg = fetch_arg (buffer, place, 5, info); const char *name = 0; - switch (val) + switch (reg) { case 2: name = "%tt0"; break; case 3: name = "%tt1"; break; @@ -1655,12 +1655,12 @@ print_insn_arg (const char *d, int break_reg = ((buffer[3] >> 2) & 7); (*info->fprintf_func) - (info->stream, val == 0x1c ? "%%bad%d" : "%%bac%d", + (info->stream, reg == 0x1c ? "%%bad%d" : "%%bac%d", break_reg); } break; default: - (*info->fprintf_func) (info->stream, "", val); + (*info->fprintf_func) (info->stream, "", reg); } if (name) (*info->fprintf_func) (info->stream, "%s", name); From 71d3612401b614bc64a00fafa8dd930a5672b782 Mon Sep 17 00:00:00 2001 From: Juan Quintela Date: Fri, 9 Jun 2023 00:49:08 +0200 Subject: [PATCH 0099/1077] migration-test: Create kvm_opts So arch_dirty_ring option becomes one option like the others. Reviewed-by: Peter Xu Message-ID: <20230608224943.3877-8-quintela@redhat.com> Signed-off-by: Juan Quintela --- tests/qtest/migration-test.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/tests/qtest/migration-test.c b/tests/qtest/migration-test.c index 1b43df5ca7..bde553730e 100644 --- a/tests/qtest/migration-test.c +++ b/tests/qtest/migration-test.c @@ -710,6 +710,7 @@ static int test_migrate_start(QTestState **from, QTestState **to, g_autofree char *bootpath = NULL; g_autofree char *shmem_opts = NULL; g_autofree char *shmem_path = NULL; + const char *kvm_opts = NULL; const char *arch = qtest_get_arch(); const char *memory_size; @@ -785,13 +786,16 @@ static int test_migrate_start(QTestState **from, QTestState **to, shmem_opts = g_strdup(""); } + if (args->use_dirty_ring) { + kvm_opts = ",dirty-ring-size=4096"; + } + cmd_source = g_strdup_printf("-accel kvm%s -accel tcg " "-name source,debug-threads=on " "-m %s " "-serial file:%s/src_serial " "%s %s %s %s %s", - args->use_dirty_ring ? - ",dirty-ring-size=4096" : "", + kvm_opts ? kvm_opts : "", memory_size, tmpfs, arch_opts ? arch_opts : "", arch_source ? arch_source : "", @@ -811,8 +815,7 @@ static int test_migrate_start(QTestState **from, QTestState **to, "-serial file:%s/dest_serial " "-incoming %s " "%s %s %s %s %s", - args->use_dirty_ring ? - ",dirty-ring-size=4096" : "", + kvm_opts ? kvm_opts : "", memory_size, tmpfs, uri, arch_opts ? arch_opts : "", arch_target ? arch_target : "", From 877cec63d77058c27230b33643508dfeb84d8021 Mon Sep 17 00:00:00 2001 From: Juan Quintela Date: Fri, 9 Jun 2023 00:49:09 +0200 Subject: [PATCH 0100/1077] migration-test: bootpath is the same for all tests and for all archs So just make it a global variable. Reviewed-by: Peter Xu Message-ID: <20230608224943.3877-9-quintela@redhat.com> Signed-off-by: Juan Quintela --- tests/qtest/migration-test.c | 20 +++++++++----------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/tests/qtest/migration-test.c b/tests/qtest/migration-test.c index bde553730e..e191f66e54 100644 --- a/tests/qtest/migration-test.c +++ b/tests/qtest/migration-test.c @@ -116,6 +116,7 @@ static bool ufd_version_check(void) #endif static char *tmpfs; +static char *bootpath; /* The boot file modifies memory area in [start_address, end_address) * repeatedly. It outputs a 'B' at a fixed rate while it's still running. @@ -124,7 +125,7 @@ static char *tmpfs; #include "tests/migration/aarch64/a-b-kernel.h" #include "tests/migration/s390x/a-b-bios.h" -static void init_bootfile(const char *bootpath, void *content, size_t len) +static void init_bootfile(void *content, size_t len) { FILE *bootfile = fopen(bootpath, "wb"); @@ -707,7 +708,6 @@ static int test_migrate_start(QTestState **from, QTestState **to, g_autofree gchar *cmd_source = NULL; g_autofree gchar *cmd_target = NULL; const gchar *ignore_stderr; - g_autofree char *bootpath = NULL; g_autofree char *shmem_opts = NULL; g_autofree char *shmem_path = NULL; const char *kvm_opts = NULL; @@ -723,17 +723,16 @@ static int test_migrate_start(QTestState **from, QTestState **to, got_src_stop = false; got_dst_resume = false; - bootpath = g_strdup_printf("%s/bootsect", tmpfs); if (strcmp(arch, "i386") == 0 || strcmp(arch, "x86_64") == 0) { /* the assembled x86 boot sector should be exactly one sector large */ assert(sizeof(x86_bootsect) == 512); - init_bootfile(bootpath, x86_bootsect, sizeof(x86_bootsect)); + init_bootfile(x86_bootsect, sizeof(x86_bootsect)); memory_size = "150M"; arch_opts = g_strdup_printf("-drive file=%s,format=raw", bootpath); start_address = X86_TEST_MEM_START; end_address = X86_TEST_MEM_END; } else if (g_str_equal(arch, "s390x")) { - init_bootfile(bootpath, s390x_elf, sizeof(s390x_elf)); + init_bootfile(s390x_elf, sizeof(s390x_elf)); memory_size = "128M"; arch_opts = g_strdup_printf("-bios %s", bootpath); start_address = S390_TEST_MEM_START; @@ -748,7 +747,7 @@ static int test_migrate_start(QTestState **from, QTestState **to, "until'", end_address, start_address); arch_opts = g_strdup("-nodefaults -machine vsmt=8"); } else if (strcmp(arch, "aarch64") == 0) { - init_bootfile(bootpath, aarch64_kernel, sizeof(aarch64_kernel)); + init_bootfile(aarch64_kernel, sizeof(aarch64_kernel)); memory_size = "150M"; arch_opts = g_strdup_printf("-machine virt,gic-version=max -cpu max " "-kernel %s", bootpath); @@ -866,7 +865,6 @@ static void test_migrate_end(QTestState *from, QTestState *to, bool test_dest) qtest_quit(to); - cleanup("bootsect"); cleanup("migsocket"); cleanup("src_serial"); cleanup("dest_serial"); @@ -2629,12 +2627,10 @@ static QTestState *dirtylimit_start_vm(void) QTestState *vm = NULL; g_autofree gchar *cmd = NULL; const char *arch = qtest_get_arch(); - g_autofree char *bootpath = NULL; assert((strcmp(arch, "x86_64") == 0)); - bootpath = g_strdup_printf("%s/bootsect", tmpfs); assert(sizeof(x86_bootsect) == 512); - init_bootfile(bootpath, x86_bootsect, sizeof(x86_bootsect)); + init_bootfile(x86_bootsect, sizeof(x86_bootsect)); cmd = g_strdup_printf("-accel kvm,dirty-ring-size=4096 " "-name dirtylimit-test,debug-threads=on " @@ -2650,7 +2646,6 @@ static QTestState *dirtylimit_start_vm(void) static void dirtylimit_stop_vm(QTestState *vm) { qtest_quit(vm); - cleanup("bootsect"); cleanup("vm_serial"); } @@ -2812,6 +2807,7 @@ int main(int argc, char **argv) g_get_tmp_dir(), err->message); } g_assert(tmpfs); + bootpath = g_strdup_printf("%s/bootsect", tmpfs); module_call_init(MODULE_INIT_QOM); @@ -2959,6 +2955,8 @@ int main(int argc, char **argv) g_assert_cmpint(ret, ==, 0); + cleanup("bootsect"); + g_free(bootpath); ret = rmdir(tmpfs); if (ret != 0) { g_test_message("unable to rmdir: path (%s): %s", From 0c690d3e2a3eb73a6c27afb66ec87534c1259bae Mon Sep 17 00:00:00 2001 From: Juan Quintela Date: Fri, 9 Jun 2023 00:49:10 +0200 Subject: [PATCH 0101/1077] migration-test: Add bootfile_create/delete() functions The bootsector code is read only from the guest (otherwise we are going to have problems with it being read from both source and destination). Create a single copy for all the tests. Reviewed-by: Peter Xu Message-ID: <20230608224943.3877-10-quintela@redhat.com> Signed-off-by: Juan Quintela --- tests/qtest/migration-test.c | 50 ++++++++++++++++++++++++++---------- 1 file changed, 36 insertions(+), 14 deletions(-) diff --git a/tests/qtest/migration-test.c b/tests/qtest/migration-test.c index e191f66e54..f601249391 100644 --- a/tests/qtest/migration-test.c +++ b/tests/qtest/migration-test.c @@ -125,14 +125,47 @@ static char *bootpath; #include "tests/migration/aarch64/a-b-kernel.h" #include "tests/migration/s390x/a-b-bios.h" -static void init_bootfile(void *content, size_t len) +static void bootfile_create(char *dir) { + const char *arch = qtest_get_arch(); + unsigned char *content; + size_t len; + + bootpath = g_strdup_printf("%s/bootsect", dir); + if (strcmp(arch, "i386") == 0 || strcmp(arch, "x86_64") == 0) { + /* the assembled x86 boot sector should be exactly one sector large */ + g_assert(sizeof(x86_bootsect) == 512); + content = x86_bootsect; + len = sizeof(x86_bootsect); + } else if (g_str_equal(arch, "s390x")) { + content = s390x_elf; + len = sizeof(s390x_elf); + } else if (strcmp(arch, "ppc64") == 0) { + /* + * sane architectures can be programmed at the boot prompt + */ + return; + } else if (strcmp(arch, "aarch64") == 0) { + content = aarch64_kernel; + len = sizeof(aarch64_kernel); + g_assert(sizeof(aarch64_kernel) <= ARM_TEST_MAX_KERNEL_SIZE); + } else { + g_assert_not_reached(); + } + FILE *bootfile = fopen(bootpath, "wb"); g_assert_cmpint(fwrite(content, len, 1, bootfile), ==, 1); fclose(bootfile); } +static void bootfile_delete(void) +{ + unlink(bootpath); + g_free(bootpath); + bootpath = NULL; +} + /* * Wait for some output in the serial output file, * we get an 'A' followed by an endless string of 'B's @@ -724,15 +757,11 @@ static int test_migrate_start(QTestState **from, QTestState **to, got_src_stop = false; got_dst_resume = false; if (strcmp(arch, "i386") == 0 || strcmp(arch, "x86_64") == 0) { - /* the assembled x86 boot sector should be exactly one sector large */ - assert(sizeof(x86_bootsect) == 512); - init_bootfile(x86_bootsect, sizeof(x86_bootsect)); memory_size = "150M"; arch_opts = g_strdup_printf("-drive file=%s,format=raw", bootpath); start_address = X86_TEST_MEM_START; end_address = X86_TEST_MEM_END; } else if (g_str_equal(arch, "s390x")) { - init_bootfile(s390x_elf, sizeof(s390x_elf)); memory_size = "128M"; arch_opts = g_strdup_printf("-bios %s", bootpath); start_address = S390_TEST_MEM_START; @@ -747,14 +776,11 @@ static int test_migrate_start(QTestState **from, QTestState **to, "until'", end_address, start_address); arch_opts = g_strdup("-nodefaults -machine vsmt=8"); } else if (strcmp(arch, "aarch64") == 0) { - init_bootfile(aarch64_kernel, sizeof(aarch64_kernel)); memory_size = "150M"; arch_opts = g_strdup_printf("-machine virt,gic-version=max -cpu max " "-kernel %s", bootpath); start_address = ARM_TEST_MEM_START; end_address = ARM_TEST_MEM_END; - - g_assert(sizeof(aarch64_kernel) <= ARM_TEST_MAX_KERNEL_SIZE); } else { g_assert_not_reached(); } @@ -2629,9 +2655,6 @@ static QTestState *dirtylimit_start_vm(void) const char *arch = qtest_get_arch(); assert((strcmp(arch, "x86_64") == 0)); - assert(sizeof(x86_bootsect) == 512); - init_bootfile(x86_bootsect, sizeof(x86_bootsect)); - cmd = g_strdup_printf("-accel kvm,dirty-ring-size=4096 " "-name dirtylimit-test,debug-threads=on " "-m 150M -smp 1 " @@ -2807,7 +2830,7 @@ int main(int argc, char **argv) g_get_tmp_dir(), err->message); } g_assert(tmpfs); - bootpath = g_strdup_printf("%s/bootsect", tmpfs); + bootfile_create(tmpfs); module_call_init(MODULE_INIT_QOM); @@ -2955,8 +2978,7 @@ int main(int argc, char **argv) g_assert_cmpint(ret, ==, 0); - cleanup("bootsect"); - g_free(bootpath); + bootfile_delete(); ret = rmdir(tmpfs); if (ret != 0) { g_test_message("unable to rmdir: path (%s): %s", From 22d3c6e16c69ea581eef6f7ff8ebb2e63107d3f5 Mon Sep 17 00:00:00 2001 From: Juan Quintela Date: Fri, 9 Jun 2023 00:49:11 +0200 Subject: [PATCH 0102/1077] migration-test: dirtylimit checks for x86_64 arch before So no need to assert we are in x86_64. Once there, refactor the function to remove useless variables. Reviewed-by: Peter Xu Message-ID: <20230608224943.3877-11-quintela@redhat.com> Signed-off-by: Juan Quintela --- tests/qtest/migration-test.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/tests/qtest/migration-test.c b/tests/qtest/migration-test.c index f601249391..334648ae19 100644 --- a/tests/qtest/migration-test.c +++ b/tests/qtest/migration-test.c @@ -2651,10 +2651,7 @@ static int64_t get_limit_rate(QTestState *who) static QTestState *dirtylimit_start_vm(void) { QTestState *vm = NULL; - g_autofree gchar *cmd = NULL; - const char *arch = qtest_get_arch(); - - assert((strcmp(arch, "x86_64") == 0)); + g_autofree gchar * cmd = g_strdup_printf("-accel kvm,dirty-ring-size=4096 " "-name dirtylimit-test,debug-threads=on " "-m 150M -smp 1 " From 0368ace8f9eb24c5959466db352e4c4afc734954 Mon Sep 17 00:00:00 2001 From: Juan Quintela Date: Fri, 9 Jun 2023 00:49:04 +0200 Subject: [PATCH 0103/1077] migration-test: simplify shmem_opts handling Reviewed-by: Peter Xu Message-ID: <20230608224943.3877-4-quintela@redhat.com> Signed-off-by: Juan Quintela --- tests/qtest/migration-test.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/tests/qtest/migration-test.c b/tests/qtest/migration-test.c index 334648ae19..46f1c275a2 100644 --- a/tests/qtest/migration-test.c +++ b/tests/qtest/migration-test.c @@ -806,9 +806,6 @@ static int test_migrate_start(QTestState **from, QTestState **to, "-object memory-backend-file,id=mem0,size=%s" ",mem-path=%s,share=on -numa node,memdev=mem0", memory_size, shmem_path); - } else { - shmem_path = NULL; - shmem_opts = g_strdup(""); } if (args->use_dirty_ring) { @@ -824,7 +821,7 @@ static int test_migrate_start(QTestState **from, QTestState **to, memory_size, tmpfs, arch_opts ? arch_opts : "", arch_source ? arch_source : "", - shmem_opts, + shmem_opts ? shmem_opts : "", args->opts_source ? args->opts_source : "", ignore_stderr); if (!args->only_target) { @@ -844,7 +841,7 @@ static int test_migrate_start(QTestState **from, QTestState **to, memory_size, tmpfs, uri, arch_opts ? arch_opts : "", arch_target ? arch_target : "", - shmem_opts, + shmem_opts ? shmem_opts : "", args->opts_target ? args->opts_target : "", ignore_stderr); *to = qtest_init(cmd_target); From f4e1b613362e51e205081a60b94f157c16acdca3 Mon Sep 17 00:00:00 2001 From: Tejus GK Date: Wed, 21 Jun 2023 13:09:40 +0000 Subject: [PATCH 0104/1077] migration: Refactor repeated call of yank_unregister_instance MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In the function qmp_migrate(), yank_unregister_instance() gets called twice which isn't required. Hence, refactoring it so that it gets called during the local_error cleanup. Reviewed-by: Daniel P. Berrangé Reviewed-by: Juan Quintela Acked-by: Peter Xu Signed-off-by: Tejus GK Message-ID: <20230621130940.178659-3-tejus.gk@nutanix.com> Signed-off-by: Juan Quintela --- migration/migration.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/migration/migration.c b/migration/migration.c index e2ed85b5be..6d3cf5d5cd 100644 --- a/migration/migration.c +++ b/migration/migration.c @@ -1703,15 +1703,11 @@ void qmp_migrate(const char *uri, bool has_blk, bool blk, } else if (strstart(uri, "fd:", &p)) { fd_start_outgoing_migration(s, p, &local_err); } else { - if (!resume_requested) { - yank_unregister_instance(MIGRATION_YANK_INSTANCE); - } error_setg(&local_err, QERR_INVALID_PARAMETER_VALUE, "uri", "a valid migration protocol"); migrate_set_state(&s->state, MIGRATION_STATUS_SETUP, MIGRATION_STATUS_FAILED); block_cleanup_parameters(); - return; } if (local_err) { From f16ecfa9f9c147168630422a6f4a4c0eddfbe574 Mon Sep 17 00:00:00 2001 From: Juan Quintela Date: Tue, 30 May 2023 20:39:24 +0200 Subject: [PATCH 0105/1077] migration: Use qemu_file_transferred_noflush() for block migration. We only care about the amount of bytes transferred. Flushing is done by the system somewhere else. Reviewed-by: Fabiano Rosas Signed-off-by: Juan Quintela Message-ID: <20230530183941.7223-4-quintela@redhat.com> Signed-off-by: Juan Quintela --- migration/block.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/migration/block.c b/migration/block.c index 86c2256a2b..26c10c0a0c 100644 --- a/migration/block.c +++ b/migration/block.c @@ -755,7 +755,7 @@ static int block_save_setup(QEMUFile *f, void *opaque) static int block_save_iterate(QEMUFile *f, void *opaque) { int ret; - uint64_t last_bytes = qemu_file_transferred(f); + uint64_t last_bytes = qemu_file_transferred_noflush(f); trace_migration_block_save("iterate", block_mig_state.submitted, block_mig_state.transferred); @@ -807,7 +807,7 @@ static int block_save_iterate(QEMUFile *f, void *opaque) } qemu_put_be64(f, BLK_MIG_FLAG_EOS); - uint64_t delta_bytes = qemu_file_transferred(f) - last_bytes; + uint64_t delta_bytes = qemu_file_transferred_noflush(f) - last_bytes; return (delta_bytes > 0); } From 67c31c9c1af1bb8f7df8275cc8731629e2690f89 Mon Sep 17 00:00:00 2001 From: Juan Quintela Date: Mon, 15 May 2023 21:57:03 +0200 Subject: [PATCH 0106/1077] migration: Don't abuse qemu_file transferred for RDMA Just create a variable for it, the same way that multifd does. This way it is safe to use for other thread, etc, etc. Reviewed-by: Leonardo Bras Signed-off-by: Juan Quintela Message-Id: <20230515195709.63843-11-quintela@redhat.com> --- migration/migration-stats.c | 5 +++-- migration/migration-stats.h | 4 ++++ migration/rdma.c | 22 ++++++++++++++++++++-- migration/trace-events | 2 +- 4 files changed, 28 insertions(+), 5 deletions(-) diff --git a/migration/migration-stats.c b/migration/migration-stats.c index 095d6d75bb..84e11e6dd8 100644 --- a/migration/migration-stats.c +++ b/migration/migration-stats.c @@ -61,8 +61,9 @@ void migration_rate_reset(QEMUFile *f) uint64_t migration_transferred_bytes(QEMUFile *f) { uint64_t multifd = stat64_get(&mig_stats.multifd_bytes); + uint64_t rdma = stat64_get(&mig_stats.rdma_bytes); uint64_t qemu_file = qemu_file_transferred(f); - trace_migration_transferred_bytes(qemu_file, multifd); - return qemu_file + multifd; + trace_migration_transferred_bytes(qemu_file, multifd, rdma); + return qemu_file + multifd + rdma; } diff --git a/migration/migration-stats.h b/migration/migration-stats.h index ac2260e987..2358caad63 100644 --- a/migration/migration-stats.h +++ b/migration/migration-stats.h @@ -89,6 +89,10 @@ typedef struct { * Maximum amount of data we can send in a cycle. */ Stat64 rate_limit_max; + /* + * Number of bytes sent through RDMA. + */ + Stat64 rdma_bytes; /* * Total number of bytes transferred. */ diff --git a/migration/rdma.c b/migration/rdma.c index a2a3db35b1..2a3c784328 100644 --- a/migration/rdma.c +++ b/migration/rdma.c @@ -2122,9 +2122,18 @@ retry: return -EIO; } + /* + * TODO: Here we are sending something, but we are not + * accounting for anything transferred. The following is wrong: + * + * stat64_add(&mig_stats.rdma_bytes, sge.length); + * + * because we are using some kind of compression. I + * would think that head.len would be the more similar + * thing to a correct value. + */ stat64_add(&mig_stats.zero_pages, sge.length / qemu_target_page_size()); - return 1; } @@ -2232,8 +2241,17 @@ retry: set_bit(chunk, block->transit_bitmap); stat64_add(&mig_stats.normal_pages, sge.length / qemu_target_page_size()); + /* + * We are adding to transferred the amount of data written, but no + * overhead at all. I will asume that RDMA is magicaly and don't + * need to transfer (at least) the addresses where it wants to + * write the pages. Here it looks like it should be something + * like: + * sizeof(send_wr) + sge.length + * but this being RDMA, who knows. + */ + stat64_add(&mig_stats.rdma_bytes, sge.length); ram_transferred_add(sge.length); - qemu_file_credit_transfer(f, sge.length); rdma->total_writes++; return 0; diff --git a/migration/trace-events b/migration/trace-events index 4666f19325..63483732ce 100644 --- a/migration/trace-events +++ b/migration/trace-events @@ -191,7 +191,7 @@ process_incoming_migration_co_postcopy_end_main(void) "" postcopy_preempt_enabled(bool value) "%d" # migration-stats -migration_transferred_bytes(uint64_t qemu_file, uint64_t multifd) "qemu_file %" PRIu64 " multifd %" PRIu64 +migration_transferred_bytes(uint64_t qemu_file, uint64_t multifd, uint64_t rdma) "qemu_file %" PRIu64 " multifd %" PRIu64 " RDMA %" PRIu64 # channel.c migration_set_incoming_channel(void *ioc, const char *ioctype) "ioc=%p ioctype=%s" From 19df4f3226c0f3e80291a40aec3c9c459dadfdf4 Mon Sep 17 00:00:00 2001 From: Juan Quintela Date: Mon, 15 May 2023 21:57:04 +0200 Subject: [PATCH 0107/1077] migration/RDMA: It is accounting for zero/normal pages in two places Remove the one in control_save_page(). Reviewed-by: Leonardo Bras Signed-off-by: Juan Quintela Message-Id: <20230515195709.63843-12-quintela@redhat.com> --- migration/ram.c | 7 ------- 1 file changed, 7 deletions(-) diff --git a/migration/ram.c b/migration/ram.c index 9040d66e61..f2c5b07919 100644 --- a/migration/ram.c +++ b/migration/ram.c @@ -1204,13 +1204,6 @@ static bool control_save_page(PageSearchStatus *pss, RAMBlock *block, if (ret == RAM_SAVE_CONTROL_DELAYED) { return true; } - - if (bytes_xmit > 0) { - stat64_add(&mig_stats.normal_pages, 1); - } else if (bytes_xmit == 0) { - stat64_add(&mig_stats.zero_pages, 1); - } - return true; } From e33780351ceb8317dccec143e722ae8434d58c34 Mon Sep 17 00:00:00 2001 From: Juan Quintela Date: Mon, 15 May 2023 21:57:05 +0200 Subject: [PATCH 0108/1077] migration/rdma: Remove QEMUFile parameter when not used Reviewed-by: Leonardo Bras Signed-off-by: Juan Quintela Message-Id: <20230515195709.63843-13-quintela@redhat.com> --- migration/rdma.c | 23 +++++++++++------------ 1 file changed, 11 insertions(+), 12 deletions(-) diff --git a/migration/rdma.c b/migration/rdma.c index 2a3c784328..9007261b5c 100644 --- a/migration/rdma.c +++ b/migration/rdma.c @@ -2027,7 +2027,7 @@ static int qemu_rdma_exchange_recv(RDMAContext *rdma, RDMAControlHeader *head, * If we're using dynamic registration on the dest-side, we have to * send a registration command first. */ -static int qemu_rdma_write_one(QEMUFile *f, RDMAContext *rdma, +static int qemu_rdma_write_one(RDMAContext *rdma, int current_index, uint64_t current_addr, uint64_t length) { @@ -2263,7 +2263,7 @@ retry: * We support sending out multiple chunks at the same time. * Not all of them need to get signaled in the completion queue. */ -static int qemu_rdma_write_flush(QEMUFile *f, RDMAContext *rdma) +static int qemu_rdma_write_flush(RDMAContext *rdma) { int ret; @@ -2271,7 +2271,7 @@ static int qemu_rdma_write_flush(QEMUFile *f, RDMAContext *rdma) return 0; } - ret = qemu_rdma_write_one(f, rdma, + ret = qemu_rdma_write_one(rdma, rdma->current_index, rdma->current_addr, rdma->current_length); if (ret < 0) { @@ -2344,7 +2344,7 @@ static inline int qemu_rdma_buffer_mergable(RDMAContext *rdma, * and only require that a batch gets acknowledged in the completion * queue instead of each individual chunk. */ -static int qemu_rdma_write(QEMUFile *f, RDMAContext *rdma, +static int qemu_rdma_write(RDMAContext *rdma, uint64_t block_offset, uint64_t offset, uint64_t len) { @@ -2355,7 +2355,7 @@ static int qemu_rdma_write(QEMUFile *f, RDMAContext *rdma, /* If we cannot merge it, we flush the current buffer first. */ if (!qemu_rdma_buffer_mergable(rdma, current_addr, len)) { - ret = qemu_rdma_write_flush(f, rdma); + ret = qemu_rdma_write_flush(rdma); if (ret) { return ret; } @@ -2377,7 +2377,7 @@ static int qemu_rdma_write(QEMUFile *f, RDMAContext *rdma, /* flush it if buffer is too large */ if (rdma->current_length >= RDMA_MERGE_MAX) { - return qemu_rdma_write_flush(f, rdma); + return qemu_rdma_write_flush(rdma); } return 0; @@ -2798,7 +2798,6 @@ static ssize_t qio_channel_rdma_writev(QIOChannel *ioc, Error **errp) { QIOChannelRDMA *rioc = QIO_CHANNEL_RDMA(ioc); - QEMUFile *f = rioc->file; RDMAContext *rdma; int ret; ssize_t done = 0; @@ -2819,7 +2818,7 @@ static ssize_t qio_channel_rdma_writev(QIOChannel *ioc, * Push out any writes that * we're queued up for VM's ram. */ - ret = qemu_rdma_write_flush(f, rdma); + ret = qemu_rdma_write_flush(rdma); if (ret < 0) { rdma->error_state = ret; error_setg(errp, "qemu_rdma_write_flush returned %d", ret); @@ -2958,11 +2957,11 @@ static ssize_t qio_channel_rdma_readv(QIOChannel *ioc, /* * Block until all the outstanding chunks have been delivered by the hardware. */ -static int qemu_rdma_drain_cq(QEMUFile *f, RDMAContext *rdma) +static int qemu_rdma_drain_cq(RDMAContext *rdma) { int ret; - if (qemu_rdma_write_flush(f, rdma) < 0) { + if (qemu_rdma_write_flush(rdma) < 0) { return -EIO; } @@ -3273,7 +3272,7 @@ static size_t qemu_rdma_save_page(QEMUFile *f, * is full, or the page doesn't belong to the current chunk, * an actual RDMA write will occur and a new chunk will be formed. */ - ret = qemu_rdma_write(f, rdma, block_offset, offset, size); + ret = qemu_rdma_write(rdma, block_offset, offset, size); if (ret < 0) { error_report("rdma migration: write error! %d", ret); goto err; @@ -3928,7 +3927,7 @@ static int qemu_rdma_registration_stop(QEMUFile *f, CHECK_ERROR_STATE(); qemu_fflush(f); - ret = qemu_rdma_drain_cq(f, rdma); + ret = qemu_rdma_drain_cq(rdma); if (ret < 0) { goto err; From 2ebe5d4d5aa4d11f02a2d52fa398a52a6a0dc2ee Mon Sep 17 00:00:00 2001 From: Juan Quintela Date: Mon, 15 May 2023 21:57:06 +0200 Subject: [PATCH 0109/1077] migration/rdma: Don't use imaginary transfers RDMA protocol is completely asynchronous, so in qemu_rdma_save_page() they "invent" that a byte has been transferred. And then they call qemu_file_credit_transfer() and ram_transferred_add() with that byte. Just remove that calls as nothing has been sent. Reviewed-by: Leonardo Bras Signed-off-by: Juan Quintela Message-Id: <20230515195709.63843-14-quintela@redhat.com> --- migration/qemu-file.c | 5 +---- migration/ram.c | 1 - 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/migration/qemu-file.c b/migration/qemu-file.c index 19c33c9985..e53ff2dd86 100644 --- a/migration/qemu-file.c +++ b/migration/qemu-file.c @@ -332,13 +332,10 @@ size_t ram_control_save_page(QEMUFile *f, ram_addr_t block_offset, if (ret != RAM_SAVE_CONTROL_DELAYED && ret != RAM_SAVE_CONTROL_NOT_SUPP) { - if (bytes_sent && *bytes_sent > 0) { - qemu_file_credit_transfer(f, *bytes_sent); - } else if (ret < 0) { + if (ret < 0) { qemu_file_set_error(f, ret); } } - return ret; } diff --git a/migration/ram.c b/migration/ram.c index f2c5b07919..c6238f7a8b 100644 --- a/migration/ram.c +++ b/migration/ram.c @@ -1197,7 +1197,6 @@ static bool control_save_page(PageSearchStatus *pss, RAMBlock *block, } if (bytes_xmit) { - ram_transferred_add(bytes_xmit); *pages = 1; } From 9f51fe92392f601a177687bef01a545298cb47e1 Mon Sep 17 00:00:00 2001 From: Juan Quintela Date: Mon, 15 May 2023 21:57:07 +0200 Subject: [PATCH 0110/1077] migration: Remove unused qemu_file_credit_transfer() After this change, nothing abuses QEMUFile to account for data transferrefd during migration. Reviewed-by: Leonardo Bras Signed-off-by: Juan Quintela Message-Id: <20230515195709.63843-15-quintela@redhat.com> --- migration/qemu-file.c | 5 ----- migration/qemu-file.h | 8 -------- 2 files changed, 13 deletions(-) diff --git a/migration/qemu-file.c b/migration/qemu-file.c index e53ff2dd86..5c43fa34e7 100644 --- a/migration/qemu-file.c +++ b/migration/qemu-file.c @@ -397,11 +397,6 @@ static ssize_t coroutine_mixed_fn qemu_fill_buffer(QEMUFile *f) return len; } -void qemu_file_credit_transfer(QEMUFile *f, size_t size) -{ - f->total_transferred += size; -} - /** Closes the file * * Returns negative error value if any error happened on previous operations or diff --git a/migration/qemu-file.h b/migration/qemu-file.h index 47015f5201..57b00c8562 100644 --- a/migration/qemu-file.h +++ b/migration/qemu-file.h @@ -119,14 +119,6 @@ bool qemu_file_buffer_empty(QEMUFile *file); */ int coroutine_mixed_fn qemu_peek_byte(QEMUFile *f, int offset); void qemu_file_skip(QEMUFile *f, int size); -/* - * qemu_file_credit_transfer: - * - * Report on a number of bytes that have been transferred - * out of band from the main file object I/O methods. This - * accounting information tracks the total migration traffic. - */ -void qemu_file_credit_transfer(QEMUFile *f, size_t size); int qemu_file_get_error_obj_any(QEMUFile *f1, QEMUFile *f2, Error **errp); void qemu_file_set_error_obj(QEMUFile *f, int ret, Error *err); void qemu_file_set_error(QEMUFile *f, int ret); From 9c53d369e5903375a2e3358f739be77dcb8dae49 Mon Sep 17 00:00:00 2001 From: Juan Quintela Date: Mon, 15 May 2023 21:57:08 +0200 Subject: [PATCH 0111/1077] migration/rdma: Simplify the function that saves a page When we sent a page through QEMUFile hooks (RDMA) there are three posiblities: - We are not using RDMA. return RAM_SAVE_CONTROL_DELAYED and control_save_page() returns false to let anything else to proceed. - There is one error but we are using RDMA. Then we return a negative value, control_save_page() needs to return true. - Everything goes well and RDMA start the sent of the page asynchronously. It returns RAM_SAVE_CONTROL_DELAYED and we need to return 1 for ram_save_page_legacy. Clear? I know, I know, the interface is as bad as it gets. I think that now it is a bit clearer, but this needs to be done some other way. Reviewed-by: Leonardo Bras Signed-off-by: Juan Quintela Message-Id: <20230515195709.63843-16-quintela@redhat.com> --- migration/qemu-file.c | 12 ++++++------ migration/qemu-file.h | 14 ++++++-------- migration/ram.c | 10 +++------- migration/rdma.c | 19 +++---------------- 4 files changed, 18 insertions(+), 37 deletions(-) diff --git a/migration/qemu-file.c b/migration/qemu-file.c index 5c43fa34e7..5e8207dae4 100644 --- a/migration/qemu-file.c +++ b/migration/qemu-file.c @@ -322,14 +322,14 @@ void ram_control_load_hook(QEMUFile *f, uint64_t flags, void *data) } } -size_t ram_control_save_page(QEMUFile *f, ram_addr_t block_offset, - ram_addr_t offset, size_t size, - uint64_t *bytes_sent) +int ram_control_save_page(QEMUFile *f, ram_addr_t block_offset, + ram_addr_t offset, size_t size) { if (f->hooks && f->hooks->save_page) { - int ret = f->hooks->save_page(f, block_offset, - offset, size, bytes_sent); - + int ret = f->hooks->save_page(f, block_offset, offset, size); + /* + * RAM_SAVE_CONTROL_* are negative values + */ if (ret != RAM_SAVE_CONTROL_DELAYED && ret != RAM_SAVE_CONTROL_NOT_SUPP) { if (ret < 0) { diff --git a/migration/qemu-file.h b/migration/qemu-file.h index 57b00c8562..03e718c264 100644 --- a/migration/qemu-file.h +++ b/migration/qemu-file.h @@ -49,11 +49,10 @@ typedef int (QEMURamHookFunc)(QEMUFile *f, uint64_t flags, void *data); * This function allows override of where the RAM page * is saved (such as RDMA, for example.) */ -typedef size_t (QEMURamSaveFunc)(QEMUFile *f, - ram_addr_t block_offset, - ram_addr_t offset, - size_t size, - uint64_t *bytes_sent); +typedef int (QEMURamSaveFunc)(QEMUFile *f, + ram_addr_t block_offset, + ram_addr_t offset, + size_t size); typedef struct QEMUFileHooks { QEMURamHookFunc *before_ram_iterate; @@ -142,9 +141,8 @@ void ram_control_load_hook(QEMUFile *f, uint64_t flags, void *data); #define RAM_SAVE_CONTROL_NOT_SUPP -1000 #define RAM_SAVE_CONTROL_DELAYED -2000 -size_t ram_control_save_page(QEMUFile *f, ram_addr_t block_offset, - ram_addr_t offset, size_t size, - uint64_t *bytes_sent); +int ram_control_save_page(QEMUFile *f, ram_addr_t block_offset, + ram_addr_t offset, size_t size); QIOChannel *qemu_file_get_ioc(QEMUFile *file); #endif diff --git a/migration/ram.c b/migration/ram.c index c6238f7a8b..99cff591a3 100644 --- a/migration/ram.c +++ b/migration/ram.c @@ -1186,23 +1186,19 @@ static int save_zero_page(PageSearchStatus *pss, QEMUFile *f, RAMBlock *block, static bool control_save_page(PageSearchStatus *pss, RAMBlock *block, ram_addr_t offset, int *pages) { - uint64_t bytes_xmit = 0; int ret; - *pages = -1; ret = ram_control_save_page(pss->pss_channel, block->offset, offset, - TARGET_PAGE_SIZE, &bytes_xmit); + TARGET_PAGE_SIZE); if (ret == RAM_SAVE_CONTROL_NOT_SUPP) { return false; } - if (bytes_xmit) { - *pages = 1; - } - if (ret == RAM_SAVE_CONTROL_DELAYED) { + *pages = 1; return true; } + *pages = ret; return true; } diff --git a/migration/rdma.c b/migration/rdma.c index 9007261b5c..5748c9045b 100644 --- a/migration/rdma.c +++ b/migration/rdma.c @@ -3240,13 +3240,12 @@ qio_channel_rdma_shutdown(QIOChannel *ioc, * * @size : Number of bytes to transfer * - * @bytes_sent : User-specificed pointer to indicate how many bytes were + * @pages_sent : User-specificed pointer to indicate how many pages were * sent. Usually, this will not be more than a few bytes of * the protocol because most transfers are sent asynchronously. */ -static size_t qemu_rdma_save_page(QEMUFile *f, - ram_addr_t block_offset, ram_addr_t offset, - size_t size, uint64_t *bytes_sent) +static int qemu_rdma_save_page(QEMUFile *f, ram_addr_t block_offset, + ram_addr_t offset, size_t size) { QIOChannelRDMA *rioc = QIO_CHANNEL_RDMA(qemu_file_get_ioc(f)); RDMAContext *rdma; @@ -3278,18 +3277,6 @@ static size_t qemu_rdma_save_page(QEMUFile *f, goto err; } - /* - * We always return 1 bytes because the RDMA - * protocol is completely asynchronous. We do not yet know - * whether an identified chunk is zero or not because we're - * waiting for other pages to potentially be merged with - * the current chunk. So, we have to call qemu_update_position() - * later on when the actual write occurs. - */ - if (bytes_sent) { - *bytes_sent = 1; - } - /* * Drain the Completion Queue if possible, but do not block, * just poll. From ce43e84260a7d6250bf212aac958d73cfa1ca704 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Thu, 28 Sep 2023 09:53:55 +0200 Subject: [PATCH 0112/1077] Makefile: build plugins before running TCG tests MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add back test-plugins and, after making sure it is always defined, do so unconditionally. Reported-by: Alex Bennée Fixes: 2c13c574418 ("configure, meson: move --enable-plugins to meson", 2023-09-07) Reviewed-by: Alex Bennée Tested-by: Alex Bennée Signed-off-by: Paolo Bonzini --- tests/Makefile.include | 2 +- tests/meson.build | 5 +---- tests/plugin/meson.build | 18 ++++++++++++------ 3 files changed, 14 insertions(+), 11 deletions(-) diff --git a/tests/Makefile.include b/tests/Makefile.include index 3898742659..dab1989a07 100644 --- a/tests/Makefile.include +++ b/tests/Makefile.include @@ -73,7 +73,7 @@ $(TCG_TESTS_TARGETS:%=distclean-tcg-tests-%): distclean-tcg-tests-%: build-tcg: $(BUILD_TCG_TARGET_RULES) .PHONY: check-tcg -.ninja-goals.check-tcg = all +.ninja-goals.check-tcg = all test-plugins check-tcg: $(RUN_TCG_TARGET_RULES) .PHONY: clean-tcg diff --git a/tests/meson.build b/tests/meson.build index debaa4505e..9996a293fb 100644 --- a/tests/meson.build +++ b/tests/meson.build @@ -80,10 +80,7 @@ if 'CONFIG_TCG' in config_all subdir('fp') endif -if get_option('plugins') - subdir('plugin') -endif - +subdir('plugin') subdir('unit') subdir('qapi-schema') subdir('qtest') diff --git a/tests/plugin/meson.build b/tests/plugin/meson.build index 2bbfc4b19e..322cafcdf6 100644 --- a/tests/plugin/meson.build +++ b/tests/plugin/meson.build @@ -1,7 +1,13 @@ t = [] -foreach i : ['bb', 'empty', 'insn', 'mem', 'syscall'] - t += shared_module(i, files(i + '.c'), - include_directories: '../../include/qemu', - dependencies: glib) -endforeach -alias_target('test-plugins', t) +if get_option('plugins') + foreach i : ['bb', 'empty', 'insn', 'mem', 'syscall'] + t += shared_module(i, files(i + '.c'), + include_directories: '../../include/qemu', + dependencies: glib) + endforeach +endif +if t.length() > 0 + alias_target('test-plugins', t) +else + run_target('test-plugins', command: find_program('true')) +endif From b86dc5cb0b4105fa8ad29e822ab5d21c589c5ec5 Mon Sep 17 00:00:00 2001 From: Mark Cave-Ayland Date: Wed, 13 Sep 2023 21:44:08 +0100 Subject: [PATCH 0113/1077] esp: use correct type for esp_dma_enable() in sysbus_esp_gpio_demux() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The call to esp_dma_enable() was being made with the SYSBUS_ESP type instead of the ESP type. This meant that when GPIO 1 was being used to trigger a DMA request from an external DMA controller, the setting of ESPState's dma_enabled field would clobber unknown memory whilst the dma_cb callback pointer would typically return NULL so the DMA request would never start. Signed-off-by: Mark Cave-Ayland Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Thomas Huth Message-ID: <20230913204410.65650-2-mark.cave-ayland@ilande.co.uk> Signed-off-by: Paolo Bonzini --- hw/scsi/esp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/scsi/esp.c b/hw/scsi/esp.c index e52188d022..4218a6a960 100644 --- a/hw/scsi/esp.c +++ b/hw/scsi/esp.c @@ -1395,7 +1395,7 @@ static void sysbus_esp_gpio_demux(void *opaque, int irq, int level) parent_esp_reset(s, irq, level); break; case 1: - esp_dma_enable(opaque, irq, level); + esp_dma_enable(s, irq, level); break; } } From 77668e4b9bca03a856c27ba899a2513ddf52bb52 Mon Sep 17 00:00:00 2001 From: Mark Cave-Ayland Date: Wed, 13 Sep 2023 21:44:09 +0100 Subject: [PATCH 0114/1077] esp: restrict non-DMA transfer length to that of available data In the case where a SCSI layer transfer is incorrectly terminated, it is possible for a TI command to cause a SCSI buffer overflow due to the expected transfer data length being less than the available data in the FIFO. When this occurs the unsigned async_len variable underflows and becomes a large offset which writes past the end of the allocated SCSI buffer. Restrict the non-DMA transfer length to be the smallest of the expected transfer length and the available FIFO data to ensure that it is no longer possible for the SCSI buffer overflow to occur. Signed-off-by: Mark Cave-Ayland Resolves: https://gitlab.com/qemu-project/qemu/-/issues/1810 Reviewed-by: Thomas Huth Message-ID: <20230913204410.65650-3-mark.cave-ayland@ilande.co.uk> Signed-off-by: Paolo Bonzini --- hw/scsi/esp.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/hw/scsi/esp.c b/hw/scsi/esp.c index 4218a6a960..9b11d8c573 100644 --- a/hw/scsi/esp.c +++ b/hw/scsi/esp.c @@ -759,7 +759,8 @@ static void esp_do_nodma(ESPState *s) } if (to_device) { - len = MIN(fifo8_num_used(&s->fifo), ESP_FIFO_SZ); + len = MIN(s->async_len, ESP_FIFO_SZ); + len = MIN(len, fifo8_num_used(&s->fifo)); esp_fifo_pop_buf(&s->fifo, s->async_buf, len); s->async_buf += len; s->async_len -= len; From be2b619a17345d007bcf9987a3e4afd1edea3e4f Mon Sep 17 00:00:00 2001 From: Mark Cave-Ayland Date: Wed, 13 Sep 2023 21:44:10 +0100 Subject: [PATCH 0115/1077] scsi-disk: ensure that FORMAT UNIT commands are terminated Otherwise when a FORMAT UNIT command is issued, the SCSI layer can become confused because it can find itself in the situation where it thinks there is still data to be transferred which can cause the next emulated SCSI command to fail. Signed-off-by: Mark Cave-Ayland Fixes: 6ab71761 ("scsi-disk: add FORMAT UNIT command") Tested-by: Thomas Huth Message-ID: <20230913204410.65650-4-mark.cave-ayland@ilande.co.uk> Signed-off-by: Paolo Bonzini --- hw/scsi/scsi-disk.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/hw/scsi/scsi-disk.c b/hw/scsi/scsi-disk.c index 477ee2bcd4..6691f5edb8 100644 --- a/hw/scsi/scsi-disk.c +++ b/hw/scsi/scsi-disk.c @@ -1959,6 +1959,10 @@ static void scsi_disk_emulate_write_data(SCSIRequest *req) scsi_disk_emulate_write_same(r, r->iov.iov_base); break; + case FORMAT_UNIT: + scsi_req_complete(&r->req, GOOD); + break; + default: abort(); } From 0c1a5299ab1d04ade6e6ff0fa2bc98e33cecaa80 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Thu, 28 Sep 2023 09:49:15 +0200 Subject: [PATCH 0116/1077] crypto: only include tls-cipher-suites in emulators MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit tls-cipher-suites is an object that is used to inject TLS configuration into the guest (via fw_cfg). It is never used for host-side TLS operation, and therefore it need not be available in the tools. Reviewed-by: Daniel P. Berrangé Signed-off-by: Paolo Bonzini --- crypto/meson.build | 3 ++- hw/nvram/meson.build | 6 +----- 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/crypto/meson.build b/crypto/meson.build index 9ac1a89802..c46f9c22a7 100644 --- a/crypto/meson.build +++ b/crypto/meson.build @@ -46,7 +46,8 @@ endif if have_afalg crypto_ss.add(if_true: files('afalg.c', 'cipher-afalg.c', 'hash-afalg.c')) endif -crypto_ss.add(when: gnutls, if_true: files('tls-cipher-suites.c')) + +system_ss.add(when: gnutls, if_true: files('tls-cipher-suites.c')) util_ss.add(files( 'aes.c', diff --git a/hw/nvram/meson.build b/hw/nvram/meson.build index 988dff6f8e..75e415b1a0 100644 --- a/hw/nvram/meson.build +++ b/hw/nvram/meson.build @@ -1,8 +1,4 @@ -if have_system or have_tools - # QOM interfaces must be available anytime QOM is used. - qom_ss.add(files('fw_cfg-interface.c')) -endif - +system_ss.add(files('fw_cfg-interface.c')) system_ss.add(files('fw_cfg.c')) system_ss.add(when: 'CONFIG_CHRP_NVRAM', if_true: files('chrp_nvram.c')) system_ss.add(when: 'CONFIG_DS1225Y', if_true: files('ds1225y.c')) From 9e58d7a7561ace2e4ed62049f9d0ff488e1bb7f1 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Mon, 25 Sep 2023 13:08:27 +0200 Subject: [PATCH 0117/1077] ui/vnc: Require audiodev= to enable audio MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit If there is no audiodev do not send the audio ack in response to VNC_ENCODING_AUDIO, so that clients aren't told audio exists, and immediately drop the client if they try to send any audio control messages when audio is not advertised. Reviewed-by: Daniel P. Berrangé Signed-off-by: Paolo Bonzini --- docs/about/deprecated.rst | 8 +++----- docs/about/removed-features.rst | 6 ++++++ ui/vnc.c | 11 ++++++++++- ui/vnc.h | 2 ++ 4 files changed, 21 insertions(+), 6 deletions(-) diff --git a/docs/about/deprecated.rst b/docs/about/deprecated.rst index 8f3fef97bd..c07bf58dde 100644 --- a/docs/about/deprecated.rst +++ b/docs/about/deprecated.rst @@ -45,13 +45,11 @@ backend settings instead of environment variables. To ease migration to the new format, the ``-audiodev-help`` option can be used to convert the current values of the environment variables to ``-audiodev`` options. -Creating sound card devices and vnc without ``audiodev=`` property (since 4.2) -'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' +Creating sound card devices without ``audiodev=`` property (since 4.2) +'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' When not using the deprecated legacy audio config, each sound card -should specify an ``audiodev=`` property. Additionally, when using -vnc, you should specify an ``audiodev=`` property if you plan to -transmit audio through the VNC protocol. +should specify an ``audiodev=`` property. Short-form boolean options (since 6.0) '''''''''''''''''''''''''''''''''''''' diff --git a/docs/about/removed-features.rst b/docs/about/removed-features.rst index 97ec47f1d2..276060b320 100644 --- a/docs/about/removed-features.rst +++ b/docs/about/removed-features.rst @@ -436,6 +436,12 @@ the process listing. This was replaced by the new ``password-secret`` option which lets the password be securely provided on the command line using a ``secret`` object instance. +Creating vnc without ``audiodev=`` property (removed in 8.2) +'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' + +When using vnc, you should specify an ``audiodev=`` property if +you plan to transmit audio through the VNC protocol. + QEMU Machine Protocol (QMP) commands ------------------------------------ diff --git a/ui/vnc.c b/ui/vnc.c index c302bb07a5..acb56461b2 100644 --- a/ui/vnc.c +++ b/ui/vnc.c @@ -2195,7 +2195,10 @@ static void set_encodings(VncState *vs, int32_t *encodings, size_t n_encodings) send_ext_key_event_ack(vs); break; case VNC_ENCODING_AUDIO: - send_ext_audio_ack(vs); + if (vs->vd->audio_state) { + vs->features |= VNC_FEATURE_AUDIO_MASK; + send_ext_audio_ack(vs); + } break; case VNC_ENCODING_WMVi: vs->features |= VNC_FEATURE_WMVI_MASK; @@ -2502,6 +2505,12 @@ static int protocol_client_msg(VncState *vs, uint8_t *data, size_t len) read_u32(data, 4), read_u32(data, 8)); break; case VNC_MSG_CLIENT_QEMU_AUDIO: + if (!vnc_has_feature(vs, VNC_FEATURE_AUDIO)) { + error_report("Audio message %d with audio disabled", read_u8(data, 2)); + vnc_client_error(vs); + break; + } + if (len == 2) return 4; diff --git a/ui/vnc.h b/ui/vnc.h index 757fa83044..96d19dce19 100644 --- a/ui/vnc.h +++ b/ui/vnc.h @@ -464,6 +464,7 @@ enum VncFeatures { VNC_FEATURE_LED_STATE, VNC_FEATURE_XVP, VNC_FEATURE_CLIPBOARD_EXT, + VNC_FEATURE_AUDIO, }; #define VNC_FEATURE_RESIZE_MASK (1 << VNC_FEATURE_RESIZE) @@ -481,6 +482,7 @@ enum VncFeatures { #define VNC_FEATURE_LED_STATE_MASK (1 << VNC_FEATURE_LED_STATE) #define VNC_FEATURE_XVP_MASK (1 << VNC_FEATURE_XVP) #define VNC_FEATURE_CLIPBOARD_EXT_MASK (1 << VNC_FEATURE_CLIPBOARD_EXT) +#define VNC_FEATURE_AUDIO_MASK (1 << VNC_FEATURE_AUDIO) /* Client -> Server message IDs */ From aaa6a6f93dc88f9201b9872fa64a565d52628208 Mon Sep 17 00:00:00 2001 From: Martin Kletzander Date: Mon, 25 Apr 2022 10:21:57 +0200 Subject: [PATCH 0118/1077] audio: Require AudioState in AUD_add_capture Since all callers require a valid audiodev this function can now safely abort in case of missing AudioState. Signed-off-by: Martin Kletzander Message-ID: Signed-off-by: Paolo Bonzini --- audio/audio.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/audio/audio.c b/audio/audio.c index 2f47965711..d4387cb3e2 100644 --- a/audio/audio.c +++ b/audio/audio.c @@ -1876,10 +1876,8 @@ CaptureVoiceOut *AUD_add_capture( struct capture_callback *cb; if (!s) { - if (!legacy_config) { - dolog("Capturing without setting an audiodev is deprecated\n"); - } - s = audio_init(NULL, NULL); + error_report("Capturing without setting an audiodev is not supported"); + abort(); } if (!audio_get_pdo_out(s->dev)->mixing_engine) { From f6061733a96314ccb732efe6c91357d66f8970af Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Fri, 22 Sep 2023 19:13:44 +0200 Subject: [PATCH 0119/1077] audio: allow returning an error from the driver init MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit An error is already printed by audio_driver_init, but we can make it more precise if the driver can return an Error *. Reviewed-by: Daniel P. Berrangé Signed-off-by: Paolo Bonzini --- audio/alsaaudio.c | 2 +- audio/audio.c | 13 ++++++++++--- audio/audio_int.h | 2 +- audio/coreaudio.m | 2 +- audio/dbusaudio.c | 2 +- audio/dsoundaudio.c | 2 +- audio/jackaudio.c | 2 +- audio/noaudio.c | 2 +- audio/ossaudio.c | 11 ++++++++--- audio/paaudio.c | 7 +++++-- audio/pwaudio.c | 16 +++++++++------- audio/sdlaudio.c | 5 +++-- audio/sndioaudio.c | 2 +- audio/spiceaudio.c | 5 ++++- audio/wavaudio.c | 2 +- 15 files changed, 48 insertions(+), 27 deletions(-) diff --git a/audio/alsaaudio.c b/audio/alsaaudio.c index 057571dd1e..6fb78e5b97 100644 --- a/audio/alsaaudio.c +++ b/audio/alsaaudio.c @@ -904,7 +904,7 @@ static void alsa_init_per_direction(AudiodevAlsaPerDirectionOptions *apdo) } } -static void *alsa_audio_init(Audiodev *dev) +static void *alsa_audio_init(Audiodev *dev, Error **errp) { AudiodevAlsaOptions *aopts; assert(dev->driver == AUDIODEV_DRIVER_ALSA); diff --git a/audio/audio.c b/audio/audio.c index d4387cb3e2..fdc34a7752 100644 --- a/audio/audio.c +++ b/audio/audio.c @@ -33,6 +33,7 @@ #include "qapi/qapi-visit-audio.h" #include "qapi/qapi-commands-audio.h" #include "qemu/cutils.h" +#include "qemu/error-report.h" #include "qemu/log.h" #include "qemu/module.h" #include "qemu/help_option.h" @@ -1555,7 +1556,9 @@ size_t audio_generic_read(HWVoiceIn *hw, void *buf, size_t size) static int audio_driver_init(AudioState *s, struct audio_driver *drv, bool msg, Audiodev *dev) { - s->drv_opaque = drv->init(dev); + Error *local_err = NULL; + + s->drv_opaque = drv->init(dev, &local_err); if (s->drv_opaque) { if (!drv->pcm_ops->get_buffer_in) { @@ -1572,8 +1575,12 @@ static int audio_driver_init(AudioState *s, struct audio_driver *drv, s->drv = drv; return 0; } else { - if (msg) { - dolog("Could not init `%s' audio driver\n", drv->name); + if (!msg) { + error_free(local_err); + } else if (local_err) { + error_report_err(local_err); + } else { + error_report("Could not init `%s' audio driver", drv->name); } return -1; } diff --git a/audio/audio_int.h b/audio/audio_int.h index e57ff50155..06e815de9f 100644 --- a/audio/audio_int.h +++ b/audio/audio_int.h @@ -140,7 +140,7 @@ typedef struct audio_driver audio_driver; struct audio_driver { const char *name; const char *descr; - void *(*init) (Audiodev *); + void *(*init) (Audiodev *, Error **); void (*fini) (void *); #ifdef CONFIG_GIO void (*set_dbus_server) (AudioState *s, GDBusObjectManagerServer *manager, bool p2p); diff --git a/audio/coreaudio.m b/audio/coreaudio.m index 4695291621..7cfb38fb6a 100644 --- a/audio/coreaudio.m +++ b/audio/coreaudio.m @@ -644,7 +644,7 @@ static void coreaudio_enable_out(HWVoiceOut *hw, bool enable) update_device_playback_state(core); } -static void *coreaudio_audio_init(Audiodev *dev) +static void *coreaudio_audio_init(Audiodev *dev, Error **errp) { return dev; } diff --git a/audio/dbusaudio.c b/audio/dbusaudio.c index 7a11fbfb42..310ca997ff 100644 --- a/audio/dbusaudio.c +++ b/audio/dbusaudio.c @@ -395,7 +395,7 @@ dbus_enable_in(HWVoiceIn *hw, bool enable) } static void * -dbus_audio_init(Audiodev *dev) +dbus_audio_init(Audiodev *dev, Error **errp) { DBusAudio *da = g_new0(DBusAudio, 1); diff --git a/audio/dsoundaudio.c b/audio/dsoundaudio.c index 3fb67ec3ee..eefde88edc 100644 --- a/audio/dsoundaudio.c +++ b/audio/dsoundaudio.c @@ -619,7 +619,7 @@ static void dsound_audio_fini (void *opaque) g_free(s); } -static void *dsound_audio_init(Audiodev *dev) +static void *dsound_audio_init(Audiodev *dev, Error **errp) { int err; HRESULT hr; diff --git a/audio/jackaudio.c b/audio/jackaudio.c index e1eaa3477d..823e7d96ba 100644 --- a/audio/jackaudio.c +++ b/audio/jackaudio.c @@ -645,7 +645,7 @@ static int qjack_thread_creator(jack_native_thread_t *thread, } #endif -static void *qjack_init(Audiodev *dev) +static void *qjack_init(Audiodev *dev, Error **errp) { assert(dev->driver == AUDIODEV_DRIVER_JACK); return dev; diff --git a/audio/noaudio.c b/audio/noaudio.c index 4fdee5adec..a36bfeffd1 100644 --- a/audio/noaudio.c +++ b/audio/noaudio.c @@ -104,7 +104,7 @@ static void no_enable_in(HWVoiceIn *hw, bool enable) } } -static void *no_audio_init(Audiodev *dev) +static void *no_audio_init(Audiodev *dev, Error **errp) { return &no_audio_init; } diff --git a/audio/ossaudio.c b/audio/ossaudio.c index e8d732b612..ec4448d573 100644 --- a/audio/ossaudio.c +++ b/audio/ossaudio.c @@ -28,6 +28,7 @@ #include "qemu/main-loop.h" #include "qemu/module.h" #include "qemu/host-utils.h" +#include "qapi/error.h" #include "audio.h" #include "trace.h" @@ -736,7 +737,7 @@ static void oss_init_per_direction(AudiodevOssPerDirectionOptions *opdo) } } -static void *oss_audio_init(Audiodev *dev) +static void *oss_audio_init(Audiodev *dev, Error **errp) { AudiodevOssOptions *oopts; assert(dev->driver == AUDIODEV_DRIVER_OSS); @@ -745,8 +746,12 @@ static void *oss_audio_init(Audiodev *dev) oss_init_per_direction(oopts->in); oss_init_per_direction(oopts->out); - if (access(oopts->in->dev ?: "/dev/dsp", R_OK | W_OK) < 0 || - access(oopts->out->dev ?: "/dev/dsp", R_OK | W_OK) < 0) { + if (access(oopts->in->dev ?: "/dev/dsp", R_OK | W_OK) < 0) { + error_setg_errno(errp, errno, "%s not accessible", oopts->in->dev ?: "/dev/dsp"); + return NULL; + } + if (access(oopts->out->dev ?: "/dev/dsp", R_OK | W_OK) < 0) { + error_setg_errno(errp, errno, "%s not accessible", oopts->out->dev ?: "/dev/dsp"); return NULL; } return dev; diff --git a/audio/paaudio.c b/audio/paaudio.c index 529b39daac..39bd6cfa38 100644 --- a/audio/paaudio.c +++ b/audio/paaudio.c @@ -3,7 +3,7 @@ #include "qemu/osdep.h" #include "qemu/module.h" #include "audio.h" -#include "qapi/opts-visitor.h" +#include "qapi/error.h" #include @@ -818,7 +818,7 @@ fail: return NULL; } -static void *qpa_audio_init(Audiodev *dev) +static void *qpa_audio_init(Audiodev *dev, Error **errp) { paaudio *g; AudiodevPaOptions *popts = &dev->u.pa; @@ -834,10 +834,12 @@ static void *qpa_audio_init(Audiodev *dev) runtime = getenv("XDG_RUNTIME_DIR"); if (!runtime) { + error_setg(errp, "XDG_RUNTIME_DIR not set"); return NULL; } snprintf(pidfile, sizeof(pidfile), "%s/pulse/pid", runtime); if (stat(pidfile, &st) != 0) { + error_setg_errno(errp, errno, "could not stat pidfile %s", pidfile); return NULL; } } @@ -867,6 +869,7 @@ static void *qpa_audio_init(Audiodev *dev) } if (!g->conn) { g_free(g); + error_setg(errp, "could not connect to PulseAudio server"); return NULL; } diff --git a/audio/pwaudio.c b/audio/pwaudio.c index b6a38738ee..1020cb11df 100644 --- a/audio/pwaudio.c +++ b/audio/pwaudio.c @@ -13,6 +13,7 @@ #include "audio.h" #include #include "qemu/error-report.h" +#include "qapi/error.h" #include #include #include @@ -736,7 +737,7 @@ static const struct pw_core_events core_events = { }; static void * -qpw_audio_init(Audiodev *dev) +qpw_audio_init(Audiodev *dev, Error **errp) { g_autofree pwaudio *pw = g_new0(pwaudio, 1); @@ -748,19 +749,19 @@ qpw_audio_init(Audiodev *dev) pw->dev = dev; pw->thread_loop = pw_thread_loop_new("PipeWire thread loop", NULL); if (pw->thread_loop == NULL) { - error_report("Could not create PipeWire loop: %s", g_strerror(errno)); + error_setg_errno(errp, errno, "Could not create PipeWire loop"); goto fail; } pw->context = pw_context_new(pw_thread_loop_get_loop(pw->thread_loop), NULL, 0); if (pw->context == NULL) { - error_report("Could not create PipeWire context: %s", g_strerror(errno)); + error_setg_errno(errp, errno, "Could not create PipeWire context"); goto fail; } if (pw_thread_loop_start(pw->thread_loop) < 0) { - error_report("Could not start PipeWire loop: %s", g_strerror(errno)); + error_setg_errno(errp, errno, "Could not start PipeWire loop"); goto fail; } @@ -769,13 +770,13 @@ qpw_audio_init(Audiodev *dev) pw->core = pw_context_connect(pw->context, NULL, 0); if (pw->core == NULL) { pw_thread_loop_unlock(pw->thread_loop); - goto fail; + goto fail_error; } if (pw_core_add_listener(pw->core, &pw->core_listener, &core_events, pw) < 0) { pw_thread_loop_unlock(pw->thread_loop); - goto fail; + goto fail_error; } if (wait_resync(pw) < 0) { pw_thread_loop_unlock(pw->thread_loop); @@ -785,8 +786,9 @@ qpw_audio_init(Audiodev *dev) return g_steal_pointer(&pw); +fail_error: + error_setg(errp, "Failed to initialize PW context"); fail: - AUD_log(AUDIO_CAP, "Failed to initialize PW context"); if (pw->thread_loop) { pw_thread_loop_stop(pw->thread_loop); } diff --git a/audio/sdlaudio.c b/audio/sdlaudio.c index 68a237b76b..4d8473d9ec 100644 --- a/audio/sdlaudio.c +++ b/audio/sdlaudio.c @@ -26,6 +26,7 @@ #include #include #include "qemu/module.h" +#include "qapi/error.h" #include "audio.h" #ifndef _WIN32 @@ -449,10 +450,10 @@ static void sdl_enable_in(HWVoiceIn *hw, bool enable) SDL_PauseAudioDevice(sdl->devid, !enable); } -static void *sdl_audio_init(Audiodev *dev) +static void *sdl_audio_init(Audiodev *dev, Error **errp) { if (SDL_InitSubSystem (SDL_INIT_AUDIO)) { - sdl_logerr ("SDL failed to initialize audio subsystem\n"); + error_setg(errp, "SDL failed to initialize audio subsystem"); return NULL; } diff --git a/audio/sndioaudio.c b/audio/sndioaudio.c index 3fde01fdbd..1e35925a49 100644 --- a/audio/sndioaudio.c +++ b/audio/sndioaudio.c @@ -518,7 +518,7 @@ static void sndio_fini_in(HWVoiceIn *hw) sndio_fini(self); } -static void *sndio_audio_init(Audiodev *dev) +static void *sndio_audio_init(Audiodev *dev, Error **errp) { assert(dev->driver == AUDIODEV_DRIVER_SNDIO); return dev; diff --git a/audio/spiceaudio.c b/audio/spiceaudio.c index d17ef1a25e..7f02f7285c 100644 --- a/audio/spiceaudio.c +++ b/audio/spiceaudio.c @@ -22,6 +22,7 @@ #include "qemu/module.h" #include "qemu/error-report.h" #include "qemu/timer.h" +#include "qapi/error.h" #include "ui/qemu-spice.h" #define AUDIO_CAP "spice" @@ -71,11 +72,13 @@ static const SpiceRecordInterface record_sif = { .base.minor_version = SPICE_INTERFACE_RECORD_MINOR, }; -static void *spice_audio_init(Audiodev *dev) +static void *spice_audio_init(Audiodev *dev, Error **errp) { if (!using_spice) { + error_setg(errp, "Cannot use spice audio without -spice"); return NULL; } + return &spice_audio_init; } diff --git a/audio/wavaudio.c b/audio/wavaudio.c index 6445a2cb90..26b03906d5 100644 --- a/audio/wavaudio.c +++ b/audio/wavaudio.c @@ -182,7 +182,7 @@ static void wav_enable_out(HWVoiceOut *hw, bool enable) } } -static void *wav_audio_init(Audiodev *dev) +static void *wav_audio_init(Audiodev *dev, Error **errp) { assert(dev->driver == AUDIODEV_DRIVER_WAV); return dev; From 176adafca72ecc35e7f1f011deb52ca1ae091df6 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Fri, 22 Sep 2023 17:29:19 +0200 Subject: [PATCH 0120/1077] audio: return Error ** from audio_state_by_name Remove duplicate error formatting code. Signed-off-by: Paolo Bonzini --- audio/audio-hmp-cmds.c | 6 ++++-- audio/audio.c | 3 ++- audio/audio.h | 2 +- hw/core/qdev-properties-system.c | 16 ++++------------ ui/dbus.c | 3 +-- ui/vnc.c | 3 +-- 6 files changed, 13 insertions(+), 20 deletions(-) diff --git a/audio/audio-hmp-cmds.c b/audio/audio-hmp-cmds.c index 1237ce9e75..c9608b715b 100644 --- a/audio/audio-hmp-cmds.c +++ b/audio/audio-hmp-cmds.c @@ -26,6 +26,7 @@ #include "audio/audio.h" #include "monitor/hmp.h" #include "monitor/monitor.h" +#include "qapi/error.h" #include "qapi/qmp/qdict.h" static QLIST_HEAD (capture_list_head, CaptureState) capture_head; @@ -65,10 +66,11 @@ void hmp_wavcapture(Monitor *mon, const QDict *qdict) int nchannels = qdict_get_try_int(qdict, "nchannels", 2); const char *audiodev = qdict_get_str(qdict, "audiodev"); CaptureState *s; - AudioState *as = audio_state_by_name(audiodev); + Error *local_err = NULL; + AudioState *as = audio_state_by_name(audiodev, &local_err); if (!as) { - monitor_printf(mon, "Audiodev '%s' not found\n", audiodev); + error_report_err(local_err); return; } diff --git a/audio/audio.c b/audio/audio.c index fdc34a7752..874a4c3c41 100644 --- a/audio/audio.c +++ b/audio/audio.c @@ -2260,7 +2260,7 @@ int audio_buffer_bytes(AudiodevPerDirectionOptions *pdo, audioformat_bytes_per_sample(as->fmt); } -AudioState *audio_state_by_name(const char *name) +AudioState *audio_state_by_name(const char *name, Error **errp) { AudioState *s; QTAILQ_FOREACH(s, &audio_states, list) { @@ -2269,6 +2269,7 @@ AudioState *audio_state_by_name(const char *name) return s; } } + error_setg(errp, "audiodev '%s' not found", name); return NULL; } diff --git a/audio/audio.h b/audio/audio.h index 01bdc567fb..e0c13b5dcd 100644 --- a/audio/audio.h +++ b/audio/audio.h @@ -174,7 +174,7 @@ bool audio_init_audiodevs(void); void audio_help(void); void audio_legacy_help(void); -AudioState *audio_state_by_name(const char *name); +AudioState *audio_state_by_name(const char *name, Error **errp); const char *audio_get_id(QEMUSoundCard *card); #define DEFINE_AUDIO_PROPERTIES(_s, _f) \ diff --git a/hw/core/qdev-properties-system.c b/hw/core/qdev-properties-system.c index 41b7e682c7..688340610e 100644 --- a/hw/core/qdev-properties-system.c +++ b/hw/core/qdev-properties-system.c @@ -480,24 +480,16 @@ static void set_audiodev(Object *obj, Visitor *v, const char* name, Property *prop = opaque; QEMUSoundCard *card = object_field_prop_ptr(obj, prop); AudioState *state; - int err = 0; - char *str; + g_autofree char *str = NULL; if (!visit_type_str(v, name, &str, errp)) { return; } - state = audio_state_by_name(str); - - if (!state) { - err = -ENOENT; - goto out; + state = audio_state_by_name(str, errp); + if (state) { + card->state = state; } - card->state = state; - -out: - error_set_from_qdev_prop_error(errp, err, obj, name, str); - g_free(str); } const PropertyInfo qdev_prop_audiodev = { diff --git a/ui/dbus.c b/ui/dbus.c index 32f1bbe81a..866467ad2e 100644 --- a/ui/dbus.c +++ b/ui/dbus.c @@ -220,9 +220,8 @@ dbus_display_complete(UserCreatable *uc, Error **errp) } if (dd->audiodev && *dd->audiodev) { - AudioState *audio_state = audio_state_by_name(dd->audiodev); + AudioState *audio_state = audio_state_by_name(dd->audiodev, errp); if (!audio_state) { - error_setg(errp, "Audiodev '%s' not found", dd->audiodev); return; } if (!g_str_equal(audio_state->drv->name, "dbus")) { diff --git a/ui/vnc.c b/ui/vnc.c index acb56461b2..8292946913 100644 --- a/ui/vnc.c +++ b/ui/vnc.c @@ -4181,9 +4181,8 @@ void vnc_display_open(const char *id, Error **errp) audiodev = qemu_opt_get(opts, "audiodev"); if (audiodev) { - vd->audio_state = audio_state_by_name(audiodev); + vd->audio_state = audio_state_by_name(audiodev, errp); if (!vd->audio_state) { - error_setg(errp, "Audiodev '%s' not found", audiodev); goto fail; } } From 5c63d141dc8768c7418893beef8f151a13883e65 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Fri, 22 Sep 2023 18:36:28 +0200 Subject: [PATCH 0121/1077] audio: commonize voice initialization Move some mostly irrelevant code out of audio_init. Signed-off-by: Paolo Bonzini --- audio/audio.c | 19 ++----------------- audio/audio_template.h | 9 ++++++++- 2 files changed, 10 insertions(+), 18 deletions(-) diff --git a/audio/audio.c b/audio/audio.c index 874a4c3c41..bb1734a95d 100644 --- a/audio/audio.c +++ b/audio/audio.c @@ -1570,8 +1570,8 @@ static int audio_driver_init(AudioState *s, struct audio_driver *drv, drv->pcm_ops->put_buffer_out = audio_generic_put_buffer_out; } - audio_init_nb_voices_out(s, drv); - audio_init_nb_voices_in(s, drv); + audio_init_nb_voices_out(s, drv, 1); + audio_init_nb_voices_in(s, drv, 0); s->drv = drv; return 0; } else { @@ -1774,21 +1774,6 @@ static AudioState *audio_init(Audiodev *dev, const char *name) s->ts = timer_new_ns(QEMU_CLOCK_VIRTUAL, audio_timer, s); - s->nb_hw_voices_out = audio_get_pdo_out(dev)->voices; - s->nb_hw_voices_in = audio_get_pdo_in(dev)->voices; - - if (s->nb_hw_voices_out < 1) { - dolog ("Bogus number of playback voices %d, setting to 1\n", - s->nb_hw_voices_out); - s->nb_hw_voices_out = 1; - } - - if (s->nb_hw_voices_in < 0) { - dolog ("Bogus number of capture voices %d, setting to 0\n", - s->nb_hw_voices_in); - s->nb_hw_voices_in = 0; - } - if (drvname) { driver = audio_driver_lookup(drvname); if (driver) { diff --git a/audio/audio_template.h b/audio/audio_template.h index dc0c74aa74..7ccfec0116 100644 --- a/audio/audio_template.h +++ b/audio/audio_template.h @@ -37,11 +37,12 @@ #endif static void glue(audio_init_nb_voices_, TYPE)(AudioState *s, - struct audio_driver *drv) + struct audio_driver *drv, int min_voices) { int max_voices = glue (drv->max_voices_, TYPE); size_t voice_size = glue(drv->voice_size_, TYPE); + glue (s->nb_hw_voices_, TYPE) = glue(audio_get_pdo_, TYPE)(s->dev)->voices; if (glue (s->nb_hw_voices_, TYPE) > max_voices) { if (!max_voices) { #ifdef DAC @@ -56,6 +57,12 @@ static void glue(audio_init_nb_voices_, TYPE)(AudioState *s, glue (s->nb_hw_voices_, TYPE) = max_voices; } + if (glue (s->nb_hw_voices_, TYPE) < min_voices) { + dolog ("Bogus number of " NAME " voices %d, setting to %d\n", + glue (s->nb_hw_voices_, TYPE), + min_voices); + } + if (audio_bug(__func__, !voice_size && max_voices)) { dolog ("drv=`%s' voice_size=0 max_voices=%d\n", drv->name, max_voices); From e3299631720732ceb02cf3f10b175c5e6ffcad39 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Fri, 22 Sep 2023 17:46:28 +0200 Subject: [PATCH 0122/1077] audio: simplify flow in audio_init Merge two ifs into one. Signed-off-by: Paolo Bonzini --- audio/audio.c | 76 +++++++++++++++++++++++++-------------------------- 1 file changed, 38 insertions(+), 38 deletions(-) diff --git a/audio/audio.c b/audio/audio.c index bb1734a95d..2e22664daf 100644 --- a/audio/audio.c +++ b/audio/audio.c @@ -1707,12 +1707,12 @@ static AudiodevListEntry *audiodev_find( * if dev == NULL => legacy implicit initialization, return the already created * state or create a new one */ -static AudioState *audio_init(Audiodev *dev, const char *name) +static AudioState *audio_init(Audiodev *dev) { static bool atexit_registered; size_t i; int done = 0; - const char *drvname = NULL; + const char *drvname; VMChangeStateEntry *vmse; AudioState *s; struct audio_driver *driver; @@ -1736,17 +1736,32 @@ static AudioState *audio_init(Audiodev *dev, const char *name) } } + s = g_new0(AudioState, 1); + + QLIST_INIT (&s->hw_head_out); + QLIST_INIT (&s->hw_head_in); + QLIST_INIT (&s->cap_head); + if (!atexit_registered) { + atexit(audio_cleanup); + atexit_registered = true; + } + + s->ts = timer_new_ns(QEMU_CLOCK_VIRTUAL, audio_timer, s); + if (dev) { /* -audiodev option */ - legacy_config = false; + s->dev = dev; drvname = AudiodevDriver_str(dev->driver); - } else if (!QTAILQ_EMPTY(&audio_states)) { - if (!legacy_config) { - dolog("Device %s: audiodev default parameter is deprecated, please " - "specify audiodev=%s\n", name, - QTAILQ_FIRST(&audio_states)->dev->id); + driver = audio_driver_lookup(drvname); + if (driver) { + done = !audio_driver_init(s, driver, true, dev); + } else { + dolog ("Unknown audio driver `%s'\n", drvname); + } + if (!done) { + free_audio_state(s); + return NULL; } - return QTAILQ_FIRST(&audio_states); } else { /* legacy implicit initialization */ head = audio_handle_legacy_opts(); @@ -1759,33 +1774,7 @@ static AudioState *audio_init(Audiodev *dev, const char *name) */ dev = QSIMPLEQ_FIRST(&head)->dev; audio_validate_opts(dev, &error_abort); - } - s = g_new0(AudioState, 1); - s->dev = dev; - - QLIST_INIT (&s->hw_head_out); - QLIST_INIT (&s->hw_head_in); - QLIST_INIT (&s->cap_head); - if (!atexit_registered) { - atexit(audio_cleanup); - atexit_registered = true; - } - - s->ts = timer_new_ns(QEMU_CLOCK_VIRTUAL, audio_timer, s); - - if (drvname) { - driver = audio_driver_lookup(drvname); - if (driver) { - done = !audio_driver_init(s, driver, true, dev); - } else { - dolog ("Unknown audio driver `%s'\n", drvname); - } - if (!done) { - free_audio_state(s); - return NULL; - } - } else { for (i = 0; audio_prio_list[i]; i++) { AudiodevListEntry *e = audiodev_find(&head, audio_prio_list[i]); driver = audio_driver_lookup(audio_prio_list[i]); @@ -1800,8 +1789,9 @@ static AudioState *audio_init(Audiodev *dev, const char *name) } } } + + audio_free_audiodev_list(&head); } - audio_free_audiodev_list(&head); if (!done) { driver = audio_driver_lookup("none"); @@ -1841,7 +1831,16 @@ void audio_free_audiodev_list(AudiodevListHead *head) void AUD_register_card (const char *name, QEMUSoundCard *card) { if (!card->state) { - card->state = audio_init(NULL, name); + if (!QTAILQ_EMPTY(&audio_states)) { + if (!legacy_config) { + dolog("Device %s: audiodev default parameter is deprecated, please " + "specify audiodev=%s\n", name, + QTAILQ_FIRST(&audio_states)->dev->id); + } + card->state = QTAILQ_FIRST(&audio_states); + } else { + card->state = audio_init(NULL); + } } card->name = g_strdup (name); @@ -2171,6 +2170,7 @@ void audio_define(Audiodev *dev) e = g_new0(AudiodevListEntry, 1); e->dev = dev; QSIMPLEQ_INSERT_TAIL(&audiodevs, e, next); + legacy_config = false; } bool audio_init_audiodevs(void) @@ -2178,7 +2178,7 @@ bool audio_init_audiodevs(void) AudiodevListEntry *e; QSIMPLEQ_FOREACH(e, &audiodevs, next) { - if (!audio_init(e->dev, NULL)) { + if (!audio_init(e->dev)) { return false; } } From 69a802792ab3705074585a75f5645297ae9f6794 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Tue, 5 Sep 2023 11:41:05 +0200 Subject: [PATCH 0123/1077] audio: remove QEMU_AUDIO_* and -audio-help support These have been deprecated for a long time, and the introduction of -audio in 7.1.0 has cemented the new way of specifying an audio backend's parameters. However, there is still a need for simple configuration of the audio backend in the desktop case; therefore, if no audiodev is passed to audio_init(), go through a bunch of simple Audiodev* structures and pick the first that can be initialized successfully. The only QEMU_AUDIO_* option that is left in, waiting for a better idea, is QEMU_AUDIO_DRV=none which is used by qtest. Remove all the parsing code, including the concept of "can_be_default" audio drivers: now that audio_prio_list[] is only used in a single place, wav can be excluded directly in that function. Signed-off-by: Paolo Bonzini --- audio/alsaaudio.c | 1 - audio/audio.c | 138 ++++---- audio/audio.h | 1 - audio/audio_int.h | 5 - audio/audio_legacy.c | 591 -------------------------------- audio/coreaudio.m | 1 - audio/dbusaudio.c | 1 - audio/dsoundaudio.c | 1 - audio/jackaudio.c | 1 - audio/meson.build | 1 - audio/noaudio.c | 1 - audio/ossaudio.c | 1 - audio/paaudio.c | 1 - audio/pwaudio.c | 1 - audio/sdlaudio.c | 1 - audio/sndioaudio.c | 1 - audio/wavaudio.c | 1 - docs/about/deprecated.rst | 8 - docs/about/removed-features.rst | 6 + qemu-options.hx | 10 - softmmu/vl.c | 4 - 21 files changed, 65 insertions(+), 711 deletions(-) delete mode 100644 audio/audio_legacy.c diff --git a/audio/alsaaudio.c b/audio/alsaaudio.c index 6fb78e5b97..cacae1ea59 100644 --- a/audio/alsaaudio.c +++ b/audio/alsaaudio.c @@ -960,7 +960,6 @@ static struct audio_driver alsa_audio_driver = { .init = alsa_audio_init, .fini = alsa_audio_fini, .pcm_ops = &alsa_pcm_ops, - .can_be_default = 1, .max_voices_out = INT_MAX, .max_voices_in = INT_MAX, .voice_size_out = sizeof (ALSAVoiceOut), diff --git a/audio/audio.c b/audio/audio.c index 2e22664daf..818d79e50f 100644 --- a/audio/audio.c +++ b/audio/audio.c @@ -32,6 +32,7 @@ #include "qapi/qobject-input-visitor.h" #include "qapi/qapi-visit-audio.h" #include "qapi/qapi-commands-audio.h" +#include "qapi/qmp/qdict.h" #include "qemu/cutils.h" #include "qemu/error-report.h" #include "qemu/log.h" @@ -62,19 +63,22 @@ const char *audio_prio_list[] = { "spice", CONFIG_AUDIO_DRIVERS "none", - "wav", NULL }; static QLIST_HEAD(, audio_driver) audio_drivers; -static AudiodevListHead audiodevs = QSIMPLEQ_HEAD_INITIALIZER(audiodevs); +static AudiodevListHead audiodevs = + QSIMPLEQ_HEAD_INITIALIZER(audiodevs); +static AudiodevListHead default_audiodevs = + QSIMPLEQ_HEAD_INITIALIZER(default_audiodevs); + void audio_driver_register(audio_driver *drv) { QLIST_INSERT_HEAD(&audio_drivers, drv, next); } -audio_driver *audio_driver_lookup(const char *name) +static audio_driver *audio_driver_lookup(const char *name) { struct audio_driver *d; Error *local_err = NULL; @@ -112,8 +116,6 @@ const struct mixeng_volume nominal_volume = { #endif }; -static bool legacy_config = true; - int audio_bug (const char *funcname, int cond) { if (cond) { @@ -1688,17 +1690,41 @@ static const VMStateDescription vmstate_audio = { static void audio_validate_opts(Audiodev *dev, Error **errp); -static AudiodevListEntry *audiodev_find( - AudiodevListHead *head, const char *drvname) +static void audio_create_default_audiodevs(void) { - AudiodevListEntry *e; - QSIMPLEQ_FOREACH(e, head, next) { - if (strcmp(AudiodevDriver_str(e->dev->driver), drvname) == 0) { - return e; - } + const char *drvname = getenv("QEMU_AUDIO_DRV"); + + /* QEMU_AUDIO_DRV=none is used by libqtest. */ + if (drvname && !g_str_equal(drvname, "none")) { + error_report("Please use -audiodev instead of QEMU_AUDIO_*"); + exit(1); } - return NULL; + for (int i = 0; audio_prio_list[i]; i++) { + if (drvname && !g_str_equal(drvname, audio_prio_list[i])) { + continue; + } + + if (audio_driver_lookup(audio_prio_list[i])) { + QDict *dict = qdict_new(); + Audiodev *dev = NULL; + AudiodevListEntry *e; + Visitor *v; + + qdict_put_str(dict, "driver", audio_prio_list[i]); + qdict_put_str(dict, "id", "#default"); + + v = qobject_input_visitor_new_keyval(QOBJECT(dict)); + qobject_unref(dict); + visit_type_Audiodev(v, NULL, &dev, &error_fatal); + visit_free(v); + + audio_validate_opts(dev, &error_abort); + e = g_new0(AudiodevListEntry, 1); + e->dev = dev; + QSIMPLEQ_INSERT_TAIL(&default_audiodevs, e, next); + } + } } /* @@ -1710,31 +1736,11 @@ static AudiodevListEntry *audiodev_find( static AudioState *audio_init(Audiodev *dev) { static bool atexit_registered; - size_t i; int done = 0; const char *drvname; VMChangeStateEntry *vmse; AudioState *s; struct audio_driver *driver; - /* silence gcc warning about uninitialized variable */ - AudiodevListHead head = QSIMPLEQ_HEAD_INITIALIZER(head); - - if (using_spice) { - /* - * When using spice allow the spice audio driver being picked - * as default. - * - * Temporary hack. Using audio devices without explicit - * audiodev= property is already deprecated. Same goes for - * the -soundhw switch. Once this support gets finally - * removed we can also drop the concept of a default audio - * backend and this can go away. - */ - driver = audio_driver_lookup("spice"); - if (driver) { - driver->can_be_default = 1; - } - } s = g_new0(AudioState, 1); @@ -1759,45 +1765,23 @@ static AudioState *audio_init(Audiodev *dev) dolog ("Unknown audio driver `%s'\n", drvname); } if (!done) { - free_audio_state(s); - return NULL; + goto out; } } else { - /* legacy implicit initialization */ - head = audio_handle_legacy_opts(); - /* - * In case of legacy initialization, all Audiodevs in the list will have - * the same configuration (except the driver), so it doesn't matter which - * one we chose. We need an Audiodev to set up AudioState before we can - * init a driver. Also note that dev at this point is still in the - * list. - */ - dev = QSIMPLEQ_FIRST(&head)->dev; - audio_validate_opts(dev, &error_abort); - - for (i = 0; audio_prio_list[i]; i++) { - AudiodevListEntry *e = audiodev_find(&head, audio_prio_list[i]); - driver = audio_driver_lookup(audio_prio_list[i]); - - if (e && driver) { - s->dev = dev = e->dev; - audio_validate_opts(dev, &error_abort); - done = !audio_driver_init(s, driver, false, dev); - if (done) { - e->dev = NULL; - break; - } + for (;;) { + AudiodevListEntry *e = QSIMPLEQ_FIRST(&default_audiodevs); + if (!e) { + dolog("no default audio driver available\n"); + goto out; } + s->dev = dev = e->dev; + drvname = AudiodevDriver_str(dev->driver); + driver = audio_driver_lookup(drvname); + if (!audio_driver_init(s, driver, false, dev)) { + break; + } + QSIMPLEQ_REMOVE_HEAD(&default_audiodevs, next); } - - audio_free_audiodev_list(&head); - } - - if (!done) { - driver = audio_driver_lookup("none"); - done = !audio_driver_init(s, driver, false, dev); - assert(done); - dolog("warning: Using timer based audio emulation\n"); } if (dev->timer_period <= 0) { @@ -1816,29 +1800,26 @@ static AudioState *audio_init(Audiodev *dev) QLIST_INIT (&s->card_head); vmstate_register (NULL, 0, &vmstate_audio, s); return s; -} -void audio_free_audiodev_list(AudiodevListHead *head) -{ - AudiodevListEntry *e; - while ((e = QSIMPLEQ_FIRST(head))) { - QSIMPLEQ_REMOVE_HEAD(head, next); - qapi_free_Audiodev(e->dev); - g_free(e); - } +out: + free_audio_state(s); + return NULL; } void AUD_register_card (const char *name, QEMUSoundCard *card) { if (!card->state) { if (!QTAILQ_EMPTY(&audio_states)) { - if (!legacy_config) { + if (QSIMPLEQ_EMPTY(&default_audiodevs)) { dolog("Device %s: audiodev default parameter is deprecated, please " "specify audiodev=%s\n", name, QTAILQ_FIRST(&audio_states)->dev->id); } card->state = QTAILQ_FIRST(&audio_states); } else { + if (QSIMPLEQ_EMPTY(&default_audiodevs)) { + audio_create_default_audiodevs(); + } card->state = audio_init(NULL); } } @@ -2170,7 +2151,6 @@ void audio_define(Audiodev *dev) e = g_new0(AudiodevListEntry, 1); e->dev = dev; QSIMPLEQ_INSERT_TAIL(&audiodevs, e, next); - legacy_config = false; } bool audio_init_audiodevs(void) diff --git a/audio/audio.h b/audio/audio.h index e0c13b5dcd..34df8962a6 100644 --- a/audio/audio.h +++ b/audio/audio.h @@ -172,7 +172,6 @@ void audio_define(Audiodev *audio); void audio_parse_option(const char *opt); bool audio_init_audiodevs(void); void audio_help(void); -void audio_legacy_help(void); AudioState *audio_state_by_name(const char *name, Error **errp); const char *audio_get_id(QEMUSoundCard *card); diff --git a/audio/audio_int.h b/audio/audio_int.h index 06e815de9f..2d079d00a2 100644 --- a/audio/audio_int.h +++ b/audio/audio_int.h @@ -146,7 +146,6 @@ struct audio_driver { void (*set_dbus_server) (AudioState *s, GDBusObjectManagerServer *manager, bool p2p); #endif struct audio_pcm_ops *pcm_ops; - int can_be_default; int max_voices_out; int max_voices_in; size_t voice_size_out; @@ -243,7 +242,6 @@ extern const struct mixeng_volume nominal_volume; extern const char *audio_prio_list[]; void audio_driver_register(audio_driver *drv); -audio_driver *audio_driver_lookup(const char *name); void audio_pcm_init_info (struct audio_pcm_info *info, struct audsettings *as); void audio_pcm_info_clear_buf (struct audio_pcm_info *info, void *buf, int len); @@ -297,9 +295,6 @@ typedef struct AudiodevListEntry { } AudiodevListEntry; typedef QSIMPLEQ_HEAD(, AudiodevListEntry) AudiodevListHead; -AudiodevListHead audio_handle_legacy_opts(void); - -void audio_free_audiodev_list(AudiodevListHead *head); void audio_create_pdos(Audiodev *dev); AudiodevPerDirectionOptions *audio_get_pdo_in(Audiodev *dev); diff --git a/audio/audio_legacy.c b/audio/audio_legacy.c deleted file mode 100644 index dc72ba55e9..0000000000 --- a/audio/audio_legacy.c +++ /dev/null @@ -1,591 +0,0 @@ -/* - * QEMU Audio subsystem: legacy configuration handling - * - * Copyright (c) 2015-2019 Zoltán Kővágó - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ -#include "qemu/osdep.h" -#include "audio.h" -#include "audio_int.h" -#include "qemu/cutils.h" -#include "qemu/timer.h" -#include "qapi/error.h" -#include "qapi/qapi-visit-audio.h" -#include "qapi/visitor-impl.h" - -#define AUDIO_CAP "audio-legacy" -#include "audio_int.h" - -static uint32_t toui32(const char *str) -{ - uint64_t ret; - if (parse_uint_full(str, 10, &ret) || ret > UINT32_MAX) { - dolog("Invalid integer value `%s'\n", str); - exit(1); - } - return ret; -} - -/* helper functions to convert env variables */ -static void get_bool(const char *env, bool *dst, bool *has_dst) -{ - const char *val = getenv(env); - if (val) { - *dst = toui32(val) != 0; - *has_dst = true; - } -} - -static void get_int(const char *env, uint32_t *dst, bool *has_dst) -{ - const char *val = getenv(env); - if (val) { - *dst = toui32(val); - *has_dst = true; - } -} - -static void get_str(const char *env, char **dst) -{ - const char *val = getenv(env); - if (val) { - g_free(*dst); - *dst = g_strdup(val); - } -} - -static void get_fmt(const char *env, AudioFormat *dst, bool *has_dst) -{ - const char *val = getenv(env); - if (val) { - size_t i; - for (i = 0; AudioFormat_lookup.size; ++i) { - if (strcasecmp(val, AudioFormat_lookup.array[i]) == 0) { - *dst = i; - *has_dst = true; - return; - } - } - - dolog("Invalid audio format `%s'\n", val); - exit(1); - } -} - - -#if defined(CONFIG_AUDIO_ALSA) || defined(CONFIG_AUDIO_DSOUND) -static void get_millis_to_usecs(const char *env, uint32_t *dst, bool *has_dst) -{ - const char *val = getenv(env); - if (val) { - *dst = toui32(val) * 1000; - *has_dst = true; - } -} -#endif - -#if defined(CONFIG_AUDIO_ALSA) || defined(CONFIG_AUDIO_COREAUDIO) || \ - defined(CONFIG_AUDIO_PA) || defined(CONFIG_AUDIO_SDL) || \ - defined(CONFIG_AUDIO_DSOUND) || defined(CONFIG_AUDIO_OSS) -static uint32_t frames_to_usecs(uint32_t frames, - AudiodevPerDirectionOptions *pdo) -{ - uint32_t freq = pdo->has_frequency ? pdo->frequency : 44100; - return (frames * 1000000 + freq / 2) / freq; -} -#endif - -#ifdef CONFIG_AUDIO_COREAUDIO -static void get_frames_to_usecs(const char *env, uint32_t *dst, bool *has_dst, - AudiodevPerDirectionOptions *pdo) -{ - const char *val = getenv(env); - if (val) { - *dst = frames_to_usecs(toui32(val), pdo); - *has_dst = true; - } -} -#endif - -#if defined(CONFIG_AUDIO_PA) || defined(CONFIG_AUDIO_SDL) || \ - defined(CONFIG_AUDIO_DSOUND) || defined(CONFIG_AUDIO_OSS) -static uint32_t samples_to_usecs(uint32_t samples, - AudiodevPerDirectionOptions *pdo) -{ - uint32_t channels = pdo->has_channels ? pdo->channels : 2; - return frames_to_usecs(samples / channels, pdo); -} -#endif - -#if defined(CONFIG_AUDIO_PA) || defined(CONFIG_AUDIO_SDL) -static void get_samples_to_usecs(const char *env, uint32_t *dst, bool *has_dst, - AudiodevPerDirectionOptions *pdo) -{ - const char *val = getenv(env); - if (val) { - *dst = samples_to_usecs(toui32(val), pdo); - *has_dst = true; - } -} -#endif - -#if defined(CONFIG_AUDIO_DSOUND) || defined(CONFIG_AUDIO_OSS) -static uint32_t bytes_to_usecs(uint32_t bytes, AudiodevPerDirectionOptions *pdo) -{ - AudioFormat fmt = pdo->has_format ? pdo->format : AUDIO_FORMAT_S16; - uint32_t bytes_per_sample = audioformat_bytes_per_sample(fmt); - return samples_to_usecs(bytes / bytes_per_sample, pdo); -} - -static void get_bytes_to_usecs(const char *env, uint32_t *dst, bool *has_dst, - AudiodevPerDirectionOptions *pdo) -{ - const char *val = getenv(env); - if (val) { - *dst = bytes_to_usecs(toui32(val), pdo); - *has_dst = true; - } -} -#endif - -/* backend specific functions */ - -#ifdef CONFIG_AUDIO_ALSA -/* ALSA */ -static void handle_alsa_per_direction( - AudiodevAlsaPerDirectionOptions *apdo, const char *prefix) -{ - char buf[64]; - size_t len = strlen(prefix); - bool size_in_usecs = false; - bool dummy; - - memcpy(buf, prefix, len); - strcpy(buf + len, "TRY_POLL"); - get_bool(buf, &apdo->try_poll, &apdo->has_try_poll); - - strcpy(buf + len, "DEV"); - get_str(buf, &apdo->dev); - - strcpy(buf + len, "SIZE_IN_USEC"); - get_bool(buf, &size_in_usecs, &dummy); - - strcpy(buf + len, "PERIOD_SIZE"); - get_int(buf, &apdo->period_length, &apdo->has_period_length); - if (apdo->has_period_length && !size_in_usecs) { - apdo->period_length = frames_to_usecs( - apdo->period_length, - qapi_AudiodevAlsaPerDirectionOptions_base(apdo)); - } - - strcpy(buf + len, "BUFFER_SIZE"); - get_int(buf, &apdo->buffer_length, &apdo->has_buffer_length); - if (apdo->has_buffer_length && !size_in_usecs) { - apdo->buffer_length = frames_to_usecs( - apdo->buffer_length, - qapi_AudiodevAlsaPerDirectionOptions_base(apdo)); - } -} - -static void handle_alsa(Audiodev *dev) -{ - AudiodevAlsaOptions *aopt = &dev->u.alsa; - handle_alsa_per_direction(aopt->in, "QEMU_ALSA_ADC_"); - handle_alsa_per_direction(aopt->out, "QEMU_ALSA_DAC_"); - - get_millis_to_usecs("QEMU_ALSA_THRESHOLD", - &aopt->threshold, &aopt->has_threshold); -} -#endif - -#ifdef CONFIG_AUDIO_COREAUDIO -/* coreaudio */ -static void handle_coreaudio(Audiodev *dev) -{ - get_frames_to_usecs( - "QEMU_COREAUDIO_BUFFER_SIZE", - &dev->u.coreaudio.out->buffer_length, - &dev->u.coreaudio.out->has_buffer_length, - qapi_AudiodevCoreaudioPerDirectionOptions_base(dev->u.coreaudio.out)); - get_int("QEMU_COREAUDIO_BUFFER_COUNT", - &dev->u.coreaudio.out->buffer_count, - &dev->u.coreaudio.out->has_buffer_count); -} -#endif - -#ifdef CONFIG_AUDIO_DSOUND -/* dsound */ -static void handle_dsound(Audiodev *dev) -{ - get_millis_to_usecs("QEMU_DSOUND_LATENCY_MILLIS", - &dev->u.dsound.latency, &dev->u.dsound.has_latency); - get_bytes_to_usecs("QEMU_DSOUND_BUFSIZE_OUT", - &dev->u.dsound.out->buffer_length, - &dev->u.dsound.out->has_buffer_length, - dev->u.dsound.out); - get_bytes_to_usecs("QEMU_DSOUND_BUFSIZE_IN", - &dev->u.dsound.in->buffer_length, - &dev->u.dsound.in->has_buffer_length, - dev->u.dsound.in); -} -#endif - -#ifdef CONFIG_AUDIO_OSS -/* OSS */ -static void handle_oss_per_direction( - AudiodevOssPerDirectionOptions *opdo, const char *try_poll_env, - const char *dev_env) -{ - get_bool(try_poll_env, &opdo->try_poll, &opdo->has_try_poll); - get_str(dev_env, &opdo->dev); - - get_bytes_to_usecs("QEMU_OSS_FRAGSIZE", - &opdo->buffer_length, &opdo->has_buffer_length, - qapi_AudiodevOssPerDirectionOptions_base(opdo)); - get_int("QEMU_OSS_NFRAGS", &opdo->buffer_count, - &opdo->has_buffer_count); -} - -static void handle_oss(Audiodev *dev) -{ - AudiodevOssOptions *oopt = &dev->u.oss; - handle_oss_per_direction(oopt->in, "QEMU_AUDIO_ADC_TRY_POLL", - "QEMU_OSS_ADC_DEV"); - handle_oss_per_direction(oopt->out, "QEMU_AUDIO_DAC_TRY_POLL", - "QEMU_OSS_DAC_DEV"); - - get_bool("QEMU_OSS_MMAP", &oopt->try_mmap, &oopt->has_try_mmap); - get_bool("QEMU_OSS_EXCLUSIVE", &oopt->exclusive, &oopt->has_exclusive); - get_int("QEMU_OSS_POLICY", &oopt->dsp_policy, &oopt->has_dsp_policy); -} -#endif - -#ifdef CONFIG_AUDIO_PA -/* pulseaudio */ -static void handle_pa_per_direction( - AudiodevPaPerDirectionOptions *ppdo, const char *env) -{ - get_str(env, &ppdo->name); -} - -static void handle_pa(Audiodev *dev) -{ - handle_pa_per_direction(dev->u.pa.in, "QEMU_PA_SOURCE"); - handle_pa_per_direction(dev->u.pa.out, "QEMU_PA_SINK"); - - get_samples_to_usecs( - "QEMU_PA_SAMPLES", &dev->u.pa.in->buffer_length, - &dev->u.pa.in->has_buffer_length, - qapi_AudiodevPaPerDirectionOptions_base(dev->u.pa.in)); - get_samples_to_usecs( - "QEMU_PA_SAMPLES", &dev->u.pa.out->buffer_length, - &dev->u.pa.out->has_buffer_length, - qapi_AudiodevPaPerDirectionOptions_base(dev->u.pa.out)); - - get_str("QEMU_PA_SERVER", &dev->u.pa.server); -} -#endif - -#ifdef CONFIG_AUDIO_SDL -/* SDL */ -static void handle_sdl(Audiodev *dev) -{ - /* SDL is output only */ - get_samples_to_usecs("QEMU_SDL_SAMPLES", &dev->u.sdl.out->buffer_length, - &dev->u.sdl.out->has_buffer_length, - qapi_AudiodevSdlPerDirectionOptions_base(dev->u.sdl.out)); -} -#endif - -/* wav */ -static void handle_wav(Audiodev *dev) -{ - get_int("QEMU_WAV_FREQUENCY", - &dev->u.wav.out->frequency, &dev->u.wav.out->has_frequency); - get_fmt("QEMU_WAV_FORMAT", &dev->u.wav.out->format, - &dev->u.wav.out->has_format); - get_int("QEMU_WAV_DAC_FIXED_CHANNELS", - &dev->u.wav.out->channels, &dev->u.wav.out->has_channels); - get_str("QEMU_WAV_PATH", &dev->u.wav.path); -} - -/* general */ -static void handle_per_direction( - AudiodevPerDirectionOptions *pdo, const char *prefix) -{ - char buf[64]; - size_t len = strlen(prefix); - - memcpy(buf, prefix, len); - strcpy(buf + len, "FIXED_SETTINGS"); - get_bool(buf, &pdo->fixed_settings, &pdo->has_fixed_settings); - - strcpy(buf + len, "FIXED_FREQ"); - get_int(buf, &pdo->frequency, &pdo->has_frequency); - - strcpy(buf + len, "FIXED_FMT"); - get_fmt(buf, &pdo->format, &pdo->has_format); - - strcpy(buf + len, "FIXED_CHANNELS"); - get_int(buf, &pdo->channels, &pdo->has_channels); - - strcpy(buf + len, "VOICES"); - get_int(buf, &pdo->voices, &pdo->has_voices); -} - -static AudiodevListEntry *legacy_opt(const char *drvname) -{ - AudiodevListEntry *e = g_new0(AudiodevListEntry, 1); - e->dev = g_new0(Audiodev, 1); - e->dev->id = g_strdup(drvname); - e->dev->driver = qapi_enum_parse( - &AudiodevDriver_lookup, drvname, -1, &error_abort); - - audio_create_pdos(e->dev); - - handle_per_direction(audio_get_pdo_in(e->dev), "QEMU_AUDIO_ADC_"); - handle_per_direction(audio_get_pdo_out(e->dev), "QEMU_AUDIO_DAC_"); - - /* Original description: Timer period in HZ (0 - use lowest possible) */ - get_int("QEMU_AUDIO_TIMER_PERIOD", - &e->dev->timer_period, &e->dev->has_timer_period); - if (e->dev->has_timer_period && e->dev->timer_period) { - e->dev->timer_period = NANOSECONDS_PER_SECOND / 1000 / - e->dev->timer_period; - } - - switch (e->dev->driver) { -#ifdef CONFIG_AUDIO_ALSA - case AUDIODEV_DRIVER_ALSA: - handle_alsa(e->dev); - break; -#endif - -#ifdef CONFIG_AUDIO_COREAUDIO - case AUDIODEV_DRIVER_COREAUDIO: - handle_coreaudio(e->dev); - break; -#endif - -#ifdef CONFIG_AUDIO_DSOUND - case AUDIODEV_DRIVER_DSOUND: - handle_dsound(e->dev); - break; -#endif - -#ifdef CONFIG_AUDIO_OSS - case AUDIODEV_DRIVER_OSS: - handle_oss(e->dev); - break; -#endif - -#ifdef CONFIG_AUDIO_PA - case AUDIODEV_DRIVER_PA: - handle_pa(e->dev); - break; -#endif - -#ifdef CONFIG_AUDIO_SDL - case AUDIODEV_DRIVER_SDL: - handle_sdl(e->dev); - break; -#endif - - case AUDIODEV_DRIVER_WAV: - handle_wav(e->dev); - break; - - default: - break; - } - - return e; -} - -AudiodevListHead audio_handle_legacy_opts(void) -{ - const char *drvname = getenv("QEMU_AUDIO_DRV"); - AudiodevListHead head = QSIMPLEQ_HEAD_INITIALIZER(head); - - if (drvname) { - AudiodevListEntry *e; - audio_driver *driver = audio_driver_lookup(drvname); - if (!driver) { - dolog("Unknown audio driver `%s'\n", drvname); - exit(1); - } - e = legacy_opt(drvname); - QSIMPLEQ_INSERT_TAIL(&head, e, next); - } else { - for (int i = 0; audio_prio_list[i]; i++) { - audio_driver *driver = audio_driver_lookup(audio_prio_list[i]); - if (driver && driver->can_be_default) { - AudiodevListEntry *e = legacy_opt(driver->name); - QSIMPLEQ_INSERT_TAIL(&head, e, next); - } - } - if (QSIMPLEQ_EMPTY(&head)) { - dolog("Internal error: no default audio driver available\n"); - exit(1); - } - } - - return head; -} - -/* visitor to print -audiodev option */ -typedef struct { - Visitor visitor; - - bool comma; - GList *path; -} LegacyPrintVisitor; - -static bool lv_start_struct(Visitor *v, const char *name, void **obj, - size_t size, Error **errp) -{ - LegacyPrintVisitor *lv = (LegacyPrintVisitor *) v; - lv->path = g_list_append(lv->path, g_strdup(name)); - return true; -} - -static void lv_end_struct(Visitor *v, void **obj) -{ - LegacyPrintVisitor *lv = (LegacyPrintVisitor *) v; - lv->path = g_list_delete_link(lv->path, g_list_last(lv->path)); -} - -static void lv_print_key(Visitor *v, const char *name) -{ - GList *e; - LegacyPrintVisitor *lv = (LegacyPrintVisitor *) v; - if (lv->comma) { - putchar(','); - } else { - lv->comma = true; - } - - for (e = lv->path; e; e = e->next) { - if (e->data) { - printf("%s.", (const char *) e->data); - } - } - - printf("%s=", name); -} - -static bool lv_type_int64(Visitor *v, const char *name, int64_t *obj, - Error **errp) -{ - lv_print_key(v, name); - printf("%" PRIi64, *obj); - return true; -} - -static bool lv_type_uint64(Visitor *v, const char *name, uint64_t *obj, - Error **errp) -{ - lv_print_key(v, name); - printf("%" PRIu64, *obj); - return true; -} - -static bool lv_type_bool(Visitor *v, const char *name, bool *obj, Error **errp) -{ - lv_print_key(v, name); - printf("%s", *obj ? "on" : "off"); - return true; -} - -static bool lv_type_str(Visitor *v, const char *name, char **obj, Error **errp) -{ - const char *str = *obj; - lv_print_key(v, name); - - while (*str) { - if (*str == ',') { - putchar(','); - } - putchar(*str++); - } - return true; -} - -static void lv_complete(Visitor *v, void *opaque) -{ - LegacyPrintVisitor *lv = (LegacyPrintVisitor *) v; - assert(lv->path == NULL); -} - -static void lv_free(Visitor *v) -{ - LegacyPrintVisitor *lv = (LegacyPrintVisitor *) v; - - g_list_free_full(lv->path, g_free); - g_free(lv); -} - -static Visitor *legacy_visitor_new(void) -{ - LegacyPrintVisitor *lv = g_new0(LegacyPrintVisitor, 1); - - lv->visitor.start_struct = lv_start_struct; - lv->visitor.end_struct = lv_end_struct; - /* lists not supported */ - lv->visitor.type_int64 = lv_type_int64; - lv->visitor.type_uint64 = lv_type_uint64; - lv->visitor.type_bool = lv_type_bool; - lv->visitor.type_str = lv_type_str; - - lv->visitor.type = VISITOR_OUTPUT; - lv->visitor.complete = lv_complete; - lv->visitor.free = lv_free; - - return &lv->visitor; -} - -void audio_legacy_help(void) -{ - AudiodevListHead head; - AudiodevListEntry *e; - - printf("Environment variable based configuration deprecated.\n"); - printf("Please use the new -audiodev option.\n"); - - head = audio_handle_legacy_opts(); - printf("\nEquivalent -audiodev to your current environment variables:\n"); - if (!getenv("QEMU_AUDIO_DRV")) { - printf("(Since you didn't specify QEMU_AUDIO_DRV, I'll list all " - "possibilities)\n"); - } - - QSIMPLEQ_FOREACH(e, &head, next) { - Visitor *v; - Audiodev *dev = e->dev; - printf("-audiodev "); - - v = legacy_visitor_new(); - visit_type_Audiodev(v, NULL, &dev, &error_abort); - visit_free(v); - - printf("\n"); - } - audio_free_audiodev_list(&head); -} diff --git a/audio/coreaudio.m b/audio/coreaudio.m index 7cfb38fb6a..8cd129a27d 100644 --- a/audio/coreaudio.m +++ b/audio/coreaudio.m @@ -673,7 +673,6 @@ static struct audio_driver coreaudio_audio_driver = { .init = coreaudio_audio_init, .fini = coreaudio_audio_fini, .pcm_ops = &coreaudio_pcm_ops, - .can_be_default = 1, .max_voices_out = 1, .max_voices_in = 0, .voice_size_out = sizeof (coreaudioVoiceOut), diff --git a/audio/dbusaudio.c b/audio/dbusaudio.c index 310ca997ff..60fcf643ec 100644 --- a/audio/dbusaudio.c +++ b/audio/dbusaudio.c @@ -676,7 +676,6 @@ static struct audio_driver dbus_audio_driver = { .fini = dbus_audio_fini, .set_dbus_server = dbus_audio_set_server, .pcm_ops = &dbus_pcm_ops, - .can_be_default = 1, .max_voices_out = INT_MAX, .max_voices_in = INT_MAX, .voice_size_out = sizeof(DBusVoiceOut), diff --git a/audio/dsoundaudio.c b/audio/dsoundaudio.c index eefde88edc..f3bb48d007 100644 --- a/audio/dsoundaudio.c +++ b/audio/dsoundaudio.c @@ -721,7 +721,6 @@ static struct audio_driver dsound_audio_driver = { .init = dsound_audio_init, .fini = dsound_audio_fini, .pcm_ops = &dsound_pcm_ops, - .can_be_default = 1, .max_voices_out = INT_MAX, .max_voices_in = 1, .voice_size_out = sizeof (DSoundVoiceOut), diff --git a/audio/jackaudio.c b/audio/jackaudio.c index 823e7d96ba..974a3caad3 100644 --- a/audio/jackaudio.c +++ b/audio/jackaudio.c @@ -676,7 +676,6 @@ static struct audio_driver jack_driver = { .init = qjack_init, .fini = qjack_fini, .pcm_ops = &jack_pcm_ops, - .can_be_default = 1, .max_voices_out = INT_MAX, .max_voices_in = INT_MAX, .voice_size_out = sizeof(QJackOut), diff --git a/audio/meson.build b/audio/meson.build index df4d968c0f..c8f658611f 100644 --- a/audio/meson.build +++ b/audio/meson.build @@ -1,7 +1,6 @@ system_ss.add([spice_headers, files('audio.c')]) system_ss.add(files( 'audio-hmp-cmds.c', - 'audio_legacy.c', 'mixeng.c', 'noaudio.c', 'wavaudio.c', diff --git a/audio/noaudio.c b/audio/noaudio.c index a36bfeffd1..1b60d8518a 100644 --- a/audio/noaudio.c +++ b/audio/noaudio.c @@ -135,7 +135,6 @@ static struct audio_driver no_audio_driver = { .init = no_audio_init, .fini = no_audio_fini, .pcm_ops = &no_pcm_ops, - .can_be_default = 1, .max_voices_out = INT_MAX, .max_voices_in = INT_MAX, .voice_size_out = sizeof (NoVoiceOut), diff --git a/audio/ossaudio.c b/audio/ossaudio.c index ec4448d573..3f31852371 100644 --- a/audio/ossaudio.c +++ b/audio/ossaudio.c @@ -784,7 +784,6 @@ static struct audio_driver oss_audio_driver = { .init = oss_audio_init, .fini = oss_audio_fini, .pcm_ops = &oss_pcm_ops, - .can_be_default = 1, .max_voices_out = INT_MAX, .max_voices_in = INT_MAX, .voice_size_out = sizeof (OSSVoiceOut), diff --git a/audio/paaudio.c b/audio/paaudio.c index 39bd6cfa38..f3193b08c3 100644 --- a/audio/paaudio.c +++ b/audio/paaudio.c @@ -931,7 +931,6 @@ static struct audio_driver pa_audio_driver = { .init = qpa_audio_init, .fini = qpa_audio_fini, .pcm_ops = &qpa_pcm_ops, - .can_be_default = 1, .max_voices_out = INT_MAX, .max_voices_in = INT_MAX, .voice_size_out = sizeof (PAVoiceOut), diff --git a/audio/pwaudio.c b/audio/pwaudio.c index 1020cb11df..3ce5f6507b 100644 --- a/audio/pwaudio.c +++ b/audio/pwaudio.c @@ -843,7 +843,6 @@ static struct audio_driver pw_audio_driver = { .init = qpw_audio_init, .fini = qpw_audio_fini, .pcm_ops = &qpw_pcm_ops, - .can_be_default = 1, .max_voices_out = INT_MAX, .max_voices_in = INT_MAX, .voice_size_out = sizeof(PWVoiceOut), diff --git a/audio/sdlaudio.c b/audio/sdlaudio.c index 4d8473d9ec..641357e5ee 100644 --- a/audio/sdlaudio.c +++ b/audio/sdlaudio.c @@ -494,7 +494,6 @@ static struct audio_driver sdl_audio_driver = { .init = sdl_audio_init, .fini = sdl_audio_fini, .pcm_ops = &sdl_pcm_ops, - .can_be_default = 1, .max_voices_out = INT_MAX, .max_voices_in = INT_MAX, .voice_size_out = sizeof(SDLVoiceOut), diff --git a/audio/sndioaudio.c b/audio/sndioaudio.c index 1e35925a49..8eb35e1e53 100644 --- a/audio/sndioaudio.c +++ b/audio/sndioaudio.c @@ -550,7 +550,6 @@ static struct audio_driver sndio_audio_driver = { .init = sndio_audio_init, .fini = sndio_audio_fini, .pcm_ops = &sndio_pcm_ops, - .can_be_default = 1, .max_voices_out = INT_MAX, .max_voices_in = INT_MAX, .voice_size_out = sizeof(SndioVoice), diff --git a/audio/wavaudio.c b/audio/wavaudio.c index 26b03906d5..ea20fed0cc 100644 --- a/audio/wavaudio.c +++ b/audio/wavaudio.c @@ -208,7 +208,6 @@ static struct audio_driver wav_audio_driver = { .init = wav_audio_init, .fini = wav_audio_fini, .pcm_ops = &wav_pcm_ops, - .can_be_default = 0, .max_voices_out = 1, .max_voices_in = 0, .voice_size_out = sizeof (WAVVoiceOut), diff --git a/docs/about/deprecated.rst b/docs/about/deprecated.rst index c07bf58dde..2f51cf770a 100644 --- a/docs/about/deprecated.rst +++ b/docs/about/deprecated.rst @@ -37,14 +37,6 @@ coverage. System emulator command line arguments -------------------------------------- -``QEMU_AUDIO_`` environment variables and ``-audio-help`` (since 4.0) -''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' - -The ``-audiodev`` argument is now the preferred way to specify audio -backend settings instead of environment variables. To ease migration to -the new format, the ``-audiodev-help`` option can be used to convert -the current values of the environment variables to ``-audiodev`` options. - Creating sound card devices without ``audiodev=`` property (since 4.2) '''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' diff --git a/docs/about/removed-features.rst b/docs/about/removed-features.rst index 276060b320..e83ed087f6 100644 --- a/docs/about/removed-features.rst +++ b/docs/about/removed-features.rst @@ -436,6 +436,12 @@ the process listing. This was replaced by the new ``password-secret`` option which lets the password be securely provided on the command line using a ``secret`` object instance. +``QEMU_AUDIO_`` environment variables and ``-audio-help`` (removed in 8.2) +'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' + +The ``-audiodev`` and ``-audio`` command line options are now the only +way to specify audio backend settings. + Creating vnc without ``audiodev=`` property (removed in 8.2) '''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' diff --git a/qemu-options.hx b/qemu-options.hx index bcd77255cb..9ce8a5b957 100644 --- a/qemu-options.hx +++ b/qemu-options.hx @@ -727,16 +727,6 @@ SRST ERST -HXCOMM Deprecated by -audiodev -DEF("audio-help", 0, QEMU_OPTION_audio_help, - "-audio-help show -audiodev equivalent of the currently specified audio settings\n", - QEMU_ARCH_ALL) -SRST -``-audio-help`` - Will show the -audiodev equivalent of the currently specified - (deprecated) environment variables. -ERST - DEF("audio", HAS_ARG, QEMU_OPTION_audio, "-audio [driver=]driver,model=value[,prop[=value][,...]]\n" " specifies the audio backend and device to use;\n" diff --git a/softmmu/vl.c b/softmmu/vl.c index 59a472a0b1..cafb1a9842 100644 --- a/softmmu/vl.c +++ b/softmmu/vl.c @@ -2926,10 +2926,6 @@ void qemu_init(int argc, char **argv) } break; #endif - case QEMU_OPTION_audio_help: - audio_legacy_help(); - exit (0); - break; case QEMU_OPTION_audiodev: audio_parse_option(optarg); break; From 7a2c7da6448eb8538bccbbc288508bde69bc4c2d Mon Sep 17 00:00:00 2001 From: Martin Kletzander Date: Mon, 25 Apr 2022 10:21:50 +0200 Subject: [PATCH 0124/1077] Introduce machine property "audiodev" Many machine types have default audio devices with no way to set the underlying audiodev. Instead of adding an option for each and every one of them, this new property can be used as a default during machine initialisation when creating such devices. Signed-off-by: Martin Kletzander [Make the property optional, instead of including it in all machines. - Paolo] Signed-off-by: Paolo Bonzini --- hw/core/machine.c | 33 +++++++++++++++++++++++++++++++++ include/hw/boards.h | 9 +++++++++ 2 files changed, 42 insertions(+) diff --git a/hw/core/machine.c b/hw/core/machine.c index cb38b8cf4c..6aa49c8d4f 100644 --- a/hw/core/machine.c +++ b/hw/core/machine.c @@ -39,6 +39,7 @@ #include "hw/virtio/virtio.h" #include "hw/virtio/virtio-pci.h" #include "hw/virtio/virtio-net.h" +#include "audio/audio.h" GlobalProperty hw_compat_8_1[] = {}; const size_t hw_compat_8_1_len = G_N_ELEMENTS(hw_compat_8_1); @@ -686,6 +687,26 @@ bool device_type_is_dynamic_sysbus(MachineClass *mc, const char *type) return allowed; } +static char *machine_get_audiodev(Object *obj, Error **errp) +{ + MachineState *ms = MACHINE(obj); + + return g_strdup(ms->audiodev); +} + +static void machine_set_audiodev(Object *obj, const char *value, + Error **errp) +{ + MachineState *ms = MACHINE(obj); + + if (!audio_state_by_name(value, errp)) { + return; + } + + g_free(ms->audiodev); + ms->audiodev = g_strdup(value); +} + HotpluggableCPUList *machine_query_hotpluggable_cpus(MachineState *machine) { int i; @@ -931,6 +952,17 @@ out_free: qapi_free_BootConfiguration(config); } +void machine_add_audiodev_property(MachineClass *mc) +{ + ObjectClass *oc = OBJECT_CLASS(mc); + + object_class_property_add_str(oc, "audiodev", + machine_get_audiodev, + machine_set_audiodev); + object_class_property_set_description(oc, "audiodev", + "Audiodev to use for default machine devices"); +} + static void machine_class_init(ObjectClass *oc, void *data) { MachineClass *mc = MACHINE_CLASS(oc); @@ -1136,6 +1168,7 @@ static void machine_finalize(Object *obj) g_free(ms->device_memory); g_free(ms->nvdimms_state); g_free(ms->numa_state); + g_free(ms->audiodev); } bool machine_usb(MachineState *machine) diff --git a/include/hw/boards.h b/include/hw/boards.h index 6c67af196a..55a64a13fd 100644 --- a/include/hw/boards.h +++ b/include/hw/boards.h @@ -24,6 +24,7 @@ OBJECT_DECLARE_TYPE(MachineState, MachineClass, MACHINE) extern MachineState *current_machine; +void machine_add_audiodev_property(MachineClass *mc); void machine_run_board_init(MachineState *machine, const char *mem_path, Error **errp); bool machine_usb(MachineState *machine); int machine_phandle_start(MachineState *machine); @@ -358,6 +359,14 @@ struct MachineState { MemoryRegion *ram; DeviceMemoryState *device_memory; + /* + * Included in MachineState for simplicity, but not supported + * unless machine_add_audiodev_property is called. Boards + * that have embedded audio devices can call it from the + * machine init function and forward the property to the device. + */ + char *audiodev; + ram_addr_t ram_size; ram_addr_t maxram_size; uint64_t ram_slots; From b8ab0303de5a72d89da5ab25d8fe817d8797888f Mon Sep 17 00:00:00 2001 From: Martin Kletzander Date: Fri, 22 Sep 2023 17:21:39 +0200 Subject: [PATCH 0125/1077] hw/arm: Support machine-default audiodev with fallback Signed-off-by: Martin Kletzander Signed-off-by: Paolo Bonzini --- hw/arm/integratorcp.c | 11 ++++++++++- hw/arm/musicpal.c | 11 +++++++++-- hw/arm/nseries.c | 4 ++++ hw/arm/omap2.c | 5 +++++ hw/arm/palm.c | 2 ++ hw/arm/realview.c | 12 ++++++++++++ hw/arm/spitz.c | 17 ++++++++++++----- hw/arm/versatilepb.c | 8 ++++++++ hw/arm/vexpress.c | 5 +++++ hw/arm/xlnx-zcu102.c | 6 ++++++ hw/arm/z2.c | 15 ++++++++++++++- hw/input/tsc210x.c | 5 +++++ 12 files changed, 92 insertions(+), 9 deletions(-) diff --git a/hw/arm/integratorcp.c b/hw/arm/integratorcp.c index b109ece3ae..d176e9af7e 100644 --- a/hw/arm/integratorcp.c +++ b/hw/arm/integratorcp.c @@ -27,6 +27,7 @@ #include "hw/irq.h" #include "hw/sd/sd.h" #include "qom/object.h" +#include "audio/audio.h" #define TYPE_INTEGRATOR_CM "integrator_core" OBJECT_DECLARE_SIMPLE_TYPE(IntegratorCMState, INTEGRATOR_CM) @@ -660,7 +661,13 @@ static void integratorcp_init(MachineState *machine) &error_fatal); } - sysbus_create_varargs("pl041", 0x1d000000, pic[25], NULL); + dev = qdev_new("pl041"); + if (machine->audiodev) { + qdev_prop_set_string(dev, "audiodev", machine->audiodev); + } + sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal); + sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, 0x1d000000); + sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, pic[25]); if (nd_table[0].used) smc91c111_init(&nd_table[0], 0xc8000000, pic[27]); @@ -678,6 +685,8 @@ static void integratorcp_machine_init(MachineClass *mc) mc->ignore_memory_transaction_failures = true; mc->default_cpu_type = ARM_CPU_TYPE_NAME("arm926"); mc->default_ram_id = "integrator.ram"; + + machine_add_audiodev_property(mc); } DEFINE_MACHINE("integratorcp", integratorcp_machine_init) diff --git a/hw/arm/musicpal.c b/hw/arm/musicpal.c index dc4e43e0ee..9703bfb97f 100644 --- a/hw/arm/musicpal.c +++ b/hw/arm/musicpal.c @@ -37,9 +37,9 @@ #include "qemu/cutils.h" #include "qom/object.h" #include "hw/net/mv88w8618_eth.h" +#include "audio/audio.h" #include "qemu/error-report.h" - #define MP_MISC_BASE 0x80002000 #define MP_MISC_SIZE 0x00001000 @@ -1326,7 +1326,12 @@ static void musicpal_init(MachineState *machine) qdev_connect_gpio_out(key_dev, i, qdev_get_gpio_in(dev, i + 15)); } - wm8750_dev = i2c_slave_create_simple(i2c, TYPE_WM8750, MP_WM_ADDR); + wm8750_dev = i2c_slave_new(TYPE_WM8750, MP_WM_ADDR); + if (machine->audiodev) { + qdev_prop_set_string(DEVICE(wm8750_dev), "audiodev", machine->audiodev); + } + i2c_slave_realize_and_unref(wm8750_dev, i2c, &error_abort); + dev = qdev_new(TYPE_MV88W8618_AUDIO); s = SYS_BUS_DEVICE(dev); object_property_set_link(OBJECT(dev), "wm8750", OBJECT(wm8750_dev), @@ -1347,6 +1352,8 @@ static void musicpal_machine_init(MachineClass *mc) mc->default_cpu_type = ARM_CPU_TYPE_NAME("arm926"); mc->default_ram_size = MP_RAM_DEFAULT_SIZE; mc->default_ram_id = "musicpal.ram"; + + machine_add_audiodev_property(mc); } DEFINE_MACHINE("musicpal", musicpal_machine_init) diff --git a/hw/arm/nseries.c b/hw/arm/nseries.c index 9e49e9e177..35aff46b4b 100644 --- a/hw/arm/nseries.c +++ b/hw/arm/nseries.c @@ -1432,6 +1432,8 @@ static void n800_class_init(ObjectClass *oc, void *data) /* Actually two chips of 0x4000000 bytes each */ mc->default_ram_size = 0x08000000; mc->default_ram_id = "omap2.dram"; + + machine_add_audiodev_property(mc); } static const TypeInfo n800_type = { @@ -1452,6 +1454,8 @@ static void n810_class_init(ObjectClass *oc, void *data) /* Actually two chips of 0x4000000 bytes each */ mc->default_ram_size = 0x08000000; mc->default_ram_id = "omap2.dram"; + + machine_add_audiodev_property(mc); } static const TypeInfo n810_type = { diff --git a/hw/arm/omap2.c b/hw/arm/omap2.c index d5a2ae7af6..41b1f596dc 100644 --- a/hw/arm/omap2.c +++ b/hw/arm/omap2.c @@ -37,6 +37,7 @@ #include "hw/block/flash.h" #include "hw/arm/soc_dma.h" #include "hw/sysbus.h" +#include "hw/boards.h" #include "audio/audio.h" /* Enhanced Audio Controller (CODEC only) */ @@ -609,6 +610,10 @@ static struct omap_eac_s *omap_eac_init(struct omap_target_agent_s *ta, s->codec.txdrq = *drq; omap_eac_reset(s); + if (current_machine->audiodev) { + s->codec.card.name = g_strdup(current_machine->audiodev); + s->codec.card.state = audio_state_by_name(s->codec.card.name, &error_fatal); + } AUD_register_card("OMAP EAC", &s->codec.card); memory_region_init_io(&s->iomem, NULL, &omap_eac_ops, s, "omap.eac", diff --git a/hw/arm/palm.c b/hw/arm/palm.c index 17c11ac4ce..b86f2c331b 100644 --- a/hw/arm/palm.c +++ b/hw/arm/palm.c @@ -310,6 +310,8 @@ static void palmte_machine_init(MachineClass *mc) mc->default_cpu_type = ARM_CPU_TYPE_NAME("ti925t"); mc->default_ram_size = 0x02000000; mc->default_ram_id = "omap1.dram"; + + machine_add_audiodev_property(mc); } DEFINE_MACHINE("cheetah", palmte_machine_init) diff --git a/hw/arm/realview.c b/hw/arm/realview.c index a5aa2f046a..8f89526596 100644 --- a/hw/arm/realview.c +++ b/hw/arm/realview.c @@ -29,6 +29,7 @@ #include "hw/irq.h" #include "hw/i2c/arm_sbcon_i2c.h" #include "hw/sd/sd.h" +#include "audio/audio.h" #define SMP_BOOT_ADDR 0xe0000000 #define SMP_BOOTREG_ADDR 0x10000030 @@ -207,6 +208,9 @@ static void realview_init(MachineState *machine, pl041 = qdev_new("pl041"); qdev_prop_set_uint32(pl041, "nc_fifo_depth", 512); + if (machine->audiodev) { + qdev_prop_set_string(pl041, "audiodev", machine->audiodev); + } sysbus_realize_and_unref(SYS_BUS_DEVICE(pl041), &error_fatal); sysbus_mmio_map(SYS_BUS_DEVICE(pl041), 0, 0x10004000); sysbus_connect_irq(SYS_BUS_DEVICE(pl041), 0, pic[19]); @@ -412,6 +416,8 @@ static void realview_eb_class_init(ObjectClass *oc, void *data) mc->block_default_type = IF_SCSI; mc->ignore_memory_transaction_failures = true; mc->default_cpu_type = ARM_CPU_TYPE_NAME("arm926"); + + machine_add_audiodev_property(mc); } static const TypeInfo realview_eb_type = { @@ -430,6 +436,8 @@ static void realview_eb_mpcore_class_init(ObjectClass *oc, void *data) mc->max_cpus = 4; mc->ignore_memory_transaction_failures = true; mc->default_cpu_type = ARM_CPU_TYPE_NAME("arm11mpcore"); + + machine_add_audiodev_property(mc); } static const TypeInfo realview_eb_mpcore_type = { @@ -446,6 +454,8 @@ static void realview_pb_a8_class_init(ObjectClass *oc, void *data) mc->init = realview_pb_a8_init; mc->ignore_memory_transaction_failures = true; mc->default_cpu_type = ARM_CPU_TYPE_NAME("cortex-a8"); + + machine_add_audiodev_property(mc); } static const TypeInfo realview_pb_a8_type = { @@ -463,6 +473,8 @@ static void realview_pbx_a9_class_init(ObjectClass *oc, void *data) mc->max_cpus = 4; mc->ignore_memory_transaction_failures = true; mc->default_cpu_type = ARM_CPU_TYPE_NAME("cortex-a9"); + + machine_add_audiodev_property(mc); } static const TypeInfo realview_pbx_a9_type = { diff --git a/hw/arm/spitz.c b/hw/arm/spitz.c index f732fe0acf..cc268c6ac0 100644 --- a/hw/arm/spitz.c +++ b/hw/arm/spitz.c @@ -35,6 +35,7 @@ #include "exec/address-spaces.h" #include "cpu.h" #include "qom/object.h" +#include "audio/audio.h" enum spitz_model_e { spitz, akita, borzoi, terrier }; @@ -774,15 +775,19 @@ static void spitz_wm8750_addr(void *opaque, int line, int level) i2c_slave_set_address(wm, SPITZ_WM_ADDRL); } -static void spitz_i2c_setup(PXA2xxState *cpu) +static void spitz_i2c_setup(MachineState *machine, PXA2xxState *cpu) { /* Attach the CPU on one end of our I2C bus. */ I2CBus *bus = pxa2xx_i2c_bus(cpu->i2c[0]); - DeviceState *wm; - /* Attach a WM8750 to the bus */ - wm = DEVICE(i2c_slave_create_simple(bus, TYPE_WM8750, 0)); + I2CSlave *i2c_dev = i2c_slave_new(TYPE_WM8750, 0); + DeviceState *wm = DEVICE(i2c_dev); + + if (machine->audiodev) { + qdev_prop_set_string(wm, "audiodev", machine->audiodev); + } + i2c_slave_realize_and_unref(i2c_dev, bus, &error_abort); spitz_wm8750_addr(wm, 0, 0); qdev_connect_gpio_out(cpu->gpio, SPITZ_GPIO_WM, @@ -1013,7 +1018,7 @@ static void spitz_common_init(MachineState *machine) spitz_gpio_setup(mpu, (model == akita) ? 1 : 2); - spitz_i2c_setup(mpu); + spitz_i2c_setup(machine, mpu); if (model == akita) spitz_akita_i2c_setup(mpu); @@ -1037,6 +1042,8 @@ static void spitz_common_class_init(ObjectClass *oc, void *data) mc->block_default_type = IF_IDE; mc->ignore_memory_transaction_failures = true; mc->init = spitz_common_init; + + machine_add_audiodev_property(mc); } static const TypeInfo spitz_common_info = { diff --git a/hw/arm/versatilepb.c b/hw/arm/versatilepb.c index 05b9462a5b..2f22dc890f 100644 --- a/hw/arm/versatilepb.c +++ b/hw/arm/versatilepb.c @@ -26,6 +26,7 @@ #include "hw/char/pl011.h" #include "hw/sd/sd.h" #include "qom/object.h" +#include "audio/audio.h" #define VERSATILE_FLASH_ADDR 0x34000000 #define VERSATILE_FLASH_SIZE (64 * 1024 * 1024) @@ -343,6 +344,9 @@ static void versatile_init(MachineState *machine, int board_id) /* Add PL041 AACI Interface to the LM4549 codec */ pl041 = qdev_new("pl041"); qdev_prop_set_uint32(pl041, "nc_fifo_depth", 512); + if (machine->audiodev) { + qdev_prop_set_string(pl041, "audiodev", machine->audiodev); + } sysbus_realize_and_unref(SYS_BUS_DEVICE(pl041), &error_fatal); sysbus_mmio_map(SYS_BUS_DEVICE(pl041), 0, 0x10004000); sysbus_connect_irq(SYS_BUS_DEVICE(pl041), 0, sic[24]); @@ -416,6 +420,8 @@ static void versatilepb_class_init(ObjectClass *oc, void *data) mc->ignore_memory_transaction_failures = true; mc->default_cpu_type = ARM_CPU_TYPE_NAME("arm926"); mc->default_ram_id = "versatile.ram"; + + machine_add_audiodev_property(mc); } static const TypeInfo versatilepb_type = { @@ -434,6 +440,8 @@ static void versatileab_class_init(ObjectClass *oc, void *data) mc->ignore_memory_transaction_failures = true; mc->default_cpu_type = ARM_CPU_TYPE_NAME("arm926"); mc->default_ram_id = "versatile.ram"; + + machine_add_audiodev_property(mc); } static const TypeInfo versatileab_type = { diff --git a/hw/arm/vexpress.c b/hw/arm/vexpress.c index 56abadd9b8..8ff37f52ca 100644 --- a/hw/arm/vexpress.c +++ b/hw/arm/vexpress.c @@ -44,6 +44,7 @@ #include "hw/i2c/arm_sbcon_i2c.h" #include "hw/sd/sd.h" #include "qom/object.h" +#include "audio/audio.h" #define VEXPRESS_BOARD_ID 0x8e0 #define VEXPRESS_FLASH_SIZE (64 * 1024 * 1024) @@ -613,6 +614,9 @@ static void vexpress_common_init(MachineState *machine) pl041 = qdev_new("pl041"); qdev_prop_set_uint32(pl041, "nc_fifo_depth", 512); + if (machine->audiodev) { + qdev_prop_set_string(pl041, "audiodev", machine->audiodev); + } sysbus_realize_and_unref(SYS_BUS_DEVICE(pl041), &error_fatal); sysbus_mmio_map(SYS_BUS_DEVICE(pl041), 0, map[VE_PL041]); sysbus_connect_irq(SYS_BUS_DEVICE(pl041), 0, pic[11]); @@ -776,6 +780,7 @@ static void vexpress_class_init(ObjectClass *oc, void *data) mc->ignore_memory_transaction_failures = true; mc->default_ram_id = "vexpress.highmem"; + machine_add_audiodev_property(mc); object_class_property_add_bool(oc, "secure", vexpress_get_secure, vexpress_set_secure); object_class_property_set_description(oc, "secure", diff --git a/hw/arm/xlnx-zcu102.c b/hw/arm/xlnx-zcu102.c index 21483f75fd..c5a07cfe19 100644 --- a/hw/arm/xlnx-zcu102.c +++ b/hw/arm/xlnx-zcu102.c @@ -24,6 +24,7 @@ #include "sysemu/device_tree.h" #include "qom/object.h" #include "net/can_emu.h" +#include "audio/audio.h" struct XlnxZCU102 { MachineState parent_obj; @@ -143,6 +144,10 @@ static void xlnx_zcu102_init(MachineState *machine) object_initialize_child(OBJECT(machine), "soc", &s->soc, TYPE_XLNX_ZYNQMP); + if (machine->audiodev) { + qdev_prop_set_string(DEVICE(&s->soc.dp), "audiodev", machine->audiodev); + } + object_property_set_link(OBJECT(&s->soc), "ddr-ram", OBJECT(machine->ram), &error_abort); object_property_set_bool(OBJECT(&s->soc), "secure", s->secure, @@ -275,6 +280,7 @@ static void xlnx_zcu102_machine_class_init(ObjectClass *oc, void *data) mc->default_cpus = XLNX_ZYNQMP_NUM_APU_CPUS; mc->default_ram_id = "ddr-ram"; + machine_add_audiodev_property(mc); object_class_property_add_bool(oc, "secure", zcu102_get_secure, zcu102_set_secure); object_class_property_set_description(oc, "secure", diff --git a/hw/arm/z2.c b/hw/arm/z2.c index dc25304290..d9a08fa67b 100644 --- a/hw/arm/z2.c +++ b/hw/arm/z2.c @@ -27,6 +27,7 @@ #include "exec/address-spaces.h" #include "cpu.h" #include "qom/object.h" +#include "qapi/error.h" #ifdef DEBUG_Z2 #define DPRINTF(fmt, ...) \ @@ -307,6 +308,7 @@ static void z2_init(MachineState *machine) void *z2_lcd; I2CBus *bus; DeviceState *wm; + I2CSlave *i2c_dev; /* Setup CPU & memory */ mpu = pxa270_init(z2_binfo.ram_size, machine->cpu_type); @@ -328,8 +330,17 @@ static void z2_init(MachineState *machine) type_register_static(&aer915_info); z2_lcd = ssi_create_peripheral(mpu->ssp[1], TYPE_ZIPIT_LCD); bus = pxa2xx_i2c_bus(mpu->i2c[0]); + i2c_slave_create_simple(bus, TYPE_AER915, 0x55); - wm = DEVICE(i2c_slave_create_simple(bus, TYPE_WM8750, 0x1b)); + + i2c_dev = i2c_slave_new(TYPE_WM8750, 0x1b); + wm = DEVICE(i2c_dev); + + if (machine->audiodev) { + qdev_prop_set_string(wm, "audiodev", machine->audiodev); + } + i2c_slave_realize_and_unref(i2c_dev, bus, &error_abort); + mpu->i2s->opaque = wm; mpu->i2s->codec_out = wm8750_dac_dat; mpu->i2s->codec_in = wm8750_adc_dat; @@ -348,6 +359,8 @@ static void z2_machine_init(MachineClass *mc) mc->init = z2_init; mc->ignore_memory_transaction_failures = true; mc->default_cpu_type = ARM_CPU_TYPE_NAME("pxa270-c5"); + + machine_add_audiodev_property(mc); } DEFINE_MACHINE("z2", z2_machine_init) diff --git a/hw/input/tsc210x.c b/hw/input/tsc210x.c index f568759e05..e7960a5069 100644 --- a/hw/input/tsc210x.c +++ b/hw/input/tsc210x.c @@ -27,6 +27,7 @@ #include "sysemu/reset.h" #include "ui/console.h" #include "hw/arm/omap.h" /* For I2SCodec */ +#include "hw/boards.h" /* for current_machine */ #include "hw/input/tsc2xxx.h" #include "hw/irq.h" #include "migration/vmstate.h" @@ -1097,6 +1098,10 @@ static void tsc210x_init(TSC210xState *s, qemu_add_mouse_event_handler(tsc210x_touchscreen_event, s, 1, name); + if (current_machine->audiodev) { + s->card.name = g_strdup(current_machine->audiodev); + s->card.state = audio_state_by_name(s->card.name, &error_fatal); + } AUD_register_card(s->name, &s->card); qemu_register_reset((void *) tsc210x_reset, s); From 2b16397264a8ea4b5274023b22b09a69e92cb8e9 Mon Sep 17 00:00:00 2001 From: Martin Kletzander Date: Mon, 25 Apr 2022 10:21:55 +0200 Subject: [PATCH 0126/1077] hw/ppc: Support machine-default audiodev with fallback Signed-off-by: Martin Kletzander Signed-off-by: Paolo Bonzini --- hw/ppc/prep.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/hw/ppc/prep.c b/hw/ppc/prep.c index f6fd35fcb9..137276bcb9 100644 --- a/hw/ppc/prep.c +++ b/hw/ppc/prep.c @@ -45,6 +45,7 @@ #include "trace.h" #include "elf.h" #include "qemu/units.h" +#include "audio/audio.h" /* SMP is not enabled, for now */ #define MAX_CPUS 1 @@ -310,6 +311,10 @@ static void ibm_40p_init(MachineState *machine) dev = DEVICE(isa_dev); qdev_prop_set_uint32(dev, "iobase", 0x830); qdev_prop_set_uint32(dev, "irq", 10); + + if (machine->audiodev) { + qdev_prop_set_string(dev, "audiodev", machine->audiodev); + } isa_realize_and_unref(isa_dev, isa_bus, &error_fatal); isa_dev = isa_new("pc87312"); @@ -426,6 +431,8 @@ static void ibm_40p_machine_init(MachineClass *mc) mc->default_cpu_type = POWERPC_CPU_TYPE_NAME("604"); mc->default_display = "std"; mc->default_nic = "pcnet"; + + machine_add_audiodev_property(mc); } DEFINE_MACHINE("40p", ibm_40p_machine_init) From 9dcb64c96073e9898105cdbef6553cfef0fadcdb Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Thu, 21 Sep 2023 09:51:04 +0200 Subject: [PATCH 0127/1077] vt82c686 machines: Support machine-default audiodev with fallback Signed-off-by: Paolo Bonzini --- hw/mips/fuloong2e.c | 15 ++++++++++++--- hw/ppc/pegasos2.c | 12 ++++++++++-- 2 files changed, 22 insertions(+), 5 deletions(-) diff --git a/hw/mips/fuloong2e.c b/hw/mips/fuloong2e.c index c827f615f3..c6109633fe 100644 --- a/hw/mips/fuloong2e.c +++ b/hw/mips/fuloong2e.c @@ -295,9 +295,17 @@ static void mips_fuloong2e_init(MachineState *machine) pci_bus = bonito_init((qemu_irq *)&(env->irq[2])); /* South bridge -> IP5 */ - pci_dev = pci_create_simple_multifunction(pci_bus, - PCI_DEVFN(FULOONG2E_VIA_SLOT, 0), - TYPE_VT82C686B_ISA); + pci_dev = pci_new_multifunction(PCI_DEVFN(FULOONG2E_VIA_SLOT, 0), + TYPE_VT82C686B_ISA); + + /* Set properties on individual devices before realizing the south bridge */ + if (machine->audiodev) { + dev = DEVICE(object_resolve_path_component(OBJECT(pci_dev), "ac97")); + qdev_prop_set_string(dev, "audiodev", machine->audiodev); + } + + pci_realize_and_unref(pci_dev, pci_bus, &error_abort); + object_property_add_alias(OBJECT(machine), "rtc-time", object_resolve_path_component(OBJECT(pci_dev), "rtc"), @@ -337,6 +345,7 @@ static void mips_fuloong2e_machine_init(MachineClass *mc) mc->default_ram_size = 256 * MiB; mc->default_ram_id = "fuloong2e.ram"; mc->minimum_page_bits = 14; + machine_add_audiodev_property(mc); } DEFINE_MACHINE("fuloong2e", mips_fuloong2e_machine_init) diff --git a/hw/ppc/pegasos2.c b/hw/ppc/pegasos2.c index bd397cf2b5..3203a4a728 100644 --- a/hw/ppc/pegasos2.c +++ b/hw/ppc/pegasos2.c @@ -180,8 +180,15 @@ static void pegasos2_init(MachineState *machine) pci_bus_irqs(pci_bus, pegasos2_pci_irq, pm, PCI_NUM_PINS); /* VIA VT8231 South Bridge (multifunction PCI device) */ - via = OBJECT(pci_create_simple_multifunction(pci_bus, PCI_DEVFN(12, 0), - TYPE_VT8231_ISA)); + via = OBJECT(pci_new_multifunction(PCI_DEVFN(12, 0), TYPE_VT8231_ISA)); + + /* Set properties on individual devices before realizing the south bridge */ + if (machine->audiodev) { + dev = PCI_DEVICE(object_resolve_path_component(via, "ac97")); + qdev_prop_set_string(DEVICE(dev), "audiodev", machine->audiodev); + } + + pci_realize_and_unref(PCI_DEVICE(via), pci_bus, &error_abort); for (i = 0; i < PCI_NUM_PINS; i++) { pm->via_pirq[i] = qdev_get_gpio_in_named(DEVICE(via), "pirq", i); } @@ -556,6 +563,7 @@ static void pegasos2_machine_class_init(ObjectClass *oc, void *data) mc->default_cpu_type = POWERPC_CPU_TYPE_NAME("7457_v1.2"); mc->default_ram_id = "pegasos2.ram"; mc->default_ram_size = 512 * MiB; + machine_add_audiodev_property(mc); vhc->cpu_in_nested = pegasos2_cpu_in_nested; vhc->hypercall = pegasos2_hypercall; From cb94ff5f80c537e43c04fa4f071f1df784255310 Mon Sep 17 00:00:00 2001 From: Martin Kletzander Date: Mon, 2 Oct 2023 16:27:57 +0200 Subject: [PATCH 0128/1077] audio: propagate Error * out of audio_init Starting from audio_driver_init, propagate errors via Error ** so that audio_init_audiodevs can simply pass &error_fatal, and AUD_register_card can signal faiure. Signed-off-by: Martin Kletzander [Reworked the audio/audio.c parts, while keeping Martin's hw/ changes. - Paolo] Signed-off-by: Paolo Bonzini --- audio/audio.c | 37 ++++++++++++++++++------------------- audio/audio.h | 4 ++-- hw/arm/omap2.c | 2 +- hw/audio/ac97.c | 6 +++++- hw/audio/adlib.c | 6 ++++-- hw/audio/cs4231a.c | 6 ++++-- hw/audio/es1370.c | 5 ++++- hw/audio/gus.c | 6 ++++-- hw/audio/hda-codec.c | 5 ++++- hw/audio/lm4549.c | 8 +++++--- hw/audio/pcspk.c | 4 +--- hw/audio/sb16.c | 6 ++++-- hw/audio/via-ac97.c | 6 ++++-- hw/audio/wm8750.c | 5 ++++- hw/display/xlnx_dp.c | 6 ++++-- hw/input/tsc210x.c | 2 +- hw/usb/dev-audio.c | 5 ++++- softmmu/vl.c | 4 +--- 18 files changed, 74 insertions(+), 49 deletions(-) diff --git a/audio/audio.c b/audio/audio.c index 818d79e50f..4289b7bf02 100644 --- a/audio/audio.c +++ b/audio/audio.c @@ -1556,7 +1556,7 @@ size_t audio_generic_read(HWVoiceIn *hw, void *buf, size_t size) } static int audio_driver_init(AudioState *s, struct audio_driver *drv, - bool msg, Audiodev *dev) + Audiodev *dev, Error **errp) { Error *local_err = NULL; @@ -1577,12 +1577,10 @@ static int audio_driver_init(AudioState *s, struct audio_driver *drv, s->drv = drv; return 0; } else { - if (!msg) { - error_free(local_err); - } else if (local_err) { - error_report_err(local_err); + if (local_err) { + error_propagate(errp, local_err); } else { - error_report("Could not init `%s' audio driver", drv->name); + error_setg(errp, "Could not init `%s' audio driver", drv->name); } return -1; } @@ -1733,7 +1731,7 @@ static void audio_create_default_audiodevs(void) * if dev == NULL => legacy implicit initialization, return the already created * state or create a new one */ -static AudioState *audio_init(Audiodev *dev) +static AudioState *audio_init(Audiodev *dev, Error **errp) { static bool atexit_registered; int done = 0; @@ -1760,9 +1758,9 @@ static AudioState *audio_init(Audiodev *dev) drvname = AudiodevDriver_str(dev->driver); driver = audio_driver_lookup(drvname); if (driver) { - done = !audio_driver_init(s, driver, true, dev); + done = !audio_driver_init(s, driver, dev, errp); } else { - dolog ("Unknown audio driver `%s'\n", drvname); + error_setg(errp, "Unknown audio driver `%s'\n", drvname); } if (!done) { goto out; @@ -1771,13 +1769,13 @@ static AudioState *audio_init(Audiodev *dev) for (;;) { AudiodevListEntry *e = QSIMPLEQ_FIRST(&default_audiodevs); if (!e) { - dolog("no default audio driver available\n"); + error_setg(errp, "no default audio driver available"); goto out; } s->dev = dev = e->dev; drvname = AudiodevDriver_str(dev->driver); driver = audio_driver_lookup(drvname); - if (!audio_driver_init(s, driver, false, dev)) { + if (!audio_driver_init(s, driver, dev, NULL)) { break; } QSIMPLEQ_REMOVE_HEAD(&default_audiodevs, next); @@ -1806,7 +1804,7 @@ out: return NULL; } -void AUD_register_card (const char *name, QEMUSoundCard *card) +bool AUD_register_card (const char *name, QEMUSoundCard *card, Error **errp) { if (!card->state) { if (!QTAILQ_EMPTY(&audio_states)) { @@ -1820,13 +1818,18 @@ void AUD_register_card (const char *name, QEMUSoundCard *card) if (QSIMPLEQ_EMPTY(&default_audiodevs)) { audio_create_default_audiodevs(); } - card->state = audio_init(NULL); + card->state = audio_init(NULL, errp); + if (!card->state) { + return false; + } } } card->name = g_strdup (name); memset (&card->entries, 0, sizeof (card->entries)); QLIST_INSERT_HEAD(&card->state->card_head, card, entries); + + return true; } void AUD_remove_card (QEMUSoundCard *card) @@ -2153,17 +2156,13 @@ void audio_define(Audiodev *dev) QSIMPLEQ_INSERT_TAIL(&audiodevs, e, next); } -bool audio_init_audiodevs(void) +void audio_init_audiodevs(void) { AudiodevListEntry *e; QSIMPLEQ_FOREACH(e, &audiodevs, next) { - if (!audio_init(e->dev)) { - return false; - } + audio_init(e->dev, &error_fatal); } - - return true; } audsettings audiodev_to_audsettings(AudiodevPerDirectionOptions *pdo) diff --git a/audio/audio.h b/audio/audio.h index 34df8962a6..80f3f92124 100644 --- a/audio/audio.h +++ b/audio/audio.h @@ -94,7 +94,7 @@ typedef struct QEMUAudioTimeStamp { void AUD_vlog (const char *cap, const char *fmt, va_list ap) G_GNUC_PRINTF(2, 0); void AUD_log (const char *cap, const char *fmt, ...) G_GNUC_PRINTF(2, 3); -void AUD_register_card (const char *name, QEMUSoundCard *card); +bool AUD_register_card (const char *name, QEMUSoundCard *card, Error **errp); void AUD_remove_card (QEMUSoundCard *card); CaptureVoiceOut *AUD_add_capture( AudioState *s, @@ -170,7 +170,7 @@ void audio_sample_from_uint64(void *samples, int pos, void audio_define(Audiodev *audio); void audio_parse_option(const char *opt); -bool audio_init_audiodevs(void); +void audio_init_audiodevs(void); void audio_help(void); AudioState *audio_state_by_name(const char *name, Error **errp); diff --git a/hw/arm/omap2.c b/hw/arm/omap2.c index 41b1f596dc..f170728e7e 100644 --- a/hw/arm/omap2.c +++ b/hw/arm/omap2.c @@ -614,7 +614,7 @@ static struct omap_eac_s *omap_eac_init(struct omap_target_agent_s *ta, s->codec.card.name = g_strdup(current_machine->audiodev); s->codec.card.state = audio_state_by_name(s->codec.card.name, &error_fatal); } - AUD_register_card("OMAP EAC", &s->codec.card); + AUD_register_card("OMAP EAC", &s->codec.card, &error_fatal); memory_region_init_io(&s->iomem, NULL, &omap_eac_ops, s, "omap.eac", omap_l4_region_size(ta, 0)); diff --git a/hw/audio/ac97.c b/hw/audio/ac97.c index c2a5ce062a..6a7a2dc80c 100644 --- a/hw/audio/ac97.c +++ b/hw/audio/ac97.c @@ -1273,6 +1273,10 @@ static void ac97_realize(PCIDevice *dev, Error **errp) AC97LinkState *s = AC97(dev); uint8_t *c = s->dev.config; + if (!AUD_register_card ("ac97", &s->card, errp)) { + return; + } + /* TODO: no need to override */ c[PCI_COMMAND] = 0x00; /* pcicmd pci command rw, ro */ c[PCI_COMMAND + 1] = 0x00; @@ -1306,7 +1310,7 @@ static void ac97_realize(PCIDevice *dev, Error **errp) "ac97-nabm", 256); pci_register_bar(&s->dev, 0, PCI_BASE_ADDRESS_SPACE_IO, &s->io_nam); pci_register_bar(&s->dev, 1, PCI_BASE_ADDRESS_SPACE_IO, &s->io_nabm); - AUD_register_card("ac97", &s->card); + ac97_on_reset(DEVICE(s)); } diff --git a/hw/audio/adlib.c b/hw/audio/adlib.c index 5f979b1487..bd73806d83 100644 --- a/hw/audio/adlib.c +++ b/hw/audio/adlib.c @@ -255,6 +255,10 @@ static void adlib_realizefn (DeviceState *dev, Error **errp) AdlibState *s = ADLIB(dev); struct audsettings as; + if (!AUD_register_card ("adlib", &s->card, errp)) { + return; + } + s->opl = OPLCreate (3579545, s->freq); if (!s->opl) { error_setg (errp, "OPLCreate %d failed", s->freq); @@ -270,8 +274,6 @@ static void adlib_realizefn (DeviceState *dev, Error **errp) as.fmt = AUDIO_FORMAT_S16; as.endianness = AUDIO_HOST_ENDIANNESS; - AUD_register_card ("adlib", &s->card); - s->voice = AUD_open_out ( &s->card, s->voice, diff --git a/hw/audio/cs4231a.c b/hw/audio/cs4231a.c index 5c6d643732..3aa105748d 100644 --- a/hw/audio/cs4231a.c +++ b/hw/audio/cs4231a.c @@ -678,13 +678,15 @@ static void cs4231a_realizefn (DeviceState *dev, Error **errp) return; } + if (!AUD_register_card ("cs4231a", &s->card, errp)) { + return; + } + s->pic = isa_bus_get_irq(bus, s->irq); k = ISADMA_GET_CLASS(s->isa_dma); k->register_channel(s->isa_dma, s->dma, cs_dma_read, s); isa_register_ioport (d, &s->ioports, s->port); - - AUD_register_card ("cs4231a", &s->card); } static Property cs4231a_properties[] = { diff --git a/hw/audio/es1370.c b/hw/audio/es1370.c index 4f738a0ad8..90f73d4c23 100644 --- a/hw/audio/es1370.c +++ b/hw/audio/es1370.c @@ -853,6 +853,10 @@ static void es1370_realize(PCIDevice *dev, Error **errp) ES1370State *s = ES1370(dev); uint8_t *c = s->dev.config; + if (!AUD_register_card ("es1370", &s->card, errp)) { + return; + } + c[PCI_STATUS + 1] = PCI_STATUS_DEVSEL_SLOW >> 8; #if 0 @@ -868,7 +872,6 @@ static void es1370_realize(PCIDevice *dev, Error **errp) memory_region_init_io (&s->io, OBJECT(s), &es1370_io_ops, s, "es1370", 256); pci_register_bar (&s->dev, 0, PCI_BASE_ADDRESS_SPACE_IO, &s->io); - AUD_register_card ("es1370", &s->card); es1370_reset (s); } diff --git a/hw/audio/gus.c b/hw/audio/gus.c index 787345ce54..6c2b586ca7 100644 --- a/hw/audio/gus.c +++ b/hw/audio/gus.c @@ -241,14 +241,16 @@ static void gus_realizefn (DeviceState *dev, Error **errp) IsaDmaClass *k; struct audsettings as; + if (!AUD_register_card ("gus", &s->card, errp)) { + return; + } + s->isa_dma = isa_bus_get_dma(bus, s->emu.gusdma); if (!s->isa_dma) { error_setg(errp, "ISA controller does not support DMA"); return; } - AUD_register_card ("gus", &s->card); - as.freq = s->freq; as.nchannels = 2; as.fmt = AUDIO_FORMAT_S16; diff --git a/hw/audio/hda-codec.c b/hw/audio/hda-codec.c index a26048cf15..b9ad1f4c39 100644 --- a/hw/audio/hda-codec.c +++ b/hw/audio/hda-codec.c @@ -685,11 +685,14 @@ static void hda_audio_init(HDACodecDevice *hda, const desc_param *param; uint32_t i, type; + if (!AUD_register_card("hda", &a->card, errp)) { + return; + } + a->desc = desc; a->name = object_get_typename(OBJECT(a)); dprint(a, 1, "%s: cad %d\n", __func__, a->hda.cad); - AUD_register_card("hda", &a->card); for (i = 0; i < a->desc->nnodes; i++) { node = a->desc->nodes + i; param = hda_codec_find_param(node, AC_PAR_AUDIO_WIDGET_CAP); diff --git a/hw/audio/lm4549.c b/hw/audio/lm4549.c index 418041bc9c..e7bfcc4b9f 100644 --- a/hw/audio/lm4549.c +++ b/hw/audio/lm4549.c @@ -281,6 +281,11 @@ void lm4549_init(lm4549_state *s, lm4549_callback data_req_cb, void* opaque, { struct audsettings as; + /* Register an audio card */ + if (!AUD_register_card("lm4549", &s->card, errp)) { + return; + } + /* Store the callback and opaque pointer */ s->data_req_cb = data_req_cb; s->opaque = opaque; @@ -288,9 +293,6 @@ void lm4549_init(lm4549_state *s, lm4549_callback data_req_cb, void* opaque, /* Init the registers */ lm4549_reset(s); - /* Register an audio card */ - AUD_register_card("lm4549", &s->card); - /* Open a default voice */ as.freq = 48000; as.nchannels = 2; diff --git a/hw/audio/pcspk.c b/hw/audio/pcspk.c index daf92a4ce1..fe7f07ced2 100644 --- a/hw/audio/pcspk.c +++ b/hw/audio/pcspk.c @@ -123,8 +123,6 @@ static int pcspk_audio_init(PCSpkState *s) return 0; } - AUD_register_card(s_spk, &s->card); - s->voice = AUD_open_out(&s->card, s->voice, s_spk, s, pcspk_callback, &as); if (!s->voice) { AUD_log(s_spk, "Could not open voice\n"); @@ -191,7 +189,7 @@ static void pcspk_realizefn(DeviceState *dev, Error **errp) isa_register_ioport(isadev, &s->ioport, s->iobase); - if (s->card.state) { + if (s->card.state && AUD_register_card(s_spk, &s->card, errp)) { pcspk_audio_init(s); } diff --git a/hw/audio/sb16.c b/hw/audio/sb16.c index 535ccccdc9..18f6d252db 100644 --- a/hw/audio/sb16.c +++ b/hw/audio/sb16.c @@ -1402,6 +1402,10 @@ static void sb16_realizefn (DeviceState *dev, Error **errp) SB16State *s = SB16 (dev); IsaDmaClass *k; + if (!AUD_register_card ("sb16", &s->card, errp)) { + return; + } + s->isa_hdma = isa_bus_get_dma(bus, s->hdma); s->isa_dma = isa_bus_get_dma(bus, s->dma); if (!s->isa_dma || !s->isa_hdma) { @@ -1434,8 +1438,6 @@ static void sb16_realizefn (DeviceState *dev, Error **errp) k->register_channel(s->isa_dma, s->dma, SB_read_DMA, s); s->can_write = 1; - - AUD_register_card ("sb16", &s->card); } static Property sb16_properties[] = { diff --git a/hw/audio/via-ac97.c b/hw/audio/via-ac97.c index 676254b7a4..30095a4c7a 100644 --- a/hw/audio/via-ac97.c +++ b/hw/audio/via-ac97.c @@ -426,6 +426,10 @@ static void via_ac97_realize(PCIDevice *pci_dev, Error **errp) ViaAC97State *s = VIA_AC97(pci_dev); Object *o = OBJECT(s); + if (!AUD_register_card ("via-ac97", &s->card, errp)) { + return; + } + /* * Command register Bus Master bit is documented to be fixed at 0 but it's * needed for PCI DMA to work in QEMU. The pegasos2 firmware writes 0 here @@ -445,8 +449,6 @@ static void via_ac97_realize(PCIDevice *pci_dev, Error **errp) pci_register_bar(pci_dev, 1, PCI_BASE_ADDRESS_SPACE_IO, &s->fm); memory_region_init_io(&s->midi, o, &midi_ops, s, "via-ac97.midi", 4); pci_register_bar(pci_dev, 2, PCI_BASE_ADDRESS_SPACE_IO, &s->midi); - - AUD_register_card ("via-ac97", &s->card); } static void via_ac97_exit(PCIDevice *dev) diff --git a/hw/audio/wm8750.c b/hw/audio/wm8750.c index b5722b37c3..57954a6314 100644 --- a/hw/audio/wm8750.c +++ b/hw/audio/wm8750.c @@ -624,7 +624,10 @@ static void wm8750_realize(DeviceState *dev, Error **errp) { WM8750State *s = WM8750(dev); - AUD_register_card(CODEC, &s->card); + if (!AUD_register_card(CODEC, &s->card, errp)) { + return; + } + wm8750_reset(I2C_SLAVE(s)); } diff --git a/hw/display/xlnx_dp.c b/hw/display/xlnx_dp.c index 341e91e886..eee8f33a58 100644 --- a/hw/display/xlnx_dp.c +++ b/hw/display/xlnx_dp.c @@ -1302,6 +1302,10 @@ static void xlnx_dp_realize(DeviceState *dev, Error **errp) DisplaySurface *surface; struct audsettings as; + if (!AUD_register_card("xlnx_dp.audio", &s->aud_card, errp)) { + return; + } + aux_bus_realize(s->aux_bus); qdev_realize(DEVICE(s->dpcd), BUS(s->aux_bus), &error_fatal); @@ -1320,8 +1324,6 @@ static void xlnx_dp_realize(DeviceState *dev, Error **errp) as.fmt = AUDIO_FORMAT_S16; as.endianness = 0; - AUD_register_card("xlnx_dp.audio", &s->aud_card); - s->amixer_output_stream = AUD_open_out(&s->aud_card, s->amixer_output_stream, "xlnx_dp.audio.out", diff --git a/hw/input/tsc210x.c b/hw/input/tsc210x.c index e7960a5069..950506fb38 100644 --- a/hw/input/tsc210x.c +++ b/hw/input/tsc210x.c @@ -1102,7 +1102,7 @@ static void tsc210x_init(TSC210xState *s, s->card.name = g_strdup(current_machine->audiodev); s->card.state = audio_state_by_name(s->card.name, &error_fatal); } - AUD_register_card(s->name, &s->card); + AUD_register_card(s->name, &s->card, &error_fatal); qemu_register_reset((void *) tsc210x_reset, s); vmstate_register(NULL, 0, vmsd, s); diff --git a/hw/usb/dev-audio.c b/hw/usb/dev-audio.c index 8748c1ba04..d5ac1f8962 100644 --- a/hw/usb/dev-audio.c +++ b/hw/usb/dev-audio.c @@ -944,12 +944,15 @@ static void usb_audio_realize(USBDevice *dev, Error **errp) USBAudioState *s = USB_AUDIO(dev); int i; + if (!AUD_register_card(TYPE_USB_AUDIO, &s->card, errp)) { + return; + } + dev->usb_desc = s->multi ? &desc_audio_multi : &desc_audio; usb_desc_create_serial(dev); usb_desc_init(dev); s->dev.opaque = s; - AUD_register_card(TYPE_USB_AUDIO, &s->card); s->out.altset = ALTSET_OFF; s->out.vol.mute = false; diff --git a/softmmu/vl.c b/softmmu/vl.c index cafb1a9842..98e071e63b 100644 --- a/softmmu/vl.c +++ b/softmmu/vl.c @@ -1962,9 +1962,7 @@ static void qemu_create_early_backends(void) * setting machine properties, so they can be referred to. */ configure_blockdev(&bdo_queue, machine_class, snapshot); - if (!audio_init_audiodevs()) { - exit(1); - } + audio_init_audiodevs(); } From 9f8cf356723702272af124e621e4c0e9805c8e22 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Mon, 2 Oct 2023 16:48:28 +0200 Subject: [PATCH 0129/1077] audio: forbid default audiodev backend with -nodefaults Now that all callers support setting an audiodev, forbid using the default audiodev if -nodefaults is provided on the command line. Signed-off-by: Paolo Bonzini --- audio/audio.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/audio/audio.c b/audio/audio.c index 4289b7bf02..730bf2498d 100644 --- a/audio/audio.c +++ b/audio/audio.c @@ -1692,6 +1692,10 @@ static void audio_create_default_audiodevs(void) { const char *drvname = getenv("QEMU_AUDIO_DRV"); + if (!defaults_enabled()) { + return; + } + /* QEMU_AUDIO_DRV=none is used by libqtest. */ if (drvname && !g_str_equal(drvname, "none")) { error_report("Please use -audiodev instead of QEMU_AUDIO_*"); @@ -1808,6 +1812,14 @@ bool AUD_register_card (const char *name, QEMUSoundCard *card, Error **errp) { if (!card->state) { if (!QTAILQ_EMPTY(&audio_states)) { + /* + * FIXME: once it is possible to create an arbitrary + * default device via -audio DRIVER,OPT=VALUE (no "model"), + * replace this special case with the default AudioState*, + * storing it in a separate global. For now, keep the + * warning to encourage moving off magic use of the first + * -audiodev. + */ if (QSIMPLEQ_EMPTY(&default_audiodevs)) { dolog("Device %s: audiodev default parameter is deprecated, please " "specify audiodev=%s\n", name, @@ -1820,6 +1832,10 @@ bool AUD_register_card (const char *name, QEMUSoundCard *card, Error **errp) } card->state = audio_init(NULL, errp); if (!card->state) { + if (!QSIMPLEQ_EMPTY(&audiodevs)) { + error_append_hint(errp, "Perhaps you wanted to set audiodev=%s?", + QSIMPLEQ_FIRST(&audiodevs)->dev->id); + } return false; } } From 0337e4123e62721bd0bcb4d5645fee2a31e8906d Mon Sep 17 00:00:00 2001 From: Akihiko Odaki Date: Thu, 21 Sep 2023 17:29:34 +0900 Subject: [PATCH 0130/1077] input: Allow to choose console with qemu_input_is_absolute MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Although an input is routed depending on the console, qemu_input_is_absolute() had no mechanism to specify the console. Accept QemuConsole as an argument for qemu_input_is_absolute, and let the display know the absolute/relative state for a particular console. Signed-off-by: Akihiko Odaki Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Marc-André Lureau Message-Id: <20230921082936.28100-1-akihiko.odaki@daynix.com> --- include/ui/input.h | 2 +- ui/cocoa.m | 2 +- ui/dbus-console.c | 6 +++--- ui/gtk.c | 12 ++++++------ ui/input.c | 29 +++++++---------------------- ui/sdl2.c | 26 +++++++++++++------------- ui/spice-input.c | 2 +- ui/trace-events | 1 - ui/vnc.c | 2 +- 9 files changed, 33 insertions(+), 49 deletions(-) diff --git a/include/ui/input.h b/include/ui/input.h index c29a730a71..24d8e4579e 100644 --- a/include/ui/input.h +++ b/include/ui/input.h @@ -57,7 +57,7 @@ void qemu_input_queue_btn(QemuConsole *src, InputButton btn, bool down); void qemu_input_update_buttons(QemuConsole *src, uint32_t *button_map, uint32_t button_old, uint32_t button_new); -bool qemu_input_is_absolute(void); +bool qemu_input_is_absolute(QemuConsole *con); int qemu_input_scale_axis(int value, int min_in, int max_in, int min_out, int max_out); diff --git a/ui/cocoa.m b/ui/cocoa.m index df6d13be38..145f42d190 100644 --- a/ui/cocoa.m +++ b/ui/cocoa.m @@ -2001,7 +2001,7 @@ static void cocoa_refresh(DisplayChangeListener *dcl) COCOA_DEBUG("qemu_cocoa: cocoa_refresh\n"); graphic_hw_update(NULL); - if (qemu_input_is_absolute()) { + if (qemu_input_is_absolute(dcl->con)) { dispatch_async(dispatch_get_main_queue(), ^{ if (![cocoaView isAbsoluteEnabled]) { if ([cocoaView isMouseGrabbed]) { diff --git a/ui/dbus-console.c b/ui/dbus-console.c index 36f7349585..49da9ccc83 100644 --- a/ui/dbus-console.c +++ b/ui/dbus-console.c @@ -386,7 +386,7 @@ dbus_mouse_rel_motion(DBusDisplayConsole *ddc, { trace_dbus_mouse_rel_motion(dx, dy); - if (qemu_input_is_absolute()) { + if (qemu_input_is_absolute(ddc->dcl.con)) { g_dbus_method_invocation_return_error( invocation, DBUS_DISPLAY_ERROR, DBUS_DISPLAY_ERROR_INVALID, @@ -453,7 +453,7 @@ dbus_mouse_set_pos(DBusDisplayConsole *ddc, trace_dbus_mouse_set_pos(x, y); - if (!qemu_input_is_absolute()) { + if (!qemu_input_is_absolute(ddc->dcl.con)) { g_dbus_method_invocation_return_error( invocation, DBUS_DISPLAY_ERROR, DBUS_DISPLAY_ERROR_INVALID, @@ -514,7 +514,7 @@ static void dbus_mouse_update_is_absolute(DBusDisplayConsole *ddc) { g_object_set(ddc->iface_mouse, - "is-absolute", qemu_input_is_absolute(), + "is-absolute", qemu_input_is_absolute(ddc->dcl.con), NULL); } diff --git a/ui/gtk.c b/ui/gtk.c index 3373427c9b..cd3b8953cd 100644 --- a/ui/gtk.c +++ b/ui/gtk.c @@ -204,7 +204,7 @@ static void gd_update_cursor(VirtualConsole *vc) } window = gtk_widget_get_window(GTK_WIDGET(vc->gfx.drawing_area)); - if (s->full_screen || qemu_input_is_absolute() || s->ptr_owner == vc) { + if (s->full_screen || qemu_input_is_absolute(vc->gfx.dcl.con) || s->ptr_owner == vc) { gdk_window_set_cursor(window, s->null_cursor); } else { gdk_window_set_cursor(window, NULL); @@ -453,7 +453,7 @@ static void gd_mouse_set(DisplayChangeListener *dcl, gint x_root, y_root; if (!gtk_widget_get_realized(vc->gfx.drawing_area) || - qemu_input_is_absolute()) { + qemu_input_is_absolute(dcl->con)) { return; } @@ -689,7 +689,7 @@ static void gd_mouse_mode_change(Notifier *notify, void *data) s = container_of(notify, GtkDisplayState, mouse_mode_notifier); /* release the grab at switching to absolute mode */ - if (qemu_input_is_absolute() && s->ptr_owner) { + if (s->ptr_owner && qemu_input_is_absolute(s->ptr_owner->gfx.dcl.con)) { if (!s->ptr_owner->window) { gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(s->grab_item), FALSE); @@ -903,7 +903,7 @@ static gboolean gd_motion_event(GtkWidget *widget, GdkEventMotion *motion, x = (motion->x - mx) / vc->gfx.scale_x * ws; y = (motion->y - my) / vc->gfx.scale_y * ws; - if (qemu_input_is_absolute()) { + if (qemu_input_is_absolute(vc->gfx.dcl.con)) { if (x < 0 || y < 0 || x >= surface_width(vc->gfx.ds) || y >= surface_height(vc->gfx.ds)) { @@ -923,7 +923,7 @@ static gboolean gd_motion_event(GtkWidget *widget, GdkEventMotion *motion, s->last_y = y; s->last_set = TRUE; - if (!qemu_input_is_absolute() && s->ptr_owner == vc) { + if (!qemu_input_is_absolute(vc->gfx.dcl.con) && s->ptr_owner == vc) { GdkScreen *screen = gtk_widget_get_screen(vc->gfx.drawing_area); GdkDisplay *dpy = gtk_widget_get_display(widget); GdkWindow *win = gtk_widget_get_window(widget); @@ -965,7 +965,7 @@ static gboolean gd_button_event(GtkWidget *widget, GdkEventButton *button, /* implicitly grab the input at the first click in the relative mode */ if (button->button == 1 && button->type == GDK_BUTTON_PRESS && - !qemu_input_is_absolute() && s->ptr_owner != vc) { + !qemu_input_is_absolute(vc->gfx.dcl.con) && s->ptr_owner != vc) { if (!vc->window) { gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(s->grab_item), TRUE); diff --git a/ui/input.c b/ui/input.c index 1aad64b07c..cbe8573c5c 100644 --- a/ui/input.c +++ b/ui/input.c @@ -56,7 +56,7 @@ QemuInputHandlerState *qemu_input_handler_register(DeviceState *dev, s->id = id++; QTAILQ_INSERT_TAIL(&handlers, s, node); - qemu_input_check_mode_change(); + notifier_list_notify(&mouse_mode_notifiers, NULL); return s; } @@ -64,21 +64,21 @@ void qemu_input_handler_activate(QemuInputHandlerState *s) { QTAILQ_REMOVE(&handlers, s, node); QTAILQ_INSERT_HEAD(&handlers, s, node); - qemu_input_check_mode_change(); + notifier_list_notify(&mouse_mode_notifiers, NULL); } void qemu_input_handler_deactivate(QemuInputHandlerState *s) { QTAILQ_REMOVE(&handlers, s, node); QTAILQ_INSERT_TAIL(&handlers, s, node); - qemu_input_check_mode_change(); + notifier_list_notify(&mouse_mode_notifiers, NULL); } void qemu_input_handler_unregister(QemuInputHandlerState *s) { QTAILQ_REMOVE(&handlers, s, node); g_free(s); - qemu_input_check_mode_change(); + notifier_list_notify(&mouse_mode_notifiers, NULL); } void qemu_input_handler_bind(QemuInputHandlerState *s, @@ -494,12 +494,12 @@ void qemu_input_update_buttons(QemuConsole *src, uint32_t *button_map, } } -bool qemu_input_is_absolute(void) +bool qemu_input_is_absolute(QemuConsole *con) { QemuInputHandlerState *s; s = qemu_input_find_handler(INPUT_EVENT_MASK_REL | INPUT_EVENT_MASK_ABS, - NULL); + con); return (s != NULL) && (s->handler->mask & INPUT_EVENT_MASK_ABS); } @@ -583,21 +583,6 @@ void qemu_input_queue_mtt_abs(QemuConsole *src, InputAxis axis, int value, qemu_input_event_send(src, &evt); } -void qemu_input_check_mode_change(void) -{ - static int current_is_absolute; - int is_absolute; - - is_absolute = qemu_input_is_absolute(); - - if (is_absolute != current_is_absolute) { - trace_input_mouse_mode(is_absolute); - notifier_list_notify(&mouse_mode_notifiers, NULL); - } - - current_is_absolute = is_absolute; -} - void qemu_add_mouse_mode_change_notifier(Notifier *notify) { notifier_list_add(&mouse_mode_notifiers, notify); @@ -657,6 +642,6 @@ bool qemu_mouse_set(int index, Error **errp) } qemu_input_handler_activate(s); - qemu_input_check_mode_change(); + notifier_list_notify(&mouse_mode_notifiers, NULL); return true; } diff --git a/ui/sdl2.c b/ui/sdl2.c index 178cc054ab..fbfdb64e90 100644 --- a/ui/sdl2.c +++ b/ui/sdl2.c @@ -203,7 +203,7 @@ static void sdl_hide_cursor(struct sdl2_console *scon) SDL_ShowCursor(SDL_DISABLE); SDL_SetCursor(sdl_cursor_hidden); - if (!qemu_input_is_absolute()) { + if (!qemu_input_is_absolute(scon->dcl.con)) { SDL_SetRelativeMouseMode(SDL_TRUE); } } @@ -214,12 +214,12 @@ static void sdl_show_cursor(struct sdl2_console *scon) return; } - if (!qemu_input_is_absolute()) { + if (!qemu_input_is_absolute(scon->dcl.con)) { SDL_SetRelativeMouseMode(SDL_FALSE); } if (guest_cursor && - (gui_grab || qemu_input_is_absolute() || absolute_enabled)) { + (gui_grab || qemu_input_is_absolute(scon->dcl.con) || absolute_enabled)) { SDL_SetCursor(guest_sprite); } else { SDL_SetCursor(sdl_cursor_normal); @@ -245,7 +245,7 @@ static void sdl_grab_start(struct sdl2_console *scon) } if (guest_cursor) { SDL_SetCursor(guest_sprite); - if (!qemu_input_is_absolute() && !absolute_enabled) { + if (!qemu_input_is_absolute(scon->dcl.con) && !absolute_enabled) { SDL_WarpMouseInWindow(scon->real_window, guest_x, guest_y); } } else { @@ -280,7 +280,7 @@ static void absolute_mouse_grab(struct sdl2_console *scon) static void sdl_mouse_mode_change(Notifier *notify, void *data) { - if (qemu_input_is_absolute()) { + if (qemu_input_is_absolute(sdl2_console[0].dcl.con)) { if (!absolute_enabled) { absolute_enabled = 1; SDL_SetRelativeMouseMode(SDL_FALSE); @@ -311,7 +311,7 @@ static void sdl_send_mouse_event(struct sdl2_console *scon, int dx, int dy, prev_state = state; } - if (qemu_input_is_absolute()) { + if (qemu_input_is_absolute(scon->dcl.con)) { qemu_input_queue_abs(scon->dcl.con, INPUT_AXIS_X, x, 0, surface_width(scon->surface)); qemu_input_queue_abs(scon->dcl.con, INPUT_AXIS_Y, @@ -497,7 +497,7 @@ static void handle_mousemotion(SDL_Event *ev) return; } - if (qemu_input_is_absolute() || absolute_enabled) { + if (qemu_input_is_absolute(scon->dcl.con) || absolute_enabled) { int scr_w, scr_h; SDL_GetWindowSize(scon->real_window, &scr_w, &scr_h); max_x = scr_w - 1; @@ -513,7 +513,7 @@ static void handle_mousemotion(SDL_Event *ev) sdl_grab_start(scon); } } - if (gui_grab || qemu_input_is_absolute() || absolute_enabled) { + if (gui_grab || qemu_input_is_absolute(scon->dcl.con) || absolute_enabled) { sdl_send_mouse_event(scon, ev->motion.xrel, ev->motion.yrel, ev->motion.x, ev->motion.y, ev->motion.state); } @@ -530,7 +530,7 @@ static void handle_mousebutton(SDL_Event *ev) } bev = &ev->button; - if (!gui_grab && !qemu_input_is_absolute()) { + if (!gui_grab && !qemu_input_is_absolute(scon->dcl.con)) { if (ev->type == SDL_MOUSEBUTTONUP && bev->button == SDL_BUTTON_LEFT) { /* start grabbing all events */ sdl_grab_start(scon); @@ -603,7 +603,7 @@ static void handle_windowevent(SDL_Event *ev) } /* fall through */ case SDL_WINDOWEVENT_ENTER: - if (!gui_grab && (qemu_input_is_absolute() || absolute_enabled)) { + if (!gui_grab && (qemu_input_is_absolute(scon->dcl.con) || absolute_enabled)) { absolute_mouse_grab(scon); } /* If a new console window opened using a hotkey receives the @@ -733,9 +733,9 @@ static void sdl_mouse_warp(DisplayChangeListener *dcl, if (!guest_cursor) { sdl_show_cursor(scon); } - if (gui_grab || qemu_input_is_absolute() || absolute_enabled) { + if (gui_grab || qemu_input_is_absolute(scon->dcl.con) || absolute_enabled) { SDL_SetCursor(guest_sprite); - if (!qemu_input_is_absolute() && !absolute_enabled) { + if (!qemu_input_is_absolute(scon->dcl.con) && !absolute_enabled) { SDL_WarpMouseInWindow(scon->real_window, x, y); } } @@ -773,7 +773,7 @@ static void sdl_mouse_define(DisplayChangeListener *dcl, return; } if (guest_cursor && - (gui_grab || qemu_input_is_absolute() || absolute_enabled)) { + (gui_grab || qemu_input_is_absolute(dcl->con) || absolute_enabled)) { SDL_SetCursor(guest_sprite); } } diff --git a/ui/spice-input.c b/ui/spice-input.c index bbd502564e..a5c5d78474 100644 --- a/ui/spice-input.c +++ b/ui/spice-input.c @@ -224,7 +224,7 @@ static const SpiceTabletInterface tablet_interface = { static void mouse_mode_notifier(Notifier *notifier, void *data) { QemuSpicePointer *pointer = container_of(notifier, QemuSpicePointer, mouse_mode); - bool is_absolute = qemu_input_is_absolute(); + bool is_absolute = qemu_input_is_absolute(NULL); if (pointer->absolute == is_absolute) { return; diff --git a/ui/trace-events b/ui/trace-events index 76b19a2995..16c35c9fd6 100644 --- a/ui/trace-events +++ b/ui/trace-events @@ -92,7 +92,6 @@ input_event_rel(int conidx, const char *axis, int value) "con %d, axis %s, value input_event_abs(int conidx, const char *axis, int value) "con %d, axis %s, value 0x%x" input_event_mtt(int conidx, const char *axis, int value) "con %d, axis %s, value 0x%x" input_event_sync(void) "" -input_mouse_mode(int absolute) "absolute %d" # sdl2-input.c sdl2_process_key(int sdl_scancode, int qcode, const char *action) "translated SDL scancode %d to QKeyCode %d (%s)" diff --git a/ui/vnc.c b/ui/vnc.c index 523eb1f5b0..c66477a390 100644 --- a/ui/vnc.c +++ b/ui/vnc.c @@ -1771,7 +1771,7 @@ uint32_t read_u32(uint8_t *data, size_t offset) static void check_pointer_type_change(Notifier *notifier, void *data) { VncState *vs = container_of(notifier, VncState, mouse_mode_notifier); - int absolute = qemu_input_is_absolute(); + int absolute = qemu_input_is_absolute(vs->vd->dcl.con); if (vnc_has_feature(vs, VNC_FEATURE_POINTER_TYPE_CHANGE) && vs->absolute != absolute) { vnc_lock_output(vs); From 845fff1f83ac87f592b5b0fa01c37844ea8cc9f9 Mon Sep 17 00:00:00 2001 From: Laszlo Ersek Date: Wed, 13 Sep 2023 16:49:56 +0200 Subject: [PATCH 0131/1077] ui/console: make qemu_console_is_multihead() static MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit qemu_console_is_multihead() is only called from within "ui/console.c"; make it static. Cc: "Marc-André Lureau" (odd fixer:Graphics) Cc: Gerd Hoffmann (odd fixer:Graphics) Signed-off-by: Laszlo Ersek Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Marc-André Lureau Message-ID: <20230913144959.41891-2-lersek@redhat.com> --- include/ui/console.h | 1 - ui/console.c | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/include/ui/console.h b/include/ui/console.h index 28882f15a5..acb61a7f15 100644 --- a/include/ui/console.h +++ b/include/ui/console.h @@ -422,7 +422,6 @@ bool qemu_console_is_visible(QemuConsole *con); bool qemu_console_is_graphic(QemuConsole *con); bool qemu_console_is_fixedsize(QemuConsole *con); bool qemu_console_is_gl_blocked(QemuConsole *con); -bool qemu_console_is_multihead(DeviceState *dev); char *qemu_console_get_label(QemuConsole *con); int qemu_console_get_index(QemuConsole *con); uint32_t qemu_console_get_head(QemuConsole *con); diff --git a/ui/console.c b/ui/console.c index 4a4f19ed33..d17b4ee397 100644 --- a/ui/console.c +++ b/ui/console.c @@ -1434,7 +1434,7 @@ bool qemu_console_is_gl_blocked(QemuConsole *con) return con->gl_block; } -bool qemu_console_is_multihead(DeviceState *dev) +static bool qemu_console_is_multihead(DeviceState *dev) { QemuConsole *con; Object *obj; From 4ce2f97c000629531553328e1871b56312a210cf Mon Sep 17 00:00:00 2001 From: Laszlo Ersek Date: Wed, 13 Sep 2023 16:49:57 +0200 Subject: [PATCH 0132/1077] ui/console: only walk QemuGraphicConsoles in qemu_console_is_multihead() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit qemu_console_is_multihead() declares the console "c" a "multihead" console if there are two different consoles in the system that (a) both reference "c->device", and (b) have different "c->head" numbers. In effect, if at least two consoles exist that are different heads of the same device that underlies "c". Commit 58d5870845c6 ("ui/console: move graphic fields to QemuGraphicConsole", 2023-09-04) pushed the "device" and "head" members from the QemuConsole base class down to the QemuGraphicConsole subclass, adjusting the referring QOM properties accordingly as well. As a result, the "device" property lookup in qemu_console_is_multihead() now crashes, in case the candidate console being investigated for criterion (a) is not a QemuGraphicConsole instance: > Unexpected error in object_property_find_err() at qom/object.c:1314: > qemu: Property 'qemu-fixed-text-console.device' not found > Aborted (core dumped) This is effectively an unchecked downcast. Make it checked: only consider such console candidates that are themselves QemuGraphicConsole instances. Cc: "Marc-André Lureau" (odd fixer:Graphics) Cc: Gerd Hoffmann (odd fixer:Graphics) Fixes: 58d5870845c6 Signed-off-by: Laszlo Ersek Reviewed-by: Marc-André Lureau Message-ID: <20230913144959.41891-3-lersek@redhat.com> --- ui/console.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/ui/console.c b/ui/console.c index d17b4ee397..4fe26c08fb 100644 --- a/ui/console.c +++ b/ui/console.c @@ -1442,6 +1442,9 @@ static bool qemu_console_is_multihead(DeviceState *dev) uint32_t h; QTAILQ_FOREACH(con, &consoles, next) { + if (!QEMU_IS_GRAPHIC_CONSOLE(con)) { + continue; + } obj = object_property_get_link(OBJECT(con), "device", &error_abort); if (DEVICE(obj) != dev) { From 2c0c4c1f650d48c814df5a8b48544ea44918bd8f Mon Sep 17 00:00:00 2001 From: Laszlo Ersek Date: Wed, 13 Sep 2023 16:49:58 +0200 Subject: [PATCH 0133/1077] ui/console: eliminate QOM properties from qemu_console_is_multihead() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit According to Marc-André's and Gerd's descriptions, the "device" and "head" members of QemuGraphicConsole are exposed as QOM properties for two purposes: (1) Introspection (e.g., "qom-get" monitor command). (2) A VNC server can display a specific device + head. This lets us run a multihead configuration by using multiple VNC servers (one for each head). Further, we can link input devices to device + head, so input events are routed to different devices dependent on where they are coming from. Which is most useful for tablet devices in a VNC multihead setup, each head has its own tablet device then. This does requires manual guest-side configuration, for establishing the same tablet <-> head relationship. However, neither goal seems to justify the complicated QOM property lookup that's internal to qemu_console_is_multihead(). Rework qemu_console_is_multihead() with plain old C language field accesses. Cc: "Marc-André Lureau" (odd fixer:Graphics) Cc: Gerd Hoffmann (odd fixer:Graphics) Signed-off-by: Laszlo Ersek Reviewed-by: Marc-André Lureau Message-ID: <20230913144959.41891-4-lersek@redhat.com> --- ui/console.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/ui/console.c b/ui/console.c index 4fe26c08fb..65463d84a7 100644 --- a/ui/console.c +++ b/ui/console.c @@ -1434,25 +1434,25 @@ bool qemu_console_is_gl_blocked(QemuConsole *con) return con->gl_block; } -static bool qemu_console_is_multihead(DeviceState *dev) +static bool qemu_graphic_console_is_multihead(QemuGraphicConsole *c) { QemuConsole *con; - Object *obj; uint32_t f = 0xffffffff; uint32_t h; QTAILQ_FOREACH(con, &consoles, next) { + QemuGraphicConsole *candidate; + if (!QEMU_IS_GRAPHIC_CONSOLE(con)) { continue; } - obj = object_property_get_link(OBJECT(con), - "device", &error_abort); - if (DEVICE(obj) != dev) { + + candidate = QEMU_GRAPHIC_CONSOLE(con); + if (candidate->device != c->device) { continue; } - h = object_property_get_uint(OBJECT(con), - "head", &error_abort); + h = candidate->head; if (f == 0xffffffff) { f = h; } else if (h != f) { @@ -1471,7 +1471,7 @@ char *qemu_console_get_label(QemuConsole *con) bool multihead; dev = DEVICE(c->device); - multihead = qemu_console_is_multihead(dev); + multihead = qemu_graphic_console_is_multihead(c); if (multihead) { return g_strdup_printf("%s.%d", dev->id ? dev->id : From 65d7ceb49b434d578cee61467c009cb16a794b16 Mon Sep 17 00:00:00 2001 From: Laszlo Ersek Date: Wed, 13 Sep 2023 16:49:59 +0200 Subject: [PATCH 0134/1077] ui/console: sanitize search in qemu_graphic_console_is_multihead() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit qemu_graphic_console_is_multihead() declares the graphical console "c" a "multihead" console if there are two different graphical consoles in the system that (a) both reference "c->device", and (b) have different "c->head" numbers. In effect, if at least two graphical consoles exist that are different heads of the same device that underlies "c". In fact, "c" may be one of these two graphical consoles, or "c" may differ from both of those consoles (in case "c->device" has at least three heads). The loop currently uses this awkward "two different consoles" approach because the function used not to have access to "c", only to "c->device", which didn't allow for fetching (and comparing) "c->head". But, we've changed that in the last patch; we now pass all of "c" to qemu_graphic_console_is_multihead(). Thus, look for the *first* (and possibly *only*) graphical console, if any, that refers to the same "device" as "c", but by a different "head" number. Cc: "Marc-André Lureau" (odd fixer:Graphics) Cc: Gerd Hoffmann (odd fixer:Graphics) Signed-off-by: Laszlo Ersek Reviewed-by: Marc-André Lureau Message-ID: <20230913144959.41891-5-lersek@redhat.com> --- ui/console.c | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/ui/console.c b/ui/console.c index 65463d84a7..8ee66d10c5 100644 --- a/ui/console.c +++ b/ui/console.c @@ -1437,8 +1437,6 @@ bool qemu_console_is_gl_blocked(QemuConsole *con) static bool qemu_graphic_console_is_multihead(QemuGraphicConsole *c) { QemuConsole *con; - uint32_t f = 0xffffffff; - uint32_t h; QTAILQ_FOREACH(con, &consoles, next) { QemuGraphicConsole *candidate; @@ -1452,10 +1450,7 @@ static bool qemu_graphic_console_is_multihead(QemuGraphicConsole *c) continue; } - h = candidate->head; - if (f == 0xffffffff) { - f = h; - } else if (h != f) { + if (candidate->head != c->head) { return true; } } From 7db57a73f66463488fbd53fe5f9589de49534fe8 Mon Sep 17 00:00:00 2001 From: Ken Xue Date: Thu, 14 Sep 2023 09:31:51 +0800 Subject: [PATCH 0135/1077] ui: add XBGR8888 and ABGR8888 in drm_format_pixman_map MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Android uses XBGR8888 and ABGR8888 as default scanout buffer, But qemu does not support them for qemu_pixman_to_drm_format conversion within virtio_gpu_create_dmabuf for virtio gpu. so, add those 2 formats into drm_format_pixman_map. Signed-off-by: Ken Xue Reviewed-by: Marc-André Lureau Message-ID: <20230914013151.805363-1-Ken.Xue@amd.com> --- include/ui/qemu-pixman.h | 4 ++++ ui/qemu-pixman.c | 4 +++- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/include/ui/qemu-pixman.h b/include/ui/qemu-pixman.h index 51f8709327..e587c48b1f 100644 --- a/include/ui/qemu-pixman.h +++ b/include/ui/qemu-pixman.h @@ -32,6 +32,8 @@ # define PIXMAN_LE_r8g8b8 PIXMAN_b8g8r8 # define PIXMAN_LE_a8r8g8b8 PIXMAN_b8g8r8a8 # define PIXMAN_LE_x8r8g8b8 PIXMAN_b8g8r8x8 +# define PIXMAN_LE_a8b8g8r8 PIXMAN_r8g8b8a8 +# define PIXMAN_LE_x8b8g8r8 PIXMAN_r8g8b8x8 #else # define PIXMAN_BE_r8g8b8 PIXMAN_b8g8r8 # define PIXMAN_BE_x8r8g8b8 PIXMAN_b8g8r8x8 @@ -45,6 +47,8 @@ # define PIXMAN_LE_r8g8b8 PIXMAN_r8g8b8 # define PIXMAN_LE_a8r8g8b8 PIXMAN_a8r8g8b8 # define PIXMAN_LE_x8r8g8b8 PIXMAN_x8r8g8b8 +# define PIXMAN_LE_a8b8g8r8 PIXMAN_a8b8g8r8 +# define PIXMAN_LE_x8b8g8r8 PIXMAN_x8b8g8r8 #endif #define QEMU_PIXMAN_COLOR(r, g, b) \ diff --git a/ui/qemu-pixman.c b/ui/qemu-pixman.c index be00a96340..b43ec38bf0 100644 --- a/ui/qemu-pixman.c +++ b/ui/qemu-pixman.c @@ -96,7 +96,9 @@ static const struct { } drm_format_pixman_map[] = { { DRM_FORMAT_RGB888, PIXMAN_LE_r8g8b8 }, { DRM_FORMAT_ARGB8888, PIXMAN_LE_a8r8g8b8 }, - { DRM_FORMAT_XRGB8888, PIXMAN_LE_x8r8g8b8 } + { DRM_FORMAT_XRGB8888, PIXMAN_LE_x8r8g8b8 }, + { DRM_FORMAT_XBGR8888, PIXMAN_LE_x8b8g8r8 }, + { DRM_FORMAT_ABGR8888, PIXMAN_LE_a8b8g8r8 }, }; pixman_format_code_t qemu_drm_format_to_pixman(uint32_t drm_format) From 75b773d84c89220463a14a6883d2b2a8e49e5b68 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= Date: Mon, 25 Sep 2023 15:36:04 +0400 Subject: [PATCH 0136/1077] win32: avoid discarding the exception handler MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In all likelihood, the compiler with lto doesn't see the function being used, from assembly macro __try1. Help it by marking the function has being used. Resolves: https://gitlab.com/qemu-project/qemu/-/issues/1904 Fixes: commit d89f30b4df ("win32: wrap socket close() with an exception handler") Signed-off-by: Marc-André Lureau Reviewed-by: Thomas Huth --- include/qemu/compiler.h | 6 ++++++ util/oslib-win32.c | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/include/qemu/compiler.h b/include/qemu/compiler.h index 7f1bbbf05f..1109482a00 100644 --- a/include/qemu/compiler.h +++ b/include/qemu/compiler.h @@ -206,4 +206,10 @@ #define QEMU_ANNOTATE(x) #endif +#if __has_attribute(used) +# define QEMU_USED __attribute__((used)) +#else +# define QEMU_USED +#endif + #endif /* COMPILER_H */ diff --git a/util/oslib-win32.c b/util/oslib-win32.c index 19a0ea7fbe..55b0189dc3 100644 --- a/util/oslib-win32.c +++ b/util/oslib-win32.c @@ -479,7 +479,7 @@ int qemu_bind_wrap(int sockfd, const struct sockaddr *addr, return ret; } -EXCEPTION_DISPOSITION +QEMU_USED EXCEPTION_DISPOSITION win32_close_exception_handler(struct _EXCEPTION_RECORD *exception_record, void *registration, struct _CONTEXT *context, void *dispatcher) From 9bd4d3df633593878ada3dffcfe05318754b4596 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= Date: Fri, 15 Sep 2023 15:28:31 +0400 Subject: [PATCH 0137/1077] ui/gtk: fix UI info precondition MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit dpy_get_ui_info() shouldn't be called if the underlying GPU doesn't support it. Before the assert() was added and the regression introduced, GTK code used to get "zero" UI info, for ex with a simple VGA device. The assert was added to prevent from calling when there are no console too. The other display backend that calls dpy_get_ui_info() correctly checks that pre-condition. Calling dpy_set_ui_info() is "safe" in this case, it will simply return an error that can be generally ignored. Fixes: commit a92e7bb4c ("ui: add precondition for dpy_get_ui_info()") Signed-off-by: Marc-André Lureau --- ui/gtk.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/ui/gtk.c b/ui/gtk.c index cd3b8953cd..935de1209b 100644 --- a/ui/gtk.c +++ b/ui/gtk.c @@ -726,6 +726,10 @@ static void gd_set_ui_refresh_rate(VirtualConsole *vc, int refresh_rate) { QemuUIInfo info; + if (!dpy_ui_info_supported(vc->gfx.dcl.con)) { + return; + } + info = *dpy_get_ui_info(vc->gfx.dcl.con); info.refresh_rate = refresh_rate; dpy_set_ui_info(vc->gfx.dcl.con, &info, true); @@ -735,6 +739,10 @@ static void gd_set_ui_size(VirtualConsole *vc, gint width, gint height) { QemuUIInfo info; + if (!dpy_ui_info_supported(vc->gfx.dcl.con)) { + return; + } + info = *dpy_get_ui_info(vc->gfx.dcl.con); info.width = width; info.height = height; From f1de309792d6656ef3443ba65272c4a868a43914 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= Date: Wed, 20 Sep 2023 11:54:54 +0400 Subject: [PATCH 0138/1077] analyze-migration: ignore RAM_SAVE_FLAG_MULTIFD_FLUSH MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Traceback (most recent call last): File "scripts/analyze-migration.py", line 605, in dump.read(dump_memory = args.memory) File "scripts/analyze-migration.py", line 542, in read section.read() File "scripts/analyze-migration.py", line 214, in read raise Exception("Unknown RAM flags: %x" % flags) Exception: Unknown RAM flags: 200 See commit 77c259a4cb ("multifd: Create property multifd-flush-after-each-section") Signed-off-by: Marc-André Lureau Reviewed-by: Fabiano Rosas --- scripts/analyze-migration.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/scripts/analyze-migration.py b/scripts/analyze-migration.py index b82a1b0c58..082424558b 100755 --- a/scripts/analyze-migration.py +++ b/scripts/analyze-migration.py @@ -111,6 +111,8 @@ class RamSection(object): RAM_SAVE_FLAG_CONTINUE = 0x20 RAM_SAVE_FLAG_XBZRLE = 0x40 RAM_SAVE_FLAG_HOOK = 0x80 + RAM_SAVE_FLAG_COMPRESS_PAGE = 0x100 + RAM_SAVE_FLAG_MULTIFD_FLUSH = 0x200 def __init__(self, file, version_id, ramargs, section_key): if version_id != 4: @@ -205,6 +207,8 @@ class RamSection(object): raise Exception("XBZRLE RAM compression is not supported yet") elif flags & self.RAM_SAVE_FLAG_HOOK: raise Exception("RAM hooks don't make sense with files") + if flags & self.RAM_SAVE_FLAG_MULTIFD_FLUSH: + continue # End of RAM section if flags & self.RAM_SAVE_FLAG_EOS: From 314e0a84cd5d3a8d04c9778eecb5618dee3574cf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= Date: Mon, 2 Oct 2023 14:27:36 +0400 Subject: [PATCH 0139/1077] hw/core: remove needless includes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The include list is large, make it smaller. Signed-off-by: Marc-André Lureau Acked-by: Laszlo Ersek --- hw/core/machine.c | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/hw/core/machine.c b/hw/core/machine.c index a232ae0bcd..df40f10dfa 100644 --- a/hw/core/machine.c +++ b/hw/core/machine.c @@ -11,32 +11,22 @@ */ #include "qemu/osdep.h" -#include "qemu/option.h" #include "qemu/accel.h" #include "sysemu/replay.h" -#include "qemu/units.h" #include "hw/boards.h" #include "hw/loader.h" #include "qapi/error.h" -#include "qapi/qapi-visit-common.h" #include "qapi/qapi-visit-machine.h" -#include "qapi/visitor.h" #include "qom/object_interfaces.h" -#include "hw/sysbus.h" #include "sysemu/cpus.h" #include "sysemu/sysemu.h" #include "sysemu/reset.h" #include "sysemu/runstate.h" -#include "sysemu/numa.h" #include "sysemu/xen.h" -#include "qemu/error-report.h" #include "sysemu/qtest.h" -#include "hw/pci/pci.h" #include "hw/mem/nvdimm.h" #include "migration/global_state.h" -#include "migration/vmstate.h" #include "exec/confidential-guest-support.h" -#include "hw/virtio/virtio.h" #include "hw/virtio/virtio-pci.h" #include "hw/virtio/virtio-net.h" From bf7e5215c40c9c38067798fdced94623f2ee0201 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= Date: Mon, 2 Oct 2023 14:27:36 +0400 Subject: [PATCH 0140/1077] hw/pc: remove needless includes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The include list is gigantic, make it smaller. Signed-off-by: Marc-André Lureau Acked-by: Laszlo Ersek --- hw/i386/pc.c | 39 --------------------------------------- 1 file changed, 39 deletions(-) diff --git a/hw/i386/pc.c b/hw/i386/pc.c index 5d399b6247..ec01d74482 100644 --- a/hw/i386/pc.c +++ b/hw/i386/pc.c @@ -24,79 +24,40 @@ #include "qemu/osdep.h" #include "qemu/units.h" -#include "hw/i386/x86.h" #include "hw/i386/pc.h" #include "hw/char/serial.h" #include "hw/char/parallel.h" -#include "hw/i386/topology.h" #include "hw/i386/fw_cfg.h" #include "hw/i386/vmport.h" #include "sysemu/cpus.h" -#include "hw/block/fdc.h" #include "hw/ide/internal.h" -#include "hw/ide/isa.h" -#include "hw/pci/pci.h" -#include "hw/pci/pci_bus.h" -#include "hw/pci-bridge/pci_expander_bridge.h" -#include "hw/nvram/fw_cfg.h" #include "hw/timer/hpet.h" -#include "hw/firmware/smbios.h" #include "hw/loader.h" -#include "elf.h" -#include "migration/vmstate.h" -#include "multiboot.h" #include "hw/rtc/mc146818rtc.h" #include "hw/intc/i8259.h" -#include "hw/intc/ioapic.h" #include "hw/timer/i8254.h" #include "hw/input/i8042.h" -#include "hw/irq.h" #include "hw/audio/pcspk.h" -#include "hw/pci/msi.h" -#include "hw/sysbus.h" #include "sysemu/sysemu.h" -#include "sysemu/tcg.h" -#include "sysemu/numa.h" -#include "sysemu/kvm.h" #include "sysemu/xen.h" #include "sysemu/reset.h" -#include "sysemu/runstate.h" #include "kvm/kvm_i386.h" #include "hw/xen/xen.h" -#include "hw/xen/start_info.h" -#include "ui/qemu-spice.h" -#include "exec/memory.h" -#include "qemu/bitmap.h" -#include "qemu/config-file.h" #include "qemu/error-report.h" -#include "qemu/option.h" -#include "qemu/cutils.h" -#include "hw/acpi/acpi.h" #include "hw/acpi/cpu_hotplug.h" #include "acpi-build.h" -#include "hw/mem/pc-dimm.h" #include "hw/mem/nvdimm.h" -#include "hw/cxl/cxl.h" #include "hw/cxl/cxl_host.h" -#include "qapi/error.h" -#include "qapi/qapi-visit-common.h" -#include "qapi/qapi-visit-machine.h" -#include "qapi/visitor.h" -#include "hw/core/cpu.h" #include "hw/usb.h" #include "hw/i386/intel_iommu.h" #include "hw/net/ne2000-isa.h" -#include "standard-headers/asm-x86/bootparam.h" #include "hw/virtio/virtio-iommu.h" #include "hw/virtio/virtio-md-pci.h" #include "hw/i386/kvm/xen_overlay.h" #include "hw/i386/kvm/xen_evtchn.h" #include "hw/i386/kvm/xen_gnttab.h" #include "hw/i386/kvm/xen_xenstore.h" -#include "sysemu/replay.h" -#include "target/i386/cpu.h" #include "e820_memory_layout.h" -#include "fw_cfg.h" #include "trace.h" #include CONFIG_DEVICES From e0288a778473ebd35eac6cc1924faca7d477d241 Mon Sep 17 00:00:00 2001 From: Laszlo Ersek Date: Tue, 19 Sep 2023 15:19:55 +0200 Subject: [PATCH 0141/1077] hw/display/ramfb: plug slight guest-triggerable leak on mode setting MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The fw_cfg DMA write callback in ramfb prepares a new display surface in QEMU; this new surface is put to use ("swapped in") upon the next display update. At that time, the old surface (if any) is released. If the guest triggers the fw_cfg DMA write callback at least twice between two adjacent display updates, then the second callback (and further such callbacks) will leak the previously prepared (but not yet swapped in) display surface. The issue can be shown by: (1) starting QEMU with "-trace displaysurface_free", and (2) running the following program in the guest UEFI shell: > #include // ShellAppMain() > #include // gBS > #include // EFI_GRAPHICS_OUTPUT_PROTOCOL > > INTN > EFIAPI > ShellAppMain ( > IN UINTN Argc, > IN CHAR16 **Argv > ) > { > EFI_STATUS Status; > VOID *Interface; > EFI_GRAPHICS_OUTPUT_PROTOCOL *Gop; > UINT32 Mode; > > Status = gBS->LocateProtocol ( > &gEfiGraphicsOutputProtocolGuid, > NULL, > &Interface > ); > if (EFI_ERROR (Status)) { > return 1; > } > > Gop = Interface; > > Mode = 1; > for ( ; ;) { > Status = Gop->SetMode (Gop, Mode); > if (EFI_ERROR (Status)) { > break; > } > > Mode = 1 - Mode; > } > > return 1; > } The symptom is then that: - only one trace message appears periodically, - the time between adjacent messages keeps increasing -- implying that some list structure (containing the leaked resources) keeps growing, - the "surface" pointer is ever different. > 18566@1695127471.449586:displaysurface_free surface=0x7f2fcc09a7c0 > 18566@1695127471.529559:displaysurface_free surface=0x7f2fcc9dac10 > 18566@1695127471.659812:displaysurface_free surface=0x7f2fcc441dd0 > 18566@1695127471.839669:displaysurface_free surface=0x7f2fcc0363d0 > 18566@1695127472.069674:displaysurface_free surface=0x7f2fcc413a80 > 18566@1695127472.349580:displaysurface_free surface=0x7f2fcc09cd00 > 18566@1695127472.679783:displaysurface_free surface=0x7f2fcc1395f0 > 18566@1695127473.059848:displaysurface_free surface=0x7f2fcc1cae50 > 18566@1695127473.489724:displaysurface_free surface=0x7f2fcc42fc50 > 18566@1695127473.969791:displaysurface_free surface=0x7f2fcc45dcc0 > 18566@1695127474.499708:displaysurface_free surface=0x7f2fcc70b9d0 > 18566@1695127475.079769:displaysurface_free surface=0x7f2fcc82acc0 > 18566@1695127475.709941:displaysurface_free surface=0x7f2fcc369c00 > 18566@1695127476.389619:displaysurface_free surface=0x7f2fcc32b910 > 18566@1695127477.119772:displaysurface_free surface=0x7f2fcc0d5a20 > 18566@1695127477.899517:displaysurface_free surface=0x7f2fcc086c40 > 18566@1695127478.729962:displaysurface_free surface=0x7f2fccc72020 > 18566@1695127479.609839:displaysurface_free surface=0x7f2fcc185160 > 18566@1695127480.539688:displaysurface_free surface=0x7f2fcc23a7e0 > 18566@1695127481.519759:displaysurface_free surface=0x7f2fcc3ec870 > 18566@1695127482.549930:displaysurface_free surface=0x7f2fcc634960 > 18566@1695127483.629661:displaysurface_free surface=0x7f2fcc26b140 > 18566@1695127484.759987:displaysurface_free surface=0x7f2fcc321700 > 18566@1695127485.940289:displaysurface_free surface=0x7f2fccaad100 We figured this wasn't a CVE-worthy problem, as only small amounts of memory were leaked (the framebuffer itself is mapped from guest RAM, QEMU only allocates administrative structures), plus libvirt restricts QEMU memory footprint anyway, thus the guest can only DoS itself. Plug the leak, by releasing the last prepared (not yet swapped in) display surface, if any, in the fw_cfg DMA write callback. Regarding the "reproducer", with the fix in place, the log is flooded with trace messages (one per fw_cfg write), *and* the trace message alternates between just two "surface" pointer values (i.e., nothing is leaked, the allocator flip-flops between two objects in effect). This issue appears to date back to the introducion of ramfb (995b30179bdc, "hw/display: add ramfb, a simple boot framebuffer living in guest ram", 2018-06-18). Cc: Gerd Hoffmann (maintainer:ramfb) Cc: qemu-stable@nongnu.org Fixes: 995b30179bdc Signed-off-by: Laszlo Ersek Acked-by: Laszlo Ersek Reviewed-by: Gerd Hoffmann Reviewed-by: Marc-André Lureau Message-ID: <20230919131955.27223-1-lersek@redhat.com> --- hw/display/ramfb.c | 1 + 1 file changed, 1 insertion(+) diff --git a/hw/display/ramfb.c b/hw/display/ramfb.c index 79b9754a58..c2b002d534 100644 --- a/hw/display/ramfb.c +++ b/hw/display/ramfb.c @@ -97,6 +97,7 @@ static void ramfb_fw_cfg_write(void *dev, off_t offset, size_t len) s->width = width; s->height = height; + qemu_free_displaysurface(s->ds); s->ds = surface; } From 4f7689f0817a717d18cc8aca298990760f27a89b Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Wed, 16 Aug 2023 23:07:43 +0200 Subject: [PATCH 0142/1077] chardev/char-pty: Avoid losing bytes when the other side just (re-)connected MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When starting a guest via libvirt with "virsh start --console ...", the first second of the console output is missing. This is especially annoying on s390x that only has a text console by default and no graphical output - if the bios fails to boot here, the information about what went wrong is completely lost. One part of the problem (there is also some things to be done on the libvirt side) is that QEMU only checks with a 1 second timer whether the other side of the pty is already connected, so the first second of the console output is always lost. This likely used to work better in the past, since the code once checked for a re-connection during write, but this has been removed in commit f8278c7d74 ("char-pty: remove the check for connection on write") to avoid some locking. To ease the situation here at least a little bit, let's check with g_poll() whether we could send out the data anyway, even if the connection has not been marked as "connected" yet. The file descriptor is marked as non-blocking anyway since commit fac6688a18 ("Do not hang on full PTY"), so this should not cause any trouble if the other side is not ready for receiving yet. With this patch applied, I can now successfully see the bios output of a s390x guest when running it with "virsh start --console" (with a patched version of virsh that fixes the remaining issues there, too). Reported-by: Marc Hartmayer Signed-off-by: Thomas Huth Reviewed-by: Daniel P. Berrangé Message-Id: <20230816210743.1319018-1-thuth@redhat.com> --- chardev/char-pty.c | 22 +++++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) diff --git a/chardev/char-pty.c b/chardev/char-pty.c index 4e5deac18a..cc2f7617fe 100644 --- a/chardev/char-pty.c +++ b/chardev/char-pty.c @@ -106,11 +106,27 @@ static void pty_chr_update_read_handler(Chardev *chr) static int char_pty_chr_write(Chardev *chr, const uint8_t *buf, int len) { PtyChardev *s = PTY_CHARDEV(chr); + GPollFD pfd; + int rc; - if (!s->connected) { - return len; + if (s->connected) { + return io_channel_send(s->ioc, buf, len); } - return io_channel_send(s->ioc, buf, len); + + /* + * The other side might already be re-connected, but the timer might + * not have fired yet. So let's check here whether we can write again: + */ + pfd.fd = QIO_CHANNEL_FILE(s->ioc)->fd; + pfd.events = G_IO_OUT; + pfd.revents = 0; + rc = RETRY_ON_EINTR(g_poll(&pfd, 1, 0)); + g_assert(rc >= 0); + if (!(pfd.revents & G_IO_HUP) && (pfd.revents & G_IO_OUT)) { + io_channel_send(s->ioc, buf, len); + } + + return len; } static GSource *pty_chr_add_watch(Chardev *chr, GIOCondition cond) From e5dc722ca9f8b02da21e0fd7852a44b65a5686c6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Tue, 3 Oct 2023 14:30:19 +0200 Subject: [PATCH 0143/1077] accel: Rename accel_cpu_realizefn() -> accel_cpu_realize() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We use the '*fn' suffix for handlers, this is a public method. Drop the suffix. Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Claudio Fontana Message-Id: <20231003123026.99229-2-philmd@linaro.org> Signed-off-by: Richard Henderson --- accel/accel-common.c | 2 +- cpu.c | 2 +- include/qemu/accel.h | 4 ++-- target/i386/kvm/kvm-cpu.c | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/accel/accel-common.c b/accel/accel-common.c index df72cc989a..b953855e8b 100644 --- a/accel/accel-common.c +++ b/accel/accel-common.c @@ -119,7 +119,7 @@ void accel_cpu_instance_init(CPUState *cpu) } } -bool accel_cpu_realizefn(CPUState *cpu, Error **errp) +bool accel_cpu_realize(CPUState *cpu, Error **errp) { CPUClass *cc = CPU_GET_CLASS(cpu); diff --git a/cpu.c b/cpu.c index 0769b0b153..61c9760e62 100644 --- a/cpu.c +++ b/cpu.c @@ -136,7 +136,7 @@ void cpu_exec_realizefn(CPUState *cpu, Error **errp) /* cache the cpu class for the hotpath */ cpu->cc = CPU_GET_CLASS(cpu); - if (!accel_cpu_realizefn(cpu, errp)) { + if (!accel_cpu_realize(cpu, errp)) { return; } diff --git a/include/qemu/accel.h b/include/qemu/accel.h index e84db2e3e5..cb64a07b84 100644 --- a/include/qemu/accel.h +++ b/include/qemu/accel.h @@ -90,11 +90,11 @@ void accel_setup_post(MachineState *ms); void accel_cpu_instance_init(CPUState *cpu); /** - * accel_cpu_realizefn: + * accel_cpu_realize: * @cpu: The CPU that needs to call accel-specific cpu realization. * @errp: currently unused. */ -bool accel_cpu_realizefn(CPUState *cpu, Error **errp); +bool accel_cpu_realize(CPUState *cpu, Error **errp); /** * accel_supported_gdbstub_sstep_flags: diff --git a/target/i386/kvm/kvm-cpu.c b/target/i386/kvm/kvm-cpu.c index 7237378a7d..4474689f81 100644 --- a/target/i386/kvm/kvm-cpu.c +++ b/target/i386/kvm/kvm-cpu.c @@ -35,7 +35,7 @@ static bool kvm_cpu_realizefn(CPUState *cs, Error **errp) * x86_cpu_realize(): * -> x86_cpu_expand_features() * -> cpu_exec_realizefn(): - * -> accel_cpu_realizefn() + * -> accel_cpu_realize() * kvm_cpu_realizefn() -> host_cpu_realizefn() * -> check/update ucode_rev, phys_bits, mwait */ From 6294e502a95e64f75d63bd95c5a24aa4d7f00196 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Tue, 3 Oct 2023 14:30:20 +0200 Subject: [PATCH 0144/1077] accel: Rename AccelCPUClass::cpu_realizefn() -> cpu_target_realize() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The AccelCPUClass::cpu_realizefn handler is meant for target specific code, rename it using '_target_' to emphasis it. Suggested-by: Claudio Fontana Signed-off-by: Philippe Mathieu-Daudé Message-Id: <20231003123026.99229-3-philmd@linaro.org> Signed-off-by: Richard Henderson --- accel/accel-common.c | 4 ++-- include/hw/core/accel-cpu.h | 2 +- target/i386/hvf/hvf-cpu.c | 2 +- target/i386/kvm/kvm-cpu.c | 2 +- target/i386/tcg/tcg-cpu.c | 2 +- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/accel/accel-common.c b/accel/accel-common.c index b953855e8b..2e30b9d8f0 100644 --- a/accel/accel-common.c +++ b/accel/accel-common.c @@ -123,8 +123,8 @@ bool accel_cpu_realize(CPUState *cpu, Error **errp) { CPUClass *cc = CPU_GET_CLASS(cpu); - if (cc->accel_cpu && cc->accel_cpu->cpu_realizefn) { - return cc->accel_cpu->cpu_realizefn(cpu, errp); + if (cc->accel_cpu && cc->accel_cpu->cpu_target_realize) { + return cc->accel_cpu->cpu_target_realize(cpu, errp); } return true; } diff --git a/include/hw/core/accel-cpu.h b/include/hw/core/accel-cpu.h index 5dbfd79955..24dad45ab9 100644 --- a/include/hw/core/accel-cpu.h +++ b/include/hw/core/accel-cpu.h @@ -32,7 +32,7 @@ typedef struct AccelCPUClass { void (*cpu_class_init)(CPUClass *cc); void (*cpu_instance_init)(CPUState *cpu); - bool (*cpu_realizefn)(CPUState *cpu, Error **errp); + bool (*cpu_target_realize)(CPUState *cpu, Error **errp); } AccelCPUClass; #endif /* ACCEL_CPU_H */ diff --git a/target/i386/hvf/hvf-cpu.c b/target/i386/hvf/hvf-cpu.c index 333db59898..bb0da3947a 100644 --- a/target/i386/hvf/hvf-cpu.c +++ b/target/i386/hvf/hvf-cpu.c @@ -77,7 +77,7 @@ static void hvf_cpu_accel_class_init(ObjectClass *oc, void *data) { AccelCPUClass *acc = ACCEL_CPU_CLASS(oc); - acc->cpu_realizefn = host_cpu_realizefn; + acc->cpu_target_realize = host_cpu_realizefn; acc->cpu_instance_init = hvf_cpu_instance_init; } diff --git a/target/i386/kvm/kvm-cpu.c b/target/i386/kvm/kvm-cpu.c index 4474689f81..9a5e105e4e 100644 --- a/target/i386/kvm/kvm-cpu.c +++ b/target/i386/kvm/kvm-cpu.c @@ -190,7 +190,7 @@ static void kvm_cpu_accel_class_init(ObjectClass *oc, void *data) { AccelCPUClass *acc = ACCEL_CPU_CLASS(oc); - acc->cpu_realizefn = kvm_cpu_realizefn; + acc->cpu_target_realize = kvm_cpu_realizefn; acc->cpu_instance_init = kvm_cpu_instance_init; } static const TypeInfo kvm_cpu_accel_type_info = { diff --git a/target/i386/tcg/tcg-cpu.c b/target/i386/tcg/tcg-cpu.c index b942c306d6..5c3a508ddc 100644 --- a/target/i386/tcg/tcg-cpu.c +++ b/target/i386/tcg/tcg-cpu.c @@ -163,7 +163,7 @@ static void tcg_cpu_accel_class_init(ObjectClass *oc, void *data) AccelCPUClass *acc = ACCEL_CPU_CLASS(oc); #ifndef CONFIG_USER_ONLY - acc->cpu_realizefn = tcg_cpu_realizefn; + acc->cpu_target_realize = tcg_cpu_realizefn; #endif /* CONFIG_USER_ONLY */ acc->cpu_class_init = tcg_cpu_class_init; From bd684b2f3f57dd390ba715fce1597eb7ad97ee8d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Tue, 3 Oct 2023 14:30:21 +0200 Subject: [PATCH 0145/1077] accel: Rename accel_cpu_realize() -> accel_cpu_common_realize() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit accel_cpu_realize() is a generic function working with CPUs from any target. Rename it using '_common_' to emphasis it is not target specific. Suggested-by: Claudio Fontana Signed-off-by: Philippe Mathieu-Daudé Message-Id: <20231003123026.99229-4-philmd@linaro.org> Signed-off-by: Richard Henderson --- accel/accel-common.c | 2 +- cpu.c | 2 +- include/qemu/accel.h | 4 ++-- target/i386/kvm/kvm-cpu.c | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/accel/accel-common.c b/accel/accel-common.c index 2e30b9d8f0..53cf08a89a 100644 --- a/accel/accel-common.c +++ b/accel/accel-common.c @@ -119,7 +119,7 @@ void accel_cpu_instance_init(CPUState *cpu) } } -bool accel_cpu_realize(CPUState *cpu, Error **errp) +bool accel_cpu_common_realize(CPUState *cpu, Error **errp) { CPUClass *cc = CPU_GET_CLASS(cpu); diff --git a/cpu.c b/cpu.c index 61c9760e62..1e2649a706 100644 --- a/cpu.c +++ b/cpu.c @@ -136,7 +136,7 @@ void cpu_exec_realizefn(CPUState *cpu, Error **errp) /* cache the cpu class for the hotpath */ cpu->cc = CPU_GET_CLASS(cpu); - if (!accel_cpu_realize(cpu, errp)) { + if (!accel_cpu_common_realize(cpu, errp)) { return; } diff --git a/include/qemu/accel.h b/include/qemu/accel.h index cb64a07b84..898159c001 100644 --- a/include/qemu/accel.h +++ b/include/qemu/accel.h @@ -90,11 +90,11 @@ void accel_setup_post(MachineState *ms); void accel_cpu_instance_init(CPUState *cpu); /** - * accel_cpu_realize: + * accel_cpu_common_realize: * @cpu: The CPU that needs to call accel-specific cpu realization. * @errp: currently unused. */ -bool accel_cpu_realize(CPUState *cpu, Error **errp); +bool accel_cpu_common_realize(CPUState *cpu, Error **errp); /** * accel_supported_gdbstub_sstep_flags: diff --git a/target/i386/kvm/kvm-cpu.c b/target/i386/kvm/kvm-cpu.c index 9a5e105e4e..56c72f3c45 100644 --- a/target/i386/kvm/kvm-cpu.c +++ b/target/i386/kvm/kvm-cpu.c @@ -35,7 +35,7 @@ static bool kvm_cpu_realizefn(CPUState *cs, Error **errp) * x86_cpu_realize(): * -> x86_cpu_expand_features() * -> cpu_exec_realizefn(): - * -> accel_cpu_realize() + * -> accel_cpu_common_realize() * kvm_cpu_realizefn() -> host_cpu_realizefn() * -> check/update ucode_rev, phys_bits, mwait */ From 1aa1d8308d46c5ee3b8558f9f916f5da2492a60a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Tue, 3 Oct 2023 14:30:22 +0200 Subject: [PATCH 0146/1077] accel: Introduce accel_cpu_common_unrealize() stub MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Prepare the stub for parity with accel_cpu_common_realize(). Signed-off-by: Philippe Mathieu-Daudé Message-Id: <20231003123026.99229-5-philmd@linaro.org> Signed-off-by: Richard Henderson --- accel/accel-common.c | 4 ++++ cpu.c | 4 +++- include/qemu/accel.h | 6 ++++++ 3 files changed, 13 insertions(+), 1 deletion(-) diff --git a/accel/accel-common.c b/accel/accel-common.c index 53cf08a89a..e9548eac29 100644 --- a/accel/accel-common.c +++ b/accel/accel-common.c @@ -129,6 +129,10 @@ bool accel_cpu_common_realize(CPUState *cpu, Error **errp) return true; } +void accel_cpu_common_unrealize(CPUState *cpu) +{ +} + int accel_supported_gdbstub_sstep_flags(void) { AccelState *accel = current_accel(); diff --git a/cpu.c b/cpu.c index 1e2649a706..2a1eff948b 100644 --- a/cpu.c +++ b/cpu.c @@ -187,8 +187,10 @@ void cpu_exec_unrealizefn(CPUState *cpu) cpu_list_remove(cpu); /* * Now that the vCPU has been removed from the RCU list, we can call - * tcg_exec_unrealizefn, which may free fields using call_rcu. + * tcg_exec_unrealizefn and + * accel_cpu_common_unrealize, which may free fields using call_rcu. */ + accel_cpu_common_unrealize(cpu); if (tcg_enabled()) { tcg_exec_unrealizefn(cpu); } diff --git a/include/qemu/accel.h b/include/qemu/accel.h index 898159c001..446153b145 100644 --- a/include/qemu/accel.h +++ b/include/qemu/accel.h @@ -96,6 +96,12 @@ void accel_cpu_instance_init(CPUState *cpu); */ bool accel_cpu_common_realize(CPUState *cpu, Error **errp); +/** + * accel_cpu_common_unrealize: + * @cpu: The CPU that needs to call accel-specific cpu unrealization. + */ +void accel_cpu_common_unrealize(CPUState *cpu); + /** * accel_supported_gdbstub_sstep_flags: * From 59851868a2fb632dbf080feda814137fd60242db Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Tue, 3 Oct 2023 14:30:23 +0200 Subject: [PATCH 0147/1077] accel: Declare AccelClass::cpu_common_[un]realize() handlers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Currently accel_cpu_realize() only performs target-specific realization. Introduce the cpu_common_[un]realize fields in the base AccelClass to be able to perform target-agnostic [un]realization of vCPUs. Signed-off-by: Philippe Mathieu-Daudé Message-Id: <20231003123026.99229-6-philmd@linaro.org> Signed-off-by: Richard Henderson --- accel/accel-common.c | 21 +++++++++++++++++++-- include/qemu/accel.h | 2 ++ 2 files changed, 21 insertions(+), 2 deletions(-) diff --git a/accel/accel-common.c b/accel/accel-common.c index e9548eac29..11d74b4ad7 100644 --- a/accel/accel-common.c +++ b/accel/accel-common.c @@ -122,15 +122,32 @@ void accel_cpu_instance_init(CPUState *cpu) bool accel_cpu_common_realize(CPUState *cpu, Error **errp) { CPUClass *cc = CPU_GET_CLASS(cpu); + AccelState *accel = current_accel(); + AccelClass *acc = ACCEL_GET_CLASS(accel); - if (cc->accel_cpu && cc->accel_cpu->cpu_target_realize) { - return cc->accel_cpu->cpu_target_realize(cpu, errp); + /* target specific realization */ + if (cc->accel_cpu && cc->accel_cpu->cpu_target_realize + && !cc->accel_cpu->cpu_target_realize(cpu, errp)) { + return false; } + + /* generic realization */ + if (acc->cpu_common_realize && !acc->cpu_common_realize(cpu, errp)) { + return false; + } + return true; } void accel_cpu_common_unrealize(CPUState *cpu) { + AccelState *accel = current_accel(); + AccelClass *acc = ACCEL_GET_CLASS(accel); + + /* generic unrealization */ + if (acc->cpu_common_unrealize) { + acc->cpu_common_unrealize(cpu); + } } int accel_supported_gdbstub_sstep_flags(void) diff --git a/include/qemu/accel.h b/include/qemu/accel.h index 446153b145..972a849a2b 100644 --- a/include/qemu/accel.h +++ b/include/qemu/accel.h @@ -43,6 +43,8 @@ typedef struct AccelClass { bool (*has_memory)(MachineState *ms, AddressSpace *as, hwaddr start_addr, hwaddr size); #endif + bool (*cpu_common_realize)(CPUState *cpu, Error **errp); + void (*cpu_common_unrealize)(CPUState *cpu); /* gdbstub related hooks */ int (*gdbstub_supported_sstep_flags)(void); From fa312f2eaf50d7abb84dcc0d9b5d15f1ddf6f66b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Tue, 3 Oct 2023 14:30:24 +0200 Subject: [PATCH 0148/1077] accel/tcg: Have tcg_exec_realizefn() return a boolean MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Following the example documented since commit e3fe3988d7 ("error: Document Error API usage rules"), have tcg_exec_realizefn() return a boolean indicating whether an error is set or not. Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Claudio Fontana Message-Id: <20231003123026.99229-7-philmd@linaro.org> Signed-off-by: Richard Henderson --- accel/tcg/cpu-exec.c | 4 +++- include/exec/cpu-all.h | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/accel/tcg/cpu-exec.c b/accel/tcg/cpu-exec.c index c724e8b6f1..60f1986b85 100644 --- a/accel/tcg/cpu-exec.c +++ b/accel/tcg/cpu-exec.c @@ -1088,7 +1088,7 @@ int cpu_exec(CPUState *cpu) return ret; } -void tcg_exec_realizefn(CPUState *cpu, Error **errp) +bool tcg_exec_realizefn(CPUState *cpu, Error **errp) { static bool tcg_target_initialized; CPUClass *cc = CPU_GET_CLASS(cpu); @@ -1104,6 +1104,8 @@ void tcg_exec_realizefn(CPUState *cpu, Error **errp) tcg_iommu_init_notifier_list(cpu); #endif /* !CONFIG_USER_ONLY */ /* qemu_plugin_vcpu_init_hook delayed until cpu_index assigned. */ + + return true; } /* undo the initializations in reverse order */ diff --git a/include/exec/cpu-all.h b/include/exec/cpu-all.h index c2c62160c6..1e5c530ee1 100644 --- a/include/exec/cpu-all.h +++ b/include/exec/cpu-all.h @@ -422,7 +422,7 @@ void dump_exec_info(GString *buf); /* accel/tcg/cpu-exec.c */ int cpu_exec(CPUState *cpu); -void tcg_exec_realizefn(CPUState *cpu, Error **errp); +bool tcg_exec_realizefn(CPUState *cpu, Error **errp); void tcg_exec_unrealizefn(CPUState *cpu); /** From 23af78b070ebfc0bfa8f114796a2eb9b5ed31e92 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Tue, 3 Oct 2023 14:30:25 +0200 Subject: [PATCH 0149/1077] accel/tcg: Restrict tcg_exec_[un]realizefn() to TCG MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We don't need to expose these TCG-specific methods to the whole code base. Register them as AccelClass handlers, they will be called by the generic accel_cpu_[un]realize() methods. Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Claudio Fontana Message-Id: <20231003123026.99229-8-philmd@linaro.org> Signed-off-by: Richard Henderson --- accel/tcg/internal.h | 3 +++ accel/tcg/tcg-all.c | 2 ++ cpu.c | 9 --------- include/exec/cpu-all.h | 2 -- 4 files changed, 5 insertions(+), 11 deletions(-) diff --git a/accel/tcg/internal.h b/accel/tcg/internal.h index e8cbbde581..57ab397df1 100644 --- a/accel/tcg/internal.h +++ b/accel/tcg/internal.h @@ -80,6 +80,9 @@ bool tb_invalidate_phys_page_unwind(tb_page_addr_t addr, uintptr_t pc); void cpu_restore_state_from_tb(CPUState *cpu, TranslationBlock *tb, uintptr_t host_pc); +bool tcg_exec_realizefn(CPUState *cpu, Error **errp); +void tcg_exec_unrealizefn(CPUState *cpu); + /* Return the current PC from CPU, which may be cached in TB. */ static inline vaddr log_pc(CPUState *cpu, const TranslationBlock *tb) { diff --git a/accel/tcg/tcg-all.c b/accel/tcg/tcg-all.c index 03dfd67e9e..8ab873a5ab 100644 --- a/accel/tcg/tcg-all.c +++ b/accel/tcg/tcg-all.c @@ -227,6 +227,8 @@ static void tcg_accel_class_init(ObjectClass *oc, void *data) AccelClass *ac = ACCEL_CLASS(oc); ac->name = "tcg"; ac->init_machine = tcg_init_machine; + ac->cpu_common_realize = tcg_exec_realizefn; + ac->cpu_common_unrealize = tcg_exec_unrealizefn; ac->allowed = &tcg_allowed; ac->gdbstub_supported_sstep_flags = tcg_gdbstub_supported_sstep_flags; diff --git a/cpu.c b/cpu.c index 2a1eff948b..658d179582 100644 --- a/cpu.c +++ b/cpu.c @@ -140,11 +140,6 @@ void cpu_exec_realizefn(CPUState *cpu, Error **errp) return; } - /* NB: errp parameter is unused currently */ - if (tcg_enabled()) { - tcg_exec_realizefn(cpu, errp); - } - /* Wait until cpu initialization complete before exposing cpu. */ cpu_list_add(cpu); @@ -187,13 +182,9 @@ void cpu_exec_unrealizefn(CPUState *cpu) cpu_list_remove(cpu); /* * Now that the vCPU has been removed from the RCU list, we can call - * tcg_exec_unrealizefn and * accel_cpu_common_unrealize, which may free fields using call_rcu. */ accel_cpu_common_unrealize(cpu); - if (tcg_enabled()) { - tcg_exec_unrealizefn(cpu); - } } /* diff --git a/include/exec/cpu-all.h b/include/exec/cpu-all.h index 1e5c530ee1..230525ebf7 100644 --- a/include/exec/cpu-all.h +++ b/include/exec/cpu-all.h @@ -422,8 +422,6 @@ void dump_exec_info(GString *buf); /* accel/tcg/cpu-exec.c */ int cpu_exec(CPUState *cpu); -bool tcg_exec_realizefn(CPUState *cpu, Error **errp); -void tcg_exec_unrealizefn(CPUState *cpu); /** * cpu_set_cpustate_pointers(cpu) From a81fef4b6440046e21e3531329e1e21f58645c76 Mon Sep 17 00:00:00 2001 From: Anton Johansson Date: Tue, 12 Sep 2023 17:34:18 +0200 Subject: [PATCH 0150/1077] target/arm: Replace TARGET_PAGE_ENTRY_EXTRA TARGET_PAGE_ENTRY_EXTRA is a macro that allows guests to specify additional fields for caching with the full TLB entry. This macro is replaced with a union in CPUTLBEntryFull, thus making CPUTLB target-agnostic at the cost of slightly inflated CPUTLBEntryFull for non-arm guests. Note, this is needed to ensure that fields in CPUTLB don't vary in offset between various targets. (arm is the only guest actually making use of this feature.) Signed-off-by: Anton Johansson Message-Id: <20230912153428.17816-2-anjo@rev.ng> Signed-off-by: Richard Henderson --- include/exec/cpu-defs.h | 18 +++++++++++++++--- target/arm/cpu-param.h | 12 ------------ target/arm/ptw.c | 4 ++-- target/arm/tcg/mte_helper.c | 2 +- target/arm/tcg/sve_helper.c | 2 +- target/arm/tcg/tlb_helper.c | 4 ++-- target/arm/tcg/translate-a64.c | 2 +- 7 files changed, 22 insertions(+), 22 deletions(-) diff --git a/include/exec/cpu-defs.h b/include/exec/cpu-defs.h index 350287852e..46d2ac570f 100644 --- a/include/exec/cpu-defs.h +++ b/include/exec/cpu-defs.h @@ -135,9 +135,21 @@ typedef struct CPUTLBEntryFull { * This may be used to cache items from the guest cpu * page tables for later use by the implementation. */ -#ifdef TARGET_PAGE_ENTRY_EXTRA - TARGET_PAGE_ENTRY_EXTRA -#endif + union { + /* + * Cache the attrs and shareability fields from the page table entry. + * + * For ARMMMUIdx_Stage2*, pte_attrs is the S2 descriptor bits [5:2]. + * Otherwise, pte_attrs is the same as the MAIR_EL1 8-bit format. + * For shareability and guarded, as in the SH and GP fields respectively + * of the VMSAv8-64 PTEs. + */ + struct { + uint8_t pte_attrs; + uint8_t shareability; + bool guarded; + } arm; + } extra; } CPUTLBEntryFull; #endif /* CONFIG_SOFTMMU */ diff --git a/target/arm/cpu-param.h b/target/arm/cpu-param.h index b3b35f7aa1..f9b462a98f 100644 --- a/target/arm/cpu-param.h +++ b/target/arm/cpu-param.h @@ -31,18 +31,6 @@ # define TARGET_PAGE_BITS_VARY # define TARGET_PAGE_BITS_MIN 10 -/* - * Cache the attrs and shareability fields from the page table entry. - * - * For ARMMMUIdx_Stage2*, pte_attrs is the S2 descriptor bits [5:2]. - * Otherwise, pte_attrs is the same as the MAIR_EL1 8-bit format. - * For shareability and guarded, as in the SH and GP fields respectively - * of the VMSAv8-64 PTEs. - */ -# define TARGET_PAGE_ENTRY_EXTRA \ - uint8_t pte_attrs; \ - uint8_t shareability; \ - bool guarded; #endif #endif diff --git a/target/arm/ptw.c b/target/arm/ptw.c index bfbab26b9b..95db9ec4c3 100644 --- a/target/arm/ptw.c +++ b/target/arm/ptw.c @@ -579,7 +579,7 @@ static bool S1_ptw_translate(CPUARMState *env, S1Translate *ptw, } ptw->out_phys = full->phys_addr | (addr & ~TARGET_PAGE_MASK); ptw->out_rw = full->prot & PAGE_WRITE; - pte_attrs = full->pte_attrs; + pte_attrs = full->extra.arm.pte_attrs; ptw->out_space = full->attrs.space; #else g_assert_not_reached(); @@ -2036,7 +2036,7 @@ static bool get_phys_addr_lpae(CPUARMState *env, S1Translate *ptw, /* When in aarch64 mode, and BTI is enabled, remember GP in the TLB. */ if (aarch64 && cpu_isar_feature(aa64_bti, cpu)) { - result->f.guarded = extract64(attrs, 50, 1); /* GP */ + result->f.extra.arm.guarded = extract64(attrs, 50, 1); /* GP */ } } diff --git a/target/arm/tcg/mte_helper.c b/target/arm/tcg/mte_helper.c index 2dd7eb3edb..70ac876105 100644 --- a/target/arm/tcg/mte_helper.c +++ b/target/arm/tcg/mte_helper.c @@ -137,7 +137,7 @@ static uint8_t *allocation_tag_mem_probe(CPUARMState *env, int ptr_mmu_idx, assert(!(flags & TLB_INVALID_MASK)); /* If the virtual page MemAttr != Tagged, access unchecked. */ - if (full->pte_attrs != 0xf0) { + if (full->extra.arm.pte_attrs != 0xf0) { return NULL; } diff --git a/target/arm/tcg/sve_helper.c b/target/arm/tcg/sve_helper.c index 7c103fc9f7..f006d152cc 100644 --- a/target/arm/tcg/sve_helper.c +++ b/target/arm/tcg/sve_helper.c @@ -5373,7 +5373,7 @@ bool sve_probe_page(SVEHostPage *info, bool nofault, CPUARMState *env, info->tagged = (flags & PAGE_ANON) && (flags & PAGE_MTE); #else info->attrs = full->attrs; - info->tagged = full->pte_attrs == 0xf0; + info->tagged = full->extra.arm.pte_attrs == 0xf0; #endif /* Ensure that info->host[] is relative to addr, not addr + mem_off. */ diff --git a/target/arm/tcg/tlb_helper.c b/target/arm/tcg/tlb_helper.c index b22b2a4c6e..59bff8b452 100644 --- a/target/arm/tcg/tlb_helper.c +++ b/target/arm/tcg/tlb_helper.c @@ -334,8 +334,8 @@ bool arm_cpu_tlb_fill(CPUState *cs, vaddr address, int size, address &= TARGET_PAGE_MASK; } - res.f.pte_attrs = res.cacheattrs.attrs; - res.f.shareability = res.cacheattrs.shareability; + res.f.extra.arm.pte_attrs = res.cacheattrs.attrs; + res.f.extra.arm.shareability = res.cacheattrs.shareability; tlb_set_page_full(cs, mmu_idx, address, &res.f); return true; diff --git a/target/arm/tcg/translate-a64.c b/target/arm/tcg/translate-a64.c index 97f25b4451..6523bfb339 100644 --- a/target/arm/tcg/translate-a64.c +++ b/target/arm/tcg/translate-a64.c @@ -13904,7 +13904,7 @@ static bool is_guarded_page(CPUARMState *env, DisasContext *s) false, &host, &full, 0); assert(!(flags & TLB_INVALID_MASK)); - return full->guarded; + return full->extra.arm.guarded; #endif } From ef6d8210a2570b5f7c5e02ab422c92f527b62be7 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 15 Sep 2023 13:40:26 -0700 Subject: [PATCH 0151/1077] accel/tcg: Move CPUTLB definitions from cpu-defs.h Accept that we will consume space in CPUState for CONFIG_USER_ONLY, since we cannot test CONFIG_SOFTMMU within hw/core/cpu.h. Reviewed-by: Anton Johansson Signed-off-by: Richard Henderson --- include/exec/cpu-defs.h | 150 ---------------------------------------- include/hw/core/cpu.h | 141 +++++++++++++++++++++++++++++++++++++ 2 files changed, 141 insertions(+), 150 deletions(-) diff --git a/include/exec/cpu-defs.h b/include/exec/cpu-defs.h index 46d2ac570f..3915438b83 100644 --- a/include/exec/cpu-defs.h +++ b/include/exec/cpu-defs.h @@ -54,18 +54,7 @@ #include "exec/target_long.h" -/* - * Fix the number of mmu modes to 16, which is also the maximum - * supported by the softmmu tlb api. - */ -#define NB_MMU_MODES 16 - #if defined(CONFIG_SOFTMMU) && defined(CONFIG_TCG) -#include "exec/tlb-common.h" - -/* use a fully associative victim tlb of 8 entries */ -#define CPU_VTLB_SIZE 8 - #define CPU_TLB_DYN_MIN_BITS 6 #define CPU_TLB_DYN_DEFAULT_BITS 8 @@ -91,143 +80,4 @@ #endif /* CONFIG_SOFTMMU && CONFIG_TCG */ -#if defined(CONFIG_SOFTMMU) -/* - * The full TLB entry, which is not accessed by generated TCG code, - * so the layout is not as critical as that of CPUTLBEntry. This is - * also why we don't want to combine the two structs. - */ -typedef struct CPUTLBEntryFull { - /* - * @xlat_section contains: - * - For ram, an offset which must be added to the virtual address - * to obtain the ram_addr_t of the target RAM - * - For other memory regions, - * + in the lower TARGET_PAGE_BITS, the physical section number - * + with the TARGET_PAGE_BITS masked off, the offset within - * the target MemoryRegion - */ - hwaddr xlat_section; - - /* - * @phys_addr contains the physical address in the address space - * given by cpu_asidx_from_attrs(cpu, @attrs). - */ - hwaddr phys_addr; - - /* @attrs contains the memory transaction attributes for the page. */ - MemTxAttrs attrs; - - /* @prot contains the complete protections for the page. */ - uint8_t prot; - - /* @lg_page_size contains the log2 of the page size. */ - uint8_t lg_page_size; - - /* - * Additional tlb flags for use by the slow path. If non-zero, - * the corresponding CPUTLBEntry comparator must have TLB_FORCE_SLOW. - */ - uint8_t slow_flags[MMU_ACCESS_COUNT]; - - /* - * Allow target-specific additions to this structure. - * This may be used to cache items from the guest cpu - * page tables for later use by the implementation. - */ - union { - /* - * Cache the attrs and shareability fields from the page table entry. - * - * For ARMMMUIdx_Stage2*, pte_attrs is the S2 descriptor bits [5:2]. - * Otherwise, pte_attrs is the same as the MAIR_EL1 8-bit format. - * For shareability and guarded, as in the SH and GP fields respectively - * of the VMSAv8-64 PTEs. - */ - struct { - uint8_t pte_attrs; - uint8_t shareability; - bool guarded; - } arm; - } extra; -} CPUTLBEntryFull; -#endif /* CONFIG_SOFTMMU */ - -#if defined(CONFIG_SOFTMMU) && defined(CONFIG_TCG) -/* - * Data elements that are per MMU mode, minus the bits accessed by - * the TCG fast path. - */ -typedef struct CPUTLBDesc { - /* - * Describe a region covering all of the large pages allocated - * into the tlb. When any page within this region is flushed, - * we must flush the entire tlb. The region is matched if - * (addr & large_page_mask) == large_page_addr. - */ - vaddr large_page_addr; - vaddr large_page_mask; - /* host time (in ns) at the beginning of the time window */ - int64_t window_begin_ns; - /* maximum number of entries observed in the window */ - size_t window_max_entries; - size_t n_used_entries; - /* The next index to use in the tlb victim table. */ - size_t vindex; - /* The tlb victim table, in two parts. */ - CPUTLBEntry vtable[CPU_VTLB_SIZE]; - CPUTLBEntryFull vfulltlb[CPU_VTLB_SIZE]; - CPUTLBEntryFull *fulltlb; -} CPUTLBDesc; - -/* - * Data elements that are shared between all MMU modes. - */ -typedef struct CPUTLBCommon { - /* Serialize updates to f.table and d.vtable, and others as noted. */ - QemuSpin lock; - /* - * Within dirty, for each bit N, modifications have been made to - * mmu_idx N since the last time that mmu_idx was flushed. - * Protected by tlb_c.lock. - */ - uint16_t dirty; - /* - * Statistics. These are not lock protected, but are read and - * written atomically. This allows the monitor to print a snapshot - * of the stats without interfering with the cpu. - */ - size_t full_flush_count; - size_t part_flush_count; - size_t elide_flush_count; -} CPUTLBCommon; - -/* - * The entire softmmu tlb, for all MMU modes. - * The meaning of each of the MMU modes is defined in the target code. - * Since this is placed within CPUNegativeOffsetState, the smallest - * negative offsets are at the end of the struct. - */ - -typedef struct CPUTLB { - CPUTLBCommon c; - CPUTLBDesc d[NB_MMU_MODES]; - CPUTLBDescFast f[NB_MMU_MODES]; -} CPUTLB; - -#else - -typedef struct CPUTLB { } CPUTLB; - -#endif /* CONFIG_SOFTMMU && CONFIG_TCG */ - -/* - * This structure must be placed in ArchCPU immediately - * before CPUArchState, as a field named "neg". - */ -typedef struct CPUNegativeOffsetState { - CPUTLB tlb; - IcountDecr icount_decr; -} CPUNegativeOffsetState; - #endif diff --git a/include/hw/core/cpu.h b/include/hw/core/cpu.h index 648b5b3586..04baa5063c 100644 --- a/include/hw/core/cpu.h +++ b/include/hw/core/cpu.h @@ -25,6 +25,7 @@ #include "exec/cpu-common.h" #include "exec/hwaddr.h" #include "exec/memattrs.h" +#include "exec/tlb-common.h" #include "qapi/qapi-types-run-state.h" #include "qemu/bitmap.h" #include "qemu/rcu_queue.h" @@ -192,6 +193,137 @@ struct CPUClass { bool gdb_stop_before_watchpoint; }; +/* + * Fix the number of mmu modes to 16, which is also the maximum + * supported by the softmmu tlb api. + */ +#define NB_MMU_MODES 16 + +/* Use a fully associative victim tlb of 8 entries. */ +#define CPU_VTLB_SIZE 8 + +/* + * The full TLB entry, which is not accessed by generated TCG code, + * so the layout is not as critical as that of CPUTLBEntry. This is + * also why we don't want to combine the two structs. + */ +typedef struct CPUTLBEntryFull { + /* + * @xlat_section contains: + * - in the lower TARGET_PAGE_BITS, a physical section number + * - with the lower TARGET_PAGE_BITS masked off, an offset which + * must be added to the virtual address to obtain: + * + the ram_addr_t of the target RAM (if the physical section + * number is PHYS_SECTION_NOTDIRTY or PHYS_SECTION_ROM) + * + the offset within the target MemoryRegion (otherwise) + */ + hwaddr xlat_section; + + /* + * @phys_addr contains the physical address in the address space + * given by cpu_asidx_from_attrs(cpu, @attrs). + */ + hwaddr phys_addr; + + /* @attrs contains the memory transaction attributes for the page. */ + MemTxAttrs attrs; + + /* @prot contains the complete protections for the page. */ + uint8_t prot; + + /* @lg_page_size contains the log2 of the page size. */ + uint8_t lg_page_size; + + /* + * Additional tlb flags for use by the slow path. If non-zero, + * the corresponding CPUTLBEntry comparator must have TLB_FORCE_SLOW. + */ + uint8_t slow_flags[MMU_ACCESS_COUNT]; + + /* + * Allow target-specific additions to this structure. + * This may be used to cache items from the guest cpu + * page tables for later use by the implementation. + */ + union { + /* + * Cache the attrs and shareability fields from the page table entry. + * + * For ARMMMUIdx_Stage2*, pte_attrs is the S2 descriptor bits [5:2]. + * Otherwise, pte_attrs is the same as the MAIR_EL1 8-bit format. + * For shareability and guarded, as in the SH and GP fields respectively + * of the VMSAv8-64 PTEs. + */ + struct { + uint8_t pte_attrs; + uint8_t shareability; + bool guarded; + } arm; + } extra; +} CPUTLBEntryFull; + +/* + * Data elements that are per MMU mode, minus the bits accessed by + * the TCG fast path. + */ +typedef struct CPUTLBDesc { + /* + * Describe a region covering all of the large pages allocated + * into the tlb. When any page within this region is flushed, + * we must flush the entire tlb. The region is matched if + * (addr & large_page_mask) == large_page_addr. + */ + vaddr large_page_addr; + vaddr large_page_mask; + /* host time (in ns) at the beginning of the time window */ + int64_t window_begin_ns; + /* maximum number of entries observed in the window */ + size_t window_max_entries; + size_t n_used_entries; + /* The next index to use in the tlb victim table. */ + size_t vindex; + /* The tlb victim table, in two parts. */ + CPUTLBEntry vtable[CPU_VTLB_SIZE]; + CPUTLBEntryFull vfulltlb[CPU_VTLB_SIZE]; + CPUTLBEntryFull *fulltlb; +} CPUTLBDesc; + +/* + * Data elements that are shared between all MMU modes. + */ +typedef struct CPUTLBCommon { + /* Serialize updates to f.table and d.vtable, and others as noted. */ + QemuSpin lock; + /* + * Within dirty, for each bit N, modifications have been made to + * mmu_idx N since the last time that mmu_idx was flushed. + * Protected by tlb_c.lock. + */ + uint16_t dirty; + /* + * Statistics. These are not lock protected, but are read and + * written atomically. This allows the monitor to print a snapshot + * of the stats without interfering with the cpu. + */ + size_t full_flush_count; + size_t part_flush_count; + size_t elide_flush_count; +} CPUTLBCommon; + +/* + * The entire softmmu tlb, for all MMU modes. + * The meaning of each of the MMU modes is defined in the target code. + * Since this is placed within CPUNegativeOffsetState, the smallest + * negative offsets are at the end of the struct. + */ +typedef struct CPUTLB { +#ifdef CONFIG_TCG + CPUTLBCommon c; + CPUTLBDesc d[NB_MMU_MODES]; + CPUTLBDescFast f[NB_MMU_MODES]; +#endif +} CPUTLB; + /* * Low 16 bits: number of cycles left, used only in icount mode. * High 16 bits: Set to -1 to force TCG to stop executing linked TBs @@ -212,6 +344,15 @@ typedef union IcountDecr { } u16; } IcountDecr; +/* + * This structure must be placed in ArchCPU immediately + * before CPUArchState, as a field named "neg". + */ +typedef struct CPUNegativeOffsetState { + CPUTLB tlb; + IcountDecr icount_decr; +} CPUNegativeOffsetState; + typedef struct CPUBreakpoint { vaddr pc; int flags; /* BP_* */ From ad4ec2798fd7066bc9d879dcbdeae96073ad370f Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 13 Sep 2023 14:46:17 -0700 Subject: [PATCH 0152/1077] qom: Propagate alignment through type system MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Propagate alignment just like size. This is required in order to get the correct alignment on most cpu subclasses where the size and alignment is only specified for the base cpu type. Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Richard Henderson --- qom/object.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/qom/object.c b/qom/object.c index e25f1e96db..8557fe8e4e 100644 --- a/qom/object.c +++ b/qom/object.c @@ -220,6 +220,19 @@ static size_t type_object_get_size(TypeImpl *ti) return 0; } +static size_t type_object_get_align(TypeImpl *ti) +{ + if (ti->instance_align) { + return ti->instance_align; + } + + if (type_has_parent(ti)) { + return type_object_get_align(type_get_parent(ti)); + } + + return 0; +} + size_t object_type_get_instance_size(const char *typename) { TypeImpl *type = type_get_by_name(typename); @@ -293,6 +306,7 @@ static void type_initialize(TypeImpl *ti) ti->class_size = type_class_get_size(ti); ti->instance_size = type_object_get_size(ti); + ti->instance_align = type_object_get_align(ti); /* Any type with zero instance_size is implicitly abstract. * This means interface types are all abstract. */ From 61cd357698231386f482f4257fc9fc1d66c750d8 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 13 Sep 2023 14:59:52 -0700 Subject: [PATCH 0153/1077] target/arm: Remove size and alignment for cpu subclasses MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Inherit the size and alignment from TYPE_ARM_CPU. Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Richard Henderson --- target/arm/cpu.c | 3 --- target/arm/cpu64.c | 4 ---- 2 files changed, 7 deletions(-) diff --git a/target/arm/cpu.c b/target/arm/cpu.c index b9e09a702d..d48a70c039 100644 --- a/target/arm/cpu.c +++ b/target/arm/cpu.c @@ -2423,10 +2423,7 @@ void arm_cpu_register(const ARMCPUInfo *info) { TypeInfo type_info = { .parent = TYPE_ARM_CPU, - .instance_size = sizeof(ARMCPU), - .instance_align = __alignof__(ARMCPU), .instance_init = arm_cpu_instance_init, - .class_size = sizeof(ARMCPUClass), .class_init = info->class_init ?: cpu_register_class_init, .class_data = (void *)info, }; diff --git a/target/arm/cpu64.c b/target/arm/cpu64.c index f3d87e001f..811f3b38c2 100644 --- a/target/arm/cpu64.c +++ b/target/arm/cpu64.c @@ -822,9 +822,7 @@ void aarch64_cpu_register(const ARMCPUInfo *info) { TypeInfo type_info = { .parent = TYPE_AARCH64_CPU, - .instance_size = sizeof(ARMCPU), .instance_init = aarch64_cpu_instance_init, - .class_size = sizeof(ARMCPUClass), .class_init = info->class_init ?: cpu_register_class_init, .class_data = (void *)info, }; @@ -837,10 +835,8 @@ void aarch64_cpu_register(const ARMCPUInfo *info) static const TypeInfo aarch64_cpu_type_info = { .name = TYPE_AARCH64_CPU, .parent = TYPE_ARM_CPU, - .instance_size = sizeof(ARMCPU), .instance_finalize = aarch64_cpu_finalizefn, .abstract = true, - .class_size = sizeof(AArch64CPUClass), .class_init = aarch64_cpu_class_init, }; From f669c99241adfcd4186aebff6990cefdac25125b Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 13 Sep 2023 15:06:21 -0700 Subject: [PATCH 0154/1077] target/*: Add instance_align to all cpu base classes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The omission of alignment has technically been wrong since 269bd5d8f61, where QEMU_ALIGNED was added to CPUTLBDescFast. Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Richard Henderson --- target/alpha/cpu.c | 1 + target/avr/cpu.c | 1 + target/cris/cpu.c | 1 + target/hexagon/cpu.c | 1 + target/hppa/cpu.c | 1 + target/i386/cpu.c | 1 + target/loongarch/cpu.c | 1 + target/m68k/cpu.c | 1 + target/microblaze/cpu.c | 1 + target/mips/cpu.c | 1 + target/nios2/cpu.c | 1 + target/openrisc/cpu.c | 1 + target/riscv/cpu.c | 2 +- target/rx/cpu.c | 1 + target/sh4/cpu.c | 1 + target/sparc/cpu.c | 1 + target/tricore/cpu.c | 1 + target/xtensa/cpu.c | 1 + 18 files changed, 18 insertions(+), 1 deletion(-) diff --git a/target/alpha/cpu.c b/target/alpha/cpu.c index 270ae787b1..e2156fcb41 100644 --- a/target/alpha/cpu.c +++ b/target/alpha/cpu.c @@ -286,6 +286,7 @@ static const TypeInfo alpha_cpu_type_infos[] = { .name = TYPE_ALPHA_CPU, .parent = TYPE_CPU, .instance_size = sizeof(AlphaCPU), + .instance_align = __alignof(AlphaCPU), .instance_init = alpha_cpu_initfn, .abstract = true, .class_size = sizeof(AlphaCPUClass), diff --git a/target/avr/cpu.c b/target/avr/cpu.c index 8f741f258c..c5a6436336 100644 --- a/target/avr/cpu.c +++ b/target/avr/cpu.c @@ -390,6 +390,7 @@ static const TypeInfo avr_cpu_type_info[] = { .name = TYPE_AVR_CPU, .parent = TYPE_CPU, .instance_size = sizeof(AVRCPU), + .instance_align = __alignof(AVRCPU), .instance_init = avr_cpu_initfn, .class_size = sizeof(AVRCPUClass), .class_init = avr_cpu_class_init, diff --git a/target/cris/cpu.c b/target/cris/cpu.c index a6a93c2359..8ab8a30b8d 100644 --- a/target/cris/cpu.c +++ b/target/cris/cpu.c @@ -345,6 +345,7 @@ static const TypeInfo cris_cpu_model_type_infos[] = { .name = TYPE_CRIS_CPU, .parent = TYPE_CPU, .instance_size = sizeof(CRISCPU), + .instance_align = __alignof(CRISCPU), .instance_init = cris_cpu_initfn, .abstract = true, .class_size = sizeof(CRISCPUClass), diff --git a/target/hexagon/cpu.c b/target/hexagon/cpu.c index f155936289..65f198b956 100644 --- a/target/hexagon/cpu.c +++ b/target/hexagon/cpu.c @@ -408,6 +408,7 @@ static const TypeInfo hexagon_cpu_type_infos[] = { .name = TYPE_HEXAGON_CPU, .parent = TYPE_CPU, .instance_size = sizeof(HexagonCPU), + .instance_align = __alignof(HexagonCPU), .instance_init = hexagon_cpu_init, .abstract = true, .class_size = sizeof(HexagonCPUClass), diff --git a/target/hppa/cpu.c b/target/hppa/cpu.c index 11022f9c99..17fa901f6a 100644 --- a/target/hppa/cpu.c +++ b/target/hppa/cpu.c @@ -212,6 +212,7 @@ static const TypeInfo hppa_cpu_type_info = { .name = TYPE_HPPA_CPU, .parent = TYPE_CPU, .instance_size = sizeof(HPPACPU), + .instance_align = __alignof(HPPACPU), .instance_init = hppa_cpu_initfn, .abstract = false, .class_size = sizeof(HPPACPUClass), diff --git a/target/i386/cpu.c b/target/i386/cpu.c index ed72883bf3..187ebb0dbc 100644 --- a/target/i386/cpu.c +++ b/target/i386/cpu.c @@ -8022,6 +8022,7 @@ static const TypeInfo x86_cpu_type_info = { .name = TYPE_X86_CPU, .parent = TYPE_CPU, .instance_size = sizeof(X86CPU), + .instance_align = __alignof(X86CPU), .instance_init = x86_cpu_initfn, .instance_post_init = x86_cpu_post_initfn, diff --git a/target/loongarch/cpu.c b/target/loongarch/cpu.c index fc7f70fbe5..d5e403bbb7 100644 --- a/target/loongarch/cpu.c +++ b/target/loongarch/cpu.c @@ -808,6 +808,7 @@ static const TypeInfo loongarch_cpu_type_infos[] = { .name = TYPE_LOONGARCH_CPU, .parent = TYPE_CPU, .instance_size = sizeof(LoongArchCPU), + .instance_align = __alignof(LoongArchCPU), .instance_init = loongarch_cpu_init, .abstract = true, diff --git a/target/m68k/cpu.c b/target/m68k/cpu.c index 70d58471dc..d34d1b57d0 100644 --- a/target/m68k/cpu.c +++ b/target/m68k/cpu.c @@ -611,6 +611,7 @@ static const TypeInfo m68k_cpus_type_infos[] = { .name = TYPE_M68K_CPU, .parent = TYPE_CPU, .instance_size = sizeof(M68kCPU), + .instance_align = __alignof(M68kCPU), .instance_init = m68k_cpu_initfn, .abstract = true, .class_size = sizeof(M68kCPUClass), diff --git a/target/microblaze/cpu.c b/target/microblaze/cpu.c index 03c2c4db1f..c53711da52 100644 --- a/target/microblaze/cpu.c +++ b/target/microblaze/cpu.c @@ -439,6 +439,7 @@ static const TypeInfo mb_cpu_type_info = { .name = TYPE_MICROBLAZE_CPU, .parent = TYPE_CPU, .instance_size = sizeof(MicroBlazeCPU), + .instance_align = __alignof(MicroBlazeCPU), .instance_init = mb_cpu_initfn, .class_size = sizeof(MicroBlazeCPUClass), .class_init = mb_cpu_class_init, diff --git a/target/mips/cpu.c b/target/mips/cpu.c index 63da1948fd..fee791aa44 100644 --- a/target/mips/cpu.c +++ b/target/mips/cpu.c @@ -600,6 +600,7 @@ static const TypeInfo mips_cpu_type_info = { .name = TYPE_MIPS_CPU, .parent = TYPE_CPU, .instance_size = sizeof(MIPSCPU), + .instance_align = __alignof(MIPSCPU), .instance_init = mips_cpu_initfn, .abstract = true, .class_size = sizeof(MIPSCPUClass), diff --git a/target/nios2/cpu.c b/target/nios2/cpu.c index bc5cbf81c2..598976305f 100644 --- a/target/nios2/cpu.c +++ b/target/nios2/cpu.c @@ -400,6 +400,7 @@ static const TypeInfo nios2_cpu_type_info = { .name = TYPE_NIOS2_CPU, .parent = TYPE_CPU, .instance_size = sizeof(Nios2CPU), + .instance_align = __alignof(Nios2CPU), .instance_init = nios2_cpu_initfn, .class_size = sizeof(Nios2CPUClass), .class_init = nios2_cpu_class_init, diff --git a/target/openrisc/cpu.c b/target/openrisc/cpu.c index 61d748cfdc..be067709b8 100644 --- a/target/openrisc/cpu.c +++ b/target/openrisc/cpu.c @@ -314,6 +314,7 @@ static const TypeInfo openrisc_cpus_type_infos[] = { .name = TYPE_OPENRISC_CPU, .parent = TYPE_CPU, .instance_size = sizeof(OpenRISCCPU), + .instance_align = __alignof(OpenRISCCPU), .instance_init = openrisc_cpu_initfn, .abstract = true, .class_size = sizeof(OpenRISCCPUClass), diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c index 4140899c52..d69c40d380 100644 --- a/target/riscv/cpu.c +++ b/target/riscv/cpu.c @@ -2314,7 +2314,7 @@ static const TypeInfo riscv_cpu_type_infos[] = { .name = TYPE_RISCV_CPU, .parent = TYPE_CPU, .instance_size = sizeof(RISCVCPU), - .instance_align = __alignof__(RISCVCPU), + .instance_align = __alignof(RISCVCPU), .instance_init = riscv_cpu_init, .abstract = true, .class_size = sizeof(RISCVCPUClass), diff --git a/target/rx/cpu.c b/target/rx/cpu.c index 157e57da0f..51559943fb 100644 --- a/target/rx/cpu.c +++ b/target/rx/cpu.c @@ -248,6 +248,7 @@ static const TypeInfo rx_cpu_info = { .name = TYPE_RX_CPU, .parent = TYPE_CPU, .instance_size = sizeof(RXCPU), + .instance_align = __alignof(RXCPU), .instance_init = rx_cpu_init, .abstract = true, .class_size = sizeof(RXCPUClass), diff --git a/target/sh4/cpu.c b/target/sh4/cpu.c index 61769ffdfa..a90e41c4ec 100644 --- a/target/sh4/cpu.c +++ b/target/sh4/cpu.c @@ -315,6 +315,7 @@ static const TypeInfo superh_cpu_type_infos[] = { .name = TYPE_SUPERH_CPU, .parent = TYPE_CPU, .instance_size = sizeof(SuperHCPU), + .instance_align = __alignof(SuperHCPU), .instance_init = superh_cpu_initfn, .abstract = true, .class_size = sizeof(SuperHCPUClass), diff --git a/target/sparc/cpu.c b/target/sparc/cpu.c index 130ab8f578..d6d3c4b031 100644 --- a/target/sparc/cpu.c +++ b/target/sparc/cpu.c @@ -930,6 +930,7 @@ static const TypeInfo sparc_cpu_type_info = { .name = TYPE_SPARC_CPU, .parent = TYPE_CPU, .instance_size = sizeof(SPARCCPU), + .instance_align = __alignof(SPARCCPU), .instance_init = sparc_cpu_initfn, .abstract = true, .class_size = sizeof(SPARCCPUClass), diff --git a/target/tricore/cpu.c b/target/tricore/cpu.c index 133a9ac70e..50aec6cf10 100644 --- a/target/tricore/cpu.c +++ b/target/tricore/cpu.c @@ -230,6 +230,7 @@ static const TypeInfo tricore_cpu_type_infos[] = { .name = TYPE_TRICORE_CPU, .parent = TYPE_CPU, .instance_size = sizeof(TriCoreCPU), + .instance_align = __alignof(TriCoreCPU), .instance_init = tricore_cpu_initfn, .abstract = true, .class_size = sizeof(TriCoreCPUClass), diff --git a/target/xtensa/cpu.c b/target/xtensa/cpu.c index acaf8c905f..281872d7ca 100644 --- a/target/xtensa/cpu.c +++ b/target/xtensa/cpu.c @@ -273,6 +273,7 @@ static const TypeInfo xtensa_cpu_type_info = { .name = TYPE_XTENSA_CPU, .parent = TYPE_CPU, .instance_size = sizeof(XtensaCPU), + .instance_align = __alignof(XtensaCPU), .instance_init = xtensa_cpu_initfn, .abstract = true, .class_size = sizeof(XtensaCPUClass), From 5d30bdcb1b72ec1d44397ee7047417617066d97a Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Tue, 12 Sep 2023 17:18:37 -0700 Subject: [PATCH 0155/1077] accel/tcg: Validate placement of CPUNegativeOffsetState Verify that the distance between CPUNegativeOffsetState and CPUArchState is no greater than any alignment requirements. Reviewed-by: Anton Johansson Signed-off-by: Richard Henderson --- include/exec/cpu-all.h | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/include/exec/cpu-all.h b/include/exec/cpu-all.h index 230525ebf7..ed7747a5f1 100644 --- a/include/exec/cpu-all.h +++ b/include/exec/cpu-all.h @@ -457,6 +457,12 @@ static inline CPUState *env_cpu(CPUArchState *env) return &env_archcpu(env)->parent_obj; } +/* + * Validate placement of CPUNegativeOffsetState. + */ +QEMU_BUILD_BUG_ON(offsetof(ArchCPU, env) - offsetof(ArchCPU, neg) >= + sizeof(CPUNegativeOffsetState) + __alignof(CPUArchState)); + /** * env_neg(env) * @env: The architecture environment From 3b3d7df545ff30762b169147398dbf90c42eb452 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Tue, 12 Sep 2023 17:47:56 -0700 Subject: [PATCH 0156/1077] accel/tcg: Move CPUNegativeOffsetState into CPUState Retain the separate structure to emphasize its importance. Enforce CPUArchState always follows CPUState without padding. Reviewed-by: Anton Johansson Signed-off-by: Richard Henderson --- accel/tcg/translate-all.c | 4 ++-- accel/tcg/translator.c | 8 ++++---- include/exec/cpu-all.h | 22 +++++++++------------- include/hw/core/cpu.h | 17 +++++++++++++++-- target/alpha/cpu.h | 1 - target/arm/cpu.h | 1 - target/avr/cpu.h | 1 - target/cris/cpu.h | 1 - target/hexagon/cpu.h | 2 +- target/hppa/cpu.h | 1 - target/i386/cpu.h | 1 - target/loongarch/cpu.h | 1 - target/m68k/cpu.h | 1 - target/microblaze/cpu.h | 6 +++--- target/mips/cpu.h | 4 ++-- target/nios2/cpu.h | 1 - target/openrisc/cpu.h | 1 - target/ppc/cpu.h | 1 - target/riscv/cpu.h | 2 +- target/rx/cpu.h | 1 - target/s390x/cpu.h | 1 - target/sh4/cpu.h | 1 - target/sparc/cpu.h | 1 - target/tricore/cpu.h | 1 - target/xtensa/cpu.h | 3 +-- 25 files changed, 38 insertions(+), 46 deletions(-) diff --git a/accel/tcg/translate-all.c b/accel/tcg/translate-all.c index b2d4e22c17..098d99b5d4 100644 --- a/accel/tcg/translate-all.c +++ b/accel/tcg/translate-all.c @@ -344,8 +344,8 @@ TranslationBlock *tb_gen_code(CPUState *cpu, tcg_ctx->page_bits = TARGET_PAGE_BITS; tcg_ctx->page_mask = TARGET_PAGE_MASK; tcg_ctx->tlb_dyn_max_bits = CPU_TLB_DYN_MAX_BITS; - tcg_ctx->tlb_fast_offset = - (int)offsetof(ArchCPU, neg.tlb.f) - (int)offsetof(ArchCPU, env); + tcg_ctx->tlb_fast_offset = (int)offsetof(ArchCPU, parent_obj.neg.tlb.f) + - (int)offsetof(ArchCPU, env); #endif tcg_ctx->insn_start_words = TARGET_INSN_START_WORDS; #ifdef TCG_GUEST_DEFAULT_MO diff --git a/accel/tcg/translator.c b/accel/tcg/translator.c index 358214d526..b3e12d61e9 100644 --- a/accel/tcg/translator.c +++ b/accel/tcg/translator.c @@ -48,8 +48,8 @@ static TCGOp *gen_tb_start(DisasContextBase *db, uint32_t cflags) if ((cflags & CF_USE_ICOUNT) || !(cflags & CF_NOIRQ)) { count = tcg_temp_new_i32(); tcg_gen_ld_i32(count, cpu_env, - offsetof(ArchCPU, neg.icount_decr.u32) - - offsetof(ArchCPU, env)); + offsetof(ArchCPU, parent_obj.neg.icount_decr.u32) + - offsetof(ArchCPU, env)); } if (cflags & CF_USE_ICOUNT) { @@ -78,8 +78,8 @@ static TCGOp *gen_tb_start(DisasContextBase *db, uint32_t cflags) if (cflags & CF_USE_ICOUNT) { tcg_gen_st16_i32(count, cpu_env, - offsetof(ArchCPU, neg.icount_decr.u16.low) - - offsetof(ArchCPU, env)); + offsetof(ArchCPU, parent_obj.neg.icount_decr.u16.low) + - offsetof(ArchCPU, env)); } /* diff --git a/include/exec/cpu-all.h b/include/exec/cpu-all.h index ed7747a5f1..0dd32cb0e9 100644 --- a/include/exec/cpu-all.h +++ b/include/exec/cpu-all.h @@ -432,9 +432,13 @@ int cpu_exec(CPUState *cpu); static inline void cpu_set_cpustate_pointers(ArchCPU *cpu) { cpu->parent_obj.env_ptr = &cpu->env; - cpu->parent_obj.icount_decr_ptr = &cpu->neg.icount_decr; + cpu->parent_obj.icount_decr_ptr = &cpu->parent_obj.neg.icount_decr; } +/* Validate correct placement of CPUArchState. */ +QEMU_BUILD_BUG_ON(offsetof(ArchCPU, parent_obj) != 0); +QEMU_BUILD_BUG_ON(offsetof(ArchCPU, env) != sizeof(CPUState)); + /** * env_archcpu(env) * @env: The architecture environment @@ -443,7 +447,7 @@ static inline void cpu_set_cpustate_pointers(ArchCPU *cpu) */ static inline ArchCPU *env_archcpu(CPUArchState *env) { - return container_of(env, ArchCPU, env); + return (void *)env - sizeof(CPUState); } /** @@ -454,15 +458,9 @@ static inline ArchCPU *env_archcpu(CPUArchState *env) */ static inline CPUState *env_cpu(CPUArchState *env) { - return &env_archcpu(env)->parent_obj; + return (void *)env - sizeof(CPUState); } -/* - * Validate placement of CPUNegativeOffsetState. - */ -QEMU_BUILD_BUG_ON(offsetof(ArchCPU, env) - offsetof(ArchCPU, neg) >= - sizeof(CPUNegativeOffsetState) + __alignof(CPUArchState)); - /** * env_neg(env) * @env: The architecture environment @@ -471,8 +469,7 @@ QEMU_BUILD_BUG_ON(offsetof(ArchCPU, env) - offsetof(ArchCPU, neg) >= */ static inline CPUNegativeOffsetState *env_neg(CPUArchState *env) { - ArchCPU *arch_cpu = container_of(env, ArchCPU, env); - return &arch_cpu->neg; + return &env_cpu(env)->neg; } /** @@ -483,8 +480,7 @@ static inline CPUNegativeOffsetState *env_neg(CPUArchState *env) */ static inline CPUNegativeOffsetState *cpu_neg(CPUState *cpu) { - ArchCPU *arch_cpu = container_of(cpu, ArchCPU, parent_obj); - return &arch_cpu->neg; + return &cpu->neg; } /** diff --git a/include/hw/core/cpu.h b/include/hw/core/cpu.h index 04baa5063c..115ddf6d8a 100644 --- a/include/hw/core/cpu.h +++ b/include/hw/core/cpu.h @@ -345,8 +345,8 @@ typedef union IcountDecr { } IcountDecr; /* - * This structure must be placed in ArchCPU immediately - * before CPUArchState, as a field named "neg". + * Elements of CPUState most efficiently accessed from CPUArchState, + * via small negative offsets. */ typedef struct CPUNegativeOffsetState { CPUTLB tlb; @@ -453,6 +453,9 @@ struct qemu_work_item; * dirty ring structure. * * State of one CPU core or thread. + * + * Align, in order to match possible alignment required by CPUArchState, + * and eliminate a hole between CPUState and CPUArchState within ArchCPU. */ struct CPUState { /*< private >*/ @@ -571,8 +574,18 @@ struct CPUState { /* track IOMMUs whose translations we've cached in the TCG TLB */ GArray *iommu_notifiers; + + /* + * MUST BE LAST in order to minimize the displacement to CPUArchState. + */ + char neg_align[-sizeof(CPUNegativeOffsetState) % 16] QEMU_ALIGNED(16); + CPUNegativeOffsetState neg; }; +/* Validate placement of CPUNegativeOffsetState. */ +QEMU_BUILD_BUG_ON(offsetof(CPUState, neg) != + sizeof(CPUState) - sizeof(CPUNegativeOffsetState)); + typedef QTAILQ_HEAD(CPUTailQ, CPUState) CPUTailQ; extern CPUTailQ cpus; diff --git a/target/alpha/cpu.h b/target/alpha/cpu.h index 13306665af..e2a467ec17 100644 --- a/target/alpha/cpu.h +++ b/target/alpha/cpu.h @@ -263,7 +263,6 @@ struct ArchCPU { CPUState parent_obj; /*< public >*/ - CPUNegativeOffsetState neg; CPUAlphaState env; /* This alarm doesn't exist in real hardware; we wish it did. */ diff --git a/target/arm/cpu.h b/target/arm/cpu.h index bd55c5dabf..a9edfb8353 100644 --- a/target/arm/cpu.h +++ b/target/arm/cpu.h @@ -856,7 +856,6 @@ struct ArchCPU { CPUState parent_obj; /*< public >*/ - CPUNegativeOffsetState neg; CPUARMState env; /* Coprocessor information */ diff --git a/target/avr/cpu.h b/target/avr/cpu.h index 7225174668..4ce22d8e4f 100644 --- a/target/avr/cpu.h +++ b/target/avr/cpu.h @@ -148,7 +148,6 @@ struct ArchCPU { CPUState parent_obj; /*< public >*/ - CPUNegativeOffsetState neg; CPUAVRState env; }; diff --git a/target/cris/cpu.h b/target/cris/cpu.h index 8e37c6e50d..676b8e93ca 100644 --- a/target/cris/cpu.h +++ b/target/cris/cpu.h @@ -178,7 +178,6 @@ struct ArchCPU { CPUState parent_obj; /*< public >*/ - CPUNegativeOffsetState neg; CPUCRISState env; }; diff --git a/target/hexagon/cpu.h b/target/hexagon/cpu.h index daef5c3f00..10cd1efd57 100644 --- a/target/hexagon/cpu.h +++ b/target/hexagon/cpu.h @@ -141,7 +141,7 @@ struct ArchCPU { /*< private >*/ CPUState parent_obj; /*< public >*/ - CPUNegativeOffsetState neg; + CPUHexagonState env; bool lldb_compat; diff --git a/target/hppa/cpu.h b/target/hppa/cpu.h index 730f35231a..798d0c26d7 100644 --- a/target/hppa/cpu.h +++ b/target/hppa/cpu.h @@ -237,7 +237,6 @@ struct ArchCPU { CPUState parent_obj; /*< public >*/ - CPUNegativeOffsetState neg; CPUHPPAState env; QEMUTimer *alarm_timer; }; diff --git a/target/i386/cpu.h b/target/i386/cpu.h index d3f377d48a..e1875466b9 100644 --- a/target/i386/cpu.h +++ b/target/i386/cpu.h @@ -1901,7 +1901,6 @@ struct ArchCPU { CPUState parent_obj; /*< public >*/ - CPUNegativeOffsetState neg; CPUX86State env; VMChangeStateEntry *vmsentry; diff --git a/target/loongarch/cpu.h b/target/loongarch/cpu.h index f125a8e49b..40e70a8119 100644 --- a/target/loongarch/cpu.h +++ b/target/loongarch/cpu.h @@ -375,7 +375,6 @@ struct ArchCPU { CPUState parent_obj; /*< public >*/ - CPUNegativeOffsetState neg; CPULoongArchState env; QEMUTimer timer; uint32_t phy_id; diff --git a/target/m68k/cpu.h b/target/m68k/cpu.h index cf70282717..20afb0c94d 100644 --- a/target/m68k/cpu.h +++ b/target/m68k/cpu.h @@ -168,7 +168,6 @@ struct ArchCPU { CPUState parent_obj; /*< public >*/ - CPUNegativeOffsetState neg; CPUM68KState env; }; diff --git a/target/microblaze/cpu.h b/target/microblaze/cpu.h index f6cab6ce19..e43c49d4af 100644 --- a/target/microblaze/cpu.h +++ b/target/microblaze/cpu.h @@ -345,15 +345,15 @@ typedef struct { struct ArchCPU { /*< private >*/ CPUState parent_obj; - /*< public >*/ + + CPUMBState env; + bool ns_axi_dp; bool ns_axi_ip; bool ns_axi_dc; bool ns_axi_ic; - CPUNegativeOffsetState neg; - CPUMBState env; MicroBlazeCPUConfig cfg; }; diff --git a/target/mips/cpu.h b/target/mips/cpu.h index 6d6af1f2a8..67f8e8b988 100644 --- a/target/mips/cpu.h +++ b/target/mips/cpu.h @@ -1213,10 +1213,10 @@ struct ArchCPU { CPUState parent_obj; /*< public >*/ + CPUMIPSState env; + Clock *clock; Clock *count_div; /* Divider for CP0_Count clock */ - CPUNegativeOffsetState neg; - CPUMIPSState env; }; diff --git a/target/nios2/cpu.h b/target/nios2/cpu.h index 477a3161fd..70b6377a4f 100644 --- a/target/nios2/cpu.h +++ b/target/nios2/cpu.h @@ -218,7 +218,6 @@ struct ArchCPU { CPUState parent_obj; /*< public >*/ - CPUNegativeOffsetState neg; CPUNios2State env; bool diverr_present; diff --git a/target/openrisc/cpu.h b/target/openrisc/cpu.h index ce4d605eb7..334997e9a1 100644 --- a/target/openrisc/cpu.h +++ b/target/openrisc/cpu.h @@ -305,7 +305,6 @@ struct ArchCPU { CPUState parent_obj; /*< public >*/ - CPUNegativeOffsetState neg; CPUOpenRISCState env; }; diff --git a/target/ppc/cpu.h b/target/ppc/cpu.h index d703a5f3c6..30392ebeee 100644 --- a/target/ppc/cpu.h +++ b/target/ppc/cpu.h @@ -1317,7 +1317,6 @@ struct ArchCPU { CPUState parent_obj; /*< public >*/ - CPUNegativeOffsetState neg; CPUPPCState env; int vcpu_id; diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h index 6316cbcc23..ef9cf21c0c 100644 --- a/target/riscv/cpu.h +++ b/target/riscv/cpu.h @@ -388,7 +388,7 @@ struct ArchCPU { /* < private > */ CPUState parent_obj; /* < public > */ - CPUNegativeOffsetState neg; + CPURISCVState env; char *dyn_csr_xml; diff --git a/target/rx/cpu.h b/target/rx/cpu.h index 7f03ffcfed..f66754eb8a 100644 --- a/target/rx/cpu.h +++ b/target/rx/cpu.h @@ -111,7 +111,6 @@ struct ArchCPU { CPUState parent_obj; /*< public >*/ - CPUNegativeOffsetState neg; CPURXState env; }; diff --git a/target/s390x/cpu.h b/target/s390x/cpu.h index 304029e57c..7bea7075e1 100644 --- a/target/s390x/cpu.h +++ b/target/s390x/cpu.h @@ -170,7 +170,6 @@ struct ArchCPU { CPUState parent_obj; /*< public >*/ - CPUNegativeOffsetState neg; CPUS390XState env; S390CPUModel *model; /* needed for live migration */ diff --git a/target/sh4/cpu.h b/target/sh4/cpu.h index 1399d3840f..f75a235973 100644 --- a/target/sh4/cpu.h +++ b/target/sh4/cpu.h @@ -208,7 +208,6 @@ struct ArchCPU { CPUState parent_obj; /*< public >*/ - CPUNegativeOffsetState neg; CPUSH4State env; }; diff --git a/target/sparc/cpu.h b/target/sparc/cpu.h index 98044572f2..b3a98f1d74 100644 --- a/target/sparc/cpu.h +++ b/target/sparc/cpu.h @@ -561,7 +561,6 @@ struct ArchCPU { CPUState parent_obj; /*< public >*/ - CPUNegativeOffsetState neg; CPUSPARCState env; }; diff --git a/target/tricore/cpu.h b/target/tricore/cpu.h index 1cace96b01..a357b573f2 100644 --- a/target/tricore/cpu.h +++ b/target/tricore/cpu.h @@ -67,7 +67,6 @@ struct ArchCPU { CPUState parent_obj; /*< public >*/ - CPUNegativeOffsetState neg; CPUTriCoreState env; }; diff --git a/target/xtensa/cpu.h b/target/xtensa/cpu.h index 87fe992ba6..c6bbef1e5d 100644 --- a/target/xtensa/cpu.h +++ b/target/xtensa/cpu.h @@ -560,9 +560,8 @@ struct ArchCPU { CPUState parent_obj; /*< public >*/ - Clock *clock; - CPUNegativeOffsetState neg; CPUXtensaState env; + Clock *clock; }; From e62de981113350194f9c1f78a6a8fd35c03b1599 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Tue, 12 Sep 2023 18:07:00 -0700 Subject: [PATCH 0157/1077] accel/tcg: Remove CPUState.icount_decr_ptr We can now access icount_decr directly. Reviewed-by: Anton Johansson Signed-off-by: Richard Henderson --- hw/core/cpu-common.c | 4 ++-- include/exec/cpu-all.h | 1 - include/hw/core/cpu.h | 2 -- 3 files changed, 2 insertions(+), 5 deletions(-) diff --git a/hw/core/cpu-common.c b/hw/core/cpu-common.c index ced66c2b34..08d5bbc873 100644 --- a/hw/core/cpu-common.c +++ b/hw/core/cpu-common.c @@ -86,7 +86,7 @@ void cpu_exit(CPUState *cpu) qatomic_set(&cpu->exit_request, 1); /* Ensure cpu_exec will see the exit request after TCG has exited. */ smp_wmb(); - qatomic_set(&cpu->icount_decr_ptr->u16.high, -1); + qatomic_set(&cpu->neg.icount_decr.u16.high, -1); } static int cpu_common_gdb_read_register(CPUState *cpu, GByteArray *buf, int reg) @@ -130,7 +130,7 @@ static void cpu_common_reset_hold(Object *obj) cpu->halted = cpu->start_powered_off; cpu->mem_io_pc = 0; cpu->icount_extra = 0; - qatomic_set(&cpu->icount_decr_ptr->u32, 0); + qatomic_set(&cpu->neg.icount_decr.u32, 0); cpu->can_do_io = 1; cpu->exception_index = -1; cpu->crash_occurred = false; diff --git a/include/exec/cpu-all.h b/include/exec/cpu-all.h index 0dd32cb0e9..25cd63e1b8 100644 --- a/include/exec/cpu-all.h +++ b/include/exec/cpu-all.h @@ -432,7 +432,6 @@ int cpu_exec(CPUState *cpu); static inline void cpu_set_cpustate_pointers(ArchCPU *cpu) { cpu->parent_obj.env_ptr = &cpu->env; - cpu->parent_obj.icount_decr_ptr = &cpu->parent_obj.neg.icount_decr; } /* Validate correct placement of CPUArchState. */ diff --git a/include/hw/core/cpu.h b/include/hw/core/cpu.h index 115ddf6d8a..973ff9d106 100644 --- a/include/hw/core/cpu.h +++ b/include/hw/core/cpu.h @@ -429,7 +429,6 @@ struct qemu_work_item; * @as: Pointer to the first AddressSpace, for the convenience of targets which * only have a single AddressSpace * @env_ptr: Pointer to subclass-specific CPUArchState field. - * @icount_decr_ptr: Pointer to IcountDecr field within subclass. * @gdb_regs: Additional GDB registers. * @gdb_num_regs: Number of total registers accessible to GDB. * @gdb_num_g_regs: Number of registers in GDB 'g' packets. @@ -504,7 +503,6 @@ struct CPUState { MemoryRegion *memory; CPUArchState *env_ptr; - IcountDecr *icount_decr_ptr; CPUJumpCache *tb_jmp_cache; From 464dacf6090d859a919596ba7452498c7446ced1 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 15 Sep 2023 15:41:39 -0700 Subject: [PATCH 0158/1077] accel/tcg: Move can_do_io to CPUNegativeOffsetState MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Minimize the displacement to can_do_io, since it may be touched at the start of each TranslationBlock. It fits into other padding within the substructure. Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Richard Henderson --- accel/dummy-cpus.c | 2 +- accel/hvf/hvf-accel-ops.c | 2 +- accel/kvm/kvm-accel-ops.c | 2 +- accel/tcg/cpu-exec-common.c | 2 +- accel/tcg/cpu-exec.c | 2 +- accel/tcg/cputlb.c | 2 +- accel/tcg/tcg-accel-ops-icount.c | 2 +- accel/tcg/tcg-accel-ops-mttcg.c | 2 +- accel/tcg/tcg-accel-ops-rr.c | 4 ++-- accel/tcg/translator.c | 10 ++++++---- hw/core/cpu-common.c | 2 +- include/hw/core/cpu.h | 6 ++---- softmmu/icount.c | 2 +- softmmu/watchpoint.c | 2 +- 14 files changed, 21 insertions(+), 21 deletions(-) diff --git a/accel/dummy-cpus.c b/accel/dummy-cpus.c index d6a1b8d0a2..b75c919ac3 100644 --- a/accel/dummy-cpus.c +++ b/accel/dummy-cpus.c @@ -27,7 +27,7 @@ static void *dummy_cpu_thread_fn(void *arg) qemu_mutex_lock_iothread(); qemu_thread_get_self(cpu->thread); cpu->thread_id = qemu_get_thread_id(); - cpu->can_do_io = 1; + cpu->neg.can_do_io = true; current_cpu = cpu; #ifndef _WIN32 diff --git a/accel/hvf/hvf-accel-ops.c b/accel/hvf/hvf-accel-ops.c index 3c94c79747..abe7adf7ee 100644 --- a/accel/hvf/hvf-accel-ops.c +++ b/accel/hvf/hvf-accel-ops.c @@ -428,7 +428,7 @@ static void *hvf_cpu_thread_fn(void *arg) qemu_thread_get_self(cpu->thread); cpu->thread_id = qemu_get_thread_id(); - cpu->can_do_io = 1; + cpu->neg.can_do_io = true; current_cpu = cpu; hvf_init_vcpu(cpu); diff --git a/accel/kvm/kvm-accel-ops.c b/accel/kvm/kvm-accel-ops.c index 457eafa380..6195150a0b 100644 --- a/accel/kvm/kvm-accel-ops.c +++ b/accel/kvm/kvm-accel-ops.c @@ -36,7 +36,7 @@ static void *kvm_vcpu_thread_fn(void *arg) qemu_mutex_lock_iothread(); qemu_thread_get_self(cpu->thread); cpu->thread_id = qemu_get_thread_id(); - cpu->can_do_io = 1; + cpu->neg.can_do_io = true; current_cpu = cpu; r = kvm_init_vcpu(cpu, &error_fatal); diff --git a/accel/tcg/cpu-exec-common.c b/accel/tcg/cpu-exec-common.c index 7e35d7f4b5..82ae837e39 100644 --- a/accel/tcg/cpu-exec-common.c +++ b/accel/tcg/cpu-exec-common.c @@ -36,7 +36,7 @@ void cpu_loop_exit_noexc(CPUState *cpu) void cpu_loop_exit(CPUState *cpu) { /* Undo the setting in cpu_tb_exec. */ - cpu->can_do_io = 1; + cpu->neg.can_do_io = true; /* Undo any setting in generated code. */ qemu_plugin_disable_mem_helpers(cpu); siglongjmp(cpu->jmp_env, 1); diff --git a/accel/tcg/cpu-exec.c b/accel/tcg/cpu-exec.c index 60f1986b85..de60fdb612 100644 --- a/accel/tcg/cpu-exec.c +++ b/accel/tcg/cpu-exec.c @@ -455,7 +455,7 @@ cpu_tb_exec(CPUState *cpu, TranslationBlock *itb, int *tb_exit) qemu_thread_jit_execute(); ret = tcg_qemu_tb_exec(env, tb_ptr); - cpu->can_do_io = 1; + cpu->neg.can_do_io = true; qemu_plugin_disable_mem_helpers(cpu); /* * TODO: Delay swapping back to the read-write region of the TB diff --git a/accel/tcg/cputlb.c b/accel/tcg/cputlb.c index 3270f65c20..d69e046b80 100644 --- a/accel/tcg/cputlb.c +++ b/accel/tcg/cputlb.c @@ -1361,7 +1361,7 @@ io_prepare(hwaddr *out_offset, CPUArchState *env, hwaddr xlat, section = iotlb_to_section(cpu, xlat, attrs); mr_offset = (xlat & TARGET_PAGE_MASK) + addr; cpu->mem_io_pc = retaddr; - if (!cpu->can_do_io) { + if (!cpu->neg.can_do_io) { cpu_io_recompile(cpu, retaddr); } diff --git a/accel/tcg/tcg-accel-ops-icount.c b/accel/tcg/tcg-accel-ops-icount.c index 3d2cfbbc97..0af643b217 100644 --- a/accel/tcg/tcg-accel-ops-icount.c +++ b/accel/tcg/tcg-accel-ops-icount.c @@ -153,7 +153,7 @@ void icount_handle_interrupt(CPUState *cpu, int mask) tcg_handle_interrupt(cpu, mask); if (qemu_cpu_is_self(cpu) && - !cpu->can_do_io + !cpu->neg.can_do_io && (mask & ~old_mask) != 0) { cpu_abort(cpu, "Raised interrupt while not in I/O function"); } diff --git a/accel/tcg/tcg-accel-ops-mttcg.c b/accel/tcg/tcg-accel-ops-mttcg.c index 4b0dfb4be7..ae95ba419e 100644 --- a/accel/tcg/tcg-accel-ops-mttcg.c +++ b/accel/tcg/tcg-accel-ops-mttcg.c @@ -80,7 +80,7 @@ static void *mttcg_cpu_thread_fn(void *arg) qemu_thread_get_self(cpu->thread); cpu->thread_id = qemu_get_thread_id(); - cpu->can_do_io = 1; + cpu->neg.can_do_io = true; current_cpu = cpu; cpu_thread_signal_created(cpu); qemu_guest_random_seed_thread_part2(cpu->random_seed); diff --git a/accel/tcg/tcg-accel-ops-rr.c b/accel/tcg/tcg-accel-ops-rr.c index 2d523289a8..671a3c4ca0 100644 --- a/accel/tcg/tcg-accel-ops-rr.c +++ b/accel/tcg/tcg-accel-ops-rr.c @@ -192,7 +192,7 @@ static void *rr_cpu_thread_fn(void *arg) qemu_thread_get_self(cpu->thread); cpu->thread_id = qemu_get_thread_id(); - cpu->can_do_io = 1; + cpu->neg.can_do_io = true; cpu_thread_signal_created(cpu); qemu_guest_random_seed_thread_part2(cpu->random_seed); @@ -334,7 +334,7 @@ void rr_start_vcpu_thread(CPUState *cpu) cpu->thread = single_tcg_cpu_thread; cpu->halt_cond = single_tcg_halt_cond; cpu->thread_id = first_cpu->thread_id; - cpu->can_do_io = 1; + cpu->neg.can_do_io = 1; cpu->created = true; } } diff --git a/accel/tcg/translator.c b/accel/tcg/translator.c index b3e12d61e9..460bfc4c74 100644 --- a/accel/tcg/translator.c +++ b/accel/tcg/translator.c @@ -20,9 +20,11 @@ static void set_can_do_io(DisasContextBase *db, bool val) { if (db->saved_can_do_io != val) { db->saved_can_do_io = val; - tcg_gen_st_i32(tcg_constant_i32(val), cpu_env, - offsetof(ArchCPU, parent_obj.can_do_io) - - offsetof(ArchCPU, env)); + + QEMU_BUILD_BUG_ON(sizeof_field(CPUState, neg.can_do_io) != 1); + tcg_gen_st8_i32(tcg_constant_i32(val), cpu_env, + offsetof(ArchCPU, parent_obj.neg.can_do_io) - + offsetof(ArchCPU, env)); } } @@ -83,7 +85,7 @@ static TCGOp *gen_tb_start(DisasContextBase *db, uint32_t cflags) } /* - * cpu->can_do_io is set automatically here at the beginning of + * cpu->neg.can_do_io is set automatically here at the beginning of * each translation block. The cost is minimal, plus it would be * very easy to forget doing it in the translator. */ diff --git a/hw/core/cpu-common.c b/hw/core/cpu-common.c index 08d5bbc873..4d406995ab 100644 --- a/hw/core/cpu-common.c +++ b/hw/core/cpu-common.c @@ -131,7 +131,7 @@ static void cpu_common_reset_hold(Object *obj) cpu->mem_io_pc = 0; cpu->icount_extra = 0; qatomic_set(&cpu->neg.icount_decr.u32, 0); - cpu->can_do_io = 1; + cpu->neg.can_do_io = true; cpu->exception_index = -1; cpu->crash_occurred = false; cpu->cflags_next_tb = -1; diff --git a/include/hw/core/cpu.h b/include/hw/core/cpu.h index 973ff9d106..293cedd9b5 100644 --- a/include/hw/core/cpu.h +++ b/include/hw/core/cpu.h @@ -351,6 +351,7 @@ typedef union IcountDecr { typedef struct CPUNegativeOffsetState { CPUTLB tlb; IcountDecr icount_decr; + bool can_do_io; } CPUNegativeOffsetState; typedef struct CPUBreakpoint { @@ -420,9 +421,7 @@ struct qemu_work_item; * @crash_occurred: Indicates the OS reported a crash (panic) for this CPU * @singlestep_enabled: Flags for single-stepping. * @icount_extra: Instructions until next timer event. - * @can_do_io: Nonzero if memory-mapped IO is safe. Deterministic execution - * requires that IO only be performed on the last instruction of a TB - * so that interrupts take effect immediately. + * @neg.can_do_io: True if memory-mapped IO is allowed. * @cpu_ases: Pointer to array of CPUAddressSpaces (which define the * AddressSpaces this CPU has) * @num_ases: number of CPUAddressSpaces in @cpu_ases @@ -547,7 +546,6 @@ struct CPUState { int cluster_index; uint32_t tcg_cflags; uint32_t halted; - uint32_t can_do_io; int32_t exception_index; AccelCPUState *accel; diff --git a/softmmu/icount.c b/softmmu/icount.c index 144e24829c..956d15e343 100644 --- a/softmmu/icount.c +++ b/softmmu/icount.c @@ -111,7 +111,7 @@ static int64_t icount_get_raw_locked(void) CPUState *cpu = current_cpu; if (cpu && cpu->running) { - if (!cpu->can_do_io) { + if (!cpu->neg.can_do_io) { error_report("Bad icount read"); exit(1); } diff --git a/softmmu/watchpoint.c b/softmmu/watchpoint.c index 5350163385..45d1f12faf 100644 --- a/softmmu/watchpoint.c +++ b/softmmu/watchpoint.c @@ -177,7 +177,7 @@ void cpu_check_watchpoint(CPUState *cpu, vaddr addr, vaddr len, * Force recompile to succeed, because icount may * be read only at the end of the block. */ - if (!cpu->can_do_io) { + if (!cpu->neg.can_do_io) { /* Force execution of one insn next time. */ cpu->cflags_next_tb = 1 | CF_LAST_IO | CF_NOIRQ | curr_cflags(cpu); From a953b5fa153fc384d2631cda8213efe983501609 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 13 Sep 2023 15:46:45 -0700 Subject: [PATCH 0159/1077] accel/tcg: Remove cpu_neg() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Now that CPUNegativeOffsetState is part of CPUState, we can reference it directly. Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Richard Henderson --- accel/tcg/cpu-exec.c | 14 +++++++------- accel/tcg/tcg-accel-ops-icount.c | 6 +++--- accel/tcg/tcg-accel-ops.c | 2 +- accel/tcg/translate-all.c | 6 +++--- include/exec/cpu-all.h | 11 ----------- include/exec/exec-all.h | 2 +- softmmu/icount.c | 2 +- 7 files changed, 16 insertions(+), 27 deletions(-) diff --git a/accel/tcg/cpu-exec.c b/accel/tcg/cpu-exec.c index de60fdb612..3a18dd84ef 100644 --- a/accel/tcg/cpu-exec.c +++ b/accel/tcg/cpu-exec.c @@ -73,7 +73,7 @@ static void align_clocks(SyncClocks *sc, CPUState *cpu) return; } - cpu_icount = cpu->icount_extra + cpu_neg(cpu)->icount_decr.u16.low; + cpu_icount = cpu->icount_extra + cpu->neg.icount_decr.u16.low; sc->diff_clk += icount_to_ns(sc->last_cpu_icount - cpu_icount); sc->last_cpu_icount = cpu_icount; @@ -124,7 +124,7 @@ static void init_delay_params(SyncClocks *sc, CPUState *cpu) sc->realtime_clock = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL_RT); sc->diff_clk = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) - sc->realtime_clock; sc->last_cpu_icount - = cpu->icount_extra + cpu_neg(cpu)->icount_decr.u16.low; + = cpu->icount_extra + cpu->neg.icount_decr.u16.low; if (sc->diff_clk < max_delay) { max_delay = sc->diff_clk; } @@ -717,7 +717,7 @@ static inline bool cpu_handle_exception(CPUState *cpu, int *ret) if (cpu->exception_index < 0) { #ifndef CONFIG_USER_ONLY if (replay_has_exception() - && cpu_neg(cpu)->icount_decr.u16.low + cpu->icount_extra == 0) { + && cpu->neg.icount_decr.u16.low + cpu->icount_extra == 0) { /* Execute just one insn to trigger exception pending in the log */ cpu->cflags_next_tb = (curr_cflags(cpu) & ~CF_USE_ICOUNT) | CF_LAST_IO | CF_NOIRQ | 1; @@ -807,7 +807,7 @@ static inline bool cpu_handle_interrupt(CPUState *cpu, * Ensure zeroing happens before reading cpu->exit_request or * cpu->interrupt_request (see also smp_wmb in cpu_exit()) */ - qatomic_set_mb(&cpu_neg(cpu)->icount_decr.u16.high, 0); + qatomic_set_mb(&cpu->neg.icount_decr.u16.high, 0); if (unlikely(qatomic_read(&cpu->interrupt_request))) { int interrupt_request; @@ -898,7 +898,7 @@ static inline bool cpu_handle_interrupt(CPUState *cpu, if (unlikely(qatomic_read(&cpu->exit_request)) || (icount_enabled() && (cpu->cflags_next_tb == -1 || cpu->cflags_next_tb & CF_USE_ICOUNT) - && cpu_neg(cpu)->icount_decr.u16.low + cpu->icount_extra == 0)) { + && cpu->neg.icount_decr.u16.low + cpu->icount_extra == 0)) { qatomic_set(&cpu->exit_request, 0); if (cpu->exception_index == -1) { cpu->exception_index = EXCP_INTERRUPT; @@ -923,7 +923,7 @@ static inline void cpu_loop_exec_tb(CPUState *cpu, TranslationBlock *tb, } *last_tb = NULL; - insns_left = qatomic_read(&cpu_neg(cpu)->icount_decr.u32); + insns_left = qatomic_read(&cpu->neg.icount_decr.u32); if (insns_left < 0) { /* Something asked us to stop executing chained TBs; just * continue round the main loop. Whatever requested the exit @@ -942,7 +942,7 @@ static inline void cpu_loop_exec_tb(CPUState *cpu, TranslationBlock *tb, icount_update(cpu); /* Refill decrementer and continue execution. */ insns_left = MIN(0xffff, cpu->icount_budget); - cpu_neg(cpu)->icount_decr.u16.low = insns_left; + cpu->neg.icount_decr.u16.low = insns_left; cpu->icount_extra = cpu->icount_budget - insns_left; /* diff --git a/accel/tcg/tcg-accel-ops-icount.c b/accel/tcg/tcg-accel-ops-icount.c index 0af643b217..b25685fb71 100644 --- a/accel/tcg/tcg-accel-ops-icount.c +++ b/accel/tcg/tcg-accel-ops-icount.c @@ -111,14 +111,14 @@ void icount_prepare_for_run(CPUState *cpu, int64_t cpu_budget) * each vCPU execution. However u16.high can be raised * asynchronously by cpu_exit/cpu_interrupt/tcg_handle_interrupt */ - g_assert(cpu_neg(cpu)->icount_decr.u16.low == 0); + g_assert(cpu->neg.icount_decr.u16.low == 0); g_assert(cpu->icount_extra == 0); replay_mutex_lock(); cpu->icount_budget = MIN(icount_get_limit(), cpu_budget); insns_left = MIN(0xffff, cpu->icount_budget); - cpu_neg(cpu)->icount_decr.u16.low = insns_left; + cpu->neg.icount_decr.u16.low = insns_left; cpu->icount_extra = cpu->icount_budget - insns_left; if (cpu->icount_budget == 0) { @@ -138,7 +138,7 @@ void icount_process_data(CPUState *cpu) icount_update(cpu); /* Reset the counters */ - cpu_neg(cpu)->icount_decr.u16.low = 0; + cpu->neg.icount_decr.u16.low = 0; cpu->icount_extra = 0; cpu->icount_budget = 0; diff --git a/accel/tcg/tcg-accel-ops.c b/accel/tcg/tcg-accel-ops.c index 3973591508..d885cc1d3c 100644 --- a/accel/tcg/tcg-accel-ops.c +++ b/accel/tcg/tcg-accel-ops.c @@ -91,7 +91,7 @@ void tcg_handle_interrupt(CPUState *cpu, int mask) if (!qemu_cpu_is_self(cpu)) { qemu_cpu_kick(cpu); } else { - qatomic_set(&cpu_neg(cpu)->icount_decr.u16.high, -1); + qatomic_set(&cpu->neg.icount_decr.u16.high, -1); } } diff --git a/accel/tcg/translate-all.c b/accel/tcg/translate-all.c index 098d99b5d4..ed0c7ef7ce 100644 --- a/accel/tcg/translate-all.c +++ b/accel/tcg/translate-all.c @@ -214,7 +214,7 @@ void cpu_restore_state_from_tb(CPUState *cpu, TranslationBlock *tb, * Reset the cycle counter to the start of the block and * shift if to the number of actually executed instructions. */ - cpu_neg(cpu)->icount_decr.u16.low += insns_left; + cpu->neg.icount_decr.u16.low += insns_left; } cpu->cc->tcg_ops->restore_state_to_opc(cpu, tb, data); @@ -623,7 +623,7 @@ void cpu_io_recompile(CPUState *cpu, uintptr_t retaddr) cc = CPU_GET_CLASS(cpu); if (cc->tcg_ops->io_recompile_replay_branch && cc->tcg_ops->io_recompile_replay_branch(cpu, tb)) { - cpu_neg(cpu)->icount_decr.u16.low++; + cpu->neg.icount_decr.u16.low++; n = 2; } @@ -779,7 +779,7 @@ void cpu_interrupt(CPUState *cpu, int mask) { g_assert(qemu_mutex_iothread_locked()); cpu->interrupt_request |= mask; - qatomic_set(&cpu_neg(cpu)->icount_decr.u16.high, -1); + qatomic_set(&cpu->neg.icount_decr.u16.high, -1); } #endif /* CONFIG_USER_ONLY */ diff --git a/include/exec/cpu-all.h b/include/exec/cpu-all.h index 25cd63e1b8..114ec70359 100644 --- a/include/exec/cpu-all.h +++ b/include/exec/cpu-all.h @@ -471,17 +471,6 @@ static inline CPUNegativeOffsetState *env_neg(CPUArchState *env) return &env_cpu(env)->neg; } -/** - * cpu_neg(cpu) - * @cpu: The generic CPUState - * - * Return the CPUNegativeOffsetState associated with the cpu. - */ -static inline CPUNegativeOffsetState *cpu_neg(CPUState *cpu) -{ - return &cpu->neg; -} - /** * env_tlb(env) * @env: The architecture environment diff --git a/include/exec/exec-all.h b/include/exec/exec-all.h index b2f5cd4c2a..2e4d337805 100644 --- a/include/exec/exec-all.h +++ b/include/exec/exec-all.h @@ -71,7 +71,7 @@ G_NORETURN void cpu_loop_exit_atomic(CPUState *cpu, uintptr_t pc); */ static inline bool cpu_loop_exit_requested(CPUState *cpu) { - return (int32_t)qatomic_read(&cpu_neg(cpu)->icount_decr.u32) < 0; + return (int32_t)qatomic_read(&cpu->neg.icount_decr.u32) < 0; } #if !defined(CONFIG_USER_ONLY) && defined(CONFIG_TCG) diff --git a/softmmu/icount.c b/softmmu/icount.c index 956d15e343..4527bfbd6e 100644 --- a/softmmu/icount.c +++ b/softmmu/icount.c @@ -75,7 +75,7 @@ static void icount_enable_adaptive(void) static int64_t icount_get_executed(CPUState *cpu) { return (cpu->icount_budget - - (cpu_neg(cpu)->icount_decr.u16.low + cpu->icount_extra)); + (cpu->neg.icount_decr.u16.low + cpu->icount_extra)); } /* From ad75a51e84af9638e4ec51aa1e6ec5f3ff642558 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 13 Sep 2023 16:37:36 -0700 Subject: [PATCH 0160/1077] tcg: Rename cpu_env to tcg_env MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Allow the name 'cpu_env' to be used for something else. Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Richard Henderson --- accel/tcg/plugin-gen.c | 8 +- accel/tcg/translator.c | 6 +- include/tcg/tcg.h | 2 +- target/alpha/translate.c | 142 +- target/arm/tcg/translate-a32.h | 2 +- target/arm/tcg/translate-a64.c | 378 ++--- target/arm/tcg/translate-a64.h | 4 +- target/arm/tcg/translate-m-nocp.c | 24 +- target/arm/tcg/translate-mve.c | 52 +- target/arm/tcg/translate-neon.c | 78 +- target/arm/tcg/translate-sme.c | 8 +- target/arm/tcg/translate-sve.c | 172 +-- target/arm/tcg/translate-vfp.c | 56 +- target/arm/tcg/translate.c | 228 +-- target/arm/tcg/translate.h | 16 +- target/avr/translate.c | 64 +- target/cris/translate.c | 68 +- target/cris/translate_v10.c.inc | 28 +- target/hexagon/README | 10 +- target/hexagon/gen_tcg.h | 120 +- target/hexagon/gen_tcg_funcs.py | 16 +- target/hexagon/gen_tcg_hvx.h | 20 +- target/hexagon/genptr.c | 36 +- target/hexagon/idef-parser/parser-helpers.c | 2 +- target/hexagon/macros.h | 8 +- target/hexagon/translate.c | 48 +- target/hppa/translate.c | 157 +- target/i386/tcg/decode-new.c.inc | 2 +- target/i386/tcg/emit.c.inc | 262 ++-- target/i386/tcg/translate.c | 580 ++++---- .../loongarch/insn_trans/trans_atomic.c.inc | 4 +- .../loongarch/insn_trans/trans_branch.c.inc | 2 +- target/loongarch/insn_trans/trans_extra.c.inc | 10 +- .../loongarch/insn_trans/trans_farith.c.inc | 6 +- target/loongarch/insn_trans/trans_fcmp.c.inc | 8 +- .../loongarch/insn_trans/trans_fmemory.c.inc | 8 +- target/loongarch/insn_trans/trans_fmov.c.inc | 20 +- .../loongarch/insn_trans/trans_memory.c.inc | 8 +- .../insn_trans/trans_privileged.c.inc | 52 +- target/loongarch/insn_trans/trans_vec.c.inc | 24 +- target/loongarch/translate.c | 18 +- target/m68k/translate.c | 302 ++-- target/microblaze/translate.c | 50 +- target/mips/tcg/lcsr_translate.c | 6 +- target/mips/tcg/micromips_translate.c.inc | 12 +- target/mips/tcg/msa_translate.c | 34 +- target/mips/tcg/mxu_translate.c | 4 +- target/mips/tcg/nanomips_translate.c.inc | 200 +-- target/mips/tcg/translate.c | 1284 ++++++++--------- target/mips/tcg/translate.h | 6 +- target/mips/tcg/vr54xx_translate.c | 2 +- target/nios2/translate.c | 48 +- target/openrisc/translate.c | 84 +- target/ppc/power8-pmu-regs.c.inc | 8 +- target/ppc/translate.c | 362 ++--- target/ppc/translate/branch-impl.c.inc | 2 +- target/ppc/translate/dfp-impl.c.inc | 22 +- target/ppc/translate/fixedpoint-impl.c.inc | 2 +- target/ppc/translate/fp-impl.c.inc | 50 +- .../ppc/translate/processor-ctrl-impl.c.inc | 8 +- target/ppc/translate/spe-impl.c.inc | 30 +- target/ppc/translate/storage-ctrl-impl.c.inc | 26 +- target/ppc/translate/vmx-impl.c.inc | 34 +- target/ppc/translate/vsx-impl.c.inc | 54 +- .../riscv/insn_trans/trans_privileged.c.inc | 8 +- target/riscv/insn_trans/trans_rvbf16.c.inc | 10 +- target/riscv/insn_trans/trans_rvd.c.inc | 48 +- target/riscv/insn_trans/trans_rvf.c.inc | 46 +- target/riscv/insn_trans/trans_rvh.c.inc | 8 +- target/riscv/insn_trans/trans_rvi.c.inc | 16 +- target/riscv/insn_trans/trans_rvm.c.inc | 16 +- target/riscv/insn_trans/trans_rvv.c.inc | 130 +- target/riscv/insn_trans/trans_rvvk.c.inc | 30 +- target/riscv/insn_trans/trans_rvzce.c.inc | 2 +- target/riscv/insn_trans/trans_rvzfa.c.inc | 38 +- target/riscv/insn_trans/trans_rvzfh.c.inc | 54 +- target/riscv/insn_trans/trans_rvzicbo.c.inc | 8 +- target/riscv/insn_trans/trans_svinval.c.inc | 6 +- target/riscv/insn_trans/trans_xthead.c.inc | 2 +- target/riscv/translate.c | 50 +- target/rx/translate.c | 56 +- target/s390x/tcg/translate.c | 424 +++--- target/s390x/tcg/translate_vx.c.inc | 104 +- target/sh4/translate.c | 124 +- target/sparc/translate.c | 328 ++--- target/tricore/translate.c | 226 +-- target/xtensa/translate.c | 188 +-- tcg/tcg-op-gvec.c | 300 ++-- tcg/tcg-op-ldst.c | 22 +- tcg/tcg-op.c | 2 +- tcg/tcg.c | 4 +- 91 files changed, 3818 insertions(+), 3819 deletions(-) diff --git a/accel/tcg/plugin-gen.c b/accel/tcg/plugin-gen.c index 5c13615112..985c980c92 100644 --- a/accel/tcg/plugin-gen.c +++ b/accel/tcg/plugin-gen.c @@ -104,7 +104,7 @@ static void gen_empty_udata_cb(void) TCGv_ptr udata = tcg_temp_ebb_new_ptr(); tcg_gen_movi_ptr(udata, 0); - tcg_gen_ld_i32(cpu_index, cpu_env, + tcg_gen_ld_i32(cpu_index, tcg_env, -offsetof(ArchCPU, env) + offsetof(CPUState, cpu_index)); gen_helper_plugin_vcpu_udata_cb(cpu_index, udata); @@ -138,7 +138,7 @@ static void gen_empty_mem_cb(TCGv_i64 addr, uint32_t info) tcg_gen_movi_i32(meminfo, info); tcg_gen_movi_ptr(udata, 0); - tcg_gen_ld_i32(cpu_index, cpu_env, + tcg_gen_ld_i32(cpu_index, tcg_env, -offsetof(ArchCPU, env) + offsetof(CPUState, cpu_index)); gen_helper_plugin_vcpu_mem_cb(cpu_index, meminfo, addr, udata); @@ -157,7 +157,7 @@ static void gen_empty_mem_helper(void) TCGv_ptr ptr = tcg_temp_ebb_new_ptr(); tcg_gen_movi_ptr(ptr, 0); - tcg_gen_st_ptr(ptr, cpu_env, offsetof(CPUState, plugin_mem_cbs) - + tcg_gen_st_ptr(ptr, tcg_env, offsetof(CPUState, plugin_mem_cbs) - offsetof(ArchCPU, env)); tcg_temp_free_ptr(ptr); } @@ -581,7 +581,7 @@ void plugin_gen_disable_mem_helpers(void) if (!tcg_ctx->plugin_tb->mem_helper) { return; } - tcg_gen_st_ptr(tcg_constant_ptr(NULL), cpu_env, + tcg_gen_st_ptr(tcg_constant_ptr(NULL), tcg_env, offsetof(CPUState, plugin_mem_cbs) - offsetof(ArchCPU, env)); } diff --git a/accel/tcg/translator.c b/accel/tcg/translator.c index 460bfc4c74..563262e5a9 100644 --- a/accel/tcg/translator.c +++ b/accel/tcg/translator.c @@ -22,7 +22,7 @@ static void set_can_do_io(DisasContextBase *db, bool val) db->saved_can_do_io = val; QEMU_BUILD_BUG_ON(sizeof_field(CPUState, neg.can_do_io) != 1); - tcg_gen_st8_i32(tcg_constant_i32(val), cpu_env, + tcg_gen_st8_i32(tcg_constant_i32(val), tcg_env, offsetof(ArchCPU, parent_obj.neg.can_do_io) - offsetof(ArchCPU, env)); } @@ -49,7 +49,7 @@ static TCGOp *gen_tb_start(DisasContextBase *db, uint32_t cflags) if ((cflags & CF_USE_ICOUNT) || !(cflags & CF_NOIRQ)) { count = tcg_temp_new_i32(); - tcg_gen_ld_i32(count, cpu_env, + tcg_gen_ld_i32(count, tcg_env, offsetof(ArchCPU, parent_obj.neg.icount_decr.u32) - offsetof(ArchCPU, env)); } @@ -79,7 +79,7 @@ static TCGOp *gen_tb_start(DisasContextBase *db, uint32_t cflags) } if (cflags & CF_USE_ICOUNT) { - tcg_gen_st16_i32(count, cpu_env, + tcg_gen_st16_i32(count, tcg_env, offsetof(ArchCPU, parent_obj.neg.icount_decr.u16.low) - offsetof(ArchCPU, env)); } diff --git a/include/tcg/tcg.h b/include/tcg/tcg.h index c9c6d770d0..3cdbeaf460 100644 --- a/include/tcg/tcg.h +++ b/include/tcg/tcg.h @@ -577,7 +577,7 @@ static inline bool temp_readonly(TCGTemp *ts) extern __thread TCGContext *tcg_ctx; extern const void *tcg_code_gen_epilogue; extern uintptr_t tcg_splitwx_diff; -extern TCGv_env cpu_env; +extern TCGv_env tcg_env; bool in_code_gen_buffer(const void *p); diff --git a/target/alpha/translate.c b/target/alpha/translate.c index 9be912c50c..46af6574bf 100644 --- a/target/alpha/translate.c +++ b/target/alpha/translate.c @@ -131,13 +131,13 @@ void alpha_translate_init(void) int i; for (i = 0; i < 31; i++) { - cpu_std_ir[i] = tcg_global_mem_new_i64(cpu_env, + cpu_std_ir[i] = tcg_global_mem_new_i64(tcg_env, offsetof(CPUAlphaState, ir[i]), greg_names[i]); } for (i = 0; i < 31; i++) { - cpu_fir[i] = tcg_global_mem_new_i64(cpu_env, + cpu_fir[i] = tcg_global_mem_new_i64(tcg_env, offsetof(CPUAlphaState, fir[i]), freg_names[i]); } @@ -146,7 +146,7 @@ void alpha_translate_init(void) memcpy(cpu_pal_ir, cpu_std_ir, sizeof(cpu_pal_ir)); for (i = 0; i < 8; i++) { int r = (i == 7 ? 25 : i + 8); - cpu_pal_ir[r] = tcg_global_mem_new_i64(cpu_env, + cpu_pal_ir[r] = tcg_global_mem_new_i64(tcg_env, offsetof(CPUAlphaState, shadow[i]), shadow_names[i]); @@ -155,7 +155,7 @@ void alpha_translate_init(void) for (i = 0; i < ARRAY_SIZE(vars); ++i) { const GlobalVar *v = &vars[i]; - *v->var = tcg_global_mem_new_i64(cpu_env, v->ofs, v->name); + *v->var = tcg_global_mem_new_i64(tcg_env, v->ofs, v->name); } } @@ -244,12 +244,12 @@ static int get_flag_ofs(unsigned shift) static void ld_flag_byte(TCGv val, unsigned shift) { - tcg_gen_ld8u_i64(val, cpu_env, get_flag_ofs(shift)); + tcg_gen_ld8u_i64(val, tcg_env, get_flag_ofs(shift)); } static void st_flag_byte(TCGv val, unsigned shift) { - tcg_gen_st8_i64(val, cpu_env, get_flag_ofs(shift)); + tcg_gen_st8_i64(val, tcg_env, get_flag_ofs(shift)); } static void gen_excp_1(int exception, int error_code) @@ -258,7 +258,7 @@ static void gen_excp_1(int exception, int error_code) tmp1 = tcg_constant_i32(exception); tmp2 = tcg_constant_i32(error_code); - gen_helper_excp(cpu_env, tmp1, tmp2); + gen_helper_excp(tcg_env, tmp1, tmp2); } static DisasJumpType gen_excp(DisasContext *ctx, int exception, int error_code) @@ -582,7 +582,7 @@ static void gen_qual_roundmode(DisasContext *ctx, int fn11) tcg_gen_movi_i32(tmp, float_round_down); break; case QUAL_RM_D: - tcg_gen_ld8u_i32(tmp, cpu_env, + tcg_gen_ld8u_i32(tmp, tcg_env, offsetof(CPUAlphaState, fpcr_dyn_round)); break; } @@ -591,7 +591,7 @@ static void gen_qual_roundmode(DisasContext *ctx, int fn11) /* ??? The "fpu/softfloat.h" interface is to call set_float_rounding_mode. With CONFIG_SOFTFLOAT that expands to an out-of-line call that just sets the one field. */ - tcg_gen_st8_i32(tmp, cpu_env, + tcg_gen_st8_i32(tmp, tcg_env, offsetof(CPUAlphaState, fp_status.float_rounding_mode)); #else gen_helper_setroundmode(tmp); @@ -611,7 +611,7 @@ static void gen_qual_flushzero(DisasContext *ctx, int fn11) tmp = tcg_temp_new_i32(); if (fn11) { /* Underflow is enabled, use the FPCR setting. */ - tcg_gen_ld8u_i32(tmp, cpu_env, + tcg_gen_ld8u_i32(tmp, tcg_env, offsetof(CPUAlphaState, fpcr_flush_to_zero)); } else { /* Underflow is disabled, force flush-to-zero. */ @@ -619,7 +619,7 @@ static void gen_qual_flushzero(DisasContext *ctx, int fn11) } #if defined(CONFIG_SOFTFLOAT_INLINE) - tcg_gen_st8_i32(tmp, cpu_env, + tcg_gen_st8_i32(tmp, tcg_env, offsetof(CPUAlphaState, fp_status.flush_to_zero)); #else gen_helper_setflushzero(tmp); @@ -636,16 +636,16 @@ static TCGv gen_ieee_input(DisasContext *ctx, int reg, int fn11, int is_cmp) val = cpu_fir[reg]; if ((fn11 & QUAL_S) == 0) { if (is_cmp) { - gen_helper_ieee_input_cmp(cpu_env, val); + gen_helper_ieee_input_cmp(tcg_env, val); } else { - gen_helper_ieee_input(cpu_env, val); + gen_helper_ieee_input(tcg_env, val); } } else { #ifndef CONFIG_USER_ONLY /* In system mode, raise exceptions for denormals like real hardware. In user mode, proceed as if the OS completion handler is handling the denormal as per spec. */ - gen_helper_ieee_input_s(cpu_env, val); + gen_helper_ieee_input_s(tcg_env, val); #endif } } @@ -678,9 +678,9 @@ static void gen_fp_exc_raise(int rc, int fn11) or if we were to do something clever with imprecise exceptions. */ reg = tcg_constant_i32(rc + 32); if (fn11 & QUAL_S) { - gen_helper_fp_exc_raise_s(cpu_env, ign, reg); + gen_helper_fp_exc_raise_s(tcg_env, ign, reg); } else { - gen_helper_fp_exc_raise(cpu_env, ign, reg); + gen_helper_fp_exc_raise(tcg_env, ign, reg); } } @@ -705,7 +705,7 @@ static void gen_ieee_arith2(DisasContext *ctx, gen_qual_flushzero(ctx, fn11); vb = gen_ieee_input(ctx, rb, fn11, 0); - helper(dest_fpr(ctx, rc), cpu_env, vb); + helper(dest_fpr(ctx, rc), tcg_env, vb); gen_fp_exc_raise(rc, fn11); } @@ -732,10 +732,10 @@ static void gen_cvttq(DisasContext *ctx, int rb, int rc, int fn11) /* Almost all integer conversions use cropped rounding; special case that. */ if ((fn11 & QUAL_RM_MASK) == QUAL_RM_C) { - gen_helper_cvttq_c(vc, cpu_env, vb); + gen_helper_cvttq_c(vc, tcg_env, vb); } else { gen_qual_roundmode(ctx, fn11); - gen_helper_cvttq(vc, cpu_env, vb); + gen_helper_cvttq(vc, tcg_env, vb); } gen_fp_exc_raise(rc, fn11); } @@ -754,10 +754,10 @@ static void gen_ieee_intcvt(DisasContext *ctx, is inexact. Thus we only need to worry about exceptions when inexact handling is requested. */ if (fn11 & QUAL_I) { - helper(vc, cpu_env, vb); + helper(vc, tcg_env, vb); gen_fp_exc_raise(rc, fn11); } else { - helper(vc, cpu_env, vb); + helper(vc, tcg_env, vb); } } @@ -797,7 +797,7 @@ static void gen_ieee_arith3(DisasContext *ctx, va = gen_ieee_input(ctx, ra, fn11, 0); vb = gen_ieee_input(ctx, rb, fn11, 0); vc = dest_fpr(ctx, rc); - helper(vc, cpu_env, va, vb); + helper(vc, tcg_env, va, vb); gen_fp_exc_raise(rc, fn11); } @@ -826,7 +826,7 @@ static void gen_ieee_compare(DisasContext *ctx, va = gen_ieee_input(ctx, ra, fn11, 1); vb = gen_ieee_input(ctx, rb, fn11, 1); vc = dest_fpr(ctx, rc); - helper(vc, cpu_env, va, vb); + helper(vc, tcg_env, va, vb); gen_fp_exc_raise(rc, fn11); } @@ -1059,12 +1059,12 @@ static DisasJumpType gen_call_pal(DisasContext *ctx, int palcode) break; case 0x9E: /* RDUNIQUE */ - tcg_gen_ld_i64(ctx->ir[IR_V0], cpu_env, + tcg_gen_ld_i64(ctx->ir[IR_V0], tcg_env, offsetof(CPUAlphaState, unique)); break; case 0x9F: /* WRUNIQUE */ - tcg_gen_st_i64(ctx->ir[IR_A0], cpu_env, + tcg_gen_st_i64(ctx->ir[IR_A0], tcg_env, offsetof(CPUAlphaState, unique)); break; default: @@ -1088,17 +1088,17 @@ static DisasJumpType gen_call_pal(DisasContext *ctx, int palcode) break; case 0x2D: /* WRVPTPTR */ - tcg_gen_st_i64(ctx->ir[IR_A0], cpu_env, + tcg_gen_st_i64(ctx->ir[IR_A0], tcg_env, offsetof(CPUAlphaState, vptptr)); break; case 0x31: /* WRVAL */ - tcg_gen_st_i64(ctx->ir[IR_A0], cpu_env, + tcg_gen_st_i64(ctx->ir[IR_A0], tcg_env, offsetof(CPUAlphaState, sysval)); break; case 0x32: /* RDVAL */ - tcg_gen_ld_i64(ctx->ir[IR_V0], cpu_env, + tcg_gen_ld_i64(ctx->ir[IR_V0], tcg_env, offsetof(CPUAlphaState, sysval)); break; @@ -1126,23 +1126,23 @@ static DisasJumpType gen_call_pal(DisasContext *ctx, int palcode) case 0x38: /* WRUSP */ - tcg_gen_st_i64(ctx->ir[IR_A0], cpu_env, + tcg_gen_st_i64(ctx->ir[IR_A0], tcg_env, offsetof(CPUAlphaState, usp)); break; case 0x3A: /* RDUSP */ - tcg_gen_ld_i64(ctx->ir[IR_V0], cpu_env, + tcg_gen_ld_i64(ctx->ir[IR_V0], tcg_env, offsetof(CPUAlphaState, usp)); break; case 0x3C: /* WHAMI */ - tcg_gen_ld32s_i64(ctx->ir[IR_V0], cpu_env, + tcg_gen_ld32s_i64(ctx->ir[IR_V0], tcg_env, -offsetof(AlphaCPU, env) + offsetof(CPUState, cpu_index)); break; case 0x3E: /* WTINT */ - tcg_gen_st_i32(tcg_constant_i32(1), cpu_env, + tcg_gen_st_i32(tcg_constant_i32(1), tcg_env, -offsetof(AlphaCPU, env) + offsetof(CPUState, halted)); tcg_gen_movi_i64(ctx->ir[IR_V0], 0); @@ -1174,7 +1174,7 @@ static DisasJumpType gen_call_pal(DisasContext *ctx, int palcode) } tcg_gen_movi_i64(tmp, exc_addr); - tcg_gen_st_i64(tmp, cpu_env, offsetof(CPUAlphaState, exc_addr)); + tcg_gen_st_i64(tmp, tcg_env, offsetof(CPUAlphaState, exc_addr)); entry += (palcode & 0x80 ? 0x2000 + (palcode - 0x80) * 64 @@ -1254,9 +1254,9 @@ static DisasJumpType gen_mfpr(DisasContext *ctx, TCGv va, int regno) if (data == 0) { tcg_gen_movi_i64(va, 0); } else if (data & PR_LONG) { - tcg_gen_ld32s_i64(va, cpu_env, data & ~PR_LONG); + tcg_gen_ld32s_i64(va, tcg_env, data & ~PR_LONG); } else { - tcg_gen_ld_i64(va, cpu_env, data); + tcg_gen_ld_i64(va, tcg_env, data); } break; } @@ -1272,17 +1272,17 @@ static DisasJumpType gen_mtpr(DisasContext *ctx, TCGv vb, int regno) switch (regno) { case 255: /* TBIA */ - gen_helper_tbia(cpu_env); + gen_helper_tbia(tcg_env); break; case 254: /* TBIS */ - gen_helper_tbis(cpu_env, vb); + gen_helper_tbis(tcg_env, vb); break; case 253: /* WAIT */ - tcg_gen_st_i32(tcg_constant_i32(1), cpu_env, + tcg_gen_st_i32(tcg_constant_i32(1), tcg_env, -offsetof(AlphaCPU, env) + offsetof(CPUState, halted)); return gen_excp(ctx, EXCP_HALTED, 0); @@ -1296,16 +1296,16 @@ static DisasJumpType gen_mtpr(DisasContext *ctx, TCGv vb, int regno) if (translator_io_start(&ctx->base)) { ret = DISAS_PC_STALE; } - gen_helper_set_alarm(cpu_env, vb); + gen_helper_set_alarm(tcg_env, vb); break; case 7: /* PALBR */ - tcg_gen_st_i64(vb, cpu_env, offsetof(CPUAlphaState, palbr)); + tcg_gen_st_i64(vb, tcg_env, offsetof(CPUAlphaState, palbr)); /* Changing the PAL base register implies un-chaining all of the TBs that ended with a CALL_PAL. Since the base register usually only changes during boot, flushing everything works well. */ - gen_helper_tb_flush(cpu_env); + gen_helper_tb_flush(tcg_env); return DISAS_PC_STALE; case 32 ... 39: @@ -1327,9 +1327,9 @@ static DisasJumpType gen_mtpr(DisasContext *ctx, TCGv vb, int regno) data = cpu_pr_data(regno); if (data != 0) { if (data & PR_LONG) { - tcg_gen_st32_i64(vb, cpu_env, data & ~PR_LONG); + tcg_gen_st32_i64(vb, tcg_env, data & ~PR_LONG); } else { - tcg_gen_st_i64(vb, cpu_env, data); + tcg_gen_st_i64(vb, tcg_env, data); } } break; @@ -1594,7 +1594,7 @@ static DisasJumpType translate_one(DisasContext *ctx, uint32_t insn) tcg_gen_ext32s_i64(vc, vb); tcg_gen_add_i64(tmp, tmp, vc); tcg_gen_ext32s_i64(vc, tmp); - gen_helper_check_overflow(cpu_env, vc, tmp); + gen_helper_check_overflow(tcg_env, vc, tmp); break; case 0x49: /* SUBL/V */ @@ -1603,7 +1603,7 @@ static DisasJumpType translate_one(DisasContext *ctx, uint32_t insn) tcg_gen_ext32s_i64(vc, vb); tcg_gen_sub_i64(tmp, tmp, vc); tcg_gen_ext32s_i64(vc, tmp); - gen_helper_check_overflow(cpu_env, vc, tmp); + gen_helper_check_overflow(tcg_env, vc, tmp); break; case 0x4D: /* CMPLT */ @@ -1620,7 +1620,7 @@ static DisasJumpType translate_one(DisasContext *ctx, uint32_t insn) tcg_gen_and_i64(tmp, tmp, tmp2); tcg_gen_shri_i64(tmp, tmp, 63); tcg_gen_movi_i64(tmp2, 0); - gen_helper_check_overflow(cpu_env, tmp, tmp2); + gen_helper_check_overflow(tcg_env, tmp, tmp2); break; case 0x69: /* SUBQ/V */ @@ -1633,7 +1633,7 @@ static DisasJumpType translate_one(DisasContext *ctx, uint32_t insn) tcg_gen_and_i64(tmp, tmp, tmp2); tcg_gen_shri_i64(tmp, tmp, 63); tcg_gen_movi_i64(tmp2, 0); - gen_helper_check_overflow(cpu_env, tmp, tmp2); + gen_helper_check_overflow(tcg_env, tmp, tmp2); break; case 0x6D: /* CMPLE */ @@ -1924,7 +1924,7 @@ static DisasJumpType translate_one(DisasContext *ctx, uint32_t insn) tcg_gen_ext32s_i64(vc, vb); tcg_gen_mul_i64(tmp, tmp, vc); tcg_gen_ext32s_i64(vc, tmp); - gen_helper_check_overflow(cpu_env, vc, tmp); + gen_helper_check_overflow(tcg_env, vc, tmp); break; case 0x60: /* MULQ/V */ @@ -1932,7 +1932,7 @@ static DisasJumpType translate_one(DisasContext *ctx, uint32_t insn) tmp2 = tcg_temp_new(); tcg_gen_muls2_i64(vc, tmp, va, vb); tcg_gen_sari_i64(tmp2, vc, 63); - gen_helper_check_overflow(cpu_env, tmp, tmp2); + gen_helper_check_overflow(tcg_env, tmp, tmp2); break; default: goto invalid_opc; @@ -1957,7 +1957,7 @@ static DisasJumpType translate_one(DisasContext *ctx, uint32_t insn) REQUIRE_REG_31(ra); REQUIRE_FEN; vb = load_fpr(ctx, rb); - gen_helper_sqrtf(vc, cpu_env, vb); + gen_helper_sqrtf(vc, tcg_env, vb); break; case 0x0B: /* SQRTS */ @@ -1986,7 +1986,7 @@ static DisasJumpType translate_one(DisasContext *ctx, uint32_t insn) REQUIRE_REG_31(ra); REQUIRE_FEN; vb = load_fpr(ctx, rb); - gen_helper_sqrtg(vc, cpu_env, vb); + gen_helper_sqrtg(vc, tcg_env, vb); break; case 0x02B: /* SQRTT */ @@ -2009,22 +2009,22 @@ static DisasJumpType translate_one(DisasContext *ctx, uint32_t insn) case 0x00: /* ADDF */ REQUIRE_FEN; - gen_helper_addf(vc, cpu_env, va, vb); + gen_helper_addf(vc, tcg_env, va, vb); break; case 0x01: /* SUBF */ REQUIRE_FEN; - gen_helper_subf(vc, cpu_env, va, vb); + gen_helper_subf(vc, tcg_env, va, vb); break; case 0x02: /* MULF */ REQUIRE_FEN; - gen_helper_mulf(vc, cpu_env, va, vb); + gen_helper_mulf(vc, tcg_env, va, vb); break; case 0x03: /* DIVF */ REQUIRE_FEN; - gen_helper_divf(vc, cpu_env, va, vb); + gen_helper_divf(vc, tcg_env, va, vb); break; case 0x1E: /* CVTDG -- TODO */ @@ -2033,43 +2033,43 @@ static DisasJumpType translate_one(DisasContext *ctx, uint32_t insn) case 0x20: /* ADDG */ REQUIRE_FEN; - gen_helper_addg(vc, cpu_env, va, vb); + gen_helper_addg(vc, tcg_env, va, vb); break; case 0x21: /* SUBG */ REQUIRE_FEN; - gen_helper_subg(vc, cpu_env, va, vb); + gen_helper_subg(vc, tcg_env, va, vb); break; case 0x22: /* MULG */ REQUIRE_FEN; - gen_helper_mulg(vc, cpu_env, va, vb); + gen_helper_mulg(vc, tcg_env, va, vb); break; case 0x23: /* DIVG */ REQUIRE_FEN; - gen_helper_divg(vc, cpu_env, va, vb); + gen_helper_divg(vc, tcg_env, va, vb); break; case 0x25: /* CMPGEQ */ REQUIRE_FEN; - gen_helper_cmpgeq(vc, cpu_env, va, vb); + gen_helper_cmpgeq(vc, tcg_env, va, vb); break; case 0x26: /* CMPGLT */ REQUIRE_FEN; - gen_helper_cmpglt(vc, cpu_env, va, vb); + gen_helper_cmpglt(vc, tcg_env, va, vb); break; case 0x27: /* CMPGLE */ REQUIRE_FEN; - gen_helper_cmpgle(vc, cpu_env, va, vb); + gen_helper_cmpgle(vc, tcg_env, va, vb); break; case 0x2C: /* CVTGF */ REQUIRE_REG_31(ra); REQUIRE_FEN; - gen_helper_cvtgf(vc, cpu_env, vb); + gen_helper_cvtgf(vc, tcg_env, vb); break; case 0x2D: /* CVTGD -- TODO */ @@ -2079,19 +2079,19 @@ static DisasJumpType translate_one(DisasContext *ctx, uint32_t insn) /* CVTGQ */ REQUIRE_REG_31(ra); REQUIRE_FEN; - gen_helper_cvtgq(vc, cpu_env, vb); + gen_helper_cvtgq(vc, tcg_env, vb); break; case 0x3C: /* CVTQF */ REQUIRE_REG_31(ra); REQUIRE_FEN; - gen_helper_cvtqf(vc, cpu_env, vb); + gen_helper_cvtqf(vc, tcg_env, vb); break; case 0x3E: /* CVTQG */ REQUIRE_REG_31(ra); REQUIRE_FEN; - gen_helper_cvtqg(vc, cpu_env, vb); + gen_helper_cvtqg(vc, tcg_env, vb); break; default: goto invalid_opc; @@ -2242,7 +2242,7 @@ static DisasJumpType translate_one(DisasContext *ctx, uint32_t insn) /* MT_FPCR */ REQUIRE_FEN; va = load_fpr(ctx, ra); - gen_helper_store_fpcr(cpu_env, va); + gen_helper_store_fpcr(tcg_env, va); if (ctx->tb_rm == QUAL_RM_D) { /* Re-do the copy of the rounding mode to fp_status the next time we use dynamic rounding. */ @@ -2253,7 +2253,7 @@ static DisasJumpType translate_one(DisasContext *ctx, uint32_t insn) /* MF_FPCR */ REQUIRE_FEN; va = dest_fpr(ctx, ra); - gen_helper_load_fpcr(va, cpu_env); + gen_helper_load_fpcr(va, tcg_env); break; case 0x02A: /* FCMOVEQ */ @@ -2292,7 +2292,7 @@ static DisasJumpType translate_one(DisasContext *ctx, uint32_t insn) REQUIRE_FEN; vc = dest_fpr(ctx, rc); vb = load_fpr(ctx, rb); - gen_helper_cvtql(vc, cpu_env, vb); + gen_helper_cvtql(vc, tcg_env, vb); gen_fp_exc_raise(rc, fn11); break; default: @@ -2332,7 +2332,7 @@ static DisasJumpType translate_one(DisasContext *ctx, uint32_t insn) if (translator_io_start(&ctx->base)) { ret = DISAS_PC_STALE; } - gen_helper_load_pcc(va, cpu_env); + gen_helper_load_pcc(va, tcg_env); break; case 0xE000: /* RC */ @@ -2628,7 +2628,7 @@ static DisasJumpType translate_one(DisasContext *ctx, uint32_t insn) address from EXC_ADDR. This turns out to be useful for our emulation PALcode, so continue to accept it. */ vb = dest_sink(ctx); - tcg_gen_ld_i64(vb, cpu_env, offsetof(CPUAlphaState, exc_addr)); + tcg_gen_ld_i64(vb, tcg_env, offsetof(CPUAlphaState, exc_addr)); } else { vb = load_gpr(ctx, rb); } diff --git a/target/arm/tcg/translate-a32.h b/target/arm/tcg/translate-a32.h index 48a15379d2..19de6e0a1a 100644 --- a/target/arm/tcg/translate-a32.h +++ b/target/arm/tcg/translate-a32.h @@ -55,7 +55,7 @@ bool mve_skip_vmov(DisasContext *s, int vn, int index, int size); static inline TCGv_i32 load_cpu_offset(int offset) { TCGv_i32 tmp = tcg_temp_new_i32(); - tcg_gen_ld_i32(tmp, cpu_env, offset); + tcg_gen_ld_i32(tmp, tcg_env, offset); return tmp; } diff --git a/target/arm/tcg/translate-a64.c b/target/arm/tcg/translate-a64.c index 6523bfb339..66a010ecca 100644 --- a/target/arm/tcg/translate-a64.c +++ b/target/arm/tcg/translate-a64.c @@ -91,16 +91,16 @@ void a64_translate_init(void) { int i; - cpu_pc = tcg_global_mem_new_i64(cpu_env, + cpu_pc = tcg_global_mem_new_i64(tcg_env, offsetof(CPUARMState, pc), "pc"); for (i = 0; i < 32; i++) { - cpu_X[i] = tcg_global_mem_new_i64(cpu_env, + cpu_X[i] = tcg_global_mem_new_i64(tcg_env, offsetof(CPUARMState, xregs[i]), regnames[i]); } - cpu_exclusive_high = tcg_global_mem_new_i64(cpu_env, + cpu_exclusive_high = tcg_global_mem_new_i64(tcg_env, offsetof(CPUARMState, exclusive_high), "exclusive_high"); } @@ -147,7 +147,7 @@ static int get_a64_user_mem_index(DisasContext *s, bool unpriv) static void set_btype_raw(int val) { - tcg_gen_st_i32(tcg_constant_i32(val), cpu_env, + tcg_gen_st_i32(tcg_constant_i32(val), tcg_env, offsetof(CPUARMState, btype)); } @@ -269,7 +269,7 @@ static void gen_address_with_allocation_tag0(TCGv_i64 dst, TCGv_i64 src) static void gen_probe_access(DisasContext *s, TCGv_i64 ptr, MMUAccessType acc, int log2_size) { - gen_helper_probe_access(cpu_env, ptr, + gen_helper_probe_access(tcg_env, ptr, tcg_constant_i32(acc), tcg_constant_i32(get_mem_index(s)), tcg_constant_i32(1 << log2_size)); @@ -298,7 +298,7 @@ static TCGv_i64 gen_mte_check1_mmuidx(DisasContext *s, TCGv_i64 addr, desc = FIELD_DP32(desc, MTEDESC, SIZEM1, memop_size(memop) - 1); ret = tcg_temp_new_i64(); - gen_helper_mte_check(ret, cpu_env, tcg_constant_i32(desc), addr); + gen_helper_mte_check(ret, tcg_env, tcg_constant_i32(desc), addr); return ret; } @@ -330,7 +330,7 @@ TCGv_i64 gen_mte_checkN(DisasContext *s, TCGv_i64 addr, bool is_write, desc = FIELD_DP32(desc, MTEDESC, SIZEM1, total_size - 1); ret = tcg_temp_new_i64(); - gen_helper_mte_check(ret, cpu_env, tcg_constant_i32(desc), addr); + gen_helper_mte_check(ret, tcg_env, tcg_constant_i32(desc), addr); return ret; } @@ -366,7 +366,7 @@ static void check_lse2_align(DisasContext *s, int rn, int imm, type = is_write ? MMU_DATA_STORE : MMU_DATA_LOAD, mmu_idx = get_mem_index(s); - gen_helper_unaligned_access(cpu_env, addr, tcg_constant_i32(type), + gen_helper_unaligned_access(tcg_env, addr, tcg_constant_i32(type), tcg_constant_i32(mmu_idx)); gen_set_label(over_label); @@ -442,13 +442,13 @@ static void a64_test_cc(DisasCompare64 *c64, int cc) static void gen_rebuild_hflags(DisasContext *s) { - gen_helper_rebuild_hflags_a64(cpu_env, tcg_constant_i32(s->current_el)); + gen_helper_rebuild_hflags_a64(tcg_env, tcg_constant_i32(s->current_el)); } static void gen_exception_internal(int excp) { assert(excp_is_internal(excp)); - gen_helper_exception_internal(cpu_env, tcg_constant_i32(excp)); + gen_helper_exception_internal(tcg_env, tcg_constant_i32(excp)); } static void gen_exception_internal_insn(DisasContext *s, int excp) @@ -461,7 +461,7 @@ static void gen_exception_internal_insn(DisasContext *s, int excp) static void gen_exception_bkpt_insn(DisasContext *s, uint32_t syndrome) { gen_a64_update_pc(s, 0); - gen_helper_exception_bkpt_insn(cpu_env, tcg_constant_i32(syndrome)); + gen_helper_exception_bkpt_insn(tcg_env, tcg_constant_i32(syndrome)); s->base.is_jmp = DISAS_NORETURN; } @@ -608,7 +608,7 @@ static TCGv_i64 read_fp_dreg(DisasContext *s, int reg) { TCGv_i64 v = tcg_temp_new_i64(); - tcg_gen_ld_i64(v, cpu_env, fp_reg_offset(s, reg, MO_64)); + tcg_gen_ld_i64(v, tcg_env, fp_reg_offset(s, reg, MO_64)); return v; } @@ -616,7 +616,7 @@ static TCGv_i32 read_fp_sreg(DisasContext *s, int reg) { TCGv_i32 v = tcg_temp_new_i32(); - tcg_gen_ld_i32(v, cpu_env, fp_reg_offset(s, reg, MO_32)); + tcg_gen_ld_i32(v, tcg_env, fp_reg_offset(s, reg, MO_32)); return v; } @@ -624,7 +624,7 @@ static TCGv_i32 read_fp_hreg(DisasContext *s, int reg) { TCGv_i32 v = tcg_temp_new_i32(); - tcg_gen_ld16u_i32(v, cpu_env, fp_reg_offset(s, reg, MO_16)); + tcg_gen_ld16u_i32(v, tcg_env, fp_reg_offset(s, reg, MO_16)); return v; } @@ -644,7 +644,7 @@ void write_fp_dreg(DisasContext *s, int reg, TCGv_i64 v) { unsigned ofs = fp_reg_offset(s, reg, MO_64); - tcg_gen_st_i64(v, cpu_env, ofs); + tcg_gen_st_i64(v, tcg_env, ofs); clear_vec_high(s, false, reg); } @@ -730,7 +730,7 @@ static void gen_gvec_op3_qc(DisasContext *s, bool is_q, int rd, int rn, { TCGv_ptr qc_ptr = tcg_temp_new_ptr(); - tcg_gen_addi_ptr(qc_ptr, cpu_env, offsetof(CPUARMState, vfp.qc)); + tcg_gen_addi_ptr(qc_ptr, tcg_env, offsetof(CPUARMState, vfp.qc)); tcg_gen_gvec_3_ptr(vec_full_reg_offset(s, rd), vec_full_reg_offset(s, rn), vec_full_reg_offset(s, rm), qc_ptr, @@ -1025,7 +1025,7 @@ static void do_fp_st(DisasContext *s, int srcidx, TCGv_i64 tcg_addr, MemOp mop) /* This writes the bottom N bits of a 128 bit wide vector to memory */ TCGv_i64 tmplo = tcg_temp_new_i64(); - tcg_gen_ld_i64(tmplo, cpu_env, fp_reg_offset(s, srcidx, MO_64)); + tcg_gen_ld_i64(tmplo, tcg_env, fp_reg_offset(s, srcidx, MO_64)); if ((mop & MO_SIZE) < MO_128) { tcg_gen_qemu_st_i64(tmplo, tcg_addr, get_mem_index(s), mop); @@ -1033,7 +1033,7 @@ static void do_fp_st(DisasContext *s, int srcidx, TCGv_i64 tcg_addr, MemOp mop) TCGv_i64 tmphi = tcg_temp_new_i64(); TCGv_i128 t16 = tcg_temp_new_i128(); - tcg_gen_ld_i64(tmphi, cpu_env, fp_reg_hi_offset(s, srcidx)); + tcg_gen_ld_i64(tmphi, tcg_env, fp_reg_hi_offset(s, srcidx)); tcg_gen_concat_i64_i128(t16, tmplo, tmphi); tcg_gen_qemu_st_i128(t16, tcg_addr, get_mem_index(s), mop); @@ -1060,10 +1060,10 @@ static void do_fp_ld(DisasContext *s, int destidx, TCGv_i64 tcg_addr, MemOp mop) tcg_gen_extr_i128_i64(tmplo, tmphi, t16); } - tcg_gen_st_i64(tmplo, cpu_env, fp_reg_offset(s, destidx, MO_64)); + tcg_gen_st_i64(tmplo, tcg_env, fp_reg_offset(s, destidx, MO_64)); if (tmphi) { - tcg_gen_st_i64(tmphi, cpu_env, fp_reg_hi_offset(s, destidx)); + tcg_gen_st_i64(tmphi, tcg_env, fp_reg_hi_offset(s, destidx)); } clear_vec_high(s, tmphi != NULL, destidx); } @@ -1087,26 +1087,26 @@ static void read_vec_element(DisasContext *s, TCGv_i64 tcg_dest, int srcidx, int vect_off = vec_reg_offset(s, srcidx, element, memop & MO_SIZE); switch ((unsigned)memop) { case MO_8: - tcg_gen_ld8u_i64(tcg_dest, cpu_env, vect_off); + tcg_gen_ld8u_i64(tcg_dest, tcg_env, vect_off); break; case MO_16: - tcg_gen_ld16u_i64(tcg_dest, cpu_env, vect_off); + tcg_gen_ld16u_i64(tcg_dest, tcg_env, vect_off); break; case MO_32: - tcg_gen_ld32u_i64(tcg_dest, cpu_env, vect_off); + tcg_gen_ld32u_i64(tcg_dest, tcg_env, vect_off); break; case MO_8|MO_SIGN: - tcg_gen_ld8s_i64(tcg_dest, cpu_env, vect_off); + tcg_gen_ld8s_i64(tcg_dest, tcg_env, vect_off); break; case MO_16|MO_SIGN: - tcg_gen_ld16s_i64(tcg_dest, cpu_env, vect_off); + tcg_gen_ld16s_i64(tcg_dest, tcg_env, vect_off); break; case MO_32|MO_SIGN: - tcg_gen_ld32s_i64(tcg_dest, cpu_env, vect_off); + tcg_gen_ld32s_i64(tcg_dest, tcg_env, vect_off); break; case MO_64: case MO_64|MO_SIGN: - tcg_gen_ld_i64(tcg_dest, cpu_env, vect_off); + tcg_gen_ld_i64(tcg_dest, tcg_env, vect_off); break; default: g_assert_not_reached(); @@ -1119,20 +1119,20 @@ static void read_vec_element_i32(DisasContext *s, TCGv_i32 tcg_dest, int srcidx, int vect_off = vec_reg_offset(s, srcidx, element, memop & MO_SIZE); switch (memop) { case MO_8: - tcg_gen_ld8u_i32(tcg_dest, cpu_env, vect_off); + tcg_gen_ld8u_i32(tcg_dest, tcg_env, vect_off); break; case MO_16: - tcg_gen_ld16u_i32(tcg_dest, cpu_env, vect_off); + tcg_gen_ld16u_i32(tcg_dest, tcg_env, vect_off); break; case MO_8|MO_SIGN: - tcg_gen_ld8s_i32(tcg_dest, cpu_env, vect_off); + tcg_gen_ld8s_i32(tcg_dest, tcg_env, vect_off); break; case MO_16|MO_SIGN: - tcg_gen_ld16s_i32(tcg_dest, cpu_env, vect_off); + tcg_gen_ld16s_i32(tcg_dest, tcg_env, vect_off); break; case MO_32: case MO_32|MO_SIGN: - tcg_gen_ld_i32(tcg_dest, cpu_env, vect_off); + tcg_gen_ld_i32(tcg_dest, tcg_env, vect_off); break; default: g_assert_not_reached(); @@ -1146,16 +1146,16 @@ static void write_vec_element(DisasContext *s, TCGv_i64 tcg_src, int destidx, int vect_off = vec_reg_offset(s, destidx, element, memop & MO_SIZE); switch (memop) { case MO_8: - tcg_gen_st8_i64(tcg_src, cpu_env, vect_off); + tcg_gen_st8_i64(tcg_src, tcg_env, vect_off); break; case MO_16: - tcg_gen_st16_i64(tcg_src, cpu_env, vect_off); + tcg_gen_st16_i64(tcg_src, tcg_env, vect_off); break; case MO_32: - tcg_gen_st32_i64(tcg_src, cpu_env, vect_off); + tcg_gen_st32_i64(tcg_src, tcg_env, vect_off); break; case MO_64: - tcg_gen_st_i64(tcg_src, cpu_env, vect_off); + tcg_gen_st_i64(tcg_src, tcg_env, vect_off); break; default: g_assert_not_reached(); @@ -1168,13 +1168,13 @@ static void write_vec_element_i32(DisasContext *s, TCGv_i32 tcg_src, int vect_off = vec_reg_offset(s, destidx, element, memop & MO_SIZE); switch (memop) { case MO_8: - tcg_gen_st8_i32(tcg_src, cpu_env, vect_off); + tcg_gen_st8_i32(tcg_src, tcg_env, vect_off); break; case MO_16: - tcg_gen_st16_i32(tcg_src, cpu_env, vect_off); + tcg_gen_st16_i32(tcg_src, tcg_env, vect_off); break; case MO_32: - tcg_gen_st_i32(tcg_src, cpu_env, vect_off); + tcg_gen_st_i32(tcg_src, tcg_env, vect_off); break; default: g_assert_not_reached(); @@ -1542,9 +1542,9 @@ static TCGv_i64 auth_branch_target(DisasContext *s, TCGv_i64 dst, truedst = tcg_temp_new_i64(); if (use_key_a) { - gen_helper_autia_combined(truedst, cpu_env, dst, modifier); + gen_helper_autia_combined(truedst, tcg_env, dst, modifier); } else { - gen_helper_autib_combined(truedst, cpu_env, dst, modifier); + gen_helper_autib_combined(truedst, tcg_env, dst, modifier); } return truedst; } @@ -1643,12 +1643,12 @@ static bool trans_ERET(DisasContext *s, arg_ERET *a) return true; } dst = tcg_temp_new_i64(); - tcg_gen_ld_i64(dst, cpu_env, + tcg_gen_ld_i64(dst, tcg_env, offsetof(CPUARMState, elr_el[s->current_el])); translator_io_start(&s->base); - gen_helper_exception_return(cpu_env, dst); + gen_helper_exception_return(tcg_env, dst); /* Must exit loop to check un-masked IRQs */ s->base.is_jmp = DISAS_EXIT; return true; @@ -1670,14 +1670,14 @@ static bool trans_ERETA(DisasContext *s, arg_reta *a) return true; } dst = tcg_temp_new_i64(); - tcg_gen_ld_i64(dst, cpu_env, + tcg_gen_ld_i64(dst, tcg_env, offsetof(CPUARMState, elr_el[s->current_el])); dst = auth_branch_target(s, dst, cpu_X[31], !a->m); translator_io_start(&s->base); - gen_helper_exception_return(cpu_env, dst); + gen_helper_exception_return(tcg_env, dst); /* Must exit loop to check un-masked IRQs */ s->base.is_jmp = DISAS_EXIT; return true; @@ -1725,7 +1725,7 @@ static bool trans_WFE(DisasContext *s, arg_WFI *a) static bool trans_XPACLRI(DisasContext *s, arg_XPACLRI *a) { if (s->pauth_active) { - gen_helper_xpaci(cpu_X[30], cpu_env, cpu_X[30]); + gen_helper_xpaci(cpu_X[30], tcg_env, cpu_X[30]); } return true; } @@ -1733,7 +1733,7 @@ static bool trans_XPACLRI(DisasContext *s, arg_XPACLRI *a) static bool trans_PACIA1716(DisasContext *s, arg_PACIA1716 *a) { if (s->pauth_active) { - gen_helper_pacia(cpu_X[17], cpu_env, cpu_X[17], cpu_X[16]); + gen_helper_pacia(cpu_X[17], tcg_env, cpu_X[17], cpu_X[16]); } return true; } @@ -1741,7 +1741,7 @@ static bool trans_PACIA1716(DisasContext *s, arg_PACIA1716 *a) static bool trans_PACIB1716(DisasContext *s, arg_PACIB1716 *a) { if (s->pauth_active) { - gen_helper_pacib(cpu_X[17], cpu_env, cpu_X[17], cpu_X[16]); + gen_helper_pacib(cpu_X[17], tcg_env, cpu_X[17], cpu_X[16]); } return true; } @@ -1749,7 +1749,7 @@ static bool trans_PACIB1716(DisasContext *s, arg_PACIB1716 *a) static bool trans_AUTIA1716(DisasContext *s, arg_AUTIA1716 *a) { if (s->pauth_active) { - gen_helper_autia(cpu_X[17], cpu_env, cpu_X[17], cpu_X[16]); + gen_helper_autia(cpu_X[17], tcg_env, cpu_X[17], cpu_X[16]); } return true; } @@ -1757,7 +1757,7 @@ static bool trans_AUTIA1716(DisasContext *s, arg_AUTIA1716 *a) static bool trans_AUTIB1716(DisasContext *s, arg_AUTIB1716 *a) { if (s->pauth_active) { - gen_helper_autib(cpu_X[17], cpu_env, cpu_X[17], cpu_X[16]); + gen_helper_autib(cpu_X[17], tcg_env, cpu_X[17], cpu_X[16]); } return true; } @@ -1776,7 +1776,7 @@ static bool trans_ESB(DisasContext *s, arg_ESB *a) * Test for EL2 present, and defer test for SEL2 to runtime. */ if (s->current_el <= 1 && arm_dc_feature(s, ARM_FEATURE_EL2)) { - gen_helper_vesb(cpu_env); + gen_helper_vesb(tcg_env); } } return true; @@ -1785,7 +1785,7 @@ static bool trans_ESB(DisasContext *s, arg_ESB *a) static bool trans_PACIAZ(DisasContext *s, arg_PACIAZ *a) { if (s->pauth_active) { - gen_helper_pacia(cpu_X[30], cpu_env, cpu_X[30], tcg_constant_i64(0)); + gen_helper_pacia(cpu_X[30], tcg_env, cpu_X[30], tcg_constant_i64(0)); } return true; } @@ -1793,7 +1793,7 @@ static bool trans_PACIAZ(DisasContext *s, arg_PACIAZ *a) static bool trans_PACIASP(DisasContext *s, arg_PACIASP *a) { if (s->pauth_active) { - gen_helper_pacia(cpu_X[30], cpu_env, cpu_X[30], cpu_X[31]); + gen_helper_pacia(cpu_X[30], tcg_env, cpu_X[30], cpu_X[31]); } return true; } @@ -1801,7 +1801,7 @@ static bool trans_PACIASP(DisasContext *s, arg_PACIASP *a) static bool trans_PACIBZ(DisasContext *s, arg_PACIBZ *a) { if (s->pauth_active) { - gen_helper_pacib(cpu_X[30], cpu_env, cpu_X[30], tcg_constant_i64(0)); + gen_helper_pacib(cpu_X[30], tcg_env, cpu_X[30], tcg_constant_i64(0)); } return true; } @@ -1809,7 +1809,7 @@ static bool trans_PACIBZ(DisasContext *s, arg_PACIBZ *a) static bool trans_PACIBSP(DisasContext *s, arg_PACIBSP *a) { if (s->pauth_active) { - gen_helper_pacib(cpu_X[30], cpu_env, cpu_X[30], cpu_X[31]); + gen_helper_pacib(cpu_X[30], tcg_env, cpu_X[30], cpu_X[31]); } return true; } @@ -1817,7 +1817,7 @@ static bool trans_PACIBSP(DisasContext *s, arg_PACIBSP *a) static bool trans_AUTIAZ(DisasContext *s, arg_AUTIAZ *a) { if (s->pauth_active) { - gen_helper_autia(cpu_X[30], cpu_env, cpu_X[30], tcg_constant_i64(0)); + gen_helper_autia(cpu_X[30], tcg_env, cpu_X[30], tcg_constant_i64(0)); } return true; } @@ -1825,7 +1825,7 @@ static bool trans_AUTIAZ(DisasContext *s, arg_AUTIAZ *a) static bool trans_AUTIASP(DisasContext *s, arg_AUTIASP *a) { if (s->pauth_active) { - gen_helper_autia(cpu_X[30], cpu_env, cpu_X[30], cpu_X[31]); + gen_helper_autia(cpu_X[30], tcg_env, cpu_X[30], cpu_X[31]); } return true; } @@ -1833,7 +1833,7 @@ static bool trans_AUTIASP(DisasContext *s, arg_AUTIASP *a) static bool trans_AUTIBZ(DisasContext *s, arg_AUTIBZ *a) { if (s->pauth_active) { - gen_helper_autib(cpu_X[30], cpu_env, cpu_X[30], tcg_constant_i64(0)); + gen_helper_autib(cpu_X[30], tcg_env, cpu_X[30], tcg_constant_i64(0)); } return true; } @@ -1841,7 +1841,7 @@ static bool trans_AUTIBZ(DisasContext *s, arg_AUTIBZ *a) static bool trans_AUTIBSP(DisasContext *s, arg_AUTIBSP *a) { if (s->pauth_active) { - gen_helper_autib(cpu_X[30], cpu_env, cpu_X[30], cpu_X[31]); + gen_helper_autib(cpu_X[30], tcg_env, cpu_X[30], cpu_X[31]); } return true; } @@ -1996,7 +1996,7 @@ static bool trans_MSR_i_SPSEL(DisasContext *s, arg_i *a) if (s->current_el == 0) { return false; } - gen_helper_msr_i_spsel(cpu_env, tcg_constant_i32(a->imm & PSTATE_SP)); + gen_helper_msr_i_spsel(tcg_env, tcg_constant_i32(a->imm & PSTATE_SP)); s->base.is_jmp = DISAS_TOO_MANY; return true; } @@ -2055,14 +2055,14 @@ static bool trans_MSR_i_TCO(DisasContext *s, arg_i *a) static bool trans_MSR_i_DAIFSET(DisasContext *s, arg_i *a) { - gen_helper_msr_i_daifset(cpu_env, tcg_constant_i32(a->imm)); + gen_helper_msr_i_daifset(tcg_env, tcg_constant_i32(a->imm)); s->base.is_jmp = DISAS_TOO_MANY; return true; } static bool trans_MSR_i_DAIFCLEAR(DisasContext *s, arg_i *a) { - gen_helper_msr_i_daifclear(cpu_env, tcg_constant_i32(a->imm)); + gen_helper_msr_i_daifclear(tcg_env, tcg_constant_i32(a->imm)); /* Exit the cpu loop to re-evaluate pending IRQs. */ s->base.is_jmp = DISAS_UPDATE_EXIT; return true; @@ -2079,7 +2079,7 @@ static bool trans_MSR_i_SVCR(DisasContext *s, arg_MSR_i_SVCR *a) if ((old ^ new) & a->mask) { /* At least one bit changes. */ - gen_helper_set_svcr(cpu_env, tcg_constant_i32(new), + gen_helper_set_svcr(tcg_env, tcg_constant_i32(new), tcg_constant_i32(a->mask)); s->base.is_jmp = DISAS_TOO_MANY; } @@ -2177,11 +2177,11 @@ static void handle_sys(DisasContext *s, bool isread, switch (s->current_el) { case 0: if (dc_isar_feature(aa64_tidcp1, s)) { - gen_helper_tidcp_el0(cpu_env, tcg_constant_i32(syndrome)); + gen_helper_tidcp_el0(tcg_env, tcg_constant_i32(syndrome)); } break; case 1: - gen_helper_tidcp_el1(cpu_env, tcg_constant_i32(syndrome)); + gen_helper_tidcp_el1(tcg_env, tcg_constant_i32(syndrome)); break; } } @@ -2210,7 +2210,7 @@ static void handle_sys(DisasContext *s, bool isread, syndrome = syn_aa64_sysregtrap(op0, op1, op2, crn, crm, rt, isread); gen_a64_update_pc(s, 0); tcg_ri = tcg_temp_new_ptr(); - gen_helper_access_check_cp_reg(tcg_ri, cpu_env, + gen_helper_access_check_cp_reg(tcg_ri, tcg_env, tcg_constant_i32(key), tcg_constant_i32(syndrome), tcg_constant_i32(isread)); @@ -2253,12 +2253,12 @@ static void handle_sys(DisasContext *s, bool isread, desc = FIELD_DP32(desc, MTEDESC, TCMA, s->tcma); tcg_rt = tcg_temp_new_i64(); - gen_helper_mte_check_zva(tcg_rt, cpu_env, + gen_helper_mte_check_zva(tcg_rt, tcg_env, tcg_constant_i32(desc), cpu_reg(s, rt)); } else { tcg_rt = clean_data_tbi(s, cpu_reg(s, rt)); } - gen_helper_dc_zva(cpu_env, tcg_rt); + gen_helper_dc_zva(tcg_env, tcg_rt); return; case ARM_CP_DC_GVA: { @@ -2276,7 +2276,7 @@ static void handle_sys(DisasContext *s, bool isread, /* Extract the tag from the register to match STZGM. */ tag = tcg_temp_new_i64(); tcg_gen_shri_i64(tag, tcg_rt, 56); - gen_helper_stzgm_tags(cpu_env, clean_addr, tag); + gen_helper_stzgm_tags(tcg_env, clean_addr, tag); } } return; @@ -2287,13 +2287,13 @@ static void handle_sys(DisasContext *s, bool isread, /* For DC_GZVA, we can rely on DC_ZVA for the proper fault. */ tcg_rt = cpu_reg(s, rt); clean_addr = clean_data_tbi(s, tcg_rt); - gen_helper_dc_zva(cpu_env, clean_addr); + gen_helper_dc_zva(tcg_env, clean_addr); if (s->ata[0]) { /* Extract the tag from the register to match STZGM. */ tag = tcg_temp_new_i64(); tcg_gen_shri_i64(tag, tcg_rt, 56); - gen_helper_stzgm_tags(cpu_env, clean_addr, tag); + gen_helper_stzgm_tags(tcg_env, clean_addr, tag); } } return; @@ -2322,9 +2322,9 @@ static void handle_sys(DisasContext *s, bool isread, if (!tcg_ri) { tcg_ri = gen_lookup_cp_reg(key); } - gen_helper_get_cp_reg64(tcg_rt, cpu_env, tcg_ri); + gen_helper_get_cp_reg64(tcg_rt, tcg_env, tcg_ri); } else { - tcg_gen_ld_i64(tcg_rt, cpu_env, ri->fieldoffset); + tcg_gen_ld_i64(tcg_rt, tcg_env, ri->fieldoffset); } } else { if (ri->type & ARM_CP_CONST) { @@ -2334,9 +2334,9 @@ static void handle_sys(DisasContext *s, bool isread, if (!tcg_ri) { tcg_ri = gen_lookup_cp_reg(key); } - gen_helper_set_cp_reg64(cpu_env, tcg_ri, tcg_rt); + gen_helper_set_cp_reg64(tcg_env, tcg_ri, tcg_rt); } else { - tcg_gen_st_i64(tcg_rt, cpu_env, ri->fieldoffset); + tcg_gen_st_i64(tcg_rt, tcg_env, ri->fieldoffset); } } @@ -2393,7 +2393,7 @@ static bool trans_HVC(DisasContext *s, arg_i *a) * as an undefined insn by runtime configuration. */ gen_a64_update_pc(s, 0); - gen_helper_pre_hvc(cpu_env); + gen_helper_pre_hvc(tcg_env); /* Architecture requires ss advance before we do the actual work */ gen_ss_advance(s); gen_exception_insn_el(s, 4, EXCP_HVC, syn_aa64_hvc(a->imm), 2); @@ -2407,7 +2407,7 @@ static bool trans_SMC(DisasContext *s, arg_i *a) return true; } gen_a64_update_pc(s, 0); - gen_helper_pre_smc(cpu_env, tcg_constant_i32(syn_aa64_smc(a->imm))); + gen_helper_pre_smc(tcg_env, tcg_constant_i32(syn_aa64_smc(a->imm))); /* Architecture requires ss advance before we do the actual work */ gen_ss_advance(s); gen_exception_insn_el(s, 4, EXCP_SMC, syn_aa64_smc(a->imm), 3); @@ -3072,9 +3072,9 @@ static bool trans_STGP(DisasContext *s, arg_ldstpair *a) /* Perform the tag store, if tag access enabled. */ if (s->ata[0]) { if (tb_cflags(s->base.tb) & CF_PARALLEL) { - gen_helper_stg_parallel(cpu_env, dirty_addr, dirty_addr); + gen_helper_stg_parallel(tcg_env, dirty_addr, dirty_addr); } else { - gen_helper_stg(cpu_env, dirty_addr, dirty_addr); + gen_helper_stg(tcg_env, dirty_addr, dirty_addr); } } @@ -3370,10 +3370,10 @@ static bool trans_LDRA(DisasContext *s, arg_LDRA *a) if (s->pauth_active) { if (!a->m) { - gen_helper_autda_combined(dirty_addr, cpu_env, dirty_addr, + gen_helper_autda_combined(dirty_addr, tcg_env, dirty_addr, tcg_constant_i64(0)); } else { - gen_helper_autdb_combined(dirty_addr, cpu_env, dirty_addr, + gen_helper_autdb_combined(dirty_addr, tcg_env, dirty_addr, tcg_constant_i64(0)); } } @@ -3769,7 +3769,7 @@ static bool trans_STZGM(DisasContext *s, arg_ldst_tag *a) tcg_rt = cpu_reg(s, a->rt); if (s->ata[0]) { - gen_helper_stzgm_tags(cpu_env, addr, tcg_rt); + gen_helper_stzgm_tags(tcg_env, addr, tcg_rt); } /* * The non-tags portion of STZGM is mostly like DC_ZVA, @@ -3777,7 +3777,7 @@ static bool trans_STZGM(DisasContext *s, arg_ldst_tag *a) */ clean_addr = clean_data_tbi(s, addr); tcg_gen_andi_i64(clean_addr, clean_addr, -size); - gen_helper_dc_zva(cpu_env, clean_addr); + gen_helper_dc_zva(tcg_env, clean_addr); return true; } @@ -3801,7 +3801,7 @@ static bool trans_STGM(DisasContext *s, arg_ldst_tag *a) tcg_rt = cpu_reg(s, a->rt); if (s->ata[0]) { - gen_helper_stgm(cpu_env, addr, tcg_rt); + gen_helper_stgm(tcg_env, addr, tcg_rt); } else { MMUAccessType acc = MMU_DATA_STORE; int size = 4 << s->gm_blocksize; @@ -3833,7 +3833,7 @@ static bool trans_LDGM(DisasContext *s, arg_ldst_tag *a) tcg_rt = cpu_reg(s, a->rt); if (s->ata[0]) { - gen_helper_ldgm(tcg_rt, cpu_env, addr); + gen_helper_ldgm(tcg_rt, tcg_env, addr); } else { MMUAccessType acc = MMU_DATA_LOAD; int size = 4 << s->gm_blocksize; @@ -3868,7 +3868,7 @@ static bool trans_LDG(DisasContext *s, arg_ldst_tag *a) tcg_gen_andi_i64(addr, addr, -TAG_GRANULE); tcg_rt = cpu_reg(s, a->rt); if (s->ata[0]) { - gen_helper_ldg(tcg_rt, cpu_env, addr, tcg_rt); + gen_helper_ldg(tcg_rt, tcg_env, addr, tcg_rt); } else { /* * Tag access disabled: we must check for aborts on the load @@ -3911,21 +3911,21 @@ static bool do_STG(DisasContext *s, arg_ldst_tag *a, bool is_zero, bool is_pair) * at least for system mode; user-only won't enforce alignment. */ if (is_pair) { - gen_helper_st2g_stub(cpu_env, addr); + gen_helper_st2g_stub(tcg_env, addr); } else { - gen_helper_stg_stub(cpu_env, addr); + gen_helper_stg_stub(tcg_env, addr); } } else if (tb_cflags(s->base.tb) & CF_PARALLEL) { if (is_pair) { - gen_helper_st2g_parallel(cpu_env, addr, tcg_rt); + gen_helper_st2g_parallel(tcg_env, addr, tcg_rt); } else { - gen_helper_stg_parallel(cpu_env, addr, tcg_rt); + gen_helper_stg_parallel(tcg_env, addr, tcg_rt); } } else { if (is_pair) { - gen_helper_st2g(cpu_env, addr, tcg_rt); + gen_helper_st2g(tcg_env, addr, tcg_rt); } else { - gen_helper_stg(cpu_env, addr, tcg_rt); + gen_helper_stg(tcg_env, addr, tcg_rt); } } @@ -4008,7 +4008,7 @@ static bool do_SET(DisasContext *s, arg_set *a, bool is_epilogue, * the syndrome anyway, we let it extract them from there rather * than passing in an extra three integer arguments. */ - fn(cpu_env, tcg_constant_i32(syndrome), tcg_constant_i32(desc)); + fn(tcg_env, tcg_constant_i32(syndrome), tcg_constant_i32(desc)); return true; } @@ -4067,7 +4067,7 @@ static bool do_CPY(DisasContext *s, arg_cpy *a, bool is_epilogue, CpyFn fn) * the syndrome anyway, we let it extract them from there rather * than passing in an extra three integer arguments. */ - fn(cpu_env, tcg_constant_i32(syndrome), tcg_constant_i32(wdesc), + fn(tcg_env, tcg_constant_i32(syndrome), tcg_constant_i32(wdesc), tcg_constant_i32(rdesc)); return true; } @@ -4142,7 +4142,7 @@ static bool gen_add_sub_imm_with_tags(DisasContext *s, arg_rri_tag *a, tcg_rd = cpu_reg_sp(s, a->rd); if (s->ata[0]) { - gen_helper_addsubg(tcg_rd, cpu_env, tcg_rn, + gen_helper_addsubg(tcg_rd, tcg_env, tcg_rn, tcg_constant_i32(imm), tcg_constant_i32(a->uimm4)); } else { @@ -5241,7 +5241,7 @@ static void disas_data_proc_1src(DisasContext *s, uint32_t insn) case MAP(1, 0x01, 0x00): /* PACIA */ if (s->pauth_active) { tcg_rd = cpu_reg(s, rd); - gen_helper_pacia(tcg_rd, cpu_env, tcg_rd, cpu_reg_sp(s, rn)); + gen_helper_pacia(tcg_rd, tcg_env, tcg_rd, cpu_reg_sp(s, rn)); } else if (!dc_isar_feature(aa64_pauth, s)) { goto do_unallocated; } @@ -5249,7 +5249,7 @@ static void disas_data_proc_1src(DisasContext *s, uint32_t insn) case MAP(1, 0x01, 0x01): /* PACIB */ if (s->pauth_active) { tcg_rd = cpu_reg(s, rd); - gen_helper_pacib(tcg_rd, cpu_env, tcg_rd, cpu_reg_sp(s, rn)); + gen_helper_pacib(tcg_rd, tcg_env, tcg_rd, cpu_reg_sp(s, rn)); } else if (!dc_isar_feature(aa64_pauth, s)) { goto do_unallocated; } @@ -5257,7 +5257,7 @@ static void disas_data_proc_1src(DisasContext *s, uint32_t insn) case MAP(1, 0x01, 0x02): /* PACDA */ if (s->pauth_active) { tcg_rd = cpu_reg(s, rd); - gen_helper_pacda(tcg_rd, cpu_env, tcg_rd, cpu_reg_sp(s, rn)); + gen_helper_pacda(tcg_rd, tcg_env, tcg_rd, cpu_reg_sp(s, rn)); } else if (!dc_isar_feature(aa64_pauth, s)) { goto do_unallocated; } @@ -5265,7 +5265,7 @@ static void disas_data_proc_1src(DisasContext *s, uint32_t insn) case MAP(1, 0x01, 0x03): /* PACDB */ if (s->pauth_active) { tcg_rd = cpu_reg(s, rd); - gen_helper_pacdb(tcg_rd, cpu_env, tcg_rd, cpu_reg_sp(s, rn)); + gen_helper_pacdb(tcg_rd, tcg_env, tcg_rd, cpu_reg_sp(s, rn)); } else if (!dc_isar_feature(aa64_pauth, s)) { goto do_unallocated; } @@ -5273,7 +5273,7 @@ static void disas_data_proc_1src(DisasContext *s, uint32_t insn) case MAP(1, 0x01, 0x04): /* AUTIA */ if (s->pauth_active) { tcg_rd = cpu_reg(s, rd); - gen_helper_autia(tcg_rd, cpu_env, tcg_rd, cpu_reg_sp(s, rn)); + gen_helper_autia(tcg_rd, tcg_env, tcg_rd, cpu_reg_sp(s, rn)); } else if (!dc_isar_feature(aa64_pauth, s)) { goto do_unallocated; } @@ -5281,7 +5281,7 @@ static void disas_data_proc_1src(DisasContext *s, uint32_t insn) case MAP(1, 0x01, 0x05): /* AUTIB */ if (s->pauth_active) { tcg_rd = cpu_reg(s, rd); - gen_helper_autib(tcg_rd, cpu_env, tcg_rd, cpu_reg_sp(s, rn)); + gen_helper_autib(tcg_rd, tcg_env, tcg_rd, cpu_reg_sp(s, rn)); } else if (!dc_isar_feature(aa64_pauth, s)) { goto do_unallocated; } @@ -5289,7 +5289,7 @@ static void disas_data_proc_1src(DisasContext *s, uint32_t insn) case MAP(1, 0x01, 0x06): /* AUTDA */ if (s->pauth_active) { tcg_rd = cpu_reg(s, rd); - gen_helper_autda(tcg_rd, cpu_env, tcg_rd, cpu_reg_sp(s, rn)); + gen_helper_autda(tcg_rd, tcg_env, tcg_rd, cpu_reg_sp(s, rn)); } else if (!dc_isar_feature(aa64_pauth, s)) { goto do_unallocated; } @@ -5297,7 +5297,7 @@ static void disas_data_proc_1src(DisasContext *s, uint32_t insn) case MAP(1, 0x01, 0x07): /* AUTDB */ if (s->pauth_active) { tcg_rd = cpu_reg(s, rd); - gen_helper_autdb(tcg_rd, cpu_env, tcg_rd, cpu_reg_sp(s, rn)); + gen_helper_autdb(tcg_rd, tcg_env, tcg_rd, cpu_reg_sp(s, rn)); } else if (!dc_isar_feature(aa64_pauth, s)) { goto do_unallocated; } @@ -5307,7 +5307,7 @@ static void disas_data_proc_1src(DisasContext *s, uint32_t insn) goto do_unallocated; } else if (s->pauth_active) { tcg_rd = cpu_reg(s, rd); - gen_helper_pacia(tcg_rd, cpu_env, tcg_rd, tcg_constant_i64(0)); + gen_helper_pacia(tcg_rd, tcg_env, tcg_rd, tcg_constant_i64(0)); } break; case MAP(1, 0x01, 0x09): /* PACIZB */ @@ -5315,7 +5315,7 @@ static void disas_data_proc_1src(DisasContext *s, uint32_t insn) goto do_unallocated; } else if (s->pauth_active) { tcg_rd = cpu_reg(s, rd); - gen_helper_pacib(tcg_rd, cpu_env, tcg_rd, tcg_constant_i64(0)); + gen_helper_pacib(tcg_rd, tcg_env, tcg_rd, tcg_constant_i64(0)); } break; case MAP(1, 0x01, 0x0a): /* PACDZA */ @@ -5323,7 +5323,7 @@ static void disas_data_proc_1src(DisasContext *s, uint32_t insn) goto do_unallocated; } else if (s->pauth_active) { tcg_rd = cpu_reg(s, rd); - gen_helper_pacda(tcg_rd, cpu_env, tcg_rd, tcg_constant_i64(0)); + gen_helper_pacda(tcg_rd, tcg_env, tcg_rd, tcg_constant_i64(0)); } break; case MAP(1, 0x01, 0x0b): /* PACDZB */ @@ -5331,7 +5331,7 @@ static void disas_data_proc_1src(DisasContext *s, uint32_t insn) goto do_unallocated; } else if (s->pauth_active) { tcg_rd = cpu_reg(s, rd); - gen_helper_pacdb(tcg_rd, cpu_env, tcg_rd, tcg_constant_i64(0)); + gen_helper_pacdb(tcg_rd, tcg_env, tcg_rd, tcg_constant_i64(0)); } break; case MAP(1, 0x01, 0x0c): /* AUTIZA */ @@ -5339,7 +5339,7 @@ static void disas_data_proc_1src(DisasContext *s, uint32_t insn) goto do_unallocated; } else if (s->pauth_active) { tcg_rd = cpu_reg(s, rd); - gen_helper_autia(tcg_rd, cpu_env, tcg_rd, tcg_constant_i64(0)); + gen_helper_autia(tcg_rd, tcg_env, tcg_rd, tcg_constant_i64(0)); } break; case MAP(1, 0x01, 0x0d): /* AUTIZB */ @@ -5347,7 +5347,7 @@ static void disas_data_proc_1src(DisasContext *s, uint32_t insn) goto do_unallocated; } else if (s->pauth_active) { tcg_rd = cpu_reg(s, rd); - gen_helper_autib(tcg_rd, cpu_env, tcg_rd, tcg_constant_i64(0)); + gen_helper_autib(tcg_rd, tcg_env, tcg_rd, tcg_constant_i64(0)); } break; case MAP(1, 0x01, 0x0e): /* AUTDZA */ @@ -5355,7 +5355,7 @@ static void disas_data_proc_1src(DisasContext *s, uint32_t insn) goto do_unallocated; } else if (s->pauth_active) { tcg_rd = cpu_reg(s, rd); - gen_helper_autda(tcg_rd, cpu_env, tcg_rd, tcg_constant_i64(0)); + gen_helper_autda(tcg_rd, tcg_env, tcg_rd, tcg_constant_i64(0)); } break; case MAP(1, 0x01, 0x0f): /* AUTDZB */ @@ -5363,7 +5363,7 @@ static void disas_data_proc_1src(DisasContext *s, uint32_t insn) goto do_unallocated; } else if (s->pauth_active) { tcg_rd = cpu_reg(s, rd); - gen_helper_autdb(tcg_rd, cpu_env, tcg_rd, tcg_constant_i64(0)); + gen_helper_autdb(tcg_rd, tcg_env, tcg_rd, tcg_constant_i64(0)); } break; case MAP(1, 0x01, 0x10): /* XPACI */ @@ -5371,7 +5371,7 @@ static void disas_data_proc_1src(DisasContext *s, uint32_t insn) goto do_unallocated; } else if (s->pauth_active) { tcg_rd = cpu_reg(s, rd); - gen_helper_xpaci(tcg_rd, cpu_env, tcg_rd); + gen_helper_xpaci(tcg_rd, tcg_env, tcg_rd); } break; case MAP(1, 0x01, 0x11): /* XPACD */ @@ -5379,7 +5379,7 @@ static void disas_data_proc_1src(DisasContext *s, uint32_t insn) goto do_unallocated; } else if (s->pauth_active) { tcg_rd = cpu_reg(s, rd); - gen_helper_xpacd(tcg_rd, cpu_env, tcg_rd); + gen_helper_xpacd(tcg_rd, tcg_env, tcg_rd); } break; default: @@ -5529,7 +5529,7 @@ static void disas_data_proc_2src(DisasContext *s, uint32_t insn) goto do_unallocated; } if (s->ata[0]) { - gen_helper_irg(cpu_reg_sp(s, rd), cpu_env, + gen_helper_irg(cpu_reg_sp(s, rd), tcg_env, cpu_reg_sp(s, rn), cpu_reg(s, rm)); } else { gen_address_with_allocation_tag0(cpu_reg_sp(s, rd), @@ -5563,7 +5563,7 @@ static void disas_data_proc_2src(DisasContext *s, uint32_t insn) if (sf == 0 || !dc_isar_feature(aa64_pauth, s)) { goto do_unallocated; } - gen_helper_pacga(cpu_reg(s, rd), cpu_env, + gen_helper_pacga(cpu_reg(s, rd), tcg_env, cpu_reg(s, rn), cpu_reg_sp(s, rm)); break; case 16: @@ -5969,7 +5969,7 @@ static void handle_fp_1src_single(DisasContext *s, int opcode, int rd, int rn) gen_helper_vfp_negs(tcg_res, tcg_op); goto done; case 0x3: /* FSQRT */ - gen_helper_vfp_sqrts(tcg_res, tcg_op, cpu_env); + gen_helper_vfp_sqrts(tcg_res, tcg_op, tcg_env); goto done; case 0x6: /* BFCVT */ gen_fpst = gen_helper_bfcvt; @@ -6044,7 +6044,7 @@ static void handle_fp_1src_double(DisasContext *s, int opcode, int rd, int rn) gen_helper_vfp_negd(tcg_res, tcg_op); goto done; case 0x3: /* FSQRT */ - gen_helper_vfp_sqrtd(tcg_res, tcg_op, cpu_env); + gen_helper_vfp_sqrtd(tcg_res, tcg_op, tcg_env); goto done; case 0x8: /* FRINTN */ case 0x9: /* FRINTP */ @@ -6101,7 +6101,7 @@ static void handle_fp_fcvt(DisasContext *s, int opcode, if (dtype == 1) { /* Single to double */ TCGv_i64 tcg_rd = tcg_temp_new_i64(); - gen_helper_vfp_fcvtds(tcg_rd, tcg_rn, cpu_env); + gen_helper_vfp_fcvtds(tcg_rd, tcg_rn, tcg_env); write_fp_dreg(s, rd, tcg_rd); } else { /* Single to half */ @@ -6121,7 +6121,7 @@ static void handle_fp_fcvt(DisasContext *s, int opcode, TCGv_i32 tcg_rd = tcg_temp_new_i32(); if (dtype == 0) { /* Double to single */ - gen_helper_vfp_fcvtsd(tcg_rd, tcg_rn, cpu_env); + gen_helper_vfp_fcvtsd(tcg_rd, tcg_rn, tcg_env); } else { TCGv_ptr fpst = fpstatus_ptr(FPST_FPCR); TCGv_i32 ahp = get_ahp_flag(); @@ -6881,7 +6881,7 @@ static void handle_fmov(DisasContext *s, int rd, int rn, int type, bool itof) break; case 2: /* 64 bit to top half. */ - tcg_gen_st_i64(tcg_rn, cpu_env, fp_reg_hi_offset(s, rd)); + tcg_gen_st_i64(tcg_rn, tcg_env, fp_reg_hi_offset(s, rd)); clear_vec_high(s, true, rd); break; case 3: @@ -6899,19 +6899,19 @@ static void handle_fmov(DisasContext *s, int rd, int rn, int type, bool itof) switch (type) { case 0: /* 32 bit */ - tcg_gen_ld32u_i64(tcg_rd, cpu_env, fp_reg_offset(s, rn, MO_32)); + tcg_gen_ld32u_i64(tcg_rd, tcg_env, fp_reg_offset(s, rn, MO_32)); break; case 1: /* 64 bit */ - tcg_gen_ld_i64(tcg_rd, cpu_env, fp_reg_offset(s, rn, MO_64)); + tcg_gen_ld_i64(tcg_rd, tcg_env, fp_reg_offset(s, rn, MO_64)); break; case 2: /* 64 bits from top half */ - tcg_gen_ld_i64(tcg_rd, cpu_env, fp_reg_hi_offset(s, rn)); + tcg_gen_ld_i64(tcg_rd, tcg_env, fp_reg_hi_offset(s, rn)); break; case 3: /* 16 bit */ - tcg_gen_ld16u_i64(tcg_rd, cpu_env, fp_reg_offset(s, rn, MO_16)); + tcg_gen_ld16u_i64(tcg_rd, tcg_env, fp_reg_offset(s, rn, MO_16)); break; default: g_assert_not_reached(); @@ -7195,7 +7195,7 @@ static void disas_simd_tb(DisasContext *s, uint32_t insn) } tcg_gen_gvec_2_ptr(vec_full_reg_offset(s, rd), - vec_full_reg_offset(s, rm), cpu_env, + vec_full_reg_offset(s, rm), tcg_env, is_q ? 16 : 8, vec_full_reg_size(s), (len << 6) | (is_tbx << 5) | rn, gen_helper_simd_tblx); @@ -8249,7 +8249,7 @@ static void handle_vec_simd_sqshrn(DisasContext *s, bool is_scalar, bool is_q, read_vec_element(s, tcg_rn, rn, i, ldop); handle_shri_with_rndacc(tcg_rd, tcg_rn, tcg_round, false, is_u_shift, size+1, shift); - narrowfn(tcg_rd_narrowed, cpu_env, tcg_rd); + narrowfn(tcg_rd_narrowed, tcg_env, tcg_rd); tcg_gen_extu_i32_i64(tcg_rd, tcg_rd_narrowed); if (i == 0) { tcg_gen_mov_i64(tcg_final, tcg_rd); @@ -8321,7 +8321,7 @@ static void handle_simd_qshl(DisasContext *s, bool scalar, bool is_q, TCGv_i64 tcg_op = tcg_temp_new_i64(); read_vec_element(s, tcg_op, rn, pass, MO_64); - genfn(tcg_op, cpu_env, tcg_op, tcg_shift); + genfn(tcg_op, tcg_env, tcg_op, tcg_shift); write_vec_element(s, tcg_op, rd, pass, MO_64); } clear_vec_high(s, is_q, rd); @@ -8350,7 +8350,7 @@ static void handle_simd_qshl(DisasContext *s, bool scalar, bool is_q, TCGv_i32 tcg_op = tcg_temp_new_i32(); read_vec_element_i32(s, tcg_op, rn, pass, memop); - genfn(tcg_op, cpu_env, tcg_op, tcg_shift); + genfn(tcg_op, tcg_env, tcg_op, tcg_shift); if (scalar) { switch (size) { case 0: @@ -8733,7 +8733,7 @@ static void disas_simd_scalar_three_reg_diff(DisasContext *s, uint32_t insn) read_vec_element(s, tcg_op2, rm, 0, MO_32 | MO_SIGN); tcg_gen_mul_i64(tcg_res, tcg_op1, tcg_op2); - gen_helper_neon_addl_saturate_s64(tcg_res, cpu_env, tcg_res, tcg_res); + gen_helper_neon_addl_saturate_s64(tcg_res, tcg_env, tcg_res, tcg_res); switch (opcode) { case 0xd: /* SQDMULL, SQDMULL2 */ @@ -8743,7 +8743,7 @@ static void disas_simd_scalar_three_reg_diff(DisasContext *s, uint32_t insn) /* fall through */ case 0x9: /* SQDMLAL, SQDMLAL2 */ read_vec_element(s, tcg_op1, rd, 0, MO_64); - gen_helper_neon_addl_saturate_s64(tcg_res, cpu_env, + gen_helper_neon_addl_saturate_s64(tcg_res, tcg_env, tcg_res, tcg_op1); break; default: @@ -8757,7 +8757,7 @@ static void disas_simd_scalar_three_reg_diff(DisasContext *s, uint32_t insn) TCGv_i64 tcg_res = tcg_temp_new_i64(); gen_helper_neon_mull_s16(tcg_res, tcg_op1, tcg_op2); - gen_helper_neon_addl_saturate_s32(tcg_res, cpu_env, tcg_res, tcg_res); + gen_helper_neon_addl_saturate_s32(tcg_res, tcg_env, tcg_res, tcg_res); switch (opcode) { case 0xd: /* SQDMULL, SQDMULL2 */ @@ -8769,7 +8769,7 @@ static void disas_simd_scalar_three_reg_diff(DisasContext *s, uint32_t insn) { TCGv_i64 tcg_op3 = tcg_temp_new_i64(); read_vec_element(s, tcg_op3, rd, 0, MO_32); - gen_helper_neon_addl_saturate_s32(tcg_res, cpu_env, + gen_helper_neon_addl_saturate_s32(tcg_res, tcg_env, tcg_res, tcg_op3); break; } @@ -8795,16 +8795,16 @@ static void handle_3same_64(DisasContext *s, int opcode, bool u, switch (opcode) { case 0x1: /* SQADD */ if (u) { - gen_helper_neon_qadd_u64(tcg_rd, cpu_env, tcg_rn, tcg_rm); + gen_helper_neon_qadd_u64(tcg_rd, tcg_env, tcg_rn, tcg_rm); } else { - gen_helper_neon_qadd_s64(tcg_rd, cpu_env, tcg_rn, tcg_rm); + gen_helper_neon_qadd_s64(tcg_rd, tcg_env, tcg_rn, tcg_rm); } break; case 0x5: /* SQSUB */ if (u) { - gen_helper_neon_qsub_u64(tcg_rd, cpu_env, tcg_rn, tcg_rm); + gen_helper_neon_qsub_u64(tcg_rd, tcg_env, tcg_rn, tcg_rm); } else { - gen_helper_neon_qsub_s64(tcg_rd, cpu_env, tcg_rn, tcg_rm); + gen_helper_neon_qsub_s64(tcg_rd, tcg_env, tcg_rn, tcg_rm); } break; case 0x6: /* CMGT, CMHI */ @@ -8832,9 +8832,9 @@ static void handle_3same_64(DisasContext *s, int opcode, bool u, break; case 0x9: /* SQSHL, UQSHL */ if (u) { - gen_helper_neon_qshl_u64(tcg_rd, cpu_env, tcg_rn, tcg_rm); + gen_helper_neon_qshl_u64(tcg_rd, tcg_env, tcg_rn, tcg_rm); } else { - gen_helper_neon_qshl_s64(tcg_rd, cpu_env, tcg_rn, tcg_rm); + gen_helper_neon_qshl_s64(tcg_rd, tcg_env, tcg_rn, tcg_rm); } break; case 0xa: /* SRSHL, URSHL */ @@ -8846,9 +8846,9 @@ static void handle_3same_64(DisasContext *s, int opcode, bool u, break; case 0xb: /* SQRSHL, UQRSHL */ if (u) { - gen_helper_neon_qrshl_u64(tcg_rd, cpu_env, tcg_rn, tcg_rm); + gen_helper_neon_qrshl_u64(tcg_rd, tcg_env, tcg_rn, tcg_rm); } else { - gen_helper_neon_qrshl_s64(tcg_rd, cpu_env, tcg_rn, tcg_rm); + gen_helper_neon_qrshl_s64(tcg_rd, tcg_env, tcg_rn, tcg_rm); } break; case 0x10: /* ADD, SUB */ @@ -9192,7 +9192,7 @@ static void disas_simd_scalar_three_reg_same(DisasContext *s, uint32_t insn) g_assert_not_reached(); } - genenvfn(tcg_rd32, cpu_env, tcg_rn, tcg_rm); + genenvfn(tcg_rd32, tcg_env, tcg_rn, tcg_rm); tcg_gen_extu_i32_i64(tcg_rd, tcg_rd32); } @@ -9345,16 +9345,16 @@ static void disas_simd_scalar_three_reg_same_extra(DisasContext *s, switch (opcode) { case 0x0: /* SQRDMLAH */ if (size == 1) { - gen_helper_neon_qrdmlah_s16(ele3, cpu_env, ele1, ele2, ele3); + gen_helper_neon_qrdmlah_s16(ele3, tcg_env, ele1, ele2, ele3); } else { - gen_helper_neon_qrdmlah_s32(ele3, cpu_env, ele1, ele2, ele3); + gen_helper_neon_qrdmlah_s32(ele3, tcg_env, ele1, ele2, ele3); } break; case 0x1: /* SQRDMLSH */ if (size == 1) { - gen_helper_neon_qrdmlsh_s16(ele3, cpu_env, ele1, ele2, ele3); + gen_helper_neon_qrdmlsh_s16(ele3, tcg_env, ele1, ele2, ele3); } else { - gen_helper_neon_qrdmlsh_s32(ele3, cpu_env, ele1, ele2, ele3); + gen_helper_neon_qrdmlsh_s32(ele3, tcg_env, ele1, ele2, ele3); } break; default: @@ -9394,9 +9394,9 @@ static void handle_2misc_64(DisasContext *s, int opcode, bool u, break; case 0x7: /* SQABS, SQNEG */ if (u) { - gen_helper_neon_qneg_s64(tcg_rd, cpu_env, tcg_rn); + gen_helper_neon_qneg_s64(tcg_rd, tcg_env, tcg_rn); } else { - gen_helper_neon_qabs_s64(tcg_rd, cpu_env, tcg_rn); + gen_helper_neon_qabs_s64(tcg_rd, tcg_env, tcg_rn); } break; case 0xa: /* CMLT */ @@ -9425,7 +9425,7 @@ static void handle_2misc_64(DisasContext *s, int opcode, bool u, gen_helper_vfp_negd(tcg_rd, tcg_rn); break; case 0x7f: /* FSQRT */ - gen_helper_vfp_sqrtd(tcg_rd, tcg_rn, cpu_env); + gen_helper_vfp_sqrtd(tcg_rd, tcg_rn, tcg_env); break; case 0x1a: /* FCVTNS */ case 0x1b: /* FCVTMS */ @@ -9731,7 +9731,7 @@ static void handle_2misc_narrow(DisasContext *s, bool scalar, case 0x16: /* FCVTN, FCVTN2 */ /* 32 bit to 16 bit or 64 bit to 32 bit float conversion */ if (size == 2) { - gen_helper_vfp_fcvtsd(tcg_res[pass], tcg_op, cpu_env); + gen_helper_vfp_fcvtsd(tcg_res[pass], tcg_op, tcg_env); } else { TCGv_i32 tcg_lo = tcg_temp_new_i32(); TCGv_i32 tcg_hi = tcg_temp_new_i32(); @@ -9755,7 +9755,7 @@ static void handle_2misc_narrow(DisasContext *s, bool scalar, * with von Neumann rounding (round to odd) */ assert(size == 2); - gen_helper_fcvtx_f64_to_f32(tcg_res[pass], tcg_op, cpu_env); + gen_helper_fcvtx_f64_to_f32(tcg_res[pass], tcg_op, tcg_env); break; default: g_assert_not_reached(); @@ -9764,7 +9764,7 @@ static void handle_2misc_narrow(DisasContext *s, bool scalar, if (genfn) { genfn(tcg_res[pass], tcg_op); } else if (genenvfn) { - genenvfn(tcg_res[pass], cpu_env, tcg_op); + genenvfn(tcg_res[pass], tcg_env, tcg_op); } } @@ -9790,9 +9790,9 @@ static void handle_2misc_satacc(DisasContext *s, bool is_scalar, bool is_u, read_vec_element(s, tcg_rd, rd, pass, MO_64); if (is_u) { /* USQADD */ - gen_helper_neon_uqadd_s64(tcg_rd, cpu_env, tcg_rn, tcg_rd); + gen_helper_neon_uqadd_s64(tcg_rd, tcg_env, tcg_rn, tcg_rd); } else { /* SUQADD */ - gen_helper_neon_sqadd_u64(tcg_rd, cpu_env, tcg_rn, tcg_rd); + gen_helper_neon_sqadd_u64(tcg_rd, tcg_env, tcg_rn, tcg_rd); } write_vec_element(s, tcg_rd, rd, pass, MO_64); } @@ -9820,13 +9820,13 @@ static void handle_2misc_satacc(DisasContext *s, bool is_scalar, bool is_u, if (is_u) { /* USQADD */ switch (size) { case 0: - gen_helper_neon_uqadd_s8(tcg_rd, cpu_env, tcg_rn, tcg_rd); + gen_helper_neon_uqadd_s8(tcg_rd, tcg_env, tcg_rn, tcg_rd); break; case 1: - gen_helper_neon_uqadd_s16(tcg_rd, cpu_env, tcg_rn, tcg_rd); + gen_helper_neon_uqadd_s16(tcg_rd, tcg_env, tcg_rn, tcg_rd); break; case 2: - gen_helper_neon_uqadd_s32(tcg_rd, cpu_env, tcg_rn, tcg_rd); + gen_helper_neon_uqadd_s32(tcg_rd, tcg_env, tcg_rn, tcg_rd); break; default: g_assert_not_reached(); @@ -9834,13 +9834,13 @@ static void handle_2misc_satacc(DisasContext *s, bool is_scalar, bool is_u, } else { /* SUQADD */ switch (size) { case 0: - gen_helper_neon_sqadd_u8(tcg_rd, cpu_env, tcg_rn, tcg_rd); + gen_helper_neon_sqadd_u8(tcg_rd, tcg_env, tcg_rn, tcg_rd); break; case 1: - gen_helper_neon_sqadd_u16(tcg_rd, cpu_env, tcg_rn, tcg_rd); + gen_helper_neon_sqadd_u16(tcg_rd, tcg_env, tcg_rn, tcg_rd); break; case 2: - gen_helper_neon_sqadd_u32(tcg_rd, cpu_env, tcg_rn, tcg_rd); + gen_helper_neon_sqadd_u32(tcg_rd, tcg_env, tcg_rn, tcg_rd); break; default: g_assert_not_reached(); @@ -10018,7 +10018,7 @@ static void disas_simd_scalar_two_reg_misc(DisasContext *s, uint32_t insn) { gen_helper_neon_qabs_s32, gen_helper_neon_qneg_s32 }, }; genfn = fns[size][u]; - genfn(tcg_rd, cpu_env, tcg_rn); + genfn(tcg_rd, tcg_env, tcg_rn); break; } case 0x1a: /* FCVTNS */ @@ -10403,7 +10403,7 @@ static void handle_3rd_widening(DisasContext *s, int is_q, int is_u, int size, case 11: /* SQDMLSL, SQDMLSL2 */ case 13: /* SQDMULL, SQDMULL2 */ tcg_gen_mul_i64(tcg_passres, tcg_op1, tcg_op2); - gen_helper_neon_addl_saturate_s64(tcg_passres, cpu_env, + gen_helper_neon_addl_saturate_s64(tcg_passres, tcg_env, tcg_passres, tcg_passres); break; default: @@ -10415,7 +10415,7 @@ static void handle_3rd_widening(DisasContext *s, int is_q, int is_u, int size, if (accop < 0) { tcg_gen_neg_i64(tcg_passres, tcg_passres); } - gen_helper_neon_addl_saturate_s64(tcg_res[pass], cpu_env, + gen_helper_neon_addl_saturate_s64(tcg_res[pass], tcg_env, tcg_res[pass], tcg_passres); } else if (accop > 0) { tcg_gen_add_i64(tcg_res[pass], tcg_res[pass], tcg_passres); @@ -10495,7 +10495,7 @@ static void handle_3rd_widening(DisasContext *s, int is_q, int is_u, int size, case 13: /* SQDMULL, SQDMULL2 */ assert(size == 1); gen_helper_neon_mull_s16(tcg_passres, tcg_op1, tcg_op2); - gen_helper_neon_addl_saturate_s32(tcg_passres, cpu_env, + gen_helper_neon_addl_saturate_s32(tcg_passres, tcg_env, tcg_passres, tcg_passres); break; default: @@ -10508,7 +10508,7 @@ static void handle_3rd_widening(DisasContext *s, int is_q, int is_u, int size, if (accop < 0) { gen_helper_neon_negl_u32(tcg_passres, tcg_passres); } - gen_helper_neon_addl_saturate_s32(tcg_res[pass], cpu_env, + gen_helper_neon_addl_saturate_s32(tcg_res[pass], tcg_env, tcg_res[pass], tcg_passres); } else { @@ -10978,7 +10978,7 @@ static void disas_simd_3same_float(DisasContext *s, uint32_t insn) int data = (is_2 << 1) | is_s; tcg_gen_gvec_3_ptr(vec_full_reg_offset(s, rd), vec_full_reg_offset(s, rn), - vec_full_reg_offset(s, rm), cpu_env, + vec_full_reg_offset(s, rm), tcg_env, is_q ? 16 : 8, vec_full_reg_size(s), data, gen_helper_gvec_fmlal_a64); } @@ -11233,7 +11233,7 @@ static void disas_simd_3same_int(DisasContext *s, uint32_t insn) } if (genenvfn) { - genenvfn(tcg_res, cpu_env, tcg_op1, tcg_op2); + genenvfn(tcg_res, tcg_env, tcg_op1, tcg_op2); } else { genfn(tcg_res, tcg_op1, tcg_op2); } @@ -11702,7 +11702,7 @@ static void handle_2misc_widening(DisasContext *s, int opcode, bool is_q, tcg_res[pass] = tcg_temp_new_i64(); read_vec_element_i32(s, tcg_op, rn, srcelt + pass, MO_32); - gen_helper_vfp_fcvtds(tcg_res[pass], tcg_op, cpu_env); + gen_helper_vfp_fcvtds(tcg_res[pass], tcg_op, tcg_env); } for (pass = 0; pass < 2; pass++) { write_vec_element(s, tcg_res[pass], rd, pass, MO_64); @@ -12257,9 +12257,9 @@ static void disas_simd_two_reg_misc(DisasContext *s, uint32_t insn) break; case 0x7: /* SQABS, SQNEG */ if (u) { - gen_helper_neon_qneg_s32(tcg_res, cpu_env, tcg_op); + gen_helper_neon_qneg_s32(tcg_res, tcg_env, tcg_op); } else { - gen_helper_neon_qabs_s32(tcg_res, cpu_env, tcg_op); + gen_helper_neon_qabs_s32(tcg_res, tcg_env, tcg_op); } break; case 0x2f: /* FABS */ @@ -12269,7 +12269,7 @@ static void disas_simd_two_reg_misc(DisasContext *s, uint32_t insn) gen_helper_vfp_negs(tcg_res, tcg_op); break; case 0x7f: /* FSQRT */ - gen_helper_vfp_sqrts(tcg_res, tcg_op, cpu_env); + gen_helper_vfp_sqrts(tcg_res, tcg_op, tcg_env); break; case 0x1a: /* FCVTNS */ case 0x1b: /* FCVTMS */ @@ -12333,7 +12333,7 @@ static void disas_simd_two_reg_misc(DisasContext *s, uint32_t insn) { gen_helper_neon_qabs_s16, gen_helper_neon_qneg_s16 }, }; genfn = fns[size][u]; - genfn(tcg_res, cpu_env, tcg_op); + genfn(tcg_res, tcg_env, tcg_op); break; } case 0x4: /* CLS, CLZ */ @@ -12770,7 +12770,7 @@ static void disas_simd_indexed(DisasContext *s, uint32_t insn) return; } size = MO_16; - /* is_fp, but we pass cpu_env not fp_status. */ + /* is_fp, but we pass tcg_env not fp_status. */ break; default: unallocated_encoding(s); @@ -12913,7 +12913,7 @@ static void disas_simd_indexed(DisasContext *s, uint32_t insn) int data = (index << 2) | (is_2 << 1) | is_s; tcg_gen_gvec_3_ptr(vec_full_reg_offset(s, rd), vec_full_reg_offset(s, rn), - vec_full_reg_offset(s, rm), cpu_env, + vec_full_reg_offset(s, rm), tcg_env, is_q ? 16 : 8, vec_full_reg_size(s), data, gen_helper_gvec_fmlal_idx_a64); } @@ -13132,19 +13132,19 @@ static void disas_simd_indexed(DisasContext *s, uint32_t insn) break; case 0x0c: /* SQDMULH */ if (size == 1) { - gen_helper_neon_qdmulh_s16(tcg_res, cpu_env, + gen_helper_neon_qdmulh_s16(tcg_res, tcg_env, tcg_op, tcg_idx); } else { - gen_helper_neon_qdmulh_s32(tcg_res, cpu_env, + gen_helper_neon_qdmulh_s32(tcg_res, tcg_env, tcg_op, tcg_idx); } break; case 0x0d: /* SQRDMULH */ if (size == 1) { - gen_helper_neon_qrdmulh_s16(tcg_res, cpu_env, + gen_helper_neon_qrdmulh_s16(tcg_res, tcg_env, tcg_op, tcg_idx); } else { - gen_helper_neon_qrdmulh_s32(tcg_res, cpu_env, + gen_helper_neon_qrdmulh_s32(tcg_res, tcg_env, tcg_op, tcg_idx); } break; @@ -13152,10 +13152,10 @@ static void disas_simd_indexed(DisasContext *s, uint32_t insn) read_vec_element_i32(s, tcg_res, rd, pass, is_scalar ? size : MO_32); if (size == 1) { - gen_helper_neon_qrdmlah_s16(tcg_res, cpu_env, + gen_helper_neon_qrdmlah_s16(tcg_res, tcg_env, tcg_op, tcg_idx, tcg_res); } else { - gen_helper_neon_qrdmlah_s32(tcg_res, cpu_env, + gen_helper_neon_qrdmlah_s32(tcg_res, tcg_env, tcg_op, tcg_idx, tcg_res); } break; @@ -13163,10 +13163,10 @@ static void disas_simd_indexed(DisasContext *s, uint32_t insn) read_vec_element_i32(s, tcg_res, rd, pass, is_scalar ? size : MO_32); if (size == 1) { - gen_helper_neon_qrdmlsh_s16(tcg_res, cpu_env, + gen_helper_neon_qrdmlsh_s16(tcg_res, tcg_env, tcg_op, tcg_idx, tcg_res); } else { - gen_helper_neon_qrdmlsh_s32(tcg_res, cpu_env, + gen_helper_neon_qrdmlsh_s32(tcg_res, tcg_env, tcg_op, tcg_idx, tcg_res); } break; @@ -13224,7 +13224,7 @@ static void disas_simd_indexed(DisasContext *s, uint32_t insn) if (satop) { /* saturating, doubling */ - gen_helper_neon_addl_saturate_s64(tcg_passres, cpu_env, + gen_helper_neon_addl_saturate_s64(tcg_passres, tcg_env, tcg_passres, tcg_passres); } @@ -13246,7 +13246,7 @@ static void disas_simd_indexed(DisasContext *s, uint32_t insn) tcg_gen_neg_i64(tcg_passres, tcg_passres); /* fall through */ case 0x3: /* SQDMLAL, SQDMLAL2 */ - gen_helper_neon_addl_saturate_s64(tcg_res[pass], cpu_env, + gen_helper_neon_addl_saturate_s64(tcg_res[pass], tcg_env, tcg_res[pass], tcg_passres); break; @@ -13296,7 +13296,7 @@ static void disas_simd_indexed(DisasContext *s, uint32_t insn) gen_helper_neon_mull_u16(tcg_passres, tcg_op, tcg_idx); } if (satop) { - gen_helper_neon_addl_saturate_s32(tcg_passres, cpu_env, + gen_helper_neon_addl_saturate_s32(tcg_passres, tcg_env, tcg_passres, tcg_passres); } @@ -13320,7 +13320,7 @@ static void disas_simd_indexed(DisasContext *s, uint32_t insn) gen_helper_neon_negl_u32(tcg_passres, tcg_passres); /* fall through */ case 0x3: /* SQDMLAL, SQDMLAL2 */ - gen_helper_neon_addl_saturate_s32(tcg_res[pass], cpu_env, + gen_helper_neon_addl_saturate_s32(tcg_res[pass], tcg_env, tcg_res[pass], tcg_passres); break; @@ -14120,7 +14120,7 @@ static void aarch64_tr_translate_insn(DisasContextBase *dcbase, CPUState *cpu) * start of the TB. */ assert(s->base.num_insns == 1); - gen_helper_exception_pc_alignment(cpu_env, tcg_constant_tl(pc)); + gen_helper_exception_pc_alignment(tcg_env, tcg_constant_tl(pc)); s->base.is_jmp = DISAS_NORETURN; s->base.pc_next = QEMU_ALIGN_UP(pc, 4); return; @@ -14244,11 +14244,11 @@ static void aarch64_tr_tb_stop(DisasContextBase *dcbase, CPUState *cpu) break; case DISAS_WFE: gen_a64_update_pc(dc, 4); - gen_helper_wfe(cpu_env); + gen_helper_wfe(tcg_env); break; case DISAS_YIELD: gen_a64_update_pc(dc, 4); - gen_helper_yield(cpu_env); + gen_helper_yield(tcg_env); break; case DISAS_WFI: /* @@ -14256,7 +14256,7 @@ static void aarch64_tr_tb_stop(DisasContextBase *dcbase, CPUState *cpu) * the CPU if trying to debug across a WFI. */ gen_a64_update_pc(dc, 4); - gen_helper_wfi(cpu_env, tcg_constant_i32(4)); + gen_helper_wfi(tcg_env, tcg_constant_i32(4)); /* * The helper doesn't necessarily throw an exception, but we * must go back to the main loop to check for interrupts anyway. diff --git a/target/arm/tcg/translate-a64.h b/target/arm/tcg/translate-a64.h index b55dc435fc..96ba39b37e 100644 --- a/target/arm/tcg/translate-a64.h +++ b/target/arm/tcg/translate-a64.h @@ -115,7 +115,7 @@ static inline int vec_full_reg_offset(DisasContext *s, int regno) static inline TCGv_ptr vec_full_reg_ptr(DisasContext *s, int regno) { TCGv_ptr ret = tcg_temp_new_ptr(); - tcg_gen_addi_ptr(ret, cpu_env, vec_full_reg_offset(s, regno)); + tcg_gen_addi_ptr(ret, tcg_env, vec_full_reg_offset(s, regno)); return ret; } @@ -179,7 +179,7 @@ static inline int pred_gvec_reg_size(DisasContext *s) static inline TCGv_ptr pred_full_reg_ptr(DisasContext *s, int regno) { TCGv_ptr ret = tcg_temp_new_ptr(); - tcg_gen_addi_ptr(ret, cpu_env, pred_full_reg_offset(s, regno)); + tcg_gen_addi_ptr(ret, tcg_env, pred_full_reg_offset(s, regno)); return ret; } diff --git a/target/arm/tcg/translate-m-nocp.c b/target/arm/tcg/translate-m-nocp.c index 42308c4db5..f564d06ccf 100644 --- a/target/arm/tcg/translate-m-nocp.c +++ b/target/arm/tcg/translate-m-nocp.c @@ -85,9 +85,9 @@ static bool trans_VLLDM_VLSTM(DisasContext *s, arg_VLLDM_VLSTM *a) fptr = load_reg(s, a->rn); if (a->l) { - gen_helper_v7m_vlldm(cpu_env, fptr); + gen_helper_v7m_vlldm(tcg_env, fptr); } else { - gen_helper_v7m_vlstm(cpu_env, fptr); + gen_helper_v7m_vlstm(tcg_env, fptr); } clear_eci_state(s); @@ -322,7 +322,7 @@ static bool gen_M_fp_sysreg_write(DisasContext *s, int regno, switch (regno) { case ARM_VFP_FPSCR: tmp = loadfn(s, opaque, true); - gen_helper_vfp_set_fpscr(cpu_env, tmp); + gen_helper_vfp_set_fpscr(tcg_env, tmp); gen_lookup_tb(s); break; case ARM_VFP_FPSCR_NZCVQC: @@ -391,7 +391,7 @@ static bool gen_M_fp_sysreg_write(DisasContext *s, int regno, R_V7M_CONTROL_SFPA_SHIFT, 1); store_cpu_field(control, v7m.control[M_REG_S]); tcg_gen_andi_i32(tmp, tmp, ~FPCR_NZCV_MASK); - gen_helper_vfp_set_fpscr(cpu_env, tmp); + gen_helper_vfp_set_fpscr(tcg_env, tmp); s->base.is_jmp = DISAS_UPDATE_NOCHAIN; break; } @@ -451,12 +451,12 @@ static bool gen_M_fp_sysreg_read(DisasContext *s, int regno, switch (regno) { case ARM_VFP_FPSCR: tmp = tcg_temp_new_i32(); - gen_helper_vfp_get_fpscr(tmp, cpu_env); + gen_helper_vfp_get_fpscr(tmp, tcg_env); storefn(s, opaque, tmp, true); break; case ARM_VFP_FPSCR_NZCVQC: tmp = tcg_temp_new_i32(); - gen_helper_vfp_get_fpscr(tmp, cpu_env); + gen_helper_vfp_get_fpscr(tmp, tcg_env); tcg_gen_andi_i32(tmp, tmp, FPCR_NZCVQC_MASK); storefn(s, opaque, tmp, true); break; @@ -475,7 +475,7 @@ static bool gen_M_fp_sysreg_read(DisasContext *s, int regno, /* Bits [27:0] from FPSCR, bit [31] from CONTROL.SFPA */ tmp = tcg_temp_new_i32(); sfpa = tcg_temp_new_i32(); - gen_helper_vfp_get_fpscr(tmp, cpu_env); + gen_helper_vfp_get_fpscr(tmp, tcg_env); tcg_gen_andi_i32(tmp, tmp, ~FPCR_NZCV_MASK); control = load_cpu_field(v7m.control[M_REG_S]); tcg_gen_andi_i32(sfpa, control, R_V7M_CONTROL_SFPA_MASK); @@ -493,7 +493,7 @@ static bool gen_M_fp_sysreg_read(DisasContext *s, int regno, tcg_gen_andi_i32(control, control, ~R_V7M_CONTROL_SFPA_MASK); store_cpu_field(control, v7m.control[M_REG_S]); fpscr = load_cpu_field(v7m.fpdscr[M_REG_NS]); - gen_helper_vfp_set_fpscr(cpu_env, fpscr); + gen_helper_vfp_set_fpscr(tcg_env, fpscr); lookup_tb = true; break; } @@ -528,7 +528,7 @@ static bool gen_M_fp_sysreg_read(DisasContext *s, int regno, tmp = tcg_temp_new_i32(); sfpa = tcg_temp_new_i32(); fpscr = tcg_temp_new_i32(); - gen_helper_vfp_get_fpscr(fpscr, cpu_env); + gen_helper_vfp_get_fpscr(fpscr, tcg_env); tcg_gen_andi_i32(tmp, fpscr, ~FPCR_NZCV_MASK); control = load_cpu_field(v7m.control[M_REG_S]); tcg_gen_andi_i32(sfpa, control, R_V7M_CONTROL_SFPA_MASK); @@ -540,7 +540,7 @@ static bool gen_M_fp_sysreg_read(DisasContext *s, int regno, fpdscr = load_cpu_field(v7m.fpdscr[M_REG_NS]); tcg_gen_movcond_i32(TCG_COND_EQ, fpscr, sfpa, tcg_constant_i32(0), fpdscr, fpscr); - gen_helper_vfp_set_fpscr(cpu_env, fpscr); + gen_helper_vfp_set_fpscr(tcg_env, fpscr); break; } case ARM_VFP_VPR: @@ -643,7 +643,7 @@ static void fp_sysreg_to_memory(DisasContext *s, void *opaque, TCGv_i32 value, } if (s->v8m_stackcheck && a->rn == 13 && a->w) { - gen_helper_v8m_stackcheck(cpu_env, addr); + gen_helper_v8m_stackcheck(tcg_env, addr); } if (do_access) { @@ -682,7 +682,7 @@ static TCGv_i32 memory_to_fp_sysreg(DisasContext *s, void *opaque, } if (s->v8m_stackcheck && a->rn == 13 && a->w) { - gen_helper_v8m_stackcheck(cpu_env, addr); + gen_helper_v8m_stackcheck(tcg_env, addr); } if (do_access) { diff --git a/target/arm/tcg/translate-mve.c b/target/arm/tcg/translate-mve.c index 17d8e6804e..b1a8d6a65c 100644 --- a/target/arm/tcg/translate-mve.c +++ b/target/arm/tcg/translate-mve.c @@ -56,7 +56,7 @@ static inline long mve_qreg_offset(unsigned reg) static TCGv_ptr mve_qreg_ptr(unsigned reg) { TCGv_ptr ret = tcg_temp_new_ptr(); - tcg_gen_addi_ptr(ret, cpu_env, mve_qreg_offset(reg)); + tcg_gen_addi_ptr(ret, tcg_env, mve_qreg_offset(reg)); return ret; } @@ -173,7 +173,7 @@ static bool do_ldst(DisasContext *s, arg_VLDR_VSTR *a, MVEGenLdStFn *fn, } qreg = mve_qreg_ptr(a->qd); - fn(cpu_env, qreg, addr); + fn(tcg_env, qreg, addr); /* * Writeback always happens after the last beat of the insn, @@ -234,7 +234,7 @@ static bool do_ldst_sg(DisasContext *s, arg_vldst_sg *a, MVEGenLdStSGFn fn) qd = mve_qreg_ptr(a->qd); qm = mve_qreg_ptr(a->qm); - fn(cpu_env, qd, qm, addr); + fn(tcg_env, qd, qm, addr); mve_update_eci(s); return true; } @@ -330,7 +330,7 @@ static bool do_ldst_sg_imm(DisasContext *s, arg_vldst_sg_imm *a, qd = mve_qreg_ptr(a->qd); qm = mve_qreg_ptr(a->qm); - fn(cpu_env, qd, qm, tcg_constant_i32(offset)); + fn(tcg_env, qd, qm, tcg_constant_i32(offset)); mve_update_eci(s); return true; } @@ -397,7 +397,7 @@ static bool do_vldst_il(DisasContext *s, arg_vldst_il *a, MVEGenLdStIlFn *fn, * We pass the index of Qd, not a pointer, because the helper must * access multiple Q registers starting at Qd and working up. */ - fn(cpu_env, tcg_constant_i32(a->qd), rn); + fn(tcg_env, tcg_constant_i32(a->qd), rn); if (a->w) { tcg_gen_addi_i32(rn, rn, addrinc); @@ -491,7 +491,7 @@ static bool trans_VDUP(DisasContext *s, arg_VDUP *a) } else { qd = mve_qreg_ptr(a->qd); tcg_gen_dup_i32(a->size, rt, rt); - gen_helper_mve_vdup(cpu_env, qd, rt); + gen_helper_mve_vdup(tcg_env, qd, rt); } mve_update_eci(s); return true; @@ -517,7 +517,7 @@ static bool do_1op_vec(DisasContext *s, arg_1op *a, MVEGenOneOpFn fn, } else { qd = mve_qreg_ptr(a->qd); qm = mve_qreg_ptr(a->qm); - fn(cpu_env, qd, qm); + fn(tcg_env, qd, qm); } mve_update_eci(s); return true; @@ -612,7 +612,7 @@ static bool do_vcvt_rmode(DisasContext *s, arg_1op *a, qd = mve_qreg_ptr(a->qd); qm = mve_qreg_ptr(a->qm); - fn(cpu_env, qd, qm, tcg_constant_i32(arm_rmode_to_sf(rmode))); + fn(tcg_env, qd, qm, tcg_constant_i32(arm_rmode_to_sf(rmode))); mve_update_eci(s); return true; } @@ -800,7 +800,7 @@ static bool do_2op_vec(DisasContext *s, arg_2op *a, MVEGenTwoOpFn fn, qd = mve_qreg_ptr(a->qd); qn = mve_qreg_ptr(a->qn); qm = mve_qreg_ptr(a->qm); - fn(cpu_env, qd, qn, qm); + fn(tcg_env, qd, qn, qm); } mve_update_eci(s); return true; @@ -1052,7 +1052,7 @@ static bool do_2op_scalar(DisasContext *s, arg_2scalar *a, qd = mve_qreg_ptr(a->qd); qn = mve_qreg_ptr(a->qn); rm = load_reg(s, a->rm); - fn(cpu_env, qd, qn, rm); + fn(tcg_env, qd, qn, rm); mve_update_eci(s); return true; } @@ -1183,7 +1183,7 @@ static bool do_long_dual_acc(DisasContext *s, arg_vmlaldav *a, rda_i = tcg_constant_i64(0); } - fn(rda_o, cpu_env, qn, qm, rda_i); + fn(rda_o, tcg_env, qn, qm, rda_i); rdalo = tcg_temp_new_i32(); rdahi = tcg_temp_new_i32(); @@ -1281,7 +1281,7 @@ static bool do_dual_acc(DisasContext *s, arg_vmladav *a, MVEGenDualAccOpFn *fn) rda_o = tcg_temp_new_i32(); } - fn(rda_o, cpu_env, qn, qm, rda_i); + fn(rda_o, tcg_env, qn, qm, rda_i); store_reg(s, a->rda, rda_o); mve_update_eci(s); @@ -1377,7 +1377,7 @@ static bool trans_VPNOT(DisasContext *s, arg_VPNOT *a) return true; } - gen_helper_mve_vpnot(cpu_env); + gen_helper_mve_vpnot(tcg_env); /* This insn updates predication bits */ s->base.is_jmp = DISAS_UPDATE_NOCHAIN; mve_update_eci(s); @@ -1419,7 +1419,7 @@ static bool trans_VADDV(DisasContext *s, arg_VADDV *a) } qm = mve_qreg_ptr(a->qm); - fns[a->size][a->u](rda_o, cpu_env, qm, rda_i); + fns[a->size][a->u](rda_o, tcg_env, qm, rda_i); store_reg(s, a->rda, rda_o); mve_update_eci(s); @@ -1471,9 +1471,9 @@ static bool trans_VADDLV(DisasContext *s, arg_VADDLV *a) qm = mve_qreg_ptr(a->qm); if (a->u) { - gen_helper_mve_vaddlv_u(rda_o, cpu_env, qm, rda_i); + gen_helper_mve_vaddlv_u(rda_o, tcg_env, qm, rda_i); } else { - gen_helper_mve_vaddlv_s(rda_o, cpu_env, qm, rda_i); + gen_helper_mve_vaddlv_s(rda_o, tcg_env, qm, rda_i); } rdalo = tcg_temp_new_i32(); @@ -1508,7 +1508,7 @@ static bool do_1imm(DisasContext *s, arg_1imm *a, MVEGenOneOpImmFn *fn, imm, 16, 16); } else { qd = mve_qreg_ptr(a->qd); - fn(cpu_env, qd, tcg_constant_i64(imm)); + fn(tcg_env, qd, tcg_constant_i64(imm)); } mve_update_eci(s); return true; @@ -1580,7 +1580,7 @@ static bool do_2shift_vec(DisasContext *s, arg_2shift *a, MVEGenTwoOpShiftFn fn, } else { qd = mve_qreg_ptr(a->qd); qm = mve_qreg_ptr(a->qm); - fn(cpu_env, qd, qm, tcg_constant_i32(shift)); + fn(tcg_env, qd, qm, tcg_constant_i32(shift)); } mve_update_eci(s); return true; @@ -1685,7 +1685,7 @@ static bool do_2shift_scalar(DisasContext *s, arg_shl_scalar *a, qda = mve_qreg_ptr(a->qda); rm = load_reg(s, a->rm); - fn(cpu_env, qda, qda, rm); + fn(tcg_env, qda, qda, rm); mve_update_eci(s); return true; } @@ -1827,7 +1827,7 @@ static bool trans_VSHLC(DisasContext *s, arg_VSHLC *a) qd = mve_qreg_ptr(a->qd); rdm = load_reg(s, a->rdm); - gen_helper_mve_vshlc(rdm, cpu_env, qd, rdm, tcg_constant_i32(a->imm)); + gen_helper_mve_vshlc(rdm, tcg_env, qd, rdm, tcg_constant_i32(a->imm)); store_reg(s, a->rdm, rdm); mve_update_eci(s); return true; @@ -1856,7 +1856,7 @@ static bool do_vidup(DisasContext *s, arg_vidup *a, MVEGenVIDUPFn *fn) qd = mve_qreg_ptr(a->qd); rn = load_reg(s, a->rn); - fn(rn, cpu_env, qd, rn, tcg_constant_i32(a->imm)); + fn(rn, tcg_env, qd, rn, tcg_constant_i32(a->imm)); store_reg(s, a->rn, rn); mve_update_eci(s); return true; @@ -1891,7 +1891,7 @@ static bool do_viwdup(DisasContext *s, arg_viwdup *a, MVEGenVIWDUPFn *fn) qd = mve_qreg_ptr(a->qd); rn = load_reg(s, a->rn); rm = load_reg(s, a->rm); - fn(rn, cpu_env, qd, rn, rm, tcg_constant_i32(a->imm)); + fn(rn, tcg_env, qd, rn, rm, tcg_constant_i32(a->imm)); store_reg(s, a->rn, rn); mve_update_eci(s); return true; @@ -1957,7 +1957,7 @@ static bool do_vcmp(DisasContext *s, arg_vcmp *a, MVEGenCmpFn *fn) qn = mve_qreg_ptr(a->qn); qm = mve_qreg_ptr(a->qm); - fn(cpu_env, qn, qm); + fn(tcg_env, qn, qm); if (a->mask) { /* VPT */ gen_vpst(s, a->mask); @@ -1988,7 +1988,7 @@ static bool do_vcmp_scalar(DisasContext *s, arg_vcmp_scalar *a, } else { rm = load_reg(s, a->rm); } - fn(cpu_env, qn, rm); + fn(tcg_env, qn, rm); if (a->mask) { /* VPT */ gen_vpst(s, a->mask); @@ -2089,7 +2089,7 @@ static bool do_vmaxv(DisasContext *s, arg_vmaxv *a, MVEGenVADDVFn fn) qm = mve_qreg_ptr(a->qm); rda = load_reg(s, a->rda); - fn(rda, cpu_env, qm, rda); + fn(rda, tcg_env, qm, rda); store_reg(s, a->rda, rda); mve_update_eci(s); return true; @@ -2153,7 +2153,7 @@ static bool do_vabav(DisasContext *s, arg_vabav *a, MVEGenVABAVFn *fn) qm = mve_qreg_ptr(a->qm); qn = mve_qreg_ptr(a->qn); rda = load_reg(s, a->rda); - fn(rda, cpu_env, qn, qm, rda); + fn(rda, tcg_env, qn, qm, rda); store_reg(s, a->rda, rda); mve_update_eci(s); return true; diff --git a/target/arm/tcg/translate-neon.c b/target/arm/tcg/translate-neon.c index 8de4ceb203..144f18ba22 100644 --- a/target/arm/tcg/translate-neon.c +++ b/target/arm/tcg/translate-neon.c @@ -32,7 +32,7 @@ static TCGv_ptr vfp_reg_ptr(bool dp, int reg) { TCGv_ptr ret = tcg_temp_new_ptr(); - tcg_gen_addi_ptr(ret, cpu_env, vfp_reg_offset(dp, reg)); + tcg_gen_addi_ptr(ret, tcg_env, vfp_reg_offset(dp, reg)); return ret; } @@ -42,13 +42,13 @@ static void neon_load_element(TCGv_i32 var, int reg, int ele, MemOp mop) switch (mop) { case MO_UB: - tcg_gen_ld8u_i32(var, cpu_env, offset); + tcg_gen_ld8u_i32(var, tcg_env, offset); break; case MO_UW: - tcg_gen_ld16u_i32(var, cpu_env, offset); + tcg_gen_ld16u_i32(var, tcg_env, offset); break; case MO_UL: - tcg_gen_ld_i32(var, cpu_env, offset); + tcg_gen_ld_i32(var, tcg_env, offset); break; default: g_assert_not_reached(); @@ -61,16 +61,16 @@ static void neon_load_element64(TCGv_i64 var, int reg, int ele, MemOp mop) switch (mop) { case MO_UB: - tcg_gen_ld8u_i64(var, cpu_env, offset); + tcg_gen_ld8u_i64(var, tcg_env, offset); break; case MO_UW: - tcg_gen_ld16u_i64(var, cpu_env, offset); + tcg_gen_ld16u_i64(var, tcg_env, offset); break; case MO_UL: - tcg_gen_ld32u_i64(var, cpu_env, offset); + tcg_gen_ld32u_i64(var, tcg_env, offset); break; case MO_UQ: - tcg_gen_ld_i64(var, cpu_env, offset); + tcg_gen_ld_i64(var, tcg_env, offset); break; default: g_assert_not_reached(); @@ -83,13 +83,13 @@ static void neon_store_element(int reg, int ele, MemOp size, TCGv_i32 var) switch (size) { case MO_8: - tcg_gen_st8_i32(var, cpu_env, offset); + tcg_gen_st8_i32(var, tcg_env, offset); break; case MO_16: - tcg_gen_st16_i32(var, cpu_env, offset); + tcg_gen_st16_i32(var, tcg_env, offset); break; case MO_32: - tcg_gen_st_i32(var, cpu_env, offset); + tcg_gen_st_i32(var, tcg_env, offset); break; default: g_assert_not_reached(); @@ -102,16 +102,16 @@ static void neon_store_element64(int reg, int ele, MemOp size, TCGv_i64 var) switch (size) { case MO_8: - tcg_gen_st8_i64(var, cpu_env, offset); + tcg_gen_st8_i64(var, tcg_env, offset); break; case MO_16: - tcg_gen_st16_i64(var, cpu_env, offset); + tcg_gen_st16_i64(var, tcg_env, offset); break; case MO_32: - tcg_gen_st32_i64(var, cpu_env, offset); + tcg_gen_st32_i64(var, tcg_env, offset); break; case MO_64: - tcg_gen_st_i64(var, cpu_env, offset); + tcg_gen_st_i64(var, tcg_env, offset); break; default: g_assert_not_reached(); @@ -296,7 +296,7 @@ static bool trans_VFML(DisasContext *s, arg_VFML *a) tcg_gen_gvec_3_ptr(vfp_reg_offset(1, a->vd), vfp_reg_offset(a->q, a->vn), vfp_reg_offset(a->q, a->vm), - cpu_env, opr_sz, opr_sz, a->s, /* is_2 == 0 */ + tcg_env, opr_sz, opr_sz, a->s, /* is_2 == 0 */ gen_helper_gvec_fmlal_a32); return true; } @@ -390,7 +390,7 @@ static bool trans_VFML_scalar(DisasContext *s, arg_VFML_scalar *a) tcg_gen_gvec_3_ptr(vfp_reg_offset(1, a->vd), vfp_reg_offset(a->q, a->vn), vfp_reg_offset(a->q, a->rm), - cpu_env, opr_sz, opr_sz, + tcg_env, opr_sz, opr_sz, (a->index << 2) | a->s, /* is_2 == 0 */ gen_helper_gvec_fmlal_idx_a32); return true; @@ -920,7 +920,7 @@ DO_SHA2(SHA256SU1, gen_helper_crypto_sha256su1) #define DO_3SAME_64_ENV(INSN, FUNC) \ static void gen_##INSN##_elt(TCGv_i64 d, TCGv_i64 n, TCGv_i64 m) \ { \ - FUNC(d, cpu_env, n, m); \ + FUNC(d, tcg_env, n, m); \ } \ DO_3SAME_64(INSN, gen_##INSN##_elt) @@ -953,7 +953,7 @@ DO_3SAME_64_ENV(VQRSHL_U64, gen_helper_neon_qrshl_u64) } /* - * Some helper functions need to be passed the cpu_env. In order + * Some helper functions need to be passed the tcg_env. In order * to use those with the gvec APIs like tcg_gen_gvec_3() we need * to create wrapper functions whose prototype is a NeonGenTwoOpFn() * and which call a NeonGenTwoOpEnvFn(). @@ -961,7 +961,7 @@ DO_3SAME_64_ENV(VQRSHL_U64, gen_helper_neon_qrshl_u64) #define WRAP_ENV_FN(WRAPNAME, FUNC) \ static void WRAPNAME(TCGv_i32 d, TCGv_i32 n, TCGv_i32 m) \ { \ - FUNC(d, cpu_env, n, m); \ + FUNC(d, tcg_env, n, m); \ } #define DO_3SAME_32_ENV(INSN, FUNC) \ @@ -1305,7 +1305,7 @@ static bool do_2shift_env_64(DisasContext *s, arg_2reg_shift *a, { /* * 2-reg-and-shift operations, size == 3 case, where the - * function needs to be passed cpu_env. + * function needs to be passed tcg_env. */ TCGv_i64 constimm; int pass; @@ -1338,7 +1338,7 @@ static bool do_2shift_env_64(DisasContext *s, arg_2reg_shift *a, TCGv_i64 tmp = tcg_temp_new_i64(); read_neon_element64(tmp, a->vm, pass, MO_64); - fn(tmp, cpu_env, tmp, constimm); + fn(tmp, tcg_env, tmp, constimm); write_neon_element64(tmp, a->vd, pass, MO_64); } return true; @@ -1349,7 +1349,7 @@ static bool do_2shift_env_32(DisasContext *s, arg_2reg_shift *a, { /* * 2-reg-and-shift operations, size < 3 case, where the - * helper needs to be passed cpu_env. + * helper needs to be passed tcg_env. */ TCGv_i32 constimm, tmp; int pass; @@ -1381,7 +1381,7 @@ static bool do_2shift_env_32(DisasContext *s, arg_2reg_shift *a, for (pass = 0; pass < (a->q ? 4 : 2); pass++) { read_neon_element32(tmp, a->vm, pass, MO_32); - fn(tmp, cpu_env, tmp, constimm); + fn(tmp, tcg_env, tmp, constimm); write_neon_element32(tmp, a->vd, pass, MO_32); } return true; @@ -1447,11 +1447,11 @@ static bool do_2shift_narrow_64(DisasContext *s, arg_2reg_shift *a, read_neon_element64(rm2, a->vm, 1, MO_64); shiftfn(rm1, rm1, constimm); - narrowfn(rd, cpu_env, rm1); + narrowfn(rd, tcg_env, rm1); write_neon_element32(rd, a->vd, 0, MO_32); shiftfn(rm2, rm2, constimm); - narrowfn(rd, cpu_env, rm2); + narrowfn(rd, tcg_env, rm2); write_neon_element32(rd, a->vd, 1, MO_32); return true; @@ -1514,7 +1514,7 @@ static bool do_2shift_narrow_32(DisasContext *s, arg_2reg_shift *a, tcg_gen_concat_i32_i64(rtmp, rm1, rm2); - narrowfn(rm1, cpu_env, rtmp); + narrowfn(rm1, tcg_env, rtmp); write_neon_element32(rm1, a->vd, 0, MO_32); shiftfn(rm3, rm3, constimm); @@ -1522,7 +1522,7 @@ static bool do_2shift_narrow_32(DisasContext *s, arg_2reg_shift *a, tcg_gen_concat_i32_i64(rtmp, rm3, rm4); - narrowfn(rm3, cpu_env, rtmp); + narrowfn(rm3, tcg_env, rtmp); write_neon_element32(rm3, a->vd, 1, MO_32); return true; } @@ -2159,13 +2159,13 @@ DO_VMLAL(VMLSL_U,mull_u,sub) static void gen_VQDMULL_16(TCGv_i64 rd, TCGv_i32 rn, TCGv_i32 rm) { gen_helper_neon_mull_s16(rd, rn, rm); - gen_helper_neon_addl_saturate_s32(rd, cpu_env, rd, rd); + gen_helper_neon_addl_saturate_s32(rd, tcg_env, rd, rd); } static void gen_VQDMULL_32(TCGv_i64 rd, TCGv_i32 rn, TCGv_i32 rm) { gen_mull_s32(rd, rn, rm); - gen_helper_neon_addl_saturate_s64(rd, cpu_env, rd, rd); + gen_helper_neon_addl_saturate_s64(rd, tcg_env, rd, rd); } static bool trans_VQDMULL_3d(DisasContext *s, arg_3diff *a) @@ -2182,12 +2182,12 @@ static bool trans_VQDMULL_3d(DisasContext *s, arg_3diff *a) static void gen_VQDMLAL_acc_16(TCGv_i64 rd, TCGv_i64 rn, TCGv_i64 rm) { - gen_helper_neon_addl_saturate_s32(rd, cpu_env, rn, rm); + gen_helper_neon_addl_saturate_s32(rd, tcg_env, rn, rm); } static void gen_VQDMLAL_acc_32(TCGv_i64 rd, TCGv_i64 rn, TCGv_i64 rm) { - gen_helper_neon_addl_saturate_s64(rd, cpu_env, rn, rm); + gen_helper_neon_addl_saturate_s64(rd, tcg_env, rn, rm); } static bool trans_VQDMLAL_3d(DisasContext *s, arg_3diff *a) @@ -2211,13 +2211,13 @@ static bool trans_VQDMLAL_3d(DisasContext *s, arg_3diff *a) static void gen_VQDMLSL_acc_16(TCGv_i64 rd, TCGv_i64 rn, TCGv_i64 rm) { gen_helper_neon_negl_u32(rm, rm); - gen_helper_neon_addl_saturate_s32(rd, cpu_env, rn, rm); + gen_helper_neon_addl_saturate_s32(rd, tcg_env, rn, rm); } static void gen_VQDMLSL_acc_32(TCGv_i64 rd, TCGv_i64 rn, TCGv_i64 rm) { tcg_gen_neg_i64(rm, rm); - gen_helper_neon_addl_saturate_s64(rd, cpu_env, rn, rm); + gen_helper_neon_addl_saturate_s64(rd, tcg_env, rn, rm); } static bool trans_VQDMLSL_3d(DisasContext *s, arg_3diff *a) @@ -2550,7 +2550,7 @@ static bool do_vqrdmlah_2sc(DisasContext *s, arg_2scalar *a, for (pass = 0; pass < (a->q ? 4 : 2); pass++) { read_neon_element32(rn, a->vn, pass, MO_32); read_neon_element32(rd, a->vd, pass, MO_32); - opfn(rd, cpu_env, rn, scalar, rd); + opfn(rd, tcg_env, rn, scalar, rd); write_neon_element32(rd, a->vd, pass, MO_32); } return true; @@ -2837,7 +2837,7 @@ static bool trans_VTBL(DisasContext *s, arg_VTBL *a) val = tcg_temp_new_i64(); read_neon_element64(val, a->vm, 0, MO_64); - gen_helper_neon_tbl(val, cpu_env, desc, val, def); + gen_helper_neon_tbl(val, tcg_env, desc, val, def); write_neon_element64(val, a->vd, 0, MO_64); return true; } @@ -3171,9 +3171,9 @@ static bool do_vmovn(DisasContext *s, arg_2misc *a, rd1 = tcg_temp_new_i32(); read_neon_element64(rm, a->vm, 0, MO_64); - narrowfn(rd0, cpu_env, rm); + narrowfn(rd0, tcg_env, rm); read_neon_element64(rm, a->vm, 1, MO_64); - narrowfn(rd1, cpu_env, rm); + narrowfn(rd1, tcg_env, rm); write_neon_element32(rd0, a->vd, 0, MO_32); write_neon_element32(rd1, a->vd, 1, MO_32); return true; @@ -3625,7 +3625,7 @@ static bool trans_VRSQRTE(DisasContext *s, arg_2misc *a) #define WRAP_1OP_ENV_FN(WRAPNAME, FUNC) \ static void WRAPNAME(TCGv_i32 d, TCGv_i32 m) \ { \ - FUNC(d, cpu_env, m); \ + FUNC(d, tcg_env, m); \ } WRAP_1OP_ENV_FN(gen_VQABS_s8, gen_helper_neon_qabs_s8) diff --git a/target/arm/tcg/translate-sme.c b/target/arm/tcg/translate-sme.c index 6038b0a06f..8f0dfc884e 100644 --- a/target/arm/tcg/translate-sme.c +++ b/target/arm/tcg/translate-sme.c @@ -90,7 +90,7 @@ static TCGv_ptr get_tile_rowcol(DisasContext *s, int esz, int rs, /* Add the byte offset to env to produce the final pointer. */ addr = tcg_temp_new_ptr(); tcg_gen_ext_i32_ptr(addr, tmp); - tcg_gen_add_ptr(addr, addr, cpu_env); + tcg_gen_add_ptr(addr, addr, tcg_env); return addr; } @@ -106,7 +106,7 @@ static TCGv_ptr get_tile(DisasContext *s, int esz, int tile) offset = tile * sizeof(ARMVectorReg) + offsetof(CPUARMState, zarray); - tcg_gen_addi_ptr(addr, cpu_env, offset); + tcg_gen_addi_ptr(addr, tcg_env, offset); return addr; } @@ -116,7 +116,7 @@ static bool trans_ZERO(DisasContext *s, arg_ZERO *a) return false; } if (sme_za_enabled_check(s)) { - gen_helper_sme_zero(cpu_env, tcg_constant_i32(a->imm), + gen_helper_sme_zero(tcg_env, tcg_constant_i32(a->imm), tcg_constant_i32(streaming_vec_reg_size(s))); } return true; @@ -237,7 +237,7 @@ static bool trans_LDST1(DisasContext *s, arg_LDST1 *a) svl = streaming_vec_reg_size(s); desc = simd_desc(svl, svl, desc); - fns[a->esz][be][a->v][mte][a->st](cpu_env, t_za, t_pg, addr, + fns[a->esz][be][a->v][mte][a->st](tcg_env, t_za, t_pg, addr, tcg_constant_i32(desc)); return true; } diff --git a/target/arm/tcg/translate-sve.c b/target/arm/tcg/translate-sve.c index 2ba5efadfd..7b39962f20 100644 --- a/target/arm/tcg/translate-sve.c +++ b/target/arm/tcg/translate-sve.c @@ -497,8 +497,8 @@ static void do_predtest(DisasContext *s, int dofs, int gofs, int words) TCGv_ptr gptr = tcg_temp_new_ptr(); TCGv_i32 t = tcg_temp_new_i32(); - tcg_gen_addi_ptr(dptr, cpu_env, dofs); - tcg_gen_addi_ptr(gptr, cpu_env, gofs); + tcg_gen_addi_ptr(dptr, tcg_env, dofs); + tcg_gen_addi_ptr(gptr, tcg_env, gofs); gen_helper_sve_predtest(t, dptr, gptr, tcg_constant_i32(words)); @@ -956,8 +956,8 @@ static bool do_vpz_ool(DisasContext *s, arg_rpr_esz *a, t_zn = tcg_temp_new_ptr(); t_pg = tcg_temp_new_ptr(); - tcg_gen_addi_ptr(t_zn, cpu_env, vec_full_reg_offset(s, a->rn)); - tcg_gen_addi_ptr(t_pg, cpu_env, pred_full_reg_offset(s, a->pg)); + tcg_gen_addi_ptr(t_zn, tcg_env, vec_full_reg_offset(s, a->rn)); + tcg_gen_addi_ptr(t_pg, tcg_env, pred_full_reg_offset(s, a->pg)); fn(temp, t_zn, t_pg, desc); write_fp_dreg(s, a->rd, temp); @@ -1209,7 +1209,7 @@ static bool do_index(DisasContext *s, int esz, int rd, desc = tcg_constant_i32(simd_desc(vsz, vsz, 0)); t_zd = tcg_temp_new_ptr(); - tcg_gen_addi_ptr(t_zd, cpu_env, vec_full_reg_offset(s, rd)); + tcg_gen_addi_ptr(t_zd, tcg_env, vec_full_reg_offset(s, rd)); if (esz == 3) { gen_helper_sve_index_d(t_zd, start, incr, desc); } else { @@ -1379,12 +1379,12 @@ static bool do_pppp_flags(DisasContext *s, arg_rprr_s *a, TCGv_i64 pm = tcg_temp_new_i64(); TCGv_i64 pg = tcg_temp_new_i64(); - tcg_gen_ld_i64(pn, cpu_env, nofs); - tcg_gen_ld_i64(pm, cpu_env, mofs); - tcg_gen_ld_i64(pg, cpu_env, gofs); + tcg_gen_ld_i64(pn, tcg_env, nofs); + tcg_gen_ld_i64(pm, tcg_env, mofs); + tcg_gen_ld_i64(pg, tcg_env, gofs); gvec_op->fni8(pd, pn, pm, pg); - tcg_gen_st_i64(pd, cpu_env, dofs); + tcg_gen_st_i64(pd, tcg_env, dofs); do_predtest1(pd, pg); } else { @@ -1654,8 +1654,8 @@ static bool trans_PTEST(DisasContext *s, arg_PTEST *a) TCGv_i64 pn = tcg_temp_new_i64(); TCGv_i64 pg = tcg_temp_new_i64(); - tcg_gen_ld_i64(pn, cpu_env, nofs); - tcg_gen_ld_i64(pg, cpu_env, gofs); + tcg_gen_ld_i64(pn, tcg_env, nofs); + tcg_gen_ld_i64(pg, tcg_env, gofs); do_predtest1(pn, pg); } else { do_predtest(s, nofs, gofs, words); @@ -1736,7 +1736,7 @@ static bool do_predset(DisasContext *s, int esz, int rd, int pat, bool setflag) t = tcg_temp_new_i64(); if (fullsz <= 64) { tcg_gen_movi_i64(t, lastword); - tcg_gen_st_i64(t, cpu_env, ofs); + tcg_gen_st_i64(t, tcg_env, ofs); goto done; } @@ -1755,17 +1755,17 @@ static bool do_predset(DisasContext *s, int esz, int rd, int pat, bool setflag) tcg_gen_movi_i64(t, word); for (i = 0; i < QEMU_ALIGN_DOWN(setsz, 8); i += 8) { - tcg_gen_st_i64(t, cpu_env, ofs + i); + tcg_gen_st_i64(t, tcg_env, ofs + i); } if (lastword != word) { tcg_gen_movi_i64(t, lastword); - tcg_gen_st_i64(t, cpu_env, ofs + i); + tcg_gen_st_i64(t, tcg_env, ofs + i); i += 8; } if (i < fullsz) { tcg_gen_movi_i64(t, 0); for (; i < fullsz; i += 8) { - tcg_gen_st_i64(t, cpu_env, ofs + i); + tcg_gen_st_i64(t, tcg_env, ofs + i); } } @@ -1822,8 +1822,8 @@ static bool do_pfirst_pnext(DisasContext *s, arg_rr_esz *a, desc = FIELD_DP32(desc, PREDDESC, OPRSZ, pred_full_reg_size(s)); desc = FIELD_DP32(desc, PREDDESC, ESZ, a->esz); - tcg_gen_addi_ptr(t_pd, cpu_env, pred_full_reg_offset(s, a->rd)); - tcg_gen_addi_ptr(t_pg, cpu_env, pred_full_reg_offset(s, a->rn)); + tcg_gen_addi_ptr(t_pd, tcg_env, pred_full_reg_offset(s, a->rd)); + tcg_gen_addi_ptr(t_pg, tcg_env, pred_full_reg_offset(s, a->rn)); t = tcg_temp_new_i32(); gen_fn(t, t_pd, t_pg, tcg_constant_i32(desc)); @@ -1919,8 +1919,8 @@ static void do_sat_addsub_vec(DisasContext *s, int esz, int rd, int rn, dptr = tcg_temp_new_ptr(); nptr = tcg_temp_new_ptr(); - tcg_gen_addi_ptr(dptr, cpu_env, vec_full_reg_offset(s, rd)); - tcg_gen_addi_ptr(nptr, cpu_env, vec_full_reg_offset(s, rn)); + tcg_gen_addi_ptr(dptr, tcg_env, vec_full_reg_offset(s, rd)); + tcg_gen_addi_ptr(nptr, tcg_env, vec_full_reg_offset(s, rn)); desc = tcg_constant_i32(simd_desc(vsz, vsz, 0)); switch (esz) { @@ -2163,9 +2163,9 @@ static void do_cpy_m(DisasContext *s, int esz, int rd, int rn, int pg, TCGv_ptr t_zn = tcg_temp_new_ptr(); TCGv_ptr t_pg = tcg_temp_new_ptr(); - tcg_gen_addi_ptr(t_zd, cpu_env, vec_full_reg_offset(s, rd)); - tcg_gen_addi_ptr(t_zn, cpu_env, vec_full_reg_offset(s, rn)); - tcg_gen_addi_ptr(t_pg, cpu_env, pred_full_reg_offset(s, pg)); + tcg_gen_addi_ptr(t_zd, tcg_env, vec_full_reg_offset(s, rd)); + tcg_gen_addi_ptr(t_zn, tcg_env, vec_full_reg_offset(s, rn)); + tcg_gen_addi_ptr(t_pg, tcg_env, pred_full_reg_offset(s, pg)); fns[esz](t_zd, t_zn, t_pg, val, desc); } @@ -2310,8 +2310,8 @@ static void do_insr_i64(DisasContext *s, arg_rrr_esz *a, TCGv_i64 val) TCGv_ptr t_zd = tcg_temp_new_ptr(); TCGv_ptr t_zn = tcg_temp_new_ptr(); - tcg_gen_addi_ptr(t_zd, cpu_env, vec_full_reg_offset(s, a->rd)); - tcg_gen_addi_ptr(t_zn, cpu_env, vec_full_reg_offset(s, a->rn)); + tcg_gen_addi_ptr(t_zd, tcg_env, vec_full_reg_offset(s, a->rd)); + tcg_gen_addi_ptr(t_zn, tcg_env, vec_full_reg_offset(s, a->rn)); fns[a->esz](t_zd, t_zn, val, desc); } @@ -2323,7 +2323,7 @@ static bool trans_INSR_f(DisasContext *s, arg_rrr_esz *a) } if (sve_access_check(s)) { TCGv_i64 t = tcg_temp_new_i64(); - tcg_gen_ld_i64(t, cpu_env, vec_reg_offset(s, a->rm, 0, MO_64)); + tcg_gen_ld_i64(t, tcg_env, vec_reg_offset(s, a->rm, 0, MO_64)); do_insr_i64(s, a, t); } return true; @@ -2409,9 +2409,9 @@ static bool do_perm_pred3(DisasContext *s, arg_rrr_esz *a, bool high_odd, desc = FIELD_DP32(desc, PREDDESC, ESZ, a->esz); desc = FIELD_DP32(desc, PREDDESC, DATA, high_odd); - tcg_gen_addi_ptr(t_d, cpu_env, pred_full_reg_offset(s, a->rd)); - tcg_gen_addi_ptr(t_n, cpu_env, pred_full_reg_offset(s, a->rn)); - tcg_gen_addi_ptr(t_m, cpu_env, pred_full_reg_offset(s, a->rm)); + tcg_gen_addi_ptr(t_d, tcg_env, pred_full_reg_offset(s, a->rd)); + tcg_gen_addi_ptr(t_n, tcg_env, pred_full_reg_offset(s, a->rn)); + tcg_gen_addi_ptr(t_m, tcg_env, pred_full_reg_offset(s, a->rm)); fn(t_d, t_n, t_m, tcg_constant_i32(desc)); return true; @@ -2429,8 +2429,8 @@ static bool do_perm_pred2(DisasContext *s, arg_rr_esz *a, bool high_odd, TCGv_ptr t_n = tcg_temp_new_ptr(); uint32_t desc = 0; - tcg_gen_addi_ptr(t_d, cpu_env, pred_full_reg_offset(s, a->rd)); - tcg_gen_addi_ptr(t_n, cpu_env, pred_full_reg_offset(s, a->rn)); + tcg_gen_addi_ptr(t_d, tcg_env, pred_full_reg_offset(s, a->rd)); + tcg_gen_addi_ptr(t_n, tcg_env, pred_full_reg_offset(s, a->rn)); desc = FIELD_DP32(desc, PREDDESC, OPRSZ, vsz); desc = FIELD_DP32(desc, PREDDESC, ESZ, a->esz); @@ -2525,7 +2525,7 @@ static void find_last_active(DisasContext *s, TCGv_i32 ret, int esz, int pg) desc = FIELD_DP32(desc, PREDDESC, OPRSZ, pred_full_reg_size(s)); desc = FIELD_DP32(desc, PREDDESC, ESZ, esz); - tcg_gen_addi_ptr(t_p, cpu_env, pred_full_reg_offset(s, pg)); + tcg_gen_addi_ptr(t_p, tcg_env, pred_full_reg_offset(s, pg)); gen_helper_sve_last_active_element(ret, t_p, tcg_constant_i32(desc)); } @@ -2602,7 +2602,7 @@ static TCGv_i64 load_last_active(DisasContext *s, TCGv_i32 last, } #endif tcg_gen_ext_i32_ptr(p, last); - tcg_gen_add_ptr(p, p, cpu_env); + tcg_gen_add_ptr(p, p, tcg_env); return load_esz(p, vec_full_reg_offset(s, rm), esz); } @@ -2674,7 +2674,7 @@ static void do_clast_scalar(DisasContext *s, int esz, int pg, int rm, } /* The conceit here is that while last < 0 indicates not found, after - * adjusting for cpu_env->vfp.zregs[rm], it is still a valid address + * adjusting for tcg_env->vfp.zregs[rm], it is still a valid address * from which we can load garbage. We then discard the garbage with * a conditional move. */ @@ -2690,7 +2690,7 @@ static bool do_clast_fp(DisasContext *s, arg_rpr_esz *a, bool before) if (sve_access_check(s)) { int esz = a->esz; int ofs = vec_reg_offset(s, a->rd, 0, esz); - TCGv_i64 reg = load_esz(cpu_env, ofs, esz); + TCGv_i64 reg = load_esz(tcg_env, ofs, esz); do_clast_scalar(s, esz, a->pg, a->rn, before, reg); write_fp_dreg(s, a->rd, reg); @@ -2794,7 +2794,7 @@ static bool trans_CPY_m_v(DisasContext *s, arg_rpr_esz *a) } if (sve_access_check(s)) { int ofs = vec_reg_offset(s, a->rn, 0, a->esz); - TCGv_i64 t = load_esz(cpu_env, ofs, a->esz); + TCGv_i64 t = load_esz(tcg_env, ofs, a->esz); do_cpy_m(s, a->esz, a->rd, a->rd, a->pg, t); } return true; @@ -2847,10 +2847,10 @@ static bool do_ppzz_flags(DisasContext *s, arg_rprr_esz *a, zm = tcg_temp_new_ptr(); pg = tcg_temp_new_ptr(); - tcg_gen_addi_ptr(pd, cpu_env, pred_full_reg_offset(s, a->rd)); - tcg_gen_addi_ptr(zn, cpu_env, vec_full_reg_offset(s, a->rn)); - tcg_gen_addi_ptr(zm, cpu_env, vec_full_reg_offset(s, a->rm)); - tcg_gen_addi_ptr(pg, cpu_env, pred_full_reg_offset(s, a->pg)); + tcg_gen_addi_ptr(pd, tcg_env, pred_full_reg_offset(s, a->rd)); + tcg_gen_addi_ptr(zn, tcg_env, vec_full_reg_offset(s, a->rn)); + tcg_gen_addi_ptr(zm, tcg_env, vec_full_reg_offset(s, a->rm)); + tcg_gen_addi_ptr(pg, tcg_env, pred_full_reg_offset(s, a->pg)); gen_fn(t, pd, zn, zm, pg, tcg_constant_i32(simd_desc(vsz, vsz, 0))); @@ -2920,9 +2920,9 @@ static bool do_ppzi_flags(DisasContext *s, arg_rpri_esz *a, zn = tcg_temp_new_ptr(); pg = tcg_temp_new_ptr(); - tcg_gen_addi_ptr(pd, cpu_env, pred_full_reg_offset(s, a->rd)); - tcg_gen_addi_ptr(zn, cpu_env, vec_full_reg_offset(s, a->rn)); - tcg_gen_addi_ptr(pg, cpu_env, pred_full_reg_offset(s, a->pg)); + tcg_gen_addi_ptr(pd, tcg_env, pred_full_reg_offset(s, a->rd)); + tcg_gen_addi_ptr(zn, tcg_env, vec_full_reg_offset(s, a->rn)); + tcg_gen_addi_ptr(pg, tcg_env, pred_full_reg_offset(s, a->pg)); gen_fn(t, pd, zn, pg, tcg_constant_i32(simd_desc(vsz, vsz, a->imm))); @@ -2971,10 +2971,10 @@ static bool do_brk3(DisasContext *s, arg_rprr_s *a, TCGv_ptr g = tcg_temp_new_ptr(); TCGv_i32 desc = tcg_constant_i32(FIELD_DP32(0, PREDDESC, OPRSZ, vsz)); - tcg_gen_addi_ptr(d, cpu_env, pred_full_reg_offset(s, a->rd)); - tcg_gen_addi_ptr(n, cpu_env, pred_full_reg_offset(s, a->rn)); - tcg_gen_addi_ptr(m, cpu_env, pred_full_reg_offset(s, a->rm)); - tcg_gen_addi_ptr(g, cpu_env, pred_full_reg_offset(s, a->pg)); + tcg_gen_addi_ptr(d, tcg_env, pred_full_reg_offset(s, a->rd)); + tcg_gen_addi_ptr(n, tcg_env, pred_full_reg_offset(s, a->rn)); + tcg_gen_addi_ptr(m, tcg_env, pred_full_reg_offset(s, a->rm)); + tcg_gen_addi_ptr(g, tcg_env, pred_full_reg_offset(s, a->pg)); if (a->s) { TCGv_i32 t = tcg_temp_new_i32(); @@ -3001,9 +3001,9 @@ static bool do_brk2(DisasContext *s, arg_rpr_s *a, TCGv_ptr g = tcg_temp_new_ptr(); TCGv_i32 desc = tcg_constant_i32(FIELD_DP32(0, PREDDESC, OPRSZ, vsz)); - tcg_gen_addi_ptr(d, cpu_env, pred_full_reg_offset(s, a->rd)); - tcg_gen_addi_ptr(n, cpu_env, pred_full_reg_offset(s, a->rn)); - tcg_gen_addi_ptr(g, cpu_env, pred_full_reg_offset(s, a->pg)); + tcg_gen_addi_ptr(d, tcg_env, pred_full_reg_offset(s, a->rd)); + tcg_gen_addi_ptr(n, tcg_env, pred_full_reg_offset(s, a->rn)); + tcg_gen_addi_ptr(g, tcg_env, pred_full_reg_offset(s, a->pg)); if (a->s) { TCGv_i32 t = tcg_temp_new_i32(); @@ -3044,10 +3044,10 @@ static void do_cntp(DisasContext *s, TCGv_i64 val, int esz, int pn, int pg) if (psz <= 8) { uint64_t psz_mask; - tcg_gen_ld_i64(val, cpu_env, pred_full_reg_offset(s, pn)); + tcg_gen_ld_i64(val, tcg_env, pred_full_reg_offset(s, pn)); if (pn != pg) { TCGv_i64 g = tcg_temp_new_i64(); - tcg_gen_ld_i64(g, cpu_env, pred_full_reg_offset(s, pg)); + tcg_gen_ld_i64(g, tcg_env, pred_full_reg_offset(s, pg)); tcg_gen_and_i64(val, val, g); } @@ -3066,8 +3066,8 @@ static void do_cntp(DisasContext *s, TCGv_i64 val, int esz, int pn, int pg) desc = FIELD_DP32(desc, PREDDESC, OPRSZ, psz); desc = FIELD_DP32(desc, PREDDESC, ESZ, esz); - tcg_gen_addi_ptr(t_pn, cpu_env, pred_full_reg_offset(s, pn)); - tcg_gen_addi_ptr(t_pg, cpu_env, pred_full_reg_offset(s, pg)); + tcg_gen_addi_ptr(t_pn, tcg_env, pred_full_reg_offset(s, pn)); + tcg_gen_addi_ptr(t_pg, tcg_env, pred_full_reg_offset(s, pg)); gen_helper_sve_cntp(val, t_pn, t_pg, tcg_constant_i32(desc)); } @@ -3291,7 +3291,7 @@ static bool trans_WHILE(DisasContext *s, arg_WHILE *a) desc = FIELD_DP32(desc, PREDDESC, ESZ, a->esz); ptr = tcg_temp_new_ptr(); - tcg_gen_addi_ptr(ptr, cpu_env, pred_full_reg_offset(s, a->rd)); + tcg_gen_addi_ptr(ptr, tcg_env, pred_full_reg_offset(s, a->rd)); if (a->lt) { gen_helper_sve_whilel(t2, ptr, t2, tcg_constant_i32(desc)); @@ -3354,7 +3354,7 @@ static bool trans_WHILE_ptr(DisasContext *s, arg_WHILE_ptr *a) desc = FIELD_DP32(desc, PREDDESC, ESZ, a->esz); ptr = tcg_temp_new_ptr(); - tcg_gen_addi_ptr(ptr, cpu_env, pred_full_reg_offset(s, a->rd)); + tcg_gen_addi_ptr(ptr, tcg_env, pred_full_reg_offset(s, a->rd)); gen_helper_sve_whilel(t2, ptr, t2, tcg_constant_i32(desc)); do_pred_flags(t2); @@ -3684,8 +3684,8 @@ static bool do_reduce(DisasContext *s, arg_rpr_esz *a, t_zn = tcg_temp_new_ptr(); t_pg = tcg_temp_new_ptr(); - tcg_gen_addi_ptr(t_zn, cpu_env, vec_full_reg_offset(s, a->rn)); - tcg_gen_addi_ptr(t_pg, cpu_env, pred_full_reg_offset(s, a->pg)); + tcg_gen_addi_ptr(t_zn, tcg_env, vec_full_reg_offset(s, a->rn)); + tcg_gen_addi_ptr(t_pg, tcg_env, pred_full_reg_offset(s, a->pg)); status = fpstatus_ptr(a->esz == MO_16 ? FPST_FPCR_F16 : FPST_FPCR); fn(temp, t_zn, t_pg, status, t_desc); @@ -3802,11 +3802,11 @@ static bool trans_FADDA(DisasContext *s, arg_rprr_esz *a) return true; } - t_val = load_esz(cpu_env, vec_reg_offset(s, a->rn, 0, a->esz), a->esz); + t_val = load_esz(tcg_env, vec_reg_offset(s, a->rn, 0, a->esz), a->esz); t_rm = tcg_temp_new_ptr(); t_pg = tcg_temp_new_ptr(); - tcg_gen_addi_ptr(t_rm, cpu_env, vec_full_reg_offset(s, a->rm)); - tcg_gen_addi_ptr(t_pg, cpu_env, pred_full_reg_offset(s, a->pg)); + tcg_gen_addi_ptr(t_rm, tcg_env, vec_full_reg_offset(s, a->rm)); + tcg_gen_addi_ptr(t_pg, tcg_env, pred_full_reg_offset(s, a->pg)); t_fpst = fpstatus_ptr(a->esz == MO_16 ? FPST_FPCR_F16 : FPST_FPCR); t_desc = tcg_constant_i32(simd_desc(vsz, vsz, 0)); @@ -3878,9 +3878,9 @@ static void do_fp_scalar(DisasContext *s, int zd, int zn, int pg, bool is_fp16, t_zd = tcg_temp_new_ptr(); t_zn = tcg_temp_new_ptr(); t_pg = tcg_temp_new_ptr(); - tcg_gen_addi_ptr(t_zd, cpu_env, vec_full_reg_offset(s, zd)); - tcg_gen_addi_ptr(t_zn, cpu_env, vec_full_reg_offset(s, zn)); - tcg_gen_addi_ptr(t_pg, cpu_env, pred_full_reg_offset(s, pg)); + tcg_gen_addi_ptr(t_zd, tcg_env, vec_full_reg_offset(s, zd)); + tcg_gen_addi_ptr(t_zn, tcg_env, vec_full_reg_offset(s, zn)); + tcg_gen_addi_ptr(t_pg, tcg_env, pred_full_reg_offset(s, pg)); status = fpstatus_ptr(is_fp16 ? FPST_FPCR_F16 : FPST_FPCR); desc = tcg_constant_i32(simd_desc(vsz, vsz, 0)); @@ -4228,7 +4228,7 @@ void gen_sve_ldr(DisasContext *s, TCGv_ptr base, int vofs, /* * Predicate register loads can be any multiple of 2. - * Note that we still store the entire 64-bit unit into cpu_env. + * Note that we still store the entire 64-bit unit into tcg_env. */ if (len_remain >= 8) { t0 = tcg_temp_new_i64(); @@ -4370,7 +4370,7 @@ static bool trans_LDR_zri(DisasContext *s, arg_rri *a) if (sve_access_check(s)) { int size = vec_full_reg_size(s); int off = vec_full_reg_offset(s, a->rd); - gen_sve_ldr(s, cpu_env, off, size, a->rn, a->imm * size); + gen_sve_ldr(s, tcg_env, off, size, a->rn, a->imm * size); } return true; } @@ -4383,7 +4383,7 @@ static bool trans_LDR_pri(DisasContext *s, arg_rri *a) if (sve_access_check(s)) { int size = pred_full_reg_size(s); int off = pred_full_reg_offset(s, a->rd); - gen_sve_ldr(s, cpu_env, off, size, a->rn, a->imm * size); + gen_sve_ldr(s, tcg_env, off, size, a->rn, a->imm * size); } return true; } @@ -4396,7 +4396,7 @@ static bool trans_STR_zri(DisasContext *s, arg_rri *a) if (sve_access_check(s)) { int size = vec_full_reg_size(s); int off = vec_full_reg_offset(s, a->rd); - gen_sve_str(s, cpu_env, off, size, a->rn, a->imm * size); + gen_sve_str(s, tcg_env, off, size, a->rn, a->imm * size); } return true; } @@ -4409,7 +4409,7 @@ static bool trans_STR_pri(DisasContext *s, arg_rri *a) if (sve_access_check(s)) { int size = pred_full_reg_size(s); int off = pred_full_reg_offset(s, a->rd); - gen_sve_str(s, cpu_env, off, size, a->rn, a->imm * size); + gen_sve_str(s, tcg_env, off, size, a->rn, a->imm * size); } return true; } @@ -4465,8 +4465,8 @@ static void do_mem_zpa(DisasContext *s, int zt, int pg, TCGv_i64 addr, desc = simd_desc(vsz, vsz, zt | desc); t_pg = tcg_temp_new_ptr(); - tcg_gen_addi_ptr(t_pg, cpu_env, pred_full_reg_offset(s, pg)); - fn(cpu_env, t_pg, addr, tcg_constant_i32(desc)); + tcg_gen_addi_ptr(t_pg, tcg_env, pred_full_reg_offset(s, pg)); + fn(tcg_env, t_pg, addr, tcg_constant_i32(desc)); } /* Indexed by [mte][be][dtype][nreg] */ @@ -4860,18 +4860,18 @@ static void do_ldrq(DisasContext *s, int zt, int pg, TCGv_i64 addr, int dtype) #if HOST_BIG_ENDIAN poff += 6; #endif - tcg_gen_ld16u_i64(tmp, cpu_env, poff); + tcg_gen_ld16u_i64(tmp, tcg_env, poff); poff = offsetof(CPUARMState, vfp.preg_tmp); - tcg_gen_st_i64(tmp, cpu_env, poff); + tcg_gen_st_i64(tmp, tcg_env, poff); } t_pg = tcg_temp_new_ptr(); - tcg_gen_addi_ptr(t_pg, cpu_env, poff); + tcg_gen_addi_ptr(t_pg, tcg_env, poff); gen_helper_gvec_mem *fn = ldr_fns[s->mte_active[0]][s->be_data == MO_BE][dtype][0]; - fn(cpu_env, t_pg, addr, tcg_constant_i32(simd_desc(16, 16, zt))); + fn(tcg_env, t_pg, addr, tcg_constant_i32(simd_desc(16, 16, zt))); /* Replicate that first quadword. */ if (vsz > 16) { @@ -4939,18 +4939,18 @@ static void do_ldro(DisasContext *s, int zt, int pg, TCGv_i64 addr, int dtype) #if HOST_BIG_ENDIAN poff += 4; #endif - tcg_gen_ld32u_i64(tmp, cpu_env, poff); + tcg_gen_ld32u_i64(tmp, tcg_env, poff); poff = offsetof(CPUARMState, vfp.preg_tmp); - tcg_gen_st_i64(tmp, cpu_env, poff); + tcg_gen_st_i64(tmp, tcg_env, poff); } t_pg = tcg_temp_new_ptr(); - tcg_gen_addi_ptr(t_pg, cpu_env, poff); + tcg_gen_addi_ptr(t_pg, tcg_env, poff); gen_helper_gvec_mem *fn = ldr_fns[s->mte_active[0]][s->be_data == MO_BE][dtype][0]; - fn(cpu_env, t_pg, addr, tcg_constant_i32(simd_desc(32, 32, zt))); + fn(tcg_env, t_pg, addr, tcg_constant_i32(simd_desc(32, 32, zt))); /* * Replicate that first octaword. @@ -5027,7 +5027,7 @@ static bool trans_LD1R_zpri(DisasContext *s, arg_rpri_load *a) */ uint64_t psz_mask = MAKE_64BIT_MASK(0, psz * 8); temp = tcg_temp_new_i64(); - tcg_gen_ld_i64(temp, cpu_env, pred_full_reg_offset(s, a->pg)); + tcg_gen_ld_i64(temp, tcg_env, pred_full_reg_offset(s, a->pg)); tcg_gen_andi_i64(temp, temp, pred_esz_masks[esz] & psz_mask); tcg_gen_brcondi_i64(TCG_COND_EQ, temp, 0, over); } else { @@ -5238,10 +5238,10 @@ static void do_mem_zpz(DisasContext *s, int zt, int pg, int zm, } desc = simd_desc(vsz, vsz, desc | scale); - tcg_gen_addi_ptr(t_pg, cpu_env, pred_full_reg_offset(s, pg)); - tcg_gen_addi_ptr(t_zm, cpu_env, vec_full_reg_offset(s, zm)); - tcg_gen_addi_ptr(t_zt, cpu_env, vec_full_reg_offset(s, zt)); - fn(cpu_env, t_zt, t_pg, t_zm, scalar, tcg_constant_i32(desc)); + tcg_gen_addi_ptr(t_pg, tcg_env, pred_full_reg_offset(s, pg)); + tcg_gen_addi_ptr(t_zm, tcg_env, vec_full_reg_offset(s, zm)); + tcg_gen_addi_ptr(t_zt, tcg_env, vec_full_reg_offset(s, zt)); + fn(tcg_env, t_zt, t_pg, t_zm, scalar, tcg_constant_i32(desc)); } /* Indexed by [mte][be][ff][xs][u][msz]. */ @@ -7197,7 +7197,7 @@ static bool do_FMLAL_zzzw(DisasContext *s, arg_rrrr_esz *a, bool sub, bool sel) { return gen_gvec_ptr_zzzz(s, gen_helper_sve2_fmlal_zzzw_s, a->rd, a->rn, a->rm, a->ra, - (sel << 1) | sub, cpu_env); + (sel << 1) | sub, tcg_env); } TRANS_FEAT(FMLALB_zzzw, aa64_sve2, do_FMLAL_zzzw, a, false, false) @@ -7209,7 +7209,7 @@ static bool do_FMLAL_zzxw(DisasContext *s, arg_rrxr_esz *a, bool sub, bool sel) { return gen_gvec_ptr_zzzz(s, gen_helper_sve2_fmlal_zzxw_s, a->rd, a->rn, a->rm, a->ra, - (a->index << 2) | (sel << 1) | sub, cpu_env); + (a->index << 2) | (sel << 1) | sub, tcg_env); } TRANS_FEAT(FMLALB_zzxw, aa64_sve2, do_FMLAL_zzxw, a, false, false) @@ -7289,7 +7289,7 @@ static bool trans_PSEL(DisasContext *s, arg_psel *a) /* Load the predicate word. */ tcg_gen_trunc_i64_ptr(ptr, didx); - tcg_gen_add_ptr(ptr, ptr, cpu_env); + tcg_gen_add_ptr(ptr, ptr, tcg_env); tcg_gen_ld8u_i64(tmp, ptr, pred_full_reg_offset(s, a->pm)); /* Extract the predicate bit and replicate to MO_64. */ diff --git a/target/arm/tcg/translate-vfp.c b/target/arm/tcg/translate-vfp.c index d3e89fda91..b9af03b7c3 100644 --- a/target/arm/tcg/translate-vfp.c +++ b/target/arm/tcg/translate-vfp.c @@ -30,22 +30,22 @@ static inline void vfp_load_reg64(TCGv_i64 var, int reg) { - tcg_gen_ld_i64(var, cpu_env, vfp_reg_offset(true, reg)); + tcg_gen_ld_i64(var, tcg_env, vfp_reg_offset(true, reg)); } static inline void vfp_store_reg64(TCGv_i64 var, int reg) { - tcg_gen_st_i64(var, cpu_env, vfp_reg_offset(true, reg)); + tcg_gen_st_i64(var, tcg_env, vfp_reg_offset(true, reg)); } static inline void vfp_load_reg32(TCGv_i32 var, int reg) { - tcg_gen_ld_i32(var, cpu_env, vfp_reg_offset(false, reg)); + tcg_gen_ld_i32(var, tcg_env, vfp_reg_offset(false, reg)); } static inline void vfp_store_reg32(TCGv_i32 var, int reg) { - tcg_gen_st_i32(var, cpu_env, vfp_reg_offset(false, reg)); + tcg_gen_st_i32(var, tcg_env, vfp_reg_offset(false, reg)); } /* @@ -116,7 +116,7 @@ static void gen_preserve_fp_state(DisasContext *s, bool skip_context_update) if (translator_io_start(&s->base)) { s->base.is_jmp = DISAS_UPDATE_EXIT; } - gen_helper_v7m_preserve_fp_state(cpu_env); + gen_helper_v7m_preserve_fp_state(tcg_env); /* * If the preserve_fp_state helper doesn't throw an exception * then it will clear LSPACT; we don't need to repeat this for @@ -172,7 +172,7 @@ static void gen_update_fp_context(DisasContext *s) uint32_t bits = R_V7M_CONTROL_FPCA_MASK; fpscr = load_cpu_field(v7m.fpdscr[s->v8m_secure]); - gen_helper_vfp_set_fpscr(cpu_env, fpscr); + gen_helper_vfp_set_fpscr(tcg_env, fpscr); if (dc_isar_feature(aa32_mve, s)) { store_cpu_field(tcg_constant_i32(0), v7m.vpr); } @@ -815,7 +815,7 @@ static bool trans_VMSR_VMRS(DisasContext *s, arg_VMSR_VMRS *a) if (s->current_el == 1) { gen_set_condexec(s); gen_update_pc(s, 0); - gen_helper_check_hcr_el2_trap(cpu_env, + gen_helper_check_hcr_el2_trap(tcg_env, tcg_constant_i32(a->rt), tcg_constant_i32(a->reg)); } @@ -831,7 +831,7 @@ static bool trans_VMSR_VMRS(DisasContext *s, arg_VMSR_VMRS *a) tcg_gen_andi_i32(tmp, tmp, FPCR_NZCV_MASK); } else { tmp = tcg_temp_new_i32(); - gen_helper_vfp_get_fpscr(tmp, cpu_env); + gen_helper_vfp_get_fpscr(tmp, tcg_env); } break; default: @@ -855,7 +855,7 @@ static bool trans_VMSR_VMRS(DisasContext *s, arg_VMSR_VMRS *a) break; case ARM_VFP_FPSCR: tmp = load_reg(s, a->rt); - gen_helper_vfp_set_fpscr(cpu_env, tmp); + gen_helper_vfp_set_fpscr(tcg_env, tmp); gen_lookup_tb(s); break; case ARM_VFP_FPEXC: @@ -1169,7 +1169,7 @@ static bool trans_VLDM_VSTM_sp(DisasContext *s, arg_VLDM_VSTM_sp *a) * value is above, it is UNKNOWN whether the limit check * triggers; we choose to trigger. */ - gen_helper_v8m_stackcheck(cpu_env, addr); + gen_helper_v8m_stackcheck(tcg_env, addr); } offset = 4; @@ -1252,7 +1252,7 @@ static bool trans_VLDM_VSTM_dp(DisasContext *s, arg_VLDM_VSTM_dp *a) * value is above, it is UNKNOWN whether the limit check * triggers; we choose to trigger. */ - gen_helper_v8m_stackcheck(cpu_env, addr); + gen_helper_v8m_stackcheck(tcg_env, addr); } offset = 8; @@ -2419,17 +2419,17 @@ DO_VFP_2OP(VNEG, dp, gen_helper_vfp_negd, aa32_fpdp_v2) static void gen_VSQRT_hp(TCGv_i32 vd, TCGv_i32 vm) { - gen_helper_vfp_sqrth(vd, vm, cpu_env); + gen_helper_vfp_sqrth(vd, vm, tcg_env); } static void gen_VSQRT_sp(TCGv_i32 vd, TCGv_i32 vm) { - gen_helper_vfp_sqrts(vd, vm, cpu_env); + gen_helper_vfp_sqrts(vd, vm, tcg_env); } static void gen_VSQRT_dp(TCGv_i64 vd, TCGv_i64 vm) { - gen_helper_vfp_sqrtd(vd, vm, cpu_env); + gen_helper_vfp_sqrtd(vd, vm, tcg_env); } DO_VFP_2OP(VSQRT, hp, gen_VSQRT_hp, aa32_fp16_arith) @@ -2464,9 +2464,9 @@ static bool trans_VCMP_hp(DisasContext *s, arg_VCMP_sp *a) } if (a->e) { - gen_helper_vfp_cmpeh(vd, vm, cpu_env); + gen_helper_vfp_cmpeh(vd, vm, tcg_env); } else { - gen_helper_vfp_cmph(vd, vm, cpu_env); + gen_helper_vfp_cmph(vd, vm, tcg_env); } return true; } @@ -2499,9 +2499,9 @@ static bool trans_VCMP_sp(DisasContext *s, arg_VCMP_sp *a) } if (a->e) { - gen_helper_vfp_cmpes(vd, vm, cpu_env); + gen_helper_vfp_cmpes(vd, vm, tcg_env); } else { - gen_helper_vfp_cmps(vd, vm, cpu_env); + gen_helper_vfp_cmps(vd, vm, tcg_env); } return true; } @@ -2539,9 +2539,9 @@ static bool trans_VCMP_dp(DisasContext *s, arg_VCMP_dp *a) } if (a->e) { - gen_helper_vfp_cmped(vd, vm, cpu_env); + gen_helper_vfp_cmped(vd, vm, tcg_env); } else { - gen_helper_vfp_cmpd(vd, vm, cpu_env); + gen_helper_vfp_cmpd(vd, vm, tcg_env); } return true; } @@ -2564,7 +2564,7 @@ static bool trans_VCVT_f32_f16(DisasContext *s, arg_VCVT_f32_f16 *a) ahp_mode = get_ahp_flag(); tmp = tcg_temp_new_i32(); /* The T bit tells us if we want the low or high 16 bits of Vm */ - tcg_gen_ld16u_i32(tmp, cpu_env, vfp_f16_offset(a->vm, a->t)); + tcg_gen_ld16u_i32(tmp, tcg_env, vfp_f16_offset(a->vm, a->t)); gen_helper_vfp_fcvt_f16_to_f32(tmp, tmp, fpst, ahp_mode); vfp_store_reg32(tmp, a->vd); return true; @@ -2598,7 +2598,7 @@ static bool trans_VCVT_f64_f16(DisasContext *s, arg_VCVT_f64_f16 *a) ahp_mode = get_ahp_flag(); tmp = tcg_temp_new_i32(); /* The T bit tells us if we want the low or high 16 bits of Vm */ - tcg_gen_ld16u_i32(tmp, cpu_env, vfp_f16_offset(a->vm, a->t)); + tcg_gen_ld16u_i32(tmp, tcg_env, vfp_f16_offset(a->vm, a->t)); vd = tcg_temp_new_i64(); gen_helper_vfp_fcvt_f16_to_f64(vd, tmp, fpst, ahp_mode); vfp_store_reg64(vd, a->vd); @@ -2623,7 +2623,7 @@ static bool trans_VCVT_b16_f32(DisasContext *s, arg_VCVT_b16_f32 *a) vfp_load_reg32(tmp, a->vm); gen_helper_bfcvt(tmp, tmp, fpst); - tcg_gen_st16_i32(tmp, cpu_env, vfp_f16_offset(a->vd, a->t)); + tcg_gen_st16_i32(tmp, tcg_env, vfp_f16_offset(a->vd, a->t)); return true; } @@ -2647,7 +2647,7 @@ static bool trans_VCVT_f16_f32(DisasContext *s, arg_VCVT_f16_f32 *a) vfp_load_reg32(tmp, a->vm); gen_helper_vfp_fcvt_f32_to_f16(tmp, tmp, fpst, ahp_mode); - tcg_gen_st16_i32(tmp, cpu_env, vfp_f16_offset(a->vd, a->t)); + tcg_gen_st16_i32(tmp, tcg_env, vfp_f16_offset(a->vd, a->t)); return true; } @@ -2682,7 +2682,7 @@ static bool trans_VCVT_f16_f64(DisasContext *s, arg_VCVT_f16_f64 *a) vfp_load_reg64(vm, a->vm); gen_helper_vfp_fcvt_f64_to_f16(tmp, vm, fpst, ahp_mode); - tcg_gen_st16_i32(tmp, cpu_env, vfp_f16_offset(a->vd, a->t)); + tcg_gen_st16_i32(tmp, tcg_env, vfp_f16_offset(a->vd, a->t)); return true; } @@ -2932,7 +2932,7 @@ static bool trans_VCVT_sp(DisasContext *s, arg_VCVT_sp *a) vm = tcg_temp_new_i32(); vd = tcg_temp_new_i64(); vfp_load_reg32(vm, a->vm); - gen_helper_vfp_fcvtds(vd, vm, cpu_env); + gen_helper_vfp_fcvtds(vd, vm, tcg_env); vfp_store_reg64(vd, a->vd); return true; } @@ -2958,7 +2958,7 @@ static bool trans_VCVT_dp(DisasContext *s, arg_VCVT_dp *a) vd = tcg_temp_new_i32(); vm = tcg_temp_new_i64(); vfp_load_reg64(vm, a->vm); - gen_helper_vfp_fcvtsd(vd, vm, cpu_env); + gen_helper_vfp_fcvtsd(vd, vm, tcg_env); vfp_store_reg32(vd, a->vd); return true; } @@ -3076,7 +3076,7 @@ static bool trans_VJCVT(DisasContext *s, arg_VJCVT *a) vm = tcg_temp_new_i64(); vd = tcg_temp_new_i32(); vfp_load_reg64(vm, a->vm); - gen_helper_vjcvt(vd, vm, cpu_env); + gen_helper_vjcvt(vd, vm, tcg_env); vfp_store_reg32(vd, a->vd); return true; } diff --git a/target/arm/tcg/translate.c b/target/arm/tcg/translate.c index d83a0e772c..2524d8f3fb 100644 --- a/target/arm/tcg/translate.c +++ b/target/arm/tcg/translate.c @@ -63,18 +63,18 @@ void arm_translate_init(void) int i; for (i = 0; i < 16; i++) { - cpu_R[i] = tcg_global_mem_new_i32(cpu_env, + cpu_R[i] = tcg_global_mem_new_i32(tcg_env, offsetof(CPUARMState, regs[i]), regnames[i]); } - cpu_CF = tcg_global_mem_new_i32(cpu_env, offsetof(CPUARMState, CF), "CF"); - cpu_NF = tcg_global_mem_new_i32(cpu_env, offsetof(CPUARMState, NF), "NF"); - cpu_VF = tcg_global_mem_new_i32(cpu_env, offsetof(CPUARMState, VF), "VF"); - cpu_ZF = tcg_global_mem_new_i32(cpu_env, offsetof(CPUARMState, ZF), "ZF"); + cpu_CF = tcg_global_mem_new_i32(tcg_env, offsetof(CPUARMState, CF), "CF"); + cpu_NF = tcg_global_mem_new_i32(tcg_env, offsetof(CPUARMState, NF), "NF"); + cpu_VF = tcg_global_mem_new_i32(tcg_env, offsetof(CPUARMState, VF), "VF"); + cpu_ZF = tcg_global_mem_new_i32(tcg_env, offsetof(CPUARMState, ZF), "ZF"); - cpu_exclusive_addr = tcg_global_mem_new_i64(cpu_env, + cpu_exclusive_addr = tcg_global_mem_new_i64(tcg_env, offsetof(CPUARMState, exclusive_addr), "exclusive_addr"); - cpu_exclusive_val = tcg_global_mem_new_i64(cpu_env, + cpu_exclusive_val = tcg_global_mem_new_i64(tcg_env, offsetof(CPUARMState, exclusive_val), "exclusive_val"); a64_translate_init(); @@ -179,10 +179,10 @@ void store_cpu_offset(TCGv_i32 var, int offset, int size) { switch (size) { case 1: - tcg_gen_st8_i32(var, cpu_env, offset); + tcg_gen_st8_i32(var, tcg_env, offset); break; case 4: - tcg_gen_st_i32(var, cpu_env, offset); + tcg_gen_st_i32(var, tcg_env, offset); break; default: g_assert_not_reached(); @@ -329,7 +329,7 @@ static void store_sp_checked(DisasContext *s, TCGv_i32 var) { #ifndef CONFIG_USER_ONLY if (s->v8m_stackcheck) { - gen_helper_v8m_stackcheck(cpu_env, var); + gen_helper_v8m_stackcheck(tcg_env, var); } #endif store_reg(s, 13, var); @@ -346,7 +346,7 @@ static void store_sp_checked(DisasContext *s, TCGv_i32 var) void gen_set_cpsr(TCGv_i32 var, uint32_t mask) { - gen_helper_cpsr_write(cpu_env, var, tcg_constant_i32(mask)); + gen_helper_cpsr_write(tcg_env, var, tcg_constant_i32(mask)); } static void gen_rebuild_hflags(DisasContext *s, bool new_el) @@ -355,16 +355,16 @@ static void gen_rebuild_hflags(DisasContext *s, bool new_el) if (new_el) { if (m_profile) { - gen_helper_rebuild_hflags_m32_newel(cpu_env); + gen_helper_rebuild_hflags_m32_newel(tcg_env); } else { - gen_helper_rebuild_hflags_a32_newel(cpu_env); + gen_helper_rebuild_hflags_a32_newel(tcg_env); } } else { TCGv_i32 tcg_el = tcg_constant_i32(s->current_el); if (m_profile) { - gen_helper_rebuild_hflags_m32(cpu_env, tcg_el); + gen_helper_rebuild_hflags_m32(tcg_env, tcg_el); } else { - gen_helper_rebuild_hflags_a32(cpu_env, tcg_el); + gen_helper_rebuild_hflags_a32(tcg_env, tcg_el); } } } @@ -372,7 +372,7 @@ static void gen_rebuild_hflags(DisasContext *s, bool new_el) static void gen_exception_internal(int excp) { assert(excp_is_internal(excp)); - gen_helper_exception_internal(cpu_env, tcg_constant_i32(excp)); + gen_helper_exception_internal(tcg_env, tcg_constant_i32(excp)); } static void gen_singlestep_exception(DisasContext *s) @@ -617,10 +617,10 @@ static inline void gen_arm_shift_reg(TCGv_i32 var, int shiftop, { if (flags) { switch (shiftop) { - case 0: gen_helper_shl_cc(var, cpu_env, var, shift); break; - case 1: gen_helper_shr_cc(var, cpu_env, var, shift); break; - case 2: gen_helper_sar_cc(var, cpu_env, var, shift); break; - case 3: gen_helper_ror_cc(var, cpu_env, var, shift); break; + case 0: gen_helper_shl_cc(var, tcg_env, var, shift); break; + case 1: gen_helper_shr_cc(var, tcg_env, var, shift); break; + case 2: gen_helper_sar_cc(var, tcg_env, var, shift); break; + case 3: gen_helper_ror_cc(var, tcg_env, var, shift); break; } } else { switch (shiftop) { @@ -849,7 +849,7 @@ static inline void gen_bxns(DisasContext *s, int rm) * is correct in the non-UNPREDICTABLE cases, and we can choose * "zeroes the IT bits" as our UNPREDICTABLE behaviour otherwise. */ - gen_helper_v7m_bxns(cpu_env, var); + gen_helper_v7m_bxns(tcg_env, var); s->base.is_jmp = DISAS_EXIT; } @@ -862,7 +862,7 @@ static inline void gen_blxns(DisasContext *s, int rm) * The blxns helper may throw an exception. */ gen_update_pc(s, curr_insn_len(s)); - gen_helper_v7m_blxns(cpu_env, var); + gen_helper_v7m_blxns(tcg_env, var); s->base.is_jmp = DISAS_EXIT; } @@ -1024,7 +1024,7 @@ static inline void gen_hvc(DisasContext *s, int imm16) * the insn really executes). */ gen_update_pc(s, 0); - gen_helper_pre_hvc(cpu_env); + gen_helper_pre_hvc(tcg_env); /* Otherwise we will treat this as a real exception which * happens after execution of the insn. (The distinction matters * for the PC value reported to the exception handler and also @@ -1041,7 +1041,7 @@ static inline void gen_smc(DisasContext *s) * the insn executes. */ gen_update_pc(s, 0); - gen_helper_pre_smc(cpu_env, tcg_constant_i32(syn_aa32_smc())); + gen_helper_pre_smc(tcg_env, tcg_constant_i32(syn_aa32_smc())); gen_update_pc(s, curr_insn_len(s)); s->base.is_jmp = DISAS_SMC; } @@ -1056,7 +1056,7 @@ static void gen_exception_internal_insn(DisasContext *s, int excp) static void gen_exception_el_v(int excp, uint32_t syndrome, TCGv_i32 tcg_el) { - gen_helper_exception_with_syndrome_el(cpu_env, tcg_constant_i32(excp), + gen_helper_exception_with_syndrome_el(tcg_env, tcg_constant_i32(excp), tcg_constant_i32(syndrome), tcg_el); } @@ -1067,7 +1067,7 @@ static void gen_exception_el(int excp, uint32_t syndrome, uint32_t target_el) static void gen_exception(int excp, uint32_t syndrome) { - gen_helper_exception_with_syndrome(cpu_env, tcg_constant_i32(excp), + gen_helper_exception_with_syndrome(tcg_env, tcg_constant_i32(excp), tcg_constant_i32(syndrome)); } @@ -1108,7 +1108,7 @@ static void gen_exception_bkpt_insn(DisasContext *s, uint32_t syn) { gen_set_condexec(s); gen_update_pc(s, 0); - gen_helper_exception_bkpt_insn(cpu_env, tcg_constant_i32(syn)); + gen_helper_exception_bkpt_insn(tcg_env, tcg_constant_i32(syn)); s->base.is_jmp = DISAS_NORETURN; } @@ -1192,20 +1192,20 @@ void read_neon_element32(TCGv_i32 dest, int reg, int ele, MemOp memop) switch (memop) { case MO_SB: - tcg_gen_ld8s_i32(dest, cpu_env, off); + tcg_gen_ld8s_i32(dest, tcg_env, off); break; case MO_UB: - tcg_gen_ld8u_i32(dest, cpu_env, off); + tcg_gen_ld8u_i32(dest, tcg_env, off); break; case MO_SW: - tcg_gen_ld16s_i32(dest, cpu_env, off); + tcg_gen_ld16s_i32(dest, tcg_env, off); break; case MO_UW: - tcg_gen_ld16u_i32(dest, cpu_env, off); + tcg_gen_ld16u_i32(dest, tcg_env, off); break; case MO_UL: case MO_SL: - tcg_gen_ld_i32(dest, cpu_env, off); + tcg_gen_ld_i32(dest, tcg_env, off); break; default: g_assert_not_reached(); @@ -1218,13 +1218,13 @@ void read_neon_element64(TCGv_i64 dest, int reg, int ele, MemOp memop) switch (memop) { case MO_SL: - tcg_gen_ld32s_i64(dest, cpu_env, off); + tcg_gen_ld32s_i64(dest, tcg_env, off); break; case MO_UL: - tcg_gen_ld32u_i64(dest, cpu_env, off); + tcg_gen_ld32u_i64(dest, tcg_env, off); break; case MO_UQ: - tcg_gen_ld_i64(dest, cpu_env, off); + tcg_gen_ld_i64(dest, tcg_env, off); break; default: g_assert_not_reached(); @@ -1237,13 +1237,13 @@ void write_neon_element32(TCGv_i32 src, int reg, int ele, MemOp memop) switch (memop) { case MO_8: - tcg_gen_st8_i32(src, cpu_env, off); + tcg_gen_st8_i32(src, tcg_env, off); break; case MO_16: - tcg_gen_st16_i32(src, cpu_env, off); + tcg_gen_st16_i32(src, tcg_env, off); break; case MO_32: - tcg_gen_st_i32(src, cpu_env, off); + tcg_gen_st_i32(src, tcg_env, off); break; default: g_assert_not_reached(); @@ -1256,10 +1256,10 @@ void write_neon_element64(TCGv_i64 src, int reg, int ele, MemOp memop) switch (memop) { case MO_32: - tcg_gen_st32_i64(src, cpu_env, off); + tcg_gen_st32_i64(src, tcg_env, off); break; case MO_64: - tcg_gen_st_i64(src, cpu_env, off); + tcg_gen_st_i64(src, tcg_env, off); break; default: g_assert_not_reached(); @@ -1270,24 +1270,24 @@ void write_neon_element64(TCGv_i64 src, int reg, int ele, MemOp memop) static inline void iwmmxt_load_reg(TCGv_i64 var, int reg) { - tcg_gen_ld_i64(var, cpu_env, offsetof(CPUARMState, iwmmxt.regs[reg])); + tcg_gen_ld_i64(var, tcg_env, offsetof(CPUARMState, iwmmxt.regs[reg])); } static inline void iwmmxt_store_reg(TCGv_i64 var, int reg) { - tcg_gen_st_i64(var, cpu_env, offsetof(CPUARMState, iwmmxt.regs[reg])); + tcg_gen_st_i64(var, tcg_env, offsetof(CPUARMState, iwmmxt.regs[reg])); } static inline TCGv_i32 iwmmxt_load_creg(int reg) { TCGv_i32 var = tcg_temp_new_i32(); - tcg_gen_ld_i32(var, cpu_env, offsetof(CPUARMState, iwmmxt.cregs[reg])); + tcg_gen_ld_i32(var, tcg_env, offsetof(CPUARMState, iwmmxt.cregs[reg])); return var; } static inline void iwmmxt_store_creg(int reg, TCGv_i32 var) { - tcg_gen_st_i32(var, cpu_env, offsetof(CPUARMState, iwmmxt.cregs[reg])); + tcg_gen_st_i32(var, tcg_env, offsetof(CPUARMState, iwmmxt.cregs[reg])); } static inline void gen_op_iwmmxt_movq_wRn_M0(int rn) @@ -1329,7 +1329,7 @@ static inline void gen_op_iwmmxt_##name##_M0_wRn(int rn) \ static inline void gen_op_iwmmxt_##name##_M0_wRn(int rn) \ { \ iwmmxt_load_reg(cpu_V1, rn); \ - gen_helper_iwmmxt_##name(cpu_M0, cpu_env, cpu_M0, cpu_V1); \ + gen_helper_iwmmxt_##name(cpu_M0, tcg_env, cpu_M0, cpu_V1); \ } #define IWMMXT_OP_ENV_SIZE(name) \ @@ -1340,7 +1340,7 @@ IWMMXT_OP_ENV(name##l) #define IWMMXT_OP_ENV1(name) \ static inline void gen_op_iwmmxt_##name##_M0(void) \ { \ - gen_helper_iwmmxt_##name(cpu_M0, cpu_env, cpu_M0); \ + gen_helper_iwmmxt_##name(cpu_M0, tcg_env, cpu_M0); \ } IWMMXT_OP(maddsq) @@ -2113,13 +2113,13 @@ static int disas_iwmmxt_insn(DisasContext *s, uint32_t insn) } switch ((insn >> 22) & 3) { case 1: - gen_helper_iwmmxt_srlw(cpu_M0, cpu_env, cpu_M0, tmp); + gen_helper_iwmmxt_srlw(cpu_M0, tcg_env, cpu_M0, tmp); break; case 2: - gen_helper_iwmmxt_srll(cpu_M0, cpu_env, cpu_M0, tmp); + gen_helper_iwmmxt_srll(cpu_M0, tcg_env, cpu_M0, tmp); break; case 3: - gen_helper_iwmmxt_srlq(cpu_M0, cpu_env, cpu_M0, tmp); + gen_helper_iwmmxt_srlq(cpu_M0, tcg_env, cpu_M0, tmp); break; } gen_op_iwmmxt_movq_wRn_M0(wrd); @@ -2139,13 +2139,13 @@ static int disas_iwmmxt_insn(DisasContext *s, uint32_t insn) } switch ((insn >> 22) & 3) { case 1: - gen_helper_iwmmxt_sraw(cpu_M0, cpu_env, cpu_M0, tmp); + gen_helper_iwmmxt_sraw(cpu_M0, tcg_env, cpu_M0, tmp); break; case 2: - gen_helper_iwmmxt_sral(cpu_M0, cpu_env, cpu_M0, tmp); + gen_helper_iwmmxt_sral(cpu_M0, tcg_env, cpu_M0, tmp); break; case 3: - gen_helper_iwmmxt_sraq(cpu_M0, cpu_env, cpu_M0, tmp); + gen_helper_iwmmxt_sraq(cpu_M0, tcg_env, cpu_M0, tmp); break; } gen_op_iwmmxt_movq_wRn_M0(wrd); @@ -2165,13 +2165,13 @@ static int disas_iwmmxt_insn(DisasContext *s, uint32_t insn) } switch ((insn >> 22) & 3) { case 1: - gen_helper_iwmmxt_sllw(cpu_M0, cpu_env, cpu_M0, tmp); + gen_helper_iwmmxt_sllw(cpu_M0, tcg_env, cpu_M0, tmp); break; case 2: - gen_helper_iwmmxt_slll(cpu_M0, cpu_env, cpu_M0, tmp); + gen_helper_iwmmxt_slll(cpu_M0, tcg_env, cpu_M0, tmp); break; case 3: - gen_helper_iwmmxt_sllq(cpu_M0, cpu_env, cpu_M0, tmp); + gen_helper_iwmmxt_sllq(cpu_M0, tcg_env, cpu_M0, tmp); break; } gen_op_iwmmxt_movq_wRn_M0(wrd); @@ -2191,19 +2191,19 @@ static int disas_iwmmxt_insn(DisasContext *s, uint32_t insn) if (gen_iwmmxt_shift(insn, 0xf, tmp)) { return 1; } - gen_helper_iwmmxt_rorw(cpu_M0, cpu_env, cpu_M0, tmp); + gen_helper_iwmmxt_rorw(cpu_M0, tcg_env, cpu_M0, tmp); break; case 2: if (gen_iwmmxt_shift(insn, 0x1f, tmp)) { return 1; } - gen_helper_iwmmxt_rorl(cpu_M0, cpu_env, cpu_M0, tmp); + gen_helper_iwmmxt_rorl(cpu_M0, tcg_env, cpu_M0, tmp); break; case 3: if (gen_iwmmxt_shift(insn, 0x3f, tmp)) { return 1; } - gen_helper_iwmmxt_rorq(cpu_M0, cpu_env, cpu_M0, tmp); + gen_helper_iwmmxt_rorq(cpu_M0, tcg_env, cpu_M0, tmp); break; } gen_op_iwmmxt_movq_wRn_M0(wrd); @@ -2335,7 +2335,7 @@ static int disas_iwmmxt_insn(DisasContext *s, uint32_t insn) rd0 = (insn >> 16) & 0xf; gen_op_iwmmxt_movq_M0_wRn(rd0); tmp = tcg_constant_i32(((insn >> 16) & 0xf0) | (insn & 0x0f)); - gen_helper_iwmmxt_shufh(cpu_M0, cpu_env, cpu_M0, tmp); + gen_helper_iwmmxt_shufh(cpu_M0, tcg_env, cpu_M0, tmp); gen_op_iwmmxt_movq_wRn_M0(wrd); gen_op_iwmmxt_set_mup(); gen_op_iwmmxt_set_cup(); @@ -2857,7 +2857,7 @@ static void gen_msr_banked(DisasContext *s, int r, int sysm, int rn) gen_set_condexec(s); gen_update_pc(s, 0); tcg_reg = load_reg(s, rn); - gen_helper_msr_banked(cpu_env, tcg_reg, + gen_helper_msr_banked(tcg_env, tcg_reg, tcg_constant_i32(tgtmode), tcg_constant_i32(regno)); s->base.is_jmp = DISAS_UPDATE_EXIT; @@ -2876,7 +2876,7 @@ static void gen_mrs_banked(DisasContext *s, int r, int sysm, int rn) gen_set_condexec(s); gen_update_pc(s, 0); tcg_reg = tcg_temp_new_i32(); - gen_helper_mrs_banked(tcg_reg, cpu_env, + gen_helper_mrs_banked(tcg_reg, tcg_env, tcg_constant_i32(tgtmode), tcg_constant_i32(regno)); store_reg(s, rn, tcg_reg); @@ -2901,7 +2901,7 @@ static void gen_rfe(DisasContext *s, TCGv_i32 pc, TCGv_i32 cpsr) * be called after storing the new PC. */ translator_io_start(&s->base); - gen_helper_cpsr_write_eret(cpu_env, cpsr); + gen_helper_cpsr_write_eret(tcg_env, cpsr); /* Must exit loop to check un-masked IRQs */ s->base.is_jmp = DISAS_EXIT; } @@ -2918,7 +2918,7 @@ static void gen_gvec_fn3_qc(uint32_t rd_ofs, uint32_t rn_ofs, uint32_t rm_ofs, { TCGv_ptr qc_ptr = tcg_temp_new_ptr(); - tcg_gen_addi_ptr(qc_ptr, cpu_env, offsetof(CPUARMState, vfp.qc)); + tcg_gen_addi_ptr(qc_ptr, tcg_env, offsetof(CPUARMState, vfp.qc)); tcg_gen_gvec_3_ptr(rd_ofs, rn_ofs, rm_ofs, qc_ptr, opr_sz, max_sz, 0, fn); } @@ -4605,11 +4605,11 @@ static void do_coproc_insn(DisasContext *s, int cpnum, int is64, case 0: if (arm_dc_feature(s, ARM_FEATURE_AARCH64) && dc_isar_feature(aa64_tidcp1, s)) { - gen_helper_tidcp_el0(cpu_env, tcg_constant_i32(syndrome)); + gen_helper_tidcp_el0(tcg_env, tcg_constant_i32(syndrome)); } break; case 1: - gen_helper_tidcp_el1(cpu_env, tcg_constant_i32(syndrome)); + gen_helper_tidcp_el1(tcg_env, tcg_constant_i32(syndrome)); break; } } @@ -4654,7 +4654,7 @@ static void do_coproc_insn(DisasContext *s, int cpnum, int is64, gen_set_condexec(s); gen_update_pc(s, 0); tcg_ri = tcg_temp_new_ptr(); - gen_helper_access_check_cp_reg(tcg_ri, cpu_env, + gen_helper_access_check_cp_reg(tcg_ri, tcg_env, tcg_constant_i32(key), tcg_constant_i32(syndrome), tcg_constant_i32(isread)); @@ -4702,10 +4702,10 @@ static void do_coproc_insn(DisasContext *s, int cpnum, int is64, tcg_ri = gen_lookup_cp_reg(key); } tmp64 = tcg_temp_new_i64(); - gen_helper_get_cp_reg64(tmp64, cpu_env, tcg_ri); + gen_helper_get_cp_reg64(tmp64, tcg_env, tcg_ri); } else { tmp64 = tcg_temp_new_i64(); - tcg_gen_ld_i64(tmp64, cpu_env, ri->fieldoffset); + tcg_gen_ld_i64(tmp64, tcg_env, ri->fieldoffset); } tmp = tcg_temp_new_i32(); tcg_gen_extrl_i64_i32(tmp, tmp64); @@ -4722,7 +4722,7 @@ static void do_coproc_insn(DisasContext *s, int cpnum, int is64, tcg_ri = gen_lookup_cp_reg(key); } tmp = tcg_temp_new_i32(); - gen_helper_get_cp_reg(tmp, cpu_env, tcg_ri); + gen_helper_get_cp_reg(tmp, tcg_env, tcg_ri); } else { tmp = load_cpu_offset(ri->fieldoffset); } @@ -4752,9 +4752,9 @@ static void do_coproc_insn(DisasContext *s, int cpnum, int is64, if (!tcg_ri) { tcg_ri = gen_lookup_cp_reg(key); } - gen_helper_set_cp_reg64(cpu_env, tcg_ri, tmp64); + gen_helper_set_cp_reg64(tcg_env, tcg_ri, tmp64); } else { - tcg_gen_st_i64(tmp64, cpu_env, ri->fieldoffset); + tcg_gen_st_i64(tmp64, tcg_env, ri->fieldoffset); } } else { TCGv_i32 tmp = load_reg(s, rt); @@ -4762,7 +4762,7 @@ static void do_coproc_insn(DisasContext *s, int cpnum, int is64, if (!tcg_ri) { tcg_ri = gen_lookup_cp_reg(key); } - gen_helper_set_cp_reg(cpu_env, tcg_ri, tmp); + gen_helper_set_cp_reg(tcg_env, tcg_ri, tmp); } else { store_cpu_offset(tmp, ri->fieldoffset, 4); } @@ -5028,7 +5028,7 @@ static void gen_srs(DisasContext *s, /* get_r13_banked() will raise an exception if called from System mode */ gen_set_condexec(s); gen_update_pc(s, 0); - gen_helper_get_r13_banked(addr, cpu_env, tcg_constant_i32(mode)); + gen_helper_get_r13_banked(addr, tcg_env, tcg_constant_i32(mode)); switch (amode) { case 0: /* DA */ offset = -4; @@ -5069,7 +5069,7 @@ static void gen_srs(DisasContext *s, g_assert_not_reached(); } tcg_gen_addi_i32(addr, addr, offset); - gen_helper_set_r13_banked(cpu_env, tcg_constant_i32(mode), addr); + gen_helper_set_r13_banked(tcg_env, tcg_constant_i32(mode), addr); } s->base.is_jmp = DISAS_UPDATE_EXIT; } @@ -5618,7 +5618,7 @@ static bool trans_LSRL_ri(DisasContext *s, arg_mve_shl_ri *a) static void gen_mve_sqshll(TCGv_i64 r, TCGv_i64 n, int64_t shift) { - gen_helper_mve_sqshll(r, cpu_env, n, tcg_constant_i32(shift)); + gen_helper_mve_sqshll(r, tcg_env, n, tcg_constant_i32(shift)); } static bool trans_SQSHLL_ri(DisasContext *s, arg_mve_shl_ri *a) @@ -5628,7 +5628,7 @@ static bool trans_SQSHLL_ri(DisasContext *s, arg_mve_shl_ri *a) static void gen_mve_uqshll(TCGv_i64 r, TCGv_i64 n, int64_t shift) { - gen_helper_mve_uqshll(r, cpu_env, n, tcg_constant_i32(shift)); + gen_helper_mve_uqshll(r, tcg_env, n, tcg_constant_i32(shift)); } static bool trans_UQSHLL_ri(DisasContext *s, arg_mve_shl_ri *a) @@ -5674,7 +5674,7 @@ static bool do_mve_shl_rr(DisasContext *s, arg_mve_shl_rr *a, WideShiftFn *fn) tcg_gen_concat_i32_i64(rda, rdalo, rdahi); /* The helper takes care of the sign-extension of the low 8 bits of Rm */ - fn(rda, cpu_env, rda, cpu_R[a->rm]); + fn(rda, tcg_env, rda, cpu_R[a->rm]); tcg_gen_extrl_i64_i32(rdalo, rda); tcg_gen_extrh_i64_i32(rdahi, rda); @@ -5748,7 +5748,7 @@ static bool trans_SRSHR_ri(DisasContext *s, arg_mve_sh_ri *a) static void gen_mve_sqshl(TCGv_i32 r, TCGv_i32 n, int32_t shift) { - gen_helper_mve_sqshl(r, cpu_env, n, tcg_constant_i32(shift)); + gen_helper_mve_sqshl(r, tcg_env, n, tcg_constant_i32(shift)); } static bool trans_SQSHL_ri(DisasContext *s, arg_mve_sh_ri *a) @@ -5758,7 +5758,7 @@ static bool trans_SQSHL_ri(DisasContext *s, arg_mve_sh_ri *a) static void gen_mve_uqshl(TCGv_i32 r, TCGv_i32 n, int32_t shift) { - gen_helper_mve_uqshl(r, cpu_env, n, tcg_constant_i32(shift)); + gen_helper_mve_uqshl(r, tcg_env, n, tcg_constant_i32(shift)); } static bool trans_UQSHL_ri(DisasContext *s, arg_mve_sh_ri *a) @@ -5782,7 +5782,7 @@ static bool do_mve_sh_rr(DisasContext *s, arg_mve_sh_rr *a, ShiftFn *fn) } /* The helper takes care of the sign-extension of the low 8 bits of Rm */ - fn(cpu_R[a->rda], cpu_env, cpu_R[a->rda], cpu_R[a->rm]); + fn(cpu_R[a->rda], tcg_env, cpu_R[a->rda], cpu_R[a->rm]); return true; } @@ -5928,12 +5928,12 @@ static bool op_qaddsub(DisasContext *s, arg_rrr *a, bool add, bool doub) t0 = load_reg(s, a->rm); t1 = load_reg(s, a->rn); if (doub) { - gen_helper_add_saturate(t1, cpu_env, t1, t1); + gen_helper_add_saturate(t1, tcg_env, t1, t1); } if (add) { - gen_helper_add_saturate(t0, cpu_env, t0, t1); + gen_helper_add_saturate(t0, tcg_env, t0, t1); } else { - gen_helper_sub_saturate(t0, cpu_env, t0, t1); + gen_helper_sub_saturate(t0, tcg_env, t0, t1); } store_reg(s, a->rd, t0); return true; @@ -5977,7 +5977,7 @@ static bool op_smlaxxx(DisasContext *s, arg_rrrr *a, break; case 1: t1 = load_reg(s, a->ra); - gen_helper_add_setq(t0, cpu_env, t0, t1); + gen_helper_add_setq(t0, tcg_env, t0, t1); store_reg(s, a->rd, t0); break; case 2: @@ -6041,7 +6041,7 @@ static bool op_smlawx(DisasContext *s, arg_rrrr *a, bool add, bool mt) tcg_gen_muls2_i32(t0, t1, t0, t1); if (add) { t0 = load_reg(s, a->ra); - gen_helper_add_setq(t1, cpu_env, t1, t0); + gen_helper_add_setq(t1, tcg_env, t1, t0); } store_reg(s, a->rd, t1); return true; @@ -6120,7 +6120,7 @@ static bool trans_ESB(DisasContext *s, arg_ESB *a) * Test for EL2 present, and defer test for SEL2 to runtime. */ if (s->current_el <= 1 && arm_dc_feature(s, ARM_FEATURE_EL2)) { - gen_helper_vesb(cpu_env); + gen_helper_vesb(tcg_env); } } return true; @@ -6228,7 +6228,7 @@ static bool trans_MRS_reg(DisasContext *s, arg_MRS_reg *a) tmp = load_cpu_field(spsr); } else { tmp = tcg_temp_new_i32(); - gen_helper_cpsr_read(tmp, cpu_env); + gen_helper_cpsr_read(tmp, tcg_env); } store_reg(s, a->rd, tmp); return true; @@ -6257,7 +6257,7 @@ static bool trans_MRS_v7m(DisasContext *s, arg_MRS_v7m *a) return false; } tmp = tcg_temp_new_i32(); - gen_helper_v7m_mrs(tmp, cpu_env, tcg_constant_i32(a->sysm)); + gen_helper_v7m_mrs(tmp, tcg_env, tcg_constant_i32(a->sysm)); store_reg(s, a->rd, tmp); return true; } @@ -6271,7 +6271,7 @@ static bool trans_MSR_v7m(DisasContext *s, arg_MSR_v7m *a) } addr = tcg_constant_i32((a->mask << 10) | a->sysm); reg = load_reg(s, a->rn); - gen_helper_v7m_msr(cpu_env, addr, reg); + gen_helper_v7m_msr(tcg_env, addr, reg); /* If we wrote to CONTROL, the EL might have changed */ gen_rebuild_hflags(s, true); gen_lookup_tb(s); @@ -6302,7 +6302,7 @@ static bool trans_BXJ(DisasContext *s, arg_BXJ *a) if (!arm_dc_feature(s, ARM_FEATURE_V8) && arm_dc_feature(s, ARM_FEATURE_EL2) && s->current_el < 2 && s->ns) { - gen_helper_check_bxj_trap(cpu_env, tcg_constant_i32(a->rm)); + gen_helper_check_bxj_trap(tcg_env, tcg_constant_i32(a->rm)); } /* Trivial implementation equivalent to bx. */ gen_bx(s, load_reg(s, a->rm)); @@ -6480,7 +6480,7 @@ static bool trans_TT(DisasContext *s, arg_TT *a) addr = load_reg(s, a->rn); tmp = tcg_temp_new_i32(); - gen_helper_v7m_tt(tmp, cpu_env, addr, tcg_constant_i32((a->A << 1) | a->T)); + gen_helper_v7m_tt(tmp, tcg_env, addr, tcg_constant_i32((a->A << 1) | a->T)); store_reg(s, a->rd, tmp); return true; } @@ -6510,7 +6510,7 @@ static TCGv_i32 op_addr_rr_pre(DisasContext *s, arg_ldst_rr *a) TCGv_i32 addr = load_reg(s, a->rn); if (s->v8m_stackcheck && a->rn == 13 && a->w) { - gen_helper_v8m_stackcheck(cpu_env, addr); + gen_helper_v8m_stackcheck(tcg_env, addr); } if (a->p) { @@ -6665,9 +6665,9 @@ static TCGv_i32 op_addr_ri_pre(DisasContext *s, arg_ldst_ri *a) if (!a->u) { TCGv_i32 newsp = tcg_temp_new_i32(); tcg_gen_addi_i32(newsp, cpu_R[13], ofs); - gen_helper_v8m_stackcheck(cpu_env, newsp); + gen_helper_v8m_stackcheck(tcg_env, newsp); } else { - gen_helper_v8m_stackcheck(cpu_env, cpu_R[13]); + gen_helper_v8m_stackcheck(tcg_env, cpu_R[13]); } } @@ -7319,7 +7319,7 @@ static bool op_par_addsub_ge(DisasContext *s, arg_rrr *a, t1 = load_reg(s, a->rm); ge = tcg_temp_new_ptr(); - tcg_gen_addi_ptr(ge, cpu_env, offsetof(CPUARMState, GE)); + tcg_gen_addi_ptr(ge, tcg_env, offsetof(CPUARMState, GE)); gen(t0, t0, t1, ge); store_reg(s, a->rd, t0); @@ -7433,7 +7433,7 @@ static bool op_sat(DisasContext *s, arg_sat *a, tcg_gen_shli_i32(tmp, tmp, shift); } - gen(tmp, cpu_env, tmp, tcg_constant_i32(a->satimm)); + gen(tmp, tcg_env, tmp, tcg_constant_i32(a->satimm)); store_reg(s, a->rd, tmp); return true; @@ -7540,7 +7540,7 @@ static bool trans_SEL(DisasContext *s, arg_rrr *a) t1 = load_reg(s, a->rn); t2 = load_reg(s, a->rm); t3 = tcg_temp_new_i32(); - tcg_gen_ld_i32(t3, cpu_env, offsetof(CPUARMState, GE)); + tcg_gen_ld_i32(t3, tcg_env, offsetof(CPUARMState, GE)); gen_helper_sel_flags(t1, t3, t1, t2); store_reg(s, a->rd, t1); return true; @@ -7618,11 +7618,11 @@ static bool op_smlad(DisasContext *s, arg_rrrr *a, bool m_swap, bool sub) if (a->ra != 15) { t2 = load_reg(s, a->ra); - gen_helper_add_setq(t1, cpu_env, t1, t2); + gen_helper_add_setq(t1, tcg_env, t1, t2); } } else if (a->ra == 15) { /* Single saturation-checking addition */ - gen_helper_add_setq(t1, cpu_env, t1, t2); + gen_helper_add_setq(t1, tcg_env, t1, t2); } else { /* * We need to add the products and Ra together and then @@ -7804,9 +7804,9 @@ static bool op_div(DisasContext *s, arg_rrr *a, bool u) t1 = load_reg(s, a->rn); t2 = load_reg(s, a->rm); if (u) { - gen_helper_udiv(t1, cpu_env, t1, t2); + gen_helper_udiv(t1, tcg_env, t1, t2); } else { - gen_helper_sdiv(t1, cpu_env, t1, t2); + gen_helper_sdiv(t1, tcg_env, t1, t2); } store_reg(s, a->rd, t1); return true; @@ -7855,7 +7855,7 @@ static TCGv_i32 op_addr_block_pre(DisasContext *s, arg_ldst_block *a, int n) * either the original SP (if incrementing) or our * final SP (if decrementing), so that's what we check. */ - gen_helper_v8m_stackcheck(cpu_env, addr); + gen_helper_v8m_stackcheck(tcg_env, addr); } return addr; @@ -7916,7 +7916,7 @@ static bool op_stm(DisasContext *s, arg_ldst_block *a, int min_n) if (user && i != 15) { tmp = tcg_temp_new_i32(); - gen_helper_get_user_reg(tmp, cpu_env, tcg_constant_i32(i)); + gen_helper_get_user_reg(tmp, tcg_env, tcg_constant_i32(i)); } else { tmp = load_reg(s, i); } @@ -7999,7 +7999,7 @@ static bool do_ldm(DisasContext *s, arg_ldst_block *a, int min_n) tmp = tcg_temp_new_i32(); gen_aa32_ld_i32(s, tmp, addr, mem_idx, MO_UL | MO_ALIGN); if (user) { - gen_helper_set_user_reg(cpu_env, tcg_constant_i32(i), tmp); + gen_helper_set_user_reg(tcg_env, tcg_constant_i32(i), tmp); } else if (i == a->rn) { loaded_var = tmp; loaded_base = true; @@ -8026,7 +8026,7 @@ static bool do_ldm(DisasContext *s, arg_ldst_block *a, int min_n) /* Restore CPSR from SPSR. */ tmp = load_cpu_field(spsr); translator_io_start(&s->base); - gen_helper_cpsr_write_eret(cpu_env, tmp); + gen_helper_cpsr_write_eret(tcg_env, tmp); /* Must exit loop to check un-masked IRQs */ s->base.is_jmp = DISAS_EXIT; } @@ -8100,7 +8100,7 @@ static bool trans_CLRM(DisasContext *s, arg_CLRM *a) * Clear APSR (by calling the MSR helper with the same argument * as for "MSR APSR_nzcvqg, Rn": mask = 0b1100, SYSM=0) */ - gen_helper_v7m_msr(cpu_env, tcg_constant_i32(0xc00), zero); + gen_helper_v7m_msr(tcg_env, tcg_constant_i32(0xc00), zero); } clear_eci_state(s); return true; @@ -8487,7 +8487,7 @@ static bool trans_VCTP(DisasContext *s, arg_VCTP *a) tcg_gen_movcond_i32(TCG_COND_LEU, masklen, masklen, tcg_constant_i32(1 << (4 - a->size)), rn_shifted, tcg_constant_i32(16)); - gen_helper_mve_vctp(cpu_env, masklen); + gen_helper_mve_vctp(tcg_env, masklen); /* This insn updates predication bits */ s->base.is_jmp = DISAS_UPDATE_NOCHAIN; mve_update_eci(s); @@ -8665,12 +8665,12 @@ static bool trans_CPS_v7m(DisasContext *s, arg_CPS_v7m *a) /* FAULTMASK */ if (a->F) { addr = tcg_constant_i32(19); - gen_helper_v7m_msr(cpu_env, addr, tmp); + gen_helper_v7m_msr(tcg_env, addr, tmp); } /* PRIMASK */ if (a->I) { addr = tcg_constant_i32(16); - gen_helper_v7m_msr(cpu_env, addr, tmp); + gen_helper_v7m_msr(tcg_env, addr, tmp); } gen_rebuild_hflags(s, false); gen_lookup_tb(s); @@ -8740,7 +8740,7 @@ static bool trans_SETEND(DisasContext *s, arg_SETEND *a) return false; } if (a->E != (s->be_data == MO_BE)) { - gen_helper_setend(cpu_env); + gen_helper_setend(tcg_env); s->base.is_jmp = DISAS_UPDATE_EXIT; } return true; @@ -9335,7 +9335,7 @@ static void arm_tr_translate_insn(DisasContextBase *dcbase, CPUState *cpu) * be possible after an indirect branch, at the start of the TB. */ assert(dc->base.num_insns == 1); - gen_helper_exception_pc_alignment(cpu_env, tcg_constant_tl(pc)); + gen_helper_exception_pc_alignment(tcg_env, tcg_constant_tl(pc)); dc->base.is_jmp = DISAS_NORETURN; dc->base.pc_next = QEMU_ALIGN_UP(pc, 4); return; @@ -9615,7 +9615,7 @@ static void arm_tr_tb_stop(DisasContextBase *dcbase, CPUState *cpu) /* nothing more to generate */ break; case DISAS_WFI: - gen_helper_wfi(cpu_env, tcg_constant_i32(curr_insn_len(dc))); + gen_helper_wfi(tcg_env, tcg_constant_i32(curr_insn_len(dc))); /* * The helper doesn't necessarily throw an exception, but we * must go back to the main loop to check for interrupts anyway. @@ -9623,10 +9623,10 @@ static void arm_tr_tb_stop(DisasContextBase *dcbase, CPUState *cpu) tcg_gen_exit_tb(NULL, 0); break; case DISAS_WFE: - gen_helper_wfe(cpu_env); + gen_helper_wfe(tcg_env); break; case DISAS_YIELD: - gen_helper_yield(cpu_env); + gen_helper_yield(tcg_env); break; case DISAS_SWI: gen_exception(EXCP_SWI, syn_aa32_svc(dc->svc_imm, dc->thumb)); diff --git a/target/arm/tcg/translate.h b/target/arm/tcg/translate.h index 63922f8bad..b4046611f5 100644 --- a/target/arm/tcg/translate.h +++ b/target/arm/tcg/translate.h @@ -329,7 +329,7 @@ static inline TCGv_i32 get_ahp_flag(void) { TCGv_i32 ret = tcg_temp_new_i32(); - tcg_gen_ld_i32(ret, cpu_env, + tcg_gen_ld_i32(ret, tcg_env, offsetof(CPUARMState, vfp.xregs[ARM_VFP_FPSCR])); tcg_gen_extract_i32(ret, ret, 26, 1); @@ -343,9 +343,9 @@ static inline void set_pstate_bits(uint32_t bits) tcg_debug_assert(!(bits & CACHED_PSTATE_BITS)); - tcg_gen_ld_i32(p, cpu_env, offsetof(CPUARMState, pstate)); + tcg_gen_ld_i32(p, tcg_env, offsetof(CPUARMState, pstate)); tcg_gen_ori_i32(p, p, bits); - tcg_gen_st_i32(p, cpu_env, offsetof(CPUARMState, pstate)); + tcg_gen_st_i32(p, tcg_env, offsetof(CPUARMState, pstate)); } /* Clear bits within PSTATE. */ @@ -355,9 +355,9 @@ static inline void clear_pstate_bits(uint32_t bits) tcg_debug_assert(!(bits & CACHED_PSTATE_BITS)); - tcg_gen_ld_i32(p, cpu_env, offsetof(CPUARMState, pstate)); + tcg_gen_ld_i32(p, tcg_env, offsetof(CPUARMState, pstate)); tcg_gen_andi_i32(p, p, ~bits); - tcg_gen_st_i32(p, cpu_env, offsetof(CPUARMState, pstate)); + tcg_gen_st_i32(p, tcg_env, offsetof(CPUARMState, pstate)); } /* If the singlestep state is Active-not-pending, advance to Active-pending. */ @@ -374,7 +374,7 @@ static inline void gen_swstep_exception(DisasContext *s, int isv, int ex) { /* Fill in the same_el field of the syndrome in the helper. */ uint32_t syn = syn_swstep(false, isv, ex); - gen_helper_exception_swstep(cpu_env, tcg_constant_i32(syn)); + gen_helper_exception_swstep(tcg_env, tcg_constant_i32(syn)); } /* @@ -557,7 +557,7 @@ static inline TCGv_ptr fpstatus_ptr(ARMFPStatusFlavour flavour) default: g_assert_not_reached(); } - tcg_gen_addi_ptr(statusptr, cpu_env, offset); + tcg_gen_addi_ptr(statusptr, tcg_env, offset); return statusptr; } @@ -679,7 +679,7 @@ static inline void set_disas_label(DisasContext *s, DisasLabel l) static inline TCGv_ptr gen_lookup_cp_reg(uint32_t key) { TCGv_ptr ret = tcg_temp_new_ptr(); - gen_helper_lookup_cp_reg(ret, cpu_env, tcg_constant_i32(key)); + gen_helper_lookup_cp_reg(ret, tcg_env, tcg_constant_i32(key)); return ret; } diff --git a/target/avr/translate.c b/target/avr/translate.c index ef2edd7415..8d67570d17 100644 --- a/target/avr/translate.c +++ b/target/avr/translate.c @@ -127,25 +127,25 @@ void avr_cpu_tcg_init(void) int i; #define AVR_REG_OFFS(x) offsetof(CPUAVRState, x) - cpu_pc = tcg_global_mem_new_i32(cpu_env, AVR_REG_OFFS(pc_w), "pc"); - cpu_Cf = tcg_global_mem_new_i32(cpu_env, AVR_REG_OFFS(sregC), "Cf"); - cpu_Zf = tcg_global_mem_new_i32(cpu_env, AVR_REG_OFFS(sregZ), "Zf"); - cpu_Nf = tcg_global_mem_new_i32(cpu_env, AVR_REG_OFFS(sregN), "Nf"); - cpu_Vf = tcg_global_mem_new_i32(cpu_env, AVR_REG_OFFS(sregV), "Vf"); - cpu_Sf = tcg_global_mem_new_i32(cpu_env, AVR_REG_OFFS(sregS), "Sf"); - cpu_Hf = tcg_global_mem_new_i32(cpu_env, AVR_REG_OFFS(sregH), "Hf"); - cpu_Tf = tcg_global_mem_new_i32(cpu_env, AVR_REG_OFFS(sregT), "Tf"); - cpu_If = tcg_global_mem_new_i32(cpu_env, AVR_REG_OFFS(sregI), "If"); - cpu_rampD = tcg_global_mem_new_i32(cpu_env, AVR_REG_OFFS(rampD), "rampD"); - cpu_rampX = tcg_global_mem_new_i32(cpu_env, AVR_REG_OFFS(rampX), "rampX"); - cpu_rampY = tcg_global_mem_new_i32(cpu_env, AVR_REG_OFFS(rampY), "rampY"); - cpu_rampZ = tcg_global_mem_new_i32(cpu_env, AVR_REG_OFFS(rampZ), "rampZ"); - cpu_eind = tcg_global_mem_new_i32(cpu_env, AVR_REG_OFFS(eind), "eind"); - cpu_sp = tcg_global_mem_new_i32(cpu_env, AVR_REG_OFFS(sp), "sp"); - cpu_skip = tcg_global_mem_new_i32(cpu_env, AVR_REG_OFFS(skip), "skip"); + cpu_pc = tcg_global_mem_new_i32(tcg_env, AVR_REG_OFFS(pc_w), "pc"); + cpu_Cf = tcg_global_mem_new_i32(tcg_env, AVR_REG_OFFS(sregC), "Cf"); + cpu_Zf = tcg_global_mem_new_i32(tcg_env, AVR_REG_OFFS(sregZ), "Zf"); + cpu_Nf = tcg_global_mem_new_i32(tcg_env, AVR_REG_OFFS(sregN), "Nf"); + cpu_Vf = tcg_global_mem_new_i32(tcg_env, AVR_REG_OFFS(sregV), "Vf"); + cpu_Sf = tcg_global_mem_new_i32(tcg_env, AVR_REG_OFFS(sregS), "Sf"); + cpu_Hf = tcg_global_mem_new_i32(tcg_env, AVR_REG_OFFS(sregH), "Hf"); + cpu_Tf = tcg_global_mem_new_i32(tcg_env, AVR_REG_OFFS(sregT), "Tf"); + cpu_If = tcg_global_mem_new_i32(tcg_env, AVR_REG_OFFS(sregI), "If"); + cpu_rampD = tcg_global_mem_new_i32(tcg_env, AVR_REG_OFFS(rampD), "rampD"); + cpu_rampX = tcg_global_mem_new_i32(tcg_env, AVR_REG_OFFS(rampX), "rampX"); + cpu_rampY = tcg_global_mem_new_i32(tcg_env, AVR_REG_OFFS(rampY), "rampY"); + cpu_rampZ = tcg_global_mem_new_i32(tcg_env, AVR_REG_OFFS(rampZ), "rampZ"); + cpu_eind = tcg_global_mem_new_i32(tcg_env, AVR_REG_OFFS(eind), "eind"); + cpu_sp = tcg_global_mem_new_i32(tcg_env, AVR_REG_OFFS(sp), "sp"); + cpu_skip = tcg_global_mem_new_i32(tcg_env, AVR_REG_OFFS(skip), "skip"); for (i = 0; i < NUMBER_OF_CPU_REGISTERS; i++) { - cpu_r[i] = tcg_global_mem_new_i32(cpu_env, AVR_REG_OFFS(r[i]), + cpu_r[i] = tcg_global_mem_new_i32(tcg_env, AVR_REG_OFFS(r[i]), reg_names[i]); } #undef AVR_REG_OFFS @@ -184,7 +184,7 @@ static int append_16(DisasContext *ctx, int x) static bool avr_have_feature(DisasContext *ctx, int feature) { if (!avr_feature(ctx->env, feature)) { - gen_helper_unsupported(cpu_env); + gen_helper_unsupported(tcg_env); ctx->base.is_jmp = DISAS_NORETURN; return false; } @@ -1295,7 +1295,7 @@ static bool trans_SBIC(DisasContext *ctx, arg_SBIC *a) TCGv data = tcg_temp_new_i32(); TCGv port = tcg_constant_i32(a->reg); - gen_helper_inb(data, cpu_env, port); + gen_helper_inb(data, tcg_env, port); tcg_gen_andi_tl(data, data, 1 << a->bit); ctx->skip_cond = TCG_COND_EQ; ctx->skip_var0 = data; @@ -1313,7 +1313,7 @@ static bool trans_SBIS(DisasContext *ctx, arg_SBIS *a) TCGv data = tcg_temp_new_i32(); TCGv port = tcg_constant_i32(a->reg); - gen_helper_inb(data, cpu_env, port); + gen_helper_inb(data, tcg_env, port); tcg_gen_andi_tl(data, data, 1 << a->bit); ctx->skip_cond = TCG_COND_NE; ctx->skip_var0 = data; @@ -1494,7 +1494,7 @@ static TCGv gen_get_zaddr(void) static void gen_data_store(DisasContext *ctx, TCGv data, TCGv addr) { if (ctx->base.tb->flags & TB_FLAGS_FULL_ACCESS) { - gen_helper_fullwr(cpu_env, data, addr); + gen_helper_fullwr(tcg_env, data, addr); } else { tcg_gen_qemu_st_tl(data, addr, MMU_DATA_IDX, MO_UB); } @@ -1503,7 +1503,7 @@ static void gen_data_store(DisasContext *ctx, TCGv data, TCGv addr) static void gen_data_load(DisasContext *ctx, TCGv data, TCGv addr) { if (ctx->base.tb->flags & TB_FLAGS_FULL_ACCESS) { - gen_helper_fullrd(data, cpu_env, addr); + gen_helper_fullrd(data, tcg_env, addr); } else { tcg_gen_qemu_ld_tl(data, addr, MMU_DATA_IDX, MO_UB); } @@ -2130,7 +2130,7 @@ static bool trans_IN(DisasContext *ctx, arg_IN *a) TCGv Rd = cpu_r[a->rd]; TCGv port = tcg_constant_i32(a->imm); - gen_helper_inb(Rd, cpu_env, port); + gen_helper_inb(Rd, tcg_env, port); return true; } @@ -2143,7 +2143,7 @@ static bool trans_OUT(DisasContext *ctx, arg_OUT *a) TCGv Rd = cpu_r[a->rd]; TCGv port = tcg_constant_i32(a->imm); - gen_helper_outb(cpu_env, port, Rd); + gen_helper_outb(tcg_env, port, Rd); return true; } @@ -2411,9 +2411,9 @@ static bool trans_SBI(DisasContext *ctx, arg_SBI *a) TCGv data = tcg_temp_new_i32(); TCGv port = tcg_constant_i32(a->reg); - gen_helper_inb(data, cpu_env, port); + gen_helper_inb(data, tcg_env, port); tcg_gen_ori_tl(data, data, 1 << a->bit); - gen_helper_outb(cpu_env, port, data); + gen_helper_outb(tcg_env, port, data); return true; } @@ -2426,9 +2426,9 @@ static bool trans_CBI(DisasContext *ctx, arg_CBI *a) TCGv data = tcg_temp_new_i32(); TCGv port = tcg_constant_i32(a->reg); - gen_helper_inb(data, cpu_env, port); + gen_helper_inb(data, tcg_env, port); tcg_gen_andi_tl(data, data, ~(1 << a->bit)); - gen_helper_outb(cpu_env, port, data); + gen_helper_outb(tcg_env, port, data); return true; } @@ -2551,7 +2551,7 @@ static bool trans_BREAK(DisasContext *ctx, arg_BREAK *a) #ifdef BREAKPOINT_ON_BREAK tcg_gen_movi_tl(cpu_pc, ctx->npc - 1); - gen_helper_debug(cpu_env); + gen_helper_debug(tcg_env); ctx->base.is_jmp = DISAS_EXIT; #else /* NOP */ @@ -2577,7 +2577,7 @@ static bool trans_NOP(DisasContext *ctx, arg_NOP *a) */ static bool trans_SLEEP(DisasContext *ctx, arg_SLEEP *a) { - gen_helper_sleep(cpu_env); + gen_helper_sleep(tcg_env); ctx->base.is_jmp = DISAS_NORETURN; return true; } @@ -2589,7 +2589,7 @@ static bool trans_SLEEP(DisasContext *ctx, arg_SLEEP *a) */ static bool trans_WDR(DisasContext *ctx, arg_WDR *a) { - gen_helper_wdr(cpu_env); + gen_helper_wdr(tcg_env); return true; } @@ -2608,7 +2608,7 @@ static void translate(DisasContext *ctx) uint32_t opcode = next_word(ctx); if (!decode_insn(ctx, opcode)) { - gen_helper_unsupported(cpu_env); + gen_helper_unsupported(tcg_env); ctx->base.is_jmp = DISAS_NORETURN; } } diff --git a/target/cris/translate.c b/target/cris/translate.c index 42103b5558..395ba12bea 100644 --- a/target/cris/translate.c +++ b/target/cris/translate.c @@ -171,9 +171,9 @@ static const int preg_sizes[] = { }; #define t_gen_mov_TN_env(tn, member) \ - tcg_gen_ld_tl(tn, cpu_env, offsetof(CPUCRISState, member)) + tcg_gen_ld_tl(tn, tcg_env, offsetof(CPUCRISState, member)) #define t_gen_mov_env_TN(member, tn) \ - tcg_gen_st_tl(tn, cpu_env, offsetof(CPUCRISState, member)) + tcg_gen_st_tl(tn, tcg_env, offsetof(CPUCRISState, member)) #define t_gen_movi_env_TN(member, c) \ t_gen_mov_env_TN(member, tcg_constant_tl(c)) @@ -197,10 +197,10 @@ static inline void t_gen_mov_preg_TN(DisasContext *dc, int r, TCGv tn) tcg_gen_andi_tl(cpu_PR[r], tn, 3); } else { if (r == PR_PID) { - gen_helper_tlb_flush_pid(cpu_env, tn); + gen_helper_tlb_flush_pid(tcg_env, tn); } if (dc->tb_flags & S_FLAG && r == PR_SPC) { - gen_helper_spc_write(cpu_env, tn); + gen_helper_spc_write(tcg_env, tn); } else if (r == PR_CCS) { dc->cpustate_changed = 1; } @@ -265,7 +265,7 @@ static void cris_lock_irq(DisasContext *dc) static inline void t_gen_raise_exception(uint32_t index) { - gen_helper_raise_exception(cpu_env, tcg_constant_i32(index)); + gen_helper_raise_exception(tcg_env, tcg_constant_i32(index)); } static void t_gen_lsl(TCGv d, TCGv a, TCGv b) @@ -504,17 +504,17 @@ static void cris_evaluate_flags(DisasContext *dc) switch (dc->cc_op) { case CC_OP_MCP: - gen_helper_evaluate_flags_mcp(cpu_PR[PR_CCS], cpu_env, + gen_helper_evaluate_flags_mcp(cpu_PR[PR_CCS], tcg_env, cpu_PR[PR_CCS], cc_src, cc_dest, cc_result); break; case CC_OP_MULS: - gen_helper_evaluate_flags_muls(cpu_PR[PR_CCS], cpu_env, + gen_helper_evaluate_flags_muls(cpu_PR[PR_CCS], tcg_env, cpu_PR[PR_CCS], cc_result, cpu_PR[PR_MOF]); break; case CC_OP_MULU: - gen_helper_evaluate_flags_mulu(cpu_PR[PR_CCS], cpu_env, + gen_helper_evaluate_flags_mulu(cpu_PR[PR_CCS], tcg_env, cpu_PR[PR_CCS], cc_result, cpu_PR[PR_MOF]); break; @@ -528,14 +528,14 @@ static void cris_evaluate_flags(DisasContext *dc) switch (dc->cc_size) { case 4: gen_helper_evaluate_flags_move_4(cpu_PR[PR_CCS], - cpu_env, cpu_PR[PR_CCS], cc_result); + tcg_env, cpu_PR[PR_CCS], cc_result); break; case 2: gen_helper_evaluate_flags_move_2(cpu_PR[PR_CCS], - cpu_env, cpu_PR[PR_CCS], cc_result); + tcg_env, cpu_PR[PR_CCS], cc_result); break; default: - gen_helper_evaluate_flags(cpu_env); + gen_helper_evaluate_flags(tcg_env); break; } break; @@ -545,21 +545,21 @@ static void cris_evaluate_flags(DisasContext *dc) case CC_OP_SUB: case CC_OP_CMP: if (dc->cc_size == 4) { - gen_helper_evaluate_flags_sub_4(cpu_PR[PR_CCS], cpu_env, + gen_helper_evaluate_flags_sub_4(cpu_PR[PR_CCS], tcg_env, cpu_PR[PR_CCS], cc_src, cc_dest, cc_result); } else { - gen_helper_evaluate_flags(cpu_env); + gen_helper_evaluate_flags(tcg_env); } break; default: switch (dc->cc_size) { case 4: - gen_helper_evaluate_flags_alu_4(cpu_PR[PR_CCS], cpu_env, + gen_helper_evaluate_flags_alu_4(cpu_PR[PR_CCS], tcg_env, cpu_PR[PR_CCS], cc_src, cc_dest, cc_result); break; default: - gen_helper_evaluate_flags(cpu_env); + gen_helper_evaluate_flags(tcg_env); break; } break; @@ -1330,7 +1330,7 @@ static int dec_btstq(CPUCRISState *env, DisasContext *dc) cris_cc_mask(dc, CC_MASK_NZ); c = tcg_constant_tl(dc->op1); cris_evaluate_flags(dc); - gen_helper_btst(cpu_PR[PR_CCS], cpu_env, cpu_R[dc->op2], + gen_helper_btst(cpu_PR[PR_CCS], tcg_env, cpu_R[dc->op2], c, cpu_PR[PR_CCS]); cris_alu(dc, CC_OP_MOVE, cpu_R[dc->op2], cpu_R[dc->op2], cpu_R[dc->op2], 4); @@ -1744,7 +1744,7 @@ static int dec_btst_r(CPUCRISState *env, DisasContext *dc) dc->op1, dc->op2); cris_cc_mask(dc, CC_MASK_NZ); cris_evaluate_flags(dc); - gen_helper_btst(cpu_PR[PR_CCS], cpu_env, cpu_R[dc->op2], + gen_helper_btst(cpu_PR[PR_CCS], tcg_env, cpu_R[dc->op2], cpu_R[dc->op1], cpu_PR[PR_CCS]); cris_alu(dc, CC_OP_MOVE, cpu_R[dc->op2], cpu_R[dc->op2], cpu_R[dc->op2], 4); @@ -1946,7 +1946,7 @@ static int dec_move_rs(CPUCRISState *env, DisasContext *dc) c1 = tcg_constant_tl(dc->op1); c2 = tcg_constant_tl(dc->op2); cris_cc_mask(dc, 0); - gen_helper_movl_sreg_reg(cpu_env, c2, c1); + gen_helper_movl_sreg_reg(tcg_env, c2, c1); return 2; } static int dec_move_sr(CPUCRISState *env, DisasContext *dc) @@ -1956,7 +1956,7 @@ static int dec_move_sr(CPUCRISState *env, DisasContext *dc) c1 = tcg_constant_tl(dc->op1); c2 = tcg_constant_tl(dc->op2); cris_cc_mask(dc, 0); - gen_helper_movl_reg_sreg(cpu_env, c1, c2); + gen_helper_movl_reg_sreg(tcg_env, c1, c2); return 2; } @@ -2693,7 +2693,7 @@ static int dec_rfe_etc(CPUCRISState *env, DisasContext *dc) cris_cc_mask(dc, 0); if (dc->op2 == 15) { - tcg_gen_st_i32(tcg_constant_i32(1), cpu_env, + tcg_gen_st_i32(tcg_constant_i32(1), tcg_env, -offsetof(CRISCPU, env) + offsetof(CPUState, halted)); tcg_gen_movi_tl(env_pc, dc->pc + 2); t_gen_raise_exception(EXCP_HLT); @@ -2706,7 +2706,7 @@ static int dec_rfe_etc(CPUCRISState *env, DisasContext *dc) /* rfe. */ LOG_DIS("rfe\n"); cris_evaluate_flags(dc); - gen_helper_rfe(cpu_env); + gen_helper_rfe(tcg_env); dc->base.is_jmp = DISAS_UPDATE; dc->cpustate_changed = true; break; @@ -2714,7 +2714,7 @@ static int dec_rfe_etc(CPUCRISState *env, DisasContext *dc) /* rfn. */ LOG_DIS("rfn\n"); cris_evaluate_flags(dc); - gen_helper_rfn(cpu_env); + gen_helper_rfn(tcg_env); dc->base.is_jmp = DISAS_UPDATE; dc->cpustate_changed = true; break; @@ -3238,41 +3238,41 @@ void cris_initialize_tcg(void) { int i; - cc_x = tcg_global_mem_new(cpu_env, + cc_x = tcg_global_mem_new(tcg_env, offsetof(CPUCRISState, cc_x), "cc_x"); - cc_src = tcg_global_mem_new(cpu_env, + cc_src = tcg_global_mem_new(tcg_env, offsetof(CPUCRISState, cc_src), "cc_src"); - cc_dest = tcg_global_mem_new(cpu_env, + cc_dest = tcg_global_mem_new(tcg_env, offsetof(CPUCRISState, cc_dest), "cc_dest"); - cc_result = tcg_global_mem_new(cpu_env, + cc_result = tcg_global_mem_new(tcg_env, offsetof(CPUCRISState, cc_result), "cc_result"); - cc_op = tcg_global_mem_new(cpu_env, + cc_op = tcg_global_mem_new(tcg_env, offsetof(CPUCRISState, cc_op), "cc_op"); - cc_size = tcg_global_mem_new(cpu_env, + cc_size = tcg_global_mem_new(tcg_env, offsetof(CPUCRISState, cc_size), "cc_size"); - cc_mask = tcg_global_mem_new(cpu_env, + cc_mask = tcg_global_mem_new(tcg_env, offsetof(CPUCRISState, cc_mask), "cc_mask"); - env_pc = tcg_global_mem_new(cpu_env, + env_pc = tcg_global_mem_new(tcg_env, offsetof(CPUCRISState, pc), "pc"); - env_btarget = tcg_global_mem_new(cpu_env, + env_btarget = tcg_global_mem_new(tcg_env, offsetof(CPUCRISState, btarget), "btarget"); - env_btaken = tcg_global_mem_new(cpu_env, + env_btaken = tcg_global_mem_new(tcg_env, offsetof(CPUCRISState, btaken), "btaken"); for (i = 0; i < 16; i++) { - cpu_R[i] = tcg_global_mem_new(cpu_env, + cpu_R[i] = tcg_global_mem_new(tcg_env, offsetof(CPUCRISState, regs[i]), regnames_v32[i]); } for (i = 0; i < 16; i++) { - cpu_PR[i] = tcg_global_mem_new(cpu_env, + cpu_PR[i] = tcg_global_mem_new(tcg_env, offsetof(CPUCRISState, pregs[i]), pregnames_v32[i]); } diff --git a/target/cris/translate_v10.c.inc b/target/cris/translate_v10.c.inc index b7b0517982..6df599fdce 100644 --- a/target/cris/translate_v10.c.inc +++ b/target/cris/translate_v10.c.inc @@ -282,7 +282,7 @@ static unsigned int dec10_quick_imm(DisasContext *dc) } else { /* BTST */ cris_update_cc_op(dc, CC_OP_FLAGS, 4); - gen_helper_btst(cpu_PR[PR_CCS], cpu_env, cpu_R[dc->dst], + gen_helper_btst(cpu_PR[PR_CCS], tcg_env, cpu_R[dc->dst], c, cpu_PR[PR_CCS]); } break; @@ -696,7 +696,7 @@ static unsigned int dec10_reg(DisasContext *dc) LOG_DIS("btst $r%d, $r%d sz=%d\n", dc->src, dc->dst, size); cris_cc_mask(dc, CC_MASK_NZVC); cris_update_cc_op(dc, CC_OP_FLAGS, 4); - gen_helper_btst(cpu_PR[PR_CCS], cpu_env, cpu_R[dc->dst], + gen_helper_btst(cpu_PR[PR_CCS], tcg_env, cpu_R[dc->dst], cpu_R[dc->src], cpu_PR[PR_CCS]); break; case CRISV10_REG_DSTEP: @@ -1235,41 +1235,41 @@ void cris_initialize_crisv10_tcg(void) { int i; - cc_x = tcg_global_mem_new(cpu_env, + cc_x = tcg_global_mem_new(tcg_env, offsetof(CPUCRISState, cc_x), "cc_x"); - cc_src = tcg_global_mem_new(cpu_env, + cc_src = tcg_global_mem_new(tcg_env, offsetof(CPUCRISState, cc_src), "cc_src"); - cc_dest = tcg_global_mem_new(cpu_env, + cc_dest = tcg_global_mem_new(tcg_env, offsetof(CPUCRISState, cc_dest), "cc_dest"); - cc_result = tcg_global_mem_new(cpu_env, + cc_result = tcg_global_mem_new(tcg_env, offsetof(CPUCRISState, cc_result), "cc_result"); - cc_op = tcg_global_mem_new(cpu_env, + cc_op = tcg_global_mem_new(tcg_env, offsetof(CPUCRISState, cc_op), "cc_op"); - cc_size = tcg_global_mem_new(cpu_env, + cc_size = tcg_global_mem_new(tcg_env, offsetof(CPUCRISState, cc_size), "cc_size"); - cc_mask = tcg_global_mem_new(cpu_env, + cc_mask = tcg_global_mem_new(tcg_env, offsetof(CPUCRISState, cc_mask), "cc_mask"); - env_pc = tcg_global_mem_new(cpu_env, + env_pc = tcg_global_mem_new(tcg_env, offsetof(CPUCRISState, pc), "pc"); - env_btarget = tcg_global_mem_new(cpu_env, + env_btarget = tcg_global_mem_new(tcg_env, offsetof(CPUCRISState, btarget), "btarget"); - env_btaken = tcg_global_mem_new(cpu_env, + env_btaken = tcg_global_mem_new(tcg_env, offsetof(CPUCRISState, btaken), "btaken"); for (i = 0; i < 16; i++) { - cpu_R[i] = tcg_global_mem_new(cpu_env, + cpu_R[i] = tcg_global_mem_new(tcg_env, offsetof(CPUCRISState, regs[i]), regnames_v10[i]); } for (i = 0; i < 16; i++) { - cpu_PR[i] = tcg_global_mem_new(cpu_env, + cpu_PR[i] = tcg_global_mem_new(tcg_env, offsetof(CPUCRISState, pregs[i]), pregnames_v10[i]); } diff --git a/target/hexagon/README b/target/hexagon/README index e757bcb64a..69b2ffe9bb 100644 --- a/target/hexagon/README +++ b/target/hexagon/README @@ -86,7 +86,7 @@ tcg_funcs_generated.c.inc const int RdN = insn->regno[0]; TCGv RsV = hex_gpr[insn->regno[1]]; TCGv RtV = hex_gpr[insn->regno[2]]; - gen_helper_A2_add(RdV, cpu_env, RsV, RtV); + gen_helper_A2_add(RdV, tcg_env, RsV, RtV); gen_log_reg_write(ctx, RdN, RdV); } @@ -143,7 +143,7 @@ istruction. const intptr_t VdV_off = ctx_future_vreg_off(ctx, VdN, 1, true); TCGv_ptr VdV = tcg_temp_new_ptr(); - tcg_gen_addi_ptr(VdV, cpu_env, VdV_off); + tcg_gen_addi_ptr(VdV, tcg_env, VdV_off); const int VuN = insn->regno[1]; const intptr_t VuV_off = vreg_src_off(ctx, VuN); @@ -152,9 +152,9 @@ istruction. const intptr_t VvV_off = vreg_src_off(ctx, VvN); TCGv_ptr VvV = tcg_temp_new_ptr(); - tcg_gen_addi_ptr(VuV, cpu_env, VuV_off); - tcg_gen_addi_ptr(VvV, cpu_env, VvV_off); - gen_helper_V6_vaddw(cpu_env, VdV, VuV, VvV); + tcg_gen_addi_ptr(VuV, tcg_env, VuV_off); + tcg_gen_addi_ptr(VvV, tcg_env, VvV_off); + gen_helper_V6_vaddw(tcg_env, VdV, VuV, VvV); } Notice that we also generate a variable named _off for each operand of diff --git a/target/hexagon/gen_tcg.h b/target/hexagon/gen_tcg.h index d78d99d155..d992059fce 100644 --- a/target/hexagon/gen_tcg.h +++ b/target/hexagon/gen_tcg.h @@ -591,8 +591,8 @@ */ #define fGEN_TCG_A5_ACS(SHORTCODE) \ do { \ - gen_helper_vacsh_pred(PeV, cpu_env, RxxV, RssV, RttV); \ - gen_helper_vacsh_val(RxxV, cpu_env, RxxV, RssV, RttV, \ + gen_helper_vacsh_pred(PeV, tcg_env, RxxV, RssV, RttV); \ + gen_helper_vacsh_val(RxxV, tcg_env, RxxV, RssV, RttV, \ tcg_constant_tl(ctx->need_commit)); \ } while (0) @@ -614,7 +614,7 @@ #define fGEN_TCG_F2_sfrecipa(SHORTCODE) \ do { \ TCGv_i64 tmp = tcg_temp_new_i64(); \ - gen_helper_sfrecipa(tmp, cpu_env, RsV, RtV); \ + gen_helper_sfrecipa(tmp, tcg_env, RsV, RtV); \ tcg_gen_extrh_i64_i32(RdV, tmp); \ tcg_gen_extrl_i64_i32(PeV, tmp); \ } while (0) @@ -629,7 +629,7 @@ #define fGEN_TCG_F2_sfinvsqrta(SHORTCODE) \ do { \ TCGv_i64 tmp = tcg_temp_new_i64(); \ - gen_helper_sfinvsqrta(tmp, cpu_env, RsV); \ + gen_helper_sfinvsqrta(tmp, tcg_env, RsV); \ tcg_gen_extrh_i64_i32(RdV, tmp); \ tcg_gen_extrl_i64_i32(PeV, tmp); \ } while (0) @@ -1205,122 +1205,122 @@ /* Floating point */ #define fGEN_TCG_F2_conv_sf2df(SHORTCODE) \ - gen_helper_conv_sf2df(RddV, cpu_env, RsV) + gen_helper_conv_sf2df(RddV, tcg_env, RsV) #define fGEN_TCG_F2_conv_df2sf(SHORTCODE) \ - gen_helper_conv_df2sf(RdV, cpu_env, RssV) + gen_helper_conv_df2sf(RdV, tcg_env, RssV) #define fGEN_TCG_F2_conv_uw2sf(SHORTCODE) \ - gen_helper_conv_uw2sf(RdV, cpu_env, RsV) + gen_helper_conv_uw2sf(RdV, tcg_env, RsV) #define fGEN_TCG_F2_conv_uw2df(SHORTCODE) \ - gen_helper_conv_uw2df(RddV, cpu_env, RsV) + gen_helper_conv_uw2df(RddV, tcg_env, RsV) #define fGEN_TCG_F2_conv_w2sf(SHORTCODE) \ - gen_helper_conv_w2sf(RdV, cpu_env, RsV) + gen_helper_conv_w2sf(RdV, tcg_env, RsV) #define fGEN_TCG_F2_conv_w2df(SHORTCODE) \ - gen_helper_conv_w2df(RddV, cpu_env, RsV) + gen_helper_conv_w2df(RddV, tcg_env, RsV) #define fGEN_TCG_F2_conv_ud2sf(SHORTCODE) \ - gen_helper_conv_ud2sf(RdV, cpu_env, RssV) + gen_helper_conv_ud2sf(RdV, tcg_env, RssV) #define fGEN_TCG_F2_conv_ud2df(SHORTCODE) \ - gen_helper_conv_ud2df(RddV, cpu_env, RssV) + gen_helper_conv_ud2df(RddV, tcg_env, RssV) #define fGEN_TCG_F2_conv_d2sf(SHORTCODE) \ - gen_helper_conv_d2sf(RdV, cpu_env, RssV) + gen_helper_conv_d2sf(RdV, tcg_env, RssV) #define fGEN_TCG_F2_conv_d2df(SHORTCODE) \ - gen_helper_conv_d2df(RddV, cpu_env, RssV) + gen_helper_conv_d2df(RddV, tcg_env, RssV) #define fGEN_TCG_F2_conv_sf2uw(SHORTCODE) \ - gen_helper_conv_sf2uw(RdV, cpu_env, RsV) + gen_helper_conv_sf2uw(RdV, tcg_env, RsV) #define fGEN_TCG_F2_conv_sf2w(SHORTCODE) \ - gen_helper_conv_sf2w(RdV, cpu_env, RsV) + gen_helper_conv_sf2w(RdV, tcg_env, RsV) #define fGEN_TCG_F2_conv_sf2ud(SHORTCODE) \ - gen_helper_conv_sf2ud(RddV, cpu_env, RsV) + gen_helper_conv_sf2ud(RddV, tcg_env, RsV) #define fGEN_TCG_F2_conv_sf2d(SHORTCODE) \ - gen_helper_conv_sf2d(RddV, cpu_env, RsV) + gen_helper_conv_sf2d(RddV, tcg_env, RsV) #define fGEN_TCG_F2_conv_df2uw(SHORTCODE) \ - gen_helper_conv_df2uw(RdV, cpu_env, RssV) + gen_helper_conv_df2uw(RdV, tcg_env, RssV) #define fGEN_TCG_F2_conv_df2w(SHORTCODE) \ - gen_helper_conv_df2w(RdV, cpu_env, RssV) + gen_helper_conv_df2w(RdV, tcg_env, RssV) #define fGEN_TCG_F2_conv_df2ud(SHORTCODE) \ - gen_helper_conv_df2ud(RddV, cpu_env, RssV) + gen_helper_conv_df2ud(RddV, tcg_env, RssV) #define fGEN_TCG_F2_conv_df2d(SHORTCODE) \ - gen_helper_conv_df2d(RddV, cpu_env, RssV) + gen_helper_conv_df2d(RddV, tcg_env, RssV) #define fGEN_TCG_F2_conv_sf2uw_chop(SHORTCODE) \ - gen_helper_conv_sf2uw_chop(RdV, cpu_env, RsV) + gen_helper_conv_sf2uw_chop(RdV, tcg_env, RsV) #define fGEN_TCG_F2_conv_sf2w_chop(SHORTCODE) \ - gen_helper_conv_sf2w_chop(RdV, cpu_env, RsV) + gen_helper_conv_sf2w_chop(RdV, tcg_env, RsV) #define fGEN_TCG_F2_conv_sf2ud_chop(SHORTCODE) \ - gen_helper_conv_sf2ud_chop(RddV, cpu_env, RsV) + gen_helper_conv_sf2ud_chop(RddV, tcg_env, RsV) #define fGEN_TCG_F2_conv_sf2d_chop(SHORTCODE) \ - gen_helper_conv_sf2d_chop(RddV, cpu_env, RsV) + gen_helper_conv_sf2d_chop(RddV, tcg_env, RsV) #define fGEN_TCG_F2_conv_df2uw_chop(SHORTCODE) \ - gen_helper_conv_df2uw_chop(RdV, cpu_env, RssV) + gen_helper_conv_df2uw_chop(RdV, tcg_env, RssV) #define fGEN_TCG_F2_conv_df2w_chop(SHORTCODE) \ - gen_helper_conv_df2w_chop(RdV, cpu_env, RssV) + gen_helper_conv_df2w_chop(RdV, tcg_env, RssV) #define fGEN_TCG_F2_conv_df2ud_chop(SHORTCODE) \ - gen_helper_conv_df2ud_chop(RddV, cpu_env, RssV) + gen_helper_conv_df2ud_chop(RddV, tcg_env, RssV) #define fGEN_TCG_F2_conv_df2d_chop(SHORTCODE) \ - gen_helper_conv_df2d_chop(RddV, cpu_env, RssV) + gen_helper_conv_df2d_chop(RddV, tcg_env, RssV) #define fGEN_TCG_F2_sfadd(SHORTCODE) \ - gen_helper_sfadd(RdV, cpu_env, RsV, RtV) + gen_helper_sfadd(RdV, tcg_env, RsV, RtV) #define fGEN_TCG_F2_sfsub(SHORTCODE) \ - gen_helper_sfsub(RdV, cpu_env, RsV, RtV) + gen_helper_sfsub(RdV, tcg_env, RsV, RtV) #define fGEN_TCG_F2_sfcmpeq(SHORTCODE) \ - gen_helper_sfcmpeq(PdV, cpu_env, RsV, RtV) + gen_helper_sfcmpeq(PdV, tcg_env, RsV, RtV) #define fGEN_TCG_F2_sfcmpgt(SHORTCODE) \ - gen_helper_sfcmpgt(PdV, cpu_env, RsV, RtV) + gen_helper_sfcmpgt(PdV, tcg_env, RsV, RtV) #define fGEN_TCG_F2_sfcmpge(SHORTCODE) \ - gen_helper_sfcmpge(PdV, cpu_env, RsV, RtV) + gen_helper_sfcmpge(PdV, tcg_env, RsV, RtV) #define fGEN_TCG_F2_sfcmpuo(SHORTCODE) \ - gen_helper_sfcmpuo(PdV, cpu_env, RsV, RtV) + gen_helper_sfcmpuo(PdV, tcg_env, RsV, RtV) #define fGEN_TCG_F2_sfmax(SHORTCODE) \ - gen_helper_sfmax(RdV, cpu_env, RsV, RtV) + gen_helper_sfmax(RdV, tcg_env, RsV, RtV) #define fGEN_TCG_F2_sfmin(SHORTCODE) \ - gen_helper_sfmin(RdV, cpu_env, RsV, RtV) + gen_helper_sfmin(RdV, tcg_env, RsV, RtV) #define fGEN_TCG_F2_sfclass(SHORTCODE) \ do { \ TCGv imm = tcg_constant_tl(uiV); \ - gen_helper_sfclass(PdV, cpu_env, RsV, imm); \ + gen_helper_sfclass(PdV, tcg_env, RsV, imm); \ } while (0) #define fGEN_TCG_F2_sffixupn(SHORTCODE) \ - gen_helper_sffixupn(RdV, cpu_env, RsV, RtV) + gen_helper_sffixupn(RdV, tcg_env, RsV, RtV) #define fGEN_TCG_F2_sffixupd(SHORTCODE) \ - gen_helper_sffixupd(RdV, cpu_env, RsV, RtV) + gen_helper_sffixupd(RdV, tcg_env, RsV, RtV) #define fGEN_TCG_F2_sffixupr(SHORTCODE) \ - gen_helper_sffixupr(RdV, cpu_env, RsV) + gen_helper_sffixupr(RdV, tcg_env, RsV) #define fGEN_TCG_F2_dfadd(SHORTCODE) \ - gen_helper_dfadd(RddV, cpu_env, RssV, RttV) + gen_helper_dfadd(RddV, tcg_env, RssV, RttV) #define fGEN_TCG_F2_dfsub(SHORTCODE) \ - gen_helper_dfsub(RddV, cpu_env, RssV, RttV) + gen_helper_dfsub(RddV, tcg_env, RssV, RttV) #define fGEN_TCG_F2_dfmax(SHORTCODE) \ - gen_helper_dfmax(RddV, cpu_env, RssV, RttV) + gen_helper_dfmax(RddV, tcg_env, RssV, RttV) #define fGEN_TCG_F2_dfmin(SHORTCODE) \ - gen_helper_dfmin(RddV, cpu_env, RssV, RttV) + gen_helper_dfmin(RddV, tcg_env, RssV, RttV) #define fGEN_TCG_F2_dfcmpeq(SHORTCODE) \ - gen_helper_dfcmpeq(PdV, cpu_env, RssV, RttV) + gen_helper_dfcmpeq(PdV, tcg_env, RssV, RttV) #define fGEN_TCG_F2_dfcmpgt(SHORTCODE) \ - gen_helper_dfcmpgt(PdV, cpu_env, RssV, RttV) + gen_helper_dfcmpgt(PdV, tcg_env, RssV, RttV) #define fGEN_TCG_F2_dfcmpge(SHORTCODE) \ - gen_helper_dfcmpge(PdV, cpu_env, RssV, RttV) + gen_helper_dfcmpge(PdV, tcg_env, RssV, RttV) #define fGEN_TCG_F2_dfcmpuo(SHORTCODE) \ - gen_helper_dfcmpuo(PdV, cpu_env, RssV, RttV) + gen_helper_dfcmpuo(PdV, tcg_env, RssV, RttV) #define fGEN_TCG_F2_dfclass(SHORTCODE) \ do { \ TCGv imm = tcg_constant_tl(uiV); \ - gen_helper_dfclass(PdV, cpu_env, RssV, imm); \ + gen_helper_dfclass(PdV, tcg_env, RssV, imm); \ } while (0) #define fGEN_TCG_F2_sfmpy(SHORTCODE) \ - gen_helper_sfmpy(RdV, cpu_env, RsV, RtV) + gen_helper_sfmpy(RdV, tcg_env, RsV, RtV) #define fGEN_TCG_F2_sffma(SHORTCODE) \ - gen_helper_sffma(RxV, cpu_env, RxV, RsV, RtV) + gen_helper_sffma(RxV, tcg_env, RxV, RsV, RtV) #define fGEN_TCG_F2_sffma_sc(SHORTCODE) \ - gen_helper_sffma_sc(RxV, cpu_env, RxV, RsV, RtV, PuV) + gen_helper_sffma_sc(RxV, tcg_env, RxV, RsV, RtV, PuV) #define fGEN_TCG_F2_sffms(SHORTCODE) \ - gen_helper_sffms(RxV, cpu_env, RxV, RsV, RtV) + gen_helper_sffms(RxV, tcg_env, RxV, RsV, RtV) #define fGEN_TCG_F2_sffma_lib(SHORTCODE) \ - gen_helper_sffma_lib(RxV, cpu_env, RxV, RsV, RtV) + gen_helper_sffma_lib(RxV, tcg_env, RxV, RsV, RtV) #define fGEN_TCG_F2_sffms_lib(SHORTCODE) \ - gen_helper_sffms_lib(RxV, cpu_env, RxV, RsV, RtV) + gen_helper_sffms_lib(RxV, tcg_env, RxV, RsV, RtV) #define fGEN_TCG_F2_dfmpyfix(SHORTCODE) \ - gen_helper_dfmpyfix(RddV, cpu_env, RssV, RttV) + gen_helper_dfmpyfix(RddV, tcg_env, RssV, RttV) #define fGEN_TCG_F2_dfmpyhh(SHORTCODE) \ - gen_helper_dfmpyhh(RxxV, cpu_env, RxxV, RssV, RttV) + gen_helper_dfmpyhh(RxxV, tcg_env, RxxV, RssV, RttV) /* Nothing to do for these in qemu, need to suppress compiler warnings */ #define fGEN_TCG_Y4_l2fetch(SHORTCODE) \ @@ -1367,6 +1367,6 @@ uiV = uiV; \ tcg_gen_movi_tl(hex_gpr[HEX_REG_PC], ctx->pkt->pc); \ TCGv excp = tcg_constant_tl(HEX_EXCP_TRAP0); \ - gen_helper_raise_exception(cpu_env, excp); \ + gen_helper_raise_exception(tcg_env, excp); \ } while (0) #endif diff --git a/target/hexagon/gen_tcg_funcs.py b/target/hexagon/gen_tcg_funcs.py index fe29d83d4d..f5246cee6d 100755 --- a/target/hexagon/gen_tcg_funcs.py +++ b/target/hexagon/gen_tcg_funcs.py @@ -120,7 +120,7 @@ def genptr_decl(f, tag, regtype, regid, regno): if not hex_common.skip_qemu_helper(tag): f.write(f" TCGv_ptr {regtype}{regid}V = " "tcg_temp_new_ptr();\n") f.write( - f" tcg_gen_addi_ptr({regtype}{regid}V, cpu_env, " + f" tcg_gen_addi_ptr({regtype}{regid}V, tcg_env, " f"{regtype}{regid}V_off);\n" ) elif regid in {"uu", "vv", "xx"}: @@ -130,7 +130,7 @@ def genptr_decl(f, tag, regtype, regid, regno): if not hex_common.skip_qemu_helper(tag): f.write(f" TCGv_ptr {regtype}{regid}V = " "tcg_temp_new_ptr();\n") f.write( - f" tcg_gen_addi_ptr({regtype}{regid}V, cpu_env, " + f" tcg_gen_addi_ptr({regtype}{regid}V, tcg_env, " f"{regtype}{regid}V_off);\n" ) elif regid in {"s", "u", "v", "w"}: @@ -155,7 +155,7 @@ def genptr_decl(f, tag, regtype, regid, regno): if not hex_common.skip_qemu_helper(tag): f.write(f" TCGv_ptr {regtype}{regid}V = " "tcg_temp_new_ptr();\n") f.write( - f" tcg_gen_addi_ptr({regtype}{regid}V, cpu_env, " + f" tcg_gen_addi_ptr({regtype}{regid}V, tcg_env, " f"{regtype}{regid}V_off);\n" ) else: @@ -168,7 +168,7 @@ def genptr_decl(f, tag, regtype, regid, regno): if not hex_common.skip_qemu_helper(tag): f.write(f" TCGv_ptr {regtype}{regid}V = " "tcg_temp_new_ptr();\n") f.write( - f" tcg_gen_addi_ptr({regtype}{regid}V, cpu_env, " + f" tcg_gen_addi_ptr({regtype}{regid}V, tcg_env, " f"{regtype}{regid}V_off);\n" ) elif regid in {"s", "t", "u", "v"}: @@ -303,7 +303,7 @@ def genptr_src_read(f, tag, regtype, regid): elif regid in {"s", "u", "v", "w"}: if not hex_common.skip_qemu_helper(tag): f.write( - f" tcg_gen_addi_ptr({regtype}{regid}V, cpu_env, " + f" tcg_gen_addi_ptr({regtype}{regid}V, tcg_env, " f"{regtype}{regid}V_off);\n" ) elif regid in {"x", "y"}: @@ -316,7 +316,7 @@ def genptr_src_read(f, tag, regtype, regid): if regid in {"s", "t", "u", "v"}: if not hex_common.skip_qemu_helper(tag): f.write( - f" tcg_gen_addi_ptr({regtype}{regid}V, cpu_env, " + f" tcg_gen_addi_ptr({regtype}{regid}V, tcg_env, " f"{regtype}{regid}V_off);\n" ) elif regid in {"x"}: @@ -490,7 +490,7 @@ def genptr_dst_write_opn(f, regtype, regid, tag): ## if hex_common.skip_qemu_helper(tag) is True ## is fGEN_TCG_A2_add({ RdV=RsV+RtV;}); ## if hex_common.skip_qemu_helper(tag) is False -## is gen_helper_A2_add(RdV, cpu_env, RsV, RtV); +## is gen_helper_A2_add(RdV, tcg_env, RsV, RtV); ## def gen_tcg_func(f, tag, regs, imms): f.write(f"static void generate_{tag}(DisasContext *ctx)\n") @@ -572,7 +572,7 @@ def gen_tcg_func(f, tag, regs, imms): i += 1 if i > 0: f.write(", ") - f.write("cpu_env") + f.write("tcg_env") i = 1 ## For conditional instructions, we pass in the destination register if "A_CONDEXEC" in hex_common.attribdict[tag]: diff --git a/target/hexagon/gen_tcg_hvx.h b/target/hexagon/gen_tcg_hvx.h index 44bae53f8d..0da64d467e 100644 --- a/target/hexagon/gen_tcg_hvx.h +++ b/target/hexagon/gen_tcg_hvx.h @@ -43,7 +43,7 @@ static inline void assert_vhist_tmp(DisasContext *ctx) #define fGEN_TCG_V6_vhist(SHORTCODE) \ if (!ctx->pre_commit) { \ assert_vhist_tmp(ctx); \ - gen_helper_vhist(cpu_env); \ + gen_helper_vhist(tcg_env); \ } #define fGEN_TCG_V6_vhistq(SHORTCODE) \ do { \ @@ -53,13 +53,13 @@ static inline void assert_vhist_tmp(DisasContext *ctx) sizeof(MMVector), sizeof(MMVector)); \ } else { \ assert_vhist_tmp(ctx); \ - gen_helper_vhistq(cpu_env); \ + gen_helper_vhistq(tcg_env); \ } \ } while (0) #define fGEN_TCG_V6_vwhist256(SHORTCODE) \ if (!ctx->pre_commit) { \ assert_vhist_tmp(ctx); \ - gen_helper_vwhist256(cpu_env); \ + gen_helper_vwhist256(tcg_env); \ } #define fGEN_TCG_V6_vwhist256q(SHORTCODE) \ do { \ @@ -69,13 +69,13 @@ static inline void assert_vhist_tmp(DisasContext *ctx) sizeof(MMVector), sizeof(MMVector)); \ } else { \ assert_vhist_tmp(ctx); \ - gen_helper_vwhist256q(cpu_env); \ + gen_helper_vwhist256q(tcg_env); \ } \ } while (0) #define fGEN_TCG_V6_vwhist256_sat(SHORTCODE) \ if (!ctx->pre_commit) { \ assert_vhist_tmp(ctx); \ - gen_helper_vwhist256_sat(cpu_env); \ + gen_helper_vwhist256_sat(tcg_env); \ } #define fGEN_TCG_V6_vwhist256q_sat(SHORTCODE) \ do { \ @@ -85,13 +85,13 @@ static inline void assert_vhist_tmp(DisasContext *ctx) sizeof(MMVector), sizeof(MMVector)); \ } else { \ assert_vhist_tmp(ctx); \ - gen_helper_vwhist256q_sat(cpu_env); \ + gen_helper_vwhist256q_sat(tcg_env); \ } \ } while (0) #define fGEN_TCG_V6_vwhist128(SHORTCODE) \ if (!ctx->pre_commit) { \ assert_vhist_tmp(ctx); \ - gen_helper_vwhist128(cpu_env); \ + gen_helper_vwhist128(tcg_env); \ } #define fGEN_TCG_V6_vwhist128q(SHORTCODE) \ do { \ @@ -101,14 +101,14 @@ static inline void assert_vhist_tmp(DisasContext *ctx) sizeof(MMVector), sizeof(MMVector)); \ } else { \ assert_vhist_tmp(ctx); \ - gen_helper_vwhist128q(cpu_env); \ + gen_helper_vwhist128q(tcg_env); \ } \ } while (0) #define fGEN_TCG_V6_vwhist128m(SHORTCODE) \ if (!ctx->pre_commit) { \ TCGv tcgv_uiV = tcg_constant_tl(uiV); \ assert_vhist_tmp(ctx); \ - gen_helper_vwhist128m(cpu_env, tcgv_uiV); \ + gen_helper_vwhist128m(tcg_env, tcgv_uiV); \ } #define fGEN_TCG_V6_vwhist128qm(SHORTCODE) \ do { \ @@ -119,7 +119,7 @@ static inline void assert_vhist_tmp(DisasContext *ctx) } else { \ TCGv tcgv_uiV = tcg_constant_tl(uiV); \ assert_vhist_tmp(ctx); \ - gen_helper_vwhist128qm(cpu_env, tcgv_uiV); \ + gen_helper_vwhist128qm(tcg_env, tcgv_uiV); \ } \ } while (0) diff --git a/target/hexagon/genptr.c b/target/hexagon/genptr.c index 217bc7bb5a..dbae6c570a 100644 --- a/target/hexagon/genptr.c +++ b/target/hexagon/genptr.c @@ -414,50 +414,50 @@ void gen_store32(TCGv vaddr, TCGv src, int width, uint32_t slot) tcg_gen_mov_tl(hex_store_val32[slot], src); } -void gen_store1(TCGv_env cpu_env, TCGv vaddr, TCGv src, uint32_t slot) +void gen_store1(TCGv_env tcg_env, TCGv vaddr, TCGv src, uint32_t slot) { gen_store32(vaddr, src, 1, slot); } -void gen_store1i(TCGv_env cpu_env, TCGv vaddr, int32_t src, uint32_t slot) +void gen_store1i(TCGv_env tcg_env, TCGv vaddr, int32_t src, uint32_t slot) { TCGv tmp = tcg_constant_tl(src); - gen_store1(cpu_env, vaddr, tmp, slot); + gen_store1(tcg_env, vaddr, tmp, slot); } -void gen_store2(TCGv_env cpu_env, TCGv vaddr, TCGv src, uint32_t slot) +void gen_store2(TCGv_env tcg_env, TCGv vaddr, TCGv src, uint32_t slot) { gen_store32(vaddr, src, 2, slot); } -void gen_store2i(TCGv_env cpu_env, TCGv vaddr, int32_t src, uint32_t slot) +void gen_store2i(TCGv_env tcg_env, TCGv vaddr, int32_t src, uint32_t slot) { TCGv tmp = tcg_constant_tl(src); - gen_store2(cpu_env, vaddr, tmp, slot); + gen_store2(tcg_env, vaddr, tmp, slot); } -void gen_store4(TCGv_env cpu_env, TCGv vaddr, TCGv src, uint32_t slot) +void gen_store4(TCGv_env tcg_env, TCGv vaddr, TCGv src, uint32_t slot) { gen_store32(vaddr, src, 4, slot); } -void gen_store4i(TCGv_env cpu_env, TCGv vaddr, int32_t src, uint32_t slot) +void gen_store4i(TCGv_env tcg_env, TCGv vaddr, int32_t src, uint32_t slot) { TCGv tmp = tcg_constant_tl(src); - gen_store4(cpu_env, vaddr, tmp, slot); + gen_store4(tcg_env, vaddr, tmp, slot); } -void gen_store8(TCGv_env cpu_env, TCGv vaddr, TCGv_i64 src, uint32_t slot) +void gen_store8(TCGv_env tcg_env, TCGv vaddr, TCGv_i64 src, uint32_t slot) { tcg_gen_mov_tl(hex_store_addr[slot], vaddr); tcg_gen_movi_tl(hex_store_width[slot], 8); tcg_gen_mov_i64(hex_store_val64[slot], src); } -void gen_store8i(TCGv_env cpu_env, TCGv vaddr, int64_t src, uint32_t slot) +void gen_store8i(TCGv_env tcg_env, TCGv vaddr, int64_t src, uint32_t slot) { TCGv_i64 tmp = tcg_constant_i64(src); - gen_store8(cpu_env, vaddr, tmp, slot); + gen_store8(tcg_env, vaddr, tmp, slot); } TCGv gen_8bitsof(TCGv result, TCGv value) @@ -783,7 +783,7 @@ static void gen_allocframe(DisasContext *ctx, TCGv r29, int framesize) TCGv_i64 frame; tcg_gen_addi_tl(r30, r29, -8); frame = gen_frame_scramble(); - gen_store8(cpu_env, r30, frame, ctx->insn->slot); + gen_store8(tcg_env, r30, frame, ctx->insn->slot); gen_log_reg_write(ctx, HEX_REG_FP, r30); gen_framecheck(r30, framesize); tcg_gen_subi_tl(r29, r30, framesize); @@ -1239,7 +1239,7 @@ static void gen_vreg_load(DisasContext *ctx, intptr_t dstoff, TCGv src, for (int i = 0; i < sizeof(MMVector) / 8; i++) { tcg_gen_qemu_ld_i64(tmp, src, ctx->mem_idx, MO_TEUQ); tcg_gen_addi_tl(src, src, 8); - tcg_gen_st_i64(tmp, cpu_env, dstoff + i * 8); + tcg_gen_st_i64(tmp, tcg_env, dstoff + i * 8); } } @@ -1251,7 +1251,7 @@ static void gen_vreg_store(DisasContext *ctx, TCGv EA, intptr_t srcoff, if (is_gather_store_insn(ctx)) { TCGv sl = tcg_constant_tl(slot); - gen_helper_gather_store(cpu_env, EA, sl); + gen_helper_gather_store(tcg_env, EA, sl); return; } @@ -1301,7 +1301,7 @@ static void vec_to_qvec(size_t size, intptr_t dstoff, intptr_t srcoff) TCGv_i64 ones = tcg_constant_i64(~0); for (int i = 0; i < sizeof(MMVector) / 8; i++) { - tcg_gen_ld_i64(tmp, cpu_env, srcoff + i * 8); + tcg_gen_ld_i64(tmp, tcg_env, srcoff + i * 8); tcg_gen_movi_i64(mask, 0); for (int j = 0; j < 8; j += size) { @@ -1310,7 +1310,7 @@ static void vec_to_qvec(size_t size, intptr_t dstoff, intptr_t srcoff) tcg_gen_deposit_i64(mask, mask, bits, j, size); } - tcg_gen_st8_i64(mask, cpu_env, dstoff + i); + tcg_gen_st8_i64(mask, tcg_env, dstoff + i); } } @@ -1318,7 +1318,7 @@ void probe_noshuf_load(TCGv va, int s, int mi) { TCGv size = tcg_constant_tl(s); TCGv mem_idx = tcg_constant_tl(mi); - gen_helper_probe_noshuf_load(cpu_env, va, size, mem_idx); + gen_helper_probe_noshuf_load(tcg_env, va, size, mem_idx); } /* diff --git a/target/hexagon/idef-parser/parser-helpers.c b/target/hexagon/idef-parser/parser-helpers.c index ec43343801..4af020933a 100644 --- a/target/hexagon/idef-parser/parser-helpers.c +++ b/target/hexagon/idef-parser/parser-helpers.c @@ -1773,7 +1773,7 @@ void gen_store(Context *c, YYLTYPE *locp, HexValue *width, HexValue *ea, /* Lookup the effective address EA */ find_variable(c, locp, ea, ea); src_m = rvalue_materialize(c, locp, &src_m); - OUT(c, locp, "gen_store", &mem_width, "(cpu_env, ", ea, ", ", &src_m); + OUT(c, locp, "gen_store", &mem_width, "(tcg_env, ", ea, ", ", &src_m); OUT(c, locp, ", insn->slot);\n"); } diff --git a/target/hexagon/macros.h b/target/hexagon/macros.h index 5451b061ee..b356d85792 100644 --- a/target/hexagon/macros.h +++ b/target/hexagon/macros.h @@ -147,7 +147,7 @@ __builtin_choose_expr(TYPE_TCGV(X), \ gen_store1, (void)0)) #define MEM_STORE1(VA, DATA, SLOT) \ - MEM_STORE1_FUNC(DATA)(cpu_env, VA, DATA, SLOT) + MEM_STORE1_FUNC(DATA)(tcg_env, VA, DATA, SLOT) #define MEM_STORE2_FUNC(X) \ __builtin_choose_expr(TYPE_INT(X), \ @@ -155,7 +155,7 @@ __builtin_choose_expr(TYPE_TCGV(X), \ gen_store2, (void)0)) #define MEM_STORE2(VA, DATA, SLOT) \ - MEM_STORE2_FUNC(DATA)(cpu_env, VA, DATA, SLOT) + MEM_STORE2_FUNC(DATA)(tcg_env, VA, DATA, SLOT) #define MEM_STORE4_FUNC(X) \ __builtin_choose_expr(TYPE_INT(X), \ @@ -163,7 +163,7 @@ __builtin_choose_expr(TYPE_TCGV(X), \ gen_store4, (void)0)) #define MEM_STORE4(VA, DATA, SLOT) \ - MEM_STORE4_FUNC(DATA)(cpu_env, VA, DATA, SLOT) + MEM_STORE4_FUNC(DATA)(tcg_env, VA, DATA, SLOT) #define MEM_STORE8_FUNC(X) \ __builtin_choose_expr(TYPE_INT(X), \ @@ -171,7 +171,7 @@ __builtin_choose_expr(TYPE_TCGV_I64(X), \ gen_store8, (void)0)) #define MEM_STORE8(VA, DATA, SLOT) \ - MEM_STORE8_FUNC(DATA)(cpu_env, VA, DATA, SLOT) + MEM_STORE8_FUNC(DATA)(tcg_env, VA, DATA, SLOT) #else #define MEM_LOAD1s(VA) ((int8_t)mem_load1(env, pkt_has_store_s1, slot, VA)) #define MEM_LOAD1u(VA) ((uint8_t)mem_load1(env, pkt_has_store_s1, slot, VA)) diff --git a/target/hexagon/translate.c b/target/hexagon/translate.c index c00254e4d5..012c3c68ec 100644 --- a/target/hexagon/translate.c +++ b/target/hexagon/translate.c @@ -115,7 +115,7 @@ intptr_t ctx_tmp_vreg_off(DisasContext *ctx, int regnum, static void gen_exception_raw(int excp) { - gen_helper_raise_exception(cpu_env, tcg_constant_i32(excp)); + gen_helper_raise_exception(tcg_env, tcg_constant_i32(excp)); } static void gen_exec_counters(DisasContext *ctx) @@ -528,7 +528,7 @@ static void gen_start_packet(DisasContext *ctx) if (HEX_DEBUG) { /* Handy place to set a breakpoint before the packet executes */ - gen_helper_debug_start_packet(cpu_env); + gen_helper_debug_start_packet(tcg_env); } /* Initialize the runtime state for packet semantics */ @@ -701,7 +701,7 @@ static void gen_check_store_width(DisasContext *ctx, int slot_num) if (HEX_DEBUG) { TCGv slot = tcg_constant_tl(slot_num); TCGv check = tcg_constant_tl(ctx->store_width[slot_num]); - gen_helper_debug_check_store_width(cpu_env, slot, check); + gen_helper_debug_check_store_width(tcg_env, slot, check); } } @@ -783,7 +783,7 @@ void process_store(DisasContext *ctx, int slot_num) * avoid branching based on the width at runtime. */ TCGv slot = tcg_constant_tl(slot_num); - gen_helper_commit_store(cpu_env, slot); + gen_helper_commit_store(tcg_env, slot); } } } @@ -882,7 +882,7 @@ static void gen_commit_hvx(DisasContext *ctx) } if (pkt_has_hvx_store(ctx->pkt)) { - gen_helper_commit_hvx_stores(cpu_env); + gen_helper_commit_hvx_stores(tcg_env); } } @@ -942,7 +942,7 @@ static void gen_commit_packet(DisasContext *ctx) } else if (has_hvx_store) { if (!has_store_s0 && !has_store_s1) { TCGv mem_idx = tcg_constant_tl(ctx->mem_idx); - gen_helper_probe_hvx_stores(cpu_env, mem_idx); + gen_helper_probe_hvx_stores(tcg_env, mem_idx); } else { int mask = 0; @@ -971,7 +971,7 @@ static void gen_commit_packet(DisasContext *ctx) } mask = FIELD_DP32(mask, PROBE_PKT_SCALAR_HVX_STORES, MMU_IDX, ctx->mem_idx); - gen_helper_probe_pkt_scalar_hvx_stores(cpu_env, + gen_helper_probe_pkt_scalar_hvx_stores(tcg_env, tcg_constant_tl(mask)); } } else if (has_store_s0 && has_store_s1) { @@ -987,7 +987,7 @@ static void gen_commit_packet(DisasContext *ctx) FIELD_DP32(args, PROBE_PKT_SCALAR_STORE_S0, IS_PREDICATED, 1); } TCGv args_tcgv = tcg_constant_tl(args); - gen_helper_probe_pkt_scalar_store_s0(cpu_env, args_tcgv); + gen_helper_probe_pkt_scalar_store_s0(tcg_env, args_tcgv); } process_store_log(ctx); @@ -1005,7 +1005,7 @@ static void gen_commit_packet(DisasContext *ctx) tcg_constant_tl(pkt->pkt_has_store_s1 && !pkt->pkt_has_dczeroa); /* Handy place to set a breakpoint at the end of execution */ - gen_helper_debug_commit_end(cpu_env, tcg_constant_tl(ctx->pkt->pc), + gen_helper_debug_commit_end(tcg_env, tcg_constant_tl(ctx->pkt->pc), ctx->pred_written, has_st0, has_st1); } @@ -1179,68 +1179,68 @@ void hexagon_translate_init(void) opcode_init(); for (i = 0; i < TOTAL_PER_THREAD_REGS; i++) { - hex_gpr[i] = tcg_global_mem_new(cpu_env, + hex_gpr[i] = tcg_global_mem_new(tcg_env, offsetof(CPUHexagonState, gpr[i]), hexagon_regnames[i]); if (HEX_DEBUG) { snprintf(reg_written_names[i], NAME_LEN, "reg_written_%s", hexagon_regnames[i]); - hex_reg_written[i] = tcg_global_mem_new(cpu_env, + hex_reg_written[i] = tcg_global_mem_new(tcg_env, offsetof(CPUHexagonState, reg_written[i]), reg_written_names[i]); } } - hex_new_value_usr = tcg_global_mem_new(cpu_env, + hex_new_value_usr = tcg_global_mem_new(tcg_env, offsetof(CPUHexagonState, new_value_usr), "new_value_usr"); for (i = 0; i < NUM_PREGS; i++) { - hex_pred[i] = tcg_global_mem_new(cpu_env, + hex_pred[i] = tcg_global_mem_new(tcg_env, offsetof(CPUHexagonState, pred[i]), hexagon_prednames[i]); } - hex_slot_cancelled = tcg_global_mem_new(cpu_env, + hex_slot_cancelled = tcg_global_mem_new(tcg_env, offsetof(CPUHexagonState, slot_cancelled), "slot_cancelled"); - hex_llsc_addr = tcg_global_mem_new(cpu_env, + hex_llsc_addr = tcg_global_mem_new(tcg_env, offsetof(CPUHexagonState, llsc_addr), "llsc_addr"); - hex_llsc_val = tcg_global_mem_new(cpu_env, + hex_llsc_val = tcg_global_mem_new(tcg_env, offsetof(CPUHexagonState, llsc_val), "llsc_val"); - hex_llsc_val_i64 = tcg_global_mem_new_i64(cpu_env, + hex_llsc_val_i64 = tcg_global_mem_new_i64(tcg_env, offsetof(CPUHexagonState, llsc_val_i64), "llsc_val_i64"); for (i = 0; i < STORES_MAX; i++) { snprintf(store_addr_names[i], NAME_LEN, "store_addr_%d", i); - hex_store_addr[i] = tcg_global_mem_new(cpu_env, + hex_store_addr[i] = tcg_global_mem_new(tcg_env, offsetof(CPUHexagonState, mem_log_stores[i].va), store_addr_names[i]); snprintf(store_width_names[i], NAME_LEN, "store_width_%d", i); - hex_store_width[i] = tcg_global_mem_new(cpu_env, + hex_store_width[i] = tcg_global_mem_new(tcg_env, offsetof(CPUHexagonState, mem_log_stores[i].width), store_width_names[i]); snprintf(store_val32_names[i], NAME_LEN, "store_val32_%d", i); - hex_store_val32[i] = tcg_global_mem_new(cpu_env, + hex_store_val32[i] = tcg_global_mem_new(tcg_env, offsetof(CPUHexagonState, mem_log_stores[i].data32), store_val32_names[i]); snprintf(store_val64_names[i], NAME_LEN, "store_val64_%d", i); - hex_store_val64[i] = tcg_global_mem_new_i64(cpu_env, + hex_store_val64[i] = tcg_global_mem_new_i64(tcg_env, offsetof(CPUHexagonState, mem_log_stores[i].data64), store_val64_names[i]); } for (int i = 0; i < VSTORES_MAX; i++) { snprintf(vstore_addr_names[i], NAME_LEN, "vstore_addr_%d", i); - hex_vstore_addr[i] = tcg_global_mem_new(cpu_env, + hex_vstore_addr[i] = tcg_global_mem_new(tcg_env, offsetof(CPUHexagonState, vstore[i].va), vstore_addr_names[i]); snprintf(vstore_size_names[i], NAME_LEN, "vstore_size_%d", i); - hex_vstore_size[i] = tcg_global_mem_new(cpu_env, + hex_vstore_size[i] = tcg_global_mem_new(tcg_env, offsetof(CPUHexagonState, vstore[i].size), vstore_size_names[i]); snprintf(vstore_pending_names[i], NAME_LEN, "vstore_pending_%d", i); - hex_vstore_pending[i] = tcg_global_mem_new(cpu_env, + hex_vstore_pending[i] = tcg_global_mem_new(tcg_env, offsetof(CPUHexagonState, vstore_pending[i]), vstore_pending_names[i]); } diff --git a/target/hppa/translate.c b/target/hppa/translate.c index 650bbcfe95..0c67d71c75 100644 --- a/target/hppa/translate.c +++ b/target/hppa/translate.c @@ -396,28 +396,28 @@ void hppa_translate_init(void) cpu_gr[0] = NULL; for (i = 1; i < 32; i++) { - cpu_gr[i] = tcg_global_mem_new(cpu_env, + cpu_gr[i] = tcg_global_mem_new(tcg_env, offsetof(CPUHPPAState, gr[i]), gr_names[i]); } for (i = 0; i < 4; i++) { - cpu_sr[i] = tcg_global_mem_new_i64(cpu_env, + cpu_sr[i] = tcg_global_mem_new_i64(tcg_env, offsetof(CPUHPPAState, sr[i]), sr_names[i]); } - cpu_srH = tcg_global_mem_new_i64(cpu_env, + cpu_srH = tcg_global_mem_new_i64(tcg_env, offsetof(CPUHPPAState, sr[4]), sr_names[4]); for (i = 0; i < ARRAY_SIZE(vars); ++i) { const GlobalVar *v = &vars[i]; - *v->var = tcg_global_mem_new(cpu_env, v->ofs, v->name); + *v->var = tcg_global_mem_new(tcg_env, v->ofs, v->name); } - cpu_iasq_f = tcg_global_mem_new_i64(cpu_env, + cpu_iasq_f = tcg_global_mem_new_i64(tcg_env, offsetof(CPUHPPAState, iasq_f), "iasq_f"); - cpu_iasq_b = tcg_global_mem_new_i64(cpu_env, + cpu_iasq_b = tcg_global_mem_new_i64(tcg_env, offsetof(CPUHPPAState, iasq_b), "iasq_b"); } @@ -563,7 +563,7 @@ static void save_gpr(DisasContext *ctx, unsigned reg, TCGv_reg t) static TCGv_i32 load_frw_i32(unsigned rt) { TCGv_i32 ret = tcg_temp_new_i32(); - tcg_gen_ld_i32(ret, cpu_env, + tcg_gen_ld_i32(ret, tcg_env, offsetof(CPUHPPAState, fr[rt & 31]) + (rt & 32 ? LO_OFS : HI_OFS)); return ret; @@ -586,7 +586,7 @@ static TCGv_i64 load_frw0_i64(unsigned rt) if (rt == 0) { tcg_gen_movi_i64(ret, 0); } else { - tcg_gen_ld32u_i64(ret, cpu_env, + tcg_gen_ld32u_i64(ret, tcg_env, offsetof(CPUHPPAState, fr[rt & 31]) + (rt & 32 ? LO_OFS : HI_OFS)); } @@ -595,7 +595,7 @@ static TCGv_i64 load_frw0_i64(unsigned rt) static void save_frw_i32(unsigned rt, TCGv_i32 val) { - tcg_gen_st_i32(val, cpu_env, + tcg_gen_st_i32(val, tcg_env, offsetof(CPUHPPAState, fr[rt & 31]) + (rt & 32 ? LO_OFS : HI_OFS)); } @@ -606,7 +606,7 @@ static void save_frw_i32(unsigned rt, TCGv_i32 val) static TCGv_i64 load_frd(unsigned rt) { TCGv_i64 ret = tcg_temp_new_i64(); - tcg_gen_ld_i64(ret, cpu_env, offsetof(CPUHPPAState, fr[rt])); + tcg_gen_ld_i64(ret, tcg_env, offsetof(CPUHPPAState, fr[rt])); return ret; } @@ -623,7 +623,7 @@ static TCGv_i64 load_frd0(unsigned rt) static void save_frd(unsigned rt, TCGv_i64 val) { - tcg_gen_st_i64(val, cpu_env, offsetof(CPUHPPAState, fr[rt])); + tcg_gen_st_i64(val, tcg_env, offsetof(CPUHPPAState, fr[rt])); } static void load_spr(DisasContext *ctx, TCGv_i64 dest, unsigned reg) @@ -636,7 +636,7 @@ static void load_spr(DisasContext *ctx, TCGv_i64 dest, unsigned reg) } else if (ctx->tb_flags & TB_FLAG_SR_SAME) { tcg_gen_mov_i64(dest, cpu_srH); } else { - tcg_gen_ld_i64(dest, cpu_env, offsetof(CPUHPPAState, sr[reg])); + tcg_gen_ld_i64(dest, tcg_env, offsetof(CPUHPPAState, sr[reg])); } #endif } @@ -752,7 +752,7 @@ static inline target_ureg iaoq_dest(DisasContext *ctx, target_sreg disp) static void gen_excp_1(int exception) { - gen_helper_excp(cpu_env, tcg_constant_i32(exception)); + gen_helper_excp(tcg_env, tcg_constant_i32(exception)); } static void gen_excp(DisasContext *ctx, int exception) @@ -768,7 +768,7 @@ static bool gen_excp_iir(DisasContext *ctx, int exc) { nullify_over(ctx); tcg_gen_st_reg(tcg_constant_reg(ctx->insn), - cpu_env, offsetof(CPUHPPAState, cr[CR_IIR])); + tcg_env, offsetof(CPUHPPAState, cr[CR_IIR])); gen_excp(ctx, exc); return nullify_end(ctx); } @@ -1138,7 +1138,7 @@ static void do_add(DisasContext *ctx, unsigned rt, TCGv_reg in1, sv = do_add_sv(ctx, dest, in1, in2); if (is_tsv) { /* ??? Need to include overflow from shift. */ - gen_helper_tsv(cpu_env, sv); + gen_helper_tsv(tcg_env, sv); } } @@ -1147,7 +1147,7 @@ static void do_add(DisasContext *ctx, unsigned rt, TCGv_reg in1, if (is_tc) { tmp = tcg_temp_new(); tcg_gen_setcond_reg(cond.c, tmp, cond.a0, cond.a1); - gen_helper_tcond(cpu_env, tmp); + gen_helper_tcond(tcg_env, tmp); } /* Write back the result. */ @@ -1224,7 +1224,7 @@ static void do_sub(DisasContext *ctx, unsigned rt, TCGv_reg in1, if (is_tsv || cond_need_sv(c)) { sv = do_sub_sv(ctx, dest, in1, in2); if (is_tsv) { - gen_helper_tsv(cpu_env, sv); + gen_helper_tsv(tcg_env, sv); } } @@ -1239,7 +1239,7 @@ static void do_sub(DisasContext *ctx, unsigned rt, TCGv_reg in1, if (is_tc) { tmp = tcg_temp_new(); tcg_gen_setcond_reg(cond.c, tmp, cond.a0, cond.a1); - gen_helper_tcond(cpu_env, tmp); + gen_helper_tcond(tcg_env, tmp); } /* Write back the result. */ @@ -1358,7 +1358,7 @@ static void do_unit(DisasContext *ctx, unsigned rt, TCGv_reg in1, if (is_tc) { TCGv_reg tmp = tcg_temp_new(); tcg_gen_setcond_reg(cond.c, tmp, cond.a0, cond.a1); - gen_helper_tcond(cpu_env, tmp); + gen_helper_tcond(tcg_env, tmp); } save_gpr(ctx, rt, dest); @@ -1398,7 +1398,7 @@ static TCGv_i64 space_select(DisasContext *ctx, int sp, TCGv_reg base) tcg_gen_andi_reg(tmp, tmp, 030); tcg_gen_trunc_reg_ptr(ptr, tmp); - tcg_gen_add_ptr(ptr, ptr, cpu_env); + tcg_gen_add_ptr(ptr, ptr, tcg_env); tcg_gen_ld_i64(spc, ptr, offsetof(CPUHPPAState, sr[4])); return spc; @@ -1559,7 +1559,7 @@ static bool do_floadw(DisasContext *ctx, unsigned rt, unsigned rb, save_frw_i32(rt, tmp); if (rt == 0) { - gen_helper_loaded_fr0(cpu_env); + gen_helper_loaded_fr0(tcg_env); } return nullify_end(ctx); @@ -1584,7 +1584,7 @@ static bool do_floadd(DisasContext *ctx, unsigned rt, unsigned rb, save_frd(rt, tmp); if (rt == 0) { - gen_helper_loaded_fr0(cpu_env); + gen_helper_loaded_fr0(tcg_env); } return nullify_end(ctx); @@ -1653,7 +1653,7 @@ static bool do_fop_wew(DisasContext *ctx, unsigned rt, unsigned ra, nullify_over(ctx); tmp = load_frw0_i32(ra); - func(tmp, cpu_env, tmp); + func(tmp, tcg_env, tmp); save_frw_i32(rt, tmp); return nullify_end(ctx); @@ -1669,7 +1669,7 @@ static bool do_fop_wed(DisasContext *ctx, unsigned rt, unsigned ra, src = load_frd(ra); dst = tcg_temp_new_i32(); - func(dst, cpu_env, src); + func(dst, tcg_env, src); save_frw_i32(rt, dst); return nullify_end(ctx); @@ -1683,7 +1683,7 @@ static bool do_fop_ded(DisasContext *ctx, unsigned rt, unsigned ra, nullify_over(ctx); tmp = load_frd0(ra); - func(tmp, cpu_env, tmp); + func(tmp, tcg_env, tmp); save_frd(rt, tmp); return nullify_end(ctx); @@ -1699,7 +1699,7 @@ static bool do_fop_dew(DisasContext *ctx, unsigned rt, unsigned ra, src = load_frw0_i32(ra); dst = tcg_temp_new_i64(); - func(dst, cpu_env, src); + func(dst, tcg_env, src); save_frd(rt, dst); return nullify_end(ctx); @@ -1715,7 +1715,7 @@ static bool do_fop_weww(DisasContext *ctx, unsigned rt, a = load_frw0_i32(ra); b = load_frw0_i32(rb); - func(a, cpu_env, a, b); + func(a, tcg_env, a, b); save_frw_i32(rt, a); return nullify_end(ctx); @@ -1731,7 +1731,7 @@ static bool do_fop_dedd(DisasContext *ctx, unsigned rt, a = load_frd0(ra); b = load_frd0(rb); - func(a, cpu_env, a, b); + func(a, tcg_env, a, b); save_frd(rt, a); return nullify_end(ctx); @@ -1996,7 +1996,7 @@ static void do_page_zero(DisasContext *ctx) break; case 0xe0: /* SET_THREAD_POINTER */ - tcg_gen_st_reg(cpu_gr[26], cpu_env, offsetof(CPUHPPAState, cr[27])); + tcg_gen_st_reg(cpu_gr[26], tcg_env, offsetof(CPUHPPAState, cr[27])); tcg_gen_ori_reg(cpu_iaoq_f, cpu_gr[31], 3); tcg_gen_addi_reg(cpu_iaoq_b, cpu_iaoq_f, 4); ctx->base.is_jmp = DISAS_IAQ_N_UPDATED; @@ -2105,7 +2105,7 @@ static bool trans_mfctl(DisasContext *ctx, arg_mfctl *a) } tmp = get_temp(ctx); - tcg_gen_ld_reg(tmp, cpu_env, offsetof(CPUHPPAState, cr[ctl])); + tcg_gen_ld_reg(tmp, tcg_env, offsetof(CPUHPPAState, cr[ctl])); save_gpr(ctx, rt, tmp); done: @@ -2129,7 +2129,7 @@ static bool trans_mtsp(DisasContext *ctx, arg_mtsp *a) tcg_gen_shli_i64(t64, t64, 32); if (rs >= 4) { - tcg_gen_st_i64(t64, cpu_env, offsetof(CPUHPPAState, sr[rs])); + tcg_gen_st_i64(t64, tcg_env, offsetof(CPUHPPAState, sr[rs])); ctx->tb_flags &= ~TB_FLAG_SR_SAME; } else { tcg_gen_mov_i64(cpu_sr[rs], t64); @@ -2163,13 +2163,13 @@ static bool trans_mtctl(DisasContext *ctx, arg_mtctl *a) switch (ctl) { case CR_IT: - gen_helper_write_interval_timer(cpu_env, reg); + gen_helper_write_interval_timer(tcg_env, reg); break; case CR_EIRR: - gen_helper_write_eirr(cpu_env, reg); + gen_helper_write_eirr(tcg_env, reg); break; case CR_EIEM: - gen_helper_write_eiem(cpu_env, reg); + gen_helper_write_eiem(tcg_env, reg); ctx->base.is_jmp = DISAS_IAQ_N_STALE_EXIT; break; @@ -2178,10 +2178,10 @@ static bool trans_mtctl(DisasContext *ctx, arg_mtctl *a) /* FIXME: Respect PSW_Q bit */ /* The write advances the queue and stores to the back element. */ tmp = get_temp(ctx); - tcg_gen_ld_reg(tmp, cpu_env, + tcg_gen_ld_reg(tmp, tcg_env, offsetof(CPUHPPAState, cr_back[ctl - CR_IIASQ])); - tcg_gen_st_reg(tmp, cpu_env, offsetof(CPUHPPAState, cr[ctl])); - tcg_gen_st_reg(reg, cpu_env, + tcg_gen_st_reg(tmp, tcg_env, offsetof(CPUHPPAState, cr[ctl])); + tcg_gen_st_reg(reg, tcg_env, offsetof(CPUHPPAState, cr_back[ctl - CR_IIASQ])); break; @@ -2189,14 +2189,14 @@ static bool trans_mtctl(DisasContext *ctx, arg_mtctl *a) case CR_PID2: case CR_PID3: case CR_PID4: - tcg_gen_st_reg(reg, cpu_env, offsetof(CPUHPPAState, cr[ctl])); + tcg_gen_st_reg(reg, tcg_env, offsetof(CPUHPPAState, cr[ctl])); #ifndef CONFIG_USER_ONLY - gen_helper_change_prot_id(cpu_env); + gen_helper_change_prot_id(tcg_env); #endif break; default: - tcg_gen_st_reg(reg, cpu_env, offsetof(CPUHPPAState, cr[ctl])); + tcg_gen_st_reg(reg, tcg_env, offsetof(CPUHPPAState, cr[ctl])); break; } return nullify_end(ctx); @@ -2244,9 +2244,9 @@ static bool trans_rsm(DisasContext *ctx, arg_rsm *a) nullify_over(ctx); tmp = get_temp(ctx); - tcg_gen_ld_reg(tmp, cpu_env, offsetof(CPUHPPAState, psw)); + tcg_gen_ld_reg(tmp, tcg_env, offsetof(CPUHPPAState, psw)); tcg_gen_andi_reg(tmp, tmp, ~a->i); - gen_helper_swap_system_mask(tmp, cpu_env, tmp); + gen_helper_swap_system_mask(tmp, tcg_env, tmp); save_gpr(ctx, a->t, tmp); /* Exit the TB to recognize new interrupts, e.g. PSW_M. */ @@ -2264,9 +2264,9 @@ static bool trans_ssm(DisasContext *ctx, arg_ssm *a) nullify_over(ctx); tmp = get_temp(ctx); - tcg_gen_ld_reg(tmp, cpu_env, offsetof(CPUHPPAState, psw)); + tcg_gen_ld_reg(tmp, tcg_env, offsetof(CPUHPPAState, psw)); tcg_gen_ori_reg(tmp, tmp, a->i); - gen_helper_swap_system_mask(tmp, cpu_env, tmp); + gen_helper_swap_system_mask(tmp, tcg_env, tmp); save_gpr(ctx, a->t, tmp); /* Exit the TB to recognize new interrupts, e.g. PSW_I. */ @@ -2284,7 +2284,7 @@ static bool trans_mtsm(DisasContext *ctx, arg_mtsm *a) reg = load_gpr(ctx, a->r); tmp = get_temp(ctx); - gen_helper_swap_system_mask(tmp, cpu_env, reg); + gen_helper_swap_system_mask(tmp, tcg_env, reg); /* Exit the TB to recognize new interrupts. */ ctx->base.is_jmp = DISAS_IAQ_N_STALE_EXIT; @@ -2299,9 +2299,9 @@ static bool do_rfi(DisasContext *ctx, bool rfi_r) nullify_over(ctx); if (rfi_r) { - gen_helper_rfi_r(cpu_env); + gen_helper_rfi_r(tcg_env); } else { - gen_helper_rfi(cpu_env); + gen_helper_rfi(tcg_env); } /* Exit the TB to recognize new interrupts. */ tcg_gen_exit_tb(NULL, 0); @@ -2326,7 +2326,7 @@ static bool trans_halt(DisasContext *ctx, arg_halt *a) CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR); #ifndef CONFIG_USER_ONLY nullify_over(ctx); - gen_helper_halt(cpu_env); + gen_helper_halt(tcg_env); ctx->base.is_jmp = DISAS_NORETURN; return nullify_end(ctx); #endif @@ -2337,7 +2337,7 @@ static bool trans_reset(DisasContext *ctx, arg_reset *a) CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR); #ifndef CONFIG_USER_ONLY nullify_over(ctx); - gen_helper_reset(cpu_env); + gen_helper_reset(tcg_env); ctx->base.is_jmp = DISAS_NORETURN; return nullify_end(ctx); #endif @@ -2348,7 +2348,7 @@ static bool trans_getshadowregs(DisasContext *ctx, arg_getshadowregs *a) CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR); #ifndef CONFIG_USER_ONLY nullify_over(ctx); - gen_helper_getshadowregs(cpu_env); + gen_helper_getshadowregs(tcg_env); return nullify_end(ctx); #endif } @@ -2388,7 +2388,7 @@ static bool trans_probe(DisasContext *ctx, arg_probe *a) } want = tcg_constant_i32(a->write ? PAGE_WRITE : PAGE_READ); - gen_helper_probe(dest, cpu_env, addr, level, want); + gen_helper_probe(dest, tcg_env, addr, level, want); save_gpr(ctx, a->t, dest); return nullify_end(ctx); @@ -2406,9 +2406,9 @@ static bool trans_ixtlbx(DisasContext *ctx, arg_ixtlbx *a) form_gva(ctx, &addr, &ofs, a->b, 0, 0, 0, a->sp, 0, false); reg = load_gpr(ctx, a->r); if (a->addr) { - gen_helper_itlba(cpu_env, addr, reg); + gen_helper_itlba(tcg_env, addr, reg); } else { - gen_helper_itlbp(cpu_env, addr, reg); + gen_helper_itlbp(tcg_env, addr, reg); } /* Exit TB for TLB change if mmu is enabled. */ @@ -2433,9 +2433,9 @@ static bool trans_pxtlbx(DisasContext *ctx, arg_pxtlbx *a) save_gpr(ctx, a->b, ofs); } if (a->local) { - gen_helper_ptlbe(cpu_env); + gen_helper_ptlbe(tcg_env); } else { - gen_helper_ptlb(cpu_env, addr); + gen_helper_ptlb(tcg_env, addr); } /* Exit TB for TLB change if mmu is enabled. */ @@ -2473,10 +2473,10 @@ static bool trans_ixtlbxf(DisasContext *ctx, arg_ixtlbxf *a) stl = tcg_temp_new_tl(); addr = tcg_temp_new_tl(); - tcg_gen_ld32u_i64(stl, cpu_env, + tcg_gen_ld32u_i64(stl, tcg_env, a->data ? offsetof(CPUHPPAState, cr[CR_ISR]) : offsetof(CPUHPPAState, cr[CR_IIASQ])); - tcg_gen_ld32u_i64(atl, cpu_env, + tcg_gen_ld32u_i64(atl, tcg_env, a->data ? offsetof(CPUHPPAState, cr[CR_IOR]) : offsetof(CPUHPPAState, cr[CR_IIAOQ])); tcg_gen_shli_i64(stl, stl, 32); @@ -2484,9 +2484,9 @@ static bool trans_ixtlbxf(DisasContext *ctx, arg_ixtlbxf *a) reg = load_gpr(ctx, a->r); if (a->addr) { - gen_helper_itlba(cpu_env, addr, reg); + gen_helper_itlba(tcg_env, addr, reg); } else { - gen_helper_itlbp(cpu_env, addr, reg); + gen_helper_itlbp(tcg_env, addr, reg); } /* Exit TB for TLB change if mmu is enabled. */ @@ -2509,7 +2509,7 @@ static bool trans_lpa(DisasContext *ctx, arg_ldst *a) form_gva(ctx, &vaddr, &ofs, a->b, a->x, 0, 0, a->sp, a->m, false); paddr = tcg_temp_new(); - gen_helper_lpa(paddr, cpu_env, vaddr); + gen_helper_lpa(paddr, tcg_env, vaddr); /* Note that physical address result overrides base modification. */ if (a->m) { @@ -2640,7 +2640,7 @@ static bool trans_or(DisasContext *ctx, arg_rrr_cf *a) nullify_set(ctx, 0); /* Tell the qemu main loop to halt until this cpu has work. */ - tcg_gen_st_i32(tcg_constant_i32(1), cpu_env, + tcg_gen_st_i32(tcg_constant_i32(1), tcg_env, offsetof(CPUState, halted) - offsetof(HPPACPU, env)); gen_excp_1(EXCP_HALTED); ctx->base.is_jmp = DISAS_NORETURN; @@ -2907,15 +2907,15 @@ static bool trans_stby(DisasContext *ctx, arg_stby *a) val = load_gpr(ctx, a->r); if (a->a) { if (tb_cflags(ctx->base.tb) & CF_PARALLEL) { - gen_helper_stby_e_parallel(cpu_env, addr, val); + gen_helper_stby_e_parallel(tcg_env, addr, val); } else { - gen_helper_stby_e(cpu_env, addr, val); + gen_helper_stby_e(tcg_env, addr, val); } } else { if (tb_cflags(ctx->base.tb) & CF_PARALLEL) { - gen_helper_stby_b_parallel(cpu_env, addr, val); + gen_helper_stby_b_parallel(tcg_env, addr, val); } else { - gen_helper_stby_b(cpu_env, addr, val); + gen_helper_stby_b(tcg_env, addr, val); } } if (a->m) { @@ -3806,7 +3806,7 @@ static bool trans_fcmp_f(DisasContext *ctx, arg_fclass2 *a) ty = tcg_constant_i32(a->y); tc = tcg_constant_i32(a->c); - gen_helper_fcmp_s(cpu_env, ta, tb, ty, tc); + gen_helper_fcmp_s(tcg_env, ta, tb, ty, tc); return nullify_end(ctx); } @@ -3823,7 +3823,7 @@ static bool trans_fcmp_d(DisasContext *ctx, arg_fclass2 *a) ty = tcg_constant_i32(a->y); tc = tcg_constant_i32(a->c); - gen_helper_fcmp_d(cpu_env, ta, tb, ty, tc); + gen_helper_fcmp_d(tcg_env, ta, tb, ty, tc); return nullify_end(ctx); } @@ -3835,7 +3835,7 @@ static bool trans_ftest(DisasContext *ctx, arg_ftest *a) nullify_over(ctx); t = get_temp(ctx); - tcg_gen_ld32u_reg(t, cpu_env, offsetof(CPUHPPAState, fr0_shadow)); + tcg_gen_ld32u_reg(t, tcg_env, offsetof(CPUHPPAState, fr0_shadow)); if (a->y == 1) { int mask; @@ -4012,9 +4012,9 @@ static bool trans_fmpyfadd_f(DisasContext *ctx, arg_fmpyfadd_f *a) z = load_frw0_i32(a->ra3); if (a->neg) { - gen_helper_fmpynfadd_s(x, cpu_env, x, y, z); + gen_helper_fmpynfadd_s(x, tcg_env, x, y, z); } else { - gen_helper_fmpyfadd_s(x, cpu_env, x, y, z); + gen_helper_fmpyfadd_s(x, tcg_env, x, y, z); } save_frw_i32(a->t, x); @@ -4031,9 +4031,9 @@ static bool trans_fmpyfadd_d(DisasContext *ctx, arg_fmpyfadd_d *a) z = load_frd0(a->ra3); if (a->neg) { - gen_helper_fmpynfadd_d(x, cpu_env, x, y, z); + gen_helper_fmpynfadd_d(x, tcg_env, x, y, z); } else { - gen_helper_fmpyfadd_d(x, cpu_env, x, y, z); + gen_helper_fmpyfadd_d(x, tcg_env, x, y, z); } save_frd(a->t, x); @@ -4042,18 +4042,17 @@ static bool trans_fmpyfadd_d(DisasContext *ctx, arg_fmpyfadd_d *a) static bool trans_diag(DisasContext *ctx, arg_diag *a) { - nullify_over(ctx); CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR); #ifndef CONFIG_USER_ONLY if (a->i == 0x100) { /* emulate PDC BTLB, called by SeaBIOS-hppa */ - gen_helper_diag_btlb(cpu_env); - } else -#endif - { - qemu_log_mask(LOG_UNIMP, "DIAG opcode 0x%04x ignored\n", a->i); + nullify_over(ctx); + gen_helper_diag_btlb(tcg_env); + return nullify_end(ctx); } - return nullify_end(ctx); +#endif + qemu_log_mask(LOG_UNIMP, "DIAG opcode 0x%04x ignored\n", a->i); + return true; } static void hppa_tr_init_disas_context(DisasContextBase *dcbase, CPUState *cs) diff --git a/target/i386/tcg/decode-new.c.inc b/target/i386/tcg/decode-new.c.inc index 0db19cda3b..af1878c38a 100644 --- a/target/i386/tcg/decode-new.c.inc +++ b/target/i386/tcg/decode-new.c.inc @@ -1822,7 +1822,7 @@ static void disas_insn_new(DisasContext *s, CPUState *cpu, int b) } if (decode.e.special == X86_SPECIAL_MMX && !(s->prefix & (PREFIX_REPZ | PREFIX_REPNZ | PREFIX_DATA))) { - gen_helper_enter_mmx(cpu_env); + gen_helper_enter_mmx(tcg_env); } if (decode.op[0].has_ea || decode.op[1].has_ea || decode.op[2].has_ea) { diff --git a/target/i386/tcg/emit.c.inc b/target/i386/tcg/emit.c.inc index 45a3e55cbf..88793ba988 100644 --- a/target/i386/tcg/emit.c.inc +++ b/target/i386/tcg/emit.c.inc @@ -175,15 +175,15 @@ static void gen_load_sse(DisasContext *s, TCGv temp, MemOp ot, int dest_ofs, boo switch(ot) { case MO_8: gen_op_ld_v(s, MO_8, temp, s->A0); - tcg_gen_st8_tl(temp, cpu_env, dest_ofs); + tcg_gen_st8_tl(temp, tcg_env, dest_ofs); break; case MO_16: gen_op_ld_v(s, MO_16, temp, s->A0); - tcg_gen_st16_tl(temp, cpu_env, dest_ofs); + tcg_gen_st16_tl(temp, tcg_env, dest_ofs); break; case MO_32: gen_op_ld_v(s, MO_32, temp, s->A0); - tcg_gen_st32_tl(temp, cpu_env, dest_ofs); + tcg_gen_st32_tl(temp, tcg_env, dest_ofs); break; case MO_64: gen_ldq_env_A0(s, dest_ofs); @@ -226,14 +226,14 @@ static void gen_load(DisasContext *s, X86DecodedInsn *decode, int opn, TCGv v) case X86_OP_SKIP: return; case X86_OP_SEG: - tcg_gen_ld32u_tl(v, cpu_env, + tcg_gen_ld32u_tl(v, tcg_env, offsetof(CPUX86State,segs[op->n].selector)); break; case X86_OP_CR: - tcg_gen_ld_tl(v, cpu_env, offsetof(CPUX86State, cr[op->n])); + tcg_gen_ld_tl(v, tcg_env, offsetof(CPUX86State, cr[op->n])); break; case X86_OP_DR: - tcg_gen_ld_tl(v, cpu_env, offsetof(CPUX86State, dr[op->n])); + tcg_gen_ld_tl(v, tcg_env, offsetof(CPUX86State, dr[op->n])); break; case X86_OP_INT: if (op->has_ea) { @@ -273,7 +273,7 @@ static TCGv_ptr op_ptr(X86DecodedInsn *decode, int opn) op->v_ptr = tcg_temp_new_ptr(); /* The temporary points to the MMXReg or ZMMReg. */ - tcg_gen_addi_ptr(op->v_ptr, cpu_env, vector_reg_offset(op)); + tcg_gen_addi_ptr(op->v_ptr, tcg_env, vector_reg_offset(op)); return op->v_ptr; } @@ -400,12 +400,12 @@ static void gen_3dnow(DisasContext *s, CPUX86State *env, X86DecodedInsn *decode) return; } - gen_helper_enter_mmx(cpu_env); + gen_helper_enter_mmx(tcg_env); if (fn == FN_3DNOW_MOVE) { - tcg_gen_ld_i64(s->tmp1_i64, cpu_env, decode->op[1].offset); - tcg_gen_st_i64(s->tmp1_i64, cpu_env, decode->op[0].offset); + tcg_gen_ld_i64(s->tmp1_i64, tcg_env, decode->op[1].offset); + tcg_gen_st_i64(s->tmp1_i64, tcg_env, decode->op[0].offset); } else { - fn(cpu_env, OP_PTR0, OP_PTR1); + fn(tcg_env, OP_PTR0, OP_PTR1); } } @@ -426,7 +426,7 @@ static inline void gen_unary_fp_sse(DisasContext *s, CPUX86State *env, X86Decode gen_illegal_opcode(s); return; } - fn(cpu_env, OP_PTR0, OP_PTR1, OP_PTR2); + fn(tcg_env, OP_PTR0, OP_PTR1, OP_PTR2); } else { SSEFunc_0_epp ps, pd, fn; ps = s->vex_l ? ps_ymm : ps_xmm; @@ -436,7 +436,7 @@ static inline void gen_unary_fp_sse(DisasContext *s, CPUX86State *env, X86Decode gen_illegal_opcode(s); return; } - fn(cpu_env, OP_PTR0, OP_PTR2); + fn(tcg_env, OP_PTR0, OP_PTR2); } } #define UNARY_FP_SSE(uname, lname) \ @@ -472,7 +472,7 @@ static inline void gen_fp_sse(DisasContext *s, CPUX86State *env, X86DecodedInsn fn = s->prefix & PREFIX_DATA ? pd : ps; } if (fn) { - fn(cpu_env, OP_PTR0, OP_PTR1, OP_PTR2); + fn(tcg_env, OP_PTR0, OP_PTR1, OP_PTR2); } else { gen_illegal_opcode(s); } @@ -503,7 +503,7 @@ static void gen_##uname##Px(DisasContext *s, CPUX86State *env, X86DecodedInsn *d SSEFunc_0_eppppii ymm = s->vex_w ? gen_helper_fma4pd_ymm : gen_helper_fma4ps_ymm; \ SSEFunc_0_eppppii fn = s->vex_l ? ymm : xmm; \ \ - fn(cpu_env, OP_PTR0, ptr0, ptr1, ptr2, \ + fn(tcg_env, OP_PTR0, ptr0, ptr1, ptr2, \ tcg_constant_i32(even), \ tcg_constant_i32((even) ^ (odd))); \ } @@ -514,7 +514,7 @@ static void gen_##uname##Sx(DisasContext *s, CPUX86State *env, X86DecodedInsn *d { \ SSEFunc_0_eppppi fn = s->vex_w ? gen_helper_fma4sd : gen_helper_fma4ss; \ \ - fn(cpu_env, OP_PTR0, ptr0, ptr1, ptr2, \ + fn(tcg_env, OP_PTR0, ptr0, ptr1, ptr2, \ tcg_constant_i32(flags)); \ } \ @@ -571,13 +571,13 @@ static inline void gen_unary_fp32_sse(DisasContext *s, CPUX86State *env, X86Deco if (!ss) { goto illegal_op; } - ss(cpu_env, OP_PTR0, OP_PTR1, OP_PTR2); + ss(tcg_env, OP_PTR0, OP_PTR1, OP_PTR2); } else { SSEFunc_0_epp fn = s->vex_l ? ps_ymm : ps_xmm; if (!fn) { goto illegal_op; } - fn(cpu_env, OP_PTR0, OP_PTR2); + fn(tcg_env, OP_PTR0, OP_PTR2); } return; @@ -607,7 +607,7 @@ static inline void gen_horizontal_fp_sse(DisasContext *s, CPUX86State *env, X86D ps = s->vex_l ? ps_ymm : ps_xmm; pd = s->vex_l ? pd_ymm : pd_xmm; fn = s->prefix & PREFIX_DATA ? pd : ps; - fn(cpu_env, OP_PTR0, OP_PTR1, OP_PTR2); + fn(tcg_env, OP_PTR0, OP_PTR1, OP_PTR2); } #define HORIZONTAL_FP_SSE(uname, lname) \ static void gen_##uname(DisasContext *s, CPUX86State *env, X86DecodedInsn *decode) \ @@ -627,8 +627,8 @@ static inline void gen_ternary_sse(DisasContext *s, CPUX86State *env, X86Decoded TCGv_ptr ptr3 = tcg_temp_new_ptr(); /* The format of the fourth input is Lx */ - tcg_gen_addi_ptr(ptr3, cpu_env, ZMM_OFFSET(op3)); - fn(cpu_env, OP_PTR0, OP_PTR1, OP_PTR2, ptr3); + tcg_gen_addi_ptr(ptr3, tcg_env, ZMM_OFFSET(op3)); + fn(tcg_env, OP_PTR0, OP_PTR1, OP_PTR2, ptr3); } #define TERNARY_SSE(uname, uvname, lname) \ static void gen_##uvname(DisasContext *s, CPUX86State *env, X86DecodedInsn *decode) \ @@ -650,9 +650,9 @@ static inline void gen_binary_imm_sse(DisasContext *s, CPUX86State *env, X86Deco { TCGv_i32 imm = tcg_constant8u_i32(decode->immediate); if (!s->vex_l) { - xmm(cpu_env, OP_PTR0, OP_PTR1, OP_PTR2, imm); + xmm(tcg_env, OP_PTR0, OP_PTR1, OP_PTR2, imm); } else { - ymm(cpu_env, OP_PTR0, OP_PTR1, OP_PTR2, imm); + ymm(tcg_env, OP_PTR0, OP_PTR1, OP_PTR2, imm); } } @@ -763,11 +763,11 @@ static inline void gen_binary_int_sse(DisasContext *s, CPUX86State *env, X86Deco return; } if (!(s->prefix & PREFIX_DATA)) { - mmx(cpu_env, OP_PTR0, OP_PTR1, OP_PTR2); + mmx(tcg_env, OP_PTR0, OP_PTR1, OP_PTR2); } else if (!s->vex_l) { - xmm(cpu_env, OP_PTR0, OP_PTR1, OP_PTR2); + xmm(tcg_env, OP_PTR0, OP_PTR1, OP_PTR2); } else { - ymm(cpu_env, OP_PTR0, OP_PTR1, OP_PTR2); + ymm(tcg_env, OP_PTR0, OP_PTR1, OP_PTR2); } } @@ -850,9 +850,9 @@ BINARY_INT_SSE(VAESENCLAST, aesenclast) static void gen_##uname(DisasContext *s, CPUX86State *env, X86DecodedInsn *decode) \ { \ if (!s->vex_l) { \ - gen_helper_##lname##_xmm(cpu_env, OP_PTR1, OP_PTR2); \ + gen_helper_##lname##_xmm(tcg_env, OP_PTR1, OP_PTR2); \ } else { \ - gen_helper_##lname##_ymm(cpu_env, OP_PTR1, OP_PTR2); \ + gen_helper_##lname##_ymm(tcg_env, OP_PTR1, OP_PTR2); \ } \ set_cc_op(s, CC_OP_EFLAGS); \ } @@ -864,9 +864,9 @@ static inline void gen_unary_int_sse(DisasContext *s, CPUX86State *env, X86Decod SSEFunc_0_epp xmm, SSEFunc_0_epp ymm) { if (!s->vex_l) { - xmm(cpu_env, OP_PTR0, OP_PTR2); + xmm(tcg_env, OP_PTR0, OP_PTR2); } else { - ymm(cpu_env, OP_PTR0, OP_PTR2); + ymm(tcg_env, OP_PTR0, OP_PTR2); } } @@ -937,9 +937,9 @@ static inline void gen_unary_imm_fp_sse(DisasContext *s, CPUX86State *env, X86De { TCGv_i32 imm = tcg_constant8u_i32(decode->immediate); if (!s->vex_l) { - xmm(cpu_env, OP_PTR0, OP_PTR1, imm); + xmm(tcg_env, OP_PTR0, OP_PTR1, imm); } else { - ymm(cpu_env, OP_PTR0, OP_PTR1, imm); + ymm(tcg_env, OP_PTR0, OP_PTR1, imm); } } @@ -961,7 +961,7 @@ static inline void gen_vexw_avx(DisasContext *s, CPUX86State *env, X86DecodedIns SSEFunc_0_eppp d = s->vex_l ? d_ymm : d_xmm; SSEFunc_0_eppp q = s->vex_l ? q_ymm : q_xmm; SSEFunc_0_eppp fn = s->vex_w ? q : d; - fn(cpu_env, OP_PTR0, OP_PTR1, OP_PTR2); + fn(tcg_env, OP_PTR0, OP_PTR1, OP_PTR2); } /* VEX.W affects whether to operate on 32- or 64-bit elements. */ @@ -989,8 +989,8 @@ static inline void gen_vsib_avx(DisasContext *s, CPUX86State *env, X86DecodedIns TCGv_ptr index = tcg_temp_new_ptr(); /* Pass third input as (index, base, scale) */ - tcg_gen_addi_ptr(index, cpu_env, ZMM_OFFSET(decode->mem.index)); - fn(cpu_env, OP_PTR0, OP_PTR1, index, s->A0, scale); + tcg_gen_addi_ptr(index, tcg_env, ZMM_OFFSET(decode->mem.index)); + fn(tcg_env, OP_PTR0, OP_PTR1, index, s->A0, scale); /* * There are two output operands, so zero OP1's high 128 bits @@ -1175,37 +1175,37 @@ static void gen_CRC32(DisasContext *s, CPUX86State *env, X86DecodedInsn *decode) static void gen_CVTPI2Px(DisasContext *s, CPUX86State *env, X86DecodedInsn *decode) { - gen_helper_enter_mmx(cpu_env); + gen_helper_enter_mmx(tcg_env); if (s->prefix & PREFIX_DATA) { - gen_helper_cvtpi2pd(cpu_env, OP_PTR0, OP_PTR2); + gen_helper_cvtpi2pd(tcg_env, OP_PTR0, OP_PTR2); } else { - gen_helper_cvtpi2ps(cpu_env, OP_PTR0, OP_PTR2); + gen_helper_cvtpi2ps(tcg_env, OP_PTR0, OP_PTR2); } } static void gen_CVTPx2PI(DisasContext *s, CPUX86State *env, X86DecodedInsn *decode) { - gen_helper_enter_mmx(cpu_env); + gen_helper_enter_mmx(tcg_env); if (s->prefix & PREFIX_DATA) { - gen_helper_cvtpd2pi(cpu_env, OP_PTR0, OP_PTR2); + gen_helper_cvtpd2pi(tcg_env, OP_PTR0, OP_PTR2); } else { - gen_helper_cvtps2pi(cpu_env, OP_PTR0, OP_PTR2); + gen_helper_cvtps2pi(tcg_env, OP_PTR0, OP_PTR2); } } static void gen_CVTTPx2PI(DisasContext *s, CPUX86State *env, X86DecodedInsn *decode) { - gen_helper_enter_mmx(cpu_env); + gen_helper_enter_mmx(tcg_env); if (s->prefix & PREFIX_DATA) { - gen_helper_cvttpd2pi(cpu_env, OP_PTR0, OP_PTR2); + gen_helper_cvttpd2pi(tcg_env, OP_PTR0, OP_PTR2); } else { - gen_helper_cvttps2pi(cpu_env, OP_PTR0, OP_PTR2); + gen_helper_cvttps2pi(tcg_env, OP_PTR0, OP_PTR2); } } static void gen_EMMS(DisasContext *s, CPUX86State *env, X86DecodedInsn *decode) { - gen_helper_emms(cpu_env); + gen_helper_emms(tcg_env); } static void gen_EXTRQ_i(DisasContext *s, CPUX86State *env, X86DecodedInsn *decode) @@ -1213,12 +1213,12 @@ static void gen_EXTRQ_i(DisasContext *s, CPUX86State *env, X86DecodedInsn *decod TCGv_i32 length = tcg_constant_i32(decode->immediate & 63); TCGv_i32 index = tcg_constant_i32((decode->immediate >> 8) & 63); - gen_helper_extrq_i(cpu_env, OP_PTR0, index, length); + gen_helper_extrq_i(tcg_env, OP_PTR0, index, length); } static void gen_EXTRQ_r(DisasContext *s, CPUX86State *env, X86DecodedInsn *decode) { - gen_helper_extrq_r(cpu_env, OP_PTR0, OP_PTR2); + gen_helper_extrq_r(tcg_env, OP_PTR0, OP_PTR2); } static void gen_INSERTQ_i(DisasContext *s, CPUX86State *env, X86DecodedInsn *decode) @@ -1226,12 +1226,12 @@ static void gen_INSERTQ_i(DisasContext *s, CPUX86State *env, X86DecodedInsn *dec TCGv_i32 length = tcg_constant_i32(decode->immediate & 63); TCGv_i32 index = tcg_constant_i32((decode->immediate >> 8) & 63); - gen_helper_insertq_i(cpu_env, OP_PTR0, OP_PTR1, index, length); + gen_helper_insertq_i(tcg_env, OP_PTR0, OP_PTR1, index, length); } static void gen_INSERTQ_r(DisasContext *s, CPUX86State *env, X86DecodedInsn *decode) { - gen_helper_insertq_r(cpu_env, OP_PTR0, OP_PTR2); + gen_helper_insertq_r(tcg_env, OP_PTR0, OP_PTR2); } static void gen_LDMXCSR(DisasContext *s, CPUX86State *env, X86DecodedInsn *decode) @@ -1241,7 +1241,7 @@ static void gen_LDMXCSR(DisasContext *s, CPUX86State *env, X86DecodedInsn *decod return; } tcg_gen_trunc_tl_i32(s->tmp2_i32, s->T1); - gen_helper_ldmxcsr(cpu_env, s->tmp2_i32); + gen_helper_ldmxcsr(tcg_env, s->tmp2_i32); } static void gen_MASKMOV(DisasContext *s, CPUX86State *env, X86DecodedInsn *decode) @@ -1251,9 +1251,9 @@ static void gen_MASKMOV(DisasContext *s, CPUX86State *env, X86DecodedInsn *decod gen_add_A0_ds_seg(s); if (s->prefix & PREFIX_DATA) { - gen_helper_maskmov_xmm(cpu_env, OP_PTR1, OP_PTR2, s->A0); + gen_helper_maskmov_xmm(tcg_env, OP_PTR1, OP_PTR2, s->A0); } else { - gen_helper_maskmov_mmx(cpu_env, OP_PTR1, OP_PTR2, s->A0); + gen_helper_maskmov_mmx(tcg_env, OP_PTR1, OP_PTR2, s->A0); } } @@ -1276,11 +1276,11 @@ static void gen_MOVD_from(DisasContext *s, CPUX86State *env, X86DecodedInsn *dec switch (ot) { case MO_32: #ifdef TARGET_X86_64 - tcg_gen_ld32u_tl(s->T0, cpu_env, decode->op[2].offset); + tcg_gen_ld32u_tl(s->T0, tcg_env, decode->op[2].offset); break; case MO_64: #endif - tcg_gen_ld_tl(s->T0, cpu_env, decode->op[2].offset); + tcg_gen_ld_tl(s->T0, tcg_env, decode->op[2].offset); break; default: abort(); @@ -1298,11 +1298,11 @@ static void gen_MOVD_to(DisasContext *s, CPUX86State *env, X86DecodedInsn *decod switch (ot) { case MO_32: #ifdef TARGET_X86_64 - tcg_gen_st32_tl(s->T1, cpu_env, lo_ofs); + tcg_gen_st32_tl(s->T1, tcg_env, lo_ofs); break; case MO_64: #endif - tcg_gen_st_tl(s->T1, cpu_env, lo_ofs); + tcg_gen_st_tl(s->T1, tcg_env, lo_ofs); break; default: g_assert_not_reached(); @@ -1320,7 +1320,7 @@ static void gen_MOVMSK(DisasContext *s, CPUX86State *env, X86DecodedInsn *decode ps = s->vex_l ? gen_helper_movmskps_ymm : gen_helper_movmskps_xmm; pd = s->vex_l ? gen_helper_movmskpd_ymm : gen_helper_movmskpd_xmm; fn = s->prefix & PREFIX_DATA ? pd : ps; - fn(s->tmp2_i32, cpu_env, OP_PTR2); + fn(s->tmp2_i32, tcg_env, OP_PTR2); tcg_gen_extu_i32_tl(s->T0, s->tmp2_i32); } @@ -1329,7 +1329,7 @@ static void gen_MOVQ(DisasContext *s, CPUX86State *env, X86DecodedInsn *decode) int vec_len = vector_len(s, decode); int lo_ofs = vector_elem_offset(&decode->op[0], MO_64, 0); - tcg_gen_ld_i64(s->tmp1_i64, cpu_env, decode->op[2].offset); + tcg_gen_ld_i64(s->tmp1_i64, tcg_env, decode->op[2].offset); if (decode->op[0].has_ea) { tcg_gen_qemu_st_i64(s->tmp1_i64, s->A0, s->mem_index, MO_LEUQ); } else { @@ -1342,13 +1342,13 @@ static void gen_MOVQ(DisasContext *s, CPUX86State *env, X86DecodedInsn *decode) * it disqualifies using oprsz < maxsz to emulate VEX128. */ tcg_gen_gvec_dup_imm(MO_64, decode->op[0].offset, vec_len, vec_len, 0); - tcg_gen_st_i64(s->tmp1_i64, cpu_env, lo_ofs); + tcg_gen_st_i64(s->tmp1_i64, tcg_env, lo_ofs); } } static void gen_MOVq_dq(DisasContext *s, CPUX86State *env, X86DecodedInsn *decode) { - gen_helper_enter_mmx(cpu_env); + gen_helper_enter_mmx(tcg_env); /* Otherwise the same as any other movq. */ return gen_MOVQ(s, env, decode); } @@ -1380,11 +1380,11 @@ static void gen_PALIGNR(DisasContext *s, CPUX86State *env, X86DecodedInsn *decod { TCGv_i32 imm = tcg_constant8u_i32(decode->immediate); if (!(s->prefix & PREFIX_DATA)) { - gen_helper_palignr_mmx(cpu_env, OP_PTR0, OP_PTR1, OP_PTR2, imm); + gen_helper_palignr_mmx(tcg_env, OP_PTR0, OP_PTR1, OP_PTR2, imm); } else if (!s->vex_l) { - gen_helper_palignr_xmm(cpu_env, OP_PTR0, OP_PTR1, OP_PTR2, imm); + gen_helper_palignr_xmm(tcg_env, OP_PTR0, OP_PTR1, OP_PTR2, imm); } else { - gen_helper_palignr_ymm(cpu_env, OP_PTR0, OP_PTR1, OP_PTR2, imm); + gen_helper_palignr_ymm(tcg_env, OP_PTR0, OP_PTR1, OP_PTR2, imm); } } @@ -1401,14 +1401,14 @@ static void gen_PANDN(DisasContext *s, CPUX86State *env, X86DecodedInsn *decode) static void gen_PCMPESTRI(DisasContext *s, CPUX86State *env, X86DecodedInsn *decode) { TCGv_i32 imm = tcg_constant8u_i32(decode->immediate); - gen_helper_pcmpestri_xmm(cpu_env, OP_PTR1, OP_PTR2, imm); + gen_helper_pcmpestri_xmm(tcg_env, OP_PTR1, OP_PTR2, imm); set_cc_op(s, CC_OP_EFLAGS); } static void gen_PCMPESTRM(DisasContext *s, CPUX86State *env, X86DecodedInsn *decode) { TCGv_i32 imm = tcg_constant8u_i32(decode->immediate); - gen_helper_pcmpestrm_xmm(cpu_env, OP_PTR1, OP_PTR2, imm); + gen_helper_pcmpestrm_xmm(tcg_env, OP_PTR1, OP_PTR2, imm); set_cc_op(s, CC_OP_EFLAGS); if ((s->prefix & PREFIX_VEX) && !s->vex_l) { tcg_gen_gvec_dup_imm(MO_64, offsetof(CPUX86State, xmm_regs[0].ZMM_X(1)), @@ -1419,14 +1419,14 @@ static void gen_PCMPESTRM(DisasContext *s, CPUX86State *env, X86DecodedInsn *dec static void gen_PCMPISTRI(DisasContext *s, CPUX86State *env, X86DecodedInsn *decode) { TCGv_i32 imm = tcg_constant8u_i32(decode->immediate); - gen_helper_pcmpistri_xmm(cpu_env, OP_PTR1, OP_PTR2, imm); + gen_helper_pcmpistri_xmm(tcg_env, OP_PTR1, OP_PTR2, imm); set_cc_op(s, CC_OP_EFLAGS); } static void gen_PCMPISTRM(DisasContext *s, CPUX86State *env, X86DecodedInsn *decode) { TCGv_i32 imm = tcg_constant8u_i32(decode->immediate); - gen_helper_pcmpistrm_xmm(cpu_env, OP_PTR1, OP_PTR2, imm); + gen_helper_pcmpistrm_xmm(tcg_env, OP_PTR1, OP_PTR2, imm); set_cc_op(s, CC_OP_EFLAGS); if ((s->prefix & PREFIX_VEX) && !s->vex_l) { tcg_gen_gvec_dup_imm(MO_64, offsetof(CPUX86State, xmm_regs[0].ZMM_X(1)), @@ -1460,18 +1460,18 @@ static inline void gen_pextr(DisasContext *s, CPUX86State *env, X86DecodedInsn * switch (ot) { case MO_8: - tcg_gen_ld8u_tl(s->T0, cpu_env, vector_elem_offset(&decode->op[1], ot, val)); + tcg_gen_ld8u_tl(s->T0, tcg_env, vector_elem_offset(&decode->op[1], ot, val)); break; case MO_16: - tcg_gen_ld16u_tl(s->T0, cpu_env, vector_elem_offset(&decode->op[1], ot, val)); + tcg_gen_ld16u_tl(s->T0, tcg_env, vector_elem_offset(&decode->op[1], ot, val)); break; case MO_32: #ifdef TARGET_X86_64 - tcg_gen_ld32u_tl(s->T0, cpu_env, vector_elem_offset(&decode->op[1], ot, val)); + tcg_gen_ld32u_tl(s->T0, tcg_env, vector_elem_offset(&decode->op[1], ot, val)); break; case MO_64: #endif - tcg_gen_ld_tl(s->T0, cpu_env, vector_elem_offset(&decode->op[1], ot, val)); + tcg_gen_ld_tl(s->T0, tcg_env, vector_elem_offset(&decode->op[1], ot, val)); break; default: abort(); @@ -1507,18 +1507,18 @@ static inline void gen_pinsr(DisasContext *s, CPUX86State *env, X86DecodedInsn * switch (ot) { case MO_8: - tcg_gen_st8_tl(s->T1, cpu_env, vector_elem_offset(&decode->op[0], ot, val)); + tcg_gen_st8_tl(s->T1, tcg_env, vector_elem_offset(&decode->op[0], ot, val)); break; case MO_16: - tcg_gen_st16_tl(s->T1, cpu_env, vector_elem_offset(&decode->op[0], ot, val)); + tcg_gen_st16_tl(s->T1, tcg_env, vector_elem_offset(&decode->op[0], ot, val)); break; case MO_32: #ifdef TARGET_X86_64 - tcg_gen_st32_tl(s->T1, cpu_env, vector_elem_offset(&decode->op[0], ot, val)); + tcg_gen_st32_tl(s->T1, tcg_env, vector_elem_offset(&decode->op[0], ot, val)); break; case MO_64: #endif - tcg_gen_st_tl(s->T1, cpu_env, vector_elem_offset(&decode->op[0], ot, val)); + tcg_gen_st_tl(s->T1, tcg_env, vector_elem_offset(&decode->op[0], ot, val)); break; default: abort(); @@ -1599,7 +1599,7 @@ static void gen_PMOVMSKB(DisasContext *s, CPUX86State *env, X86DecodedInsn *deco tcg_gen_gvec_2(offsetof(CPUX86State, xmm_t0) + xmm_offset(ot), decode->op[2].offset, vec_len, vec_len, &g); - tcg_gen_ld8u_tl(s->T0, cpu_env, offsetof(CPUX86State, xmm_t0.ZMM_B(vec_len - 1))); + tcg_gen_ld8u_tl(s->T0, tcg_env, offsetof(CPUX86State, xmm_t0.ZMM_B(vec_len - 1))); while (vec_len > 8) { vec_len -= 8; if (TCG_TARGET_HAS_extract2_tl) { @@ -1609,9 +1609,9 @@ static void gen_PMOVMSKB(DisasContext *s, CPUX86State *env, X86DecodedInsn *deco * loading the whole word, the shift left is avoided. */ #ifdef TARGET_X86_64 - tcg_gen_ld_tl(t, cpu_env, offsetof(CPUX86State, xmm_t0.ZMM_Q((vec_len - 1) / 8))); + tcg_gen_ld_tl(t, tcg_env, offsetof(CPUX86State, xmm_t0.ZMM_Q((vec_len - 1) / 8))); #else - tcg_gen_ld_tl(t, cpu_env, offsetof(CPUX86State, xmm_t0.ZMM_L((vec_len - 1) / 4))); + tcg_gen_ld_tl(t, tcg_env, offsetof(CPUX86State, xmm_t0.ZMM_L((vec_len - 1) / 4))); #endif tcg_gen_extract2_tl(s->T0, t, s->T0, TARGET_LONG_BITS - 8); @@ -1621,7 +1621,7 @@ static void gen_PMOVMSKB(DisasContext *s, CPUX86State *env, X86DecodedInsn *deco * those bits are known to be zero after ld8u, this becomes a shift+or * if deposit is not available. */ - tcg_gen_ld8u_tl(t, cpu_env, offsetof(CPUX86State, xmm_t0.ZMM_B(vec_len - 1))); + tcg_gen_ld8u_tl(t, tcg_env, offsetof(CPUX86State, xmm_t0.ZMM_B(vec_len - 1))); tcg_gen_deposit_tl(s->T0, t, s->T0, 8, TARGET_LONG_BITS - 8); } } @@ -1744,8 +1744,8 @@ static TCGv_ptr make_imm8u_xmm_vec(uint8_t imm, int vec_len) tcg_gen_gvec_dup_imm(MO_64, offsetof(CPUX86State, xmm_t0) + xmm_offset(ot), vec_len, vec_len, 0); - tcg_gen_addi_ptr(ptr, cpu_env, offsetof(CPUX86State, xmm_t0)); - tcg_gen_st_i32(imm_v, cpu_env, offsetof(CPUX86State, xmm_t0.ZMM_L(0))); + tcg_gen_addi_ptr(ptr, tcg_env, offsetof(CPUX86State, xmm_t0)); + tcg_gen_st_i32(imm_v, tcg_env, offsetof(CPUX86State, xmm_t0.ZMM_L(0))); return ptr; } @@ -1755,9 +1755,9 @@ static void gen_PSRLDQ_i(DisasContext *s, CPUX86State *env, X86DecodedInsn *deco TCGv_ptr imm_vec = make_imm8u_xmm_vec(decode->immediate, vec_len); if (s->vex_l) { - gen_helper_psrldq_ymm(cpu_env, OP_PTR0, OP_PTR1, imm_vec); + gen_helper_psrldq_ymm(tcg_env, OP_PTR0, OP_PTR1, imm_vec); } else { - gen_helper_psrldq_xmm(cpu_env, OP_PTR0, OP_PTR1, imm_vec); + gen_helper_psrldq_xmm(tcg_env, OP_PTR0, OP_PTR1, imm_vec); } } @@ -1767,9 +1767,9 @@ static void gen_PSLLDQ_i(DisasContext *s, CPUX86State *env, X86DecodedInsn *deco TCGv_ptr imm_vec = make_imm8u_xmm_vec(decode->immediate, vec_len); if (s->vex_l) { - gen_helper_pslldq_ymm(cpu_env, OP_PTR0, OP_PTR1, imm_vec); + gen_helper_pslldq_ymm(tcg_env, OP_PTR0, OP_PTR1, imm_vec); } else { - gen_helper_pslldq_xmm(cpu_env, OP_PTR0, OP_PTR1, imm_vec); + gen_helper_pslldq_xmm(tcg_env, OP_PTR0, OP_PTR1, imm_vec); } } @@ -1827,7 +1827,7 @@ static void gen_VAESKEYGEN(DisasContext *s, CPUX86State *env, X86DecodedInsn *de { TCGv_i32 imm = tcg_constant8u_i32(decode->immediate); assert(!s->vex_l); - gen_helper_aeskeygenassist_xmm(cpu_env, OP_PTR0, OP_PTR1, imm); + gen_helper_aeskeygenassist_xmm(tcg_env, OP_PTR0, OP_PTR1, imm); } static void gen_STMXCSR(DisasContext *s, CPUX86State *env, X86DecodedInsn *decode) @@ -1836,14 +1836,14 @@ static void gen_STMXCSR(DisasContext *s, CPUX86State *env, X86DecodedInsn *decod gen_illegal_opcode(s); return; } - gen_helper_update_mxcsr(cpu_env); - tcg_gen_ld32u_tl(s->T0, cpu_env, offsetof(CPUX86State, mxcsr)); + gen_helper_update_mxcsr(tcg_env); + tcg_gen_ld32u_tl(s->T0, tcg_env, offsetof(CPUX86State, mxcsr)); } static void gen_VAESIMC(DisasContext *s, CPUX86State *env, X86DecodedInsn *decode) { assert(!s->vex_l); - gen_helper_aesimc_xmm(cpu_env, OP_PTR0, OP_PTR2); + gen_helper_aesimc_xmm(tcg_env, OP_PTR0, OP_PTR2); } /* @@ -1903,32 +1903,32 @@ static void gen_VCMP(DisasContext *s, CPUX86State *env, X86DecodedInsn *decode) s->prefix & PREFIX_REPNZ ? 3 /* sd */ : !!(s->prefix & PREFIX_DATA) /* pd */ + (s->vex_l << 2); - gen_helper_cmp_funcs[index][b](cpu_env, OP_PTR0, OP_PTR1, OP_PTR2); + gen_helper_cmp_funcs[index][b](tcg_env, OP_PTR0, OP_PTR1, OP_PTR2); } static void gen_VCOMI(DisasContext *s, CPUX86State *env, X86DecodedInsn *decode) { SSEFunc_0_epp fn; fn = s->prefix & PREFIX_DATA ? gen_helper_comisd : gen_helper_comiss; - fn(cpu_env, OP_PTR1, OP_PTR2); + fn(tcg_env, OP_PTR1, OP_PTR2); set_cc_op(s, CC_OP_EFLAGS); } static void gen_VCVTPD2PS(DisasContext *s, CPUX86State *env, X86DecodedInsn *decode) { if (s->vex_l) { - gen_helper_cvtpd2ps_ymm(cpu_env, OP_PTR0, OP_PTR2); + gen_helper_cvtpd2ps_ymm(tcg_env, OP_PTR0, OP_PTR2); } else { - gen_helper_cvtpd2ps_xmm(cpu_env, OP_PTR0, OP_PTR2); + gen_helper_cvtpd2ps_xmm(tcg_env, OP_PTR0, OP_PTR2); } } static void gen_VCVTPS2PD(DisasContext *s, CPUX86State *env, X86DecodedInsn *decode) { if (s->vex_l) { - gen_helper_cvtps2pd_ymm(cpu_env, OP_PTR0, OP_PTR2); + gen_helper_cvtps2pd_ymm(tcg_env, OP_PTR0, OP_PTR2); } else { - gen_helper_cvtps2pd_xmm(cpu_env, OP_PTR0, OP_PTR2); + gen_helper_cvtps2pd_xmm(tcg_env, OP_PTR0, OP_PTR2); } } @@ -1948,12 +1948,12 @@ static void gen_VCVTPS2PH(DisasContext *s, CPUX86State *env, X86DecodedInsn *dec static void gen_VCVTSD2SS(DisasContext *s, CPUX86State *env, X86DecodedInsn *decode) { - gen_helper_cvtsd2ss(cpu_env, OP_PTR0, OP_PTR1, OP_PTR2); + gen_helper_cvtsd2ss(tcg_env, OP_PTR0, OP_PTR1, OP_PTR2); } static void gen_VCVTSS2SD(DisasContext *s, CPUX86State *env, X86DecodedInsn *decode) { - gen_helper_cvtss2sd(cpu_env, OP_PTR0, OP_PTR1, OP_PTR2); + gen_helper_cvtss2sd(tcg_env, OP_PTR0, OP_PTR1, OP_PTR2); } static void gen_VCVTSI2Sx(DisasContext *s, CPUX86State *env, X86DecodedInsn *decode) @@ -1967,9 +1967,9 @@ static void gen_VCVTSI2Sx(DisasContext *s, CPUX86State *env, X86DecodedInsn *dec MemOp ot = decode->op[2].ot; if (ot == MO_64) { if (s->prefix & PREFIX_REPNZ) { - gen_helper_cvtsq2sd(cpu_env, OP_PTR0, s->T1); + gen_helper_cvtsq2sd(tcg_env, OP_PTR0, s->T1); } else { - gen_helper_cvtsq2ss(cpu_env, OP_PTR0, s->T1); + gen_helper_cvtsq2ss(tcg_env, OP_PTR0, s->T1); } return; } @@ -1980,9 +1980,9 @@ static void gen_VCVTSI2Sx(DisasContext *s, CPUX86State *env, X86DecodedInsn *dec #endif if (s->prefix & PREFIX_REPNZ) { - gen_helper_cvtsi2sd(cpu_env, OP_PTR0, in); + gen_helper_cvtsi2sd(tcg_env, OP_PTR0, in); } else { - gen_helper_cvtsi2ss(cpu_env, OP_PTR0, in); + gen_helper_cvtsi2ss(tcg_env, OP_PTR0, in); } } @@ -1996,9 +1996,9 @@ static inline void gen_VCVTtSx2SI(DisasContext *s, CPUX86State *env, X86DecodedI MemOp ot = decode->op[0].ot; if (ot == MO_64) { if (s->prefix & PREFIX_REPNZ) { - sd2sq(s->T0, cpu_env, OP_PTR2); + sd2sq(s->T0, tcg_env, OP_PTR2); } else { - ss2sq(s->T0, cpu_env, OP_PTR2); + ss2sq(s->T0, tcg_env, OP_PTR2); } return; } @@ -2008,9 +2008,9 @@ static inline void gen_VCVTtSx2SI(DisasContext *s, CPUX86State *env, X86DecodedI out = s->T0; #endif if (s->prefix & PREFIX_REPNZ) { - sd2si(out, cpu_env, OP_PTR2); + sd2si(out, tcg_env, OP_PTR2); } else { - ss2si(out, cpu_env, OP_PTR2); + ss2si(out, tcg_env, OP_PTR2); } #ifdef TARGET_X86_64 tcg_gen_extu_i32_tl(s->T0, out); @@ -2072,7 +2072,7 @@ static void gen_vinsertps(DisasContext *s, CPUX86State *env, X86DecodedInsn *dec } if (new_mask != (val & 15)) { - tcg_gen_st_i32(s->tmp2_i32, cpu_env, + tcg_gen_st_i32(s->tmp2_i32, tcg_env, vector_elem_offset(&decode->op[0], MO_32, dest_word)); } @@ -2081,7 +2081,7 @@ static void gen_vinsertps(DisasContext *s, CPUX86State *env, X86DecodedInsn *dec int i; for (i = 0; i < 4; i++) { if ((val >> i) & 1) { - tcg_gen_st_i32(zero, cpu_env, + tcg_gen_st_i32(zero, tcg_env, vector_elem_offset(&decode->op[0], MO_32, i)); } } @@ -2091,7 +2091,7 @@ static void gen_vinsertps(DisasContext *s, CPUX86State *env, X86DecodedInsn *dec static void gen_VINSERTPS_r(DisasContext *s, CPUX86State *env, X86DecodedInsn *decode) { int val = decode->immediate; - tcg_gen_ld_i32(s->tmp2_i32, cpu_env, + tcg_gen_ld_i32(s->tmp2_i32, tcg_env, vector_elem_offset(&decode->op[2], MO_32, (val >> 6) & 3)); gen_vinsertps(s, env, decode); } @@ -2117,9 +2117,9 @@ static inline void gen_maskmov(DisasContext *s, CPUX86State *env, X86DecodedInsn SSEFunc_0_eppt xmm, SSEFunc_0_eppt ymm) { if (!s->vex_l) { - xmm(cpu_env, OP_PTR2, OP_PTR1, s->A0); + xmm(tcg_env, OP_PTR2, OP_PTR1, s->A0); } else { - ymm(cpu_env, OP_PTR2, OP_PTR1, s->A0); + ymm(tcg_env, OP_PTR2, OP_PTR1, s->A0); } } @@ -2137,8 +2137,8 @@ static void gen_VMOVHPx_ld(DisasContext *s, CPUX86State *env, X86DecodedInsn *de { gen_ldq_env_A0(s, decode->op[0].offset + offsetof(XMMReg, XMM_Q(1))); if (decode->op[0].offset != decode->op[1].offset) { - tcg_gen_ld_i64(s->tmp1_i64, cpu_env, decode->op[1].offset + offsetof(XMMReg, XMM_Q(0))); - tcg_gen_st_i64(s->tmp1_i64, cpu_env, decode->op[0].offset + offsetof(XMMReg, XMM_Q(0))); + tcg_gen_ld_i64(s->tmp1_i64, tcg_env, decode->op[1].offset + offsetof(XMMReg, XMM_Q(0))); + tcg_gen_st_i64(s->tmp1_i64, tcg_env, decode->op[0].offset + offsetof(XMMReg, XMM_Q(0))); } } @@ -2150,32 +2150,32 @@ static void gen_VMOVHPx_st(DisasContext *s, CPUX86State *env, X86DecodedInsn *de static void gen_VMOVHPx(DisasContext *s, CPUX86State *env, X86DecodedInsn *decode) { if (decode->op[0].offset != decode->op[2].offset) { - tcg_gen_ld_i64(s->tmp1_i64, cpu_env, decode->op[2].offset + offsetof(XMMReg, XMM_Q(1))); - tcg_gen_st_i64(s->tmp1_i64, cpu_env, decode->op[0].offset + offsetof(XMMReg, XMM_Q(1))); + tcg_gen_ld_i64(s->tmp1_i64, tcg_env, decode->op[2].offset + offsetof(XMMReg, XMM_Q(1))); + tcg_gen_st_i64(s->tmp1_i64, tcg_env, decode->op[0].offset + offsetof(XMMReg, XMM_Q(1))); } if (decode->op[0].offset != decode->op[1].offset) { - tcg_gen_ld_i64(s->tmp1_i64, cpu_env, decode->op[1].offset + offsetof(XMMReg, XMM_Q(0))); - tcg_gen_st_i64(s->tmp1_i64, cpu_env, decode->op[0].offset + offsetof(XMMReg, XMM_Q(0))); + tcg_gen_ld_i64(s->tmp1_i64, tcg_env, decode->op[1].offset + offsetof(XMMReg, XMM_Q(0))); + tcg_gen_st_i64(s->tmp1_i64, tcg_env, decode->op[0].offset + offsetof(XMMReg, XMM_Q(0))); } } static void gen_VMOVHLPS(DisasContext *s, CPUX86State *env, X86DecodedInsn *decode) { - tcg_gen_ld_i64(s->tmp1_i64, cpu_env, decode->op[2].offset + offsetof(XMMReg, XMM_Q(1))); - tcg_gen_st_i64(s->tmp1_i64, cpu_env, decode->op[0].offset + offsetof(XMMReg, XMM_Q(0))); + tcg_gen_ld_i64(s->tmp1_i64, tcg_env, decode->op[2].offset + offsetof(XMMReg, XMM_Q(1))); + tcg_gen_st_i64(s->tmp1_i64, tcg_env, decode->op[0].offset + offsetof(XMMReg, XMM_Q(0))); if (decode->op[0].offset != decode->op[1].offset) { - tcg_gen_ld_i64(s->tmp1_i64, cpu_env, decode->op[1].offset + offsetof(XMMReg, XMM_Q(1))); - tcg_gen_st_i64(s->tmp1_i64, cpu_env, decode->op[0].offset + offsetof(XMMReg, XMM_Q(1))); + tcg_gen_ld_i64(s->tmp1_i64, tcg_env, decode->op[1].offset + offsetof(XMMReg, XMM_Q(1))); + tcg_gen_st_i64(s->tmp1_i64, tcg_env, decode->op[0].offset + offsetof(XMMReg, XMM_Q(1))); } } static void gen_VMOVLHPS(DisasContext *s, CPUX86State *env, X86DecodedInsn *decode) { - tcg_gen_ld_i64(s->tmp1_i64, cpu_env, decode->op[2].offset); - tcg_gen_st_i64(s->tmp1_i64, cpu_env, decode->op[0].offset + offsetof(XMMReg, XMM_Q(1))); + tcg_gen_ld_i64(s->tmp1_i64, tcg_env, decode->op[2].offset); + tcg_gen_st_i64(s->tmp1_i64, tcg_env, decode->op[0].offset + offsetof(XMMReg, XMM_Q(1))); if (decode->op[0].offset != decode->op[1].offset) { - tcg_gen_ld_i64(s->tmp1_i64, cpu_env, decode->op[1].offset + offsetof(XMMReg, XMM_Q(0))); - tcg_gen_st_i64(s->tmp1_i64, cpu_env, decode->op[0].offset + offsetof(XMMReg, XMM_Q(0))); + tcg_gen_ld_i64(s->tmp1_i64, tcg_env, decode->op[1].offset + offsetof(XMMReg, XMM_Q(0))); + tcg_gen_st_i64(s->tmp1_i64, tcg_env, decode->op[0].offset + offsetof(XMMReg, XMM_Q(0))); } } @@ -2188,9 +2188,9 @@ static void gen_VMOVLPx(DisasContext *s, CPUX86State *env, X86DecodedInsn *decod { int vec_len = vector_len(s, decode); - tcg_gen_ld_i64(s->tmp1_i64, cpu_env, decode->op[2].offset + offsetof(XMMReg, XMM_Q(0))); + tcg_gen_ld_i64(s->tmp1_i64, tcg_env, decode->op[2].offset + offsetof(XMMReg, XMM_Q(0))); tcg_gen_gvec_mov(MO_64, decode->op[0].offset, decode->op[1].offset, vec_len, vec_len); - tcg_gen_st_i64(s->tmp1_i64, cpu_env, decode->op[0].offset + offsetof(XMMReg, XMM_Q(0))); + tcg_gen_st_i64(s->tmp1_i64, tcg_env, decode->op[0].offset + offsetof(XMMReg, XMM_Q(0))); } static void gen_VMOVLPx_ld(DisasContext *s, CPUX86State *env, X86DecodedInsn *decode) @@ -2266,21 +2266,21 @@ static void gen_VPERM2x128(DisasContext *s, CPUX86State *env, X86DecodedInsn *de static void gen_VPHMINPOSUW(DisasContext *s, CPUX86State *env, X86DecodedInsn *decode) { assert(!s->vex_l); - gen_helper_phminposuw_xmm(cpu_env, OP_PTR0, OP_PTR2); + gen_helper_phminposuw_xmm(tcg_env, OP_PTR0, OP_PTR2); } static void gen_VROUNDSD(DisasContext *s, CPUX86State *env, X86DecodedInsn *decode) { TCGv_i32 imm = tcg_constant8u_i32(decode->immediate); assert(!s->vex_l); - gen_helper_roundsd_xmm(cpu_env, OP_PTR0, OP_PTR1, OP_PTR2, imm); + gen_helper_roundsd_xmm(tcg_env, OP_PTR0, OP_PTR1, OP_PTR2, imm); } static void gen_VROUNDSS(DisasContext *s, CPUX86State *env, X86DecodedInsn *decode) { TCGv_i32 imm = tcg_constant8u_i32(decode->immediate); assert(!s->vex_l); - gen_helper_roundss_xmm(cpu_env, OP_PTR0, OP_PTR1, OP_PTR2, imm); + gen_helper_roundss_xmm(tcg_env, OP_PTR0, OP_PTR1, OP_PTR2, imm); } static void gen_VSHUF(DisasContext *s, CPUX86State *env, X86DecodedInsn *decode) @@ -2297,7 +2297,7 @@ static void gen_VUCOMI(DisasContext *s, CPUX86State *env, X86DecodedInsn *decode { SSEFunc_0_epp fn; fn = s->prefix & PREFIX_DATA ? gen_helper_ucomisd : gen_helper_ucomiss; - fn(cpu_env, OP_PTR1, OP_PTR2); + fn(tcg_env, OP_PTR1, OP_PTR2); set_cc_op(s, CC_OP_EFLAGS); } @@ -2305,7 +2305,7 @@ static void gen_VZEROALL(DisasContext *s, CPUX86State *env, X86DecodedInsn *deco { TCGv_ptr ptr = tcg_temp_new_ptr(); - tcg_gen_addi_ptr(ptr, cpu_env, offsetof(CPUX86State, xmm_regs)); + tcg_gen_addi_ptr(ptr, tcg_env, offsetof(CPUX86State, xmm_regs)); gen_helper_memset(ptr, ptr, tcg_constant_i32(0), tcg_constant_ptr(CPU_NB_REGS * sizeof(ZMMReg))); } diff --git a/target/i386/tcg/translate.c b/target/i386/tcg/translate.c index 72635b87d3..4db91d11d8 100644 --- a/target/i386/tcg/translate.c +++ b/target/i386/tcg/translate.c @@ -695,7 +695,7 @@ static inline void gen_string_movl_A0_EDI(DisasContext *s) static inline void gen_op_movl_T0_Dshift(DisasContext *s, MemOp ot) { - tcg_gen_ld32s_tl(s->T0, cpu_env, offsetof(CPUX86State, df)); + tcg_gen_ld32s_tl(s->T0, tcg_env, offsetof(CPUX86State, df)); tcg_gen_shli_tl(s->T0, s->T0, ot); }; @@ -761,13 +761,13 @@ static void gen_helper_in_func(MemOp ot, TCGv v, TCGv_i32 n) { switch (ot) { case MO_8: - gen_helper_inb(v, cpu_env, n); + gen_helper_inb(v, tcg_env, n); break; case MO_16: - gen_helper_inw(v, cpu_env, n); + gen_helper_inw(v, tcg_env, n); break; case MO_32: - gen_helper_inl(v, cpu_env, n); + gen_helper_inl(v, tcg_env, n); break; default: g_assert_not_reached(); @@ -778,13 +778,13 @@ static void gen_helper_out_func(MemOp ot, TCGv_i32 v, TCGv_i32 n) { switch (ot) { case MO_8: - gen_helper_outb(cpu_env, v, n); + gen_helper_outb(tcg_env, v, n); break; case MO_16: - gen_helper_outw(cpu_env, v, n); + gen_helper_outw(tcg_env, v, n); break; case MO_32: - gen_helper_outl(cpu_env, v, n); + gen_helper_outl(tcg_env, v, n); break; default: g_assert_not_reached(); @@ -807,7 +807,7 @@ static bool gen_check_io(DisasContext *s, MemOp ot, TCGv_i32 port, return false; #else if (PE(s) && (CPL(s) > IOPL(s) || VM86(s))) { - gen_helper_check_io(cpu_env, port, tcg_constant_i32(1 << ot)); + gen_helper_check_io(tcg_env, port, tcg_constant_i32(1 << ot)); } if (GUEST(s)) { gen_update_cc_op(s); @@ -816,7 +816,7 @@ static bool gen_check_io(DisasContext *s, MemOp ot, TCGv_i32 port, svm_flags |= SVM_IOIO_REP_MASK; } svm_flags |= 1 << (SVM_IOIO_SIZE_SHIFT + ot); - gen_helper_svm_check_io(cpu_env, port, + gen_helper_svm_check_io(tcg_env, port, tcg_constant_i32(svm_flags), cur_insn_len_i32(s)); } @@ -1298,7 +1298,7 @@ static void gen_bpt_io(DisasContext *s, TCGv_i32 t_port, int ot) #else TCGv_i32 t_size = tcg_constant_i32(1 << ot); TCGv t_next = eip_next_tl(s); - gen_helper_bpt_io(cpu_env, t_port, t_size, t_next); + gen_helper_bpt_io(tcg_env, t_port, t_size, t_next); #endif /* CONFIG_USER_ONLY */ } } @@ -1388,28 +1388,28 @@ static void gen_helper_fp_arith_ST0_FT0(int op) { switch (op) { case 0: - gen_helper_fadd_ST0_FT0(cpu_env); + gen_helper_fadd_ST0_FT0(tcg_env); break; case 1: - gen_helper_fmul_ST0_FT0(cpu_env); + gen_helper_fmul_ST0_FT0(tcg_env); break; case 2: - gen_helper_fcom_ST0_FT0(cpu_env); + gen_helper_fcom_ST0_FT0(tcg_env); break; case 3: - gen_helper_fcom_ST0_FT0(cpu_env); + gen_helper_fcom_ST0_FT0(tcg_env); break; case 4: - gen_helper_fsub_ST0_FT0(cpu_env); + gen_helper_fsub_ST0_FT0(tcg_env); break; case 5: - gen_helper_fsubr_ST0_FT0(cpu_env); + gen_helper_fsubr_ST0_FT0(tcg_env); break; case 6: - gen_helper_fdiv_ST0_FT0(cpu_env); + gen_helper_fdiv_ST0_FT0(tcg_env); break; case 7: - gen_helper_fdivr_ST0_FT0(cpu_env); + gen_helper_fdivr_ST0_FT0(tcg_env); break; } } @@ -1420,22 +1420,22 @@ static void gen_helper_fp_arith_STN_ST0(int op, int opreg) TCGv_i32 tmp = tcg_constant_i32(opreg); switch (op) { case 0: - gen_helper_fadd_STN_ST0(cpu_env, tmp); + gen_helper_fadd_STN_ST0(tcg_env, tmp); break; case 1: - gen_helper_fmul_STN_ST0(cpu_env, tmp); + gen_helper_fmul_STN_ST0(tcg_env, tmp); break; case 4: - gen_helper_fsubr_STN_ST0(cpu_env, tmp); + gen_helper_fsubr_STN_ST0(tcg_env, tmp); break; case 5: - gen_helper_fsub_STN_ST0(cpu_env, tmp); + gen_helper_fsub_STN_ST0(tcg_env, tmp); break; case 6: - gen_helper_fdivr_STN_ST0(cpu_env, tmp); + gen_helper_fdivr_STN_ST0(tcg_env, tmp); break; case 7: - gen_helper_fdiv_STN_ST0(cpu_env, tmp); + gen_helper_fdiv_STN_ST0(tcg_env, tmp); break; } } @@ -1444,7 +1444,7 @@ static void gen_exception(DisasContext *s, int trapno) { gen_update_cc_op(s); gen_update_eip_cur(s); - gen_helper_raise_exception(cpu_env, tcg_constant_i32(trapno)); + gen_helper_raise_exception(tcg_env, tcg_constant_i32(trapno)); s->base.is_jmp = DISAS_NORETURN; } @@ -1923,17 +1923,17 @@ static void gen_rotc_rm_T1(DisasContext *s, MemOp ot, int op1, if (is_right) { switch (ot) { case MO_8: - gen_helper_rcrb(s->T0, cpu_env, s->T0, s->T1); + gen_helper_rcrb(s->T0, tcg_env, s->T0, s->T1); break; case MO_16: - gen_helper_rcrw(s->T0, cpu_env, s->T0, s->T1); + gen_helper_rcrw(s->T0, tcg_env, s->T0, s->T1); break; case MO_32: - gen_helper_rcrl(s->T0, cpu_env, s->T0, s->T1); + gen_helper_rcrl(s->T0, tcg_env, s->T0, s->T1); break; #ifdef TARGET_X86_64 case MO_64: - gen_helper_rcrq(s->T0, cpu_env, s->T0, s->T1); + gen_helper_rcrq(s->T0, tcg_env, s->T0, s->T1); break; #endif default: @@ -1942,17 +1942,17 @@ static void gen_rotc_rm_T1(DisasContext *s, MemOp ot, int op1, } else { switch (ot) { case MO_8: - gen_helper_rclb(s->T0, cpu_env, s->T0, s->T1); + gen_helper_rclb(s->T0, tcg_env, s->T0, s->T1); break; case MO_16: - gen_helper_rclw(s->T0, cpu_env, s->T0, s->T1); + gen_helper_rclw(s->T0, tcg_env, s->T0, s->T1); break; case MO_32: - gen_helper_rcll(s->T0, cpu_env, s->T0, s->T1); + gen_helper_rcll(s->T0, tcg_env, s->T0, s->T1); break; #ifdef TARGET_X86_64 case MO_64: - gen_helper_rclq(s->T0, cpu_env, s->T0, s->T1); + gen_helper_rclq(s->T0, tcg_env, s->T0, s->T1); break; #endif default: @@ -2354,7 +2354,7 @@ static void gen_bndck(CPUX86State *env, DisasContext *s, int modrm, } tcg_gen_setcond_i64(cond, s->tmp1_i64, s->tmp1_i64, bndv); tcg_gen_extrl_i64_i32(s->tmp2_i32, s->tmp1_i64); - gen_helper_bndck(cpu_env, s->tmp2_i32); + gen_helper_bndck(tcg_env, s->tmp2_i32); } /* used for LEA and MOV AX, mem */ @@ -2512,14 +2512,14 @@ static void gen_cmovcc1(CPUX86State *env, DisasContext *s, MemOp ot, int b, static inline void gen_op_movl_T0_seg(DisasContext *s, X86Seg seg_reg) { - tcg_gen_ld32u_tl(s->T0, cpu_env, + tcg_gen_ld32u_tl(s->T0, tcg_env, offsetof(CPUX86State,segs[seg_reg].selector)); } static inline void gen_op_movl_seg_T0_vm(DisasContext *s, X86Seg seg_reg) { tcg_gen_ext16u_tl(s->T0, s->T0); - tcg_gen_st32_tl(s->T0, cpu_env, + tcg_gen_st32_tl(s->T0, tcg_env, offsetof(CPUX86State,segs[seg_reg].selector)); tcg_gen_shli_tl(cpu_seg_base[seg_reg], s->T0, 4); } @@ -2530,7 +2530,7 @@ static void gen_movl_seg_T0(DisasContext *s, X86Seg seg_reg) { if (PE(s) && !VM86(s)) { tcg_gen_trunc_tl_i32(s->tmp2_i32, s->T0); - gen_helper_load_seg(cpu_env, tcg_constant_i32(seg_reg), s->tmp2_i32); + gen_helper_load_seg(tcg_env, tcg_constant_i32(seg_reg), s->tmp2_i32); /* abort translation because the addseg value may change or because ss32 may change. For R_SS, translation must always stop as a special handling must be done to disable hardware @@ -2554,7 +2554,7 @@ static void gen_svm_check_intercept(DisasContext *s, uint32_t type) if (likely(!GUEST(s))) { return; } - gen_helper_svm_check_intercept(cpu_env, tcg_constant_i32(type)); + gen_helper_svm_check_intercept(tcg_env, tcg_constant_i32(type)); } static inline void gen_stack_update(DisasContext *s, int addend) @@ -2724,7 +2724,7 @@ static void gen_interrupt(DisasContext *s, int intno) { gen_update_cc_op(s); gen_update_eip_cur(s); - gen_helper_raise_interrupt(cpu_env, tcg_constant_i32(intno), + gen_helper_raise_interrupt(tcg_env, tcg_constant_i32(intno), cur_insn_len_i32(s)); s->base.is_jmp = DISAS_NORETURN; } @@ -2733,9 +2733,9 @@ static void gen_set_hflag(DisasContext *s, uint32_t mask) { if ((s->flags & mask) == 0) { TCGv_i32 t = tcg_temp_new_i32(); - tcg_gen_ld_i32(t, cpu_env, offsetof(CPUX86State, hflags)); + tcg_gen_ld_i32(t, tcg_env, offsetof(CPUX86State, hflags)); tcg_gen_ori_i32(t, t, mask); - tcg_gen_st_i32(t, cpu_env, offsetof(CPUX86State, hflags)); + tcg_gen_st_i32(t, tcg_env, offsetof(CPUX86State, hflags)); s->flags |= mask; } } @@ -2744,9 +2744,9 @@ static void gen_reset_hflag(DisasContext *s, uint32_t mask) { if (s->flags & mask) { TCGv_i32 t = tcg_temp_new_i32(); - tcg_gen_ld_i32(t, cpu_env, offsetof(CPUX86State, hflags)); + tcg_gen_ld_i32(t, tcg_env, offsetof(CPUX86State, hflags)); tcg_gen_andi_i32(t, t, ~mask); - tcg_gen_st_i32(t, cpu_env, offsetof(CPUX86State, hflags)); + tcg_gen_st_i32(t, tcg_env, offsetof(CPUX86State, hflags)); s->flags &= ~mask; } } @@ -2755,18 +2755,18 @@ static void gen_set_eflags(DisasContext *s, target_ulong mask) { TCGv t = tcg_temp_new(); - tcg_gen_ld_tl(t, cpu_env, offsetof(CPUX86State, eflags)); + tcg_gen_ld_tl(t, tcg_env, offsetof(CPUX86State, eflags)); tcg_gen_ori_tl(t, t, mask); - tcg_gen_st_tl(t, cpu_env, offsetof(CPUX86State, eflags)); + tcg_gen_st_tl(t, tcg_env, offsetof(CPUX86State, eflags)); } static void gen_reset_eflags(DisasContext *s, target_ulong mask) { TCGv t = tcg_temp_new(); - tcg_gen_ld_tl(t, cpu_env, offsetof(CPUX86State, eflags)); + tcg_gen_ld_tl(t, tcg_env, offsetof(CPUX86State, eflags)); tcg_gen_andi_tl(t, t, ~mask); - tcg_gen_st_tl(t, cpu_env, offsetof(CPUX86State, eflags)); + tcg_gen_st_tl(t, tcg_env, offsetof(CPUX86State, eflags)); } /* Clear BND registers during legacy branches. */ @@ -2778,7 +2778,7 @@ static void gen_bnd_jmp(DisasContext *s) if ((s->prefix & PREFIX_REPNZ) == 0 && (s->flags & HF_MPX_EN_MASK) != 0 && (s->flags & HF_MPX_IU_MASK) != 0) { - gen_helper_bnd_jmp(cpu_env); + gen_helper_bnd_jmp(tcg_env); } } @@ -2802,10 +2802,10 @@ do_gen_eob_worker(DisasContext *s, bool inhibit, bool recheck_tf, bool jr) gen_reset_eflags(s, RF_MASK); } if (recheck_tf) { - gen_helper_rechecking_single_step(cpu_env); + gen_helper_rechecking_single_step(tcg_env); tcg_gen_exit_tb(NULL, 0); } else if (s->flags & HF_TF_MASK) { - gen_helper_single_step(cpu_env); + gen_helper_single_step(tcg_env); } else if (jr) { tcg_gen_lookup_and_goto_ptr(); } else { @@ -2907,12 +2907,12 @@ static void gen_jmp_rel_csize(DisasContext *s, int diff, int tb_num) static inline void gen_ldq_env_A0(DisasContext *s, int offset) { tcg_gen_qemu_ld_i64(s->tmp1_i64, s->A0, s->mem_index, MO_LEUQ); - tcg_gen_st_i64(s->tmp1_i64, cpu_env, offset); + tcg_gen_st_i64(s->tmp1_i64, tcg_env, offset); } static inline void gen_stq_env_A0(DisasContext *s, int offset) { - tcg_gen_ld_i64(s->tmp1_i64, cpu_env, offset); + tcg_gen_ld_i64(s->tmp1_i64, tcg_env, offset); tcg_gen_qemu_st_i64(s->tmp1_i64, s->A0, s->mem_index, MO_LEUQ); } @@ -2921,20 +2921,20 @@ static inline void gen_ldo_env_A0(DisasContext *s, int offset, bool align) int mem_index = s->mem_index; tcg_gen_qemu_ld_i64(s->tmp1_i64, s->A0, mem_index, MO_LEUQ | (align ? MO_ALIGN_16 : 0)); - tcg_gen_st_i64(s->tmp1_i64, cpu_env, offset + offsetof(XMMReg, XMM_Q(0))); + tcg_gen_st_i64(s->tmp1_i64, tcg_env, offset + offsetof(XMMReg, XMM_Q(0))); tcg_gen_addi_tl(s->tmp0, s->A0, 8); tcg_gen_qemu_ld_i64(s->tmp1_i64, s->tmp0, mem_index, MO_LEUQ); - tcg_gen_st_i64(s->tmp1_i64, cpu_env, offset + offsetof(XMMReg, XMM_Q(1))); + tcg_gen_st_i64(s->tmp1_i64, tcg_env, offset + offsetof(XMMReg, XMM_Q(1))); } static inline void gen_sto_env_A0(DisasContext *s, int offset, bool align) { int mem_index = s->mem_index; - tcg_gen_ld_i64(s->tmp1_i64, cpu_env, offset + offsetof(XMMReg, XMM_Q(0))); + tcg_gen_ld_i64(s->tmp1_i64, tcg_env, offset + offsetof(XMMReg, XMM_Q(0))); tcg_gen_qemu_st_i64(s->tmp1_i64, s->A0, mem_index, MO_LEUQ | (align ? MO_ALIGN_16 : 0)); tcg_gen_addi_tl(s->tmp0, s->A0, 8); - tcg_gen_ld_i64(s->tmp1_i64, cpu_env, offset + offsetof(XMMReg, XMM_Q(1))); + tcg_gen_ld_i64(s->tmp1_i64, tcg_env, offset + offsetof(XMMReg, XMM_Q(1))); tcg_gen_qemu_st_i64(s->tmp1_i64, s->tmp0, mem_index, MO_LEUQ); } @@ -2943,33 +2943,33 @@ static void gen_ldy_env_A0(DisasContext *s, int offset, bool align) int mem_index = s->mem_index; tcg_gen_qemu_ld_i64(s->tmp1_i64, s->A0, mem_index, MO_LEUQ | (align ? MO_ALIGN_32 : 0)); - tcg_gen_st_i64(s->tmp1_i64, cpu_env, offset + offsetof(YMMReg, YMM_Q(0))); + tcg_gen_st_i64(s->tmp1_i64, tcg_env, offset + offsetof(YMMReg, YMM_Q(0))); tcg_gen_addi_tl(s->tmp0, s->A0, 8); tcg_gen_qemu_ld_i64(s->tmp1_i64, s->tmp0, mem_index, MO_LEUQ); - tcg_gen_st_i64(s->tmp1_i64, cpu_env, offset + offsetof(YMMReg, YMM_Q(1))); + tcg_gen_st_i64(s->tmp1_i64, tcg_env, offset + offsetof(YMMReg, YMM_Q(1))); tcg_gen_addi_tl(s->tmp0, s->A0, 16); tcg_gen_qemu_ld_i64(s->tmp1_i64, s->tmp0, mem_index, MO_LEUQ); - tcg_gen_st_i64(s->tmp1_i64, cpu_env, offset + offsetof(YMMReg, YMM_Q(2))); + tcg_gen_st_i64(s->tmp1_i64, tcg_env, offset + offsetof(YMMReg, YMM_Q(2))); tcg_gen_addi_tl(s->tmp0, s->A0, 24); tcg_gen_qemu_ld_i64(s->tmp1_i64, s->tmp0, mem_index, MO_LEUQ); - tcg_gen_st_i64(s->tmp1_i64, cpu_env, offset + offsetof(YMMReg, YMM_Q(3))); + tcg_gen_st_i64(s->tmp1_i64, tcg_env, offset + offsetof(YMMReg, YMM_Q(3))); } static void gen_sty_env_A0(DisasContext *s, int offset, bool align) { int mem_index = s->mem_index; - tcg_gen_ld_i64(s->tmp1_i64, cpu_env, offset + offsetof(YMMReg, YMM_Q(0))); + tcg_gen_ld_i64(s->tmp1_i64, tcg_env, offset + offsetof(YMMReg, YMM_Q(0))); tcg_gen_qemu_st_i64(s->tmp1_i64, s->A0, mem_index, MO_LEUQ | (align ? MO_ALIGN_32 : 0)); tcg_gen_addi_tl(s->tmp0, s->A0, 8); - tcg_gen_ld_i64(s->tmp1_i64, cpu_env, offset + offsetof(YMMReg, YMM_Q(1))); + tcg_gen_ld_i64(s->tmp1_i64, tcg_env, offset + offsetof(YMMReg, YMM_Q(1))); tcg_gen_qemu_st_i64(s->tmp1_i64, s->tmp0, mem_index, MO_LEUQ); tcg_gen_addi_tl(s->tmp0, s->A0, 16); - tcg_gen_ld_i64(s->tmp1_i64, cpu_env, offset + offsetof(YMMReg, YMM_Q(2))); + tcg_gen_ld_i64(s->tmp1_i64, tcg_env, offset + offsetof(YMMReg, YMM_Q(2))); tcg_gen_qemu_st_i64(s->tmp1_i64, s->tmp0, mem_index, MO_LEUQ); tcg_gen_addi_tl(s->tmp0, s->A0, 24); - tcg_gen_ld_i64(s->tmp1_i64, cpu_env, offset + offsetof(YMMReg, YMM_Q(3))); + tcg_gen_ld_i64(s->tmp1_i64, tcg_env, offset + offsetof(YMMReg, YMM_Q(3))); tcg_gen_qemu_st_i64(s->tmp1_i64, s->tmp0, mem_index, MO_LEUQ); } @@ -3531,18 +3531,18 @@ static bool disas_insn(DisasContext *s, CPUState *cpu) case 6: /* div */ switch(ot) { case MO_8: - gen_helper_divb_AL(cpu_env, s->T0); + gen_helper_divb_AL(tcg_env, s->T0); break; case MO_16: - gen_helper_divw_AX(cpu_env, s->T0); + gen_helper_divw_AX(tcg_env, s->T0); break; default: case MO_32: - gen_helper_divl_EAX(cpu_env, s->T0); + gen_helper_divl_EAX(tcg_env, s->T0); break; #ifdef TARGET_X86_64 case MO_64: - gen_helper_divq_EAX(cpu_env, s->T0); + gen_helper_divq_EAX(tcg_env, s->T0); break; #endif } @@ -3550,18 +3550,18 @@ static bool disas_insn(DisasContext *s, CPUState *cpu) case 7: /* idiv */ switch(ot) { case MO_8: - gen_helper_idivb_AL(cpu_env, s->T0); + gen_helper_idivb_AL(tcg_env, s->T0); break; case MO_16: - gen_helper_idivw_AX(cpu_env, s->T0); + gen_helper_idivw_AX(tcg_env, s->T0); break; default: case MO_32: - gen_helper_idivl_EAX(cpu_env, s->T0); + gen_helper_idivl_EAX(tcg_env, s->T0); break; #ifdef TARGET_X86_64 case MO_64: - gen_helper_idivq_EAX(cpu_env, s->T0); + gen_helper_idivq_EAX(tcg_env, s->T0); break; #endif } @@ -3636,13 +3636,13 @@ static bool disas_insn(DisasContext *s, CPUState *cpu) do_lcall: if (PE(s) && !VM86(s)) { tcg_gen_trunc_tl_i32(s->tmp2_i32, s->T0); - gen_helper_lcall_protected(cpu_env, s->tmp2_i32, s->T1, + gen_helper_lcall_protected(tcg_env, s->tmp2_i32, s->T1, tcg_constant_i32(dflag - 1), eip_next_tl(s)); } else { tcg_gen_trunc_tl_i32(s->tmp2_i32, s->T0); tcg_gen_trunc_tl_i32(s->tmp3_i32, s->T1); - gen_helper_lcall_real(cpu_env, s->tmp2_i32, s->tmp3_i32, + gen_helper_lcall_real(tcg_env, s->tmp2_i32, s->tmp3_i32, tcg_constant_i32(dflag - 1), eip_next_i32(s)); } @@ -3666,7 +3666,7 @@ static bool disas_insn(DisasContext *s, CPUState *cpu) do_ljmp: if (PE(s) && !VM86(s)) { tcg_gen_trunc_tl_i32(s->tmp2_i32, s->T0); - gen_helper_ljmp_protected(cpu_env, s->tmp2_i32, s->T1, + gen_helper_ljmp_protected(tcg_env, s->tmp2_i32, s->T1, eip_next_tl(s)); } else { gen_op_movl_seg_T0_vm(s, R_CS); @@ -3933,7 +3933,7 @@ static bool disas_insn(DisasContext *s, CPUState *cpu) if (!(s->cpuid_ext_features & CPUID_7_0_ECX_RDPID)) { goto illegal_op; } - gen_helper_rdpid(s->T0, cpu_env); + gen_helper_rdpid(s->T0, tcg_env); rm = (modrm & 7) | REX_B(s); gen_op_mov_reg_v(s, dflag, rm, s->T0); break; @@ -3952,7 +3952,7 @@ static bool disas_insn(DisasContext *s, CPUState *cpu) } do_rdrand: translator_io_start(&s->base); - gen_helper_rdrand(s->T0, cpu_env); + gen_helper_rdrand(s->T0, tcg_env); rm = (modrm & 7) | REX_B(s); gen_op_mov_reg_v(s, dflag, rm, s->T0); set_cc_op(s, CC_OP_EFLAGS); @@ -4410,30 +4410,30 @@ static bool disas_insn(DisasContext *s, CPUState *cpu) case 0: tcg_gen_qemu_ld_i32(s->tmp2_i32, s->A0, s->mem_index, MO_LEUL); - gen_helper_flds_FT0(cpu_env, s->tmp2_i32); + gen_helper_flds_FT0(tcg_env, s->tmp2_i32); break; case 1: tcg_gen_qemu_ld_i32(s->tmp2_i32, s->A0, s->mem_index, MO_LEUL); - gen_helper_fildl_FT0(cpu_env, s->tmp2_i32); + gen_helper_fildl_FT0(tcg_env, s->tmp2_i32); break; case 2: tcg_gen_qemu_ld_i64(s->tmp1_i64, s->A0, s->mem_index, MO_LEUQ); - gen_helper_fldl_FT0(cpu_env, s->tmp1_i64); + gen_helper_fldl_FT0(tcg_env, s->tmp1_i64); break; case 3: default: tcg_gen_qemu_ld_i32(s->tmp2_i32, s->A0, s->mem_index, MO_LESW); - gen_helper_fildl_FT0(cpu_env, s->tmp2_i32); + gen_helper_fildl_FT0(tcg_env, s->tmp2_i32); break; } gen_helper_fp_arith_ST0_FT0(op1); if (op1 == 3) { /* fcomp needs pop */ - gen_helper_fpop(cpu_env); + gen_helper_fpop(tcg_env); } } break; @@ -4449,23 +4449,23 @@ static bool disas_insn(DisasContext *s, CPUState *cpu) case 0: tcg_gen_qemu_ld_i32(s->tmp2_i32, s->A0, s->mem_index, MO_LEUL); - gen_helper_flds_ST0(cpu_env, s->tmp2_i32); + gen_helper_flds_ST0(tcg_env, s->tmp2_i32); break; case 1: tcg_gen_qemu_ld_i32(s->tmp2_i32, s->A0, s->mem_index, MO_LEUL); - gen_helper_fildl_ST0(cpu_env, s->tmp2_i32); + gen_helper_fildl_ST0(tcg_env, s->tmp2_i32); break; case 2: tcg_gen_qemu_ld_i64(s->tmp1_i64, s->A0, s->mem_index, MO_LEUQ); - gen_helper_fldl_ST0(cpu_env, s->tmp1_i64); + gen_helper_fldl_ST0(tcg_env, s->tmp1_i64); break; case 3: default: tcg_gen_qemu_ld_i32(s->tmp2_i32, s->A0, s->mem_index, MO_LESW); - gen_helper_fildl_ST0(cpu_env, s->tmp2_i32); + gen_helper_fildl_ST0(tcg_env, s->tmp2_i32); break; } break; @@ -4473,116 +4473,116 @@ static bool disas_insn(DisasContext *s, CPUState *cpu) /* XXX: the corresponding CPUID bit must be tested ! */ switch (op >> 4) { case 1: - gen_helper_fisttl_ST0(s->tmp2_i32, cpu_env); + gen_helper_fisttl_ST0(s->tmp2_i32, tcg_env); tcg_gen_qemu_st_i32(s->tmp2_i32, s->A0, s->mem_index, MO_LEUL); break; case 2: - gen_helper_fisttll_ST0(s->tmp1_i64, cpu_env); + gen_helper_fisttll_ST0(s->tmp1_i64, tcg_env); tcg_gen_qemu_st_i64(s->tmp1_i64, s->A0, s->mem_index, MO_LEUQ); break; case 3: default: - gen_helper_fistt_ST0(s->tmp2_i32, cpu_env); + gen_helper_fistt_ST0(s->tmp2_i32, tcg_env); tcg_gen_qemu_st_i32(s->tmp2_i32, s->A0, s->mem_index, MO_LEUW); break; } - gen_helper_fpop(cpu_env); + gen_helper_fpop(tcg_env); break; default: switch (op >> 4) { case 0: - gen_helper_fsts_ST0(s->tmp2_i32, cpu_env); + gen_helper_fsts_ST0(s->tmp2_i32, tcg_env); tcg_gen_qemu_st_i32(s->tmp2_i32, s->A0, s->mem_index, MO_LEUL); break; case 1: - gen_helper_fistl_ST0(s->tmp2_i32, cpu_env); + gen_helper_fistl_ST0(s->tmp2_i32, tcg_env); tcg_gen_qemu_st_i32(s->tmp2_i32, s->A0, s->mem_index, MO_LEUL); break; case 2: - gen_helper_fstl_ST0(s->tmp1_i64, cpu_env); + gen_helper_fstl_ST0(s->tmp1_i64, tcg_env); tcg_gen_qemu_st_i64(s->tmp1_i64, s->A0, s->mem_index, MO_LEUQ); break; case 3: default: - gen_helper_fist_ST0(s->tmp2_i32, cpu_env); + gen_helper_fist_ST0(s->tmp2_i32, tcg_env); tcg_gen_qemu_st_i32(s->tmp2_i32, s->A0, s->mem_index, MO_LEUW); break; } if ((op & 7) == 3) { - gen_helper_fpop(cpu_env); + gen_helper_fpop(tcg_env); } break; } break; case 0x0c: /* fldenv mem */ - gen_helper_fldenv(cpu_env, s->A0, + gen_helper_fldenv(tcg_env, s->A0, tcg_constant_i32(dflag - 1)); update_fip = update_fdp = false; break; case 0x0d: /* fldcw mem */ tcg_gen_qemu_ld_i32(s->tmp2_i32, s->A0, s->mem_index, MO_LEUW); - gen_helper_fldcw(cpu_env, s->tmp2_i32); + gen_helper_fldcw(tcg_env, s->tmp2_i32); update_fip = update_fdp = false; break; case 0x0e: /* fnstenv mem */ - gen_helper_fstenv(cpu_env, s->A0, + gen_helper_fstenv(tcg_env, s->A0, tcg_constant_i32(dflag - 1)); update_fip = update_fdp = false; break; case 0x0f: /* fnstcw mem */ - gen_helper_fnstcw(s->tmp2_i32, cpu_env); + gen_helper_fnstcw(s->tmp2_i32, tcg_env); tcg_gen_qemu_st_i32(s->tmp2_i32, s->A0, s->mem_index, MO_LEUW); update_fip = update_fdp = false; break; case 0x1d: /* fldt mem */ - gen_helper_fldt_ST0(cpu_env, s->A0); + gen_helper_fldt_ST0(tcg_env, s->A0); break; case 0x1f: /* fstpt mem */ - gen_helper_fstt_ST0(cpu_env, s->A0); - gen_helper_fpop(cpu_env); + gen_helper_fstt_ST0(tcg_env, s->A0); + gen_helper_fpop(tcg_env); break; case 0x2c: /* frstor mem */ - gen_helper_frstor(cpu_env, s->A0, + gen_helper_frstor(tcg_env, s->A0, tcg_constant_i32(dflag - 1)); update_fip = update_fdp = false; break; case 0x2e: /* fnsave mem */ - gen_helper_fsave(cpu_env, s->A0, + gen_helper_fsave(tcg_env, s->A0, tcg_constant_i32(dflag - 1)); update_fip = update_fdp = false; break; case 0x2f: /* fnstsw mem */ - gen_helper_fnstsw(s->tmp2_i32, cpu_env); + gen_helper_fnstsw(s->tmp2_i32, tcg_env); tcg_gen_qemu_st_i32(s->tmp2_i32, s->A0, s->mem_index, MO_LEUW); update_fip = update_fdp = false; break; case 0x3c: /* fbld */ - gen_helper_fbld_ST0(cpu_env, s->A0); + gen_helper_fbld_ST0(tcg_env, s->A0); break; case 0x3e: /* fbstp */ - gen_helper_fbst_ST0(cpu_env, s->A0); - gen_helper_fpop(cpu_env); + gen_helper_fbst_ST0(tcg_env, s->A0); + gen_helper_fpop(tcg_env); break; case 0x3d: /* fildll */ tcg_gen_qemu_ld_i64(s->tmp1_i64, s->A0, s->mem_index, MO_LEUQ); - gen_helper_fildll_ST0(cpu_env, s->tmp1_i64); + gen_helper_fildll_ST0(tcg_env, s->tmp1_i64); break; case 0x3f: /* fistpll */ - gen_helper_fistll_ST0(s->tmp1_i64, cpu_env); + gen_helper_fistll_ST0(s->tmp1_i64, tcg_env); tcg_gen_qemu_st_i64(s->tmp1_i64, s->A0, s->mem_index, MO_LEUQ); - gen_helper_fpop(cpu_env); + gen_helper_fpop(tcg_env); break; default: goto unknown_op; @@ -4591,12 +4591,12 @@ static bool disas_insn(DisasContext *s, CPUState *cpu) if (update_fdp) { int last_seg = s->override >= 0 ? s->override : a.def_seg; - tcg_gen_ld_i32(s->tmp2_i32, cpu_env, + tcg_gen_ld_i32(s->tmp2_i32, tcg_env, offsetof(CPUX86State, segs[last_seg].selector)); - tcg_gen_st16_i32(s->tmp2_i32, cpu_env, + tcg_gen_st16_i32(s->tmp2_i32, tcg_env, offsetof(CPUX86State, fpds)); - tcg_gen_st_tl(last_addr, cpu_env, + tcg_gen_st_tl(last_addr, tcg_env, offsetof(CPUX86State, fpdp)); } } else { @@ -4605,14 +4605,14 @@ static bool disas_insn(DisasContext *s, CPUState *cpu) switch (op) { case 0x08: /* fld sti */ - gen_helper_fpush(cpu_env); - gen_helper_fmov_ST0_STN(cpu_env, + gen_helper_fpush(tcg_env); + gen_helper_fmov_ST0_STN(tcg_env, tcg_constant_i32((opreg + 1) & 7)); break; case 0x09: /* fxchg sti */ case 0x29: /* fxchg4 sti, undocumented op */ case 0x39: /* fxchg7 sti, undocumented op */ - gen_helper_fxchg_ST0_STN(cpu_env, tcg_constant_i32(opreg)); + gen_helper_fxchg_ST0_STN(tcg_env, tcg_constant_i32(opreg)); break; case 0x0a: /* grp d9/2 */ switch (rm) { @@ -4622,7 +4622,7 @@ static bool disas_insn(DisasContext *s, CPUState *cpu) * needs to be treated as I/O because of ferr_irq */ translator_io_start(&s->base); - gen_helper_fwait(cpu_env); + gen_helper_fwait(tcg_env); update_fip = false; break; default: @@ -4632,17 +4632,17 @@ static bool disas_insn(DisasContext *s, CPUState *cpu) case 0x0c: /* grp d9/4 */ switch (rm) { case 0: /* fchs */ - gen_helper_fchs_ST0(cpu_env); + gen_helper_fchs_ST0(tcg_env); break; case 1: /* fabs */ - gen_helper_fabs_ST0(cpu_env); + gen_helper_fabs_ST0(tcg_env); break; case 4: /* ftst */ - gen_helper_fldz_FT0(cpu_env); - gen_helper_fcom_ST0_FT0(cpu_env); + gen_helper_fldz_FT0(tcg_env); + gen_helper_fcom_ST0_FT0(tcg_env); break; case 5: /* fxam */ - gen_helper_fxam_ST0(cpu_env); + gen_helper_fxam_ST0(tcg_env); break; default: goto unknown_op; @@ -4652,32 +4652,32 @@ static bool disas_insn(DisasContext *s, CPUState *cpu) { switch (rm) { case 0: - gen_helper_fpush(cpu_env); - gen_helper_fld1_ST0(cpu_env); + gen_helper_fpush(tcg_env); + gen_helper_fld1_ST0(tcg_env); break; case 1: - gen_helper_fpush(cpu_env); - gen_helper_fldl2t_ST0(cpu_env); + gen_helper_fpush(tcg_env); + gen_helper_fldl2t_ST0(tcg_env); break; case 2: - gen_helper_fpush(cpu_env); - gen_helper_fldl2e_ST0(cpu_env); + gen_helper_fpush(tcg_env); + gen_helper_fldl2e_ST0(tcg_env); break; case 3: - gen_helper_fpush(cpu_env); - gen_helper_fldpi_ST0(cpu_env); + gen_helper_fpush(tcg_env); + gen_helper_fldpi_ST0(tcg_env); break; case 4: - gen_helper_fpush(cpu_env); - gen_helper_fldlg2_ST0(cpu_env); + gen_helper_fpush(tcg_env); + gen_helper_fldlg2_ST0(tcg_env); break; case 5: - gen_helper_fpush(cpu_env); - gen_helper_fldln2_ST0(cpu_env); + gen_helper_fpush(tcg_env); + gen_helper_fldln2_ST0(tcg_env); break; case 6: - gen_helper_fpush(cpu_env); - gen_helper_fldz_ST0(cpu_env); + gen_helper_fpush(tcg_env); + gen_helper_fldz_ST0(tcg_env); break; default: goto unknown_op; @@ -4687,58 +4687,58 @@ static bool disas_insn(DisasContext *s, CPUState *cpu) case 0x0e: /* grp d9/6 */ switch (rm) { case 0: /* f2xm1 */ - gen_helper_f2xm1(cpu_env); + gen_helper_f2xm1(tcg_env); break; case 1: /* fyl2x */ - gen_helper_fyl2x(cpu_env); + gen_helper_fyl2x(tcg_env); break; case 2: /* fptan */ - gen_helper_fptan(cpu_env); + gen_helper_fptan(tcg_env); break; case 3: /* fpatan */ - gen_helper_fpatan(cpu_env); + gen_helper_fpatan(tcg_env); break; case 4: /* fxtract */ - gen_helper_fxtract(cpu_env); + gen_helper_fxtract(tcg_env); break; case 5: /* fprem1 */ - gen_helper_fprem1(cpu_env); + gen_helper_fprem1(tcg_env); break; case 6: /* fdecstp */ - gen_helper_fdecstp(cpu_env); + gen_helper_fdecstp(tcg_env); break; default: case 7: /* fincstp */ - gen_helper_fincstp(cpu_env); + gen_helper_fincstp(tcg_env); break; } break; case 0x0f: /* grp d9/7 */ switch (rm) { case 0: /* fprem */ - gen_helper_fprem(cpu_env); + gen_helper_fprem(tcg_env); break; case 1: /* fyl2xp1 */ - gen_helper_fyl2xp1(cpu_env); + gen_helper_fyl2xp1(tcg_env); break; case 2: /* fsqrt */ - gen_helper_fsqrt(cpu_env); + gen_helper_fsqrt(tcg_env); break; case 3: /* fsincos */ - gen_helper_fsincos(cpu_env); + gen_helper_fsincos(tcg_env); break; case 5: /* fscale */ - gen_helper_fscale(cpu_env); + gen_helper_fscale(tcg_env); break; case 4: /* frndint */ - gen_helper_frndint(cpu_env); + gen_helper_frndint(tcg_env); break; case 6: /* fsin */ - gen_helper_fsin(cpu_env); + gen_helper_fsin(tcg_env); break; default: case 7: /* fcos */ - gen_helper_fcos(cpu_env); + gen_helper_fcos(tcg_env); break; } break; @@ -4752,10 +4752,10 @@ static bool disas_insn(DisasContext *s, CPUState *cpu) if (op >= 0x20) { gen_helper_fp_arith_STN_ST0(op1, opreg); if (op >= 0x30) { - gen_helper_fpop(cpu_env); + gen_helper_fpop(tcg_env); } } else { - gen_helper_fmov_FT0_STN(cpu_env, + gen_helper_fmov_FT0_STN(tcg_env, tcg_constant_i32(opreg)); gen_helper_fp_arith_ST0_FT0(op1); } @@ -4763,23 +4763,23 @@ static bool disas_insn(DisasContext *s, CPUState *cpu) break; case 0x02: /* fcom */ case 0x22: /* fcom2, undocumented op */ - gen_helper_fmov_FT0_STN(cpu_env, tcg_constant_i32(opreg)); - gen_helper_fcom_ST0_FT0(cpu_env); + gen_helper_fmov_FT0_STN(tcg_env, tcg_constant_i32(opreg)); + gen_helper_fcom_ST0_FT0(tcg_env); break; case 0x03: /* fcomp */ case 0x23: /* fcomp3, undocumented op */ case 0x32: /* fcomp5, undocumented op */ - gen_helper_fmov_FT0_STN(cpu_env, tcg_constant_i32(opreg)); - gen_helper_fcom_ST0_FT0(cpu_env); - gen_helper_fpop(cpu_env); + gen_helper_fmov_FT0_STN(tcg_env, tcg_constant_i32(opreg)); + gen_helper_fcom_ST0_FT0(tcg_env); + gen_helper_fpop(tcg_env); break; case 0x15: /* da/5 */ switch (rm) { case 1: /* fucompp */ - gen_helper_fmov_FT0_STN(cpu_env, tcg_constant_i32(1)); - gen_helper_fucom_ST0_FT0(cpu_env); - gen_helper_fpop(cpu_env); - gen_helper_fpop(cpu_env); + gen_helper_fmov_FT0_STN(tcg_env, tcg_constant_i32(1)); + gen_helper_fucom_ST0_FT0(tcg_env); + gen_helper_fpop(tcg_env); + gen_helper_fpop(tcg_env); break; default: goto unknown_op; @@ -4792,11 +4792,11 @@ static bool disas_insn(DisasContext *s, CPUState *cpu) case 1: /* fdisi (287 only, just do nop here) */ break; case 2: /* fclex */ - gen_helper_fclex(cpu_env); + gen_helper_fclex(tcg_env); update_fip = false; break; case 3: /* fninit */ - gen_helper_fninit(cpu_env); + gen_helper_fninit(tcg_env); update_fip = false; break; case 4: /* fsetpm (287 only, just do nop here) */ @@ -4810,8 +4810,8 @@ static bool disas_insn(DisasContext *s, CPUState *cpu) goto illegal_op; } gen_update_cc_op(s); - gen_helper_fmov_FT0_STN(cpu_env, tcg_constant_i32(opreg)); - gen_helper_fucomi_ST0_FT0(cpu_env); + gen_helper_fmov_FT0_STN(tcg_env, tcg_constant_i32(opreg)); + gen_helper_fucomi_ST0_FT0(tcg_env); set_cc_op(s, CC_OP_EFLAGS); break; case 0x1e: /* fcomi */ @@ -4819,52 +4819,52 @@ static bool disas_insn(DisasContext *s, CPUState *cpu) goto illegal_op; } gen_update_cc_op(s); - gen_helper_fmov_FT0_STN(cpu_env, tcg_constant_i32(opreg)); - gen_helper_fcomi_ST0_FT0(cpu_env); + gen_helper_fmov_FT0_STN(tcg_env, tcg_constant_i32(opreg)); + gen_helper_fcomi_ST0_FT0(tcg_env); set_cc_op(s, CC_OP_EFLAGS); break; case 0x28: /* ffree sti */ - gen_helper_ffree_STN(cpu_env, tcg_constant_i32(opreg)); + gen_helper_ffree_STN(tcg_env, tcg_constant_i32(opreg)); break; case 0x2a: /* fst sti */ - gen_helper_fmov_STN_ST0(cpu_env, tcg_constant_i32(opreg)); + gen_helper_fmov_STN_ST0(tcg_env, tcg_constant_i32(opreg)); break; case 0x2b: /* fstp sti */ case 0x0b: /* fstp1 sti, undocumented op */ case 0x3a: /* fstp8 sti, undocumented op */ case 0x3b: /* fstp9 sti, undocumented op */ - gen_helper_fmov_STN_ST0(cpu_env, tcg_constant_i32(opreg)); - gen_helper_fpop(cpu_env); + gen_helper_fmov_STN_ST0(tcg_env, tcg_constant_i32(opreg)); + gen_helper_fpop(tcg_env); break; case 0x2c: /* fucom st(i) */ - gen_helper_fmov_FT0_STN(cpu_env, tcg_constant_i32(opreg)); - gen_helper_fucom_ST0_FT0(cpu_env); + gen_helper_fmov_FT0_STN(tcg_env, tcg_constant_i32(opreg)); + gen_helper_fucom_ST0_FT0(tcg_env); break; case 0x2d: /* fucomp st(i) */ - gen_helper_fmov_FT0_STN(cpu_env, tcg_constant_i32(opreg)); - gen_helper_fucom_ST0_FT0(cpu_env); - gen_helper_fpop(cpu_env); + gen_helper_fmov_FT0_STN(tcg_env, tcg_constant_i32(opreg)); + gen_helper_fucom_ST0_FT0(tcg_env); + gen_helper_fpop(tcg_env); break; case 0x33: /* de/3 */ switch (rm) { case 1: /* fcompp */ - gen_helper_fmov_FT0_STN(cpu_env, tcg_constant_i32(1)); - gen_helper_fcom_ST0_FT0(cpu_env); - gen_helper_fpop(cpu_env); - gen_helper_fpop(cpu_env); + gen_helper_fmov_FT0_STN(tcg_env, tcg_constant_i32(1)); + gen_helper_fcom_ST0_FT0(tcg_env); + gen_helper_fpop(tcg_env); + gen_helper_fpop(tcg_env); break; default: goto unknown_op; } break; case 0x38: /* ffreep sti, undocumented op */ - gen_helper_ffree_STN(cpu_env, tcg_constant_i32(opreg)); - gen_helper_fpop(cpu_env); + gen_helper_ffree_STN(tcg_env, tcg_constant_i32(opreg)); + gen_helper_fpop(tcg_env); break; case 0x3c: /* df/4 */ switch (rm) { case 0: - gen_helper_fnstsw(s->tmp2_i32, cpu_env); + gen_helper_fnstsw(s->tmp2_i32, tcg_env); tcg_gen_extu_i32_tl(s->T0, s->tmp2_i32); gen_op_mov_reg_v(s, MO_16, R_EAX, s->T0); break; @@ -4877,9 +4877,9 @@ static bool disas_insn(DisasContext *s, CPUState *cpu) goto illegal_op; } gen_update_cc_op(s); - gen_helper_fmov_FT0_STN(cpu_env, tcg_constant_i32(opreg)); - gen_helper_fucomi_ST0_FT0(cpu_env); - gen_helper_fpop(cpu_env); + gen_helper_fmov_FT0_STN(tcg_env, tcg_constant_i32(opreg)); + gen_helper_fucomi_ST0_FT0(tcg_env); + gen_helper_fpop(tcg_env); set_cc_op(s, CC_OP_EFLAGS); break; case 0x3e: /* fcomip */ @@ -4887,9 +4887,9 @@ static bool disas_insn(DisasContext *s, CPUState *cpu) goto illegal_op; } gen_update_cc_op(s); - gen_helper_fmov_FT0_STN(cpu_env, tcg_constant_i32(opreg)); - gen_helper_fcomi_ST0_FT0(cpu_env); - gen_helper_fpop(cpu_env); + gen_helper_fmov_FT0_STN(tcg_env, tcg_constant_i32(opreg)); + gen_helper_fcomi_ST0_FT0(tcg_env); + gen_helper_fpop(tcg_env); set_cc_op(s, CC_OP_EFLAGS); break; case 0x10 ... 0x13: /* fcmovxx */ @@ -4910,7 +4910,7 @@ static bool disas_insn(DisasContext *s, CPUState *cpu) op1 = fcmov_cc[op & 3] | (((op >> 3) & 1) ^ 1); l1 = gen_new_label(); gen_jcc1_noeob(s, op1, l1); - gen_helper_fmov_ST0_STN(cpu_env, + gen_helper_fmov_ST0_STN(tcg_env, tcg_constant_i32(opreg)); gen_set_label(l1); } @@ -4921,12 +4921,12 @@ static bool disas_insn(DisasContext *s, CPUState *cpu) } if (update_fip) { - tcg_gen_ld_i32(s->tmp2_i32, cpu_env, + tcg_gen_ld_i32(s->tmp2_i32, tcg_env, offsetof(CPUX86State, segs[R_CS].selector)); - tcg_gen_st16_i32(s->tmp2_i32, cpu_env, + tcg_gen_st16_i32(s->tmp2_i32, tcg_env, offsetof(CPUX86State, fpcs)); tcg_gen_st_tl(eip_cur_tl(s), - cpu_env, offsetof(CPUX86State, fpip)); + tcg_env, offsetof(CPUX86State, fpip)); } } break; @@ -5099,7 +5099,7 @@ static bool disas_insn(DisasContext *s, CPUState *cpu) if (PE(s) && !VM86(s)) { gen_update_cc_op(s); gen_update_eip_cur(s); - gen_helper_lret_protected(cpu_env, tcg_constant_i32(dflag - 1), + gen_helper_lret_protected(tcg_env, tcg_constant_i32(dflag - 1), tcg_constant_i32(val)); } else { gen_stack_A0(s); @@ -5127,9 +5127,9 @@ static bool disas_insn(DisasContext *s, CPUState *cpu) if (!check_vm86_iopl(s)) { break; } - gen_helper_iret_real(cpu_env, tcg_constant_i32(dflag - 1)); + gen_helper_iret_real(tcg_env, tcg_constant_i32(dflag - 1)); } else { - gen_helper_iret_protected(cpu_env, tcg_constant_i32(dflag - 1), + gen_helper_iret_protected(tcg_env, tcg_constant_i32(dflag - 1), eip_next_i32(s)); } set_cc_op(s, CC_OP_EFLAGS); @@ -5226,7 +5226,7 @@ static bool disas_insn(DisasContext *s, CPUState *cpu) gen_svm_check_intercept(s, SVM_EXIT_PUSHF); if (check_vm86_iopl(s)) { gen_update_cc_op(s); - gen_helper_read_eflags(s->T0, cpu_env); + gen_helper_read_eflags(s->T0, tcg_env); gen_push_v(s, s->T0); } break; @@ -5245,7 +5245,7 @@ static bool disas_insn(DisasContext *s, CPUState *cpu) } ot = gen_pop_T0(s); - gen_helper_write_eflags(cpu_env, s->T0, tcg_constant_i32(mask)); + gen_helper_write_eflags(tcg_env, s->T0, tcg_constant_i32(mask)); gen_pop_update(s, ot); set_cc_op(s, CC_OP_EFLAGS); /* abort translation because TF/AC flag may change */ @@ -5283,11 +5283,11 @@ static bool disas_insn(DisasContext *s, CPUState *cpu) break; case 0xfc: /* cld */ tcg_gen_movi_i32(s->tmp2_i32, 1); - tcg_gen_st_i32(s->tmp2_i32, cpu_env, offsetof(CPUX86State, df)); + tcg_gen_st_i32(s->tmp2_i32, tcg_env, offsetof(CPUX86State, df)); break; case 0xfd: /* std */ tcg_gen_movi_i32(s->tmp2_i32, -1); - tcg_gen_st_i32(s->tmp2_i32, cpu_env, offsetof(CPUX86State, df)); + tcg_gen_st_i32(s->tmp2_i32, tcg_env, offsetof(CPUX86State, df)); break; /************************/ @@ -5485,28 +5485,28 @@ static bool disas_insn(DisasContext *s, CPUState *cpu) if (CODE64(s)) goto illegal_op; gen_update_cc_op(s); - gen_helper_daa(cpu_env); + gen_helper_daa(tcg_env); set_cc_op(s, CC_OP_EFLAGS); break; case 0x2f: /* das */ if (CODE64(s)) goto illegal_op; gen_update_cc_op(s); - gen_helper_das(cpu_env); + gen_helper_das(tcg_env); set_cc_op(s, CC_OP_EFLAGS); break; case 0x37: /* aaa */ if (CODE64(s)) goto illegal_op; gen_update_cc_op(s); - gen_helper_aaa(cpu_env); + gen_helper_aaa(tcg_env); set_cc_op(s, CC_OP_EFLAGS); break; case 0x3f: /* aas */ if (CODE64(s)) goto illegal_op; gen_update_cc_op(s); - gen_helper_aas(cpu_env); + gen_helper_aas(tcg_env); set_cc_op(s, CC_OP_EFLAGS); break; case 0xd4: /* aam */ @@ -5516,7 +5516,7 @@ static bool disas_insn(DisasContext *s, CPUState *cpu) if (val == 0) { gen_exception(s, EXCP00_DIVZ); } else { - gen_helper_aam(cpu_env, tcg_constant_i32(val)); + gen_helper_aam(tcg_env, tcg_constant_i32(val)); set_cc_op(s, CC_OP_LOGICB); } break; @@ -5524,7 +5524,7 @@ static bool disas_insn(DisasContext *s, CPUState *cpu) if (CODE64(s)) goto illegal_op; val = x86_ldub_code(env, s); - gen_helper_aad(cpu_env, tcg_constant_i32(val)); + gen_helper_aad(tcg_env, tcg_constant_i32(val)); set_cc_op(s, CC_OP_LOGICB); break; /************************/ @@ -5541,7 +5541,7 @@ static bool disas_insn(DisasContext *s, CPUState *cpu) if (prefixes & PREFIX_REPZ) { gen_update_cc_op(s); gen_update_eip_cur(s); - gen_helper_pause(cpu_env, cur_insn_len_i32(s)); + gen_helper_pause(tcg_env, cur_insn_len_i32(s)); s->base.is_jmp = DISAS_NORETURN; } break; @@ -5552,7 +5552,7 @@ static bool disas_insn(DisasContext *s, CPUState *cpu) } else { /* needs to be treated as I/O because of ferr_irq */ translator_io_start(&s->base); - gen_helper_fwait(cpu_env); + gen_helper_fwait(tcg_env); } break; case 0xcc: /* int3 */ @@ -5569,7 +5569,7 @@ static bool disas_insn(DisasContext *s, CPUState *cpu) goto illegal_op; gen_update_cc_op(s); gen_update_eip_cur(s); - gen_helper_into(cpu_env, cur_insn_len_i32(s)); + gen_helper_into(tcg_env, cur_insn_len_i32(s)); break; #ifdef WANT_ICEBP case 0xf1: /* icebp (undocumented, exits to external debugger) */ @@ -5603,9 +5603,9 @@ static bool disas_insn(DisasContext *s, CPUState *cpu) gen_lea_modrm(env, s, modrm); tcg_gen_trunc_tl_i32(s->tmp2_i32, s->T0); if (ot == MO_16) { - gen_helper_boundw(cpu_env, s->A0, s->tmp2_i32); + gen_helper_boundw(tcg_env, s->A0, s->tmp2_i32); } else { - gen_helper_boundl(cpu_env, s->A0, s->tmp2_i32); + gen_helper_boundl(tcg_env, s->A0, s->tmp2_i32); } break; case 0x1c8 ... 0x1cf: /* bswap reg */ @@ -5667,9 +5667,9 @@ static bool disas_insn(DisasContext *s, CPUState *cpu) gen_update_cc_op(s); gen_update_eip_cur(s); if (b & 2) { - gen_helper_rdmsr(cpu_env); + gen_helper_rdmsr(tcg_env); } else { - gen_helper_wrmsr(cpu_env); + gen_helper_wrmsr(tcg_env); s->base.is_jmp = DISAS_EOB_NEXT; } } @@ -5678,12 +5678,12 @@ static bool disas_insn(DisasContext *s, CPUState *cpu) gen_update_cc_op(s); gen_update_eip_cur(s); translator_io_start(&s->base); - gen_helper_rdtsc(cpu_env); + gen_helper_rdtsc(tcg_env); break; case 0x133: /* rdpmc */ gen_update_cc_op(s); gen_update_eip_cur(s); - gen_helper_rdpmc(cpu_env); + gen_helper_rdpmc(tcg_env); s->base.is_jmp = DISAS_NORETURN; break; case 0x134: /* sysenter */ @@ -5694,7 +5694,7 @@ static bool disas_insn(DisasContext *s, CPUState *cpu) if (!PE(s)) { gen_exception_gpf(s); } else { - gen_helper_sysenter(cpu_env); + gen_helper_sysenter(tcg_env); s->base.is_jmp = DISAS_EOB_ONLY; } break; @@ -5706,7 +5706,7 @@ static bool disas_insn(DisasContext *s, CPUState *cpu) if (!PE(s) || CPL(s) != 0) { gen_exception_gpf(s); } else { - gen_helper_sysexit(cpu_env, tcg_constant_i32(dflag - 1)); + gen_helper_sysexit(tcg_env, tcg_constant_i32(dflag - 1)); s->base.is_jmp = DISAS_EOB_ONLY; } break; @@ -5717,7 +5717,7 @@ static bool disas_insn(DisasContext *s, CPUState *cpu) } gen_update_cc_op(s); gen_update_eip_cur(s); - gen_helper_syscall(cpu_env, cur_insn_len_i32(s)); + gen_helper_syscall(tcg_env, cur_insn_len_i32(s)); /* TF handling for the syscall insn is different. The TF bit is checked after the syscall insn completes. This allows #DB to not be generated after one has entered CPL0 if TF is set in FMASK. */ @@ -5731,7 +5731,7 @@ static bool disas_insn(DisasContext *s, CPUState *cpu) if (!PE(s) || CPL(s) != 0) { gen_exception_gpf(s); } else { - gen_helper_sysret(cpu_env, tcg_constant_i32(dflag - 1)); + gen_helper_sysret(tcg_env, tcg_constant_i32(dflag - 1)); /* condition codes are modified only in long mode */ if (LMA(s)) { set_cc_op(s, CC_OP_EFLAGS); @@ -5746,13 +5746,13 @@ static bool disas_insn(DisasContext *s, CPUState *cpu) case 0x1a2: /* cpuid */ gen_update_cc_op(s); gen_update_eip_cur(s); - gen_helper_cpuid(cpu_env); + gen_helper_cpuid(tcg_env); break; case 0xf4: /* hlt */ if (check_cpl0(s)) { gen_update_cc_op(s); gen_update_eip_cur(s); - gen_helper_hlt(cpu_env, cur_insn_len_i32(s)); + gen_helper_hlt(tcg_env, cur_insn_len_i32(s)); s->base.is_jmp = DISAS_NORETURN; } break; @@ -5768,7 +5768,7 @@ static bool disas_insn(DisasContext *s, CPUState *cpu) break; } gen_svm_check_intercept(s, SVM_EXIT_LDTR_READ); - tcg_gen_ld32u_tl(s->T0, cpu_env, + tcg_gen_ld32u_tl(s->T0, tcg_env, offsetof(CPUX86State, ldt.selector)); ot = mod == 3 ? dflag : MO_16; gen_ldst_modrm(env, s, modrm, ot, OR_TMP0, 1); @@ -5780,7 +5780,7 @@ static bool disas_insn(DisasContext *s, CPUState *cpu) gen_svm_check_intercept(s, SVM_EXIT_LDTR_WRITE); gen_ldst_modrm(env, s, modrm, MO_16, OR_TMP0, 0); tcg_gen_trunc_tl_i32(s->tmp2_i32, s->T0); - gen_helper_lldt(cpu_env, s->tmp2_i32); + gen_helper_lldt(tcg_env, s->tmp2_i32); } break; case 1: /* str */ @@ -5790,7 +5790,7 @@ static bool disas_insn(DisasContext *s, CPUState *cpu) break; } gen_svm_check_intercept(s, SVM_EXIT_TR_READ); - tcg_gen_ld32u_tl(s->T0, cpu_env, + tcg_gen_ld32u_tl(s->T0, tcg_env, offsetof(CPUX86State, tr.selector)); ot = mod == 3 ? dflag : MO_16; gen_ldst_modrm(env, s, modrm, ot, OR_TMP0, 1); @@ -5802,7 +5802,7 @@ static bool disas_insn(DisasContext *s, CPUState *cpu) gen_svm_check_intercept(s, SVM_EXIT_TR_WRITE); gen_ldst_modrm(env, s, modrm, MO_16, OR_TMP0, 0); tcg_gen_trunc_tl_i32(s->tmp2_i32, s->T0); - gen_helper_ltr(cpu_env, s->tmp2_i32); + gen_helper_ltr(tcg_env, s->tmp2_i32); } break; case 4: /* verr */ @@ -5812,9 +5812,9 @@ static bool disas_insn(DisasContext *s, CPUState *cpu) gen_ldst_modrm(env, s, modrm, MO_16, OR_TMP0, 0); gen_update_cc_op(s); if (op == 4) { - gen_helper_verr(cpu_env, s->T0); + gen_helper_verr(tcg_env, s->T0); } else { - gen_helper_verw(cpu_env, s->T0); + gen_helper_verw(tcg_env, s->T0); } set_cc_op(s, CC_OP_EFLAGS); break; @@ -5833,10 +5833,10 @@ static bool disas_insn(DisasContext *s, CPUState *cpu) gen_svm_check_intercept(s, SVM_EXIT_GDTR_READ); gen_lea_modrm(env, s, modrm); tcg_gen_ld32u_tl(s->T0, - cpu_env, offsetof(CPUX86State, gdt.limit)); + tcg_env, offsetof(CPUX86State, gdt.limit)); gen_op_st_v(s, MO_16, s->T0, s->A0); gen_add_A0_im(s, 2); - tcg_gen_ld_tl(s->T0, cpu_env, offsetof(CPUX86State, gdt.base)); + tcg_gen_ld_tl(s->T0, tcg_env, offsetof(CPUX86State, gdt.base)); if (dflag == MO_16) { tcg_gen_andi_tl(s->T0, s->T0, 0xffffff); } @@ -5852,7 +5852,7 @@ static bool disas_insn(DisasContext *s, CPUState *cpu) tcg_gen_mov_tl(s->A0, cpu_regs[R_EAX]); gen_extu(s->aflag, s->A0); gen_add_A0_ds_seg(s); - gen_helper_monitor(cpu_env, s->A0); + gen_helper_monitor(tcg_env, s->A0); break; case 0xc9: /* mwait */ @@ -5861,7 +5861,7 @@ static bool disas_insn(DisasContext *s, CPUState *cpu) } gen_update_cc_op(s); gen_update_eip_cur(s); - gen_helper_mwait(cpu_env, cur_insn_len_i32(s)); + gen_helper_mwait(tcg_env, cur_insn_len_i32(s)); s->base.is_jmp = DISAS_NORETURN; break; @@ -5889,10 +5889,10 @@ static bool disas_insn(DisasContext *s, CPUState *cpu) } gen_svm_check_intercept(s, SVM_EXIT_IDTR_READ); gen_lea_modrm(env, s, modrm); - tcg_gen_ld32u_tl(s->T0, cpu_env, offsetof(CPUX86State, idt.limit)); + tcg_gen_ld32u_tl(s->T0, tcg_env, offsetof(CPUX86State, idt.limit)); gen_op_st_v(s, MO_16, s->T0, s->A0); gen_add_A0_im(s, 2); - tcg_gen_ld_tl(s->T0, cpu_env, offsetof(CPUX86State, idt.base)); + tcg_gen_ld_tl(s->T0, tcg_env, offsetof(CPUX86State, idt.base)); if (dflag == MO_16) { tcg_gen_andi_tl(s->T0, s->T0, 0xffffff); } @@ -5906,7 +5906,7 @@ static bool disas_insn(DisasContext *s, CPUState *cpu) goto illegal_op; } tcg_gen_trunc_tl_i32(s->tmp2_i32, cpu_regs[R_ECX]); - gen_helper_xgetbv(s->tmp1_i64, cpu_env, s->tmp2_i32); + gen_helper_xgetbv(s->tmp1_i64, tcg_env, s->tmp2_i32); tcg_gen_extr_i64_tl(cpu_regs[R_EAX], cpu_regs[R_EDX], s->tmp1_i64); break; @@ -5922,7 +5922,7 @@ static bool disas_insn(DisasContext *s, CPUState *cpu) tcg_gen_concat_tl_i64(s->tmp1_i64, cpu_regs[R_EAX], cpu_regs[R_EDX]); tcg_gen_trunc_tl_i32(s->tmp2_i32, cpu_regs[R_ECX]); - gen_helper_xsetbv(cpu_env, s->tmp2_i32, s->tmp1_i64); + gen_helper_xsetbv(tcg_env, s->tmp2_i32, s->tmp1_i64); /* End TB because translation flags may change. */ s->base.is_jmp = DISAS_EOB_NEXT; break; @@ -5936,7 +5936,7 @@ static bool disas_insn(DisasContext *s, CPUState *cpu) } gen_update_cc_op(s); gen_update_eip_cur(s); - gen_helper_vmrun(cpu_env, tcg_constant_i32(s->aflag - 1), + gen_helper_vmrun(tcg_env, tcg_constant_i32(s->aflag - 1), cur_insn_len_i32(s)); tcg_gen_exit_tb(NULL, 0); s->base.is_jmp = DISAS_NORETURN; @@ -5948,7 +5948,7 @@ static bool disas_insn(DisasContext *s, CPUState *cpu) } gen_update_cc_op(s); gen_update_eip_cur(s); - gen_helper_vmmcall(cpu_env); + gen_helper_vmmcall(tcg_env); break; case 0xda: /* VMLOAD */ @@ -5960,7 +5960,7 @@ static bool disas_insn(DisasContext *s, CPUState *cpu) } gen_update_cc_op(s); gen_update_eip_cur(s); - gen_helper_vmload(cpu_env, tcg_constant_i32(s->aflag - 1)); + gen_helper_vmload(tcg_env, tcg_constant_i32(s->aflag - 1)); break; case 0xdb: /* VMSAVE */ @@ -5972,7 +5972,7 @@ static bool disas_insn(DisasContext *s, CPUState *cpu) } gen_update_cc_op(s); gen_update_eip_cur(s); - gen_helper_vmsave(cpu_env, tcg_constant_i32(s->aflag - 1)); + gen_helper_vmsave(tcg_env, tcg_constant_i32(s->aflag - 1)); break; case 0xdc: /* STGI */ @@ -5984,7 +5984,7 @@ static bool disas_insn(DisasContext *s, CPUState *cpu) break; } gen_update_cc_op(s); - gen_helper_stgi(cpu_env); + gen_helper_stgi(tcg_env); s->base.is_jmp = DISAS_EOB_NEXT; break; @@ -5997,7 +5997,7 @@ static bool disas_insn(DisasContext *s, CPUState *cpu) } gen_update_cc_op(s); gen_update_eip_cur(s); - gen_helper_clgi(cpu_env); + gen_helper_clgi(tcg_env); break; case 0xde: /* SKINIT */ @@ -6022,7 +6022,7 @@ static bool disas_insn(DisasContext *s, CPUState *cpu) } else { tcg_gen_ext32u_tl(s->A0, cpu_regs[R_EAX]); } - gen_helper_flush_page(cpu_env, s->A0); + gen_helper_flush_page(tcg_env, s->A0); s->base.is_jmp = DISAS_EOB_NEXT; break; @@ -6038,8 +6038,8 @@ static bool disas_insn(DisasContext *s, CPUState *cpu) if (dflag == MO_16) { tcg_gen_andi_tl(s->T0, s->T0, 0xffffff); } - tcg_gen_st_tl(s->T0, cpu_env, offsetof(CPUX86State, gdt.base)); - tcg_gen_st32_tl(s->T1, cpu_env, offsetof(CPUX86State, gdt.limit)); + tcg_gen_st_tl(s->T0, tcg_env, offsetof(CPUX86State, gdt.base)); + tcg_gen_st32_tl(s->T1, tcg_env, offsetof(CPUX86State, gdt.limit)); break; CASE_MODRM_MEM_OP(3): /* lidt */ @@ -6054,8 +6054,8 @@ static bool disas_insn(DisasContext *s, CPUState *cpu) if (dflag == MO_16) { tcg_gen_andi_tl(s->T0, s->T0, 0xffffff); } - tcg_gen_st_tl(s->T0, cpu_env, offsetof(CPUX86State, idt.base)); - tcg_gen_st32_tl(s->T1, cpu_env, offsetof(CPUX86State, idt.limit)); + tcg_gen_st_tl(s->T0, tcg_env, offsetof(CPUX86State, idt.base)); + tcg_gen_st32_tl(s->T1, tcg_env, offsetof(CPUX86State, idt.limit)); break; CASE_MODRM_OP(4): /* smsw */ @@ -6063,7 +6063,7 @@ static bool disas_insn(DisasContext *s, CPUState *cpu) break; } gen_svm_check_intercept(s, SVM_EXIT_READ_CR0); - tcg_gen_ld_tl(s->T0, cpu_env, offsetof(CPUX86State, cr[0])); + tcg_gen_ld_tl(s->T0, tcg_env, offsetof(CPUX86State, cr[0])); /* * In 32-bit mode, the higher 16 bits of the destination * register are undefined. In practice CR0[31:0] is stored @@ -6078,7 +6078,7 @@ static bool disas_insn(DisasContext *s, CPUState *cpu) goto illegal_op; } tcg_gen_trunc_tl_i32(s->tmp2_i32, cpu_regs[R_ECX]); - gen_helper_rdpkru(s->tmp1_i64, cpu_env, s->tmp2_i32); + gen_helper_rdpkru(s->tmp1_i64, tcg_env, s->tmp2_i32); tcg_gen_extr_i64_tl(cpu_regs[R_EAX], cpu_regs[R_EDX], s->tmp1_i64); break; case 0xef: /* wrpkru */ @@ -6088,7 +6088,7 @@ static bool disas_insn(DisasContext *s, CPUState *cpu) tcg_gen_concat_tl_i64(s->tmp1_i64, cpu_regs[R_EAX], cpu_regs[R_EDX]); tcg_gen_trunc_tl_i32(s->tmp2_i32, cpu_regs[R_ECX]); - gen_helper_wrpkru(cpu_env, s->tmp2_i32, s->tmp1_i64); + gen_helper_wrpkru(tcg_env, s->tmp2_i32, s->tmp1_i64); break; CASE_MODRM_OP(6): /* lmsw */ @@ -6101,11 +6101,11 @@ static bool disas_insn(DisasContext *s, CPUState *cpu) * Only the 4 lower bits of CR0 are modified. * PE cannot be set to zero if already set to one. */ - tcg_gen_ld_tl(s->T1, cpu_env, offsetof(CPUX86State, cr[0])); + tcg_gen_ld_tl(s->T1, tcg_env, offsetof(CPUX86State, cr[0])); tcg_gen_andi_tl(s->T0, s->T0, 0xf); tcg_gen_andi_tl(s->T1, s->T1, ~0xe); tcg_gen_or_tl(s->T0, s->T0, s->T1); - gen_helper_write_crN(cpu_env, tcg_constant_i32(0), s->T0); + gen_helper_write_crN(tcg_env, tcg_constant_i32(0), s->T0); s->base.is_jmp = DISAS_EOB_NEXT; break; @@ -6115,7 +6115,7 @@ static bool disas_insn(DisasContext *s, CPUState *cpu) } gen_svm_check_intercept(s, SVM_EXIT_INVLPG); gen_lea_modrm(env, s, modrm); - gen_helper_flush_page(cpu_env, s->A0); + gen_helper_flush_page(tcg_env, s->A0); s->base.is_jmp = DISAS_EOB_NEXT; break; @@ -6124,9 +6124,9 @@ static bool disas_insn(DisasContext *s, CPUState *cpu) if (CODE64(s)) { if (check_cpl0(s)) { tcg_gen_mov_tl(s->T0, cpu_seg_base[R_GS]); - tcg_gen_ld_tl(cpu_seg_base[R_GS], cpu_env, + tcg_gen_ld_tl(cpu_seg_base[R_GS], tcg_env, offsetof(CPUX86State, kernelgsbase)); - tcg_gen_st_tl(s->T0, cpu_env, + tcg_gen_st_tl(s->T0, tcg_env, offsetof(CPUX86State, kernelgsbase)); } break; @@ -6141,8 +6141,8 @@ static bool disas_insn(DisasContext *s, CPUState *cpu) gen_update_cc_op(s); gen_update_eip_cur(s); translator_io_start(&s->base); - gen_helper_rdtsc(cpu_env); - gen_helper_rdpid(s->T0, cpu_env); + gen_helper_rdtsc(tcg_env); + gen_helper_rdpid(s->T0, tcg_env); gen_op_mov_reg_v(s, dflag, R_ECX, s->T0); break; @@ -6238,9 +6238,9 @@ static bool disas_insn(DisasContext *s, CPUState *cpu) t0 = tcg_temp_new(); gen_update_cc_op(s); if (b == 0x102) { - gen_helper_lar(t0, cpu_env, s->T0); + gen_helper_lar(t0, tcg_env, s->T0); } else { - gen_helper_lsl(t0, cpu_env, s->T0); + gen_helper_lsl(t0, tcg_env, s->T0); } tcg_gen_andi_tl(s->tmp0, cpu_cc_src, CC_Z); label1 = gen_new_label(); @@ -6345,11 +6345,11 @@ static bool disas_insn(DisasContext *s, CPUState *cpu) tcg_gen_movi_tl(s->T0, 0); } if (CODE64(s)) { - gen_helper_bndldx64(cpu_bndl[reg], cpu_env, s->A0, s->T0); - tcg_gen_ld_i64(cpu_bndu[reg], cpu_env, + gen_helper_bndldx64(cpu_bndl[reg], tcg_env, s->A0, s->T0); + tcg_gen_ld_i64(cpu_bndu[reg], tcg_env, offsetof(CPUX86State, mmx_t0.MMX_Q(0))); } else { - gen_helper_bndldx32(cpu_bndu[reg], cpu_env, s->A0, s->T0); + gen_helper_bndldx32(cpu_bndu[reg], tcg_env, s->A0, s->T0); tcg_gen_ext32u_i64(cpu_bndl[reg], cpu_bndu[reg]); tcg_gen_shri_i64(cpu_bndu[reg], cpu_bndu[reg], 32); } @@ -6450,10 +6450,10 @@ static bool disas_insn(DisasContext *s, CPUState *cpu) tcg_gen_movi_tl(s->T0, 0); } if (CODE64(s)) { - gen_helper_bndstx64(cpu_env, s->A0, s->T0, + gen_helper_bndstx64(tcg_env, s->A0, s->T0, cpu_bndl[reg], cpu_bndu[reg]); } else { - gen_helper_bndstx32(cpu_env, s->A0, s->T0, + gen_helper_bndstx32(tcg_env, s->A0, s->T0, cpu_bndl[reg], cpu_bndu[reg]); } } @@ -6500,11 +6500,11 @@ static bool disas_insn(DisasContext *s, CPUState *cpu) if (b & 2) { gen_svm_check_intercept(s, SVM_EXIT_WRITE_CR0 + reg); gen_op_mov_v_reg(s, ot, s->T0, rm); - gen_helper_write_crN(cpu_env, tcg_constant_i32(reg), s->T0); + gen_helper_write_crN(tcg_env, tcg_constant_i32(reg), s->T0); s->base.is_jmp = DISAS_EOB_NEXT; } else { gen_svm_check_intercept(s, SVM_EXIT_READ_CR0 + reg); - gen_helper_read_crN(s->T0, cpu_env, tcg_constant_i32(reg)); + gen_helper_read_crN(s->T0, tcg_env, tcg_constant_i32(reg)); gen_op_mov_reg_v(s, ot, rm, s->T0); } break; @@ -6531,12 +6531,12 @@ static bool disas_insn(DisasContext *s, CPUState *cpu) gen_svm_check_intercept(s, SVM_EXIT_WRITE_DR0 + reg); gen_op_mov_v_reg(s, ot, s->T0, rm); tcg_gen_movi_i32(s->tmp2_i32, reg); - gen_helper_set_dr(cpu_env, s->tmp2_i32, s->T0); + gen_helper_set_dr(tcg_env, s->tmp2_i32, s->T0); s->base.is_jmp = DISAS_EOB_NEXT; } else { gen_svm_check_intercept(s, SVM_EXIT_READ_DR0 + reg); tcg_gen_movi_i32(s->tmp2_i32, reg); - gen_helper_get_dr(s->T0, cpu_env, s->tmp2_i32); + gen_helper_get_dr(s->T0, tcg_env, s->tmp2_i32); gen_op_mov_reg_v(s, ot, rm, s->T0); } } @@ -6544,7 +6544,7 @@ static bool disas_insn(DisasContext *s, CPUState *cpu) case 0x106: /* clts */ if (check_cpl0(s)) { gen_svm_check_intercept(s, SVM_EXIT_WRITE_CR0); - gen_helper_clts(cpu_env); + gen_helper_clts(tcg_env); /* abort block because static cpu state changed */ s->base.is_jmp = DISAS_EOB_NEXT; } @@ -6575,7 +6575,7 @@ static bool disas_insn(DisasContext *s, CPUState *cpu) break; } gen_lea_modrm(env, s, modrm); - gen_helper_fxsave(cpu_env, s->A0); + gen_helper_fxsave(tcg_env, s->A0); break; CASE_MODRM_MEM_OP(1): /* fxrstor */ @@ -6588,7 +6588,7 @@ static bool disas_insn(DisasContext *s, CPUState *cpu) break; } gen_lea_modrm(env, s, modrm); - gen_helper_fxrstor(cpu_env, s->A0); + gen_helper_fxrstor(tcg_env, s->A0); break; CASE_MODRM_MEM_OP(2): /* ldmxcsr */ @@ -6601,7 +6601,7 @@ static bool disas_insn(DisasContext *s, CPUState *cpu) } gen_lea_modrm(env, s, modrm); tcg_gen_qemu_ld_i32(s->tmp2_i32, s->A0, s->mem_index, MO_LEUL); - gen_helper_ldmxcsr(cpu_env, s->tmp2_i32); + gen_helper_ldmxcsr(tcg_env, s->tmp2_i32); break; CASE_MODRM_MEM_OP(3): /* stmxcsr */ @@ -6612,9 +6612,9 @@ static bool disas_insn(DisasContext *s, CPUState *cpu) gen_exception(s, EXCP07_PREX); break; } - gen_helper_update_mxcsr(cpu_env); + gen_helper_update_mxcsr(tcg_env); gen_lea_modrm(env, s, modrm); - tcg_gen_ld32u_tl(s->T0, cpu_env, offsetof(CPUX86State, mxcsr)); + tcg_gen_ld32u_tl(s->T0, tcg_env, offsetof(CPUX86State, mxcsr)); gen_op_st_v(s, MO_32, s->T0, s->A0); break; @@ -6627,7 +6627,7 @@ static bool disas_insn(DisasContext *s, CPUState *cpu) gen_lea_modrm(env, s, modrm); tcg_gen_concat_tl_i64(s->tmp1_i64, cpu_regs[R_EAX], cpu_regs[R_EDX]); - gen_helper_xsave(cpu_env, s->A0, s->tmp1_i64); + gen_helper_xsave(tcg_env, s->A0, s->tmp1_i64); break; CASE_MODRM_MEM_OP(5): /* xrstor */ @@ -6639,7 +6639,7 @@ static bool disas_insn(DisasContext *s, CPUState *cpu) gen_lea_modrm(env, s, modrm); tcg_gen_concat_tl_i64(s->tmp1_i64, cpu_regs[R_EAX], cpu_regs[R_EDX]); - gen_helper_xrstor(cpu_env, s->A0, s->tmp1_i64); + gen_helper_xrstor(tcg_env, s->A0, s->tmp1_i64); /* XRSTOR is how MPX is enabled, which changes how we translate. Thus we need to end the TB. */ s->base.is_jmp = DISAS_EOB_NEXT; @@ -6665,7 +6665,7 @@ static bool disas_insn(DisasContext *s, CPUState *cpu) gen_lea_modrm(env, s, modrm); tcg_gen_concat_tl_i64(s->tmp1_i64, cpu_regs[R_EAX], cpu_regs[R_EDX]); - gen_helper_xsaveopt(cpu_env, s->A0, s->tmp1_i64); + gen_helper_xsaveopt(tcg_env, s->A0, s->tmp1_i64); } break; @@ -6700,7 +6700,7 @@ static bool disas_insn(DisasContext *s, CPUState *cpu) /* Preserve hflags bits by testing CR4 at runtime. */ tcg_gen_movi_i32(s->tmp2_i32, CR4_FSGSBASE_MASK); - gen_helper_cr4_testbit(cpu_env, s->tmp2_i32); + gen_helper_cr4_testbit(tcg_env, s->tmp2_i32); base = cpu_seg_base[modrm & 8 ? R_GS : R_FS]; treg = cpu_regs[(modrm & 7) | REX_B(s)]; @@ -6776,7 +6776,7 @@ static bool disas_insn(DisasContext *s, CPUState *cpu) #else gen_update_cc_op(s); gen_update_eip_next(s); - gen_helper_rsm(cpu_env); + gen_helper_rsm(tcg_env); #endif /* CONFIG_USER_ONLY */ s->base.is_jmp = DISAS_EOB_ONLY; break; @@ -6880,36 +6880,36 @@ void tcg_x86_init(void) }; int i; - cpu_cc_op = tcg_global_mem_new_i32(cpu_env, + cpu_cc_op = tcg_global_mem_new_i32(tcg_env, offsetof(CPUX86State, cc_op), "cc_op"); - cpu_cc_dst = tcg_global_mem_new(cpu_env, offsetof(CPUX86State, cc_dst), + cpu_cc_dst = tcg_global_mem_new(tcg_env, offsetof(CPUX86State, cc_dst), "cc_dst"); - cpu_cc_src = tcg_global_mem_new(cpu_env, offsetof(CPUX86State, cc_src), + cpu_cc_src = tcg_global_mem_new(tcg_env, offsetof(CPUX86State, cc_src), "cc_src"); - cpu_cc_src2 = tcg_global_mem_new(cpu_env, offsetof(CPUX86State, cc_src2), + cpu_cc_src2 = tcg_global_mem_new(tcg_env, offsetof(CPUX86State, cc_src2), "cc_src2"); - cpu_eip = tcg_global_mem_new(cpu_env, offsetof(CPUX86State, eip), eip_name); + cpu_eip = tcg_global_mem_new(tcg_env, offsetof(CPUX86State, eip), eip_name); for (i = 0; i < CPU_NB_REGS; ++i) { - cpu_regs[i] = tcg_global_mem_new(cpu_env, + cpu_regs[i] = tcg_global_mem_new(tcg_env, offsetof(CPUX86State, regs[i]), reg_names[i]); } for (i = 0; i < 6; ++i) { cpu_seg_base[i] - = tcg_global_mem_new(cpu_env, + = tcg_global_mem_new(tcg_env, offsetof(CPUX86State, segs[i].base), seg_base_names[i]); } for (i = 0; i < 4; ++i) { cpu_bndl[i] - = tcg_global_mem_new_i64(cpu_env, + = tcg_global_mem_new_i64(tcg_env, offsetof(CPUX86State, bnd_regs[i].lb), bnd_regl_names[i]); cpu_bndu[i] - = tcg_global_mem_new_i64(cpu_env, + = tcg_global_mem_new_i64(tcg_env, offsetof(CPUX86State, bnd_regs[i].ub), bnd_regu_names[i]); } diff --git a/target/loongarch/insn_trans/trans_atomic.c.inc b/target/loongarch/insn_trans/trans_atomic.c.inc index 40085190f6..80c2e286fd 100644 --- a/target/loongarch/insn_trans/trans_atomic.c.inc +++ b/target/loongarch/insn_trans/trans_atomic.c.inc @@ -10,8 +10,8 @@ static bool gen_ll(DisasContext *ctx, arg_rr_i *a, MemOp mop) TCGv t0 = make_address_i(ctx, src1, a->imm); tcg_gen_qemu_ld_i64(dest, t0, ctx->mem_idx, mop); - tcg_gen_st_tl(t0, cpu_env, offsetof(CPULoongArchState, lladdr)); - tcg_gen_st_tl(dest, cpu_env, offsetof(CPULoongArchState, llval)); + tcg_gen_st_tl(t0, tcg_env, offsetof(CPULoongArchState, lladdr)); + tcg_gen_st_tl(dest, tcg_env, offsetof(CPULoongArchState, llval)); gen_set_gpr(a->rd, dest, EXT_NONE); return true; diff --git a/target/loongarch/insn_trans/trans_branch.c.inc b/target/loongarch/insn_trans/trans_branch.c.inc index a4fd2092e5..221e5159db 100644 --- a/target/loongarch/insn_trans/trans_branch.c.inc +++ b/target/loongarch/insn_trans/trans_branch.c.inc @@ -66,7 +66,7 @@ static bool gen_cz_bc(DisasContext *ctx, arg_c_offs *a, TCGCond cond) TCGv src1 = tcg_temp_new(); TCGv src2 = tcg_constant_tl(0); - tcg_gen_ld8u_tl(src1, cpu_env, + tcg_gen_ld8u_tl(src1, tcg_env, offsetof(CPULoongArchState, cf[a->cj])); gen_bc(ctx, src1, src2, a->offs, cond); return true; diff --git a/target/loongarch/insn_trans/trans_extra.c.inc b/target/loongarch/insn_trans/trans_extra.c.inc index dd5d02e88c..cfa361fecf 100644 --- a/target/loongarch/insn_trans/trans_extra.c.inc +++ b/target/loongarch/insn_trans/trans_extra.c.inc @@ -24,7 +24,7 @@ static bool trans_asrtle_d(DisasContext *ctx, arg_asrtle_d * a) return false; } - gen_helper_asrtle_d(cpu_env, src1, src2); + gen_helper_asrtle_d(tcg_env, src1, src2); return true; } @@ -37,7 +37,7 @@ static bool trans_asrtgt_d(DisasContext *ctx, arg_asrtgt_d * a) return false; } - gen_helper_asrtgt_d(cpu_env, src1, src2); + gen_helper_asrtgt_d(tcg_env, src1, src2); return true; } @@ -48,11 +48,11 @@ static bool gen_rdtime(DisasContext *ctx, arg_rr *a, TCGv dst2 = gpr_dst(ctx, a->rj, EXT_NONE); translator_io_start(&ctx->base); - gen_helper_rdtime_d(dst1, cpu_env); + gen_helper_rdtime_d(dst1, tcg_env); if (word) { tcg_gen_sextract_tl(dst1, dst1, high ? 32 : 0, 32); } - tcg_gen_ld_i64(dst2, cpu_env, offsetof(CPULoongArchState, CSR_TID)); + tcg_gen_ld_i64(dst2, tcg_env, offsetof(CPULoongArchState, CSR_TID)); return true; } @@ -77,7 +77,7 @@ static bool trans_cpucfg(DisasContext *ctx, arg_cpucfg *a) TCGv dest = gpr_dst(ctx, a->rd, EXT_NONE); TCGv src1 = gpr_src(ctx, a->rj, EXT_NONE); - gen_helper_cpucfg(dest, cpu_env, src1); + gen_helper_cpucfg(dest, tcg_env, src1); gen_set_gpr(a->rd, dest, EXT_NONE); return true; diff --git a/target/loongarch/insn_trans/trans_farith.c.inc b/target/loongarch/insn_trans/trans_farith.c.inc index a7ced99fd3..f4a0dea727 100644 --- a/target/loongarch/insn_trans/trans_farith.c.inc +++ b/target/loongarch/insn_trans/trans_farith.c.inc @@ -23,7 +23,7 @@ static bool gen_fff(DisasContext *ctx, arg_fff *a, CHECK_FPE; - func(dest, cpu_env, src1, src2); + func(dest, tcg_env, src1, src2); set_fpr(a->fd, dest); return true; @@ -37,7 +37,7 @@ static bool gen_ff(DisasContext *ctx, arg_ff *a, CHECK_FPE; - func(dest, cpu_env, src); + func(dest, tcg_env, src); set_fpr(a->fd, dest); return true; @@ -55,7 +55,7 @@ static bool gen_muladd(DisasContext *ctx, arg_ffff *a, CHECK_FPE; - func(dest, cpu_env, src1, src2, src3, tflag); + func(dest, tcg_env, src1, src2, src3, tflag); set_fpr(a->fd, dest); return true; diff --git a/target/loongarch/insn_trans/trans_fcmp.c.inc b/target/loongarch/insn_trans/trans_fcmp.c.inc index 43d5866a67..3babf69e4a 100644 --- a/target/loongarch/insn_trans/trans_fcmp.c.inc +++ b/target/loongarch/insn_trans/trans_fcmp.c.inc @@ -41,9 +41,9 @@ static bool trans_fcmp_cond_s(DisasContext *ctx, arg_fcmp_cond_s *a) fn = (a->fcond & 1 ? gen_helper_fcmp_s_s : gen_helper_fcmp_c_s); flags = get_fcmp_flags(a->fcond >> 1); - fn(var, cpu_env, src1, src2, tcg_constant_i32(flags)); + fn(var, tcg_env, src1, src2, tcg_constant_i32(flags)); - tcg_gen_st8_tl(var, cpu_env, offsetof(CPULoongArchState, cf[a->cd])); + tcg_gen_st8_tl(var, tcg_env, offsetof(CPULoongArchState, cf[a->cd])); return true; } @@ -65,8 +65,8 @@ static bool trans_fcmp_cond_d(DisasContext *ctx, arg_fcmp_cond_d *a) fn = (a->fcond & 1 ? gen_helper_fcmp_s_d : gen_helper_fcmp_c_d); flags = get_fcmp_flags(a->fcond >> 1); - fn(var, cpu_env, src1, src2, tcg_constant_i32(flags)); + fn(var, tcg_env, src1, src2, tcg_constant_i32(flags)); - tcg_gen_st8_tl(var, cpu_env, offsetof(CPULoongArchState, cf[a->cd])); + tcg_gen_st8_tl(var, tcg_env, offsetof(CPULoongArchState, cf[a->cd])); return true; } diff --git a/target/loongarch/insn_trans/trans_fmemory.c.inc b/target/loongarch/insn_trans/trans_fmemory.c.inc index 5ddb8a473b..13452bc7e5 100644 --- a/target/loongarch/insn_trans/trans_fmemory.c.inc +++ b/target/loongarch/insn_trans/trans_fmemory.c.inc @@ -81,7 +81,7 @@ static bool gen_fload_gt(DisasContext *ctx, arg_frr *a, MemOp mop) CHECK_FPE; - gen_helper_asrtgt_d(cpu_env, src1, src2); + gen_helper_asrtgt_d(tcg_env, src1, src2); addr = make_address_x(ctx, src1, src2); tcg_gen_qemu_ld_tl(dest, addr, ctx->mem_idx, mop); maybe_nanbox_load(dest, mop); @@ -99,7 +99,7 @@ static bool gen_fstore_gt(DisasContext *ctx, arg_frr *a, MemOp mop) CHECK_FPE; - gen_helper_asrtgt_d(cpu_env, src1, src2); + gen_helper_asrtgt_d(tcg_env, src1, src2); addr = make_address_x(ctx, src1, src2); tcg_gen_qemu_st_tl(src3, addr, ctx->mem_idx, mop); @@ -115,7 +115,7 @@ static bool gen_fload_le(DisasContext *ctx, arg_frr *a, MemOp mop) CHECK_FPE; - gen_helper_asrtle_d(cpu_env, src1, src2); + gen_helper_asrtle_d(tcg_env, src1, src2); addr = make_address_x(ctx, src1, src2); tcg_gen_qemu_ld_tl(dest, addr, ctx->mem_idx, mop); maybe_nanbox_load(dest, mop); @@ -133,7 +133,7 @@ static bool gen_fstore_le(DisasContext *ctx, arg_frr *a, MemOp mop) CHECK_FPE; - gen_helper_asrtle_d(cpu_env, src1, src2); + gen_helper_asrtle_d(tcg_env, src1, src2); addr = make_address_x(ctx, src1, src2); tcg_gen_qemu_st_tl(src3, addr, ctx->mem_idx, mop); diff --git a/target/loongarch/insn_trans/trans_fmov.c.inc b/target/loongarch/insn_trans/trans_fmov.c.inc index 928e127820..5cbd9d3f34 100644 --- a/target/loongarch/insn_trans/trans_fmov.c.inc +++ b/target/loongarch/insn_trans/trans_fmov.c.inc @@ -22,7 +22,7 @@ static bool trans_fsel(DisasContext *ctx, arg_fsel *a) CHECK_FPE; cond = tcg_temp_new(); - tcg_gen_ld8u_tl(cond, cpu_env, offsetof(CPULoongArchState, cf[a->ca])); + tcg_gen_ld8u_tl(cond, tcg_env, offsetof(CPULoongArchState, cf[a->ca])); tcg_gen_movcond_tl(TCG_COND_EQ, dest, cond, zero, src1, src2); set_fpr(a->fd, dest); @@ -94,17 +94,17 @@ static bool trans_movgr2fcsr(DisasContext *ctx, arg_movgr2fcsr *a) CHECK_FPE; if (mask == UINT32_MAX) { - tcg_gen_st32_i64(Rj, cpu_env, offsetof(CPULoongArchState, fcsr0)); + tcg_gen_st32_i64(Rj, tcg_env, offsetof(CPULoongArchState, fcsr0)); } else { TCGv_i32 fcsr0 = tcg_temp_new_i32(); TCGv_i32 temp = tcg_temp_new_i32(); - tcg_gen_ld_i32(fcsr0, cpu_env, offsetof(CPULoongArchState, fcsr0)); + tcg_gen_ld_i32(fcsr0, tcg_env, offsetof(CPULoongArchState, fcsr0)); tcg_gen_extrl_i64_i32(temp, Rj); tcg_gen_andi_i32(temp, temp, mask); tcg_gen_andi_i32(fcsr0, fcsr0, ~mask); tcg_gen_or_i32(fcsr0, fcsr0, temp); - tcg_gen_st_i32(fcsr0, cpu_env, offsetof(CPULoongArchState, fcsr0)); + tcg_gen_st_i32(fcsr0, tcg_env, offsetof(CPULoongArchState, fcsr0)); } /* @@ -112,7 +112,7 @@ static bool trans_movgr2fcsr(DisasContext *ctx, arg_movgr2fcsr *a) * Note that FCSR3 is exactly the rounding mode field. */ if (mask & FCSR0_M3) { - gen_helper_set_rounding_mode(cpu_env); + gen_helper_set_rounding_mode(tcg_env); } return true; } @@ -127,7 +127,7 @@ static bool trans_movfcsr2gr(DisasContext *ctx, arg_movfcsr2gr *a) CHECK_FPE; - tcg_gen_ld32u_i64(dest, cpu_env, offsetof(CPULoongArchState, fcsr0)); + tcg_gen_ld32u_i64(dest, tcg_env, offsetof(CPULoongArchState, fcsr0)); tcg_gen_andi_i64(dest, dest, fcsr_mask[a->fcsrs]); gen_set_gpr(a->rd, dest, EXT_NONE); @@ -162,7 +162,7 @@ static bool trans_movfr2cf(DisasContext *ctx, arg_movfr2cf *a) t0 = tcg_temp_new(); tcg_gen_andi_tl(t0, src, 0x1); - tcg_gen_st8_tl(t0, cpu_env, offsetof(CPULoongArchState, cf[a->cd & 0x7])); + tcg_gen_st8_tl(t0, tcg_env, offsetof(CPULoongArchState, cf[a->cd & 0x7])); return true; } @@ -177,7 +177,7 @@ static bool trans_movcf2fr(DisasContext *ctx, arg_movcf2fr *a) CHECK_FPE; - tcg_gen_ld8u_tl(dest, cpu_env, + tcg_gen_ld8u_tl(dest, tcg_env, offsetof(CPULoongArchState, cf[a->cj & 0x7])); set_fpr(a->fd, dest); @@ -196,7 +196,7 @@ static bool trans_movgr2cf(DisasContext *ctx, arg_movgr2cf *a) t0 = tcg_temp_new(); tcg_gen_andi_tl(t0, gpr_src(ctx, a->rj, EXT_NONE), 0x1); - tcg_gen_st8_tl(t0, cpu_env, offsetof(CPULoongArchState, cf[a->cd & 0x7])); + tcg_gen_st8_tl(t0, tcg_env, offsetof(CPULoongArchState, cf[a->cd & 0x7])); return true; } @@ -209,7 +209,7 @@ static bool trans_movcf2gr(DisasContext *ctx, arg_movcf2gr *a) CHECK_FPE; - tcg_gen_ld8u_tl(gpr_dst(ctx, a->rd, EXT_NONE), cpu_env, + tcg_gen_ld8u_tl(gpr_dst(ctx, a->rd, EXT_NONE), tcg_env, offsetof(CPULoongArchState, cf[a->cj & 0x7])); return true; } diff --git a/target/loongarch/insn_trans/trans_memory.c.inc b/target/loongarch/insn_trans/trans_memory.c.inc index d9d062235a..c3de1404ea 100644 --- a/target/loongarch/insn_trans/trans_memory.c.inc +++ b/target/loongarch/insn_trans/trans_memory.c.inc @@ -57,7 +57,7 @@ static bool gen_load_gt(DisasContext *ctx, arg_rrr *a, MemOp mop) TCGv src1 = gpr_src(ctx, a->rj, EXT_NONE); TCGv src2 = gpr_src(ctx, a->rk, EXT_NONE); - gen_helper_asrtgt_d(cpu_env, src1, src2); + gen_helper_asrtgt_d(tcg_env, src1, src2); src1 = make_address_i(ctx, src1, 0); tcg_gen_qemu_ld_tl(dest, src1, ctx->mem_idx, mop); gen_set_gpr(a->rd, dest, EXT_NONE); @@ -71,7 +71,7 @@ static bool gen_load_le(DisasContext *ctx, arg_rrr *a, MemOp mop) TCGv src1 = gpr_src(ctx, a->rj, EXT_NONE); TCGv src2 = gpr_src(ctx, a->rk, EXT_NONE); - gen_helper_asrtle_d(cpu_env, src1, src2); + gen_helper_asrtle_d(tcg_env, src1, src2); src1 = make_address_i(ctx, src1, 0); tcg_gen_qemu_ld_tl(dest, src1, ctx->mem_idx, mop); gen_set_gpr(a->rd, dest, EXT_NONE); @@ -85,7 +85,7 @@ static bool gen_store_gt(DisasContext *ctx, arg_rrr *a, MemOp mop) TCGv src1 = gpr_src(ctx, a->rj, EXT_NONE); TCGv src2 = gpr_src(ctx, a->rk, EXT_NONE); - gen_helper_asrtgt_d(cpu_env, src1, src2); + gen_helper_asrtgt_d(tcg_env, src1, src2); src1 = make_address_i(ctx, src1, 0); tcg_gen_qemu_st_tl(data, src1, ctx->mem_idx, mop); @@ -98,7 +98,7 @@ static bool gen_store_le(DisasContext *ctx, arg_rrr *a, MemOp mop) TCGv src1 = gpr_src(ctx, a->rj, EXT_NONE); TCGv src2 = gpr_src(ctx, a->rk, EXT_NONE); - gen_helper_asrtle_d(cpu_env, src1, src2); + gen_helper_asrtle_d(tcg_env, src1, src2); src1 = make_address_i(ctx, src1, 0); tcg_gen_qemu_st_tl(data, src1, ctx->mem_idx, mop); diff --git a/target/loongarch/insn_trans/trans_privileged.c.inc b/target/loongarch/insn_trans/trans_privileged.c.inc index 4cb701b4b5..01d457212b 100644 --- a/target/loongarch/insn_trans/trans_privileged.c.inc +++ b/target/loongarch/insn_trans/trans_privileged.c.inc @@ -203,9 +203,9 @@ static bool trans_csrrd(DisasContext *ctx, arg_csrrd *a) check_csr_flags(ctx, csr, false); dest = gpr_dst(ctx, a->rd, EXT_NONE); if (csr->readfn) { - csr->readfn(dest, cpu_env); + csr->readfn(dest, tcg_env); } else { - tcg_gen_ld_tl(dest, cpu_env, csr->offset); + tcg_gen_ld_tl(dest, tcg_env, csr->offset); } } gen_set_gpr(a->rd, dest, EXT_NONE); @@ -233,11 +233,11 @@ static bool trans_csrwr(DisasContext *ctx, arg_csrwr *a) src1 = gpr_src(ctx, a->rd, EXT_NONE); if (csr->writefn) { dest = gpr_dst(ctx, a->rd, EXT_NONE); - csr->writefn(dest, cpu_env, src1); + csr->writefn(dest, tcg_env, src1); } else { dest = tcg_temp_new(); - tcg_gen_ld_tl(dest, cpu_env, csr->offset); - tcg_gen_st_tl(src1, cpu_env, csr->offset); + tcg_gen_ld_tl(dest, tcg_env, csr->offset); + tcg_gen_st_tl(src1, tcg_env, csr->offset); } gen_set_gpr(a->rd, dest, EXT_NONE); return true; @@ -272,15 +272,15 @@ static bool trans_csrxchg(DisasContext *ctx, arg_csrxchg *a) newv = tcg_temp_new(); temp = tcg_temp_new(); - tcg_gen_ld_tl(oldv, cpu_env, csr->offset); + tcg_gen_ld_tl(oldv, tcg_env, csr->offset); tcg_gen_and_tl(newv, src1, mask); tcg_gen_andc_tl(temp, oldv, mask); tcg_gen_or_tl(newv, newv, temp); if (csr->writefn) { - csr->writefn(oldv, cpu_env, newv); + csr->writefn(oldv, tcg_env, newv); } else { - tcg_gen_st_tl(newv, cpu_env, csr->offset); + tcg_gen_st_tl(newv, tcg_env, csr->offset); } gen_set_gpr(a->rd, oldv, EXT_NONE); return true; @@ -295,7 +295,7 @@ static bool gen_iocsrrd(DisasContext *ctx, arg_rr *a, if (check_plv(ctx)) { return false; } - func(dest, cpu_env, src1); + func(dest, tcg_env, src1); return true; } @@ -308,7 +308,7 @@ static bool gen_iocsrwr(DisasContext *ctx, arg_rr *a, if (check_plv(ctx)) { return false; } - func(cpu_env, addr, val); + func(tcg_env, addr, val); return true; } @@ -334,7 +334,7 @@ static bool trans_tlbsrch(DisasContext *ctx, arg_tlbsrch *a) if (check_plv(ctx)) { return false; } - gen_helper_tlbsrch(cpu_env); + gen_helper_tlbsrch(tcg_env); return true; } @@ -343,7 +343,7 @@ static bool trans_tlbrd(DisasContext *ctx, arg_tlbrd *a) if (check_plv(ctx)) { return false; } - gen_helper_tlbrd(cpu_env); + gen_helper_tlbrd(tcg_env); return true; } @@ -352,7 +352,7 @@ static bool trans_tlbwr(DisasContext *ctx, arg_tlbwr *a) if (check_plv(ctx)) { return false; } - gen_helper_tlbwr(cpu_env); + gen_helper_tlbwr(tcg_env); check_mmu_idx(ctx); return true; } @@ -362,7 +362,7 @@ static bool trans_tlbfill(DisasContext *ctx, arg_tlbfill *a) if (check_plv(ctx)) { return false; } - gen_helper_tlbfill(cpu_env); + gen_helper_tlbfill(tcg_env); check_mmu_idx(ctx); return true; } @@ -372,7 +372,7 @@ static bool trans_tlbclr(DisasContext *ctx, arg_tlbclr *a) if (check_plv(ctx)) { return false; } - gen_helper_tlbclr(cpu_env); + gen_helper_tlbclr(tcg_env); check_mmu_idx(ctx); return true; } @@ -382,7 +382,7 @@ static bool trans_tlbflush(DisasContext *ctx, arg_tlbflush *a) if (check_plv(ctx)) { return false; } - gen_helper_tlbflush(cpu_env); + gen_helper_tlbflush(tcg_env); check_mmu_idx(ctx); return true; } @@ -399,22 +399,22 @@ static bool trans_invtlb(DisasContext *ctx, arg_invtlb *a) switch (a->imm) { case 0: case 1: - gen_helper_invtlb_all(cpu_env); + gen_helper_invtlb_all(tcg_env); break; case 2: - gen_helper_invtlb_all_g(cpu_env, tcg_constant_i32(1)); + gen_helper_invtlb_all_g(tcg_env, tcg_constant_i32(1)); break; case 3: - gen_helper_invtlb_all_g(cpu_env, tcg_constant_i32(0)); + gen_helper_invtlb_all_g(tcg_env, tcg_constant_i32(0)); break; case 4: - gen_helper_invtlb_all_asid(cpu_env, rj); + gen_helper_invtlb_all_asid(tcg_env, rj); break; case 5: - gen_helper_invtlb_page_asid(cpu_env, rj, rk); + gen_helper_invtlb_page_asid(tcg_env, rj, rk); break; case 6: - gen_helper_invtlb_page_asid_or_g(cpu_env, rj, rk); + gen_helper_invtlb_page_asid_or_g(tcg_env, rj, rk); break; default: return false; @@ -444,7 +444,7 @@ static bool trans_ldpte(DisasContext *ctx, arg_ldpte *a) if (check_plv(ctx)) { return false; } - gen_helper_ldpte(cpu_env, src1, tcg_constant_tl(a->imm), mem_idx); + gen_helper_ldpte(tcg_env, src1, tcg_constant_tl(a->imm), mem_idx); return true; } @@ -461,7 +461,7 @@ static bool trans_lddir(DisasContext *ctx, arg_lddir *a) if (check_plv(ctx)) { return false; } - gen_helper_lddir(dest, cpu_env, src, tcg_constant_tl(a->imm), mem_idx); + gen_helper_lddir(dest, tcg_env, src, tcg_constant_tl(a->imm), mem_idx); return true; } @@ -470,7 +470,7 @@ static bool trans_ertn(DisasContext *ctx, arg_ertn *a) if (check_plv(ctx)) { return false; } - gen_helper_ertn(cpu_env); + gen_helper_ertn(tcg_env); ctx->base.is_jmp = DISAS_EXIT; return true; } @@ -491,7 +491,7 @@ static bool trans_idle(DisasContext *ctx, arg_idle *a) } tcg_gen_movi_tl(cpu_pc, ctx->base.pc_next + 4); - gen_helper_idle(cpu_env); + gen_helper_idle(tcg_env); ctx->base.is_jmp = DISAS_NORETURN; return true; } diff --git a/target/loongarch/insn_trans/trans_vec.c.inc b/target/loongarch/insn_trans/trans_vec.c.inc index c647137372..98f856bb29 100644 --- a/target/loongarch/insn_trans/trans_vec.c.inc +++ b/target/loongarch/insn_trans/trans_vec.c.inc @@ -41,7 +41,7 @@ static bool gen_vvvv_ptr_vl(DisasContext *ctx, arg_vvvv *a, uint32_t oprsz, vec_full_offset(a->vj), vec_full_offset(a->vk), vec_full_offset(a->va), - cpu_env, + tcg_env, oprsz, ctx->vl / 8, 0, fn); return true; } @@ -94,7 +94,7 @@ static bool gen_vvv_ptr_vl(DisasContext *ctx, arg_vvv *a, uint32_t oprsz, tcg_gen_gvec_3_ptr(vec_full_offset(a->vd), vec_full_offset(a->vj), vec_full_offset(a->vk), - cpu_env, + tcg_env, oprsz, ctx->vl / 8, 0, fn); return true; } @@ -144,7 +144,7 @@ static bool gen_vv_ptr_vl(DisasContext *ctx, arg_vv *a, uint32_t oprsz, tcg_gen_gvec_2_ptr(vec_full_offset(a->vd), vec_full_offset(a->vj), - cpu_env, + tcg_env, oprsz, ctx->vl / 8, 0, fn); return true; } @@ -219,7 +219,7 @@ static bool gen_cv_vl(DisasContext *ctx, arg_cv *a, uint32_t sz, TCGv_i32 cd = tcg_constant_i32(a->cd); TCGv_i32 oprsz = tcg_constant_i32(sz); - func(cpu_env, oprsz, cd, vj); + func(tcg_env, oprsz, cd, vj); return true; } @@ -4679,7 +4679,7 @@ static bool do_vfcmp_cond_s(DisasContext *ctx, arg_vvv_fcond *a, uint32_t sz) fn = (a->fcond & 1 ? gen_helper_vfcmp_s_s : gen_helper_vfcmp_c_s); flags = get_fcmp_flags(a->fcond >> 1); - fn(cpu_env, oprsz, vd, vj, vk, tcg_constant_i32(flags)); + fn(tcg_env, oprsz, vd, vj, vk, tcg_constant_i32(flags)); return true; } @@ -4699,7 +4699,7 @@ static bool do_vfcmp_cond_d(DisasContext *ctx, arg_vvv_fcond *a, uint32_t sz) fn = (a->fcond & 1 ? gen_helper_vfcmp_s_d : gen_helper_vfcmp_c_d); flags = get_fcmp_flags(a->fcond >> 1); - fn(cpu_env, oprsz, vd, vj, vk, tcg_constant_i32(flags)); + fn(tcg_env, oprsz, vd, vj, vk, tcg_constant_i32(flags)); return true; } @@ -4772,7 +4772,7 @@ static bool trans_## NAME (DisasContext *ctx, arg_cv *a) \ \ tcg_gen_or_i64(t1, al, ah); \ tcg_gen_setcondi_i64(COND, t1, t1, 0); \ - tcg_gen_st8_tl(t1, cpu_env, offsetof(CPULoongArchState, cf[a->cd & 0x7])); \ + tcg_gen_st8_tl(t1, tcg_env, offsetof(CPULoongArchState, cf[a->cd & 0x7])); \ \ return true; \ } @@ -4818,7 +4818,7 @@ static bool trans_## NAME(DisasContext *ctx, arg_cv * a) \ tcg_gen_or_i64(t2, d[2], d[3]); \ tcg_gen_or_i64(t1, t2, t1); \ tcg_gen_setcondi_i64(COND, t1, t1, 0); \ - tcg_gen_st8_tl(t1, cpu_env, offsetof(CPULoongArchState, cf[a->cd & 0x7])); \ + tcg_gen_st8_tl(t1, tcg_env, offsetof(CPULoongArchState, cf[a->cd & 0x7])); \ \ return true; \ } @@ -4844,7 +4844,7 @@ static bool gen_g2v_vl(DisasContext *ctx, arg_vr_i *a, uint32_t oprsz, MemOp mop return true; } - func(src, cpu_env, vec_reg_offset(a->vd, a->imm, mop)); + func(src, tcg_env, vec_reg_offset(a->vd, a->imm, mop)); return true; } @@ -4877,7 +4877,7 @@ static bool gen_v2g_vl(DisasContext *ctx, arg_rv_i *a, uint32_t oprsz, MemOp mop return true; } - func(dst, cpu_env, vec_reg_offset(a->vj, a->imm, mop)); + func(dst, tcg_env, vec_reg_offset(a->vj, a->imm, mop)); return true; } @@ -5026,7 +5026,7 @@ static bool gen_vreplve_vl(DisasContext *ctx, arg_vvr *a, } tcg_gen_trunc_i64_ptr(t1, t0); - tcg_gen_add_ptr(t1, t1, cpu_env); + tcg_gen_add_ptr(t1, t1, tcg_env); for (i = 0; i < oprsz; i += 16) { func(t2, t1, vec_full_offset(a->vj) + i); @@ -5422,7 +5422,7 @@ static bool do_vstelm_vl(DisasContext *ctx, val = tcg_temp_new_i64(); addr = make_address_i(ctx, addr, a->imm); - tcg_gen_ld_i64(val, cpu_env, vec_reg_offset(a->vd, a->imm2, mop)); + tcg_gen_ld_i64(val, tcg_env, vec_reg_offset(a->vd, a->imm2, mop)); tcg_gen_qemu_st_i64(val, addr, ctx->mem_idx, mop); return true; } diff --git a/target/loongarch/translate.c b/target/loongarch/translate.c index f6038fc567..47598a9373 100644 --- a/target/loongarch/translate.c +++ b/target/loongarch/translate.c @@ -51,13 +51,13 @@ static inline int vec_reg_offset(int regno, int index, MemOp mop) static inline void get_vreg64(TCGv_i64 dest, int regno, int index) { - tcg_gen_ld_i64(dest, cpu_env, + tcg_gen_ld_i64(dest, tcg_env, offsetof(CPULoongArchState, fpr[regno].vreg.D(index))); } static inline void set_vreg64(TCGv_i64 src, int regno, int index) { - tcg_gen_st_i64(src, cpu_env, + tcg_gen_st_i64(src, tcg_env, offsetof(CPULoongArchState, fpr[regno].vreg.D(index))); } @@ -93,7 +93,7 @@ static void gen_nanbox_s(TCGv_i64 out, TCGv_i64 in) void generate_exception(DisasContext *ctx, int excp) { tcg_gen_movi_tl(cpu_pc, ctx->base.pc_next); - gen_helper_raise_exception(cpu_env, tcg_constant_i32(excp)); + gen_helper_raise_exception(tcg_env, tcg_constant_i32(excp)); ctx->base.is_jmp = DISAS_NORETURN; } @@ -221,14 +221,14 @@ static void gen_set_gpr(int reg_num, TCGv t, DisasExtend dst_ext) static TCGv get_fpr(DisasContext *ctx, int reg_num) { TCGv t = tcg_temp_new(); - tcg_gen_ld_i64(t, cpu_env, + tcg_gen_ld_i64(t, tcg_env, offsetof(CPULoongArchState, fpr[reg_num].vreg.D(0))); return t; } static void set_fpr(int reg_num, TCGv val) { - tcg_gen_st_i64(val, cpu_env, + tcg_gen_st_i64(val, tcg_env, offsetof(CPULoongArchState, fpr[reg_num].vreg.D(0))); } @@ -357,14 +357,14 @@ void loongarch_translate_init(void) cpu_gpr[0] = NULL; for (i = 1; i < 32; i++) { - cpu_gpr[i] = tcg_global_mem_new(cpu_env, + cpu_gpr[i] = tcg_global_mem_new(tcg_env, offsetof(CPULoongArchState, gpr[i]), regnames[i]); } - cpu_pc = tcg_global_mem_new(cpu_env, offsetof(CPULoongArchState, pc), "pc"); - cpu_lladdr = tcg_global_mem_new(cpu_env, + cpu_pc = tcg_global_mem_new(tcg_env, offsetof(CPULoongArchState, pc), "pc"); + cpu_lladdr = tcg_global_mem_new(tcg_env, offsetof(CPULoongArchState, lladdr), "lladdr"); - cpu_llval = tcg_global_mem_new(cpu_env, + cpu_llval = tcg_global_mem_new(tcg_env, offsetof(CPULoongArchState, llval), "llval"); } diff --git a/target/m68k/translate.c b/target/m68k/translate.c index 15c9ddf427..587fe36356 100644 --- a/target/m68k/translate.c +++ b/target/m68k/translate.c @@ -70,19 +70,19 @@ void m68k_tcg_init(void) int i; #define DEFO32(name, offset) \ - QREG_##name = tcg_global_mem_new_i32(cpu_env, \ + QREG_##name = tcg_global_mem_new_i32(tcg_env, \ offsetof(CPUM68KState, offset), #name); #define DEFO64(name, offset) \ - QREG_##name = tcg_global_mem_new_i64(cpu_env, \ + QREG_##name = tcg_global_mem_new_i64(tcg_env, \ offsetof(CPUM68KState, offset), #name); #include "qregs.h.inc" #undef DEFO32 #undef DEFO64 - cpu_halted = tcg_global_mem_new_i32(cpu_env, + cpu_halted = tcg_global_mem_new_i32(tcg_env, -offsetof(M68kCPU, env) + offsetof(CPUState, halted), "HALTED"); - cpu_exception_index = tcg_global_mem_new_i32(cpu_env, + cpu_exception_index = tcg_global_mem_new_i32(tcg_env, -offsetof(M68kCPU, env) + offsetof(CPUState, exception_index), "EXCEPTION"); @@ -90,23 +90,23 @@ void m68k_tcg_init(void) p = cpu_reg_names; for (i = 0; i < 8; i++) { sprintf(p, "D%d", i); - cpu_dregs[i] = tcg_global_mem_new(cpu_env, + cpu_dregs[i] = tcg_global_mem_new(tcg_env, offsetof(CPUM68KState, dregs[i]), p); p += 3; sprintf(p, "A%d", i); - cpu_aregs[i] = tcg_global_mem_new(cpu_env, + cpu_aregs[i] = tcg_global_mem_new(tcg_env, offsetof(CPUM68KState, aregs[i]), p); p += 3; } for (i = 0; i < 4; i++) { sprintf(p, "ACC%d", i); - cpu_macc[i] = tcg_global_mem_new_i64(cpu_env, + cpu_macc[i] = tcg_global_mem_new_i64(tcg_env, offsetof(CPUM68KState, macc[i]), p); p += 5; } - NULL_QREG = tcg_global_mem_new(cpu_env, -4, "NULL"); - store_dummy = tcg_global_mem_new(cpu_env, -8, "NULL"); + NULL_QREG = tcg_global_mem_new(tcg_env, -4, "NULL"); + store_dummy = tcg_global_mem_new(tcg_env, -8, "NULL"); } /* internal defines */ @@ -264,7 +264,7 @@ static void gen_jmp(DisasContext *s, TCGv dest) static void gen_raise_exception(int nr) { - gen_helper_raise_exception(cpu_env, tcg_constant_i32(nr)); + gen_helper_raise_exception(tcg_env, tcg_constant_i32(nr)); } static void gen_raise_exception_format2(DisasContext *s, int nr, @@ -276,7 +276,7 @@ static void gen_raise_exception_format2(DisasContext *s, int nr, * Re-use mmu.ar for the purpose, since that's only valid * after tlb_fill. */ - tcg_gen_st_i32(tcg_constant_i32(this_pc), cpu_env, + tcg_gen_st_i32(tcg_constant_i32(this_pc), tcg_env, offsetof(CPUM68KState, mmu.ar)); gen_raise_exception(nr); s->base.is_jmp = DISAS_NORETURN; @@ -602,12 +602,12 @@ static void gen_flush_flags(DisasContext *s) break; case CC_OP_DYNAMIC: - gen_helper_flush_flags(cpu_env, QREG_CC_OP); + gen_helper_flush_flags(tcg_env, QREG_CC_OP); s->cc_op_synced = 1; break; default: - gen_helper_flush_flags(cpu_env, tcg_constant_i32(s->cc_op)); + gen_helper_flush_flags(tcg_env, tcg_constant_i32(s->cc_op)); s->cc_op_synced = 1; break; } @@ -916,14 +916,14 @@ static TCGv gen_ea(CPUM68KState *env, DisasContext *s, uint16_t insn, static TCGv_ptr gen_fp_ptr(int freg) { TCGv_ptr fp = tcg_temp_new_ptr(); - tcg_gen_addi_ptr(fp, cpu_env, offsetof(CPUM68KState, fregs[freg])); + tcg_gen_addi_ptr(fp, tcg_env, offsetof(CPUM68KState, fregs[freg])); return fp; } static TCGv_ptr gen_fp_result_ptr(void) { TCGv_ptr fp = tcg_temp_new_ptr(); - tcg_gen_addi_ptr(fp, cpu_env, offsetof(CPUM68KState, fp_result)); + tcg_gen_addi_ptr(fp, tcg_env, offsetof(CPUM68KState, fp_result)); return fp; } @@ -954,15 +954,15 @@ static void gen_load_fp(DisasContext *s, int opsize, TCGv addr, TCGv_ptr fp, case OS_WORD: case OS_LONG: tcg_gen_qemu_ld_tl(tmp, addr, index, opsize | MO_SIGN | MO_TE); - gen_helper_exts32(cpu_env, fp, tmp); + gen_helper_exts32(tcg_env, fp, tmp); break; case OS_SINGLE: tcg_gen_qemu_ld_tl(tmp, addr, index, MO_TEUL); - gen_helper_extf32(cpu_env, fp, tmp); + gen_helper_extf32(tcg_env, fp, tmp); break; case OS_DOUBLE: tcg_gen_qemu_ld_i64(t64, addr, index, MO_TEUQ); - gen_helper_extf64(cpu_env, fp, t64); + gen_helper_extf64(tcg_env, fp, t64); break; case OS_EXTENDED: if (m68k_feature(s->env, M68K_FEATURE_CF_FPU)) { @@ -1000,15 +1000,15 @@ static void gen_store_fp(DisasContext *s, int opsize, TCGv addr, TCGv_ptr fp, case OS_BYTE: case OS_WORD: case OS_LONG: - gen_helper_reds32(tmp, cpu_env, fp); + gen_helper_reds32(tmp, tcg_env, fp); tcg_gen_qemu_st_tl(tmp, addr, index, opsize | MO_TE); break; case OS_SINGLE: - gen_helper_redf32(tmp, cpu_env, fp); + gen_helper_redf32(tmp, tcg_env, fp); tcg_gen_qemu_st_tl(tmp, addr, index, MO_TEUL); break; case OS_DOUBLE: - gen_helper_redf64(t64, cpu_env, fp); + gen_helper_redf64(t64, tcg_env, fp); tcg_gen_qemu_st_i64(t64, addr, index, MO_TEUQ); break; case OS_EXTENDED: @@ -1060,10 +1060,10 @@ static int gen_ea_mode_fp(CPUM68KState *env, DisasContext *s, int mode, case OS_BYTE: case OS_WORD: case OS_LONG: - gen_helper_reds32(reg, cpu_env, fp); + gen_helper_reds32(reg, tcg_env, fp); break; case OS_SINGLE: - gen_helper_redf32(reg, cpu_env, fp); + gen_helper_redf32(reg, tcg_env, fp); break; default: g_assert_not_reached(); @@ -1073,17 +1073,17 @@ static int gen_ea_mode_fp(CPUM68KState *env, DisasContext *s, int mode, switch (opsize) { case OS_BYTE: tcg_gen_ext8s_i32(tmp, reg); - gen_helper_exts32(cpu_env, fp, tmp); + gen_helper_exts32(tcg_env, fp, tmp); break; case OS_WORD: tcg_gen_ext16s_i32(tmp, reg); - gen_helper_exts32(cpu_env, fp, tmp); + gen_helper_exts32(tcg_env, fp, tmp); break; case OS_LONG: - gen_helper_exts32(cpu_env, fp, reg); + gen_helper_exts32(tcg_env, fp, reg); break; case OS_SINGLE: - gen_helper_extf32(cpu_env, fp, reg); + gen_helper_extf32(tcg_env, fp, reg); break; default: g_assert_not_reached(); @@ -1132,23 +1132,23 @@ static int gen_ea_mode_fp(CPUM68KState *env, DisasContext *s, int mode, switch (opsize) { case OS_BYTE: tmp = tcg_constant_i32((int8_t)read_im8(env, s)); - gen_helper_exts32(cpu_env, fp, tmp); + gen_helper_exts32(tcg_env, fp, tmp); break; case OS_WORD: tmp = tcg_constant_i32((int16_t)read_im16(env, s)); - gen_helper_exts32(cpu_env, fp, tmp); + gen_helper_exts32(tcg_env, fp, tmp); break; case OS_LONG: tmp = tcg_constant_i32(read_im32(env, s)); - gen_helper_exts32(cpu_env, fp, tmp); + gen_helper_exts32(tcg_env, fp, tmp); break; case OS_SINGLE: tmp = tcg_constant_i32(read_im32(env, s)); - gen_helper_extf32(cpu_env, fp, tmp); + gen_helper_extf32(tcg_env, fp, tmp); break; case OS_DOUBLE: t64 = tcg_constant_i64(read_im64(env, s)); - gen_helper_extf64(cpu_env, fp, t64); + gen_helper_extf64(tcg_env, fp, t64); break; case OS_EXTENDED: if (m68k_feature(s->env, M68K_FEATURE_CF_FPU)) { @@ -1516,9 +1516,9 @@ DISAS_INSN(divw) destr = tcg_constant_i32(REG(insn, 9)); ilen = tcg_constant_i32(s->pc - s->base.pc_next); if (sign) { - gen_helper_divsw(cpu_env, destr, src, ilen); + gen_helper_divsw(tcg_env, destr, src, ilen); } else { - gen_helper_divuw(cpu_env, destr, src, ilen); + gen_helper_divuw(tcg_env, destr, src, ilen); } set_cc_op(s, CC_OP_FLAGS); @@ -1547,9 +1547,9 @@ DISAS_INSN(divl) reg = tcg_constant_i32(REG(ext, 0)); ilen = tcg_constant_i32(s->pc - s->base.pc_next); if (sign) { - gen_helper_divsll(cpu_env, num, reg, den, ilen); + gen_helper_divsll(tcg_env, num, reg, den, ilen); } else { - gen_helper_divull(cpu_env, num, reg, den, ilen); + gen_helper_divull(tcg_env, num, reg, den, ilen); } set_cc_op(s, CC_OP_FLAGS); return; @@ -1563,9 +1563,9 @@ DISAS_INSN(divl) reg = tcg_constant_i32(REG(ext, 0)); ilen = tcg_constant_i32(s->pc - s->base.pc_next); if (sign) { - gen_helper_divsl(cpu_env, num, reg, den, ilen); + gen_helper_divsl(tcg_env, num, reg, den, ilen); } else { - gen_helper_divul(cpu_env, num, reg, den, ilen); + gen_helper_divul(tcg_env, num, reg, den, ilen); } set_cc_op(s, CC_OP_FLAGS); @@ -2126,7 +2126,7 @@ static TCGv gen_get_ccr(DisasContext *s) update_cc_op(s); dest = tcg_temp_new(); - gen_helper_get_ccr(dest, cpu_env); + gen_helper_get_ccr(dest, tcg_env); return dest; } @@ -2153,7 +2153,7 @@ static void gen_set_sr_im(DisasContext *s, uint16_t val, int ccr_only) } else { /* Must writeback before changing security state. */ do_writebacks(s); - gen_helper_set_sr(cpu_env, tcg_constant_i32(val)); + gen_helper_set_sr(tcg_env, tcg_constant_i32(val)); } set_cc_op(s, CC_OP_FLAGS); } @@ -2161,11 +2161,11 @@ static void gen_set_sr_im(DisasContext *s, uint16_t val, int ccr_only) static void gen_set_sr(DisasContext *s, TCGv val, int ccr_only) { if (ccr_only) { - gen_helper_set_ccr(cpu_env, val); + gen_helper_set_ccr(tcg_env, val); } else { /* Must writeback before changing security state. */ do_writebacks(s); - gen_helper_set_sr(cpu_env, val); + gen_helper_set_sr(tcg_env, val); } set_cc_op(s, CC_OP_FLAGS); } @@ -2388,13 +2388,13 @@ DISAS_INSN(cas2w) */ if (tb_cflags(s->base.tb) & CF_PARALLEL) { - gen_helper_exit_atomic(cpu_env); + gen_helper_exit_atomic(tcg_env); } else { TCGv regs = tcg_constant_i32(REG(ext2, 6) | (REG(ext1, 6) << 3) | (REG(ext2, 0) << 6) | (REG(ext1, 0) << 9)); - gen_helper_cas2w(cpu_env, regs, addr1, addr2); + gen_helper_cas2w(tcg_env, regs, addr1, addr2); } /* Note that cas2w also assigned to env->cc_op. */ @@ -2442,9 +2442,9 @@ DISAS_INSN(cas2l) (REG(ext2, 0) << 6) | (REG(ext1, 0) << 9)); if (tb_cflags(s->base.tb) & CF_PARALLEL) { - gen_helper_cas2l_parallel(cpu_env, regs, addr1, addr2); + gen_helper_cas2l_parallel(tcg_env, regs, addr1, addr2); } else { - gen_helper_cas2l(cpu_env, regs, addr1, addr2); + gen_helper_cas2l(tcg_env, regs, addr1, addr2); } /* Note that cas2l also assigned to env->cc_op. */ @@ -2837,7 +2837,7 @@ DISAS_INSN(reset) return; } - gen_helper_reset(cpu_env); + gen_helper_reset(tcg_env); } #endif @@ -3971,11 +3971,11 @@ DISAS_INSN(bfext_mem) } if (is_sign) { - gen_helper_bfexts_mem(dest, cpu_env, addr, ofs, len); + gen_helper_bfexts_mem(dest, tcg_env, addr, ofs, len); tcg_gen_mov_i32(QREG_CC_N, dest); } else { TCGv_i64 tmp = tcg_temp_new_i64(); - gen_helper_bfextu_mem(tmp, cpu_env, addr, ofs, len); + gen_helper_bfextu_mem(tmp, tcg_env, addr, ofs, len); tcg_gen_extr_i64_i32(dest, QREG_CC_N, tmp); } set_cc_op(s, CC_OP_LOGIC); @@ -4093,21 +4093,21 @@ DISAS_INSN(bfop_mem) switch (insn & 0x0f00) { case 0x0a00: /* bfchg */ - gen_helper_bfchg_mem(QREG_CC_N, cpu_env, addr, ofs, len); + gen_helper_bfchg_mem(QREG_CC_N, tcg_env, addr, ofs, len); break; case 0x0c00: /* bfclr */ - gen_helper_bfclr_mem(QREG_CC_N, cpu_env, addr, ofs, len); + gen_helper_bfclr_mem(QREG_CC_N, tcg_env, addr, ofs, len); break; case 0x0d00: /* bfffo */ t64 = tcg_temp_new_i64(); - gen_helper_bfffo_mem(t64, cpu_env, addr, ofs, len); + gen_helper_bfffo_mem(t64, tcg_env, addr, ofs, len); tcg_gen_extr_i64_i32(DREG(ext, 12), QREG_CC_N, t64); break; case 0x0e00: /* bfset */ - gen_helper_bfset_mem(QREG_CC_N, cpu_env, addr, ofs, len); + gen_helper_bfset_mem(QREG_CC_N, tcg_env, addr, ofs, len); break; case 0x0800: /* bftst */ - gen_helper_bfexts_mem(QREG_CC_N, cpu_env, addr, ofs, len); + gen_helper_bfexts_mem(QREG_CC_N, tcg_env, addr, ofs, len); break; default: g_assert_not_reached(); @@ -4208,7 +4208,7 @@ DISAS_INSN(bfins_mem) ofs = tcg_constant_i32(extract32(ext, 6, 5)); } - gen_helper_bfins_mem(QREG_CC_N, cpu_env, addr, src, ofs, len); + gen_helper_bfins_mem(QREG_CC_N, tcg_env, addr, src, ofs, len); set_cc_op(s, CC_OP_LOGIC); } @@ -4243,7 +4243,7 @@ DISAS_INSN(chk) reg = gen_extend(s, DREG(insn, 9), opsize, 1); gen_flush_flags(s); - gen_helper_chk(cpu_env, reg, src); + gen_helper_chk(tcg_env, reg, src); } DISAS_INSN(chk2) @@ -4288,7 +4288,7 @@ DISAS_INSN(chk2) } gen_flush_flags(s); - gen_helper_chk2(cpu_env, reg, bound1, bound2); + gen_helper_chk2(tcg_env, reg, bound1, bound2); } static void m68k_copy_line(TCGv dst, TCGv src, int index) @@ -4462,7 +4462,7 @@ DISAS_INSN(move_from_usp) gen_exception(s, s->base.pc_next, EXCP_PRIVILEGE); return; } - tcg_gen_ld_i32(AREG(insn, 0), cpu_env, + tcg_gen_ld_i32(AREG(insn, 0), tcg_env, offsetof(CPUM68KState, sp[M68K_USP])); } @@ -4472,7 +4472,7 @@ DISAS_INSN(move_to_usp) gen_exception(s, s->base.pc_next, EXCP_PRIVILEGE); return; } - tcg_gen_st_i32(AREG(insn, 0), cpu_env, + tcg_gen_st_i32(AREG(insn, 0), tcg_env, offsetof(CPUM68KState, sp[M68K_USP])); } @@ -4528,7 +4528,7 @@ DISAS_INSN(cf_movec) } else { reg = DREG(ext, 12); } - gen_helper_cf_movec_to(cpu_env, tcg_constant_i32(ext & 0xfff), reg); + gen_helper_cf_movec_to(tcg_env, tcg_constant_i32(ext & 0xfff), reg); gen_exit_tb(s); } @@ -4551,9 +4551,9 @@ DISAS_INSN(m68k_movec) } creg = tcg_constant_i32(ext & 0xfff); if (insn & 1) { - gen_helper_m68k_movec_to(cpu_env, creg, reg); + gen_helper_m68k_movec_to(tcg_env, creg, reg); } else { - gen_helper_m68k_movec_from(reg, cpu_env, creg); + gen_helper_m68k_movec_from(reg, tcg_env, creg); } gen_exit_tb(s); } @@ -4605,7 +4605,7 @@ DISAS_INSN(pflush) } opmode = tcg_constant_i32((insn >> 3) & 3); - gen_helper_pflush(cpu_env, AREG(insn, 0), opmode); + gen_helper_pflush(tcg_env, AREG(insn, 0), opmode); } DISAS_INSN(ptest) @@ -4617,7 +4617,7 @@ DISAS_INSN(ptest) return; } is_read = tcg_constant_i32((insn >> 5) & 1); - gen_helper_ptest(cpu_env, AREG(insn, 0), is_read); + gen_helper_ptest(tcg_env, AREG(insn, 0), is_read); } #endif @@ -4703,10 +4703,10 @@ static void gen_load_fcr(DisasContext *s, TCGv res, int reg) tcg_gen_movi_i32(res, 0); break; case M68K_FPSR: - tcg_gen_ld_i32(res, cpu_env, offsetof(CPUM68KState, fpsr)); + tcg_gen_ld_i32(res, tcg_env, offsetof(CPUM68KState, fpsr)); break; case M68K_FPCR: - tcg_gen_ld_i32(res, cpu_env, offsetof(CPUM68KState, fpcr)); + tcg_gen_ld_i32(res, tcg_env, offsetof(CPUM68KState, fpcr)); break; } } @@ -4717,10 +4717,10 @@ static void gen_store_fcr(DisasContext *s, TCGv val, int reg) case M68K_FPIAR: break; case M68K_FPSR: - tcg_gen_st_i32(val, cpu_env, offsetof(CPUM68KState, fpsr)); + tcg_gen_st_i32(val, tcg_env, offsetof(CPUM68KState, fpsr)); break; case M68K_FPCR: - gen_helper_set_fpcr(cpu_env, val); + gen_helper_set_fpcr(tcg_env, val); break; } } @@ -4877,23 +4877,23 @@ static void gen_op_fmovem(CPUM68KState *env, DisasContext *s, * only available to store register to memory */ if (opsize == OS_EXTENDED) { - gen_helper_fmovemx_st_predec(tmp, cpu_env, addr, tmp); + gen_helper_fmovemx_st_predec(tmp, tcg_env, addr, tmp); } else { - gen_helper_fmovemd_st_predec(tmp, cpu_env, addr, tmp); + gen_helper_fmovemd_st_predec(tmp, tcg_env, addr, tmp); } } else { /* postincrement addressing mode */ if (opsize == OS_EXTENDED) { if (is_load) { - gen_helper_fmovemx_ld_postinc(tmp, cpu_env, addr, tmp); + gen_helper_fmovemx_ld_postinc(tmp, tcg_env, addr, tmp); } else { - gen_helper_fmovemx_st_postinc(tmp, cpu_env, addr, tmp); + gen_helper_fmovemx_st_postinc(tmp, tcg_env, addr, tmp); } } else { if (is_load) { - gen_helper_fmovemd_ld_postinc(tmp, cpu_env, addr, tmp); + gen_helper_fmovemd_ld_postinc(tmp, tcg_env, addr, tmp); } else { - gen_helper_fmovemd_st_postinc(tmp, cpu_env, addr, tmp); + gen_helper_fmovemd_st_postinc(tmp, tcg_env, addr, tmp); } } } @@ -4925,7 +4925,7 @@ DISAS_INSN(fpu) /* fmovecr */ TCGv rom_offset = tcg_constant_i32(opmode); cpu_dest = gen_fp_ptr(REG(ext, 7)); - gen_helper_fconst(cpu_env, cpu_dest, rom_offset); + gen_helper_fconst(tcg_env, cpu_dest, rom_offset); return; } break; @@ -4936,7 +4936,7 @@ DISAS_INSN(fpu) EA_STORE, IS_USER(s)) == -1) { gen_addr_fault(s); } - gen_helper_ftst(cpu_env, cpu_src); + gen_helper_ftst(tcg_env, cpu_src); return; case 4: /* fmove to control register. */ case 5: /* fmove from control register. */ @@ -4970,172 +4970,172 @@ DISAS_INSN(fpu) gen_fp_move(cpu_dest, cpu_src); break; case 0x40: /* fsmove */ - gen_helper_fsround(cpu_env, cpu_dest, cpu_src); + gen_helper_fsround(tcg_env, cpu_dest, cpu_src); break; case 0x44: /* fdmove */ - gen_helper_fdround(cpu_env, cpu_dest, cpu_src); + gen_helper_fdround(tcg_env, cpu_dest, cpu_src); break; case 1: /* fint */ - gen_helper_firound(cpu_env, cpu_dest, cpu_src); + gen_helper_firound(tcg_env, cpu_dest, cpu_src); break; case 2: /* fsinh */ - gen_helper_fsinh(cpu_env, cpu_dest, cpu_src); + gen_helper_fsinh(tcg_env, cpu_dest, cpu_src); break; case 3: /* fintrz */ - gen_helper_fitrunc(cpu_env, cpu_dest, cpu_src); + gen_helper_fitrunc(tcg_env, cpu_dest, cpu_src); break; case 4: /* fsqrt */ - gen_helper_fsqrt(cpu_env, cpu_dest, cpu_src); + gen_helper_fsqrt(tcg_env, cpu_dest, cpu_src); break; case 0x41: /* fssqrt */ - gen_helper_fssqrt(cpu_env, cpu_dest, cpu_src); + gen_helper_fssqrt(tcg_env, cpu_dest, cpu_src); break; case 0x45: /* fdsqrt */ - gen_helper_fdsqrt(cpu_env, cpu_dest, cpu_src); + gen_helper_fdsqrt(tcg_env, cpu_dest, cpu_src); break; case 0x06: /* flognp1 */ - gen_helper_flognp1(cpu_env, cpu_dest, cpu_src); + gen_helper_flognp1(tcg_env, cpu_dest, cpu_src); break; case 0x08: /* fetoxm1 */ - gen_helper_fetoxm1(cpu_env, cpu_dest, cpu_src); + gen_helper_fetoxm1(tcg_env, cpu_dest, cpu_src); break; case 0x09: /* ftanh */ - gen_helper_ftanh(cpu_env, cpu_dest, cpu_src); + gen_helper_ftanh(tcg_env, cpu_dest, cpu_src); break; case 0x0a: /* fatan */ - gen_helper_fatan(cpu_env, cpu_dest, cpu_src); + gen_helper_fatan(tcg_env, cpu_dest, cpu_src); break; case 0x0c: /* fasin */ - gen_helper_fasin(cpu_env, cpu_dest, cpu_src); + gen_helper_fasin(tcg_env, cpu_dest, cpu_src); break; case 0x0d: /* fatanh */ - gen_helper_fatanh(cpu_env, cpu_dest, cpu_src); + gen_helper_fatanh(tcg_env, cpu_dest, cpu_src); break; case 0x0e: /* fsin */ - gen_helper_fsin(cpu_env, cpu_dest, cpu_src); + gen_helper_fsin(tcg_env, cpu_dest, cpu_src); break; case 0x0f: /* ftan */ - gen_helper_ftan(cpu_env, cpu_dest, cpu_src); + gen_helper_ftan(tcg_env, cpu_dest, cpu_src); break; case 0x10: /* fetox */ - gen_helper_fetox(cpu_env, cpu_dest, cpu_src); + gen_helper_fetox(tcg_env, cpu_dest, cpu_src); break; case 0x11: /* ftwotox */ - gen_helper_ftwotox(cpu_env, cpu_dest, cpu_src); + gen_helper_ftwotox(tcg_env, cpu_dest, cpu_src); break; case 0x12: /* ftentox */ - gen_helper_ftentox(cpu_env, cpu_dest, cpu_src); + gen_helper_ftentox(tcg_env, cpu_dest, cpu_src); break; case 0x14: /* flogn */ - gen_helper_flogn(cpu_env, cpu_dest, cpu_src); + gen_helper_flogn(tcg_env, cpu_dest, cpu_src); break; case 0x15: /* flog10 */ - gen_helper_flog10(cpu_env, cpu_dest, cpu_src); + gen_helper_flog10(tcg_env, cpu_dest, cpu_src); break; case 0x16: /* flog2 */ - gen_helper_flog2(cpu_env, cpu_dest, cpu_src); + gen_helper_flog2(tcg_env, cpu_dest, cpu_src); break; case 0x18: /* fabs */ - gen_helper_fabs(cpu_env, cpu_dest, cpu_src); + gen_helper_fabs(tcg_env, cpu_dest, cpu_src); break; case 0x58: /* fsabs */ - gen_helper_fsabs(cpu_env, cpu_dest, cpu_src); + gen_helper_fsabs(tcg_env, cpu_dest, cpu_src); break; case 0x5c: /* fdabs */ - gen_helper_fdabs(cpu_env, cpu_dest, cpu_src); + gen_helper_fdabs(tcg_env, cpu_dest, cpu_src); break; case 0x19: /* fcosh */ - gen_helper_fcosh(cpu_env, cpu_dest, cpu_src); + gen_helper_fcosh(tcg_env, cpu_dest, cpu_src); break; case 0x1a: /* fneg */ - gen_helper_fneg(cpu_env, cpu_dest, cpu_src); + gen_helper_fneg(tcg_env, cpu_dest, cpu_src); break; case 0x5a: /* fsneg */ - gen_helper_fsneg(cpu_env, cpu_dest, cpu_src); + gen_helper_fsneg(tcg_env, cpu_dest, cpu_src); break; case 0x5e: /* fdneg */ - gen_helper_fdneg(cpu_env, cpu_dest, cpu_src); + gen_helper_fdneg(tcg_env, cpu_dest, cpu_src); break; case 0x1c: /* facos */ - gen_helper_facos(cpu_env, cpu_dest, cpu_src); + gen_helper_facos(tcg_env, cpu_dest, cpu_src); break; case 0x1d: /* fcos */ - gen_helper_fcos(cpu_env, cpu_dest, cpu_src); + gen_helper_fcos(tcg_env, cpu_dest, cpu_src); break; case 0x1e: /* fgetexp */ - gen_helper_fgetexp(cpu_env, cpu_dest, cpu_src); + gen_helper_fgetexp(tcg_env, cpu_dest, cpu_src); break; case 0x1f: /* fgetman */ - gen_helper_fgetman(cpu_env, cpu_dest, cpu_src); + gen_helper_fgetman(tcg_env, cpu_dest, cpu_src); break; case 0x20: /* fdiv */ - gen_helper_fdiv(cpu_env, cpu_dest, cpu_src, cpu_dest); + gen_helper_fdiv(tcg_env, cpu_dest, cpu_src, cpu_dest); break; case 0x60: /* fsdiv */ - gen_helper_fsdiv(cpu_env, cpu_dest, cpu_src, cpu_dest); + gen_helper_fsdiv(tcg_env, cpu_dest, cpu_src, cpu_dest); break; case 0x64: /* fddiv */ - gen_helper_fddiv(cpu_env, cpu_dest, cpu_src, cpu_dest); + gen_helper_fddiv(tcg_env, cpu_dest, cpu_src, cpu_dest); break; case 0x21: /* fmod */ - gen_helper_fmod(cpu_env, cpu_dest, cpu_src, cpu_dest); + gen_helper_fmod(tcg_env, cpu_dest, cpu_src, cpu_dest); break; case 0x22: /* fadd */ - gen_helper_fadd(cpu_env, cpu_dest, cpu_src, cpu_dest); + gen_helper_fadd(tcg_env, cpu_dest, cpu_src, cpu_dest); break; case 0x62: /* fsadd */ - gen_helper_fsadd(cpu_env, cpu_dest, cpu_src, cpu_dest); + gen_helper_fsadd(tcg_env, cpu_dest, cpu_src, cpu_dest); break; case 0x66: /* fdadd */ - gen_helper_fdadd(cpu_env, cpu_dest, cpu_src, cpu_dest); + gen_helper_fdadd(tcg_env, cpu_dest, cpu_src, cpu_dest); break; case 0x23: /* fmul */ - gen_helper_fmul(cpu_env, cpu_dest, cpu_src, cpu_dest); + gen_helper_fmul(tcg_env, cpu_dest, cpu_src, cpu_dest); break; case 0x63: /* fsmul */ - gen_helper_fsmul(cpu_env, cpu_dest, cpu_src, cpu_dest); + gen_helper_fsmul(tcg_env, cpu_dest, cpu_src, cpu_dest); break; case 0x67: /* fdmul */ - gen_helper_fdmul(cpu_env, cpu_dest, cpu_src, cpu_dest); + gen_helper_fdmul(tcg_env, cpu_dest, cpu_src, cpu_dest); break; case 0x24: /* fsgldiv */ - gen_helper_fsgldiv(cpu_env, cpu_dest, cpu_src, cpu_dest); + gen_helper_fsgldiv(tcg_env, cpu_dest, cpu_src, cpu_dest); break; case 0x25: /* frem */ - gen_helper_frem(cpu_env, cpu_dest, cpu_src, cpu_dest); + gen_helper_frem(tcg_env, cpu_dest, cpu_src, cpu_dest); break; case 0x26: /* fscale */ - gen_helper_fscale(cpu_env, cpu_dest, cpu_src, cpu_dest); + gen_helper_fscale(tcg_env, cpu_dest, cpu_src, cpu_dest); break; case 0x27: /* fsglmul */ - gen_helper_fsglmul(cpu_env, cpu_dest, cpu_src, cpu_dest); + gen_helper_fsglmul(tcg_env, cpu_dest, cpu_src, cpu_dest); break; case 0x28: /* fsub */ - gen_helper_fsub(cpu_env, cpu_dest, cpu_src, cpu_dest); + gen_helper_fsub(tcg_env, cpu_dest, cpu_src, cpu_dest); break; case 0x68: /* fssub */ - gen_helper_fssub(cpu_env, cpu_dest, cpu_src, cpu_dest); + gen_helper_fssub(tcg_env, cpu_dest, cpu_src, cpu_dest); break; case 0x6c: /* fdsub */ - gen_helper_fdsub(cpu_env, cpu_dest, cpu_src, cpu_dest); + gen_helper_fdsub(tcg_env, cpu_dest, cpu_src, cpu_dest); break; case 0x30: case 0x31: case 0x32: case 0x33: case 0x34: case 0x35: case 0x36: case 0x37: { TCGv_ptr cpu_dest2 = gen_fp_ptr(REG(ext, 0)); - gen_helper_fsincos(cpu_env, cpu_dest, cpu_dest2, cpu_src); + gen_helper_fsincos(tcg_env, cpu_dest, cpu_dest2, cpu_src); } break; case 0x38: /* fcmp */ - gen_helper_fcmp(cpu_env, cpu_src, cpu_dest); + gen_helper_fcmp(tcg_env, cpu_src, cpu_dest); return; case 0x3a: /* ftst */ - gen_helper_ftst(cpu_env, cpu_src); + gen_helper_ftst(tcg_env, cpu_src); return; default: goto undef; } - gen_helper_ftst(cpu_env, cpu_dest); + gen_helper_ftst(tcg_env, cpu_dest); return; undef: /* FIXME: Is this right for offset addressing modes? */ @@ -5466,12 +5466,12 @@ DISAS_INSN(mac) ry = gen_mac_extract_word(s, ry, (ext & 0x40) != 0); } if (s->env->macsr & MACSR_FI) { - gen_helper_macmulf(s->mactmp, cpu_env, rx, ry); + gen_helper_macmulf(s->mactmp, tcg_env, rx, ry); } else { if (s->env->macsr & MACSR_SU) - gen_helper_macmuls(s->mactmp, cpu_env, rx, ry); + gen_helper_macmuls(s->mactmp, tcg_env, rx, ry); else - gen_helper_macmulu(s->mactmp, cpu_env, rx, ry); + gen_helper_macmulu(s->mactmp, tcg_env, rx, ry); switch ((ext >> 9) & 3) { case 1: tcg_gen_shli_i64(s->mactmp, s->mactmp, 1); @@ -5507,11 +5507,11 @@ DISAS_INSN(mac) tcg_gen_add_i64(MACREG(acc), MACREG(acc), s->mactmp); if (s->env->macsr & MACSR_FI) - gen_helper_macsatf(cpu_env, tcg_constant_i32(acc)); + gen_helper_macsatf(tcg_env, tcg_constant_i32(acc)); else if (s->env->macsr & MACSR_SU) - gen_helper_macsats(cpu_env, tcg_constant_i32(acc)); + gen_helper_macsats(tcg_env, tcg_constant_i32(acc)); else - gen_helper_macsatu(cpu_env, tcg_constant_i32(acc)); + gen_helper_macsatu(tcg_env, tcg_constant_i32(acc)); #if 0 /* Disabled because conditional branches clobber temporary vars. */ @@ -5539,18 +5539,18 @@ DISAS_INSN(mac) else tcg_gen_add_i64(MACREG(acc), MACREG(acc), s->mactmp); if (s->env->macsr & MACSR_FI) - gen_helper_macsatf(cpu_env, tcg_constant_i32(acc)); + gen_helper_macsatf(tcg_env, tcg_constant_i32(acc)); else if (s->env->macsr & MACSR_SU) - gen_helper_macsats(cpu_env, tcg_constant_i32(acc)); + gen_helper_macsats(tcg_env, tcg_constant_i32(acc)); else - gen_helper_macsatu(cpu_env, tcg_constant_i32(acc)); + gen_helper_macsatu(tcg_env, tcg_constant_i32(acc)); #if 0 /* Disabled because conditional branches clobber temporary vars. */ if (l1 != -1) gen_set_label(l1); #endif } - gen_helper_mac_set_flags(cpu_env, tcg_constant_i32(acc)); + gen_helper_mac_set_flags(tcg_env, tcg_constant_i32(acc)); if (insn & 0x30) { TCGv rw; @@ -5580,7 +5580,7 @@ DISAS_INSN(from_mac) accnum = (insn >> 9) & 3; acc = MACREG(accnum); if (s->env->macsr & MACSR_FI) { - gen_helper_get_macf(rx, cpu_env, acc); + gen_helper_get_macf(rx, tcg_env, acc); } else if ((s->env->macsr & MACSR_OMC) == 0) { tcg_gen_extrl_i64_i32(rx, acc); } else if (s->env->macsr & MACSR_SU) { @@ -5601,9 +5601,9 @@ DISAS_INSN(move_mac) TCGv dest; src = insn & 3; dest = tcg_constant_i32((insn >> 9) & 3); - gen_helper_mac_move(cpu_env, dest, tcg_constant_i32(src)); + gen_helper_mac_move(tcg_env, dest, tcg_constant_i32(src)); gen_mac_clear_flags(); - gen_helper_mac_set_flags(cpu_env, dest); + gen_helper_mac_set_flags(tcg_env, dest); } DISAS_INSN(from_macsr) @@ -5628,9 +5628,9 @@ DISAS_INSN(from_mext) reg = (insn & 8) ? AREG(insn, 0) : DREG(insn, 0); acc = tcg_constant_i32((insn & 0x400) ? 2 : 0); if (s->env->macsr & MACSR_FI) - gen_helper_get_mac_extf(reg, cpu_env, acc); + gen_helper_get_mac_extf(reg, tcg_env, acc); else - gen_helper_get_mac_exti(reg, cpu_env, acc); + gen_helper_get_mac_exti(reg, tcg_env, acc); } DISAS_INSN(macsr_to_ccr) @@ -5639,7 +5639,7 @@ DISAS_INSN(macsr_to_ccr) /* Note that X and C are always cleared. */ tcg_gen_andi_i32(tmp, QREG_MACSR, CCF_N | CCF_Z | CCF_V); - gen_helper_set_ccr(cpu_env, tmp); + gen_helper_set_ccr(tcg_env, tmp); set_cc_op(s, CC_OP_FLAGS); } @@ -5661,14 +5661,14 @@ DISAS_INSN(to_mac) } tcg_gen_andi_i32(QREG_MACSR, QREG_MACSR, ~(MACSR_PAV0 << accnum)); gen_mac_clear_flags(); - gen_helper_mac_set_flags(cpu_env, tcg_constant_i32(accnum)); + gen_helper_mac_set_flags(tcg_env, tcg_constant_i32(accnum)); } DISAS_INSN(to_macsr) { TCGv val; SRC_EA(env, val, OS_LONG, 0, NULL); - gen_helper_set_macsr(cpu_env, val); + gen_helper_set_macsr(tcg_env, val); gen_exit_tb(s); } @@ -5686,11 +5686,11 @@ DISAS_INSN(to_mext) SRC_EA(env, val, OS_LONG, 0, NULL); acc = tcg_constant_i32((insn & 0x400) ? 2 : 0); if (s->env->macsr & MACSR_FI) - gen_helper_set_mac_extf(cpu_env, val, acc); + gen_helper_set_mac_extf(tcg_env, val, acc); else if (s->env->macsr & MACSR_SU) - gen_helper_set_mac_exts(cpu_env, val, acc); + gen_helper_set_mac_exts(tcg_env, val, acc); else - gen_helper_set_mac_extu(cpu_env, val, acc); + gen_helper_set_mac_extu(tcg_env, val, acc); } static disas_proc opcode_table[65536]; diff --git a/target/microblaze/translate.c b/target/microblaze/translate.c index d02c16296a..bb178219f1 100644 --- a/target/microblaze/translate.c +++ b/target/microblaze/translate.c @@ -102,7 +102,7 @@ static void t_sync_flags(DisasContext *dc) static void gen_raise_exception(DisasContext *dc, uint32_t index) { - gen_helper_raise_exception(cpu_env, tcg_constant_i32(index)); + gen_helper_raise_exception(tcg_env, tcg_constant_i32(index)); dc->base.is_jmp = DISAS_NORETURN; } @@ -116,7 +116,7 @@ static void gen_raise_exception_sync(DisasContext *dc, uint32_t index) static void gen_raise_hw_excp(DisasContext *dc, uint32_t esr_ec) { TCGv_i32 tmp = tcg_constant_i32(esr_ec); - tcg_gen_st_i32(tmp, cpu_env, offsetof(CPUMBState, esr)); + tcg_gen_st_i32(tmp, tcg_env, offsetof(CPUMBState, esr)); gen_raise_exception_sync(dc, EXCP_HW_EXCP); } @@ -295,11 +295,11 @@ static bool do_typeb_val(DisasContext *dc, arg_typeb *arg, bool side_effects, #define ENV_WRAPPER2(NAME, HELPER) \ static void NAME(TCGv_i32 out, TCGv_i32 ina) \ - { HELPER(out, cpu_env, ina); } + { HELPER(out, tcg_env, ina); } #define ENV_WRAPPER3(NAME, HELPER) \ static void NAME(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb) \ - { HELPER(out, cpu_env, ina, inb); } + { HELPER(out, tcg_env, ina, inb); } /* No input carry, but output carry. */ static void gen_add(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb) @@ -472,12 +472,12 @@ DO_TYPEA0_CFG(fsqrt, use_fpu >= 2, true, gen_fsqrt) /* Does not use ENV_WRAPPER3, because arguments are swapped as well. */ static void gen_idiv(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb) { - gen_helper_divs(out, cpu_env, inb, ina); + gen_helper_divs(out, tcg_env, inb, ina); } static void gen_idivu(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb) { - gen_helper_divu(out, cpu_env, inb, ina); + gen_helper_divu(out, tcg_env, inb, ina); } DO_TYPEA_CFG(idiv, use_div, true, gen_idiv) @@ -643,7 +643,7 @@ static TCGv compute_ldst_addr_typea(DisasContext *dc, int ra, int rb) } if ((ra == 1 || rb == 1) && dc->cfg->stackprot) { - gen_helper_stackprot(cpu_env, ret); + gen_helper_stackprot(tcg_env, ret); } return ret; } @@ -662,7 +662,7 @@ static TCGv compute_ldst_addr_typeb(DisasContext *dc, int ra, int imm) } if (ra == 1 && dc->cfg->stackprot) { - gen_helper_stackprot(cpu_env, ret); + gen_helper_stackprot(tcg_env, ret); } return ret; } @@ -1232,7 +1232,7 @@ static bool trans_mbar(DisasContext *dc, arg_mbar *arg) t_sync_flags(dc); - tcg_gen_st_i32(tcg_constant_i32(1), cpu_env, + tcg_gen_st_i32(tcg_constant_i32(1), tcg_env, -offsetof(MicroBlazeCPU, env) +offsetof(CPUState, halted)); @@ -1381,13 +1381,13 @@ static bool trans_mts(DisasContext *dc, arg_mts *arg) tcg_gen_andi_i32(cpu_msr, src, ~(MSR_C | MSR_CC | MSR_PVR)); break; case SR_FSR: - tcg_gen_st_i32(src, cpu_env, offsetof(CPUMBState, fsr)); + tcg_gen_st_i32(src, tcg_env, offsetof(CPUMBState, fsr)); break; case 0x800: - tcg_gen_st_i32(src, cpu_env, offsetof(CPUMBState, slr)); + tcg_gen_st_i32(src, tcg_env, offsetof(CPUMBState, slr)); break; case 0x802: - tcg_gen_st_i32(src, cpu_env, offsetof(CPUMBState, shr)); + tcg_gen_st_i32(src, tcg_env, offsetof(CPUMBState, shr)); break; case 0x1000: /* PID */ @@ -1400,7 +1400,7 @@ static bool trans_mts(DisasContext *dc, arg_mts *arg) TCGv_i32 tmp_ext = tcg_constant_i32(arg->e); TCGv_i32 tmp_reg = tcg_constant_i32(arg->rs & 7); - gen_helper_mmu_write(cpu_env, tmp_ext, tmp_reg, src); + gen_helper_mmu_write(tcg_env, tmp_ext, tmp_reg, src); } break; @@ -1422,7 +1422,7 @@ static bool trans_mfs(DisasContext *dc, arg_mfs *arg) case SR_EAR: { TCGv_i64 t64 = tcg_temp_new_i64(); - tcg_gen_ld_i64(t64, cpu_env, offsetof(CPUMBState, ear)); + tcg_gen_ld_i64(t64, tcg_env, offsetof(CPUMBState, ear)); tcg_gen_extrh_i64_i32(dest, t64); } return true; @@ -1452,27 +1452,27 @@ static bool trans_mfs(DisasContext *dc, arg_mfs *arg) case SR_EAR: { TCGv_i64 t64 = tcg_temp_new_i64(); - tcg_gen_ld_i64(t64, cpu_env, offsetof(CPUMBState, ear)); + tcg_gen_ld_i64(t64, tcg_env, offsetof(CPUMBState, ear)); tcg_gen_extrl_i64_i32(dest, t64); } break; case SR_ESR: - tcg_gen_ld_i32(dest, cpu_env, offsetof(CPUMBState, esr)); + tcg_gen_ld_i32(dest, tcg_env, offsetof(CPUMBState, esr)); break; case SR_FSR: - tcg_gen_ld_i32(dest, cpu_env, offsetof(CPUMBState, fsr)); + tcg_gen_ld_i32(dest, tcg_env, offsetof(CPUMBState, fsr)); break; case SR_BTR: - tcg_gen_ld_i32(dest, cpu_env, offsetof(CPUMBState, btr)); + tcg_gen_ld_i32(dest, tcg_env, offsetof(CPUMBState, btr)); break; case SR_EDR: - tcg_gen_ld_i32(dest, cpu_env, offsetof(CPUMBState, edr)); + tcg_gen_ld_i32(dest, tcg_env, offsetof(CPUMBState, edr)); break; case 0x800: - tcg_gen_ld_i32(dest, cpu_env, offsetof(CPUMBState, slr)); + tcg_gen_ld_i32(dest, tcg_env, offsetof(CPUMBState, slr)); break; case 0x802: - tcg_gen_ld_i32(dest, cpu_env, offsetof(CPUMBState, shr)); + tcg_gen_ld_i32(dest, tcg_env, offsetof(CPUMBState, shr)); break; #ifndef CONFIG_USER_ONLY @@ -1486,13 +1486,13 @@ static bool trans_mfs(DisasContext *dc, arg_mfs *arg) TCGv_i32 tmp_ext = tcg_constant_i32(arg->e); TCGv_i32 tmp_reg = tcg_constant_i32(arg->rs & 7); - gen_helper_mmu_read(dest, cpu_env, tmp_ext, tmp_reg); + gen_helper_mmu_read(dest, tcg_env, tmp_ext, tmp_reg); } break; #endif case 0x2000 ... 0x200c: - tcg_gen_ld_i32(dest, cpu_env, + tcg_gen_ld_i32(dest, tcg_env, offsetof(MicroBlazeCPU, cfg.pvr_regs[arg->rs - 0x2000]) - offsetof(MicroBlazeCPU, env)); break; @@ -1882,9 +1882,9 @@ void mb_tcg_init(void) for (int i = 0; i < ARRAY_SIZE(i32s); ++i) { *i32s[i].var = - tcg_global_mem_new_i32(cpu_env, i32s[i].ofs, i32s[i].name); + tcg_global_mem_new_i32(tcg_env, i32s[i].ofs, i32s[i].name); } cpu_res_addr = - tcg_global_mem_new(cpu_env, offsetof(CPUMBState, res_addr), "res_addr"); + tcg_global_mem_new(tcg_env, offsetof(CPUMBState, res_addr), "res_addr"); } diff --git a/target/mips/tcg/lcsr_translate.c b/target/mips/tcg/lcsr_translate.c index 9f2a5f4a37..352b0f4328 100644 --- a/target/mips/tcg/lcsr_translate.c +++ b/target/mips/tcg/lcsr_translate.c @@ -22,7 +22,7 @@ static bool trans_CPUCFG(DisasContext *ctx, arg_CPUCFG *a) TCGv src1 = tcg_temp_new(); gen_load_gpr(src1, a->rs); - gen_helper_lcsr_cpucfg(dest, cpu_env, src1); + gen_helper_lcsr_cpucfg(dest, tcg_env, src1); gen_store_gpr(dest, a->rd); return true; @@ -37,7 +37,7 @@ static bool gen_rdcsr(DisasContext *ctx, arg_r *a, check_cp0_enabled(ctx); gen_load_gpr(src1, a->rs); - func(dest, cpu_env, src1); + func(dest, tcg_env, src1); gen_store_gpr(dest, a->rd); return true; @@ -52,7 +52,7 @@ static bool gen_wrcsr(DisasContext *ctx, arg_r *a, check_cp0_enabled(ctx); gen_load_gpr(addr, a->rs); gen_load_gpr(val, a->rd); - func(cpu_env, addr, val); + func(tcg_env, addr, val); return true; } diff --git a/target/mips/tcg/micromips_translate.c.inc b/target/mips/tcg/micromips_translate.c.inc index 211d102cf6..7510831701 100644 --- a/target/mips/tcg/micromips_translate.c.inc +++ b/target/mips/tcg/micromips_translate.c.inc @@ -710,17 +710,17 @@ static void gen_ldst_multiple(DisasContext *ctx, uint32_t opc, int reglist, save_cpu_state(ctx, 1); switch (opc) { case LWM32: - gen_helper_lwm(cpu_env, t0, t1, t2); + gen_helper_lwm(tcg_env, t0, t1, t2); break; case SWM32: - gen_helper_swm(cpu_env, t0, t1, t2); + gen_helper_swm(tcg_env, t0, t1, t2); break; #ifdef TARGET_MIPS64 case LDM: - gen_helper_ldm(cpu_env, t0, t1, t2); + gen_helper_ldm(tcg_env, t0, t1, t2); break; case SDM: - gen_helper_sdm(cpu_env, t0, t1, t2); + gen_helper_sdm(tcg_env, t0, t1, t2); break; #endif } @@ -1271,7 +1271,7 @@ static void gen_pool32axf(CPUMIPSState *env, DisasContext *ctx, int rt, int rs) TCGv t0 = tcg_temp_new(); save_cpu_state(ctx, 1); - gen_helper_di(t0, cpu_env); + gen_helper_di(t0, tcg_env); gen_store_gpr(t0, rs); /* * Stop translation as we may have switched the execution @@ -1286,7 +1286,7 @@ static void gen_pool32axf(CPUMIPSState *env, DisasContext *ctx, int rt, int rs) TCGv t0 = tcg_temp_new(); save_cpu_state(ctx, 1); - gen_helper_ei(t0, cpu_env); + gen_helper_ei(t0, tcg_env); gen_store_gpr(t0, rs); /* * DISAS_STOP isn't sufficient, we need to ensure we break out diff --git a/target/mips/tcg/msa_translate.c b/target/mips/tcg/msa_translate.c index b5b66fb38a..75cf80a20e 100644 --- a/target/mips/tcg/msa_translate.c +++ b/target/mips/tcg/msa_translate.c @@ -140,7 +140,7 @@ void msa_translate_init(void) off = offsetof(CPUMIPSState, active_fpu.fpr[i].wr.d[1]); msa_wr_d[i * 2 + 1] = - tcg_global_mem_new_i64(cpu_env, off, msaregnames[i * 2 + 1]); + tcg_global_mem_new_i64(tcg_env, off, msaregnames[i * 2 + 1]); } } @@ -288,7 +288,7 @@ static bool trans_msa_i8(DisasContext *ctx, arg_msa_i *a, return true; } - gen_msa_i8(cpu_env, + gen_msa_i8(tcg_env, tcg_constant_i32(a->wd), tcg_constant_i32(a->ws), tcg_constant_i32(a->sa)); @@ -314,7 +314,7 @@ static bool trans_SHF(DisasContext *ctx, arg_msa_i *a) return true; } - gen_helper_msa_shf_df(cpu_env, + gen_helper_msa_shf_df(tcg_env, tcg_constant_i32(a->df), tcg_constant_i32(a->wd), tcg_constant_i32(a->ws), @@ -330,7 +330,7 @@ static bool trans_msa_i5(DisasContext *ctx, arg_msa_i *a, return true; } - gen_msa_i5(cpu_env, + gen_msa_i5(tcg_env, tcg_constant_i32(a->df), tcg_constant_i32(a->wd), tcg_constant_i32(a->ws), @@ -357,7 +357,7 @@ static bool trans_LDI(DisasContext *ctx, arg_msa_ldi *a) return true; } - gen_helper_msa_ldi_df(cpu_env, + gen_helper_msa_ldi_df(tcg_env, tcg_constant_i32(a->df), tcg_constant_i32(a->wd), tcg_constant_i32(a->sa)); @@ -376,7 +376,7 @@ static bool trans_msa_bit(DisasContext *ctx, arg_msa_bit *a, return true; } - gen_msa_bit(cpu_env, + gen_msa_bit(tcg_env, tcg_constant_i32(a->df), tcg_constant_i32(a->wd), tcg_constant_i32(a->ws), @@ -405,7 +405,7 @@ static bool trans_msa_3rf(DisasContext *ctx, arg_msa_r *a, return true; } - gen_msa_3rf(cpu_env, + gen_msa_3rf(tcg_env, tcg_constant_i32(a->df), tcg_constant_i32(a->wd), tcg_constant_i32(a->ws), @@ -425,7 +425,7 @@ static bool trans_msa_3r(DisasContext *ctx, arg_msa_r *a, return true; } - gen_msa_3r(cpu_env, + gen_msa_3r(tcg_env, tcg_constant_i32(a->wd), tcg_constant_i32(a->ws), tcg_constant_i32(a->wt)); @@ -519,7 +519,7 @@ static bool trans_MOVE_V(DisasContext *ctx, arg_msa_elm *a) return true; } - gen_helper_msa_move_v(cpu_env, + gen_helper_msa_move_v(tcg_env, tcg_constant_i32(a->wd), tcg_constant_i32(a->ws)); @@ -537,7 +537,7 @@ static bool trans_CTCMSA(DisasContext *ctx, arg_msa_elm *a) telm = tcg_temp_new(); gen_load_gpr(telm, a->ws); - gen_helper_msa_ctcmsa(cpu_env, telm, tcg_constant_i32(a->wd)); + gen_helper_msa_ctcmsa(tcg_env, telm, tcg_constant_i32(a->wd)); return true; } @@ -552,7 +552,7 @@ static bool trans_CFCMSA(DisasContext *ctx, arg_msa_elm *a) telm = tcg_temp_new(); - gen_helper_msa_cfcmsa(telm, cpu_env, tcg_constant_i32(a->ws)); + gen_helper_msa_cfcmsa(telm, tcg_env, tcg_constant_i32(a->ws)); gen_store_gpr(telm, a->wd); return true; @@ -569,7 +569,7 @@ static bool trans_msa_elm(DisasContext *ctx, arg_msa_elm_df *a, return true; } - gen_msa_elm_df(cpu_env, + gen_msa_elm_df(tcg_env, tcg_constant_i32(a->df), tcg_constant_i32(a->wd), tcg_constant_i32(a->ws), @@ -593,7 +593,7 @@ static bool trans_msa_elm_fn(DisasContext *ctx, arg_msa_elm_df *a, return true; } - gen_msa_elm[a->df](cpu_env, + gen_msa_elm[a->df](tcg_env, tcg_constant_i32(a->wd), tcg_constant_i32(a->ws), tcg_constant_i32(a->n)); @@ -698,7 +698,7 @@ static bool trans_msa_2r(DisasContext *ctx, arg_msa_r *a, return true; } - gen_msa_2r(cpu_env, tcg_constant_i32(a->wd), tcg_constant_i32(a->ws)); + gen_msa_2r(tcg_env, tcg_constant_i32(a->wd), tcg_constant_i32(a->ws)); return true; } @@ -718,7 +718,7 @@ static bool trans_FILL(DisasContext *ctx, arg_msa_r *a) return true; } - gen_helper_msa_fill_df(cpu_env, + gen_helper_msa_fill_df(tcg_env, tcg_constant_i32(a->df), tcg_constant_i32(a->wd), tcg_constant_i32(a->ws)); @@ -733,7 +733,7 @@ static bool trans_msa_2rf(DisasContext *ctx, arg_msa_r *a, return true; } - gen_msa_2rf(cpu_env, + gen_msa_2rf(tcg_env, tcg_constant_i32(a->df), tcg_constant_i32(a->wd), tcg_constant_i32(a->ws)); @@ -770,7 +770,7 @@ static bool trans_msa_ldst(DisasContext *ctx, arg_msa_i *a, taddr = tcg_temp_new(); gen_base_offset_addr(ctx, taddr, a->ws, a->sa << a->df); - gen_msa_ldst(cpu_env, tcg_constant_i32(a->wd), taddr); + gen_msa_ldst(tcg_env, tcg_constant_i32(a->wd), taddr); return true; } diff --git a/target/mips/tcg/mxu_translate.c b/target/mips/tcg/mxu_translate.c index cfcd8ac9bc..c517258ac5 100644 --- a/target/mips/tcg/mxu_translate.c +++ b/target/mips/tcg/mxu_translate.c @@ -617,12 +617,12 @@ static const char mxuregnames[NUMBER_OF_MXU_REGISTERS][4] = { void mxu_translate_init(void) { for (unsigned i = 0; i < NUMBER_OF_MXU_REGISTERS - 1; i++) { - mxu_gpr[i] = tcg_global_mem_new(cpu_env, + mxu_gpr[i] = tcg_global_mem_new(tcg_env, offsetof(CPUMIPSState, active_tc.mxu_gpr[i]), mxuregnames[i]); } - mxu_CR = tcg_global_mem_new(cpu_env, + mxu_CR = tcg_global_mem_new(tcg_env, offsetof(CPUMIPSState, active_tc.mxu_cr), mxuregnames[NUMBER_OF_MXU_REGISTERS - 1]); } diff --git a/target/mips/tcg/nanomips_translate.c.inc b/target/mips/tcg/nanomips_translate.c.inc index d81a7c2d11..b4b746d418 100644 --- a/target/mips/tcg/nanomips_translate.c.inc +++ b/target/mips/tcg/nanomips_translate.c.inc @@ -1006,8 +1006,8 @@ static void gen_llwp(DisasContext *ctx, uint32_t base, int16_t offset, } gen_store_gpr(tmp1, reg1); gen_store_gpr(tmp2, reg2); - tcg_gen_st_i64(tval, cpu_env, offsetof(CPUMIPSState, llval_wp)); - tcg_gen_st_tl(taddr, cpu_env, offsetof(CPUMIPSState, lladdr)); + tcg_gen_st_i64(tval, tcg_env, offsetof(CPUMIPSState, llval_wp)); + tcg_gen_st_tl(taddr, tcg_env, offsetof(CPUMIPSState, lladdr)); } static void gen_scwp(DisasContext *ctx, uint32_t base, int16_t offset, @@ -1025,7 +1025,7 @@ static void gen_scwp(DisasContext *ctx, uint32_t base, int16_t offset, gen_base_offset_addr(ctx, taddr, base, offset); - tcg_gen_ld_tl(lladdr, cpu_env, offsetof(CPUMIPSState, lladdr)); + tcg_gen_ld_tl(lladdr, tcg_env, offsetof(CPUMIPSState, lladdr)); tcg_gen_brcond_tl(TCG_COND_NE, taddr, lladdr, lab_fail); gen_load_gpr(tmp1, reg1); @@ -1037,7 +1037,7 @@ static void gen_scwp(DisasContext *ctx, uint32_t base, int16_t offset, tcg_gen_concat_tl_i64(tval, tmp1, tmp2); } - tcg_gen_ld_i64(llval, cpu_env, offsetof(CPUMIPSState, llval_wp)); + tcg_gen_ld_i64(llval, tcg_env, offsetof(CPUMIPSState, llval_wp)); tcg_gen_atomic_cmpxchg_i64(val, taddr, llval, tval, eva ? MIPS_HFLAG_UM : ctx->mem_idx, MO_64 | MO_ALIGN); @@ -1053,7 +1053,7 @@ static void gen_scwp(DisasContext *ctx, uint32_t base, int16_t offset, } gen_set_label(lab_done); tcg_gen_movi_tl(lladdr, -1); - tcg_gen_st_tl(lladdr, cpu_env, offsetof(CPUMIPSState, lladdr)); + tcg_gen_st_tl(lladdr, tcg_env, offsetof(CPUMIPSState, lladdr)); } static void gen_adjust_sp(DisasContext *ctx, int u) @@ -1335,14 +1335,14 @@ static void gen_pool32a0_nanomips_insn(CPUMIPSState *env, DisasContext *ctx) case NM_DVP: if (ctx->vp) { check_cp0_enabled(ctx); - gen_helper_dvp(t0, cpu_env); + gen_helper_dvp(t0, tcg_env); gen_store_gpr(t0, rt); } break; case NM_EVP: if (ctx->vp) { check_cp0_enabled(ctx); - gen_helper_evp(t0, cpu_env); + gen_helper_evp(t0, tcg_env); gen_store_gpr(t0, rt); } break; @@ -1428,7 +1428,7 @@ static void gen_pool32a0_nanomips_insn(CPUMIPSState *env, DisasContext *ctx) } else if (rs == 0) { /* DVPE */ check_cp0_mt(ctx); - gen_helper_dvpe(t0, cpu_env); + gen_helper_dvpe(t0, tcg_env); gen_store_gpr(t0, rt); } else { gen_reserved_instruction(ctx); @@ -1443,7 +1443,7 @@ static void gen_pool32a0_nanomips_insn(CPUMIPSState *env, DisasContext *ctx) } else if (rs == 0) { /* EVPE */ check_cp0_mt(ctx); - gen_helper_evpe(t0, cpu_env); + gen_helper_evpe(t0, tcg_env); gen_store_gpr(t0, rt); } else { gen_reserved_instruction(ctx); @@ -1485,7 +1485,7 @@ static void gen_pool32a0_nanomips_insn(CPUMIPSState *env, DisasContext *ctx) TCGv t0 = tcg_temp_new(); gen_load_gpr(t0, rs); - gen_helper_yield(t0, cpu_env, t0); + gen_helper_yield(t0, tcg_env, t0); gen_store_gpr(t0, rt); } break; @@ -1517,19 +1517,19 @@ static void gen_pool32axf_1_5_nanomips_insn(DisasContext *ctx, uint32_t opc, switch (opc) { case NM_MAQ_S_W_PHR: check_dsp(ctx); - gen_helper_maq_s_w_phr(t0, v1_t, v0_t, cpu_env); + gen_helper_maq_s_w_phr(t0, v1_t, v0_t, tcg_env); break; case NM_MAQ_S_W_PHL: check_dsp(ctx); - gen_helper_maq_s_w_phl(t0, v1_t, v0_t, cpu_env); + gen_helper_maq_s_w_phl(t0, v1_t, v0_t, tcg_env); break; case NM_MAQ_SA_W_PHR: check_dsp(ctx); - gen_helper_maq_sa_w_phr(t0, v1_t, v0_t, cpu_env); + gen_helper_maq_sa_w_phr(t0, v1_t, v0_t, tcg_env); break; case NM_MAQ_SA_W_PHL: check_dsp(ctx); - gen_helper_maq_sa_w_phl(t0, v1_t, v0_t, cpu_env); + gen_helper_maq_sa_w_phl(t0, v1_t, v0_t, tcg_env); break; default: gen_reserved_instruction(ctx); @@ -1571,11 +1571,11 @@ static void gen_pool32axf_1_nanomips_insn(DisasContext *ctx, uint32_t opc, switch (extract32(ctx->opcode, 12, 2)) { case NM_MTHLIP: tcg_gen_movi_tl(t0, v2 >> 3); - gen_helper_mthlip(t0, v0_t, cpu_env); + gen_helper_mthlip(t0, v0_t, tcg_env); break; case NM_SHILOV: tcg_gen_movi_tl(t0, v2 >> 3); - gen_helper_shilo(t0, v0_t, cpu_env); + gen_helper_shilo(t0, v0_t, tcg_env); break; default: gen_reserved_instruction(ctx); @@ -1588,24 +1588,24 @@ static void gen_pool32axf_1_nanomips_insn(DisasContext *ctx, uint32_t opc, switch (extract32(ctx->opcode, 12, 2)) { case NM_RDDSP: tcg_gen_movi_tl(t0, imm); - gen_helper_rddsp(t0, t0, cpu_env); + gen_helper_rddsp(t0, t0, tcg_env); gen_store_gpr(t0, ret); break; case NM_WRDSP: gen_load_gpr(t0, ret); tcg_gen_movi_tl(t1, imm); - gen_helper_wrdsp(t0, t1, cpu_env); + gen_helper_wrdsp(t0, t1, tcg_env); break; case NM_EXTP: tcg_gen_movi_tl(t0, v2 >> 3); tcg_gen_movi_tl(t1, v1); - gen_helper_extp(t0, t0, t1, cpu_env); + gen_helper_extp(t0, t0, t1, tcg_env); gen_store_gpr(t0, ret); break; case NM_EXTPDP: tcg_gen_movi_tl(t0, v2 >> 3); tcg_gen_movi_tl(t1, v1); - gen_helper_extpdp(t0, t0, t1, cpu_env); + gen_helper_extpdp(t0, t0, t1, tcg_env); gen_store_gpr(t0, ret); break; } @@ -1615,7 +1615,7 @@ static void gen_pool32axf_1_nanomips_insn(DisasContext *ctx, uint32_t opc, tcg_gen_movi_tl(t0, v2 >> 2); switch (extract32(ctx->opcode, 12, 1)) { case NM_SHLL_QB: - gen_helper_shll_qb(t0, t0, v0_t, cpu_env); + gen_helper_shll_qb(t0, t0, v0_t, tcg_env); gen_store_gpr(t0, ret); break; case NM_SHRL_QB: @@ -1634,19 +1634,19 @@ static void gen_pool32axf_1_nanomips_insn(DisasContext *ctx, uint32_t opc, tcg_gen_movi_tl(t1, v1); switch (extract32(ctx->opcode, 12, 2)) { case NM_EXTR_W: - gen_helper_extr_w(t0, t0, t1, cpu_env); + gen_helper_extr_w(t0, t0, t1, tcg_env); gen_store_gpr(t0, ret); break; case NM_EXTR_R_W: - gen_helper_extr_r_w(t0, t0, t1, cpu_env); + gen_helper_extr_r_w(t0, t0, t1, tcg_env); gen_store_gpr(t0, ret); break; case NM_EXTR_RS_W: - gen_helper_extr_rs_w(t0, t0, t1, cpu_env); + gen_helper_extr_rs_w(t0, t0, t1, tcg_env); gen_store_gpr(t0, ret); break; case NM_EXTR_S_H: - gen_helper_extr_s_h(t0, t0, t1, cpu_env); + gen_helper_extr_s_h(t0, t0, t1, tcg_env); gen_store_gpr(t0, ret); break; } @@ -1671,19 +1671,19 @@ static void gen_pool32axf_2_multiply(DisasContext *ctx, uint32_t opc, switch (extract32(ctx->opcode, 9, 3)) { case NM_DPA_W_PH: check_dsp_r2(ctx); - gen_helper_dpa_w_ph(t0, v1, v0, cpu_env); + gen_helper_dpa_w_ph(t0, v1, v0, tcg_env); break; case NM_DPAQ_S_W_PH: check_dsp(ctx); - gen_helper_dpaq_s_w_ph(t0, v1, v0, cpu_env); + gen_helper_dpaq_s_w_ph(t0, v1, v0, tcg_env); break; case NM_DPS_W_PH: check_dsp_r2(ctx); - gen_helper_dps_w_ph(t0, v1, v0, cpu_env); + gen_helper_dps_w_ph(t0, v1, v0, tcg_env); break; case NM_DPSQ_S_W_PH: check_dsp(ctx); - gen_helper_dpsq_s_w_ph(t0, v1, v0, cpu_env); + gen_helper_dpsq_s_w_ph(t0, v1, v0, tcg_env); break; default: gen_reserved_instruction(ctx); @@ -1694,19 +1694,19 @@ static void gen_pool32axf_2_multiply(DisasContext *ctx, uint32_t opc, switch (extract32(ctx->opcode, 9, 3)) { case NM_DPAX_W_PH: check_dsp_r2(ctx); - gen_helper_dpax_w_ph(t0, v0, v1, cpu_env); + gen_helper_dpax_w_ph(t0, v0, v1, tcg_env); break; case NM_DPAQ_SA_L_W: check_dsp(ctx); - gen_helper_dpaq_sa_l_w(t0, v0, v1, cpu_env); + gen_helper_dpaq_sa_l_w(t0, v0, v1, tcg_env); break; case NM_DPSX_W_PH: check_dsp_r2(ctx); - gen_helper_dpsx_w_ph(t0, v0, v1, cpu_env); + gen_helper_dpsx_w_ph(t0, v0, v1, tcg_env); break; case NM_DPSQ_SA_L_W: check_dsp(ctx); - gen_helper_dpsq_sa_l_w(t0, v0, v1, cpu_env); + gen_helper_dpsq_sa_l_w(t0, v0, v1, tcg_env); break; default: gen_reserved_instruction(ctx); @@ -1717,23 +1717,23 @@ static void gen_pool32axf_2_multiply(DisasContext *ctx, uint32_t opc, switch (extract32(ctx->opcode, 9, 3)) { case NM_DPAU_H_QBL: check_dsp(ctx); - gen_helper_dpau_h_qbl(t0, v0, v1, cpu_env); + gen_helper_dpau_h_qbl(t0, v0, v1, tcg_env); break; case NM_DPAQX_S_W_PH: check_dsp_r2(ctx); - gen_helper_dpaqx_s_w_ph(t0, v0, v1, cpu_env); + gen_helper_dpaqx_s_w_ph(t0, v0, v1, tcg_env); break; case NM_DPSU_H_QBL: check_dsp(ctx); - gen_helper_dpsu_h_qbl(t0, v0, v1, cpu_env); + gen_helper_dpsu_h_qbl(t0, v0, v1, tcg_env); break; case NM_DPSQX_S_W_PH: check_dsp_r2(ctx); - gen_helper_dpsqx_s_w_ph(t0, v0, v1, cpu_env); + gen_helper_dpsqx_s_w_ph(t0, v0, v1, tcg_env); break; case NM_MULSA_W_PH: check_dsp_r2(ctx); - gen_helper_mulsa_w_ph(t0, v0, v1, cpu_env); + gen_helper_mulsa_w_ph(t0, v0, v1, tcg_env); break; default: gen_reserved_instruction(ctx); @@ -1744,23 +1744,23 @@ static void gen_pool32axf_2_multiply(DisasContext *ctx, uint32_t opc, switch (extract32(ctx->opcode, 9, 3)) { case NM_DPAU_H_QBR: check_dsp(ctx); - gen_helper_dpau_h_qbr(t0, v1, v0, cpu_env); + gen_helper_dpau_h_qbr(t0, v1, v0, tcg_env); break; case NM_DPAQX_SA_W_PH: check_dsp_r2(ctx); - gen_helper_dpaqx_sa_w_ph(t0, v1, v0, cpu_env); + gen_helper_dpaqx_sa_w_ph(t0, v1, v0, tcg_env); break; case NM_DPSU_H_QBR: check_dsp(ctx); - gen_helper_dpsu_h_qbr(t0, v1, v0, cpu_env); + gen_helper_dpsu_h_qbr(t0, v1, v0, tcg_env); break; case NM_DPSQX_SA_W_PH: check_dsp_r2(ctx); - gen_helper_dpsqx_sa_w_ph(t0, v1, v0, cpu_env); + gen_helper_dpsqx_sa_w_ph(t0, v1, v0, tcg_env); break; case NM_MULSAQ_S_W_PH: check_dsp(ctx); - gen_helper_mulsaq_s_w_ph(t0, v1, v0, cpu_env); + gen_helper_mulsaq_s_w_ph(t0, v1, v0, tcg_env); break; default: gen_reserved_instruction(ctx); @@ -1849,7 +1849,7 @@ static void gen_pool32axf_2_nanomips_insn(DisasContext *ctx, uint32_t opc, check_dsp(ctx); gen_load_gpr(v1_t, rs); tcg_gen_movi_tl(t0, rd >> 3); - gen_helper_extr_w(t0, t0, v1_t, cpu_env); + gen_helper_extr_w(t0, t0, v1_t, tcg_env); gen_store_gpr(t0, ret); break; } @@ -1904,7 +1904,7 @@ static void gen_pool32axf_2_nanomips_insn(DisasContext *ctx, uint32_t opc, case NM_EXTRV_R_W: check_dsp(ctx); tcg_gen_movi_tl(t0, rd >> 3); - gen_helper_extr_r_w(t0, t0, v1_t, cpu_env); + gen_helper_extr_r_w(t0, t0, v1_t, tcg_env); gen_store_gpr(t0, ret); break; default: @@ -1924,7 +1924,7 @@ static void gen_pool32axf_2_nanomips_insn(DisasContext *ctx, uint32_t opc, case NM_EXTPV: check_dsp(ctx); tcg_gen_movi_tl(t0, rd >> 3); - gen_helper_extp(t0, t0, v1_t, cpu_env); + gen_helper_extp(t0, t0, v1_t, tcg_env); gen_store_gpr(t0, ret); break; case NM_MSUB: @@ -1948,7 +1948,7 @@ static void gen_pool32axf_2_nanomips_insn(DisasContext *ctx, uint32_t opc, case NM_EXTRV_RS_W: check_dsp(ctx); tcg_gen_movi_tl(t0, rd >> 3); - gen_helper_extr_rs_w(t0, t0, v1_t, cpu_env); + gen_helper_extr_rs_w(t0, t0, v1_t, tcg_env); gen_store_gpr(t0, ret); break; } @@ -1965,7 +1965,7 @@ static void gen_pool32axf_2_nanomips_insn(DisasContext *ctx, uint32_t opc, case NM_EXTPDPV: check_dsp(ctx); tcg_gen_movi_tl(t0, rd >> 3); - gen_helper_extpdp(t0, t0, v1_t, cpu_env); + gen_helper_extpdp(t0, t0, v1_t, tcg_env); gen_store_gpr(t0, ret); break; case NM_MSUBU: @@ -1991,7 +1991,7 @@ static void gen_pool32axf_2_nanomips_insn(DisasContext *ctx, uint32_t opc, case NM_EXTRV_S_H: check_dsp(ctx); tcg_gen_movi_tl(t0, rd >> 3); - gen_helper_extr_s_h(t0, t0, v1_t, cpu_env); + gen_helper_extr_s_h(t0, t0, v1_t, tcg_env); gen_store_gpr(t0, ret); break; } @@ -2014,17 +2014,17 @@ static void gen_pool32axf_4_nanomips_insn(DisasContext *ctx, uint32_t opc, switch (opc) { case NM_ABSQ_S_QB: check_dsp_r2(ctx); - gen_helper_absq_s_qb(v0_t, v0_t, cpu_env); + gen_helper_absq_s_qb(v0_t, v0_t, tcg_env); gen_store_gpr(v0_t, ret); break; case NM_ABSQ_S_PH: check_dsp(ctx); - gen_helper_absq_s_ph(v0_t, v0_t, cpu_env); + gen_helper_absq_s_ph(v0_t, v0_t, tcg_env); gen_store_gpr(v0_t, ret); break; case NM_ABSQ_S_W: check_dsp(ctx); - gen_helper_absq_s_w(v0_t, v0_t, cpu_env); + gen_helper_absq_s_w(v0_t, v0_t, tcg_env); gen_store_gpr(v0_t, ret); break; case NM_PRECEQ_W_PHL: @@ -2109,7 +2109,7 @@ static void gen_pool32axf_4_nanomips_insn(DisasContext *ctx, uint32_t opc, TCGv tv0 = tcg_temp_new(); gen_load_gpr(tv0, rt); - gen_helper_insv(v0_t, cpu_env, v0_t, tv0); + gen_helper_insv(v0_t, tcg_env, v0_t, tv0); gen_store_gpr(v0_t, ret); } break; @@ -2243,7 +2243,7 @@ static void gen_pool32axf_nanomips_insn(CPUMIPSState *env, DisasContext *ctx) TCGv t0 = tcg_temp_new(); save_cpu_state(ctx, 1); - gen_helper_di(t0, cpu_env); + gen_helper_di(t0, tcg_env); gen_store_gpr(t0, rt); /* Stop translation as we may have switched the execution mode */ ctx->base.is_jmp = DISAS_STOP; @@ -2255,7 +2255,7 @@ static void gen_pool32axf_nanomips_insn(CPUMIPSState *env, DisasContext *ctx) TCGv t0 = tcg_temp_new(); save_cpu_state(ctx, 1); - gen_helper_ei(t0, cpu_env); + gen_helper_ei(t0, tcg_env); gen_store_gpr(t0, rt); /* Stop translation as we may have switched the execution mode */ ctx->base.is_jmp = DISAS_STOP; @@ -3036,27 +3036,27 @@ static void gen_pool32a5_nanomips_insn(DisasContext *ctx, int opc, switch (opc) { case NM_CMP_EQ_PH: check_dsp(ctx); - gen_helper_cmp_eq_ph(v1_t, v2_t, cpu_env); + gen_helper_cmp_eq_ph(v1_t, v2_t, tcg_env); break; case NM_CMP_LT_PH: check_dsp(ctx); - gen_helper_cmp_lt_ph(v1_t, v2_t, cpu_env); + gen_helper_cmp_lt_ph(v1_t, v2_t, tcg_env); break; case NM_CMP_LE_PH: check_dsp(ctx); - gen_helper_cmp_le_ph(v1_t, v2_t, cpu_env); + gen_helper_cmp_le_ph(v1_t, v2_t, tcg_env); break; case NM_CMPU_EQ_QB: check_dsp(ctx); - gen_helper_cmpu_eq_qb(v1_t, v2_t, cpu_env); + gen_helper_cmpu_eq_qb(v1_t, v2_t, tcg_env); break; case NM_CMPU_LT_QB: check_dsp(ctx); - gen_helper_cmpu_lt_qb(v1_t, v2_t, cpu_env); + gen_helper_cmpu_lt_qb(v1_t, v2_t, tcg_env); break; case NM_CMPU_LE_QB: check_dsp(ctx); - gen_helper_cmpu_le_qb(v1_t, v2_t, cpu_env); + gen_helper_cmpu_le_qb(v1_t, v2_t, tcg_env); break; case NM_CMPGU_EQ_QB: check_dsp(ctx); @@ -3098,32 +3098,32 @@ static void gen_pool32a5_nanomips_insn(DisasContext *ctx, int opc, break; case NM_PICK_QB: check_dsp(ctx); - gen_helper_pick_qb(v1_t, v1_t, v2_t, cpu_env); + gen_helper_pick_qb(v1_t, v1_t, v2_t, tcg_env); gen_store_gpr(v1_t, ret); break; case NM_PICK_PH: check_dsp(ctx); - gen_helper_pick_ph(v1_t, v1_t, v2_t, cpu_env); + gen_helper_pick_ph(v1_t, v1_t, v2_t, tcg_env); gen_store_gpr(v1_t, ret); break; case NM_ADDQ_S_W: check_dsp(ctx); - gen_helper_addq_s_w(v1_t, v1_t, v2_t, cpu_env); + gen_helper_addq_s_w(v1_t, v1_t, v2_t, tcg_env); gen_store_gpr(v1_t, ret); break; case NM_SUBQ_S_W: check_dsp(ctx); - gen_helper_subq_s_w(v1_t, v1_t, v2_t, cpu_env); + gen_helper_subq_s_w(v1_t, v1_t, v2_t, tcg_env); gen_store_gpr(v1_t, ret); break; case NM_ADDSC: check_dsp(ctx); - gen_helper_addsc(v1_t, v1_t, v2_t, cpu_env); + gen_helper_addsc(v1_t, v1_t, v2_t, tcg_env); gen_store_gpr(v1_t, ret); break; case NM_ADDWC: check_dsp(ctx); - gen_helper_addwc(v1_t, v1_t, v2_t, cpu_env); + gen_helper_addwc(v1_t, v1_t, v2_t, tcg_env); gen_store_gpr(v1_t, ret); break; case NM_ADDQ_S_PH: @@ -3131,12 +3131,12 @@ static void gen_pool32a5_nanomips_insn(DisasContext *ctx, int opc, switch (extract32(ctx->opcode, 10, 1)) { case 0: /* ADDQ_PH */ - gen_helper_addq_ph(v1_t, v1_t, v2_t, cpu_env); + gen_helper_addq_ph(v1_t, v1_t, v2_t, tcg_env); gen_store_gpr(v1_t, ret); break; case 1: /* ADDQ_S_PH */ - gen_helper_addq_s_ph(v1_t, v1_t, v2_t, cpu_env); + gen_helper_addq_s_ph(v1_t, v1_t, v2_t, tcg_env); gen_store_gpr(v1_t, ret); break; } @@ -3176,12 +3176,12 @@ static void gen_pool32a5_nanomips_insn(DisasContext *ctx, int opc, switch (extract32(ctx->opcode, 10, 1)) { case 0: /* ADDU_QB */ - gen_helper_addu_qb(v1_t, v1_t, v2_t, cpu_env); + gen_helper_addu_qb(v1_t, v1_t, v2_t, tcg_env); gen_store_gpr(v1_t, ret); break; case 1: /* ADDU_S_QB */ - gen_helper_addu_s_qb(v1_t, v1_t, v2_t, cpu_env); + gen_helper_addu_s_qb(v1_t, v1_t, v2_t, tcg_env); gen_store_gpr(v1_t, ret); break; } @@ -3191,12 +3191,12 @@ static void gen_pool32a5_nanomips_insn(DisasContext *ctx, int opc, switch (extract32(ctx->opcode, 10, 1)) { case 0: /* ADDU_PH */ - gen_helper_addu_ph(v1_t, v1_t, v2_t, cpu_env); + gen_helper_addu_ph(v1_t, v1_t, v2_t, tcg_env); gen_store_gpr(v1_t, ret); break; case 1: /* ADDU_S_PH */ - gen_helper_addu_s_ph(v1_t, v1_t, v2_t, cpu_env); + gen_helper_addu_s_ph(v1_t, v1_t, v2_t, tcg_env); gen_store_gpr(v1_t, ret); break; } @@ -3251,12 +3251,12 @@ static void gen_pool32a5_nanomips_insn(DisasContext *ctx, int opc, switch (extract32(ctx->opcode, 10, 1)) { case 0: /* SUBQ_PH */ - gen_helper_subq_ph(v1_t, v1_t, v2_t, cpu_env); + gen_helper_subq_ph(v1_t, v1_t, v2_t, tcg_env); gen_store_gpr(v1_t, ret); break; case 1: /* SUBQ_S_PH */ - gen_helper_subq_s_ph(v1_t, v1_t, v2_t, cpu_env); + gen_helper_subq_s_ph(v1_t, v1_t, v2_t, tcg_env); gen_store_gpr(v1_t, ret); break; } @@ -3296,12 +3296,12 @@ static void gen_pool32a5_nanomips_insn(DisasContext *ctx, int opc, switch (extract32(ctx->opcode, 10, 1)) { case 0: /* SUBU_QB */ - gen_helper_subu_qb(v1_t, v1_t, v2_t, cpu_env); + gen_helper_subu_qb(v1_t, v1_t, v2_t, tcg_env); gen_store_gpr(v1_t, ret); break; case 1: /* SUBU_S_QB */ - gen_helper_subu_s_qb(v1_t, v1_t, v2_t, cpu_env); + gen_helper_subu_s_qb(v1_t, v1_t, v2_t, tcg_env); gen_store_gpr(v1_t, ret); break; } @@ -3311,12 +3311,12 @@ static void gen_pool32a5_nanomips_insn(DisasContext *ctx, int opc, switch (extract32(ctx->opcode, 10, 1)) { case 0: /* SUBU_PH */ - gen_helper_subu_ph(v1_t, v1_t, v2_t, cpu_env); + gen_helper_subu_ph(v1_t, v1_t, v2_t, tcg_env); gen_store_gpr(v1_t, ret); break; case 1: /* SUBU_S_PH */ - gen_helper_subu_s_ph(v1_t, v1_t, v2_t, cpu_env); + gen_helper_subu_s_ph(v1_t, v1_t, v2_t, tcg_env); gen_store_gpr(v1_t, ret); break; } @@ -3341,12 +3341,12 @@ static void gen_pool32a5_nanomips_insn(DisasContext *ctx, int opc, switch (extract32(ctx->opcode, 10, 1)) { case 0: /* SHLLV_PH */ - gen_helper_shll_ph(v1_t, v1_t, v2_t, cpu_env); + gen_helper_shll_ph(v1_t, v1_t, v2_t, tcg_env); gen_store_gpr(v1_t, ret); break; case 1: /* SHLLV_S_PH */ - gen_helper_shll_s_ph(v1_t, v1_t, v2_t, cpu_env); + gen_helper_shll_s_ph(v1_t, v1_t, v2_t, tcg_env); gen_store_gpr(v1_t, ret); break; } @@ -3376,32 +3376,32 @@ static void gen_pool32a5_nanomips_insn(DisasContext *ctx, int opc, break; case NM_MULEU_S_PH_QBL: check_dsp(ctx); - gen_helper_muleu_s_ph_qbl(v1_t, v1_t, v2_t, cpu_env); + gen_helper_muleu_s_ph_qbl(v1_t, v1_t, v2_t, tcg_env); gen_store_gpr(v1_t, ret); break; case NM_MULEU_S_PH_QBR: check_dsp(ctx); - gen_helper_muleu_s_ph_qbr(v1_t, v1_t, v2_t, cpu_env); + gen_helper_muleu_s_ph_qbr(v1_t, v1_t, v2_t, tcg_env); gen_store_gpr(v1_t, ret); break; case NM_MULQ_RS_PH: check_dsp(ctx); - gen_helper_mulq_rs_ph(v1_t, v1_t, v2_t, cpu_env); + gen_helper_mulq_rs_ph(v1_t, v1_t, v2_t, tcg_env); gen_store_gpr(v1_t, ret); break; case NM_MULQ_S_PH: check_dsp_r2(ctx); - gen_helper_mulq_s_ph(v1_t, v1_t, v2_t, cpu_env); + gen_helper_mulq_s_ph(v1_t, v1_t, v2_t, tcg_env); gen_store_gpr(v1_t, ret); break; case NM_MULQ_RS_W: check_dsp_r2(ctx); - gen_helper_mulq_rs_w(v1_t, v1_t, v2_t, cpu_env); + gen_helper_mulq_rs_w(v1_t, v1_t, v2_t, tcg_env); gen_store_gpr(v1_t, ret); break; case NM_MULQ_S_W: check_dsp_r2(ctx); - gen_helper_mulq_s_w(v1_t, v1_t, v2_t, cpu_env); + gen_helper_mulq_s_w(v1_t, v1_t, v2_t, tcg_env); gen_store_gpr(v1_t, ret); break; case NM_APPEND: @@ -3434,12 +3434,12 @@ static void gen_pool32a5_nanomips_insn(DisasContext *ctx, int opc, break; case NM_SHLLV_QB: check_dsp(ctx); - gen_helper_shll_qb(v1_t, v1_t, v2_t, cpu_env); + gen_helper_shll_qb(v1_t, v1_t, v2_t, tcg_env); gen_store_gpr(v1_t, ret); break; case NM_SHLLV_S_W: check_dsp(ctx); - gen_helper_shll_s_w(v1_t, v1_t, v2_t, cpu_env); + gen_helper_shll_s_w(v1_t, v1_t, v2_t, tcg_env); gen_store_gpr(v1_t, ret); break; case NM_SHILO: @@ -3451,17 +3451,17 @@ static void gen_pool32a5_nanomips_insn(DisasContext *ctx, int opc, tcg_gen_movi_tl(tv0, rd >> 3); tcg_gen_movi_tl(tv1, imm); - gen_helper_shilo(tv0, tv1, cpu_env); + gen_helper_shilo(tv0, tv1, tcg_env); } break; case NM_MULEQ_S_W_PHL: check_dsp(ctx); - gen_helper_muleq_s_w_phl(v1_t, v1_t, v2_t, cpu_env); + gen_helper_muleq_s_w_phl(v1_t, v1_t, v2_t, tcg_env); gen_store_gpr(v1_t, ret); break; case NM_MULEQ_S_W_PHR: check_dsp(ctx); - gen_helper_muleq_s_w_phr(v1_t, v1_t, v2_t, cpu_env); + gen_helper_muleq_s_w_phr(v1_t, v1_t, v2_t, tcg_env); gen_store_gpr(v1_t, ret); break; case NM_MUL_S_PH: @@ -3469,12 +3469,12 @@ static void gen_pool32a5_nanomips_insn(DisasContext *ctx, int opc, switch (extract32(ctx->opcode, 10, 1)) { case 0: /* MUL_PH */ - gen_helper_mul_ph(v1_t, v1_t, v2_t, cpu_env); + gen_helper_mul_ph(v1_t, v1_t, v2_t, tcg_env); gen_store_gpr(v1_t, ret); break; case 1: /* MUL_S_PH */ - gen_helper_mul_s_ph(v1_t, v1_t, v2_t, cpu_env); + gen_helper_mul_s_ph(v1_t, v1_t, v2_t, tcg_env); gen_store_gpr(v1_t, ret); break; } @@ -3496,12 +3496,12 @@ static void gen_pool32a5_nanomips_insn(DisasContext *ctx, int opc, break; case NM_PRECRQ_RS_PH_W: check_dsp(ctx); - gen_helper_precrq_rs_ph_w(v1_t, v1_t, v2_t, cpu_env); + gen_helper_precrq_rs_ph_w(v1_t, v1_t, v2_t, tcg_env); gen_store_gpr(v1_t, ret); break; case NM_PRECRQU_S_QB_PH: check_dsp(ctx); - gen_helper_precrqu_s_qb_ph(v1_t, v1_t, v2_t, cpu_env); + gen_helper_precrqu_s_qb_ph(v1_t, v1_t, v2_t, tcg_env); gen_store_gpr(v1_t, ret); break; case NM_SHRA_R_W: @@ -3532,12 +3532,12 @@ static void gen_pool32a5_nanomips_insn(DisasContext *ctx, int opc, switch (extract32(ctx->opcode, 10, 2)) { case 0: /* SHLL_PH */ - gen_helper_shll_ph(v1_t, t0, v1_t, cpu_env); + gen_helper_shll_ph(v1_t, t0, v1_t, tcg_env); gen_store_gpr(v1_t, rt); break; case 2: /* SHLL_S_PH */ - gen_helper_shll_s_ph(v1_t, t0, v1_t, cpu_env); + gen_helper_shll_s_ph(v1_t, t0, v1_t, tcg_env); gen_store_gpr(v1_t, rt); break; default: @@ -3548,7 +3548,7 @@ static void gen_pool32a5_nanomips_insn(DisasContext *ctx, int opc, case NM_SHLL_S_W: check_dsp(ctx); tcg_gen_movi_tl(t0, rd); - gen_helper_shll_s_w(v1_t, t0, v1_t, cpu_env); + gen_helper_shll_s_w(v1_t, t0, v1_t, tcg_env); gen_store_gpr(v1_t, rt); break; case NM_REPL_PH: @@ -4503,7 +4503,7 @@ static int decode_isa_nanomips(CPUMIPSState *env, DisasContext *ctx) /* make sure instructions are on a halfword boundary */ if (ctx->base.pc_next & 0x1) { TCGv tmp = tcg_constant_tl(ctx->base.pc_next); - tcg_gen_st_tl(tmp, cpu_env, offsetof(CPUMIPSState, CP0_BadVAddr)); + tcg_gen_st_tl(tmp, tcg_env, offsetof(CPUMIPSState, CP0_BadVAddr)); generate_exception_end(ctx, EXCP_AdEL); return 2; } diff --git a/target/mips/tcg/translate.c b/target/mips/tcg/translate.c index 87e1e0727e..6d5a552b2e 100644 --- a/target/mips/tcg/translate.c +++ b/target/mips/tcg/translate.c @@ -1268,12 +1268,12 @@ static inline void gen_load_srsgpr(int from, int to) TCGv_i32 t2 = tcg_temp_new_i32(); TCGv_ptr addr = tcg_temp_new_ptr(); - tcg_gen_ld_i32(t2, cpu_env, offsetof(CPUMIPSState, CP0_SRSCtl)); + tcg_gen_ld_i32(t2, tcg_env, offsetof(CPUMIPSState, CP0_SRSCtl)); tcg_gen_shri_i32(t2, t2, CP0SRSCtl_PSS); tcg_gen_andi_i32(t2, t2, 0xf); tcg_gen_muli_i32(t2, t2, sizeof(target_ulong) * 32); tcg_gen_ext_i32_ptr(addr, t2); - tcg_gen_add_ptr(addr, cpu_env, addr); + tcg_gen_add_ptr(addr, tcg_env, addr); tcg_gen_ld_tl(t0, addr, sizeof(target_ulong) * from); } @@ -1288,12 +1288,12 @@ static inline void gen_store_srsgpr(int from, int to) TCGv_ptr addr = tcg_temp_new_ptr(); gen_load_gpr(t0, from); - tcg_gen_ld_i32(t2, cpu_env, offsetof(CPUMIPSState, CP0_SRSCtl)); + tcg_gen_ld_i32(t2, tcg_env, offsetof(CPUMIPSState, CP0_SRSCtl)); tcg_gen_shri_i32(t2, t2, CP0SRSCtl_PSS); tcg_gen_andi_i32(t2, t2, 0xf); tcg_gen_muli_i32(t2, t2, sizeof(target_ulong) * 32); tcg_gen_ext_i32_ptr(addr, t2); - tcg_gen_add_ptr(addr, cpu_env, addr); + tcg_gen_add_ptr(addr, tcg_env, addr); tcg_gen_st_tl(t0, addr, sizeof(target_ulong) * to); } @@ -1344,14 +1344,14 @@ static inline void restore_cpu_state(CPUMIPSState *env, DisasContext *ctx) void generate_exception_err(DisasContext *ctx, int excp, int err) { save_cpu_state(ctx, 1); - gen_helper_raise_exception_err(cpu_env, tcg_constant_i32(excp), + gen_helper_raise_exception_err(tcg_env, tcg_constant_i32(excp), tcg_constant_i32(err)); ctx->base.is_jmp = DISAS_NORETURN; } void generate_exception(DisasContext *ctx, int excp) { - gen_helper_raise_exception(cpu_env, tcg_constant_i32(excp)); + gen_helper_raise_exception(tcg_env, tcg_constant_i32(excp)); } void generate_exception_end(DisasContext *ctx, int excp) @@ -1363,7 +1363,7 @@ void generate_exception_break(DisasContext *ctx, int code) { #ifdef CONFIG_USER_ONLY /* Pass the break code along to cpu_loop. */ - tcg_gen_st_i32(tcg_constant_i32(code), cpu_env, + tcg_gen_st_i32(tcg_constant_i32(code), tcg_env, offsetof(CPUMIPSState, error_code)); #endif generate_exception_end(ctx, EXCP_BREAK); @@ -1868,70 +1868,70 @@ static inline void gen_r6_cmp_ ## fmt(DisasContext *ctx, int n, \ gen_ldcmp_fpr ## bits(ctx, fp1, ft); \ switch (n) { \ case 0: \ - gen_helper_r6_cmp_ ## fmt ## _af(fp0, cpu_env, fp0, fp1); \ + gen_helper_r6_cmp_ ## fmt ## _af(fp0, tcg_env, fp0, fp1); \ break; \ case 1: \ - gen_helper_r6_cmp_ ## fmt ## _un(fp0, cpu_env, fp0, fp1); \ + gen_helper_r6_cmp_ ## fmt ## _un(fp0, tcg_env, fp0, fp1); \ break; \ case 2: \ - gen_helper_r6_cmp_ ## fmt ## _eq(fp0, cpu_env, fp0, fp1); \ + gen_helper_r6_cmp_ ## fmt ## _eq(fp0, tcg_env, fp0, fp1); \ break; \ case 3: \ - gen_helper_r6_cmp_ ## fmt ## _ueq(fp0, cpu_env, fp0, fp1); \ + gen_helper_r6_cmp_ ## fmt ## _ueq(fp0, tcg_env, fp0, fp1); \ break; \ case 4: \ - gen_helper_r6_cmp_ ## fmt ## _lt(fp0, cpu_env, fp0, fp1); \ + gen_helper_r6_cmp_ ## fmt ## _lt(fp0, tcg_env, fp0, fp1); \ break; \ case 5: \ - gen_helper_r6_cmp_ ## fmt ## _ult(fp0, cpu_env, fp0, fp1); \ + gen_helper_r6_cmp_ ## fmt ## _ult(fp0, tcg_env, fp0, fp1); \ break; \ case 6: \ - gen_helper_r6_cmp_ ## fmt ## _le(fp0, cpu_env, fp0, fp1); \ + gen_helper_r6_cmp_ ## fmt ## _le(fp0, tcg_env, fp0, fp1); \ break; \ case 7: \ - gen_helper_r6_cmp_ ## fmt ## _ule(fp0, cpu_env, fp0, fp1); \ + gen_helper_r6_cmp_ ## fmt ## _ule(fp0, tcg_env, fp0, fp1); \ break; \ case 8: \ - gen_helper_r6_cmp_ ## fmt ## _saf(fp0, cpu_env, fp0, fp1); \ + gen_helper_r6_cmp_ ## fmt ## _saf(fp0, tcg_env, fp0, fp1); \ break; \ case 9: \ - gen_helper_r6_cmp_ ## fmt ## _sun(fp0, cpu_env, fp0, fp1); \ + gen_helper_r6_cmp_ ## fmt ## _sun(fp0, tcg_env, fp0, fp1); \ break; \ case 10: \ - gen_helper_r6_cmp_ ## fmt ## _seq(fp0, cpu_env, fp0, fp1); \ + gen_helper_r6_cmp_ ## fmt ## _seq(fp0, tcg_env, fp0, fp1); \ break; \ case 11: \ - gen_helper_r6_cmp_ ## fmt ## _sueq(fp0, cpu_env, fp0, fp1); \ + gen_helper_r6_cmp_ ## fmt ## _sueq(fp0, tcg_env, fp0, fp1); \ break; \ case 12: \ - gen_helper_r6_cmp_ ## fmt ## _slt(fp0, cpu_env, fp0, fp1); \ + gen_helper_r6_cmp_ ## fmt ## _slt(fp0, tcg_env, fp0, fp1); \ break; \ case 13: \ - gen_helper_r6_cmp_ ## fmt ## _sult(fp0, cpu_env, fp0, fp1); \ + gen_helper_r6_cmp_ ## fmt ## _sult(fp0, tcg_env, fp0, fp1); \ break; \ case 14: \ - gen_helper_r6_cmp_ ## fmt ## _sle(fp0, cpu_env, fp0, fp1); \ + gen_helper_r6_cmp_ ## fmt ## _sle(fp0, tcg_env, fp0, fp1); \ break; \ case 15: \ - gen_helper_r6_cmp_ ## fmt ## _sule(fp0, cpu_env, fp0, fp1); \ + gen_helper_r6_cmp_ ## fmt ## _sule(fp0, tcg_env, fp0, fp1); \ break; \ case 17: \ - gen_helper_r6_cmp_ ## fmt ## _or(fp0, cpu_env, fp0, fp1); \ + gen_helper_r6_cmp_ ## fmt ## _or(fp0, tcg_env, fp0, fp1); \ break; \ case 18: \ - gen_helper_r6_cmp_ ## fmt ## _une(fp0, cpu_env, fp0, fp1); \ + gen_helper_r6_cmp_ ## fmt ## _une(fp0, tcg_env, fp0, fp1); \ break; \ case 19: \ - gen_helper_r6_cmp_ ## fmt ## _ne(fp0, cpu_env, fp0, fp1); \ + gen_helper_r6_cmp_ ## fmt ## _ne(fp0, tcg_env, fp0, fp1); \ break; \ case 25: \ - gen_helper_r6_cmp_ ## fmt ## _sor(fp0, cpu_env, fp0, fp1); \ + gen_helper_r6_cmp_ ## fmt ## _sor(fp0, tcg_env, fp0, fp1); \ break; \ case 26: \ - gen_helper_r6_cmp_ ## fmt ## _sune(fp0, cpu_env, fp0, fp1); \ + gen_helper_r6_cmp_ ## fmt ## _sune(fp0, tcg_env, fp0, fp1); \ break; \ case 27: \ - gen_helper_r6_cmp_ ## fmt ## _sne(fp0, cpu_env, fp0, fp1); \ + gen_helper_r6_cmp_ ## fmt ## _sne(fp0, tcg_env, fp0, fp1); \ break; \ default: \ abort(); \ @@ -1954,15 +1954,15 @@ static inline void op_ld_##insn(TCGv ret, TCGv arg1, int mem_idx, \ TCGv t0 = tcg_temp_new(); \ tcg_gen_mov_tl(t0, arg1); \ tcg_gen_qemu_ld_tl(ret, arg1, ctx->mem_idx, memop); \ - tcg_gen_st_tl(t0, cpu_env, offsetof(CPUMIPSState, lladdr)); \ - tcg_gen_st_tl(ret, cpu_env, offsetof(CPUMIPSState, llval)); \ + tcg_gen_st_tl(t0, tcg_env, offsetof(CPUMIPSState, lladdr)); \ + tcg_gen_st_tl(ret, tcg_env, offsetof(CPUMIPSState, llval)); \ } #else #define OP_LD_ATOMIC(insn, fname) \ static inline void op_ld_##insn(TCGv ret, TCGv arg1, int mem_idx, \ DisasContext *ctx) \ { \ - gen_helper_##insn(ret, cpu_env, arg1, tcg_constant_i32(mem_idx)); \ + gen_helper_##insn(ret, tcg_env, arg1, tcg_constant_i32(mem_idx)); \ } #endif OP_LD_ATOMIC(ll, MO_TESL); @@ -4499,7 +4499,7 @@ static void gen_trap(DisasContext *ctx, uint32_t opc, /* Always trap */ #ifdef CONFIG_USER_ONLY /* Pass the break code along to cpu_loop. */ - tcg_gen_st_i32(tcg_constant_i32(code), cpu_env, + tcg_gen_st_i32(tcg_constant_i32(code), tcg_env, offsetof(CPUMIPSState, error_code)); #endif generate_exception_end(ctx, EXCP_TRAP); @@ -4544,7 +4544,7 @@ static void gen_trap(DisasContext *ctx, uint32_t opc, } #ifdef CONFIG_USER_ONLY /* Pass the break code along to cpu_loop. */ - tcg_gen_st_i32(tcg_constant_i32(code), cpu_env, + tcg_gen_st_i32(tcg_constant_i32(code), tcg_env, offsetof(CPUMIPSState, error_code)); #endif /* Like save_cpu_state, only don't update saved values. */ @@ -5053,13 +5053,13 @@ static inline void gen_mthc0_entrylo(TCGv arg, target_ulong off) TCGv_i64 t1 = tcg_temp_new_i64(); tcg_gen_ext_tl_i64(t0, arg); - tcg_gen_ld_i64(t1, cpu_env, off); + tcg_gen_ld_i64(t1, tcg_env, off); #if defined(TARGET_MIPS64) tcg_gen_deposit_i64(t1, t1, t0, 30, 32); #else tcg_gen_concat32_i64(t1, t1, t0); #endif - tcg_gen_st_i64(t1, cpu_env, off); + tcg_gen_st_i64(t1, tcg_env, off); } static inline void gen_mthc0_store64(TCGv arg, target_ulong off) @@ -5068,16 +5068,16 @@ static inline void gen_mthc0_store64(TCGv arg, target_ulong off) TCGv_i64 t1 = tcg_temp_new_i64(); tcg_gen_ext_tl_i64(t0, arg); - tcg_gen_ld_i64(t1, cpu_env, off); + tcg_gen_ld_i64(t1, tcg_env, off); tcg_gen_concat32_i64(t1, t1, t0); - tcg_gen_st_i64(t1, cpu_env, off); + tcg_gen_st_i64(t1, tcg_env, off); } static inline void gen_mfhc0_entrylo(TCGv arg, target_ulong off) { TCGv_i64 t0 = tcg_temp_new_i64(); - tcg_gen_ld_i64(t0, cpu_env, off); + tcg_gen_ld_i64(t0, tcg_env, off); #if defined(TARGET_MIPS64) tcg_gen_shri_i64(t0, t0, 30); #else @@ -5090,7 +5090,7 @@ static inline void gen_mfhc0_load64(TCGv arg, target_ulong off, int shift) { TCGv_i64 t0 = tcg_temp_new_i64(); - tcg_gen_ld_i64(t0, cpu_env, off); + tcg_gen_ld_i64(t0, tcg_env, off); tcg_gen_shri_i64(t0, t0, 32 + shift); gen_move_low32(arg, t0); } @@ -5099,13 +5099,13 @@ static inline void gen_mfc0_load32(TCGv arg, target_ulong off) { TCGv_i32 t0 = tcg_temp_new_i32(); - tcg_gen_ld_i32(t0, cpu_env, off); + tcg_gen_ld_i32(t0, tcg_env, off); tcg_gen_ext_i32_tl(arg, t0); } static inline void gen_mfc0_load64(TCGv arg, target_ulong off) { - tcg_gen_ld_tl(arg, cpu_env, off); + tcg_gen_ld_tl(arg, tcg_env, off); tcg_gen_ext32s_tl(arg, arg); } @@ -5114,7 +5114,7 @@ static inline void gen_mtc0_store32(TCGv arg, target_ulong off) TCGv_i32 t0 = tcg_temp_new_i32(); tcg_gen_trunc_tl_i32(t0, arg); - tcg_gen_st_i32(t0, cpu_env, off); + tcg_gen_st_i32(t0, tcg_env, off); } #define CP0_CHECK(c) \ @@ -5155,7 +5155,7 @@ static void gen_mfhc0(DisasContext *ctx, TCGv arg, int reg, int sel) switch (sel) { case CP0_REG09__SAAR: CP0_CHECK(ctx->saar); - gen_helper_mfhc0_saar(arg, cpu_env); + gen_helper_mfhc0_saar(arg, tcg_env); register_name = "SAAR"; break; default: @@ -5171,7 +5171,7 @@ static void gen_mfhc0(DisasContext *ctx, TCGv arg, int reg, int sel) break; case CP0_REG17__MAAR: CP0_CHECK(ctx->mrp); - gen_helper_mfhc0_maar(arg, cpu_env); + gen_helper_mfhc0_maar(arg, tcg_env); register_name = "MAAR"; break; default: @@ -5256,7 +5256,7 @@ static void gen_mthc0(DisasContext *ctx, TCGv arg, int reg, int sel) switch (sel) { case CP0_REG09__SAAR: CP0_CHECK(ctx->saar); - gen_helper_mthc0_saar(cpu_env, arg); + gen_helper_mthc0_saar(tcg_env, arg); register_name = "SAAR"; break; default: @@ -5276,7 +5276,7 @@ static void gen_mthc0(DisasContext *ctx, TCGv arg, int reg, int sel) break; case CP0_REG17__MAAR: CP0_CHECK(ctx->mrp); - gen_helper_mthc0_maar(cpu_env, arg); + gen_helper_mthc0_maar(tcg_env, arg); register_name = "MAAR"; break; default: @@ -5353,17 +5353,17 @@ static void gen_mfc0(DisasContext *ctx, TCGv arg, int reg, int sel) break; case CP0_REG00__MVPCONTROL: CP0_CHECK(ctx->insn_flags & ASE_MT); - gen_helper_mfc0_mvpcontrol(arg, cpu_env); + gen_helper_mfc0_mvpcontrol(arg, tcg_env); register_name = "MVPControl"; break; case CP0_REG00__MVPCONF0: CP0_CHECK(ctx->insn_flags & ASE_MT); - gen_helper_mfc0_mvpconf0(arg, cpu_env); + gen_helper_mfc0_mvpconf0(arg, tcg_env); register_name = "MVPConf0"; break; case CP0_REG00__MVPCONF1: CP0_CHECK(ctx->insn_flags & ASE_MT); - gen_helper_mfc0_mvpconf1(arg, cpu_env); + gen_helper_mfc0_mvpconf1(arg, tcg_env); register_name = "MVPConf1"; break; case CP0_REG00__VPCONTROL: @@ -5379,7 +5379,7 @@ static void gen_mfc0(DisasContext *ctx, TCGv arg, int reg, int sel) switch (sel) { case CP0_REG01__RANDOM: CP0_CHECK(!(ctx->insn_flags & ISA_MIPS_R6)); - gen_helper_mfc0_random(arg, cpu_env); + gen_helper_mfc0_random(arg, tcg_env); register_name = "Random"; break; case CP0_REG01__VPECONTROL: @@ -5426,7 +5426,7 @@ static void gen_mfc0(DisasContext *ctx, TCGv arg, int reg, int sel) case CP0_REG02__ENTRYLO0: { TCGv_i64 tmp = tcg_temp_new_i64(); - tcg_gen_ld_i64(tmp, cpu_env, + tcg_gen_ld_i64(tmp, tcg_env, offsetof(CPUMIPSState, CP0_EntryLo0)); #if defined(TARGET_MIPS64) if (ctx->rxi) { @@ -5441,37 +5441,37 @@ static void gen_mfc0(DisasContext *ctx, TCGv arg, int reg, int sel) break; case CP0_REG02__TCSTATUS: CP0_CHECK(ctx->insn_flags & ASE_MT); - gen_helper_mfc0_tcstatus(arg, cpu_env); + gen_helper_mfc0_tcstatus(arg, tcg_env); register_name = "TCStatus"; break; case CP0_REG02__TCBIND: CP0_CHECK(ctx->insn_flags & ASE_MT); - gen_helper_mfc0_tcbind(arg, cpu_env); + gen_helper_mfc0_tcbind(arg, tcg_env); register_name = "TCBind"; break; case CP0_REG02__TCRESTART: CP0_CHECK(ctx->insn_flags & ASE_MT); - gen_helper_mfc0_tcrestart(arg, cpu_env); + gen_helper_mfc0_tcrestart(arg, tcg_env); register_name = "TCRestart"; break; case CP0_REG02__TCHALT: CP0_CHECK(ctx->insn_flags & ASE_MT); - gen_helper_mfc0_tchalt(arg, cpu_env); + gen_helper_mfc0_tchalt(arg, tcg_env); register_name = "TCHalt"; break; case CP0_REG02__TCCONTEXT: CP0_CHECK(ctx->insn_flags & ASE_MT); - gen_helper_mfc0_tccontext(arg, cpu_env); + gen_helper_mfc0_tccontext(arg, tcg_env); register_name = "TCContext"; break; case CP0_REG02__TCSCHEDULE: CP0_CHECK(ctx->insn_flags & ASE_MT); - gen_helper_mfc0_tcschedule(arg, cpu_env); + gen_helper_mfc0_tcschedule(arg, tcg_env); register_name = "TCSchedule"; break; case CP0_REG02__TCSCHEFBACK: CP0_CHECK(ctx->insn_flags & ASE_MT); - gen_helper_mfc0_tcschefback(arg, cpu_env); + gen_helper_mfc0_tcschefback(arg, tcg_env); register_name = "TCScheFBack"; break; default: @@ -5483,7 +5483,7 @@ static void gen_mfc0(DisasContext *ctx, TCGv arg, int reg, int sel) case CP0_REG03__ENTRYLO1: { TCGv_i64 tmp = tcg_temp_new_i64(); - tcg_gen_ld_i64(tmp, cpu_env, + tcg_gen_ld_i64(tmp, tcg_env, offsetof(CPUMIPSState, CP0_EntryLo1)); #if defined(TARGET_MIPS64) if (ctx->rxi) { @@ -5508,7 +5508,7 @@ static void gen_mfc0(DisasContext *ctx, TCGv arg, int reg, int sel) case CP0_REGISTER_04: switch (sel) { case CP0_REG04__CONTEXT: - tcg_gen_ld_tl(arg, cpu_env, offsetof(CPUMIPSState, CP0_Context)); + tcg_gen_ld_tl(arg, tcg_env, offsetof(CPUMIPSState, CP0_Context)); tcg_gen_ext32s_tl(arg, arg); register_name = "Context"; break; @@ -5519,14 +5519,14 @@ static void gen_mfc0(DisasContext *ctx, TCGv arg, int reg, int sel) goto cp0_unimplemented; case CP0_REG04__USERLOCAL: CP0_CHECK(ctx->ulri); - tcg_gen_ld_tl(arg, cpu_env, + tcg_gen_ld_tl(arg, tcg_env, offsetof(CPUMIPSState, active_tc.CP0_UserLocal)); tcg_gen_ext32s_tl(arg, arg); register_name = "UserLocal"; break; case CP0_REG04__MMID: CP0_CHECK(ctx->mi); - gen_helper_mtc0_memorymapid(cpu_env, arg); + gen_helper_mtc0_memorymapid(tcg_env, arg); register_name = "MMID"; break; default: @@ -5546,19 +5546,19 @@ static void gen_mfc0(DisasContext *ctx, TCGv arg, int reg, int sel) break; case CP0_REG05__SEGCTL0: CP0_CHECK(ctx->sc); - tcg_gen_ld_tl(arg, cpu_env, offsetof(CPUMIPSState, CP0_SegCtl0)); + tcg_gen_ld_tl(arg, tcg_env, offsetof(CPUMIPSState, CP0_SegCtl0)); tcg_gen_ext32s_tl(arg, arg); register_name = "SegCtl0"; break; case CP0_REG05__SEGCTL1: CP0_CHECK(ctx->sc); - tcg_gen_ld_tl(arg, cpu_env, offsetof(CPUMIPSState, CP0_SegCtl1)); + tcg_gen_ld_tl(arg, tcg_env, offsetof(CPUMIPSState, CP0_SegCtl1)); tcg_gen_ext32s_tl(arg, arg); register_name = "SegCtl1"; break; case CP0_REG05__SEGCTL2: CP0_CHECK(ctx->sc); - tcg_gen_ld_tl(arg, cpu_env, offsetof(CPUMIPSState, CP0_SegCtl2)); + tcg_gen_ld_tl(arg, tcg_env, offsetof(CPUMIPSState, CP0_SegCtl2)); tcg_gen_ext32s_tl(arg, arg); register_name = "SegCtl2"; break; @@ -5635,7 +5635,7 @@ static void gen_mfc0(DisasContext *ctx, TCGv arg, int reg, int sel) case CP0_REGISTER_08: switch (sel) { case CP0_REG08__BADVADDR: - tcg_gen_ld_tl(arg, cpu_env, offsetof(CPUMIPSState, CP0_BadVAddr)); + tcg_gen_ld_tl(arg, tcg_env, offsetof(CPUMIPSState, CP0_BadVAddr)); tcg_gen_ext32s_tl(arg, arg); register_name = "BadVAddr"; break; @@ -5665,7 +5665,7 @@ static void gen_mfc0(DisasContext *ctx, TCGv arg, int reg, int sel) /* Mark as an IO operation because we read the time. */ translator_io_start(&ctx->base); - gen_helper_mfc0_count(arg, cpu_env); + gen_helper_mfc0_count(arg, tcg_env); /* * Break the TB to be able to take timer interrupts immediately * after reading count. DISAS_STOP isn't sufficient, we need to @@ -5682,7 +5682,7 @@ static void gen_mfc0(DisasContext *ctx, TCGv arg, int reg, int sel) break; case CP0_REG09__SAAR: CP0_CHECK(ctx->saar); - gen_helper_mfc0_saar(arg, cpu_env); + gen_helper_mfc0_saar(arg, tcg_env); register_name = "SAAR"; break; default: @@ -5692,7 +5692,7 @@ static void gen_mfc0(DisasContext *ctx, TCGv arg, int reg, int sel) case CP0_REGISTER_10: switch (sel) { case CP0_REG10__ENTRYHI: - tcg_gen_ld_tl(arg, cpu_env, offsetof(CPUMIPSState, CP0_EntryHi)); + tcg_gen_ld_tl(arg, tcg_env, offsetof(CPUMIPSState, CP0_EntryHi)); tcg_gen_ext32s_tl(arg, arg); register_name = "EntryHi"; break; @@ -5749,7 +5749,7 @@ static void gen_mfc0(DisasContext *ctx, TCGv arg, int reg, int sel) case CP0_REGISTER_14: switch (sel) { case CP0_REG14__EPC: - tcg_gen_ld_tl(arg, cpu_env, offsetof(CPUMIPSState, CP0_EPC)); + tcg_gen_ld_tl(arg, tcg_env, offsetof(CPUMIPSState, CP0_EPC)); tcg_gen_ext32s_tl(arg, arg); register_name = "EPC"; break; @@ -5765,14 +5765,14 @@ static void gen_mfc0(DisasContext *ctx, TCGv arg, int reg, int sel) break; case CP0_REG15__EBASE: check_insn(ctx, ISA_MIPS_R2); - tcg_gen_ld_tl(arg, cpu_env, offsetof(CPUMIPSState, CP0_EBase)); + tcg_gen_ld_tl(arg, tcg_env, offsetof(CPUMIPSState, CP0_EBase)); tcg_gen_ext32s_tl(arg, arg); register_name = "EBase"; break; case CP0_REG15__CMGCRBASE: check_insn(ctx, ISA_MIPS_R2); CP0_CHECK(ctx->cmgcr); - tcg_gen_ld_tl(arg, cpu_env, offsetof(CPUMIPSState, CP0_CMGCRBase)); + tcg_gen_ld_tl(arg, tcg_env, offsetof(CPUMIPSState, CP0_CMGCRBase)); tcg_gen_ext32s_tl(arg, arg); register_name = "CMGCRBase"; break; @@ -5822,12 +5822,12 @@ static void gen_mfc0(DisasContext *ctx, TCGv arg, int reg, int sel) case CP0_REGISTER_17: switch (sel) { case CP0_REG17__LLADDR: - gen_helper_mfc0_lladdr(arg, cpu_env); + gen_helper_mfc0_lladdr(arg, tcg_env); register_name = "LLAddr"; break; case CP0_REG17__MAAR: CP0_CHECK(ctx->mrp); - gen_helper_mfc0_maar(arg, cpu_env); + gen_helper_mfc0_maar(arg, tcg_env); register_name = "MAAR"; break; case CP0_REG17__MAARI: @@ -5880,7 +5880,7 @@ static void gen_mfc0(DisasContext *ctx, TCGv arg, int reg, int sel) case CP0_REG20__XCONTEXT: #if defined(TARGET_MIPS64) check_insn(ctx, ISA_MIPS3); - tcg_gen_ld_tl(arg, cpu_env, offsetof(CPUMIPSState, CP0_XContext)); + tcg_gen_ld_tl(arg, tcg_env, offsetof(CPUMIPSState, CP0_XContext)); tcg_gen_ext32s_tl(arg, arg); register_name = "XContext"; break; @@ -5908,7 +5908,7 @@ static void gen_mfc0(DisasContext *ctx, TCGv arg, int reg, int sel) case CP0_REGISTER_23: switch (sel) { case CP0_REG23__DEBUG: - gen_helper_mfc0_debug(arg, cpu_env); /* EJTAG support */ + gen_helper_mfc0_debug(arg, tcg_env); /* EJTAG support */ register_name = "Debug"; break; case CP0_REG23__TRACECONTROL: @@ -5944,7 +5944,7 @@ static void gen_mfc0(DisasContext *ctx, TCGv arg, int reg, int sel) switch (sel) { case CP0_REG24__DEPC: /* EJTAG support */ - tcg_gen_ld_tl(arg, cpu_env, offsetof(CPUMIPSState, CP0_DEPC)); + tcg_gen_ld_tl(arg, tcg_env, offsetof(CPUMIPSState, CP0_DEPC)); tcg_gen_ext32s_tl(arg, arg); register_name = "DEPC"; break; @@ -6018,7 +6018,7 @@ static void gen_mfc0(DisasContext *ctx, TCGv arg, int reg, int sel) case CP0_REG28__TAGLO3: { TCGv_i64 tmp = tcg_temp_new_i64(); - tcg_gen_ld_i64(tmp, cpu_env, offsetof(CPUMIPSState, CP0_TagLo)); + tcg_gen_ld_i64(tmp, tcg_env, offsetof(CPUMIPSState, CP0_TagLo)); gen_move_low32(arg, tmp); } register_name = "TagLo"; @@ -6057,7 +6057,7 @@ static void gen_mfc0(DisasContext *ctx, TCGv arg, int reg, int sel) case CP0_REGISTER_30: switch (sel) { case CP0_REG30__ERROREPC: - tcg_gen_ld_tl(arg, cpu_env, offsetof(CPUMIPSState, CP0_ErrorEPC)); + tcg_gen_ld_tl(arg, tcg_env, offsetof(CPUMIPSState, CP0_ErrorEPC)); tcg_gen_ext32s_tl(arg, arg); register_name = "ErrorEPC"; break; @@ -6079,7 +6079,7 @@ static void gen_mfc0(DisasContext *ctx, TCGv arg, int reg, int sel) case CP0_REG31__KSCRATCH5: case CP0_REG31__KSCRATCH6: CP0_CHECK(ctx->kscrexist & (1 << sel)); - tcg_gen_ld_tl(arg, cpu_env, + tcg_gen_ld_tl(arg, tcg_env, offsetof(CPUMIPSState, CP0_KScratch[sel - 2])); tcg_gen_ext32s_tl(arg, arg); register_name = "KScratch"; @@ -6115,12 +6115,12 @@ static void gen_mtc0(DisasContext *ctx, TCGv arg, int reg, int sel) case CP0_REGISTER_00: switch (sel) { case CP0_REG00__INDEX: - gen_helper_mtc0_index(cpu_env, arg); + gen_helper_mtc0_index(tcg_env, arg); register_name = "Index"; break; case CP0_REG00__MVPCONTROL: CP0_CHECK(ctx->insn_flags & ASE_MT); - gen_helper_mtc0_mvpcontrol(cpu_env, arg); + gen_helper_mtc0_mvpcontrol(tcg_env, arg); register_name = "MVPControl"; break; case CP0_REG00__MVPCONF0: @@ -6150,39 +6150,39 @@ static void gen_mtc0(DisasContext *ctx, TCGv arg, int reg, int sel) break; case CP0_REG01__VPECONTROL: CP0_CHECK(ctx->insn_flags & ASE_MT); - gen_helper_mtc0_vpecontrol(cpu_env, arg); + gen_helper_mtc0_vpecontrol(tcg_env, arg); register_name = "VPEControl"; break; case CP0_REG01__VPECONF0: CP0_CHECK(ctx->insn_flags & ASE_MT); - gen_helper_mtc0_vpeconf0(cpu_env, arg); + gen_helper_mtc0_vpeconf0(tcg_env, arg); register_name = "VPEConf0"; break; case CP0_REG01__VPECONF1: CP0_CHECK(ctx->insn_flags & ASE_MT); - gen_helper_mtc0_vpeconf1(cpu_env, arg); + gen_helper_mtc0_vpeconf1(tcg_env, arg); register_name = "VPEConf1"; break; case CP0_REG01__YQMASK: CP0_CHECK(ctx->insn_flags & ASE_MT); - gen_helper_mtc0_yqmask(cpu_env, arg); + gen_helper_mtc0_yqmask(tcg_env, arg); register_name = "YQMask"; break; case CP0_REG01__VPESCHEDULE: CP0_CHECK(ctx->insn_flags & ASE_MT); - tcg_gen_st_tl(arg, cpu_env, + tcg_gen_st_tl(arg, tcg_env, offsetof(CPUMIPSState, CP0_VPESchedule)); register_name = "VPESchedule"; break; case CP0_REG01__VPESCHEFBACK: CP0_CHECK(ctx->insn_flags & ASE_MT); - tcg_gen_st_tl(arg, cpu_env, + tcg_gen_st_tl(arg, tcg_env, offsetof(CPUMIPSState, CP0_VPEScheFBack)); register_name = "VPEScheFBack"; break; case CP0_REG01__VPEOPT: CP0_CHECK(ctx->insn_flags & ASE_MT); - gen_helper_mtc0_vpeopt(cpu_env, arg); + gen_helper_mtc0_vpeopt(tcg_env, arg); register_name = "VPEOpt"; break; default: @@ -6192,42 +6192,42 @@ static void gen_mtc0(DisasContext *ctx, TCGv arg, int reg, int sel) case CP0_REGISTER_02: switch (sel) { case CP0_REG02__ENTRYLO0: - gen_helper_mtc0_entrylo0(cpu_env, arg); + gen_helper_mtc0_entrylo0(tcg_env, arg); register_name = "EntryLo0"; break; case CP0_REG02__TCSTATUS: CP0_CHECK(ctx->insn_flags & ASE_MT); - gen_helper_mtc0_tcstatus(cpu_env, arg); + gen_helper_mtc0_tcstatus(tcg_env, arg); register_name = "TCStatus"; break; case CP0_REG02__TCBIND: CP0_CHECK(ctx->insn_flags & ASE_MT); - gen_helper_mtc0_tcbind(cpu_env, arg); + gen_helper_mtc0_tcbind(tcg_env, arg); register_name = "TCBind"; break; case CP0_REG02__TCRESTART: CP0_CHECK(ctx->insn_flags & ASE_MT); - gen_helper_mtc0_tcrestart(cpu_env, arg); + gen_helper_mtc0_tcrestart(tcg_env, arg); register_name = "TCRestart"; break; case CP0_REG02__TCHALT: CP0_CHECK(ctx->insn_flags & ASE_MT); - gen_helper_mtc0_tchalt(cpu_env, arg); + gen_helper_mtc0_tchalt(tcg_env, arg); register_name = "TCHalt"; break; case CP0_REG02__TCCONTEXT: CP0_CHECK(ctx->insn_flags & ASE_MT); - gen_helper_mtc0_tccontext(cpu_env, arg); + gen_helper_mtc0_tccontext(tcg_env, arg); register_name = "TCContext"; break; case CP0_REG02__TCSCHEDULE: CP0_CHECK(ctx->insn_flags & ASE_MT); - gen_helper_mtc0_tcschedule(cpu_env, arg); + gen_helper_mtc0_tcschedule(tcg_env, arg); register_name = "TCSchedule"; break; case CP0_REG02__TCSCHEFBACK: CP0_CHECK(ctx->insn_flags & ASE_MT); - gen_helper_mtc0_tcschefback(cpu_env, arg); + gen_helper_mtc0_tcschefback(tcg_env, arg); register_name = "TCScheFBack"; break; default: @@ -6237,7 +6237,7 @@ static void gen_mtc0(DisasContext *ctx, TCGv arg, int reg, int sel) case CP0_REGISTER_03: switch (sel) { case CP0_REG03__ENTRYLO1: - gen_helper_mtc0_entrylo1(cpu_env, arg); + gen_helper_mtc0_entrylo1(tcg_env, arg); register_name = "EntryLo1"; break; case CP0_REG03__GLOBALNUM: @@ -6252,7 +6252,7 @@ static void gen_mtc0(DisasContext *ctx, TCGv arg, int reg, int sel) case CP0_REGISTER_04: switch (sel) { case CP0_REG04__CONTEXT: - gen_helper_mtc0_context(cpu_env, arg); + gen_helper_mtc0_context(tcg_env, arg); register_name = "Context"; break; case CP0_REG04__CONTEXTCONFIG: @@ -6262,7 +6262,7 @@ static void gen_mtc0(DisasContext *ctx, TCGv arg, int reg, int sel) goto cp0_unimplemented; case CP0_REG04__USERLOCAL: CP0_CHECK(ctx->ulri); - tcg_gen_st_tl(arg, cpu_env, + tcg_gen_st_tl(arg, tcg_env, offsetof(CPUMIPSState, active_tc.CP0_UserLocal)); register_name = "UserLocal"; break; @@ -6278,28 +6278,28 @@ static void gen_mtc0(DisasContext *ctx, TCGv arg, int reg, int sel) case CP0_REGISTER_05: switch (sel) { case CP0_REG05__PAGEMASK: - gen_helper_mtc0_pagemask(cpu_env, arg); + gen_helper_mtc0_pagemask(tcg_env, arg); register_name = "PageMask"; break; case CP0_REG05__PAGEGRAIN: check_insn(ctx, ISA_MIPS_R2); - gen_helper_mtc0_pagegrain(cpu_env, arg); + gen_helper_mtc0_pagegrain(tcg_env, arg); register_name = "PageGrain"; ctx->base.is_jmp = DISAS_STOP; break; case CP0_REG05__SEGCTL0: CP0_CHECK(ctx->sc); - gen_helper_mtc0_segctl0(cpu_env, arg); + gen_helper_mtc0_segctl0(tcg_env, arg); register_name = "SegCtl0"; break; case CP0_REG05__SEGCTL1: CP0_CHECK(ctx->sc); - gen_helper_mtc0_segctl1(cpu_env, arg); + gen_helper_mtc0_segctl1(tcg_env, arg); register_name = "SegCtl1"; break; case CP0_REG05__SEGCTL2: CP0_CHECK(ctx->sc); - gen_helper_mtc0_segctl2(cpu_env, arg); + gen_helper_mtc0_segctl2(tcg_env, arg); register_name = "SegCtl2"; break; case CP0_REG05__PWBASE: @@ -6309,12 +6309,12 @@ static void gen_mtc0(DisasContext *ctx, TCGv arg, int reg, int sel) break; case CP0_REG05__PWFIELD: check_pw(ctx); - gen_helper_mtc0_pwfield(cpu_env, arg); + gen_helper_mtc0_pwfield(tcg_env, arg); register_name = "PWField"; break; case CP0_REG05__PWSIZE: check_pw(ctx); - gen_helper_mtc0_pwsize(cpu_env, arg); + gen_helper_mtc0_pwsize(tcg_env, arg); register_name = "PWSize"; break; default: @@ -6324,37 +6324,37 @@ static void gen_mtc0(DisasContext *ctx, TCGv arg, int reg, int sel) case CP0_REGISTER_06: switch (sel) { case CP0_REG06__WIRED: - gen_helper_mtc0_wired(cpu_env, arg); + gen_helper_mtc0_wired(tcg_env, arg); register_name = "Wired"; break; case CP0_REG06__SRSCONF0: check_insn(ctx, ISA_MIPS_R2); - gen_helper_mtc0_srsconf0(cpu_env, arg); + gen_helper_mtc0_srsconf0(tcg_env, arg); register_name = "SRSConf0"; break; case CP0_REG06__SRSCONF1: check_insn(ctx, ISA_MIPS_R2); - gen_helper_mtc0_srsconf1(cpu_env, arg); + gen_helper_mtc0_srsconf1(tcg_env, arg); register_name = "SRSConf1"; break; case CP0_REG06__SRSCONF2: check_insn(ctx, ISA_MIPS_R2); - gen_helper_mtc0_srsconf2(cpu_env, arg); + gen_helper_mtc0_srsconf2(tcg_env, arg); register_name = "SRSConf2"; break; case CP0_REG06__SRSCONF3: check_insn(ctx, ISA_MIPS_R2); - gen_helper_mtc0_srsconf3(cpu_env, arg); + gen_helper_mtc0_srsconf3(tcg_env, arg); register_name = "SRSConf3"; break; case CP0_REG06__SRSCONF4: check_insn(ctx, ISA_MIPS_R2); - gen_helper_mtc0_srsconf4(cpu_env, arg); + gen_helper_mtc0_srsconf4(tcg_env, arg); register_name = "SRSConf4"; break; case CP0_REG06__PWCTL: check_pw(ctx); - gen_helper_mtc0_pwctl(cpu_env, arg); + gen_helper_mtc0_pwctl(tcg_env, arg); register_name = "PWCtl"; break; default: @@ -6365,7 +6365,7 @@ static void gen_mtc0(DisasContext *ctx, TCGv arg, int reg, int sel) switch (sel) { case CP0_REG07__HWRENA: check_insn(ctx, ISA_MIPS_R2); - gen_helper_mtc0_hwrena(cpu_env, arg); + gen_helper_mtc0_hwrena(tcg_env, arg); ctx->base.is_jmp = DISAS_STOP; register_name = "HWREna"; break; @@ -6398,17 +6398,17 @@ static void gen_mtc0(DisasContext *ctx, TCGv arg, int reg, int sel) case CP0_REGISTER_09: switch (sel) { case CP0_REG09__COUNT: - gen_helper_mtc0_count(cpu_env, arg); + gen_helper_mtc0_count(tcg_env, arg); register_name = "Count"; break; case CP0_REG09__SAARI: CP0_CHECK(ctx->saar); - gen_helper_mtc0_saari(cpu_env, arg); + gen_helper_mtc0_saari(tcg_env, arg); register_name = "SAARI"; break; case CP0_REG09__SAAR: CP0_CHECK(ctx->saar); - gen_helper_mtc0_saar(cpu_env, arg); + gen_helper_mtc0_saar(tcg_env, arg); register_name = "SAAR"; break; default: @@ -6418,7 +6418,7 @@ static void gen_mtc0(DisasContext *ctx, TCGv arg, int reg, int sel) case CP0_REGISTER_10: switch (sel) { case CP0_REG10__ENTRYHI: - gen_helper_mtc0_entryhi(cpu_env, arg); + gen_helper_mtc0_entryhi(tcg_env, arg); register_name = "EntryHi"; break; default: @@ -6428,7 +6428,7 @@ static void gen_mtc0(DisasContext *ctx, TCGv arg, int reg, int sel) case CP0_REGISTER_11: switch (sel) { case CP0_REG11__COMPARE: - gen_helper_mtc0_compare(cpu_env, arg); + gen_helper_mtc0_compare(tcg_env, arg); register_name = "Compare"; break; /* 6,7 are implementation dependent */ @@ -6440,7 +6440,7 @@ static void gen_mtc0(DisasContext *ctx, TCGv arg, int reg, int sel) switch (sel) { case CP0_REG12__STATUS: save_cpu_state(ctx, 1); - gen_helper_mtc0_status(cpu_env, arg); + gen_helper_mtc0_status(tcg_env, arg); /* DISAS_STOP isn't good enough here, hflags may have changed. */ gen_save_pc(ctx->base.pc_next + 4); ctx->base.is_jmp = DISAS_EXIT; @@ -6448,14 +6448,14 @@ static void gen_mtc0(DisasContext *ctx, TCGv arg, int reg, int sel) break; case CP0_REG12__INTCTL: check_insn(ctx, ISA_MIPS_R2); - gen_helper_mtc0_intctl(cpu_env, arg); + gen_helper_mtc0_intctl(tcg_env, arg); /* Stop translation as we may have switched the execution mode */ ctx->base.is_jmp = DISAS_STOP; register_name = "IntCtl"; break; case CP0_REG12__SRSCTL: check_insn(ctx, ISA_MIPS_R2); - gen_helper_mtc0_srsctl(cpu_env, arg); + gen_helper_mtc0_srsctl(tcg_env, arg); /* Stop translation as we may have switched the execution mode */ ctx->base.is_jmp = DISAS_STOP; register_name = "SRSCtl"; @@ -6475,7 +6475,7 @@ static void gen_mtc0(DisasContext *ctx, TCGv arg, int reg, int sel) switch (sel) { case CP0_REG13__CAUSE: save_cpu_state(ctx, 1); - gen_helper_mtc0_cause(cpu_env, arg); + gen_helper_mtc0_cause(tcg_env, arg); /* * Stop translation as we may have triggered an interrupt. * DISAS_STOP isn't sufficient, we need to ensure we break out of @@ -6492,7 +6492,7 @@ static void gen_mtc0(DisasContext *ctx, TCGv arg, int reg, int sel) case CP0_REGISTER_14: switch (sel) { case CP0_REG14__EPC: - tcg_gen_st_tl(arg, cpu_env, offsetof(CPUMIPSState, CP0_EPC)); + tcg_gen_st_tl(arg, tcg_env, offsetof(CPUMIPSState, CP0_EPC)); register_name = "EPC"; break; default: @@ -6507,7 +6507,7 @@ static void gen_mtc0(DisasContext *ctx, TCGv arg, int reg, int sel) break; case CP0_REG15__EBASE: check_insn(ctx, ISA_MIPS_R2); - gen_helper_mtc0_ebase(cpu_env, arg); + gen_helper_mtc0_ebase(tcg_env, arg); register_name = "EBase"; break; default: @@ -6517,7 +6517,7 @@ static void gen_mtc0(DisasContext *ctx, TCGv arg, int reg, int sel) case CP0_REGISTER_16: switch (sel) { case CP0_REG16__CONFIG: - gen_helper_mtc0_config0(cpu_env, arg); + gen_helper_mtc0_config0(tcg_env, arg); register_name = "Config"; /* Stop translation as we may have switched the execution mode */ ctx->base.is_jmp = DISAS_STOP; @@ -6527,24 +6527,24 @@ static void gen_mtc0(DisasContext *ctx, TCGv arg, int reg, int sel) register_name = "Config1"; break; case CP0_REG16__CONFIG2: - gen_helper_mtc0_config2(cpu_env, arg); + gen_helper_mtc0_config2(tcg_env, arg); register_name = "Config2"; /* Stop translation as we may have switched the execution mode */ ctx->base.is_jmp = DISAS_STOP; break; case CP0_REG16__CONFIG3: - gen_helper_mtc0_config3(cpu_env, arg); + gen_helper_mtc0_config3(tcg_env, arg); register_name = "Config3"; /* Stop translation as we may have switched the execution mode */ ctx->base.is_jmp = DISAS_STOP; break; case CP0_REG16__CONFIG4: - gen_helper_mtc0_config4(cpu_env, arg); + gen_helper_mtc0_config4(tcg_env, arg); register_name = "Config4"; ctx->base.is_jmp = DISAS_STOP; break; case CP0_REG16__CONFIG5: - gen_helper_mtc0_config5(cpu_env, arg); + gen_helper_mtc0_config5(tcg_env, arg); register_name = "Config5"; /* Stop translation as we may have switched the execution mode */ ctx->base.is_jmp = DISAS_STOP; @@ -6566,17 +6566,17 @@ static void gen_mtc0(DisasContext *ctx, TCGv arg, int reg, int sel) case CP0_REGISTER_17: switch (sel) { case CP0_REG17__LLADDR: - gen_helper_mtc0_lladdr(cpu_env, arg); + gen_helper_mtc0_lladdr(tcg_env, arg); register_name = "LLAddr"; break; case CP0_REG17__MAAR: CP0_CHECK(ctx->mrp); - gen_helper_mtc0_maar(cpu_env, arg); + gen_helper_mtc0_maar(tcg_env, arg); register_name = "MAAR"; break; case CP0_REG17__MAARI: CP0_CHECK(ctx->mrp); - gen_helper_mtc0_maari(cpu_env, arg); + gen_helper_mtc0_maari(tcg_env, arg); register_name = "MAARI"; break; default: @@ -6624,7 +6624,7 @@ static void gen_mtc0(DisasContext *ctx, TCGv arg, int reg, int sel) case CP0_REG20__XCONTEXT: #if defined(TARGET_MIPS64) check_insn(ctx, ISA_MIPS3); - gen_helper_mtc0_xcontext(cpu_env, arg); + gen_helper_mtc0_xcontext(tcg_env, arg); register_name = "XContext"; break; #endif @@ -6637,7 +6637,7 @@ static void gen_mtc0(DisasContext *ctx, TCGv arg, int reg, int sel) CP0_CHECK(!(ctx->insn_flags & ISA_MIPS_R6)); switch (sel) { case 0: - gen_helper_mtc0_framemask(cpu_env, arg); + gen_helper_mtc0_framemask(tcg_env, arg); register_name = "Framemask"; break; default: @@ -6651,7 +6651,7 @@ static void gen_mtc0(DisasContext *ctx, TCGv arg, int reg, int sel) case CP0_REGISTER_23: switch (sel) { case CP0_REG23__DEBUG: - gen_helper_mtc0_debug(cpu_env, arg); /* EJTAG support */ + gen_helper_mtc0_debug(tcg_env, arg); /* EJTAG support */ /* DISAS_STOP isn't good enough here, hflags may have changed. */ gen_save_pc(ctx->base.pc_next + 4); ctx->base.is_jmp = DISAS_EXIT; @@ -6659,14 +6659,14 @@ static void gen_mtc0(DisasContext *ctx, TCGv arg, int reg, int sel) break; case CP0_REG23__TRACECONTROL: /* PDtrace support */ - /* gen_helper_mtc0_tracecontrol(cpu_env, arg); */ + /* gen_helper_mtc0_tracecontrol(tcg_env, arg); */ register_name = "TraceControl"; /* Stop translation as we may have switched the execution mode */ ctx->base.is_jmp = DISAS_STOP; goto cp0_unimplemented; case CP0_REG23__TRACECONTROL2: /* PDtrace support */ - /* gen_helper_mtc0_tracecontrol2(cpu_env, arg); */ + /* gen_helper_mtc0_tracecontrol2(tcg_env, arg); */ register_name = "TraceControl2"; /* Stop translation as we may have switched the execution mode */ ctx->base.is_jmp = DISAS_STOP; @@ -6675,21 +6675,21 @@ static void gen_mtc0(DisasContext *ctx, TCGv arg, int reg, int sel) /* Stop translation as we may have switched the execution mode */ ctx->base.is_jmp = DISAS_STOP; /* PDtrace support */ - /* gen_helper_mtc0_usertracedata1(cpu_env, arg);*/ + /* gen_helper_mtc0_usertracedata1(tcg_env, arg);*/ register_name = "UserTraceData"; /* Stop translation as we may have switched the execution mode */ ctx->base.is_jmp = DISAS_STOP; goto cp0_unimplemented; case CP0_REG23__TRACEIBPC: /* PDtrace support */ - /* gen_helper_mtc0_traceibpc(cpu_env, arg); */ + /* gen_helper_mtc0_traceibpc(tcg_env, arg); */ /* Stop translation as we may have switched the execution mode */ ctx->base.is_jmp = DISAS_STOP; register_name = "TraceIBPC"; goto cp0_unimplemented; case CP0_REG23__TRACEDBPC: /* PDtrace support */ - /* gen_helper_mtc0_tracedbpc(cpu_env, arg); */ + /* gen_helper_mtc0_tracedbpc(tcg_env, arg); */ /* Stop translation as we may have switched the execution mode */ ctx->base.is_jmp = DISAS_STOP; register_name = "TraceDBPC"; @@ -6702,7 +6702,7 @@ static void gen_mtc0(DisasContext *ctx, TCGv arg, int reg, int sel) switch (sel) { case CP0_REG24__DEPC: /* EJTAG support */ - tcg_gen_st_tl(arg, cpu_env, offsetof(CPUMIPSState, CP0_DEPC)); + tcg_gen_st_tl(arg, tcg_env, offsetof(CPUMIPSState, CP0_DEPC)); register_name = "DEPC"; break; default: @@ -6712,7 +6712,7 @@ static void gen_mtc0(DisasContext *ctx, TCGv arg, int reg, int sel) case CP0_REGISTER_25: switch (sel) { case CP0_REG25__PERFCTL0: - gen_helper_mtc0_performance0(cpu_env, arg); + gen_helper_mtc0_performance0(tcg_env, arg); register_name = "Performance0"; break; case CP0_REG25__PERFCNT0: @@ -6750,7 +6750,7 @@ static void gen_mtc0(DisasContext *ctx, TCGv arg, int reg, int sel) case CP0_REGISTER_26: switch (sel) { case CP0_REG26__ERRCTL: - gen_helper_mtc0_errctl(cpu_env, arg); + gen_helper_mtc0_errctl(tcg_env, arg); ctx->base.is_jmp = DISAS_STOP; register_name = "ErrCtl"; break; @@ -6774,14 +6774,14 @@ static void gen_mtc0(DisasContext *ctx, TCGv arg, int reg, int sel) case CP0_REG28__TAGLO1: case CP0_REG28__TAGLO2: case CP0_REG28__TAGLO3: - gen_helper_mtc0_taglo(cpu_env, arg); + gen_helper_mtc0_taglo(tcg_env, arg); register_name = "TagLo"; break; case CP0_REG28__DATALO: case CP0_REG28__DATALO1: case CP0_REG28__DATALO2: case CP0_REG28__DATALO3: - gen_helper_mtc0_datalo(cpu_env, arg); + gen_helper_mtc0_datalo(tcg_env, arg); register_name = "DataLo"; break; default: @@ -6794,14 +6794,14 @@ static void gen_mtc0(DisasContext *ctx, TCGv arg, int reg, int sel) case CP0_REG29__TAGHI1: case CP0_REG29__TAGHI2: case CP0_REG29__TAGHI3: - gen_helper_mtc0_taghi(cpu_env, arg); + gen_helper_mtc0_taghi(tcg_env, arg); register_name = "TagHi"; break; case CP0_REG29__DATAHI: case CP0_REG29__DATAHI1: case CP0_REG29__DATAHI2: case CP0_REG29__DATAHI3: - gen_helper_mtc0_datahi(cpu_env, arg); + gen_helper_mtc0_datahi(tcg_env, arg); register_name = "DataHi"; break; default: @@ -6812,7 +6812,7 @@ static void gen_mtc0(DisasContext *ctx, TCGv arg, int reg, int sel) case CP0_REGISTER_30: switch (sel) { case CP0_REG30__ERROREPC: - tcg_gen_st_tl(arg, cpu_env, offsetof(CPUMIPSState, CP0_ErrorEPC)); + tcg_gen_st_tl(arg, tcg_env, offsetof(CPUMIPSState, CP0_ErrorEPC)); register_name = "ErrorEPC"; break; default: @@ -6833,7 +6833,7 @@ static void gen_mtc0(DisasContext *ctx, TCGv arg, int reg, int sel) case CP0_REG31__KSCRATCH5: case CP0_REG31__KSCRATCH6: CP0_CHECK(ctx->kscrexist & (1 << sel)); - tcg_gen_st_tl(arg, cpu_env, + tcg_gen_st_tl(arg, tcg_env, offsetof(CPUMIPSState, CP0_KScratch[sel - 2])); register_name = "KScratch"; break; @@ -6880,17 +6880,17 @@ static void gen_dmfc0(DisasContext *ctx, TCGv arg, int reg, int sel) break; case CP0_REG00__MVPCONTROL: CP0_CHECK(ctx->insn_flags & ASE_MT); - gen_helper_mfc0_mvpcontrol(arg, cpu_env); + gen_helper_mfc0_mvpcontrol(arg, tcg_env); register_name = "MVPControl"; break; case CP0_REG00__MVPCONF0: CP0_CHECK(ctx->insn_flags & ASE_MT); - gen_helper_mfc0_mvpconf0(arg, cpu_env); + gen_helper_mfc0_mvpconf0(arg, tcg_env); register_name = "MVPConf0"; break; case CP0_REG00__MVPCONF1: CP0_CHECK(ctx->insn_flags & ASE_MT); - gen_helper_mfc0_mvpconf1(arg, cpu_env); + gen_helper_mfc0_mvpconf1(arg, tcg_env); register_name = "MVPConf1"; break; case CP0_REG00__VPCONTROL: @@ -6906,7 +6906,7 @@ static void gen_dmfc0(DisasContext *ctx, TCGv arg, int reg, int sel) switch (sel) { case CP0_REG01__RANDOM: CP0_CHECK(!(ctx->insn_flags & ISA_MIPS_R6)); - gen_helper_mfc0_random(arg, cpu_env); + gen_helper_mfc0_random(arg, tcg_env); register_name = "Random"; break; case CP0_REG01__VPECONTROL: @@ -6926,19 +6926,19 @@ static void gen_dmfc0(DisasContext *ctx, TCGv arg, int reg, int sel) break; case CP0_REG01__YQMASK: CP0_CHECK(ctx->insn_flags & ASE_MT); - tcg_gen_ld_tl(arg, cpu_env, + tcg_gen_ld_tl(arg, tcg_env, offsetof(CPUMIPSState, CP0_YQMask)); register_name = "YQMask"; break; case CP0_REG01__VPESCHEDULE: CP0_CHECK(ctx->insn_flags & ASE_MT); - tcg_gen_ld_tl(arg, cpu_env, + tcg_gen_ld_tl(arg, tcg_env, offsetof(CPUMIPSState, CP0_VPESchedule)); register_name = "VPESchedule"; break; case CP0_REG01__VPESCHEFBACK: CP0_CHECK(ctx->insn_flags & ASE_MT); - tcg_gen_ld_tl(arg, cpu_env, + tcg_gen_ld_tl(arg, tcg_env, offsetof(CPUMIPSState, CP0_VPEScheFBack)); register_name = "VPEScheFBack"; break; @@ -6954,43 +6954,43 @@ static void gen_dmfc0(DisasContext *ctx, TCGv arg, int reg, int sel) case CP0_REGISTER_02: switch (sel) { case CP0_REG02__ENTRYLO0: - tcg_gen_ld_tl(arg, cpu_env, + tcg_gen_ld_tl(arg, tcg_env, offsetof(CPUMIPSState, CP0_EntryLo0)); register_name = "EntryLo0"; break; case CP0_REG02__TCSTATUS: CP0_CHECK(ctx->insn_flags & ASE_MT); - gen_helper_mfc0_tcstatus(arg, cpu_env); + gen_helper_mfc0_tcstatus(arg, tcg_env); register_name = "TCStatus"; break; case CP0_REG02__TCBIND: CP0_CHECK(ctx->insn_flags & ASE_MT); - gen_helper_mfc0_tcbind(arg, cpu_env); + gen_helper_mfc0_tcbind(arg, tcg_env); register_name = "TCBind"; break; case CP0_REG02__TCRESTART: CP0_CHECK(ctx->insn_flags & ASE_MT); - gen_helper_dmfc0_tcrestart(arg, cpu_env); + gen_helper_dmfc0_tcrestart(arg, tcg_env); register_name = "TCRestart"; break; case CP0_REG02__TCHALT: CP0_CHECK(ctx->insn_flags & ASE_MT); - gen_helper_dmfc0_tchalt(arg, cpu_env); + gen_helper_dmfc0_tchalt(arg, tcg_env); register_name = "TCHalt"; break; case CP0_REG02__TCCONTEXT: CP0_CHECK(ctx->insn_flags & ASE_MT); - gen_helper_dmfc0_tccontext(arg, cpu_env); + gen_helper_dmfc0_tccontext(arg, tcg_env); register_name = "TCContext"; break; case CP0_REG02__TCSCHEDULE: CP0_CHECK(ctx->insn_flags & ASE_MT); - gen_helper_dmfc0_tcschedule(arg, cpu_env); + gen_helper_dmfc0_tcschedule(arg, tcg_env); register_name = "TCSchedule"; break; case CP0_REG02__TCSCHEFBACK: CP0_CHECK(ctx->insn_flags & ASE_MT); - gen_helper_dmfc0_tcschefback(arg, cpu_env); + gen_helper_dmfc0_tcschefback(arg, tcg_env); register_name = "TCScheFBack"; break; default: @@ -7000,7 +7000,7 @@ static void gen_dmfc0(DisasContext *ctx, TCGv arg, int reg, int sel) case CP0_REGISTER_03: switch (sel) { case CP0_REG03__ENTRYLO1: - tcg_gen_ld_tl(arg, cpu_env, offsetof(CPUMIPSState, CP0_EntryLo1)); + tcg_gen_ld_tl(arg, tcg_env, offsetof(CPUMIPSState, CP0_EntryLo1)); register_name = "EntryLo1"; break; case CP0_REG03__GLOBALNUM: @@ -7015,7 +7015,7 @@ static void gen_dmfc0(DisasContext *ctx, TCGv arg, int reg, int sel) case CP0_REGISTER_04: switch (sel) { case CP0_REG04__CONTEXT: - tcg_gen_ld_tl(arg, cpu_env, offsetof(CPUMIPSState, CP0_Context)); + tcg_gen_ld_tl(arg, tcg_env, offsetof(CPUMIPSState, CP0_Context)); register_name = "Context"; break; case CP0_REG04__CONTEXTCONFIG: @@ -7025,13 +7025,13 @@ static void gen_dmfc0(DisasContext *ctx, TCGv arg, int reg, int sel) goto cp0_unimplemented; case CP0_REG04__USERLOCAL: CP0_CHECK(ctx->ulri); - tcg_gen_ld_tl(arg, cpu_env, + tcg_gen_ld_tl(arg, tcg_env, offsetof(CPUMIPSState, active_tc.CP0_UserLocal)); register_name = "UserLocal"; break; case CP0_REG04__MMID: CP0_CHECK(ctx->mi); - gen_helper_mtc0_memorymapid(cpu_env, arg); + gen_helper_mtc0_memorymapid(tcg_env, arg); register_name = "MMID"; break; default: @@ -7051,32 +7051,32 @@ static void gen_dmfc0(DisasContext *ctx, TCGv arg, int reg, int sel) break; case CP0_REG05__SEGCTL0: CP0_CHECK(ctx->sc); - tcg_gen_ld_tl(arg, cpu_env, offsetof(CPUMIPSState, CP0_SegCtl0)); + tcg_gen_ld_tl(arg, tcg_env, offsetof(CPUMIPSState, CP0_SegCtl0)); register_name = "SegCtl0"; break; case CP0_REG05__SEGCTL1: CP0_CHECK(ctx->sc); - tcg_gen_ld_tl(arg, cpu_env, offsetof(CPUMIPSState, CP0_SegCtl1)); + tcg_gen_ld_tl(arg, tcg_env, offsetof(CPUMIPSState, CP0_SegCtl1)); register_name = "SegCtl1"; break; case CP0_REG05__SEGCTL2: CP0_CHECK(ctx->sc); - tcg_gen_ld_tl(arg, cpu_env, offsetof(CPUMIPSState, CP0_SegCtl2)); + tcg_gen_ld_tl(arg, tcg_env, offsetof(CPUMIPSState, CP0_SegCtl2)); register_name = "SegCtl2"; break; case CP0_REG05__PWBASE: check_pw(ctx); - tcg_gen_ld_tl(arg, cpu_env, offsetof(CPUMIPSState, CP0_PWBase)); + tcg_gen_ld_tl(arg, tcg_env, offsetof(CPUMIPSState, CP0_PWBase)); register_name = "PWBase"; break; case CP0_REG05__PWFIELD: check_pw(ctx); - tcg_gen_ld_tl(arg, cpu_env, offsetof(CPUMIPSState, CP0_PWField)); + tcg_gen_ld_tl(arg, tcg_env, offsetof(CPUMIPSState, CP0_PWField)); register_name = "PWField"; break; case CP0_REG05__PWSIZE: check_pw(ctx); - tcg_gen_ld_tl(arg, cpu_env, offsetof(CPUMIPSState, CP0_PWSize)); + tcg_gen_ld_tl(arg, tcg_env, offsetof(CPUMIPSState, CP0_PWSize)); register_name = "PWSize"; break; default: @@ -7137,7 +7137,7 @@ static void gen_dmfc0(DisasContext *ctx, TCGv arg, int reg, int sel) case CP0_REGISTER_08: switch (sel) { case CP0_REG08__BADVADDR: - tcg_gen_ld_tl(arg, cpu_env, offsetof(CPUMIPSState, CP0_BadVAddr)); + tcg_gen_ld_tl(arg, tcg_env, offsetof(CPUMIPSState, CP0_BadVAddr)); register_name = "BadVAddr"; break; case CP0_REG08__BADINSTR: @@ -7165,7 +7165,7 @@ static void gen_dmfc0(DisasContext *ctx, TCGv arg, int reg, int sel) case CP0_REG09__COUNT: /* Mark as an IO operation because we read the time. */ translator_io_start(&ctx->base); - gen_helper_mfc0_count(arg, cpu_env); + gen_helper_mfc0_count(arg, tcg_env); /* * Break the TB to be able to take timer interrupts immediately * after reading count. DISAS_STOP isn't sufficient, we need to @@ -7182,7 +7182,7 @@ static void gen_dmfc0(DisasContext *ctx, TCGv arg, int reg, int sel) break; case CP0_REG09__SAAR: CP0_CHECK(ctx->saar); - gen_helper_dmfc0_saar(arg, cpu_env); + gen_helper_dmfc0_saar(arg, tcg_env); register_name = "SAAR"; break; default: @@ -7192,7 +7192,7 @@ static void gen_dmfc0(DisasContext *ctx, TCGv arg, int reg, int sel) case CP0_REGISTER_10: switch (sel) { case CP0_REG10__ENTRYHI: - tcg_gen_ld_tl(arg, cpu_env, offsetof(CPUMIPSState, CP0_EntryHi)); + tcg_gen_ld_tl(arg, tcg_env, offsetof(CPUMIPSState, CP0_EntryHi)); register_name = "EntryHi"; break; default: @@ -7248,7 +7248,7 @@ static void gen_dmfc0(DisasContext *ctx, TCGv arg, int reg, int sel) case CP0_REGISTER_14: switch (sel) { case CP0_REG14__EPC: - tcg_gen_ld_tl(arg, cpu_env, offsetof(CPUMIPSState, CP0_EPC)); + tcg_gen_ld_tl(arg, tcg_env, offsetof(CPUMIPSState, CP0_EPC)); register_name = "EPC"; break; default: @@ -7263,13 +7263,13 @@ static void gen_dmfc0(DisasContext *ctx, TCGv arg, int reg, int sel) break; case CP0_REG15__EBASE: check_insn(ctx, ISA_MIPS_R2); - tcg_gen_ld_tl(arg, cpu_env, offsetof(CPUMIPSState, CP0_EBase)); + tcg_gen_ld_tl(arg, tcg_env, offsetof(CPUMIPSState, CP0_EBase)); register_name = "EBase"; break; case CP0_REG15__CMGCRBASE: check_insn(ctx, ISA_MIPS_R2); CP0_CHECK(ctx->cmgcr); - tcg_gen_ld_tl(arg, cpu_env, offsetof(CPUMIPSState, CP0_CMGCRBase)); + tcg_gen_ld_tl(arg, tcg_env, offsetof(CPUMIPSState, CP0_CMGCRBase)); register_name = "CMGCRBase"; break; default: @@ -7318,12 +7318,12 @@ static void gen_dmfc0(DisasContext *ctx, TCGv arg, int reg, int sel) case CP0_REGISTER_17: switch (sel) { case CP0_REG17__LLADDR: - gen_helper_dmfc0_lladdr(arg, cpu_env); + gen_helper_dmfc0_lladdr(arg, tcg_env); register_name = "LLAddr"; break; case CP0_REG17__MAAR: CP0_CHECK(ctx->mrp); - gen_helper_dmfc0_maar(arg, cpu_env); + gen_helper_dmfc0_maar(arg, tcg_env); register_name = "MAAR"; break; case CP0_REG17__MAARI: @@ -7375,7 +7375,7 @@ static void gen_dmfc0(DisasContext *ctx, TCGv arg, int reg, int sel) switch (sel) { case CP0_REG20__XCONTEXT: check_insn(ctx, ISA_MIPS3); - tcg_gen_ld_tl(arg, cpu_env, offsetof(CPUMIPSState, CP0_XContext)); + tcg_gen_ld_tl(arg, tcg_env, offsetof(CPUMIPSState, CP0_XContext)); register_name = "XContext"; break; default: @@ -7401,32 +7401,32 @@ static void gen_dmfc0(DisasContext *ctx, TCGv arg, int reg, int sel) case CP0_REGISTER_23: switch (sel) { case CP0_REG23__DEBUG: - gen_helper_mfc0_debug(arg, cpu_env); /* EJTAG support */ + gen_helper_mfc0_debug(arg, tcg_env); /* EJTAG support */ register_name = "Debug"; break; case CP0_REG23__TRACECONTROL: /* PDtrace support */ - /* gen_helper_dmfc0_tracecontrol(arg, cpu_env); */ + /* gen_helper_dmfc0_tracecontrol(arg, tcg_env); */ register_name = "TraceControl"; goto cp0_unimplemented; case CP0_REG23__TRACECONTROL2: /* PDtrace support */ - /* gen_helper_dmfc0_tracecontrol2(arg, cpu_env); */ + /* gen_helper_dmfc0_tracecontrol2(arg, tcg_env); */ register_name = "TraceControl2"; goto cp0_unimplemented; case CP0_REG23__USERTRACEDATA1: /* PDtrace support */ - /* gen_helper_dmfc0_usertracedata1(arg, cpu_env);*/ + /* gen_helper_dmfc0_usertracedata1(arg, tcg_env);*/ register_name = "UserTraceData1"; goto cp0_unimplemented; case CP0_REG23__TRACEIBPC: /* PDtrace support */ - /* gen_helper_dmfc0_traceibpc(arg, cpu_env); */ + /* gen_helper_dmfc0_traceibpc(arg, tcg_env); */ register_name = "TraceIBPC"; goto cp0_unimplemented; case CP0_REG23__TRACEDBPC: /* PDtrace support */ - /* gen_helper_dmfc0_tracedbpc(arg, cpu_env); */ + /* gen_helper_dmfc0_tracedbpc(arg, tcg_env); */ register_name = "TraceDBPC"; goto cp0_unimplemented; default: @@ -7437,7 +7437,7 @@ static void gen_dmfc0(DisasContext *ctx, TCGv arg, int reg, int sel) switch (sel) { case CP0_REG24__DEPC: /* EJTAG support */ - tcg_gen_ld_tl(arg, cpu_env, offsetof(CPUMIPSState, CP0_DEPC)); + tcg_gen_ld_tl(arg, tcg_env, offsetof(CPUMIPSState, CP0_DEPC)); register_name = "DEPC"; break; default: @@ -7546,7 +7546,7 @@ static void gen_dmfc0(DisasContext *ctx, TCGv arg, int reg, int sel) case CP0_REGISTER_30: switch (sel) { case CP0_REG30__ERROREPC: - tcg_gen_ld_tl(arg, cpu_env, offsetof(CPUMIPSState, CP0_ErrorEPC)); + tcg_gen_ld_tl(arg, tcg_env, offsetof(CPUMIPSState, CP0_ErrorEPC)); register_name = "ErrorEPC"; break; default: @@ -7567,7 +7567,7 @@ static void gen_dmfc0(DisasContext *ctx, TCGv arg, int reg, int sel) case CP0_REG31__KSCRATCH5: case CP0_REG31__KSCRATCH6: CP0_CHECK(ctx->kscrexist & (1 << sel)); - tcg_gen_ld_tl(arg, cpu_env, + tcg_gen_ld_tl(arg, tcg_env, offsetof(CPUMIPSState, CP0_KScratch[sel - 2])); register_name = "KScratch"; break; @@ -7602,12 +7602,12 @@ static void gen_dmtc0(DisasContext *ctx, TCGv arg, int reg, int sel) case CP0_REGISTER_00: switch (sel) { case CP0_REG00__INDEX: - gen_helper_mtc0_index(cpu_env, arg); + gen_helper_mtc0_index(tcg_env, arg); register_name = "Index"; break; case CP0_REG00__MVPCONTROL: CP0_CHECK(ctx->insn_flags & ASE_MT); - gen_helper_mtc0_mvpcontrol(cpu_env, arg); + gen_helper_mtc0_mvpcontrol(tcg_env, arg); register_name = "MVPControl"; break; case CP0_REG00__MVPCONF0: @@ -7637,39 +7637,39 @@ static void gen_dmtc0(DisasContext *ctx, TCGv arg, int reg, int sel) break; case CP0_REG01__VPECONTROL: CP0_CHECK(ctx->insn_flags & ASE_MT); - gen_helper_mtc0_vpecontrol(cpu_env, arg); + gen_helper_mtc0_vpecontrol(tcg_env, arg); register_name = "VPEControl"; break; case CP0_REG01__VPECONF0: CP0_CHECK(ctx->insn_flags & ASE_MT); - gen_helper_mtc0_vpeconf0(cpu_env, arg); + gen_helper_mtc0_vpeconf0(tcg_env, arg); register_name = "VPEConf0"; break; case CP0_REG01__VPECONF1: CP0_CHECK(ctx->insn_flags & ASE_MT); - gen_helper_mtc0_vpeconf1(cpu_env, arg); + gen_helper_mtc0_vpeconf1(tcg_env, arg); register_name = "VPEConf1"; break; case CP0_REG01__YQMASK: CP0_CHECK(ctx->insn_flags & ASE_MT); - gen_helper_mtc0_yqmask(cpu_env, arg); + gen_helper_mtc0_yqmask(tcg_env, arg); register_name = "YQMask"; break; case CP0_REG01__VPESCHEDULE: CP0_CHECK(ctx->insn_flags & ASE_MT); - tcg_gen_st_tl(arg, cpu_env, + tcg_gen_st_tl(arg, tcg_env, offsetof(CPUMIPSState, CP0_VPESchedule)); register_name = "VPESchedule"; break; case CP0_REG01__VPESCHEFBACK: CP0_CHECK(ctx->insn_flags & ASE_MT); - tcg_gen_st_tl(arg, cpu_env, + tcg_gen_st_tl(arg, tcg_env, offsetof(CPUMIPSState, CP0_VPEScheFBack)); register_name = "VPEScheFBack"; break; case CP0_REG01__VPEOPT: CP0_CHECK(ctx->insn_flags & ASE_MT); - gen_helper_mtc0_vpeopt(cpu_env, arg); + gen_helper_mtc0_vpeopt(tcg_env, arg); register_name = "VPEOpt"; break; default: @@ -7679,42 +7679,42 @@ static void gen_dmtc0(DisasContext *ctx, TCGv arg, int reg, int sel) case CP0_REGISTER_02: switch (sel) { case CP0_REG02__ENTRYLO0: - gen_helper_dmtc0_entrylo0(cpu_env, arg); + gen_helper_dmtc0_entrylo0(tcg_env, arg); register_name = "EntryLo0"; break; case CP0_REG02__TCSTATUS: CP0_CHECK(ctx->insn_flags & ASE_MT); - gen_helper_mtc0_tcstatus(cpu_env, arg); + gen_helper_mtc0_tcstatus(tcg_env, arg); register_name = "TCStatus"; break; case CP0_REG02__TCBIND: CP0_CHECK(ctx->insn_flags & ASE_MT); - gen_helper_mtc0_tcbind(cpu_env, arg); + gen_helper_mtc0_tcbind(tcg_env, arg); register_name = "TCBind"; break; case CP0_REG02__TCRESTART: CP0_CHECK(ctx->insn_flags & ASE_MT); - gen_helper_mtc0_tcrestart(cpu_env, arg); + gen_helper_mtc0_tcrestart(tcg_env, arg); register_name = "TCRestart"; break; case CP0_REG02__TCHALT: CP0_CHECK(ctx->insn_flags & ASE_MT); - gen_helper_mtc0_tchalt(cpu_env, arg); + gen_helper_mtc0_tchalt(tcg_env, arg); register_name = "TCHalt"; break; case CP0_REG02__TCCONTEXT: CP0_CHECK(ctx->insn_flags & ASE_MT); - gen_helper_mtc0_tccontext(cpu_env, arg); + gen_helper_mtc0_tccontext(tcg_env, arg); register_name = "TCContext"; break; case CP0_REG02__TCSCHEDULE: CP0_CHECK(ctx->insn_flags & ASE_MT); - gen_helper_mtc0_tcschedule(cpu_env, arg); + gen_helper_mtc0_tcschedule(tcg_env, arg); register_name = "TCSchedule"; break; case CP0_REG02__TCSCHEFBACK: CP0_CHECK(ctx->insn_flags & ASE_MT); - gen_helper_mtc0_tcschefback(cpu_env, arg); + gen_helper_mtc0_tcschefback(tcg_env, arg); register_name = "TCScheFBack"; break; default: @@ -7724,7 +7724,7 @@ static void gen_dmtc0(DisasContext *ctx, TCGv arg, int reg, int sel) case CP0_REGISTER_03: switch (sel) { case CP0_REG03__ENTRYLO1: - gen_helper_dmtc0_entrylo1(cpu_env, arg); + gen_helper_dmtc0_entrylo1(tcg_env, arg); register_name = "EntryLo1"; break; case CP0_REG03__GLOBALNUM: @@ -7739,7 +7739,7 @@ static void gen_dmtc0(DisasContext *ctx, TCGv arg, int reg, int sel) case CP0_REGISTER_04: switch (sel) { case CP0_REG04__CONTEXT: - gen_helper_mtc0_context(cpu_env, arg); + gen_helper_mtc0_context(tcg_env, arg); register_name = "Context"; break; case CP0_REG04__CONTEXTCONFIG: @@ -7749,7 +7749,7 @@ static void gen_dmtc0(DisasContext *ctx, TCGv arg, int reg, int sel) goto cp0_unimplemented; case CP0_REG04__USERLOCAL: CP0_CHECK(ctx->ulri); - tcg_gen_st_tl(arg, cpu_env, + tcg_gen_st_tl(arg, tcg_env, offsetof(CPUMIPSState, active_tc.CP0_UserLocal)); register_name = "UserLocal"; break; @@ -7765,42 +7765,42 @@ static void gen_dmtc0(DisasContext *ctx, TCGv arg, int reg, int sel) case CP0_REGISTER_05: switch (sel) { case CP0_REG05__PAGEMASK: - gen_helper_mtc0_pagemask(cpu_env, arg); + gen_helper_mtc0_pagemask(tcg_env, arg); register_name = "PageMask"; break; case CP0_REG05__PAGEGRAIN: check_insn(ctx, ISA_MIPS_R2); - gen_helper_mtc0_pagegrain(cpu_env, arg); + gen_helper_mtc0_pagegrain(tcg_env, arg); register_name = "PageGrain"; break; case CP0_REG05__SEGCTL0: CP0_CHECK(ctx->sc); - gen_helper_mtc0_segctl0(cpu_env, arg); + gen_helper_mtc0_segctl0(tcg_env, arg); register_name = "SegCtl0"; break; case CP0_REG05__SEGCTL1: CP0_CHECK(ctx->sc); - gen_helper_mtc0_segctl1(cpu_env, arg); + gen_helper_mtc0_segctl1(tcg_env, arg); register_name = "SegCtl1"; break; case CP0_REG05__SEGCTL2: CP0_CHECK(ctx->sc); - gen_helper_mtc0_segctl2(cpu_env, arg); + gen_helper_mtc0_segctl2(tcg_env, arg); register_name = "SegCtl2"; break; case CP0_REG05__PWBASE: check_pw(ctx); - tcg_gen_st_tl(arg, cpu_env, offsetof(CPUMIPSState, CP0_PWBase)); + tcg_gen_st_tl(arg, tcg_env, offsetof(CPUMIPSState, CP0_PWBase)); register_name = "PWBase"; break; case CP0_REG05__PWFIELD: check_pw(ctx); - gen_helper_mtc0_pwfield(cpu_env, arg); + gen_helper_mtc0_pwfield(tcg_env, arg); register_name = "PWField"; break; case CP0_REG05__PWSIZE: check_pw(ctx); - gen_helper_mtc0_pwsize(cpu_env, arg); + gen_helper_mtc0_pwsize(tcg_env, arg); register_name = "PWSize"; break; default: @@ -7810,37 +7810,37 @@ static void gen_dmtc0(DisasContext *ctx, TCGv arg, int reg, int sel) case CP0_REGISTER_06: switch (sel) { case CP0_REG06__WIRED: - gen_helper_mtc0_wired(cpu_env, arg); + gen_helper_mtc0_wired(tcg_env, arg); register_name = "Wired"; break; case CP0_REG06__SRSCONF0: check_insn(ctx, ISA_MIPS_R2); - gen_helper_mtc0_srsconf0(cpu_env, arg); + gen_helper_mtc0_srsconf0(tcg_env, arg); register_name = "SRSConf0"; break; case CP0_REG06__SRSCONF1: check_insn(ctx, ISA_MIPS_R2); - gen_helper_mtc0_srsconf1(cpu_env, arg); + gen_helper_mtc0_srsconf1(tcg_env, arg); register_name = "SRSConf1"; break; case CP0_REG06__SRSCONF2: check_insn(ctx, ISA_MIPS_R2); - gen_helper_mtc0_srsconf2(cpu_env, arg); + gen_helper_mtc0_srsconf2(tcg_env, arg); register_name = "SRSConf2"; break; case CP0_REG06__SRSCONF3: check_insn(ctx, ISA_MIPS_R2); - gen_helper_mtc0_srsconf3(cpu_env, arg); + gen_helper_mtc0_srsconf3(tcg_env, arg); register_name = "SRSConf3"; break; case CP0_REG06__SRSCONF4: check_insn(ctx, ISA_MIPS_R2); - gen_helper_mtc0_srsconf4(cpu_env, arg); + gen_helper_mtc0_srsconf4(tcg_env, arg); register_name = "SRSConf4"; break; case CP0_REG06__PWCTL: check_pw(ctx); - gen_helper_mtc0_pwctl(cpu_env, arg); + gen_helper_mtc0_pwctl(tcg_env, arg); register_name = "PWCtl"; break; default: @@ -7851,7 +7851,7 @@ static void gen_dmtc0(DisasContext *ctx, TCGv arg, int reg, int sel) switch (sel) { case CP0_REG07__HWRENA: check_insn(ctx, ISA_MIPS_R2); - gen_helper_mtc0_hwrena(cpu_env, arg); + gen_helper_mtc0_hwrena(tcg_env, arg); ctx->base.is_jmp = DISAS_STOP; register_name = "HWREna"; break; @@ -7884,17 +7884,17 @@ static void gen_dmtc0(DisasContext *ctx, TCGv arg, int reg, int sel) case CP0_REGISTER_09: switch (sel) { case CP0_REG09__COUNT: - gen_helper_mtc0_count(cpu_env, arg); + gen_helper_mtc0_count(tcg_env, arg); register_name = "Count"; break; case CP0_REG09__SAARI: CP0_CHECK(ctx->saar); - gen_helper_mtc0_saari(cpu_env, arg); + gen_helper_mtc0_saari(tcg_env, arg); register_name = "SAARI"; break; case CP0_REG09__SAAR: CP0_CHECK(ctx->saar); - gen_helper_mtc0_saar(cpu_env, arg); + gen_helper_mtc0_saar(tcg_env, arg); register_name = "SAAR"; break; default: @@ -7906,7 +7906,7 @@ static void gen_dmtc0(DisasContext *ctx, TCGv arg, int reg, int sel) case CP0_REGISTER_10: switch (sel) { case CP0_REG10__ENTRYHI: - gen_helper_mtc0_entryhi(cpu_env, arg); + gen_helper_mtc0_entryhi(tcg_env, arg); register_name = "EntryHi"; break; default: @@ -7916,7 +7916,7 @@ static void gen_dmtc0(DisasContext *ctx, TCGv arg, int reg, int sel) case CP0_REGISTER_11: switch (sel) { case CP0_REG11__COMPARE: - gen_helper_mtc0_compare(cpu_env, arg); + gen_helper_mtc0_compare(tcg_env, arg); register_name = "Compare"; break; /* 6,7 are implementation dependent */ @@ -7930,7 +7930,7 @@ static void gen_dmtc0(DisasContext *ctx, TCGv arg, int reg, int sel) switch (sel) { case CP0_REG12__STATUS: save_cpu_state(ctx, 1); - gen_helper_mtc0_status(cpu_env, arg); + gen_helper_mtc0_status(tcg_env, arg); /* DISAS_STOP isn't good enough here, hflags may have changed. */ gen_save_pc(ctx->base.pc_next + 4); ctx->base.is_jmp = DISAS_EXIT; @@ -7938,14 +7938,14 @@ static void gen_dmtc0(DisasContext *ctx, TCGv arg, int reg, int sel) break; case CP0_REG12__INTCTL: check_insn(ctx, ISA_MIPS_R2); - gen_helper_mtc0_intctl(cpu_env, arg); + gen_helper_mtc0_intctl(tcg_env, arg); /* Stop translation as we may have switched the execution mode */ ctx->base.is_jmp = DISAS_STOP; register_name = "IntCtl"; break; case CP0_REG12__SRSCTL: check_insn(ctx, ISA_MIPS_R2); - gen_helper_mtc0_srsctl(cpu_env, arg); + gen_helper_mtc0_srsctl(tcg_env, arg); /* Stop translation as we may have switched the execution mode */ ctx->base.is_jmp = DISAS_STOP; register_name = "SRSCtl"; @@ -7965,7 +7965,7 @@ static void gen_dmtc0(DisasContext *ctx, TCGv arg, int reg, int sel) switch (sel) { case CP0_REG13__CAUSE: save_cpu_state(ctx, 1); - gen_helper_mtc0_cause(cpu_env, arg); + gen_helper_mtc0_cause(tcg_env, arg); /* * Stop translation as we may have triggered an interrupt. * DISAS_STOP isn't sufficient, we need to ensure we break out of @@ -7982,7 +7982,7 @@ static void gen_dmtc0(DisasContext *ctx, TCGv arg, int reg, int sel) case CP0_REGISTER_14: switch (sel) { case CP0_REG14__EPC: - tcg_gen_st_tl(arg, cpu_env, offsetof(CPUMIPSState, CP0_EPC)); + tcg_gen_st_tl(arg, tcg_env, offsetof(CPUMIPSState, CP0_EPC)); register_name = "EPC"; break; default: @@ -7997,7 +7997,7 @@ static void gen_dmtc0(DisasContext *ctx, TCGv arg, int reg, int sel) break; case CP0_REG15__EBASE: check_insn(ctx, ISA_MIPS_R2); - gen_helper_mtc0_ebase(cpu_env, arg); + gen_helper_mtc0_ebase(tcg_env, arg); register_name = "EBase"; break; default: @@ -8007,7 +8007,7 @@ static void gen_dmtc0(DisasContext *ctx, TCGv arg, int reg, int sel) case CP0_REGISTER_16: switch (sel) { case CP0_REG16__CONFIG: - gen_helper_mtc0_config0(cpu_env, arg); + gen_helper_mtc0_config0(tcg_env, arg); register_name = "Config"; /* Stop translation as we may have switched the execution mode */ ctx->base.is_jmp = DISAS_STOP; @@ -8017,13 +8017,13 @@ static void gen_dmtc0(DisasContext *ctx, TCGv arg, int reg, int sel) register_name = "Config1"; break; case CP0_REG16__CONFIG2: - gen_helper_mtc0_config2(cpu_env, arg); + gen_helper_mtc0_config2(tcg_env, arg); register_name = "Config2"; /* Stop translation as we may have switched the execution mode */ ctx->base.is_jmp = DISAS_STOP; break; case CP0_REG16__CONFIG3: - gen_helper_mtc0_config3(cpu_env, arg); + gen_helper_mtc0_config3(tcg_env, arg); register_name = "Config3"; /* Stop translation as we may have switched the execution mode */ ctx->base.is_jmp = DISAS_STOP; @@ -8033,7 +8033,7 @@ static void gen_dmtc0(DisasContext *ctx, TCGv arg, int reg, int sel) register_name = "Config4"; break; case CP0_REG16__CONFIG5: - gen_helper_mtc0_config5(cpu_env, arg); + gen_helper_mtc0_config5(tcg_env, arg); register_name = "Config5"; /* Stop translation as we may have switched the execution mode */ ctx->base.is_jmp = DISAS_STOP; @@ -8047,17 +8047,17 @@ static void gen_dmtc0(DisasContext *ctx, TCGv arg, int reg, int sel) case CP0_REGISTER_17: switch (sel) { case CP0_REG17__LLADDR: - gen_helper_mtc0_lladdr(cpu_env, arg); + gen_helper_mtc0_lladdr(tcg_env, arg); register_name = "LLAddr"; break; case CP0_REG17__MAAR: CP0_CHECK(ctx->mrp); - gen_helper_mtc0_maar(cpu_env, arg); + gen_helper_mtc0_maar(tcg_env, arg); register_name = "MAAR"; break; case CP0_REG17__MAARI: CP0_CHECK(ctx->mrp); - gen_helper_mtc0_maari(cpu_env, arg); + gen_helper_mtc0_maari(tcg_env, arg); register_name = "MAARI"; break; default: @@ -8104,7 +8104,7 @@ static void gen_dmtc0(DisasContext *ctx, TCGv arg, int reg, int sel) switch (sel) { case CP0_REG20__XCONTEXT: check_insn(ctx, ISA_MIPS3); - gen_helper_mtc0_xcontext(cpu_env, arg); + gen_helper_mtc0_xcontext(tcg_env, arg); register_name = "XContext"; break; default: @@ -8116,7 +8116,7 @@ static void gen_dmtc0(DisasContext *ctx, TCGv arg, int reg, int sel) CP0_CHECK(!(ctx->insn_flags & ISA_MIPS_R6)); switch (sel) { case 0: - gen_helper_mtc0_framemask(cpu_env, arg); + gen_helper_mtc0_framemask(tcg_env, arg); register_name = "Framemask"; break; default: @@ -8130,7 +8130,7 @@ static void gen_dmtc0(DisasContext *ctx, TCGv arg, int reg, int sel) case CP0_REGISTER_23: switch (sel) { case CP0_REG23__DEBUG: - gen_helper_mtc0_debug(cpu_env, arg); /* EJTAG support */ + gen_helper_mtc0_debug(tcg_env, arg); /* EJTAG support */ /* DISAS_STOP isn't good enough here, hflags may have changed. */ gen_save_pc(ctx->base.pc_next + 4); ctx->base.is_jmp = DISAS_EXIT; @@ -8138,35 +8138,35 @@ static void gen_dmtc0(DisasContext *ctx, TCGv arg, int reg, int sel) break; case CP0_REG23__TRACECONTROL: /* PDtrace support */ - /* gen_helper_mtc0_tracecontrol(cpu_env, arg); */ + /* gen_helper_mtc0_tracecontrol(tcg_env, arg); */ /* Stop translation as we may have switched the execution mode */ ctx->base.is_jmp = DISAS_STOP; register_name = "TraceControl"; goto cp0_unimplemented; case CP0_REG23__TRACECONTROL2: /* PDtrace support */ - /* gen_helper_mtc0_tracecontrol2(cpu_env, arg); */ + /* gen_helper_mtc0_tracecontrol2(tcg_env, arg); */ /* Stop translation as we may have switched the execution mode */ ctx->base.is_jmp = DISAS_STOP; register_name = "TraceControl2"; goto cp0_unimplemented; case CP0_REG23__USERTRACEDATA1: /* PDtrace support */ - /* gen_helper_mtc0_usertracedata1(cpu_env, arg);*/ + /* gen_helper_mtc0_usertracedata1(tcg_env, arg);*/ /* Stop translation as we may have switched the execution mode */ ctx->base.is_jmp = DISAS_STOP; register_name = "UserTraceData1"; goto cp0_unimplemented; case CP0_REG23__TRACEIBPC: /* PDtrace support */ - /* gen_helper_mtc0_traceibpc(cpu_env, arg); */ + /* gen_helper_mtc0_traceibpc(tcg_env, arg); */ /* Stop translation as we may have switched the execution mode */ ctx->base.is_jmp = DISAS_STOP; register_name = "TraceIBPC"; goto cp0_unimplemented; case CP0_REG23__TRACEDBPC: /* PDtrace support */ - /* gen_helper_mtc0_tracedbpc(cpu_env, arg); */ + /* gen_helper_mtc0_tracedbpc(tcg_env, arg); */ /* Stop translation as we may have switched the execution mode */ ctx->base.is_jmp = DISAS_STOP; register_name = "TraceDBPC"; @@ -8179,7 +8179,7 @@ static void gen_dmtc0(DisasContext *ctx, TCGv arg, int reg, int sel) switch (sel) { case CP0_REG24__DEPC: /* EJTAG support */ - tcg_gen_st_tl(arg, cpu_env, offsetof(CPUMIPSState, CP0_DEPC)); + tcg_gen_st_tl(arg, tcg_env, offsetof(CPUMIPSState, CP0_DEPC)); register_name = "DEPC"; break; default: @@ -8189,35 +8189,35 @@ static void gen_dmtc0(DisasContext *ctx, TCGv arg, int reg, int sel) case CP0_REGISTER_25: switch (sel) { case CP0_REG25__PERFCTL0: - gen_helper_mtc0_performance0(cpu_env, arg); + gen_helper_mtc0_performance0(tcg_env, arg); register_name = "Performance0"; break; case CP0_REG25__PERFCNT0: - /* gen_helper_mtc0_performance1(cpu_env, arg); */ + /* gen_helper_mtc0_performance1(tcg_env, arg); */ register_name = "Performance1"; goto cp0_unimplemented; case CP0_REG25__PERFCTL1: - /* gen_helper_mtc0_performance2(cpu_env, arg); */ + /* gen_helper_mtc0_performance2(tcg_env, arg); */ register_name = "Performance2"; goto cp0_unimplemented; case CP0_REG25__PERFCNT1: - /* gen_helper_mtc0_performance3(cpu_env, arg); */ + /* gen_helper_mtc0_performance3(tcg_env, arg); */ register_name = "Performance3"; goto cp0_unimplemented; case CP0_REG25__PERFCTL2: - /* gen_helper_mtc0_performance4(cpu_env, arg); */ + /* gen_helper_mtc0_performance4(tcg_env, arg); */ register_name = "Performance4"; goto cp0_unimplemented; case CP0_REG25__PERFCNT2: - /* gen_helper_mtc0_performance5(cpu_env, arg); */ + /* gen_helper_mtc0_performance5(tcg_env, arg); */ register_name = "Performance5"; goto cp0_unimplemented; case CP0_REG25__PERFCTL3: - /* gen_helper_mtc0_performance6(cpu_env, arg); */ + /* gen_helper_mtc0_performance6(tcg_env, arg); */ register_name = "Performance6"; goto cp0_unimplemented; case CP0_REG25__PERFCNT3: - /* gen_helper_mtc0_performance7(cpu_env, arg); */ + /* gen_helper_mtc0_performance7(tcg_env, arg); */ register_name = "Performance7"; goto cp0_unimplemented; default: @@ -8227,7 +8227,7 @@ static void gen_dmtc0(DisasContext *ctx, TCGv arg, int reg, int sel) case CP0_REGISTER_26: switch (sel) { case CP0_REG26__ERRCTL: - gen_helper_mtc0_errctl(cpu_env, arg); + gen_helper_mtc0_errctl(tcg_env, arg); ctx->base.is_jmp = DISAS_STOP; register_name = "ErrCtl"; break; @@ -8251,14 +8251,14 @@ static void gen_dmtc0(DisasContext *ctx, TCGv arg, int reg, int sel) case CP0_REG28__TAGLO1: case CP0_REG28__TAGLO2: case CP0_REG28__TAGLO3: - gen_helper_mtc0_taglo(cpu_env, arg); + gen_helper_mtc0_taglo(tcg_env, arg); register_name = "TagLo"; break; case CP0_REG28__DATALO: case CP0_REG28__DATALO1: case CP0_REG28__DATALO2: case CP0_REG28__DATALO3: - gen_helper_mtc0_datalo(cpu_env, arg); + gen_helper_mtc0_datalo(tcg_env, arg); register_name = "DataLo"; break; default: @@ -8271,14 +8271,14 @@ static void gen_dmtc0(DisasContext *ctx, TCGv arg, int reg, int sel) case CP0_REG29__TAGHI1: case CP0_REG29__TAGHI2: case CP0_REG29__TAGHI3: - gen_helper_mtc0_taghi(cpu_env, arg); + gen_helper_mtc0_taghi(tcg_env, arg); register_name = "TagHi"; break; case CP0_REG29__DATAHI: case CP0_REG29__DATAHI1: case CP0_REG29__DATAHI2: case CP0_REG29__DATAHI3: - gen_helper_mtc0_datahi(cpu_env, arg); + gen_helper_mtc0_datahi(tcg_env, arg); register_name = "DataHi"; break; default: @@ -8289,7 +8289,7 @@ static void gen_dmtc0(DisasContext *ctx, TCGv arg, int reg, int sel) case CP0_REGISTER_30: switch (sel) { case CP0_REG30__ERROREPC: - tcg_gen_st_tl(arg, cpu_env, offsetof(CPUMIPSState, CP0_ErrorEPC)); + tcg_gen_st_tl(arg, tcg_env, offsetof(CPUMIPSState, CP0_ErrorEPC)); register_name = "ErrorEPC"; break; default: @@ -8310,7 +8310,7 @@ static void gen_dmtc0(DisasContext *ctx, TCGv arg, int reg, int sel) case CP0_REG31__KSCRATCH5: case CP0_REG31__KSCRATCH6: CP0_CHECK(ctx->kscrexist & (1 << sel)); - tcg_gen_st_tl(arg, cpu_env, + tcg_gen_st_tl(arg, tcg_env, offsetof(CPUMIPSState, CP0_KScratch[sel - 2])); register_name = "KScratch"; break; @@ -8358,10 +8358,10 @@ static void gen_mftr(CPUMIPSState *env, DisasContext *ctx, int rt, int rd, case 1: switch (sel) { case 1: - gen_helper_mftc0_vpecontrol(t0, cpu_env); + gen_helper_mftc0_vpecontrol(t0, tcg_env); break; case 2: - gen_helper_mftc0_vpeconf0(t0, cpu_env); + gen_helper_mftc0_vpeconf0(t0, tcg_env); break; default: goto die; @@ -8371,25 +8371,25 @@ static void gen_mftr(CPUMIPSState *env, DisasContext *ctx, int rt, int rd, case 2: switch (sel) { case 1: - gen_helper_mftc0_tcstatus(t0, cpu_env); + gen_helper_mftc0_tcstatus(t0, tcg_env); break; case 2: - gen_helper_mftc0_tcbind(t0, cpu_env); + gen_helper_mftc0_tcbind(t0, tcg_env); break; case 3: - gen_helper_mftc0_tcrestart(t0, cpu_env); + gen_helper_mftc0_tcrestart(t0, tcg_env); break; case 4: - gen_helper_mftc0_tchalt(t0, cpu_env); + gen_helper_mftc0_tchalt(t0, tcg_env); break; case 5: - gen_helper_mftc0_tccontext(t0, cpu_env); + gen_helper_mftc0_tccontext(t0, tcg_env); break; case 6: - gen_helper_mftc0_tcschedule(t0, cpu_env); + gen_helper_mftc0_tcschedule(t0, tcg_env); break; case 7: - gen_helper_mftc0_tcschefback(t0, cpu_env); + gen_helper_mftc0_tcschefback(t0, tcg_env); break; default: gen_mfc0(ctx, t0, rt, sel); @@ -8399,7 +8399,7 @@ static void gen_mftr(CPUMIPSState *env, DisasContext *ctx, int rt, int rd, case 10: switch (sel) { case 0: - gen_helper_mftc0_entryhi(t0, cpu_env); + gen_helper_mftc0_entryhi(t0, tcg_env); break; default: gen_mfc0(ctx, t0, rt, sel); @@ -8409,7 +8409,7 @@ static void gen_mftr(CPUMIPSState *env, DisasContext *ctx, int rt, int rd, case 12: switch (sel) { case 0: - gen_helper_mftc0_status(t0, cpu_env); + gen_helper_mftc0_status(t0, tcg_env); break; default: gen_mfc0(ctx, t0, rt, sel); @@ -8419,7 +8419,7 @@ static void gen_mftr(CPUMIPSState *env, DisasContext *ctx, int rt, int rd, case 13: switch (sel) { case 0: - gen_helper_mftc0_cause(t0, cpu_env); + gen_helper_mftc0_cause(t0, tcg_env); break; default: goto die; @@ -8429,7 +8429,7 @@ static void gen_mftr(CPUMIPSState *env, DisasContext *ctx, int rt, int rd, case 14: switch (sel) { case 0: - gen_helper_mftc0_epc(t0, cpu_env); + gen_helper_mftc0_epc(t0, tcg_env); break; default: goto die; @@ -8439,7 +8439,7 @@ static void gen_mftr(CPUMIPSState *env, DisasContext *ctx, int rt, int rd, case 15: switch (sel) { case 1: - gen_helper_mftc0_ebase(t0, cpu_env); + gen_helper_mftc0_ebase(t0, tcg_env); break; default: goto die; @@ -8456,7 +8456,7 @@ static void gen_mftr(CPUMIPSState *env, DisasContext *ctx, int rt, int rd, case 5: case 6: case 7: - gen_helper_mftc0_configx(t0, cpu_env, tcg_constant_tl(sel)); + gen_helper_mftc0_configx(t0, tcg_env, tcg_constant_tl(sel)); break; default: goto die; @@ -8466,7 +8466,7 @@ static void gen_mftr(CPUMIPSState *env, DisasContext *ctx, int rt, int rd, case 23: switch (sel) { case 0: - gen_helper_mftc0_debug(t0, cpu_env); + gen_helper_mftc0_debug(t0, tcg_env); break; default: gen_mfc0(ctx, t0, rt, sel); @@ -8522,7 +8522,7 @@ static void gen_mftr(CPUMIPSState *env, DisasContext *ctx, int rt, int rd, gen_helper_1e0i(mftacx, t0, 3); break; case 16: - gen_helper_mftdsp(t0, cpu_env); + gen_helper_mftdsp(t0, tcg_env); break; default: goto die; @@ -8585,10 +8585,10 @@ static void gen_mttr(CPUMIPSState *env, DisasContext *ctx, int rd, int rt, case 1: switch (sel) { case 1: - gen_helper_mttc0_vpecontrol(cpu_env, t0); + gen_helper_mttc0_vpecontrol(tcg_env, t0); break; case 2: - gen_helper_mttc0_vpeconf0(cpu_env, t0); + gen_helper_mttc0_vpeconf0(tcg_env, t0); break; default: goto die; @@ -8598,25 +8598,25 @@ static void gen_mttr(CPUMIPSState *env, DisasContext *ctx, int rd, int rt, case 2: switch (sel) { case 1: - gen_helper_mttc0_tcstatus(cpu_env, t0); + gen_helper_mttc0_tcstatus(tcg_env, t0); break; case 2: - gen_helper_mttc0_tcbind(cpu_env, t0); + gen_helper_mttc0_tcbind(tcg_env, t0); break; case 3: - gen_helper_mttc0_tcrestart(cpu_env, t0); + gen_helper_mttc0_tcrestart(tcg_env, t0); break; case 4: - gen_helper_mttc0_tchalt(cpu_env, t0); + gen_helper_mttc0_tchalt(tcg_env, t0); break; case 5: - gen_helper_mttc0_tccontext(cpu_env, t0); + gen_helper_mttc0_tccontext(tcg_env, t0); break; case 6: - gen_helper_mttc0_tcschedule(cpu_env, t0); + gen_helper_mttc0_tcschedule(tcg_env, t0); break; case 7: - gen_helper_mttc0_tcschefback(cpu_env, t0); + gen_helper_mttc0_tcschefback(tcg_env, t0); break; default: gen_mtc0(ctx, t0, rd, sel); @@ -8626,7 +8626,7 @@ static void gen_mttr(CPUMIPSState *env, DisasContext *ctx, int rd, int rt, case 10: switch (sel) { case 0: - gen_helper_mttc0_entryhi(cpu_env, t0); + gen_helper_mttc0_entryhi(tcg_env, t0); break; default: gen_mtc0(ctx, t0, rd, sel); @@ -8636,7 +8636,7 @@ static void gen_mttr(CPUMIPSState *env, DisasContext *ctx, int rd, int rt, case 12: switch (sel) { case 0: - gen_helper_mttc0_status(cpu_env, t0); + gen_helper_mttc0_status(tcg_env, t0); break; default: gen_mtc0(ctx, t0, rd, sel); @@ -8646,7 +8646,7 @@ static void gen_mttr(CPUMIPSState *env, DisasContext *ctx, int rd, int rt, case 13: switch (sel) { case 0: - gen_helper_mttc0_cause(cpu_env, t0); + gen_helper_mttc0_cause(tcg_env, t0); break; default: goto die; @@ -8656,7 +8656,7 @@ static void gen_mttr(CPUMIPSState *env, DisasContext *ctx, int rd, int rt, case 15: switch (sel) { case 1: - gen_helper_mttc0_ebase(cpu_env, t0); + gen_helper_mttc0_ebase(tcg_env, t0); break; default: goto die; @@ -8666,7 +8666,7 @@ static void gen_mttr(CPUMIPSState *env, DisasContext *ctx, int rd, int rt, case 23: switch (sel) { case 0: - gen_helper_mttc0_debug(cpu_env, t0); + gen_helper_mttc0_debug(tcg_env, t0); break; default: gen_mtc0(ctx, t0, rd, sel); @@ -8722,7 +8722,7 @@ static void gen_mttr(CPUMIPSState *env, DisasContext *ctx, int rd, int rt, gen_helper_0e1i(mttacx, t0, 3); break; case 16: - gen_helper_mttdsp(cpu_env, t0); + gen_helper_mttdsp(tcg_env, t0); break; default: goto die; @@ -8849,7 +8849,7 @@ static void gen_cp0(CPUMIPSState *env, DisasContext *ctx, uint32_t opc, if (!env->tlb->helper_tlbwi) { goto die; } - gen_helper_tlbwi(cpu_env); + gen_helper_tlbwi(tcg_env); break; case OPC_TLBINV: opn = "tlbinv"; @@ -8857,7 +8857,7 @@ static void gen_cp0(CPUMIPSState *env, DisasContext *ctx, uint32_t opc, if (!env->tlb->helper_tlbinv) { goto die; } - gen_helper_tlbinv(cpu_env); + gen_helper_tlbinv(tcg_env); } /* treat as nop if TLBINV not supported */ break; case OPC_TLBINVF: @@ -8866,7 +8866,7 @@ static void gen_cp0(CPUMIPSState *env, DisasContext *ctx, uint32_t opc, if (!env->tlb->helper_tlbinvf) { goto die; } - gen_helper_tlbinvf(cpu_env); + gen_helper_tlbinvf(tcg_env); } /* treat as nop if TLBINV not supported */ break; case OPC_TLBWR: @@ -8874,21 +8874,21 @@ static void gen_cp0(CPUMIPSState *env, DisasContext *ctx, uint32_t opc, if (!env->tlb->helper_tlbwr) { goto die; } - gen_helper_tlbwr(cpu_env); + gen_helper_tlbwr(tcg_env); break; case OPC_TLBP: opn = "tlbp"; if (!env->tlb->helper_tlbp) { goto die; } - gen_helper_tlbp(cpu_env); + gen_helper_tlbp(tcg_env); break; case OPC_TLBR: opn = "tlbr"; if (!env->tlb->helper_tlbr) { goto die; } - gen_helper_tlbr(cpu_env); + gen_helper_tlbr(tcg_env); break; case OPC_ERET: /* OPC_ERETNC */ if ((ctx->insn_flags & ISA_MIPS_R6) && @@ -8900,12 +8900,12 @@ static void gen_cp0(CPUMIPSState *env, DisasContext *ctx, uint32_t opc, /* OPC_ERETNC */ opn = "eretnc"; check_insn(ctx, ISA_MIPS_R5); - gen_helper_eretnc(cpu_env); + gen_helper_eretnc(tcg_env); } else { /* OPC_ERET */ opn = "eret"; check_insn(ctx, ISA_MIPS2); - gen_helper_eret(cpu_env); + gen_helper_eret(tcg_env); } ctx->base.is_jmp = DISAS_EXIT; } @@ -8921,7 +8921,7 @@ static void gen_cp0(CPUMIPSState *env, DisasContext *ctx, uint32_t opc, MIPS_INVAL(opn); gen_reserved_instruction(ctx); } else { - gen_helper_deret(cpu_env); + gen_helper_deret(tcg_env); ctx->base.is_jmp = DISAS_EXIT; } break; @@ -8936,7 +8936,7 @@ static void gen_cp0(CPUMIPSState *env, DisasContext *ctx, uint32_t opc, ctx->base.pc_next += 4; save_cpu_state(ctx, 1); ctx->base.pc_next -= 4; - gen_helper_wait(cpu_env); + gen_helper_wait(tcg_env); ctx->base.is_jmp = DISAS_NORETURN; break; default: @@ -9557,7 +9557,7 @@ static void gen_farith(DisasContext *ctx, enum fopcode op1, gen_load_fpr32(ctx, fp0, fs); gen_load_fpr32(ctx, fp1, ft); - gen_helper_float_add_s(fp0, cpu_env, fp0, fp1); + gen_helper_float_add_s(fp0, tcg_env, fp0, fp1); gen_store_fpr32(ctx, fp0, fd); } break; @@ -9568,7 +9568,7 @@ static void gen_farith(DisasContext *ctx, enum fopcode op1, gen_load_fpr32(ctx, fp0, fs); gen_load_fpr32(ctx, fp1, ft); - gen_helper_float_sub_s(fp0, cpu_env, fp0, fp1); + gen_helper_float_sub_s(fp0, tcg_env, fp0, fp1); gen_store_fpr32(ctx, fp0, fd); } break; @@ -9579,7 +9579,7 @@ static void gen_farith(DisasContext *ctx, enum fopcode op1, gen_load_fpr32(ctx, fp0, fs); gen_load_fpr32(ctx, fp1, ft); - gen_helper_float_mul_s(fp0, cpu_env, fp0, fp1); + gen_helper_float_mul_s(fp0, tcg_env, fp0, fp1); gen_store_fpr32(ctx, fp0, fd); } break; @@ -9590,7 +9590,7 @@ static void gen_farith(DisasContext *ctx, enum fopcode op1, gen_load_fpr32(ctx, fp0, fs); gen_load_fpr32(ctx, fp1, ft); - gen_helper_float_div_s(fp0, cpu_env, fp0, fp1); + gen_helper_float_div_s(fp0, tcg_env, fp0, fp1); gen_store_fpr32(ctx, fp0, fd); } break; @@ -9599,7 +9599,7 @@ static void gen_farith(DisasContext *ctx, enum fopcode op1, TCGv_i32 fp0 = tcg_temp_new_i32(); gen_load_fpr32(ctx, fp0, fs); - gen_helper_float_sqrt_s(fp0, cpu_env, fp0); + gen_helper_float_sqrt_s(fp0, tcg_env, fp0); gen_store_fpr32(ctx, fp0, fd); } break; @@ -9645,9 +9645,9 @@ static void gen_farith(DisasContext *ctx, enum fopcode op1, gen_load_fpr32(ctx, fp32, fs); if (ctx->nan2008) { - gen_helper_float_round_2008_l_s(fp64, cpu_env, fp32); + gen_helper_float_round_2008_l_s(fp64, tcg_env, fp32); } else { - gen_helper_float_round_l_s(fp64, cpu_env, fp32); + gen_helper_float_round_l_s(fp64, tcg_env, fp32); } gen_store_fpr64(ctx, fp64, fd); } @@ -9660,9 +9660,9 @@ static void gen_farith(DisasContext *ctx, enum fopcode op1, gen_load_fpr32(ctx, fp32, fs); if (ctx->nan2008) { - gen_helper_float_trunc_2008_l_s(fp64, cpu_env, fp32); + gen_helper_float_trunc_2008_l_s(fp64, tcg_env, fp32); } else { - gen_helper_float_trunc_l_s(fp64, cpu_env, fp32); + gen_helper_float_trunc_l_s(fp64, tcg_env, fp32); } gen_store_fpr64(ctx, fp64, fd); } @@ -9675,9 +9675,9 @@ static void gen_farith(DisasContext *ctx, enum fopcode op1, gen_load_fpr32(ctx, fp32, fs); if (ctx->nan2008) { - gen_helper_float_ceil_2008_l_s(fp64, cpu_env, fp32); + gen_helper_float_ceil_2008_l_s(fp64, tcg_env, fp32); } else { - gen_helper_float_ceil_l_s(fp64, cpu_env, fp32); + gen_helper_float_ceil_l_s(fp64, tcg_env, fp32); } gen_store_fpr64(ctx, fp64, fd); } @@ -9690,9 +9690,9 @@ static void gen_farith(DisasContext *ctx, enum fopcode op1, gen_load_fpr32(ctx, fp32, fs); if (ctx->nan2008) { - gen_helper_float_floor_2008_l_s(fp64, cpu_env, fp32); + gen_helper_float_floor_2008_l_s(fp64, tcg_env, fp32); } else { - gen_helper_float_floor_l_s(fp64, cpu_env, fp32); + gen_helper_float_floor_l_s(fp64, tcg_env, fp32); } gen_store_fpr64(ctx, fp64, fd); } @@ -9703,9 +9703,9 @@ static void gen_farith(DisasContext *ctx, enum fopcode op1, gen_load_fpr32(ctx, fp0, fs); if (ctx->nan2008) { - gen_helper_float_round_2008_w_s(fp0, cpu_env, fp0); + gen_helper_float_round_2008_w_s(fp0, tcg_env, fp0); } else { - gen_helper_float_round_w_s(fp0, cpu_env, fp0); + gen_helper_float_round_w_s(fp0, tcg_env, fp0); } gen_store_fpr32(ctx, fp0, fd); } @@ -9716,9 +9716,9 @@ static void gen_farith(DisasContext *ctx, enum fopcode op1, gen_load_fpr32(ctx, fp0, fs); if (ctx->nan2008) { - gen_helper_float_trunc_2008_w_s(fp0, cpu_env, fp0); + gen_helper_float_trunc_2008_w_s(fp0, tcg_env, fp0); } else { - gen_helper_float_trunc_w_s(fp0, cpu_env, fp0); + gen_helper_float_trunc_w_s(fp0, tcg_env, fp0); } gen_store_fpr32(ctx, fp0, fd); } @@ -9729,9 +9729,9 @@ static void gen_farith(DisasContext *ctx, enum fopcode op1, gen_load_fpr32(ctx, fp0, fs); if (ctx->nan2008) { - gen_helper_float_ceil_2008_w_s(fp0, cpu_env, fp0); + gen_helper_float_ceil_2008_w_s(fp0, tcg_env, fp0); } else { - gen_helper_float_ceil_w_s(fp0, cpu_env, fp0); + gen_helper_float_ceil_w_s(fp0, tcg_env, fp0); } gen_store_fpr32(ctx, fp0, fd); } @@ -9742,9 +9742,9 @@ static void gen_farith(DisasContext *ctx, enum fopcode op1, gen_load_fpr32(ctx, fp0, fs); if (ctx->nan2008) { - gen_helper_float_floor_2008_w_s(fp0, cpu_env, fp0); + gen_helper_float_floor_2008_w_s(fp0, tcg_env, fp0); } else { - gen_helper_float_floor_w_s(fp0, cpu_env, fp0); + gen_helper_float_floor_w_s(fp0, tcg_env, fp0); } gen_store_fpr32(ctx, fp0, fd); } @@ -9800,7 +9800,7 @@ static void gen_farith(DisasContext *ctx, enum fopcode op1, TCGv_i32 fp0 = tcg_temp_new_i32(); gen_load_fpr32(ctx, fp0, fs); - gen_helper_float_recip_s(fp0, cpu_env, fp0); + gen_helper_float_recip_s(fp0, tcg_env, fp0); gen_store_fpr32(ctx, fp0, fd); } break; @@ -9809,7 +9809,7 @@ static void gen_farith(DisasContext *ctx, enum fopcode op1, TCGv_i32 fp0 = tcg_temp_new_i32(); gen_load_fpr32(ctx, fp0, fs); - gen_helper_float_rsqrt_s(fp0, cpu_env, fp0); + gen_helper_float_rsqrt_s(fp0, tcg_env, fp0); gen_store_fpr32(ctx, fp0, fd); } break; @@ -9822,7 +9822,7 @@ static void gen_farith(DisasContext *ctx, enum fopcode op1, gen_load_fpr32(ctx, fp0, fs); gen_load_fpr32(ctx, fp1, ft); gen_load_fpr32(ctx, fp2, fd); - gen_helper_float_maddf_s(fp2, cpu_env, fp0, fp1, fp2); + gen_helper_float_maddf_s(fp2, tcg_env, fp0, fp1, fp2); gen_store_fpr32(ctx, fp2, fd); } break; @@ -9835,7 +9835,7 @@ static void gen_farith(DisasContext *ctx, enum fopcode op1, gen_load_fpr32(ctx, fp0, fs); gen_load_fpr32(ctx, fp1, ft); gen_load_fpr32(ctx, fp2, fd); - gen_helper_float_msubf_s(fp2, cpu_env, fp0, fp1, fp2); + gen_helper_float_msubf_s(fp2, tcg_env, fp0, fp1, fp2); gen_store_fpr32(ctx, fp2, fd); } break; @@ -9844,7 +9844,7 @@ static void gen_farith(DisasContext *ctx, enum fopcode op1, { TCGv_i32 fp0 = tcg_temp_new_i32(); gen_load_fpr32(ctx, fp0, fs); - gen_helper_float_rint_s(fp0, cpu_env, fp0); + gen_helper_float_rint_s(fp0, tcg_env, fp0); gen_store_fpr32(ctx, fp0, fd); } break; @@ -9853,7 +9853,7 @@ static void gen_farith(DisasContext *ctx, enum fopcode op1, { TCGv_i32 fp0 = tcg_temp_new_i32(); gen_load_fpr32(ctx, fp0, fs); - gen_helper_float_class_s(fp0, cpu_env, fp0); + gen_helper_float_class_s(fp0, tcg_env, fp0); gen_store_fpr32(ctx, fp0, fd); } break; @@ -9865,7 +9865,7 @@ static void gen_farith(DisasContext *ctx, enum fopcode op1, TCGv_i32 fp2 = tcg_temp_new_i32(); gen_load_fpr32(ctx, fp0, fs); gen_load_fpr32(ctx, fp1, ft); - gen_helper_float_min_s(fp2, cpu_env, fp0, fp1); + gen_helper_float_min_s(fp2, tcg_env, fp0, fp1); gen_store_fpr32(ctx, fp2, fd); } else { /* OPC_RECIP2_S */ @@ -9876,7 +9876,7 @@ static void gen_farith(DisasContext *ctx, enum fopcode op1, gen_load_fpr32(ctx, fp0, fs); gen_load_fpr32(ctx, fp1, ft); - gen_helper_float_recip2_s(fp0, cpu_env, fp0, fp1); + gen_helper_float_recip2_s(fp0, tcg_env, fp0, fp1); gen_store_fpr32(ctx, fp0, fd); } } @@ -9889,7 +9889,7 @@ static void gen_farith(DisasContext *ctx, enum fopcode op1, TCGv_i32 fp2 = tcg_temp_new_i32(); gen_load_fpr32(ctx, fp0, fs); gen_load_fpr32(ctx, fp1, ft); - gen_helper_float_mina_s(fp2, cpu_env, fp0, fp1); + gen_helper_float_mina_s(fp2, tcg_env, fp0, fp1); gen_store_fpr32(ctx, fp2, fd); } else { /* OPC_RECIP1_S */ @@ -9898,7 +9898,7 @@ static void gen_farith(DisasContext *ctx, enum fopcode op1, TCGv_i32 fp0 = tcg_temp_new_i32(); gen_load_fpr32(ctx, fp0, fs); - gen_helper_float_recip1_s(fp0, cpu_env, fp0); + gen_helper_float_recip1_s(fp0, tcg_env, fp0); gen_store_fpr32(ctx, fp0, fd); } } @@ -9910,7 +9910,7 @@ static void gen_farith(DisasContext *ctx, enum fopcode op1, TCGv_i32 fp1 = tcg_temp_new_i32(); gen_load_fpr32(ctx, fp0, fs); gen_load_fpr32(ctx, fp1, ft); - gen_helper_float_max_s(fp1, cpu_env, fp0, fp1); + gen_helper_float_max_s(fp1, tcg_env, fp0, fp1); gen_store_fpr32(ctx, fp1, fd); } else { /* OPC_RSQRT1_S */ @@ -9919,7 +9919,7 @@ static void gen_farith(DisasContext *ctx, enum fopcode op1, TCGv_i32 fp0 = tcg_temp_new_i32(); gen_load_fpr32(ctx, fp0, fs); - gen_helper_float_rsqrt1_s(fp0, cpu_env, fp0); + gen_helper_float_rsqrt1_s(fp0, tcg_env, fp0); gen_store_fpr32(ctx, fp0, fd); } } @@ -9931,7 +9931,7 @@ static void gen_farith(DisasContext *ctx, enum fopcode op1, TCGv_i32 fp1 = tcg_temp_new_i32(); gen_load_fpr32(ctx, fp0, fs); gen_load_fpr32(ctx, fp1, ft); - gen_helper_float_maxa_s(fp1, cpu_env, fp0, fp1); + gen_helper_float_maxa_s(fp1, tcg_env, fp0, fp1); gen_store_fpr32(ctx, fp1, fd); } else { /* OPC_RSQRT2_S */ @@ -9942,7 +9942,7 @@ static void gen_farith(DisasContext *ctx, enum fopcode op1, gen_load_fpr32(ctx, fp0, fs); gen_load_fpr32(ctx, fp1, ft); - gen_helper_float_rsqrt2_s(fp0, cpu_env, fp0, fp1); + gen_helper_float_rsqrt2_s(fp0, tcg_env, fp0, fp1); gen_store_fpr32(ctx, fp0, fd); } } @@ -9954,7 +9954,7 @@ static void gen_farith(DisasContext *ctx, enum fopcode op1, TCGv_i64 fp64 = tcg_temp_new_i64(); gen_load_fpr32(ctx, fp32, fs); - gen_helper_float_cvtd_s(fp64, cpu_env, fp32); + gen_helper_float_cvtd_s(fp64, tcg_env, fp32); gen_store_fpr64(ctx, fp64, fd); } break; @@ -9964,9 +9964,9 @@ static void gen_farith(DisasContext *ctx, enum fopcode op1, gen_load_fpr32(ctx, fp0, fs); if (ctx->nan2008) { - gen_helper_float_cvt_2008_w_s(fp0, cpu_env, fp0); + gen_helper_float_cvt_2008_w_s(fp0, tcg_env, fp0); } else { - gen_helper_float_cvt_w_s(fp0, cpu_env, fp0); + gen_helper_float_cvt_w_s(fp0, tcg_env, fp0); } gen_store_fpr32(ctx, fp0, fd); } @@ -9979,9 +9979,9 @@ static void gen_farith(DisasContext *ctx, enum fopcode op1, gen_load_fpr32(ctx, fp32, fs); if (ctx->nan2008) { - gen_helper_float_cvt_2008_l_s(fp64, cpu_env, fp32); + gen_helper_float_cvt_2008_l_s(fp64, tcg_env, fp32); } else { - gen_helper_float_cvt_l_s(fp64, cpu_env, fp32); + gen_helper_float_cvt_l_s(fp64, tcg_env, fp32); } gen_store_fpr64(ctx, fp64, fd); } @@ -10030,7 +10030,7 @@ static void gen_farith(DisasContext *ctx, enum fopcode op1, gen_load_fpr64(ctx, fp0, fs); gen_load_fpr64(ctx, fp1, ft); - gen_helper_float_add_d(fp0, cpu_env, fp0, fp1); + gen_helper_float_add_d(fp0, tcg_env, fp0, fp1); gen_store_fpr64(ctx, fp0, fd); } break; @@ -10042,7 +10042,7 @@ static void gen_farith(DisasContext *ctx, enum fopcode op1, gen_load_fpr64(ctx, fp0, fs); gen_load_fpr64(ctx, fp1, ft); - gen_helper_float_sub_d(fp0, cpu_env, fp0, fp1); + gen_helper_float_sub_d(fp0, tcg_env, fp0, fp1); gen_store_fpr64(ctx, fp0, fd); } break; @@ -10054,7 +10054,7 @@ static void gen_farith(DisasContext *ctx, enum fopcode op1, gen_load_fpr64(ctx, fp0, fs); gen_load_fpr64(ctx, fp1, ft); - gen_helper_float_mul_d(fp0, cpu_env, fp0, fp1); + gen_helper_float_mul_d(fp0, tcg_env, fp0, fp1); gen_store_fpr64(ctx, fp0, fd); } break; @@ -10066,7 +10066,7 @@ static void gen_farith(DisasContext *ctx, enum fopcode op1, gen_load_fpr64(ctx, fp0, fs); gen_load_fpr64(ctx, fp1, ft); - gen_helper_float_div_d(fp0, cpu_env, fp0, fp1); + gen_helper_float_div_d(fp0, tcg_env, fp0, fp1); gen_store_fpr64(ctx, fp0, fd); } break; @@ -10076,7 +10076,7 @@ static void gen_farith(DisasContext *ctx, enum fopcode op1, TCGv_i64 fp0 = tcg_temp_new_i64(); gen_load_fpr64(ctx, fp0, fs); - gen_helper_float_sqrt_d(fp0, cpu_env, fp0); + gen_helper_float_sqrt_d(fp0, tcg_env, fp0); gen_store_fpr64(ctx, fp0, fd); } break; @@ -10124,9 +10124,9 @@ static void gen_farith(DisasContext *ctx, enum fopcode op1, gen_load_fpr64(ctx, fp0, fs); if (ctx->nan2008) { - gen_helper_float_round_2008_l_d(fp0, cpu_env, fp0); + gen_helper_float_round_2008_l_d(fp0, tcg_env, fp0); } else { - gen_helper_float_round_l_d(fp0, cpu_env, fp0); + gen_helper_float_round_l_d(fp0, tcg_env, fp0); } gen_store_fpr64(ctx, fp0, fd); } @@ -10138,9 +10138,9 @@ static void gen_farith(DisasContext *ctx, enum fopcode op1, gen_load_fpr64(ctx, fp0, fs); if (ctx->nan2008) { - gen_helper_float_trunc_2008_l_d(fp0, cpu_env, fp0); + gen_helper_float_trunc_2008_l_d(fp0, tcg_env, fp0); } else { - gen_helper_float_trunc_l_d(fp0, cpu_env, fp0); + gen_helper_float_trunc_l_d(fp0, tcg_env, fp0); } gen_store_fpr64(ctx, fp0, fd); } @@ -10152,9 +10152,9 @@ static void gen_farith(DisasContext *ctx, enum fopcode op1, gen_load_fpr64(ctx, fp0, fs); if (ctx->nan2008) { - gen_helper_float_ceil_2008_l_d(fp0, cpu_env, fp0); + gen_helper_float_ceil_2008_l_d(fp0, tcg_env, fp0); } else { - gen_helper_float_ceil_l_d(fp0, cpu_env, fp0); + gen_helper_float_ceil_l_d(fp0, tcg_env, fp0); } gen_store_fpr64(ctx, fp0, fd); } @@ -10166,9 +10166,9 @@ static void gen_farith(DisasContext *ctx, enum fopcode op1, gen_load_fpr64(ctx, fp0, fs); if (ctx->nan2008) { - gen_helper_float_floor_2008_l_d(fp0, cpu_env, fp0); + gen_helper_float_floor_2008_l_d(fp0, tcg_env, fp0); } else { - gen_helper_float_floor_l_d(fp0, cpu_env, fp0); + gen_helper_float_floor_l_d(fp0, tcg_env, fp0); } gen_store_fpr64(ctx, fp0, fd); } @@ -10181,9 +10181,9 @@ static void gen_farith(DisasContext *ctx, enum fopcode op1, gen_load_fpr64(ctx, fp64, fs); if (ctx->nan2008) { - gen_helper_float_round_2008_w_d(fp32, cpu_env, fp64); + gen_helper_float_round_2008_w_d(fp32, tcg_env, fp64); } else { - gen_helper_float_round_w_d(fp32, cpu_env, fp64); + gen_helper_float_round_w_d(fp32, tcg_env, fp64); } gen_store_fpr32(ctx, fp32, fd); } @@ -10196,9 +10196,9 @@ static void gen_farith(DisasContext *ctx, enum fopcode op1, gen_load_fpr64(ctx, fp64, fs); if (ctx->nan2008) { - gen_helper_float_trunc_2008_w_d(fp32, cpu_env, fp64); + gen_helper_float_trunc_2008_w_d(fp32, tcg_env, fp64); } else { - gen_helper_float_trunc_w_d(fp32, cpu_env, fp64); + gen_helper_float_trunc_w_d(fp32, tcg_env, fp64); } gen_store_fpr32(ctx, fp32, fd); } @@ -10211,9 +10211,9 @@ static void gen_farith(DisasContext *ctx, enum fopcode op1, gen_load_fpr64(ctx, fp64, fs); if (ctx->nan2008) { - gen_helper_float_ceil_2008_w_d(fp32, cpu_env, fp64); + gen_helper_float_ceil_2008_w_d(fp32, tcg_env, fp64); } else { - gen_helper_float_ceil_w_d(fp32, cpu_env, fp64); + gen_helper_float_ceil_w_d(fp32, tcg_env, fp64); } gen_store_fpr32(ctx, fp32, fd); } @@ -10226,9 +10226,9 @@ static void gen_farith(DisasContext *ctx, enum fopcode op1, gen_load_fpr64(ctx, fp64, fs); if (ctx->nan2008) { - gen_helper_float_floor_2008_w_d(fp32, cpu_env, fp64); + gen_helper_float_floor_2008_w_d(fp32, tcg_env, fp64); } else { - gen_helper_float_floor_w_d(fp32, cpu_env, fp64); + gen_helper_float_floor_w_d(fp32, tcg_env, fp64); } gen_store_fpr32(ctx, fp32, fd); } @@ -10285,7 +10285,7 @@ static void gen_farith(DisasContext *ctx, enum fopcode op1, TCGv_i64 fp0 = tcg_temp_new_i64(); gen_load_fpr64(ctx, fp0, fs); - gen_helper_float_recip_d(fp0, cpu_env, fp0); + gen_helper_float_recip_d(fp0, tcg_env, fp0); gen_store_fpr64(ctx, fp0, fd); } break; @@ -10295,7 +10295,7 @@ static void gen_farith(DisasContext *ctx, enum fopcode op1, TCGv_i64 fp0 = tcg_temp_new_i64(); gen_load_fpr64(ctx, fp0, fs); - gen_helper_float_rsqrt_d(fp0, cpu_env, fp0); + gen_helper_float_rsqrt_d(fp0, tcg_env, fp0); gen_store_fpr64(ctx, fp0, fd); } break; @@ -10308,7 +10308,7 @@ static void gen_farith(DisasContext *ctx, enum fopcode op1, gen_load_fpr64(ctx, fp0, fs); gen_load_fpr64(ctx, fp1, ft); gen_load_fpr64(ctx, fp2, fd); - gen_helper_float_maddf_d(fp2, cpu_env, fp0, fp1, fp2); + gen_helper_float_maddf_d(fp2, tcg_env, fp0, fp1, fp2); gen_store_fpr64(ctx, fp2, fd); } break; @@ -10321,7 +10321,7 @@ static void gen_farith(DisasContext *ctx, enum fopcode op1, gen_load_fpr64(ctx, fp0, fs); gen_load_fpr64(ctx, fp1, ft); gen_load_fpr64(ctx, fp2, fd); - gen_helper_float_msubf_d(fp2, cpu_env, fp0, fp1, fp2); + gen_helper_float_msubf_d(fp2, tcg_env, fp0, fp1, fp2); gen_store_fpr64(ctx, fp2, fd); } break; @@ -10330,7 +10330,7 @@ static void gen_farith(DisasContext *ctx, enum fopcode op1, { TCGv_i64 fp0 = tcg_temp_new_i64(); gen_load_fpr64(ctx, fp0, fs); - gen_helper_float_rint_d(fp0, cpu_env, fp0); + gen_helper_float_rint_d(fp0, tcg_env, fp0); gen_store_fpr64(ctx, fp0, fd); } break; @@ -10339,7 +10339,7 @@ static void gen_farith(DisasContext *ctx, enum fopcode op1, { TCGv_i64 fp0 = tcg_temp_new_i64(); gen_load_fpr64(ctx, fp0, fs); - gen_helper_float_class_d(fp0, cpu_env, fp0); + gen_helper_float_class_d(fp0, tcg_env, fp0); gen_store_fpr64(ctx, fp0, fd); } break; @@ -10350,7 +10350,7 @@ static void gen_farith(DisasContext *ctx, enum fopcode op1, TCGv_i64 fp1 = tcg_temp_new_i64(); gen_load_fpr64(ctx, fp0, fs); gen_load_fpr64(ctx, fp1, ft); - gen_helper_float_min_d(fp1, cpu_env, fp0, fp1); + gen_helper_float_min_d(fp1, tcg_env, fp0, fp1); gen_store_fpr64(ctx, fp1, fd); } else { /* OPC_RECIP2_D */ @@ -10361,7 +10361,7 @@ static void gen_farith(DisasContext *ctx, enum fopcode op1, gen_load_fpr64(ctx, fp0, fs); gen_load_fpr64(ctx, fp1, ft); - gen_helper_float_recip2_d(fp0, cpu_env, fp0, fp1); + gen_helper_float_recip2_d(fp0, tcg_env, fp0, fp1); gen_store_fpr64(ctx, fp0, fd); } } @@ -10373,7 +10373,7 @@ static void gen_farith(DisasContext *ctx, enum fopcode op1, TCGv_i64 fp1 = tcg_temp_new_i64(); gen_load_fpr64(ctx, fp0, fs); gen_load_fpr64(ctx, fp1, ft); - gen_helper_float_mina_d(fp1, cpu_env, fp0, fp1); + gen_helper_float_mina_d(fp1, tcg_env, fp0, fp1); gen_store_fpr64(ctx, fp1, fd); } else { /* OPC_RECIP1_D */ @@ -10382,7 +10382,7 @@ static void gen_farith(DisasContext *ctx, enum fopcode op1, TCGv_i64 fp0 = tcg_temp_new_i64(); gen_load_fpr64(ctx, fp0, fs); - gen_helper_float_recip1_d(fp0, cpu_env, fp0); + gen_helper_float_recip1_d(fp0, tcg_env, fp0); gen_store_fpr64(ctx, fp0, fd); } } @@ -10394,7 +10394,7 @@ static void gen_farith(DisasContext *ctx, enum fopcode op1, TCGv_i64 fp1 = tcg_temp_new_i64(); gen_load_fpr64(ctx, fp0, fs); gen_load_fpr64(ctx, fp1, ft); - gen_helper_float_max_d(fp1, cpu_env, fp0, fp1); + gen_helper_float_max_d(fp1, tcg_env, fp0, fp1); gen_store_fpr64(ctx, fp1, fd); } else { /* OPC_RSQRT1_D */ @@ -10403,7 +10403,7 @@ static void gen_farith(DisasContext *ctx, enum fopcode op1, TCGv_i64 fp0 = tcg_temp_new_i64(); gen_load_fpr64(ctx, fp0, fs); - gen_helper_float_rsqrt1_d(fp0, cpu_env, fp0); + gen_helper_float_rsqrt1_d(fp0, tcg_env, fp0); gen_store_fpr64(ctx, fp0, fd); } } @@ -10415,7 +10415,7 @@ static void gen_farith(DisasContext *ctx, enum fopcode op1, TCGv_i64 fp1 = tcg_temp_new_i64(); gen_load_fpr64(ctx, fp0, fs); gen_load_fpr64(ctx, fp1, ft); - gen_helper_float_maxa_d(fp1, cpu_env, fp0, fp1); + gen_helper_float_maxa_d(fp1, tcg_env, fp0, fp1); gen_store_fpr64(ctx, fp1, fd); } else { /* OPC_RSQRT2_D */ @@ -10426,7 +10426,7 @@ static void gen_farith(DisasContext *ctx, enum fopcode op1, gen_load_fpr64(ctx, fp0, fs); gen_load_fpr64(ctx, fp1, ft); - gen_helper_float_rsqrt2_d(fp0, cpu_env, fp0, fp1); + gen_helper_float_rsqrt2_d(fp0, tcg_env, fp0, fp1); gen_store_fpr64(ctx, fp0, fd); } } @@ -10461,7 +10461,7 @@ static void gen_farith(DisasContext *ctx, enum fopcode op1, TCGv_i64 fp64 = tcg_temp_new_i64(); gen_load_fpr64(ctx, fp64, fs); - gen_helper_float_cvts_d(fp32, cpu_env, fp64); + gen_helper_float_cvts_d(fp32, tcg_env, fp64); gen_store_fpr32(ctx, fp32, fd); } break; @@ -10473,9 +10473,9 @@ static void gen_farith(DisasContext *ctx, enum fopcode op1, gen_load_fpr64(ctx, fp64, fs); if (ctx->nan2008) { - gen_helper_float_cvt_2008_w_d(fp32, cpu_env, fp64); + gen_helper_float_cvt_2008_w_d(fp32, tcg_env, fp64); } else { - gen_helper_float_cvt_w_d(fp32, cpu_env, fp64); + gen_helper_float_cvt_w_d(fp32, tcg_env, fp64); } gen_store_fpr32(ctx, fp32, fd); } @@ -10487,9 +10487,9 @@ static void gen_farith(DisasContext *ctx, enum fopcode op1, gen_load_fpr64(ctx, fp0, fs); if (ctx->nan2008) { - gen_helper_float_cvt_2008_l_d(fp0, cpu_env, fp0); + gen_helper_float_cvt_2008_l_d(fp0, tcg_env, fp0); } else { - gen_helper_float_cvt_l_d(fp0, cpu_env, fp0); + gen_helper_float_cvt_l_d(fp0, tcg_env, fp0); } gen_store_fpr64(ctx, fp0, fd); } @@ -10499,7 +10499,7 @@ static void gen_farith(DisasContext *ctx, enum fopcode op1, TCGv_i32 fp0 = tcg_temp_new_i32(); gen_load_fpr32(ctx, fp0, fs); - gen_helper_float_cvts_w(fp0, cpu_env, fp0); + gen_helper_float_cvts_w(fp0, tcg_env, fp0); gen_store_fpr32(ctx, fp0, fd); } break; @@ -10510,7 +10510,7 @@ static void gen_farith(DisasContext *ctx, enum fopcode op1, TCGv_i64 fp64 = tcg_temp_new_i64(); gen_load_fpr32(ctx, fp32, fs); - gen_helper_float_cvtd_w(fp64, cpu_env, fp32); + gen_helper_float_cvtd_w(fp64, tcg_env, fp32); gen_store_fpr64(ctx, fp64, fd); } break; @@ -10521,7 +10521,7 @@ static void gen_farith(DisasContext *ctx, enum fopcode op1, TCGv_i64 fp64 = tcg_temp_new_i64(); gen_load_fpr64(ctx, fp64, fs); - gen_helper_float_cvts_l(fp32, cpu_env, fp64); + gen_helper_float_cvts_l(fp32, tcg_env, fp64); gen_store_fpr32(ctx, fp32, fd); } break; @@ -10531,7 +10531,7 @@ static void gen_farith(DisasContext *ctx, enum fopcode op1, TCGv_i64 fp0 = tcg_temp_new_i64(); gen_load_fpr64(ctx, fp0, fs); - gen_helper_float_cvtd_l(fp0, cpu_env, fp0); + gen_helper_float_cvtd_l(fp0, tcg_env, fp0); gen_store_fpr64(ctx, fp0, fd); } break; @@ -10541,7 +10541,7 @@ static void gen_farith(DisasContext *ctx, enum fopcode op1, TCGv_i64 fp0 = tcg_temp_new_i64(); gen_load_fpr64(ctx, fp0, fs); - gen_helper_float_cvtps_pw(fp0, cpu_env, fp0); + gen_helper_float_cvtps_pw(fp0, tcg_env, fp0); gen_store_fpr64(ctx, fp0, fd); } break; @@ -10553,7 +10553,7 @@ static void gen_farith(DisasContext *ctx, enum fopcode op1, gen_load_fpr64(ctx, fp0, fs); gen_load_fpr64(ctx, fp1, ft); - gen_helper_float_add_ps(fp0, cpu_env, fp0, fp1); + gen_helper_float_add_ps(fp0, tcg_env, fp0, fp1); gen_store_fpr64(ctx, fp0, fd); } break; @@ -10565,7 +10565,7 @@ static void gen_farith(DisasContext *ctx, enum fopcode op1, gen_load_fpr64(ctx, fp0, fs); gen_load_fpr64(ctx, fp1, ft); - gen_helper_float_sub_ps(fp0, cpu_env, fp0, fp1); + gen_helper_float_sub_ps(fp0, tcg_env, fp0, fp1); gen_store_fpr64(ctx, fp0, fd); } break; @@ -10577,7 +10577,7 @@ static void gen_farith(DisasContext *ctx, enum fopcode op1, gen_load_fpr64(ctx, fp0, fs); gen_load_fpr64(ctx, fp1, ft); - gen_helper_float_mul_ps(fp0, cpu_env, fp0, fp1); + gen_helper_float_mul_ps(fp0, tcg_env, fp0, fp1); gen_store_fpr64(ctx, fp0, fd); } break; @@ -10652,7 +10652,7 @@ static void gen_farith(DisasContext *ctx, enum fopcode op1, gen_load_fpr64(ctx, fp0, ft); gen_load_fpr64(ctx, fp1, fs); - gen_helper_float_addr_ps(fp0, cpu_env, fp0, fp1); + gen_helper_float_addr_ps(fp0, tcg_env, fp0, fp1); gen_store_fpr64(ctx, fp0, fd); } break; @@ -10664,7 +10664,7 @@ static void gen_farith(DisasContext *ctx, enum fopcode op1, gen_load_fpr64(ctx, fp0, ft); gen_load_fpr64(ctx, fp1, fs); - gen_helper_float_mulr_ps(fp0, cpu_env, fp0, fp1); + gen_helper_float_mulr_ps(fp0, tcg_env, fp0, fp1); gen_store_fpr64(ctx, fp0, fd); } break; @@ -10676,7 +10676,7 @@ static void gen_farith(DisasContext *ctx, enum fopcode op1, gen_load_fpr64(ctx, fp0, fs); gen_load_fpr64(ctx, fp1, ft); - gen_helper_float_recip2_ps(fp0, cpu_env, fp0, fp1); + gen_helper_float_recip2_ps(fp0, tcg_env, fp0, fp1); gen_store_fpr64(ctx, fp0, fd); } break; @@ -10686,7 +10686,7 @@ static void gen_farith(DisasContext *ctx, enum fopcode op1, TCGv_i64 fp0 = tcg_temp_new_i64(); gen_load_fpr64(ctx, fp0, fs); - gen_helper_float_recip1_ps(fp0, cpu_env, fp0); + gen_helper_float_recip1_ps(fp0, tcg_env, fp0); gen_store_fpr64(ctx, fp0, fd); } break; @@ -10696,7 +10696,7 @@ static void gen_farith(DisasContext *ctx, enum fopcode op1, TCGv_i64 fp0 = tcg_temp_new_i64(); gen_load_fpr64(ctx, fp0, fs); - gen_helper_float_rsqrt1_ps(fp0, cpu_env, fp0); + gen_helper_float_rsqrt1_ps(fp0, tcg_env, fp0); gen_store_fpr64(ctx, fp0, fd); } break; @@ -10708,7 +10708,7 @@ static void gen_farith(DisasContext *ctx, enum fopcode op1, gen_load_fpr64(ctx, fp0, fs); gen_load_fpr64(ctx, fp1, ft); - gen_helper_float_rsqrt2_ps(fp0, cpu_env, fp0, fp1); + gen_helper_float_rsqrt2_ps(fp0, tcg_env, fp0, fp1); gen_store_fpr64(ctx, fp0, fd); } break; @@ -10718,7 +10718,7 @@ static void gen_farith(DisasContext *ctx, enum fopcode op1, TCGv_i32 fp0 = tcg_temp_new_i32(); gen_load_fpr32h(ctx, fp0, fs); - gen_helper_float_cvts_pu(fp0, cpu_env, fp0); + gen_helper_float_cvts_pu(fp0, tcg_env, fp0); gen_store_fpr32(ctx, fp0, fd); } break; @@ -10728,7 +10728,7 @@ static void gen_farith(DisasContext *ctx, enum fopcode op1, TCGv_i64 fp0 = tcg_temp_new_i64(); gen_load_fpr64(ctx, fp0, fs); - gen_helper_float_cvtpw_ps(fp0, cpu_env, fp0); + gen_helper_float_cvtpw_ps(fp0, tcg_env, fp0); gen_store_fpr64(ctx, fp0, fd); } break; @@ -10738,7 +10738,7 @@ static void gen_farith(DisasContext *ctx, enum fopcode op1, TCGv_i32 fp0 = tcg_temp_new_i32(); gen_load_fpr32(ctx, fp0, fs); - gen_helper_float_cvts_pl(fp0, cpu_env, fp0); + gen_helper_float_cvts_pl(fp0, tcg_env, fp0); gen_store_fpr32(ctx, fp0, fd); } break; @@ -10943,7 +10943,7 @@ static void gen_flt3_arith(DisasContext *ctx, uint32_t opc, gen_load_fpr32(ctx, fp0, fs); gen_load_fpr32(ctx, fp1, ft); gen_load_fpr32(ctx, fp2, fr); - gen_helper_float_madd_s(fp2, cpu_env, fp0, fp1, fp2); + gen_helper_float_madd_s(fp2, tcg_env, fp0, fp1, fp2); gen_store_fpr32(ctx, fp2, fd); } break; @@ -10958,7 +10958,7 @@ static void gen_flt3_arith(DisasContext *ctx, uint32_t opc, gen_load_fpr64(ctx, fp0, fs); gen_load_fpr64(ctx, fp1, ft); gen_load_fpr64(ctx, fp2, fr); - gen_helper_float_madd_d(fp2, cpu_env, fp0, fp1, fp2); + gen_helper_float_madd_d(fp2, tcg_env, fp0, fp1, fp2); gen_store_fpr64(ctx, fp2, fd); } break; @@ -10972,7 +10972,7 @@ static void gen_flt3_arith(DisasContext *ctx, uint32_t opc, gen_load_fpr64(ctx, fp0, fs); gen_load_fpr64(ctx, fp1, ft); gen_load_fpr64(ctx, fp2, fr); - gen_helper_float_madd_ps(fp2, cpu_env, fp0, fp1, fp2); + gen_helper_float_madd_ps(fp2, tcg_env, fp0, fp1, fp2); gen_store_fpr64(ctx, fp2, fd); } break; @@ -10986,7 +10986,7 @@ static void gen_flt3_arith(DisasContext *ctx, uint32_t opc, gen_load_fpr32(ctx, fp0, fs); gen_load_fpr32(ctx, fp1, ft); gen_load_fpr32(ctx, fp2, fr); - gen_helper_float_msub_s(fp2, cpu_env, fp0, fp1, fp2); + gen_helper_float_msub_s(fp2, tcg_env, fp0, fp1, fp2); gen_store_fpr32(ctx, fp2, fd); } break; @@ -11001,7 +11001,7 @@ static void gen_flt3_arith(DisasContext *ctx, uint32_t opc, gen_load_fpr64(ctx, fp0, fs); gen_load_fpr64(ctx, fp1, ft); gen_load_fpr64(ctx, fp2, fr); - gen_helper_float_msub_d(fp2, cpu_env, fp0, fp1, fp2); + gen_helper_float_msub_d(fp2, tcg_env, fp0, fp1, fp2); gen_store_fpr64(ctx, fp2, fd); } break; @@ -11015,7 +11015,7 @@ static void gen_flt3_arith(DisasContext *ctx, uint32_t opc, gen_load_fpr64(ctx, fp0, fs); gen_load_fpr64(ctx, fp1, ft); gen_load_fpr64(ctx, fp2, fr); - gen_helper_float_msub_ps(fp2, cpu_env, fp0, fp1, fp2); + gen_helper_float_msub_ps(fp2, tcg_env, fp0, fp1, fp2); gen_store_fpr64(ctx, fp2, fd); } break; @@ -11029,7 +11029,7 @@ static void gen_flt3_arith(DisasContext *ctx, uint32_t opc, gen_load_fpr32(ctx, fp0, fs); gen_load_fpr32(ctx, fp1, ft); gen_load_fpr32(ctx, fp2, fr); - gen_helper_float_nmadd_s(fp2, cpu_env, fp0, fp1, fp2); + gen_helper_float_nmadd_s(fp2, tcg_env, fp0, fp1, fp2); gen_store_fpr32(ctx, fp2, fd); } break; @@ -11044,7 +11044,7 @@ static void gen_flt3_arith(DisasContext *ctx, uint32_t opc, gen_load_fpr64(ctx, fp0, fs); gen_load_fpr64(ctx, fp1, ft); gen_load_fpr64(ctx, fp2, fr); - gen_helper_float_nmadd_d(fp2, cpu_env, fp0, fp1, fp2); + gen_helper_float_nmadd_d(fp2, tcg_env, fp0, fp1, fp2); gen_store_fpr64(ctx, fp2, fd); } break; @@ -11058,7 +11058,7 @@ static void gen_flt3_arith(DisasContext *ctx, uint32_t opc, gen_load_fpr64(ctx, fp0, fs); gen_load_fpr64(ctx, fp1, ft); gen_load_fpr64(ctx, fp2, fr); - gen_helper_float_nmadd_ps(fp2, cpu_env, fp0, fp1, fp2); + gen_helper_float_nmadd_ps(fp2, tcg_env, fp0, fp1, fp2); gen_store_fpr64(ctx, fp2, fd); } break; @@ -11072,7 +11072,7 @@ static void gen_flt3_arith(DisasContext *ctx, uint32_t opc, gen_load_fpr32(ctx, fp0, fs); gen_load_fpr32(ctx, fp1, ft); gen_load_fpr32(ctx, fp2, fr); - gen_helper_float_nmsub_s(fp2, cpu_env, fp0, fp1, fp2); + gen_helper_float_nmsub_s(fp2, tcg_env, fp0, fp1, fp2); gen_store_fpr32(ctx, fp2, fd); } break; @@ -11087,7 +11087,7 @@ static void gen_flt3_arith(DisasContext *ctx, uint32_t opc, gen_load_fpr64(ctx, fp0, fs); gen_load_fpr64(ctx, fp1, ft); gen_load_fpr64(ctx, fp2, fr); - gen_helper_float_nmsub_d(fp2, cpu_env, fp0, fp1, fp2); + gen_helper_float_nmsub_d(fp2, tcg_env, fp0, fp1, fp2); gen_store_fpr64(ctx, fp2, fd); } break; @@ -11101,7 +11101,7 @@ static void gen_flt3_arith(DisasContext *ctx, uint32_t opc, gen_load_fpr64(ctx, fp0, fs); gen_load_fpr64(ctx, fp1, ft); gen_load_fpr64(ctx, fp2, fr); - gen_helper_float_nmsub_ps(fp2, cpu_env, fp0, fp1, fp2); + gen_helper_float_nmsub_ps(fp2, tcg_env, fp0, fp1, fp2); gen_store_fpr64(ctx, fp2, fd); } break; @@ -11127,16 +11127,16 @@ void gen_rdhwr(DisasContext *ctx, int rt, int rd, int sel) switch (rd) { case 0: - gen_helper_rdhwr_cpunum(t0, cpu_env); + gen_helper_rdhwr_cpunum(t0, tcg_env); gen_store_gpr(t0, rt); break; case 1: - gen_helper_rdhwr_synci_step(t0, cpu_env); + gen_helper_rdhwr_synci_step(t0, tcg_env); gen_store_gpr(t0, rt); break; case 2: translator_io_start(&ctx->base); - gen_helper_rdhwr_cc(t0, cpu_env); + gen_helper_rdhwr_cc(t0, tcg_env); gen_store_gpr(t0, rt); /* * Break the TB to be able to take timer interrupts immediately @@ -11147,7 +11147,7 @@ void gen_rdhwr(DisasContext *ctx, int rt, int rd, int sel) ctx->base.is_jmp = DISAS_EXIT; break; case 3: - gen_helper_rdhwr_ccres(t0, cpu_env); + gen_helper_rdhwr_ccres(t0, tcg_env); gen_store_gpr(t0, rt); break; case 4: @@ -11159,24 +11159,24 @@ void gen_rdhwr(DisasContext *ctx, int rt, int rd, int sel) */ generate_exception(ctx, EXCP_RI); } - gen_helper_rdhwr_performance(t0, cpu_env); + gen_helper_rdhwr_performance(t0, tcg_env); gen_store_gpr(t0, rt); break; case 5: check_insn(ctx, ISA_MIPS_R6); - gen_helper_rdhwr_xnp(t0, cpu_env); + gen_helper_rdhwr_xnp(t0, tcg_env); gen_store_gpr(t0, rt); break; case 29: #if defined(CONFIG_USER_ONLY) - tcg_gen_ld_tl(t0, cpu_env, + tcg_gen_ld_tl(t0, tcg_env, offsetof(CPUMIPSState, active_tc.CP0_UserLocal)); gen_store_gpr(t0, rt); break; #else if ((ctx->hflags & MIPS_HFLAG_CP0) || (ctx->hflags & MIPS_HFLAG_HWRENA_ULR)) { - tcg_gen_ld_tl(t0, cpu_env, + tcg_gen_ld_tl(t0, tcg_env, offsetof(CPUMIPSState, active_tc.CP0_UserLocal)); gen_store_gpr(t0, rt); } else { @@ -11513,7 +11513,7 @@ static void gen_cache_operation(DisasContext *ctx, uint32_t op, int base, TCGv_i32 t0 = tcg_constant_i32(op); TCGv t1 = tcg_temp_new(); gen_base_offset_addr(ctx, t1, base, offset); - gen_helper_cache(cpu_env, t1, t0); + gen_helper_cache(tcg_env, t1, t0); } static inline bool is_uhi(DisasContext *ctx, int sdbbp_code) @@ -11710,15 +11710,15 @@ static void gen_mipsdsp_arith(DisasContext *ctx, uint32_t op1, uint32_t op2, switch (op2) { case OPC_ABSQ_S_QB: check_dsp_r2(ctx); - gen_helper_absq_s_qb(cpu_gpr[ret], v2_t, cpu_env); + gen_helper_absq_s_qb(cpu_gpr[ret], v2_t, tcg_env); break; case OPC_ABSQ_S_PH: check_dsp(ctx); - gen_helper_absq_s_ph(cpu_gpr[ret], v2_t, cpu_env); + gen_helper_absq_s_ph(cpu_gpr[ret], v2_t, tcg_env); break; case OPC_ABSQ_S_W: check_dsp(ctx); - gen_helper_absq_s_w(cpu_gpr[ret], v2_t, cpu_env); + gen_helper_absq_s_w(cpu_gpr[ret], v2_t, tcg_env); break; case OPC_PRECEQ_W_PHL: check_dsp(ctx); @@ -11769,67 +11769,67 @@ static void gen_mipsdsp_arith(DisasContext *ctx, uint32_t op1, uint32_t op2, switch (op2) { case OPC_ADDQ_PH: check_dsp(ctx); - gen_helper_addq_ph(cpu_gpr[ret], v1_t, v2_t, cpu_env); + gen_helper_addq_ph(cpu_gpr[ret], v1_t, v2_t, tcg_env); break; case OPC_ADDQ_S_PH: check_dsp(ctx); - gen_helper_addq_s_ph(cpu_gpr[ret], v1_t, v2_t, cpu_env); + gen_helper_addq_s_ph(cpu_gpr[ret], v1_t, v2_t, tcg_env); break; case OPC_ADDQ_S_W: check_dsp(ctx); - gen_helper_addq_s_w(cpu_gpr[ret], v1_t, v2_t, cpu_env); + gen_helper_addq_s_w(cpu_gpr[ret], v1_t, v2_t, tcg_env); break; case OPC_ADDU_QB: check_dsp(ctx); - gen_helper_addu_qb(cpu_gpr[ret], v1_t, v2_t, cpu_env); + gen_helper_addu_qb(cpu_gpr[ret], v1_t, v2_t, tcg_env); break; case OPC_ADDU_S_QB: check_dsp(ctx); - gen_helper_addu_s_qb(cpu_gpr[ret], v1_t, v2_t, cpu_env); + gen_helper_addu_s_qb(cpu_gpr[ret], v1_t, v2_t, tcg_env); break; case OPC_ADDU_PH: check_dsp_r2(ctx); - gen_helper_addu_ph(cpu_gpr[ret], v1_t, v2_t, cpu_env); + gen_helper_addu_ph(cpu_gpr[ret], v1_t, v2_t, tcg_env); break; case OPC_ADDU_S_PH: check_dsp_r2(ctx); - gen_helper_addu_s_ph(cpu_gpr[ret], v1_t, v2_t, cpu_env); + gen_helper_addu_s_ph(cpu_gpr[ret], v1_t, v2_t, tcg_env); break; case OPC_SUBQ_PH: check_dsp(ctx); - gen_helper_subq_ph(cpu_gpr[ret], v1_t, v2_t, cpu_env); + gen_helper_subq_ph(cpu_gpr[ret], v1_t, v2_t, tcg_env); break; case OPC_SUBQ_S_PH: check_dsp(ctx); - gen_helper_subq_s_ph(cpu_gpr[ret], v1_t, v2_t, cpu_env); + gen_helper_subq_s_ph(cpu_gpr[ret], v1_t, v2_t, tcg_env); break; case OPC_SUBQ_S_W: check_dsp(ctx); - gen_helper_subq_s_w(cpu_gpr[ret], v1_t, v2_t, cpu_env); + gen_helper_subq_s_w(cpu_gpr[ret], v1_t, v2_t, tcg_env); break; case OPC_SUBU_QB: check_dsp(ctx); - gen_helper_subu_qb(cpu_gpr[ret], v1_t, v2_t, cpu_env); + gen_helper_subu_qb(cpu_gpr[ret], v1_t, v2_t, tcg_env); break; case OPC_SUBU_S_QB: check_dsp(ctx); - gen_helper_subu_s_qb(cpu_gpr[ret], v1_t, v2_t, cpu_env); + gen_helper_subu_s_qb(cpu_gpr[ret], v1_t, v2_t, tcg_env); break; case OPC_SUBU_PH: check_dsp_r2(ctx); - gen_helper_subu_ph(cpu_gpr[ret], v1_t, v2_t, cpu_env); + gen_helper_subu_ph(cpu_gpr[ret], v1_t, v2_t, tcg_env); break; case OPC_SUBU_S_PH: check_dsp_r2(ctx); - gen_helper_subu_s_ph(cpu_gpr[ret], v1_t, v2_t, cpu_env); + gen_helper_subu_s_ph(cpu_gpr[ret], v1_t, v2_t, tcg_env); break; case OPC_ADDSC: check_dsp(ctx); - gen_helper_addsc(cpu_gpr[ret], v1_t, v2_t, cpu_env); + gen_helper_addsc(cpu_gpr[ret], v1_t, v2_t, tcg_env); break; case OPC_ADDWC: check_dsp(ctx); - gen_helper_addwc(cpu_gpr[ret], v1_t, v2_t, cpu_env); + gen_helper_addwc(cpu_gpr[ret], v1_t, v2_t, tcg_env); break; case OPC_MODSUB: check_dsp(ctx); @@ -11873,11 +11873,11 @@ static void gen_mipsdsp_arith(DisasContext *ctx, uint32_t op1, uint32_t op2, break; case OPC_PRECRQ_RS_PH_W: check_dsp(ctx); - gen_helper_precrq_rs_ph_w(cpu_gpr[ret], v1_t, v2_t, cpu_env); + gen_helper_precrq_rs_ph_w(cpu_gpr[ret], v1_t, v2_t, tcg_env); break; case OPC_PRECRQU_S_QB_PH: check_dsp(ctx); - gen_helper_precrqu_s_qb_ph(cpu_gpr[ret], v1_t, v2_t, cpu_env); + gen_helper_precrqu_s_qb_ph(cpu_gpr[ret], v1_t, v2_t, tcg_env); break; } break; @@ -11942,15 +11942,15 @@ static void gen_mipsdsp_arith(DisasContext *ctx, uint32_t op1, uint32_t op2, break; case OPC_ABSQ_S_OB: check_dsp_r2(ctx); - gen_helper_absq_s_ob(cpu_gpr[ret], v2_t, cpu_env); + gen_helper_absq_s_ob(cpu_gpr[ret], v2_t, tcg_env); break; case OPC_ABSQ_S_PW: check_dsp(ctx); - gen_helper_absq_s_pw(cpu_gpr[ret], v2_t, cpu_env); + gen_helper_absq_s_pw(cpu_gpr[ret], v2_t, tcg_env); break; case OPC_ABSQ_S_QH: check_dsp(ctx); - gen_helper_absq_s_qh(cpu_gpr[ret], v2_t, cpu_env); + gen_helper_absq_s_qh(cpu_gpr[ret], v2_t, tcg_env); break; } break; @@ -11962,35 +11962,35 @@ static void gen_mipsdsp_arith(DisasContext *ctx, uint32_t op1, uint32_t op2, break; case OPC_SUBQ_PW: check_dsp(ctx); - gen_helper_subq_pw(cpu_gpr[ret], v1_t, v2_t, cpu_env); + gen_helper_subq_pw(cpu_gpr[ret], v1_t, v2_t, tcg_env); break; case OPC_SUBQ_S_PW: check_dsp(ctx); - gen_helper_subq_s_pw(cpu_gpr[ret], v1_t, v2_t, cpu_env); + gen_helper_subq_s_pw(cpu_gpr[ret], v1_t, v2_t, tcg_env); break; case OPC_SUBQ_QH: check_dsp(ctx); - gen_helper_subq_qh(cpu_gpr[ret], v1_t, v2_t, cpu_env); + gen_helper_subq_qh(cpu_gpr[ret], v1_t, v2_t, tcg_env); break; case OPC_SUBQ_S_QH: check_dsp(ctx); - gen_helper_subq_s_qh(cpu_gpr[ret], v1_t, v2_t, cpu_env); + gen_helper_subq_s_qh(cpu_gpr[ret], v1_t, v2_t, tcg_env); break; case OPC_SUBU_OB: check_dsp(ctx); - gen_helper_subu_ob(cpu_gpr[ret], v1_t, v2_t, cpu_env); + gen_helper_subu_ob(cpu_gpr[ret], v1_t, v2_t, tcg_env); break; case OPC_SUBU_S_OB: check_dsp(ctx); - gen_helper_subu_s_ob(cpu_gpr[ret], v1_t, v2_t, cpu_env); + gen_helper_subu_s_ob(cpu_gpr[ret], v1_t, v2_t, tcg_env); break; case OPC_SUBU_QH: check_dsp_r2(ctx); - gen_helper_subu_qh(cpu_gpr[ret], v1_t, v2_t, cpu_env); + gen_helper_subu_qh(cpu_gpr[ret], v1_t, v2_t, tcg_env); break; case OPC_SUBU_S_QH: check_dsp_r2(ctx); - gen_helper_subu_s_qh(cpu_gpr[ret], v1_t, v2_t, cpu_env); + gen_helper_subu_s_qh(cpu_gpr[ret], v1_t, v2_t, tcg_env); break; case OPC_SUBUH_OB: check_dsp_r2(ctx); @@ -12002,35 +12002,35 @@ static void gen_mipsdsp_arith(DisasContext *ctx, uint32_t op1, uint32_t op2, break; case OPC_ADDQ_PW: check_dsp(ctx); - gen_helper_addq_pw(cpu_gpr[ret], v1_t, v2_t, cpu_env); + gen_helper_addq_pw(cpu_gpr[ret], v1_t, v2_t, tcg_env); break; case OPC_ADDQ_S_PW: check_dsp(ctx); - gen_helper_addq_s_pw(cpu_gpr[ret], v1_t, v2_t, cpu_env); + gen_helper_addq_s_pw(cpu_gpr[ret], v1_t, v2_t, tcg_env); break; case OPC_ADDQ_QH: check_dsp(ctx); - gen_helper_addq_qh(cpu_gpr[ret], v1_t, v2_t, cpu_env); + gen_helper_addq_qh(cpu_gpr[ret], v1_t, v2_t, tcg_env); break; case OPC_ADDQ_S_QH: check_dsp(ctx); - gen_helper_addq_s_qh(cpu_gpr[ret], v1_t, v2_t, cpu_env); + gen_helper_addq_s_qh(cpu_gpr[ret], v1_t, v2_t, tcg_env); break; case OPC_ADDU_OB: check_dsp(ctx); - gen_helper_addu_ob(cpu_gpr[ret], v1_t, v2_t, cpu_env); + gen_helper_addu_ob(cpu_gpr[ret], v1_t, v2_t, tcg_env); break; case OPC_ADDU_S_OB: check_dsp(ctx); - gen_helper_addu_s_ob(cpu_gpr[ret], v1_t, v2_t, cpu_env); + gen_helper_addu_s_ob(cpu_gpr[ret], v1_t, v2_t, tcg_env); break; case OPC_ADDU_QH: check_dsp_r2(ctx); - gen_helper_addu_qh(cpu_gpr[ret], v1_t, v2_t, cpu_env); + gen_helper_addu_qh(cpu_gpr[ret], v1_t, v2_t, tcg_env); break; case OPC_ADDU_S_QH: check_dsp_r2(ctx); - gen_helper_addu_s_qh(cpu_gpr[ret], v1_t, v2_t, cpu_env); + gen_helper_addu_s_qh(cpu_gpr[ret], v1_t, v2_t, tcg_env); break; case OPC_ADDUH_OB: check_dsp_r2(ctx); @@ -12076,11 +12076,11 @@ static void gen_mipsdsp_arith(DisasContext *ctx, uint32_t op1, uint32_t op2, break; case OPC_PRECRQ_RS_QH_PW: check_dsp(ctx); - gen_helper_precrq_rs_qh_pw(cpu_gpr[ret], v1_t, v2_t, cpu_env); + gen_helper_precrq_rs_qh_pw(cpu_gpr[ret], v1_t, v2_t, tcg_env); break; case OPC_PRECRQU_S_OB_QH: check_dsp(ctx); - gen_helper_precrqu_s_ob_qh(cpu_gpr[ret], v1_t, v2_t, cpu_env); + gen_helper_precrqu_s_ob_qh(cpu_gpr[ret], v1_t, v2_t, tcg_env); break; } break; @@ -12116,35 +12116,35 @@ static void gen_mipsdsp_shift(DisasContext *ctx, uint32_t opc, switch (op2) { case OPC_SHLL_QB: check_dsp(ctx); - gen_helper_shll_qb(cpu_gpr[ret], t0, v2_t, cpu_env); + gen_helper_shll_qb(cpu_gpr[ret], t0, v2_t, tcg_env); break; case OPC_SHLLV_QB: check_dsp(ctx); - gen_helper_shll_qb(cpu_gpr[ret], v1_t, v2_t, cpu_env); + gen_helper_shll_qb(cpu_gpr[ret], v1_t, v2_t, tcg_env); break; case OPC_SHLL_PH: check_dsp(ctx); - gen_helper_shll_ph(cpu_gpr[ret], t0, v2_t, cpu_env); + gen_helper_shll_ph(cpu_gpr[ret], t0, v2_t, tcg_env); break; case OPC_SHLLV_PH: check_dsp(ctx); - gen_helper_shll_ph(cpu_gpr[ret], v1_t, v2_t, cpu_env); + gen_helper_shll_ph(cpu_gpr[ret], v1_t, v2_t, tcg_env); break; case OPC_SHLL_S_PH: check_dsp(ctx); - gen_helper_shll_s_ph(cpu_gpr[ret], t0, v2_t, cpu_env); + gen_helper_shll_s_ph(cpu_gpr[ret], t0, v2_t, tcg_env); break; case OPC_SHLLV_S_PH: check_dsp(ctx); - gen_helper_shll_s_ph(cpu_gpr[ret], v1_t, v2_t, cpu_env); + gen_helper_shll_s_ph(cpu_gpr[ret], v1_t, v2_t, tcg_env); break; case OPC_SHLL_S_W: check_dsp(ctx); - gen_helper_shll_s_w(cpu_gpr[ret], t0, v2_t, cpu_env); + gen_helper_shll_s_w(cpu_gpr[ret], t0, v2_t, tcg_env); break; case OPC_SHLLV_S_W: check_dsp(ctx); - gen_helper_shll_s_w(cpu_gpr[ret], v1_t, v2_t, cpu_env); + gen_helper_shll_s_w(cpu_gpr[ret], v1_t, v2_t, tcg_env); break; case OPC_SHRL_QB: check_dsp(ctx); @@ -12215,43 +12215,43 @@ static void gen_mipsdsp_shift(DisasContext *ctx, uint32_t opc, switch (op2) { case OPC_SHLL_PW: check_dsp(ctx); - gen_helper_shll_pw(cpu_gpr[ret], v2_t, t0, cpu_env); + gen_helper_shll_pw(cpu_gpr[ret], v2_t, t0, tcg_env); break; case OPC_SHLLV_PW: check_dsp(ctx); - gen_helper_shll_pw(cpu_gpr[ret], v2_t, v1_t, cpu_env); + gen_helper_shll_pw(cpu_gpr[ret], v2_t, v1_t, tcg_env); break; case OPC_SHLL_S_PW: check_dsp(ctx); - gen_helper_shll_s_pw(cpu_gpr[ret], v2_t, t0, cpu_env); + gen_helper_shll_s_pw(cpu_gpr[ret], v2_t, t0, tcg_env); break; case OPC_SHLLV_S_PW: check_dsp(ctx); - gen_helper_shll_s_pw(cpu_gpr[ret], v2_t, v1_t, cpu_env); + gen_helper_shll_s_pw(cpu_gpr[ret], v2_t, v1_t, tcg_env); break; case OPC_SHLL_OB: check_dsp(ctx); - gen_helper_shll_ob(cpu_gpr[ret], v2_t, t0, cpu_env); + gen_helper_shll_ob(cpu_gpr[ret], v2_t, t0, tcg_env); break; case OPC_SHLLV_OB: check_dsp(ctx); - gen_helper_shll_ob(cpu_gpr[ret], v2_t, v1_t, cpu_env); + gen_helper_shll_ob(cpu_gpr[ret], v2_t, v1_t, tcg_env); break; case OPC_SHLL_QH: check_dsp(ctx); - gen_helper_shll_qh(cpu_gpr[ret], v2_t, t0, cpu_env); + gen_helper_shll_qh(cpu_gpr[ret], v2_t, t0, tcg_env); break; case OPC_SHLLV_QH: check_dsp(ctx); - gen_helper_shll_qh(cpu_gpr[ret], v2_t, v1_t, cpu_env); + gen_helper_shll_qh(cpu_gpr[ret], v2_t, v1_t, tcg_env); break; case OPC_SHLL_S_QH: check_dsp(ctx); - gen_helper_shll_s_qh(cpu_gpr[ret], v2_t, t0, cpu_env); + gen_helper_shll_s_qh(cpu_gpr[ret], v2_t, t0, tcg_env); break; case OPC_SHLLV_S_QH: check_dsp(ctx); - gen_helper_shll_s_qh(cpu_gpr[ret], v2_t, v1_t, cpu_env); + gen_helper_shll_s_qh(cpu_gpr[ret], v2_t, v1_t, tcg_env); break; case OPC_SHRA_OB: check_dsp_r2(ctx); @@ -12356,16 +12356,16 @@ static void gen_mipsdsp_multiply(DisasContext *ctx, uint32_t op1, uint32_t op2, check_dsp_r2(ctx); switch (op2) { case OPC_MUL_PH: - gen_helper_mul_ph(cpu_gpr[ret], v1_t, v2_t, cpu_env); + gen_helper_mul_ph(cpu_gpr[ret], v1_t, v2_t, tcg_env); break; case OPC_MUL_S_PH: - gen_helper_mul_s_ph(cpu_gpr[ret], v1_t, v2_t, cpu_env); + gen_helper_mul_s_ph(cpu_gpr[ret], v1_t, v2_t, tcg_env); break; case OPC_MULQ_S_W: - gen_helper_mulq_s_w(cpu_gpr[ret], v1_t, v2_t, cpu_env); + gen_helper_mulq_s_w(cpu_gpr[ret], v1_t, v2_t, tcg_env); break; case OPC_MULQ_RS_W: - gen_helper_mulq_rs_w(cpu_gpr[ret], v1_t, v2_t, cpu_env); + gen_helper_mulq_rs_w(cpu_gpr[ret], v1_t, v2_t, tcg_env); break; } break; @@ -12373,91 +12373,91 @@ static void gen_mipsdsp_multiply(DisasContext *ctx, uint32_t op1, uint32_t op2, switch (op2) { case OPC_DPAU_H_QBL: check_dsp(ctx); - gen_helper_dpau_h_qbl(t0, v1_t, v2_t, cpu_env); + gen_helper_dpau_h_qbl(t0, v1_t, v2_t, tcg_env); break; case OPC_DPAU_H_QBR: check_dsp(ctx); - gen_helper_dpau_h_qbr(t0, v1_t, v2_t, cpu_env); + gen_helper_dpau_h_qbr(t0, v1_t, v2_t, tcg_env); break; case OPC_DPSU_H_QBL: check_dsp(ctx); - gen_helper_dpsu_h_qbl(t0, v1_t, v2_t, cpu_env); + gen_helper_dpsu_h_qbl(t0, v1_t, v2_t, tcg_env); break; case OPC_DPSU_H_QBR: check_dsp(ctx); - gen_helper_dpsu_h_qbr(t0, v1_t, v2_t, cpu_env); + gen_helper_dpsu_h_qbr(t0, v1_t, v2_t, tcg_env); break; case OPC_DPA_W_PH: check_dsp_r2(ctx); - gen_helper_dpa_w_ph(t0, v1_t, v2_t, cpu_env); + gen_helper_dpa_w_ph(t0, v1_t, v2_t, tcg_env); break; case OPC_DPAX_W_PH: check_dsp_r2(ctx); - gen_helper_dpax_w_ph(t0, v1_t, v2_t, cpu_env); + gen_helper_dpax_w_ph(t0, v1_t, v2_t, tcg_env); break; case OPC_DPAQ_S_W_PH: check_dsp(ctx); - gen_helper_dpaq_s_w_ph(t0, v1_t, v2_t, cpu_env); + gen_helper_dpaq_s_w_ph(t0, v1_t, v2_t, tcg_env); break; case OPC_DPAQX_S_W_PH: check_dsp_r2(ctx); - gen_helper_dpaqx_s_w_ph(t0, v1_t, v2_t, cpu_env); + gen_helper_dpaqx_s_w_ph(t0, v1_t, v2_t, tcg_env); break; case OPC_DPAQX_SA_W_PH: check_dsp_r2(ctx); - gen_helper_dpaqx_sa_w_ph(t0, v1_t, v2_t, cpu_env); + gen_helper_dpaqx_sa_w_ph(t0, v1_t, v2_t, tcg_env); break; case OPC_DPS_W_PH: check_dsp_r2(ctx); - gen_helper_dps_w_ph(t0, v1_t, v2_t, cpu_env); + gen_helper_dps_w_ph(t0, v1_t, v2_t, tcg_env); break; case OPC_DPSX_W_PH: check_dsp_r2(ctx); - gen_helper_dpsx_w_ph(t0, v1_t, v2_t, cpu_env); + gen_helper_dpsx_w_ph(t0, v1_t, v2_t, tcg_env); break; case OPC_DPSQ_S_W_PH: check_dsp(ctx); - gen_helper_dpsq_s_w_ph(t0, v1_t, v2_t, cpu_env); + gen_helper_dpsq_s_w_ph(t0, v1_t, v2_t, tcg_env); break; case OPC_DPSQX_S_W_PH: check_dsp_r2(ctx); - gen_helper_dpsqx_s_w_ph(t0, v1_t, v2_t, cpu_env); + gen_helper_dpsqx_s_w_ph(t0, v1_t, v2_t, tcg_env); break; case OPC_DPSQX_SA_W_PH: check_dsp_r2(ctx); - gen_helper_dpsqx_sa_w_ph(t0, v1_t, v2_t, cpu_env); + gen_helper_dpsqx_sa_w_ph(t0, v1_t, v2_t, tcg_env); break; case OPC_MULSAQ_S_W_PH: check_dsp(ctx); - gen_helper_mulsaq_s_w_ph(t0, v1_t, v2_t, cpu_env); + gen_helper_mulsaq_s_w_ph(t0, v1_t, v2_t, tcg_env); break; case OPC_DPAQ_SA_L_W: check_dsp(ctx); - gen_helper_dpaq_sa_l_w(t0, v1_t, v2_t, cpu_env); + gen_helper_dpaq_sa_l_w(t0, v1_t, v2_t, tcg_env); break; case OPC_DPSQ_SA_L_W: check_dsp(ctx); - gen_helper_dpsq_sa_l_w(t0, v1_t, v2_t, cpu_env); + gen_helper_dpsq_sa_l_w(t0, v1_t, v2_t, tcg_env); break; case OPC_MAQ_S_W_PHL: check_dsp(ctx); - gen_helper_maq_s_w_phl(t0, v1_t, v2_t, cpu_env); + gen_helper_maq_s_w_phl(t0, v1_t, v2_t, tcg_env); break; case OPC_MAQ_S_W_PHR: check_dsp(ctx); - gen_helper_maq_s_w_phr(t0, v1_t, v2_t, cpu_env); + gen_helper_maq_s_w_phr(t0, v1_t, v2_t, tcg_env); break; case OPC_MAQ_SA_W_PHL: check_dsp(ctx); - gen_helper_maq_sa_w_phl(t0, v1_t, v2_t, cpu_env); + gen_helper_maq_sa_w_phl(t0, v1_t, v2_t, tcg_env); break; case OPC_MAQ_SA_W_PHR: check_dsp(ctx); - gen_helper_maq_sa_w_phr(t0, v1_t, v2_t, cpu_env); + gen_helper_maq_sa_w_phr(t0, v1_t, v2_t, tcg_env); break; case OPC_MULSA_W_PH: check_dsp_r2(ctx); - gen_helper_mulsa_w_ph(t0, v1_t, v2_t, cpu_env); + gen_helper_mulsa_w_ph(t0, v1_t, v2_t, tcg_env); break; } break; @@ -12470,107 +12470,107 @@ static void gen_mipsdsp_multiply(DisasContext *ctx, uint32_t op1, uint32_t op2, switch (op2) { case OPC_DMADD: check_dsp(ctx); - gen_helper_dmadd(v1_t, v2_t, t0, cpu_env); + gen_helper_dmadd(v1_t, v2_t, t0, tcg_env); break; case OPC_DMADDU: check_dsp(ctx); - gen_helper_dmaddu(v1_t, v2_t, t0, cpu_env); + gen_helper_dmaddu(v1_t, v2_t, t0, tcg_env); break; case OPC_DMSUB: check_dsp(ctx); - gen_helper_dmsub(v1_t, v2_t, t0, cpu_env); + gen_helper_dmsub(v1_t, v2_t, t0, tcg_env); break; case OPC_DMSUBU: check_dsp(ctx); - gen_helper_dmsubu(v1_t, v2_t, t0, cpu_env); + gen_helper_dmsubu(v1_t, v2_t, t0, tcg_env); break; case OPC_DPA_W_QH: check_dsp_r2(ctx); - gen_helper_dpa_w_qh(v1_t, v2_t, t0, cpu_env); + gen_helper_dpa_w_qh(v1_t, v2_t, t0, tcg_env); break; case OPC_DPAQ_S_W_QH: check_dsp(ctx); - gen_helper_dpaq_s_w_qh(v1_t, v2_t, t0, cpu_env); + gen_helper_dpaq_s_w_qh(v1_t, v2_t, t0, tcg_env); break; case OPC_DPAQ_SA_L_PW: check_dsp(ctx); - gen_helper_dpaq_sa_l_pw(v1_t, v2_t, t0, cpu_env); + gen_helper_dpaq_sa_l_pw(v1_t, v2_t, t0, tcg_env); break; case OPC_DPAU_H_OBL: check_dsp(ctx); - gen_helper_dpau_h_obl(v1_t, v2_t, t0, cpu_env); + gen_helper_dpau_h_obl(v1_t, v2_t, t0, tcg_env); break; case OPC_DPAU_H_OBR: check_dsp(ctx); - gen_helper_dpau_h_obr(v1_t, v2_t, t0, cpu_env); + gen_helper_dpau_h_obr(v1_t, v2_t, t0, tcg_env); break; case OPC_DPS_W_QH: check_dsp_r2(ctx); - gen_helper_dps_w_qh(v1_t, v2_t, t0, cpu_env); + gen_helper_dps_w_qh(v1_t, v2_t, t0, tcg_env); break; case OPC_DPSQ_S_W_QH: check_dsp(ctx); - gen_helper_dpsq_s_w_qh(v1_t, v2_t, t0, cpu_env); + gen_helper_dpsq_s_w_qh(v1_t, v2_t, t0, tcg_env); break; case OPC_DPSQ_SA_L_PW: check_dsp(ctx); - gen_helper_dpsq_sa_l_pw(v1_t, v2_t, t0, cpu_env); + gen_helper_dpsq_sa_l_pw(v1_t, v2_t, t0, tcg_env); break; case OPC_DPSU_H_OBL: check_dsp(ctx); - gen_helper_dpsu_h_obl(v1_t, v2_t, t0, cpu_env); + gen_helper_dpsu_h_obl(v1_t, v2_t, t0, tcg_env); break; case OPC_DPSU_H_OBR: check_dsp(ctx); - gen_helper_dpsu_h_obr(v1_t, v2_t, t0, cpu_env); + gen_helper_dpsu_h_obr(v1_t, v2_t, t0, tcg_env); break; case OPC_MAQ_S_L_PWL: check_dsp(ctx); - gen_helper_maq_s_l_pwl(v1_t, v2_t, t0, cpu_env); + gen_helper_maq_s_l_pwl(v1_t, v2_t, t0, tcg_env); break; case OPC_MAQ_S_L_PWR: check_dsp(ctx); - gen_helper_maq_s_l_pwr(v1_t, v2_t, t0, cpu_env); + gen_helper_maq_s_l_pwr(v1_t, v2_t, t0, tcg_env); break; case OPC_MAQ_S_W_QHLL: check_dsp(ctx); - gen_helper_maq_s_w_qhll(v1_t, v2_t, t0, cpu_env); + gen_helper_maq_s_w_qhll(v1_t, v2_t, t0, tcg_env); break; case OPC_MAQ_SA_W_QHLL: check_dsp(ctx); - gen_helper_maq_sa_w_qhll(v1_t, v2_t, t0, cpu_env); + gen_helper_maq_sa_w_qhll(v1_t, v2_t, t0, tcg_env); break; case OPC_MAQ_S_W_QHLR: check_dsp(ctx); - gen_helper_maq_s_w_qhlr(v1_t, v2_t, t0, cpu_env); + gen_helper_maq_s_w_qhlr(v1_t, v2_t, t0, tcg_env); break; case OPC_MAQ_SA_W_QHLR: check_dsp(ctx); - gen_helper_maq_sa_w_qhlr(v1_t, v2_t, t0, cpu_env); + gen_helper_maq_sa_w_qhlr(v1_t, v2_t, t0, tcg_env); break; case OPC_MAQ_S_W_QHRL: check_dsp(ctx); - gen_helper_maq_s_w_qhrl(v1_t, v2_t, t0, cpu_env); + gen_helper_maq_s_w_qhrl(v1_t, v2_t, t0, tcg_env); break; case OPC_MAQ_SA_W_QHRL: check_dsp(ctx); - gen_helper_maq_sa_w_qhrl(v1_t, v2_t, t0, cpu_env); + gen_helper_maq_sa_w_qhrl(v1_t, v2_t, t0, tcg_env); break; case OPC_MAQ_S_W_QHRR: check_dsp(ctx); - gen_helper_maq_s_w_qhrr(v1_t, v2_t, t0, cpu_env); + gen_helper_maq_s_w_qhrr(v1_t, v2_t, t0, tcg_env); break; case OPC_MAQ_SA_W_QHRR: check_dsp(ctx); - gen_helper_maq_sa_w_qhrr(v1_t, v2_t, t0, cpu_env); + gen_helper_maq_sa_w_qhrr(v1_t, v2_t, t0, tcg_env); break; case OPC_MULSAQ_S_L_PW: check_dsp(ctx); - gen_helper_mulsaq_s_l_pw(v1_t, v2_t, t0, cpu_env); + gen_helper_mulsaq_s_l_pw(v1_t, v2_t, t0, tcg_env); break; case OPC_MULSAQ_S_W_QH: check_dsp(ctx); - gen_helper_mulsaq_s_w_qh(v1_t, v2_t, t0, cpu_env); + gen_helper_mulsaq_s_w_qh(v1_t, v2_t, t0, tcg_env); break; } } @@ -12580,27 +12580,27 @@ static void gen_mipsdsp_multiply(DisasContext *ctx, uint32_t op1, uint32_t op2, switch (op2) { case OPC_MULEU_S_PH_QBL: check_dsp(ctx); - gen_helper_muleu_s_ph_qbl(cpu_gpr[ret], v1_t, v2_t, cpu_env); + gen_helper_muleu_s_ph_qbl(cpu_gpr[ret], v1_t, v2_t, tcg_env); break; case OPC_MULEU_S_PH_QBR: check_dsp(ctx); - gen_helper_muleu_s_ph_qbr(cpu_gpr[ret], v1_t, v2_t, cpu_env); + gen_helper_muleu_s_ph_qbr(cpu_gpr[ret], v1_t, v2_t, tcg_env); break; case OPC_MULQ_RS_PH: check_dsp(ctx); - gen_helper_mulq_rs_ph(cpu_gpr[ret], v1_t, v2_t, cpu_env); + gen_helper_mulq_rs_ph(cpu_gpr[ret], v1_t, v2_t, tcg_env); break; case OPC_MULEQ_S_W_PHL: check_dsp(ctx); - gen_helper_muleq_s_w_phl(cpu_gpr[ret], v1_t, v2_t, cpu_env); + gen_helper_muleq_s_w_phl(cpu_gpr[ret], v1_t, v2_t, tcg_env); break; case OPC_MULEQ_S_W_PHR: check_dsp(ctx); - gen_helper_muleq_s_w_phr(cpu_gpr[ret], v1_t, v2_t, cpu_env); + gen_helper_muleq_s_w_phr(cpu_gpr[ret], v1_t, v2_t, tcg_env); break; case OPC_MULQ_S_PH: check_dsp_r2(ctx); - gen_helper_mulq_s_ph(cpu_gpr[ret], v1_t, v2_t, cpu_env); + gen_helper_mulq_s_ph(cpu_gpr[ret], v1_t, v2_t, tcg_env); break; } break; @@ -12609,23 +12609,23 @@ static void gen_mipsdsp_multiply(DisasContext *ctx, uint32_t op1, uint32_t op2, switch (op2) { case OPC_MULEQ_S_PW_QHL: check_dsp(ctx); - gen_helper_muleq_s_pw_qhl(cpu_gpr[ret], v1_t, v2_t, cpu_env); + gen_helper_muleq_s_pw_qhl(cpu_gpr[ret], v1_t, v2_t, tcg_env); break; case OPC_MULEQ_S_PW_QHR: check_dsp(ctx); - gen_helper_muleq_s_pw_qhr(cpu_gpr[ret], v1_t, v2_t, cpu_env); + gen_helper_muleq_s_pw_qhr(cpu_gpr[ret], v1_t, v2_t, tcg_env); break; case OPC_MULEU_S_QH_OBL: check_dsp(ctx); - gen_helper_muleu_s_qh_obl(cpu_gpr[ret], v1_t, v2_t, cpu_env); + gen_helper_muleu_s_qh_obl(cpu_gpr[ret], v1_t, v2_t, tcg_env); break; case OPC_MULEU_S_QH_OBR: check_dsp(ctx); - gen_helper_muleu_s_qh_obr(cpu_gpr[ret], v1_t, v2_t, cpu_env); + gen_helper_muleu_s_qh_obr(cpu_gpr[ret], v1_t, v2_t, tcg_env); break; case OPC_MULQ_RS_QH: check_dsp(ctx); - gen_helper_mulq_rs_qh(cpu_gpr[ret], v1_t, v2_t, cpu_env); + gen_helper_mulq_rs_qh(cpu_gpr[ret], v1_t, v2_t, tcg_env); break; } break; @@ -12794,15 +12794,15 @@ static void gen_mipsdsp_add_cmp_pick(DisasContext *ctx, switch (op2) { case OPC_CMPU_EQ_QB: check_dsp(ctx); - gen_helper_cmpu_eq_qb(v1_t, v2_t, cpu_env); + gen_helper_cmpu_eq_qb(v1_t, v2_t, tcg_env); break; case OPC_CMPU_LT_QB: check_dsp(ctx); - gen_helper_cmpu_lt_qb(v1_t, v2_t, cpu_env); + gen_helper_cmpu_lt_qb(v1_t, v2_t, tcg_env); break; case OPC_CMPU_LE_QB: check_dsp(ctx); - gen_helper_cmpu_le_qb(v1_t, v2_t, cpu_env); + gen_helper_cmpu_le_qb(v1_t, v2_t, tcg_env); break; case OPC_CMPGU_EQ_QB: check_dsp(ctx); @@ -12842,23 +12842,23 @@ static void gen_mipsdsp_add_cmp_pick(DisasContext *ctx, break; case OPC_CMP_EQ_PH: check_dsp(ctx); - gen_helper_cmp_eq_ph(v1_t, v2_t, cpu_env); + gen_helper_cmp_eq_ph(v1_t, v2_t, tcg_env); break; case OPC_CMP_LT_PH: check_dsp(ctx); - gen_helper_cmp_lt_ph(v1_t, v2_t, cpu_env); + gen_helper_cmp_lt_ph(v1_t, v2_t, tcg_env); break; case OPC_CMP_LE_PH: check_dsp(ctx); - gen_helper_cmp_le_ph(v1_t, v2_t, cpu_env); + gen_helper_cmp_le_ph(v1_t, v2_t, tcg_env); break; case OPC_PICK_QB: check_dsp(ctx); - gen_helper_pick_qb(cpu_gpr[ret], v1_t, v2_t, cpu_env); + gen_helper_pick_qb(cpu_gpr[ret], v1_t, v2_t, tcg_env); break; case OPC_PICK_PH: check_dsp(ctx); - gen_helper_pick_ph(cpu_gpr[ret], v1_t, v2_t, cpu_env); + gen_helper_pick_ph(cpu_gpr[ret], v1_t, v2_t, tcg_env); break; case OPC_PACKRL_PH: check_dsp(ctx); @@ -12871,39 +12871,39 @@ static void gen_mipsdsp_add_cmp_pick(DisasContext *ctx, switch (op2) { case OPC_CMP_EQ_PW: check_dsp(ctx); - gen_helper_cmp_eq_pw(v1_t, v2_t, cpu_env); + gen_helper_cmp_eq_pw(v1_t, v2_t, tcg_env); break; case OPC_CMP_LT_PW: check_dsp(ctx); - gen_helper_cmp_lt_pw(v1_t, v2_t, cpu_env); + gen_helper_cmp_lt_pw(v1_t, v2_t, tcg_env); break; case OPC_CMP_LE_PW: check_dsp(ctx); - gen_helper_cmp_le_pw(v1_t, v2_t, cpu_env); + gen_helper_cmp_le_pw(v1_t, v2_t, tcg_env); break; case OPC_CMP_EQ_QH: check_dsp(ctx); - gen_helper_cmp_eq_qh(v1_t, v2_t, cpu_env); + gen_helper_cmp_eq_qh(v1_t, v2_t, tcg_env); break; case OPC_CMP_LT_QH: check_dsp(ctx); - gen_helper_cmp_lt_qh(v1_t, v2_t, cpu_env); + gen_helper_cmp_lt_qh(v1_t, v2_t, tcg_env); break; case OPC_CMP_LE_QH: check_dsp(ctx); - gen_helper_cmp_le_qh(v1_t, v2_t, cpu_env); + gen_helper_cmp_le_qh(v1_t, v2_t, tcg_env); break; case OPC_CMPGDU_EQ_OB: check_dsp_r2(ctx); - gen_helper_cmpgdu_eq_ob(cpu_gpr[ret], v1_t, v2_t, cpu_env); + gen_helper_cmpgdu_eq_ob(cpu_gpr[ret], v1_t, v2_t, tcg_env); break; case OPC_CMPGDU_LT_OB: check_dsp_r2(ctx); - gen_helper_cmpgdu_lt_ob(cpu_gpr[ret], v1_t, v2_t, cpu_env); + gen_helper_cmpgdu_lt_ob(cpu_gpr[ret], v1_t, v2_t, tcg_env); break; case OPC_CMPGDU_LE_OB: check_dsp_r2(ctx); - gen_helper_cmpgdu_le_ob(cpu_gpr[ret], v1_t, v2_t, cpu_env); + gen_helper_cmpgdu_le_ob(cpu_gpr[ret], v1_t, v2_t, tcg_env); break; case OPC_CMPGU_EQ_OB: check_dsp(ctx); @@ -12919,15 +12919,15 @@ static void gen_mipsdsp_add_cmp_pick(DisasContext *ctx, break; case OPC_CMPU_EQ_OB: check_dsp(ctx); - gen_helper_cmpu_eq_ob(v1_t, v2_t, cpu_env); + gen_helper_cmpu_eq_ob(v1_t, v2_t, tcg_env); break; case OPC_CMPU_LT_OB: check_dsp(ctx); - gen_helper_cmpu_lt_ob(v1_t, v2_t, cpu_env); + gen_helper_cmpu_lt_ob(v1_t, v2_t, tcg_env); break; case OPC_CMPU_LE_OB: check_dsp(ctx); - gen_helper_cmpu_le_ob(v1_t, v2_t, cpu_env); + gen_helper_cmpu_le_ob(v1_t, v2_t, tcg_env); break; case OPC_PACKRL_PW: check_dsp(ctx); @@ -12935,15 +12935,15 @@ static void gen_mipsdsp_add_cmp_pick(DisasContext *ctx, break; case OPC_PICK_OB: check_dsp(ctx); - gen_helper_pick_ob(cpu_gpr[ret], v1_t, v2_t, cpu_env); + gen_helper_pick_ob(cpu_gpr[ret], v1_t, v2_t, tcg_env); break; case OPC_PICK_PW: check_dsp(ctx); - gen_helper_pick_pw(cpu_gpr[ret], v1_t, v2_t, cpu_env); + gen_helper_pick_pw(cpu_gpr[ret], v1_t, v2_t, tcg_env); break; case OPC_PICK_QH: check_dsp(ctx); - gen_helper_pick_qh(cpu_gpr[ret], v1_t, v2_t, cpu_env); + gen_helper_pick_qh(cpu_gpr[ret], v1_t, v2_t, tcg_env); break; } break; @@ -13065,80 +13065,80 @@ static void gen_mipsdsp_accinsn(DisasContext *ctx, uint32_t op1, uint32_t op2, case OPC_EXTR_W: tcg_gen_movi_tl(t0, v2); tcg_gen_movi_tl(t1, v1); - gen_helper_extr_w(cpu_gpr[ret], t0, t1, cpu_env); + gen_helper_extr_w(cpu_gpr[ret], t0, t1, tcg_env); break; case OPC_EXTR_R_W: tcg_gen_movi_tl(t0, v2); tcg_gen_movi_tl(t1, v1); - gen_helper_extr_r_w(cpu_gpr[ret], t0, t1, cpu_env); + gen_helper_extr_r_w(cpu_gpr[ret], t0, t1, tcg_env); break; case OPC_EXTR_RS_W: tcg_gen_movi_tl(t0, v2); tcg_gen_movi_tl(t1, v1); - gen_helper_extr_rs_w(cpu_gpr[ret], t0, t1, cpu_env); + gen_helper_extr_rs_w(cpu_gpr[ret], t0, t1, tcg_env); break; case OPC_EXTR_S_H: tcg_gen_movi_tl(t0, v2); tcg_gen_movi_tl(t1, v1); - gen_helper_extr_s_h(cpu_gpr[ret], t0, t1, cpu_env); + gen_helper_extr_s_h(cpu_gpr[ret], t0, t1, tcg_env); break; case OPC_EXTRV_S_H: tcg_gen_movi_tl(t0, v2); - gen_helper_extr_s_h(cpu_gpr[ret], t0, v1_t, cpu_env); + gen_helper_extr_s_h(cpu_gpr[ret], t0, v1_t, tcg_env); break; case OPC_EXTRV_W: tcg_gen_movi_tl(t0, v2); - gen_helper_extr_w(cpu_gpr[ret], t0, v1_t, cpu_env); + gen_helper_extr_w(cpu_gpr[ret], t0, v1_t, tcg_env); break; case OPC_EXTRV_R_W: tcg_gen_movi_tl(t0, v2); - gen_helper_extr_r_w(cpu_gpr[ret], t0, v1_t, cpu_env); + gen_helper_extr_r_w(cpu_gpr[ret], t0, v1_t, tcg_env); break; case OPC_EXTRV_RS_W: tcg_gen_movi_tl(t0, v2); - gen_helper_extr_rs_w(cpu_gpr[ret], t0, v1_t, cpu_env); + gen_helper_extr_rs_w(cpu_gpr[ret], t0, v1_t, tcg_env); break; case OPC_EXTP: tcg_gen_movi_tl(t0, v2); tcg_gen_movi_tl(t1, v1); - gen_helper_extp(cpu_gpr[ret], t0, t1, cpu_env); + gen_helper_extp(cpu_gpr[ret], t0, t1, tcg_env); break; case OPC_EXTPV: tcg_gen_movi_tl(t0, v2); - gen_helper_extp(cpu_gpr[ret], t0, v1_t, cpu_env); + gen_helper_extp(cpu_gpr[ret], t0, v1_t, tcg_env); break; case OPC_EXTPDP: tcg_gen_movi_tl(t0, v2); tcg_gen_movi_tl(t1, v1); - gen_helper_extpdp(cpu_gpr[ret], t0, t1, cpu_env); + gen_helper_extpdp(cpu_gpr[ret], t0, t1, tcg_env); break; case OPC_EXTPDPV: tcg_gen_movi_tl(t0, v2); - gen_helper_extpdp(cpu_gpr[ret], t0, v1_t, cpu_env); + gen_helper_extpdp(cpu_gpr[ret], t0, v1_t, tcg_env); break; case OPC_SHILO: imm = (ctx->opcode >> 20) & 0x3F; tcg_gen_movi_tl(t0, ret); tcg_gen_movi_tl(t1, imm); - gen_helper_shilo(t0, t1, cpu_env); + gen_helper_shilo(t0, t1, tcg_env); break; case OPC_SHILOV: tcg_gen_movi_tl(t0, ret); - gen_helper_shilo(t0, v1_t, cpu_env); + gen_helper_shilo(t0, v1_t, tcg_env); break; case OPC_MTHLIP: tcg_gen_movi_tl(t0, ret); - gen_helper_mthlip(t0, v1_t, cpu_env); + gen_helper_mthlip(t0, v1_t, tcg_env); break; case OPC_WRDSP: imm = (ctx->opcode >> 11) & 0x3FF; tcg_gen_movi_tl(t0, imm); - gen_helper_wrdsp(v1_t, t0, cpu_env); + gen_helper_wrdsp(v1_t, t0, tcg_env); break; case OPC_RDDSP: imm = (ctx->opcode >> 16) & 0x03FF; tcg_gen_movi_tl(t0, imm); - gen_helper_rddsp(cpu_gpr[ret], t0, cpu_env); + gen_helper_rddsp(cpu_gpr[ret], t0, tcg_env); break; } break; @@ -13148,7 +13148,7 @@ static void gen_mipsdsp_accinsn(DisasContext *ctx, uint32_t op1, uint32_t op2, switch (op2) { case OPC_DMTHLIP: tcg_gen_movi_tl(t0, ret); - gen_helper_dmthlip(v1_t, t0, cpu_env); + gen_helper_dmthlip(v1_t, t0, tcg_env); break; case OPC_DSHILO: { @@ -13156,97 +13156,97 @@ static void gen_mipsdsp_accinsn(DisasContext *ctx, uint32_t op1, uint32_t op2, int ac = (ctx->opcode >> 11) & 0x03; tcg_gen_movi_tl(t0, shift); tcg_gen_movi_tl(t1, ac); - gen_helper_dshilo(t0, t1, cpu_env); + gen_helper_dshilo(t0, t1, tcg_env); break; } case OPC_DSHILOV: { int ac = (ctx->opcode >> 11) & 0x03; tcg_gen_movi_tl(t0, ac); - gen_helper_dshilo(v1_t, t0, cpu_env); + gen_helper_dshilo(v1_t, t0, tcg_env); break; } case OPC_DEXTP: tcg_gen_movi_tl(t0, v2); tcg_gen_movi_tl(t1, v1); - gen_helper_dextp(cpu_gpr[ret], t0, t1, cpu_env); + gen_helper_dextp(cpu_gpr[ret], t0, t1, tcg_env); break; case OPC_DEXTPV: tcg_gen_movi_tl(t0, v2); - gen_helper_dextp(cpu_gpr[ret], t0, v1_t, cpu_env); + gen_helper_dextp(cpu_gpr[ret], t0, v1_t, tcg_env); break; case OPC_DEXTPDP: tcg_gen_movi_tl(t0, v2); tcg_gen_movi_tl(t1, v1); - gen_helper_dextpdp(cpu_gpr[ret], t0, t1, cpu_env); + gen_helper_dextpdp(cpu_gpr[ret], t0, t1, tcg_env); break; case OPC_DEXTPDPV: tcg_gen_movi_tl(t0, v2); - gen_helper_dextpdp(cpu_gpr[ret], t0, v1_t, cpu_env); + gen_helper_dextpdp(cpu_gpr[ret], t0, v1_t, tcg_env); break; case OPC_DEXTR_L: tcg_gen_movi_tl(t0, v2); tcg_gen_movi_tl(t1, v1); - gen_helper_dextr_l(cpu_gpr[ret], t0, t1, cpu_env); + gen_helper_dextr_l(cpu_gpr[ret], t0, t1, tcg_env); break; case OPC_DEXTR_R_L: tcg_gen_movi_tl(t0, v2); tcg_gen_movi_tl(t1, v1); - gen_helper_dextr_r_l(cpu_gpr[ret], t0, t1, cpu_env); + gen_helper_dextr_r_l(cpu_gpr[ret], t0, t1, tcg_env); break; case OPC_DEXTR_RS_L: tcg_gen_movi_tl(t0, v2); tcg_gen_movi_tl(t1, v1); - gen_helper_dextr_rs_l(cpu_gpr[ret], t0, t1, cpu_env); + gen_helper_dextr_rs_l(cpu_gpr[ret], t0, t1, tcg_env); break; case OPC_DEXTR_W: tcg_gen_movi_tl(t0, v2); tcg_gen_movi_tl(t1, v1); - gen_helper_dextr_w(cpu_gpr[ret], t0, t1, cpu_env); + gen_helper_dextr_w(cpu_gpr[ret], t0, t1, tcg_env); break; case OPC_DEXTR_R_W: tcg_gen_movi_tl(t0, v2); tcg_gen_movi_tl(t1, v1); - gen_helper_dextr_r_w(cpu_gpr[ret], t0, t1, cpu_env); + gen_helper_dextr_r_w(cpu_gpr[ret], t0, t1, tcg_env); break; case OPC_DEXTR_RS_W: tcg_gen_movi_tl(t0, v2); tcg_gen_movi_tl(t1, v1); - gen_helper_dextr_rs_w(cpu_gpr[ret], t0, t1, cpu_env); + gen_helper_dextr_rs_w(cpu_gpr[ret], t0, t1, tcg_env); break; case OPC_DEXTR_S_H: tcg_gen_movi_tl(t0, v2); tcg_gen_movi_tl(t1, v1); - gen_helper_dextr_s_h(cpu_gpr[ret], t0, t1, cpu_env); + gen_helper_dextr_s_h(cpu_gpr[ret], t0, t1, tcg_env); break; case OPC_DEXTRV_S_H: tcg_gen_movi_tl(t0, v2); - gen_helper_dextr_s_h(cpu_gpr[ret], t0, v1_t, cpu_env); + gen_helper_dextr_s_h(cpu_gpr[ret], t0, v1_t, tcg_env); break; case OPC_DEXTRV_L: tcg_gen_movi_tl(t0, v2); - gen_helper_dextr_l(cpu_gpr[ret], t0, v1_t, cpu_env); + gen_helper_dextr_l(cpu_gpr[ret], t0, v1_t, tcg_env); break; case OPC_DEXTRV_R_L: tcg_gen_movi_tl(t0, v2); - gen_helper_dextr_r_l(cpu_gpr[ret], t0, v1_t, cpu_env); + gen_helper_dextr_r_l(cpu_gpr[ret], t0, v1_t, tcg_env); break; case OPC_DEXTRV_RS_L: tcg_gen_movi_tl(t0, v2); - gen_helper_dextr_rs_l(cpu_gpr[ret], t0, v1_t, cpu_env); + gen_helper_dextr_rs_l(cpu_gpr[ret], t0, v1_t, tcg_env); break; case OPC_DEXTRV_W: tcg_gen_movi_tl(t0, v2); - gen_helper_dextr_w(cpu_gpr[ret], t0, v1_t, cpu_env); + gen_helper_dextr_w(cpu_gpr[ret], t0, v1_t, tcg_env); break; case OPC_DEXTRV_R_W: tcg_gen_movi_tl(t0, v2); - gen_helper_dextr_r_w(cpu_gpr[ret], t0, v1_t, cpu_env); + gen_helper_dextr_r_w(cpu_gpr[ret], t0, v1_t, tcg_env); break; case OPC_DEXTRV_RS_W: tcg_gen_movi_tl(t0, v2); - gen_helper_dextr_rs_w(cpu_gpr[ret], t0, v1_t, cpu_env); + gen_helper_dextr_rs_w(cpu_gpr[ret], t0, v1_t, tcg_env); break; } break; @@ -13578,7 +13578,7 @@ static void decode_opc_special(CPUMIPSState *env, DisasContext *ctx) MIPS_INVAL("PMON / selsl"); gen_reserved_instruction(ctx); #else - gen_helper_pmon(cpu_env, tcg_constant_i32(sa)); + gen_helper_pmon(tcg_env, tcg_constant_i32(sa)); #endif break; case OPC_SYSCALL: @@ -14101,7 +14101,7 @@ static void decode_opc_special3_legacy(CPUMIPSState *env, DisasContext *ctx) gen_load_gpr(t0, rt); gen_load_gpr(t1, rs); - gen_helper_insv(cpu_gpr[rt], cpu_env, t1, t0); + gen_helper_insv(cpu_gpr[rt], tcg_env, t1, t0); break; } default: /* Invalid */ @@ -14370,7 +14370,7 @@ static void decode_opc_special3_legacy(CPUMIPSState *env, DisasContext *ctx) gen_load_gpr(t0, rt); gen_load_gpr(t1, rs); - gen_helper_dinsv(cpu_gpr[rt], cpu_env, t1, t0); + gen_helper_dinsv(cpu_gpr[rt], tcg_env, t1, t0); break; } default: /* Invalid */ @@ -14605,7 +14605,7 @@ static void decode_opc_special3(CPUMIPSState *env, DisasContext *ctx) TCGv t0 = tcg_temp_new(); gen_load_gpr(t0, rs); - gen_helper_yield(t0, cpu_env, t0); + gen_helper_yield(t0, tcg_env, t0); gen_store_gpr(t0, rd); } break; @@ -14796,32 +14796,32 @@ static bool decode_opc_legacy(CPUMIPSState *env, DisasContext *ctx) break; case OPC_DVPE: check_cp0_mt(ctx); - gen_helper_dvpe(t0, cpu_env); + gen_helper_dvpe(t0, tcg_env); gen_store_gpr(t0, rt); break; case OPC_EVPE: check_cp0_mt(ctx); - gen_helper_evpe(t0, cpu_env); + gen_helper_evpe(t0, tcg_env); gen_store_gpr(t0, rt); break; case OPC_DVP: check_insn(ctx, ISA_MIPS_R6); if (ctx->vp) { - gen_helper_dvp(t0, cpu_env); + gen_helper_dvp(t0, tcg_env); gen_store_gpr(t0, rt); } break; case OPC_EVP: check_insn(ctx, ISA_MIPS_R6); if (ctx->vp) { - gen_helper_evp(t0, cpu_env); + gen_helper_evp(t0, tcg_env); gen_store_gpr(t0, rt); } break; case OPC_DI: check_insn(ctx, ISA_MIPS_R2); save_cpu_state(ctx, 1); - gen_helper_di(t0, cpu_env); + gen_helper_di(t0, tcg_env); gen_store_gpr(t0, rt); /* * Stop translation as we may have switched @@ -14832,7 +14832,7 @@ static bool decode_opc_legacy(CPUMIPSState *env, DisasContext *ctx) case OPC_EI: check_insn(ctx, ISA_MIPS_R2); save_cpu_state(ctx, 1); - gen_helper_ei(t0, cpu_env); + gen_helper_ei(t0, tcg_env); gen_store_gpr(t0, rt); /* * DISAS_STOP isn't sufficient, we need to ensure we break @@ -15565,7 +15565,7 @@ void mips_tcg_init(void) { cpu_gpr[0] = NULL; for (unsigned i = 1; i < 32; i++) - cpu_gpr[i] = tcg_global_mem_new(cpu_env, + cpu_gpr[i] = tcg_global_mem_new(tcg_env, offsetof(CPUMIPSState, active_tc.gpr[i]), regnames[i]); @@ -15575,7 +15575,7 @@ void mips_tcg_init(void) for (unsigned i = 1; i < 32; i++) { g_autofree char *rname = g_strdup_printf("%s[hi]", regnames[i]); - cpu_gpr_hi[i] = tcg_global_mem_new_i64(cpu_env, + cpu_gpr_hi[i] = tcg_global_mem_new_i64(tcg_env, offsetof(CPUMIPSState, active_tc.gpr_hi[i]), rname); @@ -15584,39 +15584,39 @@ void mips_tcg_init(void) for (unsigned i = 0; i < 32; i++) { int off = offsetof(CPUMIPSState, active_fpu.fpr[i].wr.d[0]); - fpu_f64[i] = tcg_global_mem_new_i64(cpu_env, off, fregnames[i]); + fpu_f64[i] = tcg_global_mem_new_i64(tcg_env, off, fregnames[i]); } msa_translate_init(); - cpu_PC = tcg_global_mem_new(cpu_env, + cpu_PC = tcg_global_mem_new(tcg_env, offsetof(CPUMIPSState, active_tc.PC), "PC"); for (unsigned i = 0; i < MIPS_DSP_ACC; i++) { - cpu_HI[i] = tcg_global_mem_new(cpu_env, + cpu_HI[i] = tcg_global_mem_new(tcg_env, offsetof(CPUMIPSState, active_tc.HI[i]), regnames_HI[i]); - cpu_LO[i] = tcg_global_mem_new(cpu_env, + cpu_LO[i] = tcg_global_mem_new(tcg_env, offsetof(CPUMIPSState, active_tc.LO[i]), regnames_LO[i]); } - cpu_dspctrl = tcg_global_mem_new(cpu_env, + cpu_dspctrl = tcg_global_mem_new(tcg_env, offsetof(CPUMIPSState, active_tc.DSPControl), "DSPControl"); - bcond = tcg_global_mem_new(cpu_env, + bcond = tcg_global_mem_new(tcg_env, offsetof(CPUMIPSState, bcond), "bcond"); - btarget = tcg_global_mem_new(cpu_env, + btarget = tcg_global_mem_new(tcg_env, offsetof(CPUMIPSState, btarget), "btarget"); - hflags = tcg_global_mem_new_i32(cpu_env, + hflags = tcg_global_mem_new_i32(tcg_env, offsetof(CPUMIPSState, hflags), "hflags"); - fpu_fcr0 = tcg_global_mem_new_i32(cpu_env, + fpu_fcr0 = tcg_global_mem_new_i32(tcg_env, offsetof(CPUMIPSState, active_fpu.fcr0), "fcr0"); - fpu_fcr31 = tcg_global_mem_new_i32(cpu_env, + fpu_fcr31 = tcg_global_mem_new_i32(tcg_env, offsetof(CPUMIPSState, active_fpu.fcr31), "fcr31"); - cpu_lladdr = tcg_global_mem_new(cpu_env, offsetof(CPUMIPSState, lladdr), + cpu_lladdr = tcg_global_mem_new(tcg_env, offsetof(CPUMIPSState, lladdr), "lladdr"); - cpu_llval = tcg_global_mem_new(cpu_env, offsetof(CPUMIPSState, llval), + cpu_llval = tcg_global_mem_new(tcg_env, offsetof(CPUMIPSState, llval), "llval"); if (TARGET_LONG_BITS == 32) { diff --git a/target/mips/tcg/translate.h b/target/mips/tcg/translate.h index db3dc932c7..cffcfeab8c 100644 --- a/target/mips/tcg/translate.h +++ b/target/mips/tcg/translate.h @@ -123,15 +123,15 @@ enum { }; #define gen_helper_0e1i(name, arg1, arg2) do { \ - gen_helper_##name(cpu_env, arg1, tcg_constant_i32(arg2)); \ + gen_helper_##name(tcg_env, arg1, tcg_constant_i32(arg2)); \ } while (0) #define gen_helper_1e0i(name, ret, arg1) do { \ - gen_helper_##name(ret, cpu_env, tcg_constant_i32(arg1)); \ + gen_helper_##name(ret, tcg_env, tcg_constant_i32(arg1)); \ } while (0) #define gen_helper_0e2i(name, arg1, arg2, arg3) do { \ - gen_helper_##name(cpu_env, arg1, arg2, tcg_constant_i32(arg3));\ + gen_helper_##name(tcg_env, arg1, arg2, tcg_constant_i32(arg3));\ } while (0) void generate_exception(DisasContext *ctx, int excp); diff --git a/target/mips/tcg/vr54xx_translate.c b/target/mips/tcg/vr54xx_translate.c index 2c1f6cc527..c877ede76e 100644 --- a/target/mips/tcg/vr54xx_translate.c +++ b/target/mips/tcg/vr54xx_translate.c @@ -43,7 +43,7 @@ static bool trans_mult_acc(DisasContext *ctx, arg_r *a, gen_load_gpr(t0, a->rs); gen_load_gpr(t1, a->rt); - gen_helper_mult_acc(t0, cpu_env, t0, t1); + gen_helper_mult_acc(t0, tcg_env, t0, t1); gen_store_gpr(t0, a->rd); return true; diff --git a/target/nios2/translate.c b/target/nios2/translate.c index dfc546d3bb..93ded65f9a 100644 --- a/target/nios2/translate.c +++ b/target/nios2/translate.c @@ -209,7 +209,7 @@ static void t_gen_helper_raise_exception(DisasContext *dc, uint32_t index) { /* Note that PC is advanced for all hardware exceptions. */ tcg_gen_movi_tl(cpu_pc, dc->base.pc_next); - gen_helper_raise_exception(cpu_env, tcg_constant_i32(index)); + gen_helper_raise_exception(tcg_env, tcg_constant_i32(index)); dc->base.is_jmp = DISAS_NORETURN; } @@ -244,7 +244,7 @@ static void gen_jumpr(DisasContext *dc, int regno, bool is_call) tcg_gen_lookup_and_goto_ptr(); gen_set_label(l); - tcg_gen_st_tl(dest, cpu_env, offsetof(CPUNios2State, ctrl[CR_BADADDR])); + tcg_gen_st_tl(dest, tcg_env, offsetof(CPUNios2State, ctrl[CR_BADADDR])); t_gen_helper_raise_exception(dc, EXCP_UNALIGND); dc->base.is_jmp = DISAS_NORETURN; @@ -414,7 +414,7 @@ static void rdprs(DisasContext *dc, uint32_t code, uint32_t flags) #else I_TYPE(instr, code); TCGv dest = dest_gpr(dc, instr.b); - gen_helper_rdprs(dest, cpu_env, tcg_constant_i32(instr.a)); + gen_helper_rdprs(dest, tcg_env, tcg_constant_i32(instr.a)); tcg_gen_addi_tl(dest, dest, instr.imm16.s); #endif } @@ -508,10 +508,10 @@ static void eret(DisasContext *dc, uint32_t code, uint32_t flags) #else if (FIELD_EX32(dc->tb_flags, TBFLAGS, CRS0)) { TCGv tmp = tcg_temp_new(); - tcg_gen_ld_tl(tmp, cpu_env, offsetof(CPUNios2State, ctrl[CR_ESTATUS])); - gen_helper_eret(cpu_env, tmp, load_gpr(dc, R_EA)); + tcg_gen_ld_tl(tmp, tcg_env, offsetof(CPUNios2State, ctrl[CR_ESTATUS])); + gen_helper_eret(tcg_env, tmp, load_gpr(dc, R_EA)); } else { - gen_helper_eret(cpu_env, load_gpr(dc, R_SSTATUS), load_gpr(dc, R_EA)); + gen_helper_eret(tcg_env, load_gpr(dc, R_SSTATUS), load_gpr(dc, R_EA)); } dc->base.is_jmp = DISAS_NORETURN; #endif @@ -537,8 +537,8 @@ static void bret(DisasContext *dc, uint32_t code, uint32_t flags) g_assert_not_reached(); #else TCGv tmp = tcg_temp_new(); - tcg_gen_ld_tl(tmp, cpu_env, offsetof(CPUNios2State, ctrl[CR_BSTATUS])); - gen_helper_eret(cpu_env, tmp, load_gpr(dc, R_BA)); + tcg_gen_ld_tl(tmp, tcg_env, offsetof(CPUNios2State, ctrl[CR_BSTATUS])); + gen_helper_eret(tcg_env, tmp, load_gpr(dc, R_BA)); dc->base.is_jmp = DISAS_NORETURN; #endif @@ -602,12 +602,12 @@ static void rdctl(DisasContext *dc, uint32_t code, uint32_t flags) */ t1 = tcg_temp_new(); t2 = tcg_temp_new(); - tcg_gen_ld_tl(t1, cpu_env, offsetof(CPUNios2State, ctrl[CR_IPENDING])); - tcg_gen_ld_tl(t2, cpu_env, offsetof(CPUNios2State, ctrl[CR_IENABLE])); + tcg_gen_ld_tl(t1, tcg_env, offsetof(CPUNios2State, ctrl[CR_IPENDING])); + tcg_gen_ld_tl(t2, tcg_env, offsetof(CPUNios2State, ctrl[CR_IENABLE])); tcg_gen_and_tl(dest, t1, t2); break; default: - tcg_gen_ld_tl(dest, cpu_env, + tcg_gen_ld_tl(dest, tcg_env, offsetof(CPUNios2State, ctrl[instr.imm5])); break; } @@ -637,13 +637,13 @@ static void wrctl(DisasContext *dc, uint32_t code, uint32_t flags) switch (instr.imm5) { case CR_PTEADDR: - gen_helper_mmu_write_pteaddr(cpu_env, v); + gen_helper_mmu_write_pteaddr(tcg_env, v); break; case CR_TLBACC: - gen_helper_mmu_write_tlbacc(cpu_env, v); + gen_helper_mmu_write_tlbacc(tcg_env, v); break; case CR_TLBMISC: - gen_helper_mmu_write_tlbmisc(cpu_env, v); + gen_helper_mmu_write_tlbmisc(tcg_env, v); break; case CR_STATUS: case CR_IENABLE: @@ -653,7 +653,7 @@ static void wrctl(DisasContext *dc, uint32_t code, uint32_t flags) default: if (wr == -1) { /* The register is entirely writable. */ - tcg_gen_st_tl(v, cpu_env, ofs); + tcg_gen_st_tl(v, tcg_env, ofs); } else { /* * The register is partially read-only or reserved: @@ -665,12 +665,12 @@ static void wrctl(DisasContext *dc, uint32_t code, uint32_t flags) if (ro != 0) { TCGv o = tcg_temp_new(); - tcg_gen_ld_tl(o, cpu_env, ofs); + tcg_gen_ld_tl(o, tcg_env, ofs); tcg_gen_andi_tl(o, o, ro); tcg_gen_or_tl(n, n, o); } - tcg_gen_st_tl(n, cpu_env, ofs); + tcg_gen_st_tl(n, tcg_env, ofs); } break; } @@ -692,7 +692,7 @@ static void wrprs(DisasContext *dc, uint32_t code, uint32_t flags) g_assert_not_reached(); #else R_TYPE(instr, code); - gen_helper_wrprs(cpu_env, tcg_constant_i32(instr.c), + gen_helper_wrprs(tcg_env, tcg_constant_i32(instr.c), load_gpr(dc, instr.a)); /* * The expected write to PRS[r0] is 0, from CRS[r0]. @@ -789,14 +789,14 @@ gen_rr_shift(ror, rotr) static void divs(DisasContext *dc, uint32_t code, uint32_t flags) { R_TYPE(instr, (code)); - gen_helper_divs(dest_gpr(dc, instr.c), cpu_env, + gen_helper_divs(dest_gpr(dc, instr.c), tcg_env, load_gpr(dc, instr.a), load_gpr(dc, instr.b)); } static void divu(DisasContext *dc, uint32_t code, uint32_t flags) { R_TYPE(instr, (code)); - gen_helper_divu(dest_gpr(dc, instr.c), cpu_env, + gen_helper_divu(dest_gpr(dc, instr.c), tcg_env, load_gpr(dc, instr.a), load_gpr(dc, instr.b)); } @@ -809,7 +809,7 @@ static void trap(DisasContext *dc, uint32_t code, uint32_t flags) * things easier for cpu_loop if we pop this into env->error_code. */ R_TYPE(instr, code); - tcg_gen_st_i32(tcg_constant_i32(instr.imm5), cpu_env, + tcg_gen_st_i32(tcg_constant_i32(instr.imm5), tcg_env, offsetof(CPUNios2State, error_code)); #endif t_gen_helper_raise_exception(dc, EXCP_TRAP); @@ -1084,7 +1084,7 @@ void nios2_cpu_dump_state(CPUState *cs, FILE *f, int flags) void nios2_tcg_init(void) { #ifndef CONFIG_USER_ONLY - TCGv_ptr crs = tcg_global_mem_new_ptr(cpu_env, + TCGv_ptr crs = tcg_global_mem_new_ptr(tcg_env, offsetof(CPUNios2State, regs), "crs"); for (int i = 0; i < NUM_GP_REGS; i++) { @@ -1097,12 +1097,12 @@ void nios2_tcg_init(void) #endif for (int i = 0; i < NUM_GP_REGS; i++) { - cpu_R[i] = tcg_global_mem_new(cpu_env, offsetof_regs0(i), + cpu_R[i] = tcg_global_mem_new(tcg_env, offsetof_regs0(i), gr_regnames[i]); } #undef offsetof_regs0 - cpu_pc = tcg_global_mem_new(cpu_env, + cpu_pc = tcg_global_mem_new(tcg_env, offsetof(CPUNios2State, pc), "pc"); } diff --git a/target/openrisc/translate.c b/target/openrisc/translate.c index d65758449f..1b4df1c214 100644 --- a/target/openrisc/translate.c +++ b/target/openrisc/translate.c @@ -95,37 +95,37 @@ void openrisc_translate_init(void) }; int i; - cpu_sr = tcg_global_mem_new(cpu_env, + cpu_sr = tcg_global_mem_new(tcg_env, offsetof(CPUOpenRISCState, sr), "sr"); - cpu_dflag = tcg_global_mem_new_i32(cpu_env, + cpu_dflag = tcg_global_mem_new_i32(tcg_env, offsetof(CPUOpenRISCState, dflag), "dflag"); - cpu_pc = tcg_global_mem_new(cpu_env, + cpu_pc = tcg_global_mem_new(tcg_env, offsetof(CPUOpenRISCState, pc), "pc"); - cpu_ppc = tcg_global_mem_new(cpu_env, + cpu_ppc = tcg_global_mem_new(tcg_env, offsetof(CPUOpenRISCState, ppc), "ppc"); - jmp_pc = tcg_global_mem_new(cpu_env, + jmp_pc = tcg_global_mem_new(tcg_env, offsetof(CPUOpenRISCState, jmp_pc), "jmp_pc"); - cpu_sr_f = tcg_global_mem_new(cpu_env, + cpu_sr_f = tcg_global_mem_new(tcg_env, offsetof(CPUOpenRISCState, sr_f), "sr_f"); - cpu_sr_cy = tcg_global_mem_new(cpu_env, + cpu_sr_cy = tcg_global_mem_new(tcg_env, offsetof(CPUOpenRISCState, sr_cy), "sr_cy"); - cpu_sr_ov = tcg_global_mem_new(cpu_env, + cpu_sr_ov = tcg_global_mem_new(tcg_env, offsetof(CPUOpenRISCState, sr_ov), "sr_ov"); - cpu_lock_addr = tcg_global_mem_new(cpu_env, + cpu_lock_addr = tcg_global_mem_new(tcg_env, offsetof(CPUOpenRISCState, lock_addr), "lock_addr"); - cpu_lock_value = tcg_global_mem_new(cpu_env, + cpu_lock_value = tcg_global_mem_new(tcg_env, offsetof(CPUOpenRISCState, lock_value), "lock_value"); - fpcsr = tcg_global_mem_new_i32(cpu_env, + fpcsr = tcg_global_mem_new_i32(tcg_env, offsetof(CPUOpenRISCState, fpcsr), "fpcsr"); - cpu_mac = tcg_global_mem_new_i64(cpu_env, + cpu_mac = tcg_global_mem_new_i64(tcg_env, offsetof(CPUOpenRISCState, mac), "mac"); for (i = 0; i < 32; i++) { - cpu_regs[i] = tcg_global_mem_new(cpu_env, + cpu_regs[i] = tcg_global_mem_new(tcg_env, offsetof(CPUOpenRISCState, shadow_gpr[0][i]), regnames[i]); @@ -134,7 +134,7 @@ void openrisc_translate_init(void) static void gen_exception(DisasContext *dc, unsigned int excp) { - gen_helper_exception(cpu_env, tcg_constant_i32(excp)); + gen_helper_exception(tcg_env, tcg_constant_i32(excp)); } static void gen_illegal_exception(DisasContext *dc) @@ -182,21 +182,21 @@ static void check_r0_write(DisasContext *dc, int reg) static void gen_ove_cy(DisasContext *dc) { if (dc->tb_flags & SR_OVE) { - gen_helper_ove_cy(cpu_env); + gen_helper_ove_cy(tcg_env); } } static void gen_ove_ov(DisasContext *dc) { if (dc->tb_flags & SR_OVE) { - gen_helper_ove_ov(cpu_env); + gen_helper_ove_ov(tcg_env); } } static void gen_ove_cyov(DisasContext *dc) { if (dc->tb_flags & SR_OVE) { - gen_helper_ove_cyov(cpu_env); + gen_helper_ove_cyov(tcg_env); } } @@ -835,7 +835,7 @@ static bool trans_l_mfspr(DisasContext *dc, arg_l_mfspr *a) } tcg_gen_ori_tl(spr, cpu_R(dc, a->a), a->k); - gen_helper_mfspr(cpu_R(dc, a->d), cpu_env, cpu_R(dc, a->d), spr); + gen_helper_mfspr(cpu_R(dc, a->d), tcg_env, cpu_R(dc, a->d), spr); return true; } @@ -860,7 +860,7 @@ static bool trans_l_mtspr(DisasContext *dc, arg_l_mtspr *a) dc->base.is_jmp = DISAS_EXIT; tcg_gen_ori_tl(spr, cpu_R(dc, a->a), a->k); - gen_helper_mtspr(cpu_env, spr, cpu_R(dc, a->b)); + gen_helper_mtspr(tcg_env, spr, cpu_R(dc, a->b)); return true; } @@ -1102,7 +1102,7 @@ static bool trans_l_rfe(DisasContext *dc, arg_l_rfe *a) if (is_user(dc)) { gen_illegal_exception(dc); } else { - gen_helper_rfe(cpu_env); + gen_helper_rfe(tcg_env); dc->base.is_jmp = DISAS_EXIT; } return true; @@ -1115,8 +1115,8 @@ static bool do_fp2(DisasContext *dc, arg_da *a, return false; } check_r0_write(dc, a->d); - fn(cpu_R(dc, a->d), cpu_env, cpu_R(dc, a->a)); - gen_helper_update_fpcsr(cpu_env); + fn(cpu_R(dc, a->d), tcg_env, cpu_R(dc, a->a)); + gen_helper_update_fpcsr(tcg_env); return true; } @@ -1127,8 +1127,8 @@ static bool do_fp3(DisasContext *dc, arg_dab *a, return false; } check_r0_write(dc, a->d); - fn(cpu_R(dc, a->d), cpu_env, cpu_R(dc, a->a), cpu_R(dc, a->b)); - gen_helper_update_fpcsr(cpu_env); + fn(cpu_R(dc, a->d), tcg_env, cpu_R(dc, a->a), cpu_R(dc, a->b)); + gen_helper_update_fpcsr(tcg_env); return true; } @@ -1140,14 +1140,14 @@ static bool do_fpcmp(DisasContext *dc, arg_ab *a, return false; } if (swap) { - fn(cpu_sr_f, cpu_env, cpu_R(dc, a->b), cpu_R(dc, a->a)); + fn(cpu_sr_f, tcg_env, cpu_R(dc, a->b), cpu_R(dc, a->a)); } else { - fn(cpu_sr_f, cpu_env, cpu_R(dc, a->a), cpu_R(dc, a->b)); + fn(cpu_sr_f, tcg_env, cpu_R(dc, a->a), cpu_R(dc, a->b)); } if (inv) { tcg_gen_xori_tl(cpu_sr_f, cpu_sr_f, 1); } - gen_helper_update_fpcsr(cpu_env); + gen_helper_update_fpcsr(tcg_env); return true; } @@ -1193,9 +1193,9 @@ static bool trans_lf_madd_s(DisasContext *dc, arg_dab *a) return false; } check_r0_write(dc, a->d); - gen_helper_float_madd_s(cpu_R(dc, a->d), cpu_env, cpu_R(dc, a->d), + gen_helper_float_madd_s(cpu_R(dc, a->d), tcg_env, cpu_R(dc, a->d), cpu_R(dc, a->a), cpu_R(dc, a->b)); - gen_helper_update_fpcsr(cpu_env); + gen_helper_update_fpcsr(tcg_env); return true; } @@ -1309,10 +1309,10 @@ static bool do_dp3(DisasContext *dc, arg_dab_pair *a, t1 = tcg_temp_new_i64(); load_pair(dc, t0, a->a, a->ap); load_pair(dc, t1, a->b, a->bp); - fn(t0, cpu_env, t0, t1); + fn(t0, tcg_env, t0, t1); save_pair(dc, t0, a->d, a->dp); - gen_helper_update_fpcsr(cpu_env); + gen_helper_update_fpcsr(tcg_env); return true; } @@ -1330,10 +1330,10 @@ static bool do_dp2(DisasContext *dc, arg_da_pair *a, t0 = tcg_temp_new_i64(); load_pair(dc, t0, a->a, a->ap); - fn(t0, cpu_env, t0); + fn(t0, tcg_env, t0); save_pair(dc, t0, a->d, a->dp); - gen_helper_update_fpcsr(cpu_env); + gen_helper_update_fpcsr(tcg_env); return true; } @@ -1354,15 +1354,15 @@ static bool do_dpcmp(DisasContext *dc, arg_ab_pair *a, load_pair(dc, t0, a->a, a->ap); load_pair(dc, t1, a->b, a->bp); if (swap) { - fn(cpu_sr_f, cpu_env, t1, t0); + fn(cpu_sr_f, tcg_env, t1, t0); } else { - fn(cpu_sr_f, cpu_env, t0, t1); + fn(cpu_sr_f, tcg_env, t0, t1); } if (inv) { tcg_gen_xori_tl(cpu_sr_f, cpu_sr_f, 1); } - gen_helper_update_fpcsr(cpu_env); + gen_helper_update_fpcsr(tcg_env); return true; } @@ -1412,10 +1412,10 @@ static bool trans_lf_stod_d(DisasContext *dc, arg_lf_stod_d *a) check_r0_write(dc, a->d); t0 = tcg_temp_new_i64(); - gen_helper_stod(t0, cpu_env, cpu_R(dc, a->a)); + gen_helper_stod(t0, tcg_env, cpu_R(dc, a->a)); save_pair(dc, t0, a->d, a->dp); - gen_helper_update_fpcsr(cpu_env); + gen_helper_update_fpcsr(tcg_env); return true; } @@ -1431,9 +1431,9 @@ static bool trans_lf_dtos_d(DisasContext *dc, arg_lf_dtos_d *a) t0 = tcg_temp_new_i64(); load_pair(dc, t0, a->a, a->ap); - gen_helper_dtos(cpu_R(dc, a->d), cpu_env, t0); + gen_helper_dtos(cpu_R(dc, a->d), tcg_env, t0); - gen_helper_update_fpcsr(cpu_env); + gen_helper_update_fpcsr(tcg_env); return true; } @@ -1455,10 +1455,10 @@ static bool trans_lf_madd_d(DisasContext *dc, arg_dab_pair *a) load_pair(dc, t0, a->d, a->dp); load_pair(dc, t1, a->a, a->ap); load_pair(dc, t2, a->b, a->bp); - gen_helper_float_madd_d(t0, cpu_env, t0, t1, t2); + gen_helper_float_madd_d(t0, tcg_env, t0, t1, t2); save_pair(dc, t0, a->d, a->dp); - gen_helper_update_fpcsr(cpu_env); + gen_helper_update_fpcsr(tcg_env); return true; } diff --git a/target/ppc/power8-pmu-regs.c.inc b/target/ppc/power8-pmu-regs.c.inc index 75513db894..4956a8b350 100644 --- a/target/ppc/power8-pmu-regs.c.inc +++ b/target/ppc/power8-pmu-regs.c.inc @@ -106,7 +106,7 @@ static void write_MMCR0_common(DisasContext *ctx, TCGv val) * translator_io_start() beforehand. */ translator_io_start(&ctx->base); - gen_helper_store_mmcr0(cpu_env, val); + gen_helper_store_mmcr0(tcg_env, val); /* * End the translation block because MMCR0 writes can change @@ -180,7 +180,7 @@ void spr_read_PMC(DisasContext *ctx, int gprn, int sprn) TCGv_i32 t_sprn = tcg_constant_i32(sprn); translator_io_start(&ctx->base); - gen_helper_read_pmc(cpu_gpr[gprn], cpu_env, t_sprn); + gen_helper_read_pmc(cpu_gpr[gprn], tcg_env, t_sprn); } void spr_read_PMC14_ureg(DisasContext *ctx, int gprn, int sprn) @@ -213,7 +213,7 @@ void spr_write_PMC(DisasContext *ctx, int sprn, int gprn) TCGv_i32 t_sprn = tcg_constant_i32(sprn); translator_io_start(&ctx->base); - gen_helper_store_pmc(cpu_env, t_sprn, cpu_gpr[gprn]); + gen_helper_store_pmc(tcg_env, t_sprn, cpu_gpr[gprn]); } void spr_write_PMC14_ureg(DisasContext *ctx, int sprn, int gprn) @@ -249,7 +249,7 @@ void spr_write_MMCR0(DisasContext *ctx, int sprn, int gprn) void spr_write_MMCR1(DisasContext *ctx, int sprn, int gprn) { translator_io_start(&ctx->base); - gen_helper_store_mmcr1(cpu_env, cpu_gpr[gprn]); + gen_helper_store_mmcr1(tcg_env, cpu_gpr[gprn]); } #else void spr_read_MMCR0_ureg(DisasContext *ctx, int gprn, int sprn) diff --git a/target/ppc/translate.c b/target/ppc/translate.c index 5c28afbbb8..e20a1bea62 100644 --- a/target/ppc/translate.c +++ b/target/ppc/translate.c @@ -92,7 +92,7 @@ void ppc_translate_init(void) for (i = 0; i < 8; i++) { snprintf(p, cpu_reg_names_size, "crf%d", i); - cpu_crf[i] = tcg_global_mem_new_i32(cpu_env, + cpu_crf[i] = tcg_global_mem_new_i32(tcg_env, offsetof(CPUPPCState, crf[i]), p); p += 5; cpu_reg_names_size -= 5; @@ -100,67 +100,67 @@ void ppc_translate_init(void) for (i = 0; i < 32; i++) { snprintf(p, cpu_reg_names_size, "r%d", i); - cpu_gpr[i] = tcg_global_mem_new(cpu_env, + cpu_gpr[i] = tcg_global_mem_new(tcg_env, offsetof(CPUPPCState, gpr[i]), p); p += (i < 10) ? 3 : 4; cpu_reg_names_size -= (i < 10) ? 3 : 4; snprintf(p, cpu_reg_names_size, "r%dH", i); - cpu_gprh[i] = tcg_global_mem_new(cpu_env, + cpu_gprh[i] = tcg_global_mem_new(tcg_env, offsetof(CPUPPCState, gprh[i]), p); p += (i < 10) ? 4 : 5; cpu_reg_names_size -= (i < 10) ? 4 : 5; } - cpu_nip = tcg_global_mem_new(cpu_env, + cpu_nip = tcg_global_mem_new(tcg_env, offsetof(CPUPPCState, nip), "nip"); - cpu_msr = tcg_global_mem_new(cpu_env, + cpu_msr = tcg_global_mem_new(tcg_env, offsetof(CPUPPCState, msr), "msr"); - cpu_ctr = tcg_global_mem_new(cpu_env, + cpu_ctr = tcg_global_mem_new(tcg_env, offsetof(CPUPPCState, ctr), "ctr"); - cpu_lr = tcg_global_mem_new(cpu_env, + cpu_lr = tcg_global_mem_new(tcg_env, offsetof(CPUPPCState, lr), "lr"); #if defined(TARGET_PPC64) - cpu_cfar = tcg_global_mem_new(cpu_env, + cpu_cfar = tcg_global_mem_new(tcg_env, offsetof(CPUPPCState, cfar), "cfar"); #endif - cpu_xer = tcg_global_mem_new(cpu_env, + cpu_xer = tcg_global_mem_new(tcg_env, offsetof(CPUPPCState, xer), "xer"); - cpu_so = tcg_global_mem_new(cpu_env, + cpu_so = tcg_global_mem_new(tcg_env, offsetof(CPUPPCState, so), "SO"); - cpu_ov = tcg_global_mem_new(cpu_env, + cpu_ov = tcg_global_mem_new(tcg_env, offsetof(CPUPPCState, ov), "OV"); - cpu_ca = tcg_global_mem_new(cpu_env, + cpu_ca = tcg_global_mem_new(tcg_env, offsetof(CPUPPCState, ca), "CA"); - cpu_ov32 = tcg_global_mem_new(cpu_env, + cpu_ov32 = tcg_global_mem_new(tcg_env, offsetof(CPUPPCState, ov32), "OV32"); - cpu_ca32 = tcg_global_mem_new(cpu_env, + cpu_ca32 = tcg_global_mem_new(tcg_env, offsetof(CPUPPCState, ca32), "CA32"); - cpu_reserve = tcg_global_mem_new(cpu_env, + cpu_reserve = tcg_global_mem_new(tcg_env, offsetof(CPUPPCState, reserve_addr), "reserve_addr"); - cpu_reserve_length = tcg_global_mem_new(cpu_env, + cpu_reserve_length = tcg_global_mem_new(tcg_env, offsetof(CPUPPCState, reserve_length), "reserve_length"); - cpu_reserve_val = tcg_global_mem_new(cpu_env, + cpu_reserve_val = tcg_global_mem_new(tcg_env, offsetof(CPUPPCState, reserve_val), "reserve_val"); #if defined(TARGET_PPC64) - cpu_reserve_val2 = tcg_global_mem_new(cpu_env, + cpu_reserve_val2 = tcg_global_mem_new(tcg_env, offsetof(CPUPPCState, reserve_val2), "reserve_val2"); #endif - cpu_fpscr = tcg_global_mem_new(cpu_env, + cpu_fpscr = tcg_global_mem_new(tcg_env, offsetof(CPUPPCState, fpscr), "fpscr"); - cpu_access_type = tcg_global_mem_new_i32(cpu_env, + cpu_access_type = tcg_global_mem_new_i32(tcg_env, offsetof(CPUPPCState, access_type), "access_type"); } @@ -240,7 +240,7 @@ static inline bool gen_serialize(DisasContext *ctx) { if (tb_cflags(ctx->base.tb) & CF_PARALLEL) { /* Restart with exclusive lock. */ - gen_helper_exit_atomic(cpu_env); + gen_helper_exit_atomic(tcg_env); ctx->base.is_jmp = DISAS_NORETURN; return false; } @@ -261,12 +261,12 @@ static inline bool gen_serialize_core_lpar(DisasContext *ctx) /* SPR load/store helpers */ static inline void gen_load_spr(TCGv t, int reg) { - tcg_gen_ld_tl(t, cpu_env, offsetof(CPUPPCState, spr[reg])); + tcg_gen_ld_tl(t, tcg_env, offsetof(CPUPPCState, spr[reg])); } static inline void gen_store_spr(int reg, TCGv t) { - tcg_gen_st_tl(t, cpu_env, offsetof(CPUPPCState, spr[reg])); + tcg_gen_st_tl(t, tcg_env, offsetof(CPUPPCState, spr[reg])); } static inline void gen_set_access_type(DisasContext *ctx, int access_type) @@ -296,7 +296,7 @@ static void gen_exception_err(DisasContext *ctx, uint32_t excp, uint32_t error) gen_update_nip(ctx, ctx->cia); t0 = tcg_constant_i32(excp); t1 = tcg_constant_i32(error); - gen_helper_raise_exception_err(cpu_env, t0, t1); + gen_helper_raise_exception_err(tcg_env, t0, t1); ctx->base.is_jmp = DISAS_NORETURN; } @@ -310,7 +310,7 @@ static void gen_exception(DisasContext *ctx, uint32_t excp) */ gen_update_nip(ctx, ctx->cia); t0 = tcg_constant_i32(excp); - gen_helper_raise_exception(cpu_env, t0); + gen_helper_raise_exception(tcg_env, t0); ctx->base.is_jmp = DISAS_NORETURN; } @@ -321,7 +321,7 @@ static void gen_exception_nip(DisasContext *ctx, uint32_t excp, gen_update_nip(ctx, nip); t0 = tcg_constant_i32(excp); - gen_helper_raise_exception(cpu_env, t0); + gen_helper_raise_exception(tcg_env, t0); ctx->base.is_jmp = DISAS_NORETURN; } @@ -329,7 +329,7 @@ static void gen_exception_nip(DisasContext *ctx, uint32_t excp, static void gen_ppc_maybe_interrupt(DisasContext *ctx) { translator_io_start(&ctx->base); - gen_helper_ppc_maybe_interrupt(cpu_env); + gen_helper_ppc_maybe_interrupt(tcg_env); } #endif @@ -355,14 +355,14 @@ static void gen_debug_exception(DisasContext *ctx, bool rfi_type) gen_load_spr(t0, SPR_BOOKE_DBSR); tcg_gen_ori_tl(t0, t0, dbsr); gen_store_spr(SPR_BOOKE_DBSR, t0); - gen_helper_raise_exception(cpu_env, + gen_helper_raise_exception(tcg_env, tcg_constant_i32(POWERPC_EXCP_DEBUG)); ctx->base.is_jmp = DISAS_NORETURN; } else { if (!rfi_type) { /* BookS does not single step rfi type instructions */ TCGv t0 = tcg_temp_new(); tcg_gen_movi_tl(t0, ctx->cia); - gen_helper_book3s_trace(cpu_env, t0); + gen_helper_book3s_trace(tcg_env, t0); ctx->base.is_jmp = DISAS_NORETURN; } } @@ -407,7 +407,7 @@ static void spr_load_dump_spr(int sprn) { #ifdef PPC_DUMP_SPR_ACCESSES TCGv_i32 t0 = tcg_constant_i32(sprn); - gen_helper_load_dump_spr(cpu_env, t0); + gen_helper_load_dump_spr(tcg_env, t0); #endif } @@ -421,7 +421,7 @@ static void spr_store_dump_spr(int sprn) { #ifdef PPC_DUMP_SPR_ACCESSES TCGv_i32 t0 = tcg_constant_i32(sprn); - gen_helper_store_dump_spr(cpu_env, t0); + gen_helper_store_dump_spr(tcg_env, t0); #endif } @@ -454,7 +454,7 @@ void spr_core_write_generic(DisasContext *ctx, int sprn, int gprn) return; } - gen_helper_spr_core_write_generic(cpu_env, tcg_constant_i32(sprn), + gen_helper_spr_core_write_generic(tcg_env, tcg_constant_i32(sprn), cpu_gpr[gprn]); spr_store_dump_spr(sprn); } @@ -482,7 +482,7 @@ void spr_write_CTRL(DisasContext *ctx, int sprn, int gprn) return; } - gen_helper_spr_write_CTRL(cpu_env, tcg_constant_i32(sprn), + gen_helper_spr_write_CTRL(tcg_env, tcg_constant_i32(sprn), cpu_gpr[gprn]); out: spr_store_dump_spr(sprn); @@ -578,20 +578,20 @@ void spr_write_cfar(DisasContext *ctx, int sprn, int gprn) void spr_write_ciabr(DisasContext *ctx, int sprn, int gprn) { translator_io_start(&ctx->base); - gen_helper_store_ciabr(cpu_env, cpu_gpr[gprn]); + gen_helper_store_ciabr(tcg_env, cpu_gpr[gprn]); } /* Watchpoint */ void spr_write_dawr0(DisasContext *ctx, int sprn, int gprn) { translator_io_start(&ctx->base); - gen_helper_store_dawr0(cpu_env, cpu_gpr[gprn]); + gen_helper_store_dawr0(tcg_env, cpu_gpr[gprn]); } void spr_write_dawrx0(DisasContext *ctx, int sprn, int gprn) { translator_io_start(&ctx->base); - gen_helper_store_dawrx0(cpu_env, cpu_gpr[gprn]); + gen_helper_store_dawrx0(tcg_env, cpu_gpr[gprn]); } #endif /* defined(TARGET_PPC64) && !defined(CONFIG_USER_ONLY) */ @@ -630,13 +630,13 @@ void spr_write_ureg(DisasContext *ctx, int sprn, int gprn) void spr_read_decr(DisasContext *ctx, int gprn, int sprn) { translator_io_start(&ctx->base); - gen_helper_load_decr(cpu_gpr[gprn], cpu_env); + gen_helper_load_decr(cpu_gpr[gprn], tcg_env); } void spr_write_decr(DisasContext *ctx, int sprn, int gprn) { translator_io_start(&ctx->base); - gen_helper_store_decr(cpu_env, cpu_gpr[gprn]); + gen_helper_store_decr(tcg_env, cpu_gpr[gprn]); } #endif @@ -645,90 +645,90 @@ void spr_write_decr(DisasContext *ctx, int sprn, int gprn) void spr_read_tbl(DisasContext *ctx, int gprn, int sprn) { translator_io_start(&ctx->base); - gen_helper_load_tbl(cpu_gpr[gprn], cpu_env); + gen_helper_load_tbl(cpu_gpr[gprn], tcg_env); } void spr_read_tbu(DisasContext *ctx, int gprn, int sprn) { translator_io_start(&ctx->base); - gen_helper_load_tbu(cpu_gpr[gprn], cpu_env); + gen_helper_load_tbu(cpu_gpr[gprn], tcg_env); } void spr_read_atbl(DisasContext *ctx, int gprn, int sprn) { - gen_helper_load_atbl(cpu_gpr[gprn], cpu_env); + gen_helper_load_atbl(cpu_gpr[gprn], tcg_env); } void spr_read_atbu(DisasContext *ctx, int gprn, int sprn) { - gen_helper_load_atbu(cpu_gpr[gprn], cpu_env); + gen_helper_load_atbu(cpu_gpr[gprn], tcg_env); } #if !defined(CONFIG_USER_ONLY) void spr_write_tbl(DisasContext *ctx, int sprn, int gprn) { translator_io_start(&ctx->base); - gen_helper_store_tbl(cpu_env, cpu_gpr[gprn]); + gen_helper_store_tbl(tcg_env, cpu_gpr[gprn]); } void spr_write_tbu(DisasContext *ctx, int sprn, int gprn) { translator_io_start(&ctx->base); - gen_helper_store_tbu(cpu_env, cpu_gpr[gprn]); + gen_helper_store_tbu(tcg_env, cpu_gpr[gprn]); } void spr_write_atbl(DisasContext *ctx, int sprn, int gprn) { - gen_helper_store_atbl(cpu_env, cpu_gpr[gprn]); + gen_helper_store_atbl(tcg_env, cpu_gpr[gprn]); } void spr_write_atbu(DisasContext *ctx, int sprn, int gprn) { - gen_helper_store_atbu(cpu_env, cpu_gpr[gprn]); + gen_helper_store_atbu(tcg_env, cpu_gpr[gprn]); } #if defined(TARGET_PPC64) void spr_read_purr(DisasContext *ctx, int gprn, int sprn) { translator_io_start(&ctx->base); - gen_helper_load_purr(cpu_gpr[gprn], cpu_env); + gen_helper_load_purr(cpu_gpr[gprn], tcg_env); } void spr_write_purr(DisasContext *ctx, int sprn, int gprn) { translator_io_start(&ctx->base); - gen_helper_store_purr(cpu_env, cpu_gpr[gprn]); + gen_helper_store_purr(tcg_env, cpu_gpr[gprn]); } /* HDECR */ void spr_read_hdecr(DisasContext *ctx, int gprn, int sprn) { translator_io_start(&ctx->base); - gen_helper_load_hdecr(cpu_gpr[gprn], cpu_env); + gen_helper_load_hdecr(cpu_gpr[gprn], tcg_env); } void spr_write_hdecr(DisasContext *ctx, int sprn, int gprn) { translator_io_start(&ctx->base); - gen_helper_store_hdecr(cpu_env, cpu_gpr[gprn]); + gen_helper_store_hdecr(tcg_env, cpu_gpr[gprn]); } void spr_read_vtb(DisasContext *ctx, int gprn, int sprn) { translator_io_start(&ctx->base); - gen_helper_load_vtb(cpu_gpr[gprn], cpu_env); + gen_helper_load_vtb(cpu_gpr[gprn], tcg_env); } void spr_write_vtb(DisasContext *ctx, int sprn, int gprn) { translator_io_start(&ctx->base); - gen_helper_store_vtb(cpu_env, cpu_gpr[gprn]); + gen_helper_store_vtb(tcg_env, cpu_gpr[gprn]); } void spr_write_tbu40(DisasContext *ctx, int sprn, int gprn) { translator_io_start(&ctx->base); - gen_helper_store_tbu40(cpu_env, cpu_gpr[gprn]); + gen_helper_store_tbu40(tcg_env, cpu_gpr[gprn]); } #endif @@ -739,14 +739,14 @@ void spr_write_tbu40(DisasContext *ctx, int sprn, int gprn) /* IBAT0L...IBAT7L */ void spr_read_ibat(DisasContext *ctx, int gprn, int sprn) { - tcg_gen_ld_tl(cpu_gpr[gprn], cpu_env, + tcg_gen_ld_tl(cpu_gpr[gprn], tcg_env, offsetof(CPUPPCState, IBAT[sprn & 1][(sprn - SPR_IBAT0U) / 2])); } void spr_read_ibat_h(DisasContext *ctx, int gprn, int sprn) { - tcg_gen_ld_tl(cpu_gpr[gprn], cpu_env, + tcg_gen_ld_tl(cpu_gpr[gprn], tcg_env, offsetof(CPUPPCState, IBAT[sprn & 1][((sprn - SPR_IBAT4U) / 2) + 4])); } @@ -754,39 +754,39 @@ void spr_read_ibat_h(DisasContext *ctx, int gprn, int sprn) void spr_write_ibatu(DisasContext *ctx, int sprn, int gprn) { TCGv_i32 t0 = tcg_constant_i32((sprn - SPR_IBAT0U) / 2); - gen_helper_store_ibatu(cpu_env, t0, cpu_gpr[gprn]); + gen_helper_store_ibatu(tcg_env, t0, cpu_gpr[gprn]); } void spr_write_ibatu_h(DisasContext *ctx, int sprn, int gprn) { TCGv_i32 t0 = tcg_constant_i32(((sprn - SPR_IBAT4U) / 2) + 4); - gen_helper_store_ibatu(cpu_env, t0, cpu_gpr[gprn]); + gen_helper_store_ibatu(tcg_env, t0, cpu_gpr[gprn]); } void spr_write_ibatl(DisasContext *ctx, int sprn, int gprn) { TCGv_i32 t0 = tcg_constant_i32((sprn - SPR_IBAT0L) / 2); - gen_helper_store_ibatl(cpu_env, t0, cpu_gpr[gprn]); + gen_helper_store_ibatl(tcg_env, t0, cpu_gpr[gprn]); } void spr_write_ibatl_h(DisasContext *ctx, int sprn, int gprn) { TCGv_i32 t0 = tcg_constant_i32(((sprn - SPR_IBAT4L) / 2) + 4); - gen_helper_store_ibatl(cpu_env, t0, cpu_gpr[gprn]); + gen_helper_store_ibatl(tcg_env, t0, cpu_gpr[gprn]); } /* DBAT0U...DBAT7U */ /* DBAT0L...DBAT7L */ void spr_read_dbat(DisasContext *ctx, int gprn, int sprn) { - tcg_gen_ld_tl(cpu_gpr[gprn], cpu_env, + tcg_gen_ld_tl(cpu_gpr[gprn], tcg_env, offsetof(CPUPPCState, DBAT[sprn & 1][(sprn - SPR_DBAT0U) / 2])); } void spr_read_dbat_h(DisasContext *ctx, int gprn, int sprn) { - tcg_gen_ld_tl(cpu_gpr[gprn], cpu_env, + tcg_gen_ld_tl(cpu_gpr[gprn], tcg_env, offsetof(CPUPPCState, DBAT[sprn & 1][((sprn - SPR_DBAT4U) / 2) + 4])); } @@ -794,31 +794,31 @@ void spr_read_dbat_h(DisasContext *ctx, int gprn, int sprn) void spr_write_dbatu(DisasContext *ctx, int sprn, int gprn) { TCGv_i32 t0 = tcg_constant_i32((sprn - SPR_DBAT0U) / 2); - gen_helper_store_dbatu(cpu_env, t0, cpu_gpr[gprn]); + gen_helper_store_dbatu(tcg_env, t0, cpu_gpr[gprn]); } void spr_write_dbatu_h(DisasContext *ctx, int sprn, int gprn) { TCGv_i32 t0 = tcg_constant_i32(((sprn - SPR_DBAT4U) / 2) + 4); - gen_helper_store_dbatu(cpu_env, t0, cpu_gpr[gprn]); + gen_helper_store_dbatu(tcg_env, t0, cpu_gpr[gprn]); } void spr_write_dbatl(DisasContext *ctx, int sprn, int gprn) { TCGv_i32 t0 = tcg_constant_i32((sprn - SPR_DBAT0L) / 2); - gen_helper_store_dbatl(cpu_env, t0, cpu_gpr[gprn]); + gen_helper_store_dbatl(tcg_env, t0, cpu_gpr[gprn]); } void spr_write_dbatl_h(DisasContext *ctx, int sprn, int gprn) { TCGv_i32 t0 = tcg_constant_i32(((sprn - SPR_DBAT4L) / 2) + 4); - gen_helper_store_dbatl(cpu_env, t0, cpu_gpr[gprn]); + gen_helper_store_dbatl(tcg_env, t0, cpu_gpr[gprn]); } /* SDR1 */ void spr_write_sdr1(DisasContext *ctx, int sprn, int gprn) { - gen_helper_store_sdr1(cpu_env, cpu_gpr[gprn]); + gen_helper_store_sdr1(tcg_env, cpu_gpr[gprn]); } #if defined(TARGET_PPC64) @@ -826,33 +826,33 @@ void spr_write_sdr1(DisasContext *ctx, int sprn, int gprn) /* PIDR */ void spr_write_pidr(DisasContext *ctx, int sprn, int gprn) { - gen_helper_store_pidr(cpu_env, cpu_gpr[gprn]); + gen_helper_store_pidr(tcg_env, cpu_gpr[gprn]); } void spr_write_lpidr(DisasContext *ctx, int sprn, int gprn) { - gen_helper_store_lpidr(cpu_env, cpu_gpr[gprn]); + gen_helper_store_lpidr(tcg_env, cpu_gpr[gprn]); } void spr_read_hior(DisasContext *ctx, int gprn, int sprn) { - tcg_gen_ld_tl(cpu_gpr[gprn], cpu_env, offsetof(CPUPPCState, excp_prefix)); + tcg_gen_ld_tl(cpu_gpr[gprn], tcg_env, offsetof(CPUPPCState, excp_prefix)); } void spr_write_hior(DisasContext *ctx, int sprn, int gprn) { TCGv t0 = tcg_temp_new(); tcg_gen_andi_tl(t0, cpu_gpr[gprn], 0x3FFFFF00000ULL); - tcg_gen_st_tl(t0, cpu_env, offsetof(CPUPPCState, excp_prefix)); + tcg_gen_st_tl(t0, tcg_env, offsetof(CPUPPCState, excp_prefix)); } void spr_write_ptcr(DisasContext *ctx, int sprn, int gprn) { - gen_helper_store_ptcr(cpu_env, cpu_gpr[gprn]); + gen_helper_store_ptcr(tcg_env, cpu_gpr[gprn]); } void spr_write_pcr(DisasContext *ctx, int sprn, int gprn) { - gen_helper_store_pcr(cpu_env, cpu_gpr[gprn]); + gen_helper_store_pcr(tcg_env, cpu_gpr[gprn]); } /* DPDES */ @@ -862,7 +862,7 @@ void spr_read_dpdes(DisasContext *ctx, int gprn, int sprn) return; } - gen_helper_load_dpdes(cpu_gpr[gprn], cpu_env); + gen_helper_load_dpdes(cpu_gpr[gprn], tcg_env); } void spr_write_dpdes(DisasContext *ctx, int sprn, int gprn) @@ -871,7 +871,7 @@ void spr_write_dpdes(DisasContext *ctx, int sprn, int gprn) return; } - gen_helper_store_dpdes(cpu_env, cpu_gpr[gprn]); + gen_helper_store_dpdes(tcg_env, cpu_gpr[gprn]); } #endif #endif @@ -881,20 +881,20 @@ void spr_write_dpdes(DisasContext *ctx, int sprn, int gprn) void spr_read_40x_pit(DisasContext *ctx, int gprn, int sprn) { translator_io_start(&ctx->base); - gen_helper_load_40x_pit(cpu_gpr[gprn], cpu_env); + gen_helper_load_40x_pit(cpu_gpr[gprn], tcg_env); } void spr_write_40x_pit(DisasContext *ctx, int sprn, int gprn) { translator_io_start(&ctx->base); - gen_helper_store_40x_pit(cpu_env, cpu_gpr[gprn]); + gen_helper_store_40x_pit(tcg_env, cpu_gpr[gprn]); } void spr_write_40x_dbcr0(DisasContext *ctx, int sprn, int gprn) { translator_io_start(&ctx->base); gen_store_spr(sprn, cpu_gpr[gprn]); - gen_helper_store_40x_dbcr0(cpu_env, cpu_gpr[gprn]); + gen_helper_store_40x_dbcr0(tcg_env, cpu_gpr[gprn]); /* We must stop translation as we may have rebooted */ ctx->base.is_jmp = DISAS_EXIT_UPDATE; } @@ -902,38 +902,38 @@ void spr_write_40x_dbcr0(DisasContext *ctx, int sprn, int gprn) void spr_write_40x_sler(DisasContext *ctx, int sprn, int gprn) { translator_io_start(&ctx->base); - gen_helper_store_40x_sler(cpu_env, cpu_gpr[gprn]); + gen_helper_store_40x_sler(tcg_env, cpu_gpr[gprn]); } void spr_write_40x_tcr(DisasContext *ctx, int sprn, int gprn) { translator_io_start(&ctx->base); - gen_helper_store_40x_tcr(cpu_env, cpu_gpr[gprn]); + gen_helper_store_40x_tcr(tcg_env, cpu_gpr[gprn]); } void spr_write_40x_tsr(DisasContext *ctx, int sprn, int gprn) { translator_io_start(&ctx->base); - gen_helper_store_40x_tsr(cpu_env, cpu_gpr[gprn]); + gen_helper_store_40x_tsr(tcg_env, cpu_gpr[gprn]); } void spr_write_40x_pid(DisasContext *ctx, int sprn, int gprn) { TCGv t0 = tcg_temp_new(); tcg_gen_andi_tl(t0, cpu_gpr[gprn], 0xFF); - gen_helper_store_40x_pid(cpu_env, t0); + gen_helper_store_40x_pid(tcg_env, t0); } void spr_write_booke_tcr(DisasContext *ctx, int sprn, int gprn) { translator_io_start(&ctx->base); - gen_helper_store_booke_tcr(cpu_env, cpu_gpr[gprn]); + gen_helper_store_booke_tcr(tcg_env, cpu_gpr[gprn]); } void spr_write_booke_tsr(DisasContext *ctx, int sprn, int gprn) { translator_io_start(&ctx->base); - gen_helper_store_booke_tsr(cpu_env, cpu_gpr[gprn]); + gen_helper_store_booke_tsr(tcg_env, cpu_gpr[gprn]); } #endif @@ -951,7 +951,7 @@ void spr_write_pir(DisasContext *ctx, int sprn, int gprn) void spr_read_spefscr(DisasContext *ctx, int gprn, int sprn) { TCGv_i32 t0 = tcg_temp_new_i32(); - tcg_gen_ld_i32(t0, cpu_env, offsetof(CPUPPCState, spe_fscr)); + tcg_gen_ld_i32(t0, tcg_env, offsetof(CPUPPCState, spe_fscr)); tcg_gen_extu_i32_tl(cpu_gpr[gprn], t0); } @@ -959,7 +959,7 @@ void spr_write_spefscr(DisasContext *ctx, int sprn, int gprn) { TCGv_i32 t0 = tcg_temp_new_i32(); tcg_gen_trunc_tl_i32(t0, cpu_gpr[gprn]); - tcg_gen_st_i32(t0, cpu_env, offsetof(CPUPPCState, spe_fscr)); + tcg_gen_st_i32(t0, tcg_env, offsetof(CPUPPCState, spe_fscr)); } #if !defined(CONFIG_USER_ONLY) @@ -967,9 +967,9 @@ void spr_write_spefscr(DisasContext *ctx, int sprn, int gprn) void spr_write_excp_prefix(DisasContext *ctx, int sprn, int gprn) { TCGv t0 = tcg_temp_new(); - tcg_gen_ld_tl(t0, cpu_env, offsetof(CPUPPCState, ivpr_mask)); + tcg_gen_ld_tl(t0, tcg_env, offsetof(CPUPPCState, ivpr_mask)); tcg_gen_and_tl(t0, t0, cpu_gpr[gprn]); - tcg_gen_st_tl(t0, cpu_env, offsetof(CPUPPCState, excp_prefix)); + tcg_gen_st_tl(t0, tcg_env, offsetof(CPUPPCState, excp_prefix)); gen_store_spr(sprn, t0); } @@ -991,9 +991,9 @@ void spr_write_excp_vector(DisasContext *ctx, int sprn, int gprn) } TCGv t0 = tcg_temp_new(); - tcg_gen_ld_tl(t0, cpu_env, offsetof(CPUPPCState, ivor_mask)); + tcg_gen_ld_tl(t0, tcg_env, offsetof(CPUPPCState, ivor_mask)); tcg_gen_and_tl(t0, t0, cpu_gpr[gprn]); - tcg_gen_st_tl(t0, cpu_env, offsetof(CPUPPCState, excp_vectors[sprn_offs])); + tcg_gen_st_tl(t0, tcg_env, offsetof(CPUPPCState, excp_vectors[sprn_offs])); gen_store_spr(sprn, t0); } #endif @@ -1090,7 +1090,7 @@ void spr_write_iamr(DisasContext *ctx, int sprn, int gprn) #ifndef CONFIG_USER_ONLY void spr_read_thrm(DisasContext *ctx, int gprn, int sprn) { - gen_helper_fixup_thrm(cpu_env); + gen_helper_fixup_thrm(tcg_env); gen_load_spr(cpu_gpr[gprn], sprn); spr_load_dump_spr(sprn); } @@ -1124,23 +1124,23 @@ void spr_write_e500_l2csr0(DisasContext *ctx, int sprn, int gprn) void spr_write_booke206_mmucsr0(DisasContext *ctx, int sprn, int gprn) { - gen_helper_booke206_tlbflush(cpu_env, cpu_gpr[gprn]); + gen_helper_booke206_tlbflush(tcg_env, cpu_gpr[gprn]); } void spr_write_booke_pid(DisasContext *ctx, int sprn, int gprn) { TCGv_i32 t0 = tcg_constant_i32(sprn); - gen_helper_booke_setpid(cpu_env, t0, cpu_gpr[gprn]); + gen_helper_booke_setpid(tcg_env, t0, cpu_gpr[gprn]); } void spr_write_eplc(DisasContext *ctx, int sprn, int gprn) { - gen_helper_booke_set_eplc(cpu_env, cpu_gpr[gprn]); + gen_helper_booke_set_eplc(tcg_env, cpu_gpr[gprn]); } void spr_write_epsc(DisasContext *ctx, int sprn, int gprn) { - gen_helper_booke_set_epsc(cpu_env, cpu_gpr[gprn]); + gen_helper_booke_set_epsc(tcg_env, cpu_gpr[gprn]); } #endif @@ -1175,7 +1175,7 @@ static void gen_fscr_facility_check(DisasContext *ctx, int facility_sprn, TCGv_i32 t2 = tcg_constant_i32(sprn); TCGv_i32 t3 = tcg_constant_i32(cause); - gen_helper_fscr_facility_check(cpu_env, t1, t2, t3); + gen_helper_fscr_facility_check(tcg_env, t1, t2, t3); } static void gen_msr_facility_check(DisasContext *ctx, int facility_sprn, @@ -1185,7 +1185,7 @@ static void gen_msr_facility_check(DisasContext *ctx, int facility_sprn, TCGv_i32 t2 = tcg_constant_i32(sprn); TCGv_i32 t3 = tcg_constant_i32(cause); - gen_helper_msr_facility_check(cpu_env, t1, t2, t3); + gen_helper_msr_facility_check(tcg_env, t1, t2, t3); } void spr_read_prev_upper32(DisasContext *ctx, int gprn, int sprn) @@ -1220,18 +1220,18 @@ void spr_write_hmer(DisasContext *ctx, int sprn, int gprn) void spr_read_tfmr(DisasContext *ctx, int gprn, int sprn) { - gen_helper_load_tfmr(cpu_gpr[gprn], cpu_env); + gen_helper_load_tfmr(cpu_gpr[gprn], tcg_env); } void spr_write_tfmr(DisasContext *ctx, int sprn, int gprn) { - gen_helper_store_tfmr(cpu_env, cpu_gpr[gprn]); + gen_helper_store_tfmr(tcg_env, cpu_gpr[gprn]); } void spr_write_lpcr(DisasContext *ctx, int sprn, int gprn) { translator_io_start(&ctx->base); - gen_helper_store_lpcr(cpu_env, cpu_gpr[gprn]); + gen_helper_store_lpcr(tcg_env, cpu_gpr[gprn]); } #endif /* !defined(CONFIG_USER_ONLY) */ @@ -1812,7 +1812,7 @@ GEN_INT_ARITH_DIVW(divwo, 0x1F, 1, 1); static void gen_##name(DisasContext *ctx) \ { \ TCGv_i32 t0 = tcg_constant_i32(compute_ov); \ - gen_helper_##hlpr(cpu_gpr[rD(ctx->opcode)], cpu_env, \ + gen_helper_##hlpr(cpu_gpr[rD(ctx->opcode)], tcg_env, \ cpu_gpr[rA(ctx->opcode)], cpu_gpr[rB(ctx->opcode)], t0); \ if (unlikely(Rc(ctx->opcode) != 0)) { \ gen_set_Rc0(ctx, cpu_gpr[rD(ctx->opcode)]); \ @@ -2317,7 +2317,7 @@ GEN_LOGICAL2(nor, tcg_gen_nor_tl, 0x03, PPC_INTEGER); static void gen_pause(DisasContext *ctx) { TCGv_i32 t0 = tcg_constant_i32(0); - tcg_gen_st_i32(t0, cpu_env, + tcg_gen_st_i32(t0, tcg_env, -offsetof(PowerPCCPU, env) + offsetof(CPUState, halted)); /* Stop translation, this gives other CPUs a chance to run */ @@ -2912,7 +2912,7 @@ static void gen_slw(DisasContext *ctx) /* sraw & sraw. */ static void gen_sraw(DisasContext *ctx) { - gen_helper_sraw(cpu_gpr[rA(ctx->opcode)], cpu_env, + gen_helper_sraw(cpu_gpr[rA(ctx->opcode)], tcg_env, cpu_gpr[rS(ctx->opcode)], cpu_gpr[rB(ctx->opcode)]); if (unlikely(Rc(ctx->opcode) != 0)) { gen_set_Rc0(ctx, cpu_gpr[rA(ctx->opcode)]); @@ -2995,7 +2995,7 @@ static void gen_sld(DisasContext *ctx) /* srad & srad. */ static void gen_srad(DisasContext *ctx) { - gen_helper_srad(cpu_gpr[rA(ctx->opcode)], cpu_env, + gen_helper_srad(cpu_gpr[rA(ctx->opcode)], tcg_env, cpu_gpr[rS(ctx->opcode)], cpu_gpr[rB(ctx->opcode)]); if (unlikely(Rc(ctx->opcode) != 0)) { gen_set_Rc0(ctx, cpu_gpr[rA(ctx->opcode)]); @@ -3360,7 +3360,7 @@ static void gen_lmw(DisasContext *ctx) t0 = tcg_temp_new(); t1 = tcg_constant_i32(rD(ctx->opcode)); gen_addr_imm_index(ctx, t0, 0); - gen_helper_lmw(cpu_env, t0, t1); + gen_helper_lmw(tcg_env, t0, t1); } /* stmw */ @@ -3377,7 +3377,7 @@ static void gen_stmw(DisasContext *ctx) t0 = tcg_temp_new(); t1 = tcg_constant_i32(rS(ctx->opcode)); gen_addr_imm_index(ctx, t0, 0); - gen_helper_stmw(cpu_env, t0, t1); + gen_helper_stmw(tcg_env, t0, t1); } /*** Integer load and store strings ***/ @@ -3415,7 +3415,7 @@ static void gen_lswi(DisasContext *ctx) gen_addr_register(ctx, t0); t1 = tcg_constant_i32(nb); t2 = tcg_constant_i32(start); - gen_helper_lsw(cpu_env, t0, t1, t2); + gen_helper_lsw(tcg_env, t0, t1, t2); } /* lswx */ @@ -3434,7 +3434,7 @@ static void gen_lswx(DisasContext *ctx) t1 = tcg_constant_i32(rD(ctx->opcode)); t2 = tcg_constant_i32(rA(ctx->opcode)); t3 = tcg_constant_i32(rB(ctx->opcode)); - gen_helper_lswx(cpu_env, t0, t1, t2, t3); + gen_helper_lswx(tcg_env, t0, t1, t2, t3); } /* stswi */ @@ -3456,7 +3456,7 @@ static void gen_stswi(DisasContext *ctx) } t1 = tcg_constant_i32(nb); t2 = tcg_constant_i32(rS(ctx->opcode)); - gen_helper_stsw(cpu_env, t0, t1, t2); + gen_helper_stsw(tcg_env, t0, t1, t2); } /* stswx */ @@ -3476,7 +3476,7 @@ static void gen_stswx(DisasContext *ctx) tcg_gen_trunc_tl_i32(t1, cpu_xer); tcg_gen_andi_i32(t1, t1, 0x7F); t2 = tcg_constant_i32(rS(ctx->opcode)); - gen_helper_stsw(cpu_env, t0, t1, t2); + gen_helper_stsw(tcg_env, t0, t1, t2); } /*** Memory synchronisation ***/ @@ -3543,12 +3543,12 @@ static inline void gen_check_tlb_flush(DisasContext *ctx, bool global) } l = gen_new_label(); t = tcg_temp_new_i32(); - tcg_gen_ld_i32(t, cpu_env, offsetof(CPUPPCState, tlb_need_flush)); + tcg_gen_ld_i32(t, tcg_env, offsetof(CPUPPCState, tlb_need_flush)); tcg_gen_brcondi_i32(TCG_COND_EQ, t, 0, l); if (global) { - gen_helper_check_tlb_flush_global(cpu_env); + gen_helper_check_tlb_flush_global(tcg_env); } else { - gen_helper_check_tlb_flush_local(cpu_env); + gen_helper_check_tlb_flush_local(tcg_env); } gen_set_label(l); } @@ -3710,7 +3710,7 @@ static void gen_ld_atomic(DisasContext *ctx, MemOp memop) if (need_serial) { /* Restart with exclusive lock. */ - gen_helper_exit_atomic(cpu_env); + gen_helper_exit_atomic(tcg_env); ctx->base.is_jmp = DISAS_NORETURN; } } @@ -3766,7 +3766,7 @@ static void gen_st_atomic(DisasContext *ctx, MemOp memop) case 24: /* Store twin */ if (tb_cflags(ctx->base.tb) & CF_PARALLEL) { /* Restart with exclusive lock. */ - gen_helper_exit_atomic(cpu_env); + gen_helper_exit_atomic(tcg_env); ctx->base.is_jmp = DISAS_NORETURN; } else { TCGv t = tcg_temp_new(); @@ -3876,8 +3876,8 @@ static void gen_lqarx(DisasContext *ctx) tcg_gen_mov_tl(cpu_reserve, EA); tcg_gen_movi_tl(cpu_reserve_length, 16); - tcg_gen_st_tl(hi, cpu_env, offsetof(CPUPPCState, reserve_val)); - tcg_gen_st_tl(lo, cpu_env, offsetof(CPUPPCState, reserve_val2)); + tcg_gen_st_tl(hi, tcg_env, offsetof(CPUPPCState, reserve_val)); + tcg_gen_st_tl(lo, tcg_env, offsetof(CPUPPCState, reserve_val2)); } /* stqcx. */ @@ -4011,7 +4011,7 @@ static void gen_wait(DisasContext *ctx) */ if (wc == 0) { TCGv_i32 t0 = tcg_constant_i32(1); - tcg_gen_st_i32(t0, cpu_env, + tcg_gen_st_i32(t0, tcg_env, -offsetof(PowerPCCPU, env) + offsetof(CPUState, halted)); /* Stop translation, as the CPU is supposed to sleep from now */ gen_exception_nip(ctx, EXCP_HLT, ctx->base.pc_next); @@ -4058,7 +4058,7 @@ static void gen_doze(DisasContext *ctx) CHK_HV(ctx); translator_io_start(&ctx->base); t = tcg_constant_i32(PPC_PM_DOZE); - gen_helper_pminsn(cpu_env, t); + gen_helper_pminsn(tcg_env, t); /* Stop translation, as the CPU is supposed to sleep from now */ gen_exception_nip(ctx, EXCP_HLT, ctx->base.pc_next); #endif /* defined(CONFIG_USER_ONLY) */ @@ -4074,7 +4074,7 @@ static void gen_nap(DisasContext *ctx) CHK_HV(ctx); translator_io_start(&ctx->base); t = tcg_constant_i32(PPC_PM_NAP); - gen_helper_pminsn(cpu_env, t); + gen_helper_pminsn(tcg_env, t); /* Stop translation, as the CPU is supposed to sleep from now */ gen_exception_nip(ctx, EXCP_HLT, ctx->base.pc_next); #endif /* defined(CONFIG_USER_ONLY) */ @@ -4090,7 +4090,7 @@ static void gen_stop(DisasContext *ctx) CHK_HV(ctx); translator_io_start(&ctx->base); t = tcg_constant_i32(PPC_PM_STOP); - gen_helper_pminsn(cpu_env, t); + gen_helper_pminsn(tcg_env, t); /* Stop translation, as the CPU is supposed to sleep from now */ gen_exception_nip(ctx, EXCP_HLT, ctx->base.pc_next); #endif /* defined(CONFIG_USER_ONLY) */ @@ -4106,7 +4106,7 @@ static void gen_sleep(DisasContext *ctx) CHK_HV(ctx); translator_io_start(&ctx->base); t = tcg_constant_i32(PPC_PM_SLEEP); - gen_helper_pminsn(cpu_env, t); + gen_helper_pminsn(tcg_env, t); /* Stop translation, as the CPU is supposed to sleep from now */ gen_exception_nip(ctx, EXCP_HLT, ctx->base.pc_next); #endif /* defined(CONFIG_USER_ONLY) */ @@ -4122,7 +4122,7 @@ static void gen_rvwinkle(DisasContext *ctx) CHK_HV(ctx); translator_io_start(&ctx->base); t = tcg_constant_i32(PPC_PM_RVWINKLE); - gen_helper_pminsn(cpu_env, t); + gen_helper_pminsn(tcg_env, t); /* Stop translation, as the CPU is supposed to sleep from now */ gen_exception_nip(ctx, EXCP_HLT, ctx->base.pc_next); #endif /* defined(CONFIG_USER_ONLY) */ @@ -4172,12 +4172,12 @@ static void pmu_count_insns(DisasContext *ctx) /* Check for overflow, if it's enabled */ if (ctx->mmcr0_pmcjce) { tcg_gen_brcondi_tl(TCG_COND_LT, t0, PMC_COUNTER_NEGATIVE_VAL, l); - gen_helper_handle_pmc5_overflow(cpu_env); + gen_helper_handle_pmc5_overflow(tcg_env); } gen_set_label(l); } else { - gen_helper_insns_inc(cpu_env, tcg_constant_i32(ctx->base.num_insns)); + gen_helper_insns_inc(tcg_env, tcg_constant_i32(ctx->base.num_insns)); } #else /* @@ -4477,7 +4477,7 @@ static void gen_rfi(DisasContext *ctx) CHK_SV(ctx); translator_io_start(&ctx->base); gen_update_cfar(ctx, ctx->cia); - gen_helper_rfi(cpu_env); + gen_helper_rfi(tcg_env); ctx->base.is_jmp = DISAS_EXIT; #endif } @@ -4492,7 +4492,7 @@ static void gen_rfid(DisasContext *ctx) CHK_SV(ctx); translator_io_start(&ctx->base); gen_update_cfar(ctx, ctx->cia); - gen_helper_rfid(cpu_env); + gen_helper_rfid(tcg_env); ctx->base.is_jmp = DISAS_EXIT; #endif } @@ -4507,7 +4507,7 @@ static void gen_rfscv(DisasContext *ctx) CHK_SV(ctx); translator_io_start(&ctx->base); gen_update_cfar(ctx, ctx->cia); - gen_helper_rfscv(cpu_env); + gen_helper_rfscv(tcg_env); ctx->base.is_jmp = DISAS_EXIT; #endif } @@ -4521,7 +4521,7 @@ static void gen_hrfid(DisasContext *ctx) /* Restore CPU state */ CHK_HV(ctx); translator_io_start(&ctx->base); - gen_helper_hrfid(cpu_env); + gen_helper_hrfid(tcg_env); ctx->base.is_jmp = DISAS_EXIT; #endif } @@ -4554,7 +4554,7 @@ static void gen_scv(DisasContext *ctx) /* Set the PC back to the faulting instruction. */ gen_update_nip(ctx, ctx->cia); - gen_helper_scv(cpu_env, tcg_constant_i32(lev)); + gen_helper_scv(tcg_env, tcg_constant_i32(lev)); ctx->base.is_jmp = DISAS_NORETURN; } @@ -4587,7 +4587,7 @@ static void gen_tw(DisasContext *ctx) return; } t0 = tcg_constant_i32(TO(ctx->opcode)); - gen_helper_tw(cpu_env, cpu_gpr[rA(ctx->opcode)], cpu_gpr[rB(ctx->opcode)], + gen_helper_tw(tcg_env, cpu_gpr[rA(ctx->opcode)], cpu_gpr[rB(ctx->opcode)], t0); } @@ -4602,7 +4602,7 @@ static void gen_twi(DisasContext *ctx) } t0 = tcg_constant_tl(SIMM(ctx->opcode)); t1 = tcg_constant_i32(TO(ctx->opcode)); - gen_helper_tw(cpu_env, cpu_gpr[rA(ctx->opcode)], t0, t1); + gen_helper_tw(tcg_env, cpu_gpr[rA(ctx->opcode)], t0, t1); } #if defined(TARGET_PPC64) @@ -4615,7 +4615,7 @@ static void gen_td(DisasContext *ctx) return; } t0 = tcg_constant_i32(TO(ctx->opcode)); - gen_helper_td(cpu_env, cpu_gpr[rA(ctx->opcode)], cpu_gpr[rB(ctx->opcode)], + gen_helper_td(tcg_env, cpu_gpr[rA(ctx->opcode)], cpu_gpr[rB(ctx->opcode)], t0); } @@ -4630,7 +4630,7 @@ static void gen_tdi(DisasContext *ctx) } t0 = tcg_constant_tl(SIMM(ctx->opcode)); t1 = tcg_constant_i32(TO(ctx->opcode)); - gen_helper_td(cpu_env, cpu_gpr[rA(ctx->opcode)], t0, t1); + gen_helper_td(tcg_env, cpu_gpr[rA(ctx->opcode)], t0, t1); } #endif @@ -4856,7 +4856,7 @@ static void gen_mtmsrd(DisasContext *ctx) tcg_gen_andi_tl(t1, cpu_msr, ~mask); tcg_gen_or_tl(t0, t0, t1); - gen_helper_store_msr(cpu_env, t0); + gen_helper_store_msr(tcg_env, t0); /* Must stop the translation as machine state (may have) changed */ ctx->base.is_jmp = DISAS_EXIT_UPDATE; @@ -4895,7 +4895,7 @@ static void gen_mtmsr(DisasContext *ctx) tcg_gen_andi_tl(t1, cpu_msr, ~mask); tcg_gen_or_tl(t0, t0, t1); - gen_helper_store_msr(cpu_env, t0); + gen_helper_store_msr(tcg_env, t0); /* Must stop the translation as machine state (may have) changed */ ctx->base.is_jmp = DISAS_EXIT_UPDATE; @@ -5108,7 +5108,7 @@ static void gen_dcbz(DisasContext *ctx) tcgv_addr = tcg_temp_new(); tcgv_op = tcg_constant_i32(ctx->opcode & 0x03FF000); gen_addr_reg_index(ctx, tcgv_addr); - gen_helper_dcbz(cpu_env, tcgv_addr, tcgv_op); + gen_helper_dcbz(tcg_env, tcgv_addr, tcgv_op); } /* dcbzep */ @@ -5121,7 +5121,7 @@ static void gen_dcbzep(DisasContext *ctx) tcgv_addr = tcg_temp_new(); tcgv_op = tcg_constant_i32(ctx->opcode & 0x03FF000); gen_addr_reg_index(ctx, tcgv_addr); - gen_helper_dcbzep(cpu_env, tcgv_addr, tcgv_op); + gen_helper_dcbzep(tcg_env, tcgv_addr, tcgv_op); } /* dst / dstt */ @@ -5158,7 +5158,7 @@ static void gen_icbi(DisasContext *ctx) gen_set_access_type(ctx, ACCESS_CACHE); t0 = tcg_temp_new(); gen_addr_reg_index(ctx, t0); - gen_helper_icbi(cpu_env, t0); + gen_helper_icbi(tcg_env, t0); } /* icbiep */ @@ -5168,7 +5168,7 @@ static void gen_icbiep(DisasContext *ctx) gen_set_access_type(ctx, ACCESS_CACHE); t0 = tcg_temp_new(); gen_addr_reg_index(ctx, t0); - gen_helper_icbiep(cpu_env, t0); + gen_helper_icbiep(tcg_env, t0); } /* Optional: */ @@ -5195,7 +5195,7 @@ static void gen_mfsr(DisasContext *ctx) CHK_SV(ctx); t0 = tcg_constant_tl(SR(ctx->opcode)); - gen_helper_load_sr(cpu_gpr[rD(ctx->opcode)], cpu_env, t0); + gen_helper_load_sr(cpu_gpr[rD(ctx->opcode)], tcg_env, t0); #endif /* defined(CONFIG_USER_ONLY) */ } @@ -5210,7 +5210,7 @@ static void gen_mfsrin(DisasContext *ctx) CHK_SV(ctx); t0 = tcg_temp_new(); tcg_gen_extract_tl(t0, cpu_gpr[rB(ctx->opcode)], 28, 4); - gen_helper_load_sr(cpu_gpr[rD(ctx->opcode)], cpu_env, t0); + gen_helper_load_sr(cpu_gpr[rD(ctx->opcode)], tcg_env, t0); #endif /* defined(CONFIG_USER_ONLY) */ } @@ -5224,7 +5224,7 @@ static void gen_mtsr(DisasContext *ctx) CHK_SV(ctx); t0 = tcg_constant_tl(SR(ctx->opcode)); - gen_helper_store_sr(cpu_env, t0, cpu_gpr[rS(ctx->opcode)]); + gen_helper_store_sr(tcg_env, t0, cpu_gpr[rS(ctx->opcode)]); #endif /* defined(CONFIG_USER_ONLY) */ } @@ -5239,7 +5239,7 @@ static void gen_mtsrin(DisasContext *ctx) t0 = tcg_temp_new(); tcg_gen_extract_tl(t0, cpu_gpr[rB(ctx->opcode)], 28, 4); - gen_helper_store_sr(cpu_env, t0, cpu_gpr[rD(ctx->opcode)]); + gen_helper_store_sr(tcg_env, t0, cpu_gpr[rD(ctx->opcode)]); #endif /* defined(CONFIG_USER_ONLY) */ } @@ -5256,7 +5256,7 @@ static void gen_mfsr_64b(DisasContext *ctx) CHK_SV(ctx); t0 = tcg_constant_tl(SR(ctx->opcode)); - gen_helper_load_sr(cpu_gpr[rD(ctx->opcode)], cpu_env, t0); + gen_helper_load_sr(cpu_gpr[rD(ctx->opcode)], tcg_env, t0); #endif /* defined(CONFIG_USER_ONLY) */ } @@ -5271,7 +5271,7 @@ static void gen_mfsrin_64b(DisasContext *ctx) CHK_SV(ctx); t0 = tcg_temp_new(); tcg_gen_extract_tl(t0, cpu_gpr[rB(ctx->opcode)], 28, 4); - gen_helper_load_sr(cpu_gpr[rD(ctx->opcode)], cpu_env, t0); + gen_helper_load_sr(cpu_gpr[rD(ctx->opcode)], tcg_env, t0); #endif /* defined(CONFIG_USER_ONLY) */ } @@ -5285,7 +5285,7 @@ static void gen_mtsr_64b(DisasContext *ctx) CHK_SV(ctx); t0 = tcg_constant_tl(SR(ctx->opcode)); - gen_helper_store_sr(cpu_env, t0, cpu_gpr[rS(ctx->opcode)]); + gen_helper_store_sr(tcg_env, t0, cpu_gpr[rS(ctx->opcode)]); #endif /* defined(CONFIG_USER_ONLY) */ } @@ -5300,7 +5300,7 @@ static void gen_mtsrin_64b(DisasContext *ctx) CHK_SV(ctx); t0 = tcg_temp_new(); tcg_gen_extract_tl(t0, cpu_gpr[rB(ctx->opcode)], 28, 4); - gen_helper_store_sr(cpu_env, t0, cpu_gpr[rS(ctx->opcode)]); + gen_helper_store_sr(tcg_env, t0, cpu_gpr[rS(ctx->opcode)]); #endif /* defined(CONFIG_USER_ONLY) */ } @@ -5317,7 +5317,7 @@ static void gen_tlbia(DisasContext *ctx) #else CHK_HV(ctx); - gen_helper_tlbia(cpu_env); + gen_helper_tlbia(tcg_env); #endif /* defined(CONFIG_USER_ONLY) */ } @@ -5377,7 +5377,7 @@ static void gen_tlbld_6xx(DisasContext *ctx) GEN_PRIV(ctx); #else CHK_SV(ctx); - gen_helper_6xx_tlbd(cpu_env, cpu_gpr[rB(ctx->opcode)]); + gen_helper_6xx_tlbd(tcg_env, cpu_gpr[rB(ctx->opcode)]); #endif /* defined(CONFIG_USER_ONLY) */ } @@ -5388,7 +5388,7 @@ static void gen_tlbli_6xx(DisasContext *ctx) GEN_PRIV(ctx); #else CHK_SV(ctx); - gen_helper_6xx_tlbi(cpu_env, cpu_gpr[rB(ctx->opcode)]); + gen_helper_6xx_tlbi(tcg_env, cpu_gpr[rB(ctx->opcode)]); #endif /* defined(CONFIG_USER_ONLY) */ } @@ -5412,7 +5412,7 @@ static void gen_tlbiva(DisasContext *ctx) CHK_SV(ctx); t0 = tcg_temp_new(); gen_addr_reg_index(ctx, t0); - gen_helper_tlbiva(cpu_env, cpu_gpr[rB(ctx->opcode)]); + gen_helper_tlbiva(tcg_env, cpu_gpr[rB(ctx->opcode)]); #endif /* defined(CONFIG_USER_ONLY) */ } @@ -5639,7 +5639,7 @@ static void gen_mfdcr(DisasContext *ctx) CHK_SV(ctx); dcrn = tcg_constant_tl(SPR(ctx->opcode)); - gen_helper_load_dcr(cpu_gpr[rD(ctx->opcode)], cpu_env, dcrn); + gen_helper_load_dcr(cpu_gpr[rD(ctx->opcode)], tcg_env, dcrn); #endif /* defined(CONFIG_USER_ONLY) */ } @@ -5653,7 +5653,7 @@ static void gen_mtdcr(DisasContext *ctx) CHK_SV(ctx); dcrn = tcg_constant_tl(SPR(ctx->opcode)); - gen_helper_store_dcr(cpu_env, dcrn, cpu_gpr[rS(ctx->opcode)]); + gen_helper_store_dcr(tcg_env, dcrn, cpu_gpr[rS(ctx->opcode)]); #endif /* defined(CONFIG_USER_ONLY) */ } @@ -5665,7 +5665,7 @@ static void gen_mfdcrx(DisasContext *ctx) GEN_PRIV(ctx); #else CHK_SV(ctx); - gen_helper_load_dcr(cpu_gpr[rD(ctx->opcode)], cpu_env, + gen_helper_load_dcr(cpu_gpr[rD(ctx->opcode)], tcg_env, cpu_gpr[rA(ctx->opcode)]); /* Note: Rc update flag set leads to undefined state of Rc0 */ #endif /* defined(CONFIG_USER_ONLY) */ @@ -5679,7 +5679,7 @@ static void gen_mtdcrx(DisasContext *ctx) GEN_PRIV(ctx); #else CHK_SV(ctx); - gen_helper_store_dcr(cpu_env, cpu_gpr[rA(ctx->opcode)], + gen_helper_store_dcr(tcg_env, cpu_gpr[rA(ctx->opcode)], cpu_gpr[rS(ctx->opcode)]); /* Note: Rc update flag set leads to undefined state of Rc0 */ #endif /* defined(CONFIG_USER_ONLY) */ @@ -5742,7 +5742,7 @@ static void gen_rfci_40x(DisasContext *ctx) #else CHK_SV(ctx); /* Restore CPU state */ - gen_helper_40x_rfci(cpu_env); + gen_helper_40x_rfci(tcg_env); ctx->base.is_jmp = DISAS_EXIT; #endif /* defined(CONFIG_USER_ONLY) */ } @@ -5754,7 +5754,7 @@ static void gen_rfci(DisasContext *ctx) #else CHK_SV(ctx); /* Restore CPU state */ - gen_helper_rfci(cpu_env); + gen_helper_rfci(tcg_env); ctx->base.is_jmp = DISAS_EXIT; #endif /* defined(CONFIG_USER_ONLY) */ } @@ -5769,7 +5769,7 @@ static void gen_rfdi(DisasContext *ctx) #else CHK_SV(ctx); /* Restore CPU state */ - gen_helper_rfdi(cpu_env); + gen_helper_rfdi(tcg_env); ctx->base.is_jmp = DISAS_EXIT; #endif /* defined(CONFIG_USER_ONLY) */ } @@ -5782,7 +5782,7 @@ static void gen_rfmci(DisasContext *ctx) #else CHK_SV(ctx); /* Restore CPU state */ - gen_helper_rfmci(cpu_env); + gen_helper_rfmci(tcg_env); ctx->base.is_jmp = DISAS_EXIT; #endif /* defined(CONFIG_USER_ONLY) */ } @@ -5798,11 +5798,11 @@ static void gen_tlbre_40x(DisasContext *ctx) CHK_SV(ctx); switch (rB(ctx->opcode)) { case 0: - gen_helper_4xx_tlbre_hi(cpu_gpr[rD(ctx->opcode)], cpu_env, + gen_helper_4xx_tlbre_hi(cpu_gpr[rD(ctx->opcode)], tcg_env, cpu_gpr[rA(ctx->opcode)]); break; case 1: - gen_helper_4xx_tlbre_lo(cpu_gpr[rD(ctx->opcode)], cpu_env, + gen_helper_4xx_tlbre_lo(cpu_gpr[rD(ctx->opcode)], tcg_env, cpu_gpr[rA(ctx->opcode)]); break; default: @@ -5823,7 +5823,7 @@ static void gen_tlbsx_40x(DisasContext *ctx) CHK_SV(ctx); t0 = tcg_temp_new(); gen_addr_reg_index(ctx, t0); - gen_helper_4xx_tlbsx(cpu_gpr[rD(ctx->opcode)], cpu_env, t0); + gen_helper_4xx_tlbsx(cpu_gpr[rD(ctx->opcode)], tcg_env, t0); if (Rc(ctx->opcode)) { TCGLabel *l1 = gen_new_label(); tcg_gen_trunc_tl_i32(cpu_crf[0], cpu_so); @@ -5844,11 +5844,11 @@ static void gen_tlbwe_40x(DisasContext *ctx) switch (rB(ctx->opcode)) { case 0: - gen_helper_4xx_tlbwe_hi(cpu_env, cpu_gpr[rA(ctx->opcode)], + gen_helper_4xx_tlbwe_hi(tcg_env, cpu_gpr[rA(ctx->opcode)], cpu_gpr[rS(ctx->opcode)]); break; case 1: - gen_helper_4xx_tlbwe_lo(cpu_env, cpu_gpr[rA(ctx->opcode)], + gen_helper_4xx_tlbwe_lo(tcg_env, cpu_gpr[rA(ctx->opcode)], cpu_gpr[rS(ctx->opcode)]); break; default: @@ -5874,7 +5874,7 @@ static void gen_tlbre_440(DisasContext *ctx) case 2: { TCGv_i32 t0 = tcg_constant_i32(rB(ctx->opcode)); - gen_helper_440_tlbre(cpu_gpr[rD(ctx->opcode)], cpu_env, + gen_helper_440_tlbre(cpu_gpr[rD(ctx->opcode)], tcg_env, t0, cpu_gpr[rA(ctx->opcode)]); } break; @@ -5896,7 +5896,7 @@ static void gen_tlbsx_440(DisasContext *ctx) CHK_SV(ctx); t0 = tcg_temp_new(); gen_addr_reg_index(ctx, t0); - gen_helper_440_tlbsx(cpu_gpr[rD(ctx->opcode)], cpu_env, t0); + gen_helper_440_tlbsx(cpu_gpr[rD(ctx->opcode)], tcg_env, t0); if (Rc(ctx->opcode)) { TCGLabel *l1 = gen_new_label(); tcg_gen_trunc_tl_i32(cpu_crf[0], cpu_so); @@ -5920,7 +5920,7 @@ static void gen_tlbwe_440(DisasContext *ctx) case 2: { TCGv_i32 t0 = tcg_constant_i32(rB(ctx->opcode)); - gen_helper_440_tlbwe(cpu_env, t0, cpu_gpr[rA(ctx->opcode)], + gen_helper_440_tlbwe(tcg_env, t0, cpu_gpr[rA(ctx->opcode)], cpu_gpr[rS(ctx->opcode)]); } break; @@ -5940,7 +5940,7 @@ static void gen_tlbre_booke206(DisasContext *ctx) GEN_PRIV(ctx); #else CHK_SV(ctx); - gen_helper_booke206_tlbre(cpu_env); + gen_helper_booke206_tlbre(tcg_env); #endif /* defined(CONFIG_USER_ONLY) */ } @@ -5959,7 +5959,7 @@ static void gen_tlbsx_booke206(DisasContext *ctx) } else { t0 = cpu_gpr[rB(ctx->opcode)]; } - gen_helper_booke206_tlbsx(cpu_env, t0); + gen_helper_booke206_tlbsx(tcg_env, t0); #endif /* defined(CONFIG_USER_ONLY) */ } @@ -5970,7 +5970,7 @@ static void gen_tlbwe_booke206(DisasContext *ctx) GEN_PRIV(ctx); #else CHK_SV(ctx); - gen_helper_booke206_tlbwe(cpu_env); + gen_helper_booke206_tlbwe(tcg_env); #endif /* defined(CONFIG_USER_ONLY) */ } @@ -5984,7 +5984,7 @@ static void gen_tlbivax_booke206(DisasContext *ctx) CHK_SV(ctx); t0 = tcg_temp_new(); gen_addr_reg_index(ctx, t0); - gen_helper_booke206_tlbivax(cpu_env, t0); + gen_helper_booke206_tlbivax(tcg_env, t0); #endif /* defined(CONFIG_USER_ONLY) */ } @@ -6001,13 +6001,13 @@ static void gen_tlbilx_booke206(DisasContext *ctx) switch ((ctx->opcode >> 21) & 0x3) { case 0: - gen_helper_booke206_tlbilx0(cpu_env, t0); + gen_helper_booke206_tlbilx0(tcg_env, t0); break; case 1: - gen_helper_booke206_tlbilx1(cpu_env, t0); + gen_helper_booke206_tlbilx1(tcg_env, t0); break; case 3: - gen_helper_booke206_tlbilx3(cpu_env, t0); + gen_helper_booke206_tlbilx3(tcg_env, t0); break; default: gen_inval_exception(ctx, POWERPC_EXCP_INVAL_INVAL); @@ -6062,7 +6062,7 @@ static void gen_wrteei(DisasContext *ctx) static void gen_dlmzb(DisasContext *ctx) { TCGv_i32 t0 = tcg_constant_i32(Rc(ctx->opcode)); - gen_helper_dlmzb(cpu_gpr[rA(ctx->opcode)], cpu_env, + gen_helper_dlmzb(cpu_gpr[rA(ctx->opcode)], tcg_env, cpu_gpr[rS(ctx->opcode)], cpu_gpr[rB(ctx->opcode)], t0); } @@ -6129,7 +6129,7 @@ static void gen_tbegin(DisasContext *ctx) gen_exception_err(ctx, POWERPC_EXCP_FU, FSCR_IC_TM); return; } - gen_helper_tbegin(cpu_env); + gen_helper_tbegin(tcg_env); } #define GEN_TM_NOOP(name) \ @@ -6225,12 +6225,12 @@ GEN_TM_PRIV_NOOP(trechkpt); static inline void get_fpr(TCGv_i64 dst, int regno) { - tcg_gen_ld_i64(dst, cpu_env, fpr_offset(regno)); + tcg_gen_ld_i64(dst, tcg_env, fpr_offset(regno)); } static inline void set_fpr(int regno, TCGv_i64 src) { - tcg_gen_st_i64(src, cpu_env, fpr_offset(regno)); + tcg_gen_st_i64(src, tcg_env, fpr_offset(regno)); /* * Before PowerISA v3.1 the result of doubleword 1 of the VSR * corresponding to the target FPR was undefined. However, @@ -6238,17 +6238,17 @@ static inline void set_fpr(int regno, TCGv_i64 src) * Starting at ISA v3.1, the result for doubleword 1 is now defined * to be 0. */ - tcg_gen_st_i64(tcg_constant_i64(0), cpu_env, vsr64_offset(regno, false)); + tcg_gen_st_i64(tcg_constant_i64(0), tcg_env, vsr64_offset(regno, false)); } static inline void get_avr64(TCGv_i64 dst, int regno, bool high) { - tcg_gen_ld_i64(dst, cpu_env, avr64_offset(regno, high)); + tcg_gen_ld_i64(dst, tcg_env, avr64_offset(regno, high)); } static inline void set_avr64(int regno, TCGv_i64 src, bool high) { - tcg_gen_st_i64(src, cpu_env, avr64_offset(regno, high)); + tcg_gen_st_i64(src, tcg_env, avr64_offset(regno, high)); } /* diff --git a/target/ppc/translate/branch-impl.c.inc b/target/ppc/translate/branch-impl.c.inc index f9931b9d73..fb0fcf30cc 100644 --- a/target/ppc/translate/branch-impl.c.inc +++ b/target/ppc/translate/branch-impl.c.inc @@ -18,7 +18,7 @@ static bool trans_RFEBB(DisasContext *ctx, arg_XL_s *arg) translator_io_start(&ctx->base); gen_update_cfar(ctx, ctx->cia); - gen_helper_rfebb(cpu_env, cpu_gpr[arg->s]); + gen_helper_rfebb(tcg_env, cpu_gpr[arg->s]); ctx->base.is_jmp = DISAS_CHAIN; diff --git a/target/ppc/translate/dfp-impl.c.inc b/target/ppc/translate/dfp-impl.c.inc index 62911e04c7..371076582b 100644 --- a/target/ppc/translate/dfp-impl.c.inc +++ b/target/ppc/translate/dfp-impl.c.inc @@ -3,7 +3,7 @@ static inline TCGv_ptr gen_fprp_ptr(int reg) { TCGv_ptr r = tcg_temp_new_ptr(); - tcg_gen_addi_ptr(r, cpu_env, offsetof(CPUPPCState, vsr[reg].u64[0])); + tcg_gen_addi_ptr(r, tcg_env, offsetof(CPUPPCState, vsr[reg].u64[0])); return r; } @@ -16,7 +16,7 @@ static bool trans_##NAME(DisasContext *ctx, arg_##NAME *a) \ rt = gen_fprp_ptr(a->rt); \ ra = gen_fprp_ptr(a->ra); \ rb = gen_fprp_ptr(a->rb); \ - gen_helper_##NAME(cpu_env, rt, ra, rb); \ + gen_helper_##NAME(tcg_env, rt, ra, rb); \ if (unlikely(a->rc)) { \ gen_set_cr1_from_fpscr(ctx); \ } \ @@ -32,7 +32,7 @@ static bool trans_##NAME(DisasContext *ctx, arg_##NAME *a) \ ra = gen_fprp_ptr(a->ra); \ rb = gen_fprp_ptr(a->rb); \ gen_helper_##NAME(cpu_crf[a->bf], \ - cpu_env, ra, rb); \ + tcg_env, ra, rb); \ return true; \ } @@ -44,7 +44,7 @@ static bool trans_##NAME(DisasContext *ctx, arg_##NAME *a) \ REQUIRE_FPU(ctx); \ rb = gen_fprp_ptr(a->rb); \ gen_helper_##NAME(cpu_crf[a->bf], \ - cpu_env, tcg_constant_i32(a->uim), rb);\ + tcg_env, tcg_constant_i32(a->uim), rb);\ return true; \ } @@ -56,7 +56,7 @@ static bool trans_##NAME(DisasContext *ctx, arg_##NAME *a) \ REQUIRE_FPU(ctx); \ ra = gen_fprp_ptr(a->fra); \ gen_helper_##NAME(cpu_crf[a->bf], \ - cpu_env, ra, tcg_constant_i32(a->dm)); \ + tcg_env, ra, tcg_constant_i32(a->dm)); \ return true; \ } @@ -68,7 +68,7 @@ static bool trans_##NAME(DisasContext *ctx, arg_##NAME *a) \ REQUIRE_FPU(ctx); \ rt = gen_fprp_ptr(a->frt); \ rb = gen_fprp_ptr(a->frb); \ - gen_helper_##NAME(cpu_env, rt, rb, \ + gen_helper_##NAME(tcg_env, rt, rb, \ tcg_constant_i32(a->U32F1), \ tcg_constant_i32(a->U32F2)); \ if (unlikely(a->rc)) { \ @@ -86,7 +86,7 @@ static bool trans_##NAME(DisasContext *ctx, arg_##NAME *a) \ rt = gen_fprp_ptr(a->frt); \ ra = gen_fprp_ptr(a->fra); \ rb = gen_fprp_ptr(a->frb); \ - gen_helper_##NAME(cpu_env, rt, ra, rb, \ + gen_helper_##NAME(tcg_env, rt, ra, rb, \ tcg_constant_i32(a->I32FLD)); \ if (unlikely(a->rc)) { \ gen_set_cr1_from_fpscr(ctx); \ @@ -102,7 +102,7 @@ static bool trans_##NAME(DisasContext *ctx, arg_##NAME *a) \ REQUIRE_FPU(ctx); \ rt = gen_fprp_ptr(a->rt); \ rb = gen_fprp_ptr(a->rb); \ - gen_helper_##NAME(cpu_env, rt, rb); \ + gen_helper_##NAME(tcg_env, rt, rb); \ if (unlikely(a->rc)) { \ gen_set_cr1_from_fpscr(ctx); \ } \ @@ -117,7 +117,7 @@ static bool trans_##NAME(DisasContext *ctx, arg_##NAME *a) \ REQUIRE_FPU(ctx); \ rt = gen_fprp_ptr(a->rt); \ rx = gen_fprp_ptr(a->FPRFLD); \ - gen_helper_##NAME(cpu_env, rt, rx, \ + gen_helper_##NAME(tcg_env, rt, rx, \ tcg_constant_i32(a->I32FLD)); \ if (unlikely(a->rc)) { \ gen_set_cr1_from_fpscr(ctx); \ @@ -188,7 +188,7 @@ static bool trans_DCFFIXQQ(DisasContext *ctx, arg_DCFFIXQQ *a) rt = gen_fprp_ptr(a->frtp); rb = gen_avr_ptr(a->vrb); - gen_helper_DCFFIXQQ(cpu_env, rt, rb); + gen_helper_DCFFIXQQ(tcg_env, rt, rb); return true; } @@ -203,7 +203,7 @@ static bool trans_DCTFIXQQ(DisasContext *ctx, arg_DCTFIXQQ *a) rt = gen_avr_ptr(a->vrt); rb = gen_fprp_ptr(a->frbp); - gen_helper_DCTFIXQQ(cpu_env, rt, rb); + gen_helper_DCTFIXQQ(tcg_env, rt, rb); return true; } diff --git a/target/ppc/translate/fixedpoint-impl.c.inc b/target/ppc/translate/fixedpoint-impl.c.inc index 7ff7e1ec46..51c6fa7330 100644 --- a/target/ppc/translate/fixedpoint-impl.c.inc +++ b/target/ppc/translate/fixedpoint-impl.c.inc @@ -517,7 +517,7 @@ static bool do_hash(DisasContext *ctx, arg_X *a, bool priv, } ea = do_ea_calc(ctx, a->ra, tcg_constant_tl(a->rt)); - helper(cpu_env, ea, cpu_gpr[a->ra], cpu_gpr[a->rb]); + helper(tcg_env, ea, cpu_gpr[a->ra], cpu_gpr[a->rb]); return true; } diff --git a/target/ppc/translate/fp-impl.c.inc b/target/ppc/translate/fp-impl.c.inc index 874774eade..189cd8c979 100644 --- a/target/ppc/translate/fp-impl.c.inc +++ b/target/ppc/translate/fp-impl.c.inc @@ -6,13 +6,13 @@ static inline void gen_reset_fpstatus(void) { - gen_helper_reset_fpstatus(cpu_env); + gen_helper_reset_fpstatus(tcg_env); } static inline void gen_compute_fprf_float64(TCGv_i64 arg) { - gen_helper_compute_fprf_float64(cpu_env, arg); - gen_helper_float_check_status(cpu_env); + gen_helper_compute_fprf_float64(tcg_env, arg); + gen_helper_float_check_status(tcg_env); } #if defined(TARGET_PPC64) @@ -49,7 +49,7 @@ static void gen_f##name(DisasContext *ctx) \ get_fpr(t0, rA(ctx->opcode)); \ get_fpr(t1, rC(ctx->opcode)); \ get_fpr(t2, rB(ctx->opcode)); \ - gen_helper_f##name(t3, cpu_env, t0, t1, t2); \ + gen_helper_f##name(t3, tcg_env, t0, t1, t2); \ set_fpr(rD(ctx->opcode), t3); \ if (set_fprf) { \ gen_compute_fprf_float64(t3); \ @@ -79,7 +79,7 @@ static void gen_f##name(DisasContext *ctx) \ gen_reset_fpstatus(); \ get_fpr(t0, rA(ctx->opcode)); \ get_fpr(t1, rB(ctx->opcode)); \ - gen_helper_f##name(t2, cpu_env, t0, t1); \ + gen_helper_f##name(t2, tcg_env, t0, t1); \ set_fpr(rD(ctx->opcode), t2); \ if (set_fprf) { \ gen_compute_fprf_float64(t2); \ @@ -108,7 +108,7 @@ static void gen_f##name(DisasContext *ctx) \ gen_reset_fpstatus(); \ get_fpr(t0, rA(ctx->opcode)); \ get_fpr(t1, rC(ctx->opcode)); \ - gen_helper_f##name(t2, cpu_env, t0, t1); \ + gen_helper_f##name(t2, tcg_env, t0, t1); \ set_fpr(rD(ctx->opcode), t2); \ if (set_fprf) { \ gen_compute_fprf_float64(t2); \ @@ -134,12 +134,12 @@ static void gen_f##name(DisasContext *ctx) \ t1 = tcg_temp_new_i64(); \ gen_reset_fpstatus(); \ get_fpr(t0, rB(ctx->opcode)); \ - gen_helper_f##name(t1, cpu_env, t0); \ + gen_helper_f##name(t1, tcg_env, t0); \ set_fpr(rD(ctx->opcode), t1); \ if (set_fprf) { \ - gen_helper_compute_fprf_float64(cpu_env, t1); \ + gen_helper_compute_fprf_float64(tcg_env, t1); \ } \ - gen_helper_float_check_status(cpu_env); \ + gen_helper_float_check_status(tcg_env); \ if (unlikely(Rc(ctx->opcode) != 0)) { \ gen_set_cr1_from_fpscr(ctx); \ } \ @@ -158,7 +158,7 @@ static void gen_f##name(DisasContext *ctx) \ t1 = tcg_temp_new_i64(); \ gen_reset_fpstatus(); \ get_fpr(t0, rB(ctx->opcode)); \ - gen_helper_f##name(t1, cpu_env, t0); \ + gen_helper_f##name(t1, tcg_env, t0); \ set_fpr(rD(ctx->opcode), t1); \ if (set_fprf) { \ gen_compute_fprf_float64(t1); \ @@ -197,7 +197,7 @@ static void gen_frsqrtes(DisasContext *ctx) t1 = tcg_temp_new_i64(); gen_reset_fpstatus(); get_fpr(t0, rB(ctx->opcode)); - gen_helper_frsqrtes(t1, cpu_env, t0); + gen_helper_frsqrtes(t1, tcg_env, t0); set_fpr(rD(ctx->opcode), t1); gen_compute_fprf_float64(t1); if (unlikely(Rc(ctx->opcode) != 0)) { @@ -245,7 +245,7 @@ static bool do_helper_fsqrt(DisasContext *ctx, arg_A_tb *a, gen_reset_fpstatus(); get_fpr(t0, a->frb); - helper(t1, cpu_env, t0); + helper(t1, tcg_env, t0); set_fpr(a->frt, t1); gen_compute_fprf_float64(t1); if (unlikely(a->rc != 0)) { @@ -351,8 +351,8 @@ static void gen_fcmpo(DisasContext *ctx) crf = tcg_constant_i32(crfD(ctx->opcode)); get_fpr(t0, rA(ctx->opcode)); get_fpr(t1, rB(ctx->opcode)); - gen_helper_fcmpo(cpu_env, t0, t1, crf); - gen_helper_float_check_status(cpu_env); + gen_helper_fcmpo(tcg_env, t0, t1, crf); + gen_helper_float_check_status(tcg_env); } /* fcmpu */ @@ -371,8 +371,8 @@ static void gen_fcmpu(DisasContext *ctx) crf = tcg_constant_i32(crfD(ctx->opcode)); get_fpr(t0, rA(ctx->opcode)); get_fpr(t1, rB(ctx->opcode)); - gen_helper_fcmpu(cpu_env, t0, t1, crf); - gen_helper_float_check_status(cpu_env); + gen_helper_fcmpu(tcg_env, t0, t1, crf); + gen_helper_float_check_status(tcg_env); } /*** Floating-point move ***/ @@ -542,7 +542,7 @@ static void gen_mcrfs(DisasContext *ctx) ~((0xF << shift) & FP_EX_CLEAR_BITS)); /* FEX and VX need to be updated, so don't set fpscr directly */ tmask = tcg_constant_i32(1 << nibble); - gen_helper_store_fpscr(cpu_env, tnew_fpscr, tmask); + gen_helper_store_fpscr(tcg_env, tnew_fpscr, tmask); } static TCGv_i64 place_from_fpscr(int rt, uint64_t mask) @@ -565,7 +565,7 @@ static void store_fpscr_masked(TCGv_i64 fpscr, uint64_t clear_mask, tcg_gen_andi_i64(fpscr_masked, fpscr, ~clear_mask); tcg_gen_or_i64(fpscr_masked, fpscr_masked, set_mask); - gen_helper_store_fpscr(cpu_env, fpscr_masked, st_mask); + gen_helper_store_fpscr(tcg_env, fpscr_masked, st_mask); } static bool trans_MFFS_ISA207(DisasContext *ctx, arg_X_t_rc *a) @@ -691,7 +691,7 @@ static void gen_mtfsb0(DisasContext *ctx) crb = 31 - crbD(ctx->opcode); gen_reset_fpstatus(); if (likely(crb != FPSCR_FEX && crb != FPSCR_VX)) { - gen_helper_fpscr_clrbit(cpu_env, tcg_constant_i32(crb)); + gen_helper_fpscr_clrbit(tcg_env, tcg_constant_i32(crb)); } if (unlikely(Rc(ctx->opcode) != 0)) { tcg_gen_trunc_tl_i32(cpu_crf[1], cpu_fpscr); @@ -711,14 +711,14 @@ static void gen_mtfsb1(DisasContext *ctx) crb = 31 - crbD(ctx->opcode); /* XXX: we pretend we can only do IEEE floating-point computations */ if (likely(crb != FPSCR_FEX && crb != FPSCR_VX && crb != FPSCR_NI)) { - gen_helper_fpscr_setbit(cpu_env, tcg_constant_i32(crb)); + gen_helper_fpscr_setbit(tcg_env, tcg_constant_i32(crb)); } if (unlikely(Rc(ctx->opcode) != 0)) { tcg_gen_trunc_tl_i32(cpu_crf[1], cpu_fpscr); tcg_gen_shri_i32(cpu_crf[1], cpu_crf[1], FPSCR_OX); } /* We can raise a deferred exception */ - gen_helper_fpscr_check_status(cpu_env); + gen_helper_fpscr_check_status(tcg_env); } /* mtfsf */ @@ -748,13 +748,13 @@ static void gen_mtfsf(DisasContext *ctx) } t1 = tcg_temp_new_i64(); get_fpr(t1, rB(ctx->opcode)); - gen_helper_store_fpscr(cpu_env, t1, t0); + gen_helper_store_fpscr(tcg_env, t1, t0); if (unlikely(Rc(ctx->opcode) != 0)) { tcg_gen_trunc_tl_i32(cpu_crf[1], cpu_fpscr); tcg_gen_shri_i32(cpu_crf[1], cpu_crf[1], FPSCR_OX); } /* We can raise a deferred exception */ - gen_helper_fpscr_check_status(cpu_env); + gen_helper_fpscr_check_status(tcg_env); } /* mtfsfi */ @@ -777,13 +777,13 @@ static void gen_mtfsfi(DisasContext *ctx) sh = (8 * w) + 7 - bf; t0 = tcg_constant_i64(((uint64_t)FPIMM(ctx->opcode)) << (4 * sh)); t1 = tcg_constant_i32(1 << sh); - gen_helper_store_fpscr(cpu_env, t0, t1); + gen_helper_store_fpscr(tcg_env, t0, t1); if (unlikely(Rc(ctx->opcode) != 0)) { tcg_gen_trunc_tl_i32(cpu_crf[1], cpu_fpscr); tcg_gen_shri_i32(cpu_crf[1], cpu_crf[1], FPSCR_OX); } /* We can raise a deferred exception */ - gen_helper_fpscr_check_status(cpu_env); + gen_helper_fpscr_check_status(tcg_env); } static void gen_qemu_ld32fs(DisasContext *ctx, TCGv_i64 dest, TCGv addr) diff --git a/target/ppc/translate/processor-ctrl-impl.c.inc b/target/ppc/translate/processor-ctrl-impl.c.inc index cc7a50d579..0142801985 100644 --- a/target/ppc/translate/processor-ctrl-impl.c.inc +++ b/target/ppc/translate/processor-ctrl-impl.c.inc @@ -35,9 +35,9 @@ static bool trans_MSGCLR(DisasContext *ctx, arg_X_rb *a) #if !defined(CONFIG_USER_ONLY) if (is_book3s_arch2x(ctx)) { - gen_helper_book3s_msgclr(cpu_env, cpu_gpr[a->rb]); + gen_helper_book3s_msgclr(tcg_env, cpu_gpr[a->rb]); } else { - gen_helper_msgclr(cpu_env, cpu_gpr[a->rb]); + gen_helper_msgclr(tcg_env, cpu_gpr[a->rb]); } #else qemu_build_not_reached(); @@ -75,7 +75,7 @@ static bool trans_MSGCLRP(DisasContext *ctx, arg_X_rb *a) REQUIRE_INSNS_FLAGS2(ctx, ISA207S); REQUIRE_SV(ctx); #if !defined(CONFIG_USER_ONLY) && defined(TARGET_PPC64) - gen_helper_book3s_msgclrp(cpu_env, cpu_gpr[a->rb]); + gen_helper_book3s_msgclrp(tcg_env, cpu_gpr[a->rb]); #else qemu_build_not_reached(); #endif @@ -88,7 +88,7 @@ static bool trans_MSGSNDP(DisasContext *ctx, arg_X_rb *a) REQUIRE_INSNS_FLAGS2(ctx, ISA207S); REQUIRE_SV(ctx); #if !defined(CONFIG_USER_ONLY) && defined(TARGET_PPC64) - gen_helper_book3s_msgsndp(cpu_env, cpu_gpr[a->rb]); + gen_helper_book3s_msgsndp(tcg_env, cpu_gpr[a->rb]); #else qemu_build_not_reached(); #endif diff --git a/target/ppc/translate/spe-impl.c.inc b/target/ppc/translate/spe-impl.c.inc index f4a858487d..454dac823e 100644 --- a/target/ppc/translate/spe-impl.c.inc +++ b/target/ppc/translate/spe-impl.c.inc @@ -22,7 +22,7 @@ static inline void gen_evmra(DisasContext *ctx) cpu_gprh[rA(ctx->opcode)]); /* spe_acc := tmp */ - tcg_gen_st_i64(tmp, cpu_env, offsetof(CPUPPCState, spe_acc)); + tcg_gen_st_i64(tmp, tcg_env, offsetof(CPUPPCState, spe_acc)); /* rD := rA */ tcg_gen_mov_tl(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)]); @@ -457,7 +457,7 @@ static inline void gen_evmwumia(DisasContext *ctx) /* acc := rD */ gen_load_gpr64(tmp, rD(ctx->opcode)); - tcg_gen_st_i64(tmp, cpu_env, offsetof(CPUPPCState, spe_acc)); + tcg_gen_st_i64(tmp, tcg_env, offsetof(CPUPPCState, spe_acc)); } static inline void gen_evmwumiaa(DisasContext *ctx) @@ -479,13 +479,13 @@ static inline void gen_evmwumiaa(DisasContext *ctx) gen_load_gpr64(tmp, rD(ctx->opcode)); /* Load acc */ - tcg_gen_ld_i64(acc, cpu_env, offsetof(CPUPPCState, spe_acc)); + tcg_gen_ld_i64(acc, tcg_env, offsetof(CPUPPCState, spe_acc)); /* acc := tmp + acc */ tcg_gen_add_i64(acc, acc, tmp); /* Store acc */ - tcg_gen_st_i64(acc, cpu_env, offsetof(CPUPPCState, spe_acc)); + tcg_gen_st_i64(acc, tcg_env, offsetof(CPUPPCState, spe_acc)); /* rD := acc */ gen_store_gpr64(rD(ctx->opcode), acc); @@ -529,7 +529,7 @@ static inline void gen_evmwsmia(DisasContext *ctx) /* acc := rD */ gen_load_gpr64(tmp, rD(ctx->opcode)); - tcg_gen_st_i64(tmp, cpu_env, offsetof(CPUPPCState, spe_acc)); + tcg_gen_st_i64(tmp, tcg_env, offsetof(CPUPPCState, spe_acc)); } static inline void gen_evmwsmiaa(DisasContext *ctx) @@ -551,13 +551,13 @@ static inline void gen_evmwsmiaa(DisasContext *ctx) gen_load_gpr64(tmp, rD(ctx->opcode)); /* Load acc */ - tcg_gen_ld_i64(acc, cpu_env, offsetof(CPUPPCState, spe_acc)); + tcg_gen_ld_i64(acc, tcg_env, offsetof(CPUPPCState, spe_acc)); /* acc := tmp + acc */ tcg_gen_add_i64(acc, acc, tmp); /* Store acc */ - tcg_gen_st_i64(acc, cpu_env, offsetof(CPUPPCState, spe_acc)); + tcg_gen_st_i64(acc, tcg_env, offsetof(CPUPPCState, spe_acc)); /* rD := acc */ gen_store_gpr64(rD(ctx->opcode), acc); @@ -878,7 +878,7 @@ static inline void gen_##name(DisasContext *ctx) \ { \ TCGv_i32 t0 = tcg_temp_new_i32(); \ tcg_gen_trunc_tl_i32(t0, cpu_gpr[rB(ctx->opcode)]); \ - gen_helper_##name(t0, cpu_env, t0); \ + gen_helper_##name(t0, tcg_env, t0); \ tcg_gen_extu_i32_tl(cpu_gpr[rD(ctx->opcode)], t0); \ } #define GEN_SPEFPUOP_CONV_32_64(name) \ @@ -893,7 +893,7 @@ static inline void gen_##name(DisasContext *ctx) \ t0 = tcg_temp_new_i64(); \ t1 = tcg_temp_new_i32(); \ gen_load_gpr64(t0, rB(ctx->opcode)); \ - gen_helper_##name(t1, cpu_env, t0); \ + gen_helper_##name(t1, tcg_env, t0); \ tcg_gen_extu_i32_tl(cpu_gpr[rD(ctx->opcode)], t1); \ } #define GEN_SPEFPUOP_CONV_64_32(name) \ @@ -908,7 +908,7 @@ static inline void gen_##name(DisasContext *ctx) \ t0 = tcg_temp_new_i64(); \ t1 = tcg_temp_new_i32(); \ tcg_gen_trunc_tl_i32(t1, cpu_gpr[rB(ctx->opcode)]); \ - gen_helper_##name(t0, cpu_env, t1); \ + gen_helper_##name(t0, tcg_env, t1); \ gen_store_gpr64(rD(ctx->opcode), t0); \ } #define GEN_SPEFPUOP_CONV_64_64(name) \ @@ -921,7 +921,7 @@ static inline void gen_##name(DisasContext *ctx) \ } \ t0 = tcg_temp_new_i64(); \ gen_load_gpr64(t0, rB(ctx->opcode)); \ - gen_helper_##name(t0, cpu_env, t0); \ + gen_helper_##name(t0, tcg_env, t0); \ gen_store_gpr64(rD(ctx->opcode), t0); \ } #define GEN_SPEFPUOP_ARITH2_32_32(name) \ @@ -931,7 +931,7 @@ static inline void gen_##name(DisasContext *ctx) \ TCGv_i32 t1 = tcg_temp_new_i32(); \ tcg_gen_trunc_tl_i32(t0, cpu_gpr[rA(ctx->opcode)]); \ tcg_gen_trunc_tl_i32(t1, cpu_gpr[rB(ctx->opcode)]); \ - gen_helper_##name(t0, cpu_env, t0, t1); \ + gen_helper_##name(t0, tcg_env, t0, t1); \ tcg_gen_extu_i32_tl(cpu_gpr[rD(ctx->opcode)], t0); \ } #define GEN_SPEFPUOP_ARITH2_64_64(name) \ @@ -946,7 +946,7 @@ static inline void gen_##name(DisasContext *ctx) \ t1 = tcg_temp_new_i64(); \ gen_load_gpr64(t0, rA(ctx->opcode)); \ gen_load_gpr64(t1, rB(ctx->opcode)); \ - gen_helper_##name(t0, cpu_env, t0, t1); \ + gen_helper_##name(t0, tcg_env, t0, t1); \ gen_store_gpr64(rD(ctx->opcode), t0); \ } #define GEN_SPEFPUOP_COMP_32(name) \ @@ -957,7 +957,7 @@ static inline void gen_##name(DisasContext *ctx) \ \ tcg_gen_trunc_tl_i32(t0, cpu_gpr[rA(ctx->opcode)]); \ tcg_gen_trunc_tl_i32(t1, cpu_gpr[rB(ctx->opcode)]); \ - gen_helper_##name(cpu_crf[crfD(ctx->opcode)], cpu_env, t0, t1); \ + gen_helper_##name(cpu_crf[crfD(ctx->opcode)], tcg_env, t0, t1); \ } #define GEN_SPEFPUOP_COMP_64(name) \ static inline void gen_##name(DisasContext *ctx) \ @@ -971,7 +971,7 @@ static inline void gen_##name(DisasContext *ctx) \ t1 = tcg_temp_new_i64(); \ gen_load_gpr64(t0, rA(ctx->opcode)); \ gen_load_gpr64(t1, rB(ctx->opcode)); \ - gen_helper_##name(cpu_crf[crfD(ctx->opcode)], cpu_env, t0, t1); \ + gen_helper_##name(cpu_crf[crfD(ctx->opcode)], tcg_env, t0, t1); \ } /* Single precision floating-point vectors operations */ diff --git a/target/ppc/translate/storage-ctrl-impl.c.inc b/target/ppc/translate/storage-ctrl-impl.c.inc index faa7b04bbc..74c23a4191 100644 --- a/target/ppc/translate/storage-ctrl-impl.c.inc +++ b/target/ppc/translate/storage-ctrl-impl.c.inc @@ -30,7 +30,7 @@ static bool trans_SLBIE(DisasContext *ctx, arg_SLBIE *a) REQUIRE_SV(ctx); #if !defined(CONFIG_USER_ONLY) && defined(TARGET_PPC64) - gen_helper_SLBIE(cpu_env, cpu_gpr[a->rb]); + gen_helper_SLBIE(tcg_env, cpu_gpr[a->rb]); #else qemu_build_not_reached(); #endif @@ -44,7 +44,7 @@ static bool trans_SLBIEG(DisasContext *ctx, arg_SLBIEG *a) REQUIRE_SV(ctx); #if !defined(CONFIG_USER_ONLY) && defined(TARGET_PPC64) - gen_helper_SLBIEG(cpu_env, cpu_gpr[a->rb]); + gen_helper_SLBIEG(tcg_env, cpu_gpr[a->rb]); #else qemu_build_not_reached(); #endif @@ -58,7 +58,7 @@ static bool trans_SLBIA(DisasContext *ctx, arg_SLBIA *a) REQUIRE_SV(ctx); #if !defined(CONFIG_USER_ONLY) && defined(TARGET_PPC64) - gen_helper_SLBIA(cpu_env, tcg_constant_i32(a->ih)); + gen_helper_SLBIA(tcg_env, tcg_constant_i32(a->ih)); #else qemu_build_not_reached(); #endif @@ -72,7 +72,7 @@ static bool trans_SLBIAG(DisasContext *ctx, arg_SLBIAG *a) REQUIRE_SV(ctx); #if !defined(CONFIG_USER_ONLY) && defined(TARGET_PPC64) - gen_helper_SLBIAG(cpu_env, cpu_gpr[a->rs], tcg_constant_i32(a->l)); + gen_helper_SLBIAG(tcg_env, cpu_gpr[a->rs], tcg_constant_i32(a->l)); #else qemu_build_not_reached(); #endif @@ -86,7 +86,7 @@ static bool trans_SLBMTE(DisasContext *ctx, arg_SLBMTE *a) REQUIRE_SV(ctx); #if !defined(CONFIG_USER_ONLY) && defined(TARGET_PPC64) - gen_helper_SLBMTE(cpu_env, cpu_gpr[a->rb], cpu_gpr[a->rt]); + gen_helper_SLBMTE(tcg_env, cpu_gpr[a->rb], cpu_gpr[a->rt]); #else qemu_build_not_reached(); #endif @@ -100,7 +100,7 @@ static bool trans_SLBMFEV(DisasContext *ctx, arg_SLBMFEV *a) REQUIRE_SV(ctx); #if !defined(CONFIG_USER_ONLY) && defined(TARGET_PPC64) - gen_helper_SLBMFEV(cpu_gpr[a->rt], cpu_env, cpu_gpr[a->rb]); + gen_helper_SLBMFEV(cpu_gpr[a->rt], tcg_env, cpu_gpr[a->rb]); #else qemu_build_not_reached(); #endif @@ -114,7 +114,7 @@ static bool trans_SLBMFEE(DisasContext *ctx, arg_SLBMFEE *a) REQUIRE_SV(ctx); #if !defined(CONFIG_USER_ONLY) && defined(TARGET_PPC64) - gen_helper_SLBMFEE(cpu_gpr[a->rt], cpu_env, cpu_gpr[a->rb]); + gen_helper_SLBMFEE(cpu_gpr[a->rt], tcg_env, cpu_gpr[a->rb]); #else qemu_build_not_reached(); #endif @@ -137,7 +137,7 @@ static bool trans_SLBFEE(DisasContext *ctx, arg_SLBFEE *a) gen_inval_exception(ctx, POWERPC_EXCP_PRIV_REG); return true; } - gen_helper_SLBFEE(cpu_gpr[a->rt], cpu_env, + gen_helper_SLBFEE(cpu_gpr[a->rt], tcg_env, cpu_gpr[a->rb]); l1 = gen_new_label(); l2 = gen_new_label(); @@ -211,7 +211,7 @@ static bool do_tlbie(DisasContext *ctx, arg_X_tlbie *a, bool local) if (!local && NARROW_MODE(ctx)) { TCGv t0 = tcg_temp_new(); tcg_gen_ext32u_tl(t0, cpu_gpr[rb]); - gen_helper_tlbie(cpu_env, t0); + gen_helper_tlbie(tcg_env, t0); #if defined(TARGET_PPC64) /* @@ -219,7 +219,7 @@ static bool do_tlbie(DisasContext *ctx, arg_X_tlbie *a, bool local) * otherwise the results are undefined. */ } else if (a->r) { - gen_helper_tlbie_isa300(cpu_env, cpu_gpr[rb], cpu_gpr[a->rs], + gen_helper_tlbie_isa300(tcg_env, cpu_gpr[rb], cpu_gpr[a->rs], tcg_constant_i32(a->ric << TLBIE_F_RIC_SHIFT | a->prs << TLBIE_F_PRS_SHIFT | a->r << TLBIE_F_R_SHIFT | @@ -228,7 +228,7 @@ static bool do_tlbie(DisasContext *ctx, arg_X_tlbie *a, bool local) #endif } else { - gen_helper_tlbie(cpu_env, cpu_gpr[rb]); + gen_helper_tlbie(tcg_env, cpu_gpr[rb]); } if (local) { @@ -236,9 +236,9 @@ static bool do_tlbie(DisasContext *ctx, arg_X_tlbie *a, bool local) } t1 = tcg_temp_new_i32(); - tcg_gen_ld_i32(t1, cpu_env, offsetof(CPUPPCState, tlb_need_flush)); + tcg_gen_ld_i32(t1, tcg_env, offsetof(CPUPPCState, tlb_need_flush)); tcg_gen_ori_i32(t1, t1, TLB_NEED_GLOBAL_FLUSH); - tcg_gen_st_i32(t1, cpu_env, offsetof(CPUPPCState, tlb_need_flush)); + tcg_gen_st_i32(t1, tcg_env, offsetof(CPUPPCState, tlb_need_flush)); return true; #endif diff --git a/target/ppc/translate/vmx-impl.c.inc b/target/ppc/translate/vmx-impl.c.inc index 5cdf53a9df..4b91c3489d 100644 --- a/target/ppc/translate/vmx-impl.c.inc +++ b/target/ppc/translate/vmx-impl.c.inc @@ -10,7 +10,7 @@ static inline TCGv_ptr gen_avr_ptr(int reg) { TCGv_ptr r = tcg_temp_new_ptr(); - tcg_gen_addi_ptr(r, cpu_env, avr_full_offset(reg)); + tcg_gen_addi_ptr(r, tcg_env, avr_full_offset(reg)); return r; } @@ -96,7 +96,7 @@ static void gen_lve##name(DisasContext *ctx) \ tcg_gen_andi_tl(EA, EA, ~(size - 1)); \ } \ rs = gen_avr_ptr(rS(ctx->opcode)); \ - gen_helper_lve##name(cpu_env, rs, EA); \ + gen_helper_lve##name(tcg_env, rs, EA); \ } #define GEN_VR_STVE(name, opc2, opc3, size) \ @@ -115,7 +115,7 @@ static void gen_stve##name(DisasContext *ctx) \ tcg_gen_andi_tl(EA, EA, ~(size - 1)); \ } \ rs = gen_avr_ptr(rS(ctx->opcode)); \ - gen_helper_stve##name(cpu_env, rs, EA); \ + gen_helper_stve##name(tcg_env, rs, EA); \ } GEN_VR_LDX(lvx, 0x07, 0x03); @@ -146,7 +146,7 @@ static void gen_mfvscr(DisasContext *ctx) tcg_gen_movi_i64(avr, 0); set_avr64(rD(ctx->opcode), avr, true); t = tcg_temp_new_i32(); - gen_helper_mfvscr(t, cpu_env); + gen_helper_mfvscr(t, tcg_env); tcg_gen_extu_i32_i64(avr, t); set_avr64(rD(ctx->opcode), avr, false); } @@ -167,8 +167,8 @@ static void gen_mtvscr(DisasContext *ctx) bofs += 3 * 4; #endif - tcg_gen_ld_i32(val, cpu_env, bofs); - gen_helper_mtvscr(cpu_env, val); + tcg_gen_ld_i32(val, tcg_env, bofs); + gen_helper_mtvscr(tcg_env, val); } static void gen_vx_vmul10(DisasContext *ctx, bool add_cin, bool ret_carry) @@ -287,7 +287,7 @@ static void glue(gen_, name)(DisasContext *ctx) \ ra = gen_avr_ptr(rA(ctx->opcode)); \ rb = gen_avr_ptr(rB(ctx->opcode)); \ rd = gen_avr_ptr(rD(ctx->opcode)); \ - gen_helper_##name(cpu_env, rd, ra, rb); \ + gen_helper_##name(tcg_env, rd, ra, rb); \ } #define GEN_VXFORM3(name, opc2, opc3) \ @@ -689,10 +689,10 @@ static void trans_vclzw(DisasContext *ctx) /* Perform count for every word element using tcg_gen_clzi_i32. */ for (i = 0; i < 4; i++) { - tcg_gen_ld_i32(tmp, cpu_env, + tcg_gen_ld_i32(tmp, tcg_env, offsetof(CPUPPCState, vsr[32 + VB].u64[0]) + i * 4); tcg_gen_clzi_i32(tmp, tmp, 32); - tcg_gen_st_i32(tmp, cpu_env, + tcg_gen_st_i32(tmp, tcg_env, offsetof(CPUPPCState, vsr[32 + VT].u64[0]) + i * 4); } } @@ -1174,7 +1174,7 @@ static void glue(gen_, name)(DisasContext *ctx) \ ra = gen_avr_ptr(rA(ctx->opcode)); \ rb = gen_avr_ptr(rB(ctx->opcode)); \ rd = gen_avr_ptr(rD(ctx->opcode)); \ - gen_helper_##opname(cpu_env, rd, ra, rb); \ + gen_helper_##opname(tcg_env, rd, ra, rb); \ } #define GEN_VXRFORM(name, opc2, opc3) \ @@ -1478,7 +1478,7 @@ static void glue(gen_, name)(DisasContext *ctx) \ } \ rb = gen_avr_ptr(rB(ctx->opcode)); \ rd = gen_avr_ptr(rD(ctx->opcode)); \ - gen_helper_##name(cpu_env, rd, rb); \ + gen_helper_##name(tcg_env, rd, rb); \ } #define GEN_VXFORM_NOA_2(name, opc2, opc3, opc4) \ @@ -1625,7 +1625,7 @@ static void glue(gen_, name)(DisasContext *ctx) \ uimm = tcg_constant_i32(UIMM5(ctx->opcode)); \ rb = gen_avr_ptr(rB(ctx->opcode)); \ rd = gen_avr_ptr(rD(ctx->opcode)); \ - gen_helper_##name(cpu_env, rd, rb, uimm); \ + gen_helper_##name(tcg_env, rd, rb, uimm); \ } #define GEN_VXFORM_UIMM_SPLAT(name, opc2, opc3, splat_max) \ @@ -1813,7 +1813,7 @@ static bool do_vextdx(DisasContext *ctx, arg_VA *a, int size, bool right, if (right) { tcg_gen_subfi_tl(rc, 32 - size, rc); } - gen_helper(cpu_env, vrt, vra, vrb, rc); + gen_helper(tcg_env, vrt, vra, vrb, rc); return true; } @@ -1841,7 +1841,7 @@ static bool do_vinsx(DisasContext *ctx, int vrt, int size, bool right, TCGv ra, tcg_gen_subfi_tl(idx, 16 - size, idx); } - gen_helper(cpu_env, t, rb, idx); + gen_helper(tcg_env, t, rb, idx); return true; } @@ -2349,9 +2349,9 @@ static void glue(gen_, name0##_##name1)(DisasContext *ctx) \ rc = gen_avr_ptr(rC(ctx->opcode)); \ rd = gen_avr_ptr(rD(ctx->opcode)); \ if (Rc(ctx->opcode)) { \ - gen_helper_##name1(cpu_env, rd, ra, rb, rc); \ + gen_helper_##name1(tcg_env, rd, ra, rb, rc); \ } else { \ - gen_helper_##name0(cpu_env, rd, ra, rb, rc); \ + gen_helper_##name0(tcg_env, rd, ra, rb, rc); \ } \ } @@ -2437,7 +2437,7 @@ static bool do_va_env_helper(DisasContext *ctx, arg_VA *a, vra = gen_avr_ptr(a->vra); vrb = gen_avr_ptr(a->vrb); vrc = gen_avr_ptr(a->rc); - gen_helper(cpu_env, vrt, vra, vrb, vrc); + gen_helper(tcg_env, vrt, vra, vrb, vrc); return true; } diff --git a/target/ppc/translate/vsx-impl.c.inc b/target/ppc/translate/vsx-impl.c.inc index 0f5b0056f1..6db87ab336 100644 --- a/target/ppc/translate/vsx-impl.c.inc +++ b/target/ppc/translate/vsx-impl.c.inc @@ -2,25 +2,25 @@ static inline void get_cpu_vsr(TCGv_i64 dst, int n, bool high) { - tcg_gen_ld_i64(dst, cpu_env, vsr64_offset(n, high)); + tcg_gen_ld_i64(dst, tcg_env, vsr64_offset(n, high)); } static inline void set_cpu_vsr(int n, TCGv_i64 src, bool high) { - tcg_gen_st_i64(src, cpu_env, vsr64_offset(n, high)); + tcg_gen_st_i64(src, tcg_env, vsr64_offset(n, high)); } static inline TCGv_ptr gen_vsr_ptr(int reg) { TCGv_ptr r = tcg_temp_new_ptr(); - tcg_gen_addi_ptr(r, cpu_env, vsr_full_offset(reg)); + tcg_gen_addi_ptr(r, tcg_env, vsr_full_offset(reg)); return r; } static inline TCGv_ptr gen_acc_ptr(int reg) { TCGv_ptr r = tcg_temp_new_ptr(); - tcg_gen_addi_ptr(r, cpu_env, acc_full_offset(reg)); + tcg_gen_addi_ptr(r, tcg_env, acc_full_offset(reg)); return r; } @@ -257,7 +257,7 @@ static void gen_##name(DisasContext *ctx) \ xt = gen_vsr_ptr(xT(ctx->opcode)); \ gen_set_access_type(ctx, ACCESS_INT); \ gen_addr_register(ctx, EA); \ - gen_helper_##name(cpu_env, EA, xt, cpu_gpr[rB(ctx->opcode)]); \ + gen_helper_##name(tcg_env, EA, xt, cpu_gpr[rB(ctx->opcode)]); \ } VSX_VECTOR_LOAD_STORE_LENGTH(lxvl) @@ -801,10 +801,10 @@ static void gen_##name(DisasContext *ctx) \ xa = gen_vsr_ptr(xA(ctx->opcode)); \ xb = gen_vsr_ptr(xB(ctx->opcode)); \ if ((ctx->opcode >> (31 - 21)) & 1) { \ - gen_helper_##name(cpu_crf[6], cpu_env, xt, xa, xb); \ + gen_helper_##name(cpu_crf[6], tcg_env, xt, xa, xb); \ } else { \ ignored = tcg_temp_new_i32(); \ - gen_helper_##name(ignored, cpu_env, xt, xa, xb); \ + gen_helper_##name(ignored, tcg_env, xt, xa, xb); \ } \ } @@ -829,7 +829,7 @@ static bool trans_XSCVQPDP(DisasContext *ctx, arg_X_tb_rc *a) xt = gen_avr_ptr(a->rt); xb = gen_avr_ptr(a->rb); - gen_helper_XSCVQPDP(cpu_env, ro, xt, xb); + gen_helper_XSCVQPDP(tcg_env, ro, xt, xb); return true; } @@ -843,7 +843,7 @@ static bool do_helper_env_X_tb(DisasContext *ctx, arg_X_tb *a, xt = gen_avr_ptr(a->rt); xb = gen_avr_ptr(a->rb); - gen_helper(cpu_env, xt, xb); + gen_helper(tcg_env, xt, xb); return true; } @@ -861,7 +861,7 @@ static void gen_##name(DisasContext *ctx) \ return; \ } \ opc = tcg_constant_i32(ctx->opcode); \ - gen_helper_##name(cpu_env, opc); \ + gen_helper_##name(tcg_env, opc); \ } #define GEN_VSX_HELPER_X3(name, op1, op2, inval, type) \ @@ -875,7 +875,7 @@ static void gen_##name(DisasContext *ctx) \ xt = gen_vsr_ptr(xT(ctx->opcode)); \ xa = gen_vsr_ptr(xA(ctx->opcode)); \ xb = gen_vsr_ptr(xB(ctx->opcode)); \ - gen_helper_##name(cpu_env, xt, xa, xb); \ + gen_helper_##name(tcg_env, xt, xa, xb); \ } #define GEN_VSX_HELPER_X2(name, op1, op2, inval, type) \ @@ -888,7 +888,7 @@ static void gen_##name(DisasContext *ctx) \ } \ xt = gen_vsr_ptr(xT(ctx->opcode)); \ xb = gen_vsr_ptr(xB(ctx->opcode)); \ - gen_helper_##name(cpu_env, xt, xb); \ + gen_helper_##name(tcg_env, xt, xb); \ } #define GEN_VSX_HELPER_X2_AB(name, op1, op2, inval, type) \ @@ -903,7 +903,7 @@ static void gen_##name(DisasContext *ctx) \ opc = tcg_constant_i32(ctx->opcode); \ xa = gen_vsr_ptr(xA(ctx->opcode)); \ xb = gen_vsr_ptr(xB(ctx->opcode)); \ - gen_helper_##name(cpu_env, opc, xa, xb); \ + gen_helper_##name(tcg_env, opc, xa, xb); \ } #define GEN_VSX_HELPER_X1(name, op1, op2, inval, type) \ @@ -917,7 +917,7 @@ static void gen_##name(DisasContext *ctx) \ } \ opc = tcg_constant_i32(ctx->opcode); \ xb = gen_vsr_ptr(xB(ctx->opcode)); \ - gen_helper_##name(cpu_env, opc, xb); \ + gen_helper_##name(tcg_env, opc, xb); \ } #define GEN_VSX_HELPER_R3(name, op1, op2, inval, type) \ @@ -933,7 +933,7 @@ static void gen_##name(DisasContext *ctx) \ xt = gen_vsr_ptr(rD(ctx->opcode) + 32); \ xa = gen_vsr_ptr(rA(ctx->opcode) + 32); \ xb = gen_vsr_ptr(rB(ctx->opcode) + 32); \ - gen_helper_##name(cpu_env, opc, xt, xa, xb); \ + gen_helper_##name(tcg_env, opc, xt, xa, xb); \ } #define GEN_VSX_HELPER_R2(name, op1, op2, inval, type) \ @@ -948,7 +948,7 @@ static void gen_##name(DisasContext *ctx) \ opc = tcg_constant_i32(ctx->opcode); \ xt = gen_vsr_ptr(rD(ctx->opcode) + 32); \ xb = gen_vsr_ptr(rB(ctx->opcode) + 32); \ - gen_helper_##name(cpu_env, opc, xt, xb); \ + gen_helper_##name(tcg_env, opc, xt, xb); \ } #define GEN_VSX_HELPER_R2_AB(name, op1, op2, inval, type) \ @@ -963,7 +963,7 @@ static void gen_##name(DisasContext *ctx) \ opc = tcg_constant_i32(ctx->opcode); \ xa = gen_vsr_ptr(rA(ctx->opcode) + 32); \ xb = gen_vsr_ptr(rB(ctx->opcode) + 32); \ - gen_helper_##name(cpu_env, opc, xa, xb); \ + gen_helper_##name(tcg_env, opc, xa, xb); \ } #define GEN_VSX_HELPER_XT_XB_ENV(name, op1, op2, inval, type) \ @@ -978,7 +978,7 @@ static void gen_##name(DisasContext *ctx) \ t0 = tcg_temp_new_i64(); \ t1 = tcg_temp_new_i64(); \ get_cpu_vsr(t0, xB(ctx->opcode), true); \ - gen_helper_##name(t1, cpu_env, t0); \ + gen_helper_##name(t1, tcg_env, t0); \ set_cpu_vsr(xT(ctx->opcode), t1, true); \ set_cpu_vsr(xT(ctx->opcode), tcg_constant_i64(0), false); \ } @@ -1191,7 +1191,7 @@ static bool do_XX2_bf_uim(DisasContext *ctx, arg_XX2_bf_uim *a, bool vsr, REQUIRE_VSX(ctx); xb = vsr ? gen_vsr_ptr(a->xb) : gen_avr_ptr(a->xb); - gen_helper(cpu_env, tcg_constant_i32(a->bf), tcg_constant_i32(a->uim), xb); + gen_helper(tcg_env, tcg_constant_i32(a->bf), tcg_constant_i32(a->uim), xb); return true; } @@ -1420,7 +1420,7 @@ static bool do_xsmadd(DisasContext *ctx, int tgt, int src1, int src2, int src3, s2 = gen_vsr_ptr(src2); s3 = gen_vsr_ptr(src3); - gen_helper(cpu_env, t, s1, s2, s3); + gen_helper(tcg_env, t, s1, s2, s3); return true; } @@ -1500,7 +1500,7 @@ static void gen_##name(DisasContext *ctx) \ s2 = gen_vsr_ptr(xT(ctx->opcode)); \ s3 = gen_vsr_ptr(xB(ctx->opcode)); \ } \ - gen_helper_##name(cpu_env, xt, s1, s2, s3); \ + gen_helper_##name(tcg_env, xt, s1, s2, s3); \ } GEN_VSX_HELPER_VSX_MADD(xvmadddp, 0x04, 0x0C, 0x0D, 0, PPC2_VSX) @@ -1728,9 +1728,9 @@ static bool trans_XXSPLTI32DX(DisasContext *ctx, arg_8RR_D_IX *a) imm = tcg_constant_i32(a->si); - tcg_gen_st_i32(imm, cpu_env, + tcg_gen_st_i32(imm, tcg_env, offsetof(CPUPPCState, vsr[a->xt].VsrW(0 + a->ix))); - tcg_gen_st_i32(imm, cpu_env, + tcg_gen_st_i32(imm, tcg_env, offsetof(CPUPPCState, vsr[a->xt].VsrW(2 + a->ix))); return true; @@ -2720,7 +2720,7 @@ static bool do_helper_XX3(DisasContext *ctx, arg_XX3 *a, xa = gen_vsr_ptr(a->xa); xb = gen_vsr_ptr(a->xb); - helper(cpu_env, xt, xa, xb); + helper(tcg_env, xt, xa, xb); return true; } @@ -2741,7 +2741,7 @@ static bool do_helper_X(arg_X *a, ra = gen_avr_ptr(a->ra); rb = gen_avr_ptr(a->rb); - helper(cpu_env, rt, ra, rb); + helper(tcg_env, rt, ra, rb); return true; } @@ -2770,7 +2770,7 @@ static bool trans_XVCVSPBF16(DisasContext *ctx, arg_XX2 *a) xt = gen_vsr_ptr(a->xt); xb = gen_vsr_ptr(a->xb); - gen_helper_XVCVSPBF16(cpu_env, xt, xb); + gen_helper_XVCVSPBF16(tcg_env, xt, xb); return true; } @@ -2833,7 +2833,7 @@ static bool do_ger(DisasContext *ctx, arg_MMIRR_XX3 *a, xb = gen_vsr_ptr(a->xb); mask = ger_pack_masks(a->pmsk, a->ymsk, a->xmsk); - helper(cpu_env, xa, xb, xt, tcg_constant_i32(mask)); + helper(tcg_env, xa, xb, xt, tcg_constant_i32(mask)); return true; } diff --git a/target/riscv/insn_trans/trans_privileged.c.inc b/target/riscv/insn_trans/trans_privileged.c.inc index dc14d7fc7a..620ab54eb0 100644 --- a/target/riscv/insn_trans/trans_privileged.c.inc +++ b/target/riscv/insn_trans/trans_privileged.c.inc @@ -78,7 +78,7 @@ static bool trans_sret(DisasContext *ctx, arg_sret *a) if (has_ext(ctx, RVS)) { decode_save_opc(ctx); translator_io_start(&ctx->base); - gen_helper_sret(cpu_pc, cpu_env); + gen_helper_sret(cpu_pc, tcg_env); exit_tb(ctx); /* no chaining */ ctx->base.is_jmp = DISAS_NORETURN; } else { @@ -95,7 +95,7 @@ static bool trans_mret(DisasContext *ctx, arg_mret *a) #ifndef CONFIG_USER_ONLY decode_save_opc(ctx); translator_io_start(&ctx->base); - gen_helper_mret(cpu_pc, cpu_env); + gen_helper_mret(cpu_pc, tcg_env); exit_tb(ctx); /* no chaining */ ctx->base.is_jmp = DISAS_NORETURN; return true; @@ -109,7 +109,7 @@ static bool trans_wfi(DisasContext *ctx, arg_wfi *a) #ifndef CONFIG_USER_ONLY decode_save_opc(ctx); gen_update_pc(ctx, ctx->cur_insn_len); - gen_helper_wfi(cpu_env); + gen_helper_wfi(tcg_env); return true; #else return false; @@ -120,7 +120,7 @@ static bool trans_sfence_vma(DisasContext *ctx, arg_sfence_vma *a) { #ifndef CONFIG_USER_ONLY decode_save_opc(ctx); - gen_helper_tlb_flush(cpu_env); + gen_helper_tlb_flush(tcg_env); return true; #endif return false; diff --git a/target/riscv/insn_trans/trans_rvbf16.c.inc b/target/riscv/insn_trans/trans_rvbf16.c.inc index 911bc29908..4e39c00884 100644 --- a/target/riscv/insn_trans/trans_rvbf16.c.inc +++ b/target/riscv/insn_trans/trans_rvbf16.c.inc @@ -43,7 +43,7 @@ static bool trans_fcvt_bf16_s(DisasContext *ctx, arg_fcvt_bf16_s *a) TCGv_i64 src1 = get_fpr_hs(ctx, a->rs1); gen_set_rm(ctx, a->rm); - gen_helper_fcvt_bf16_s(dest, cpu_env, src1); + gen_helper_fcvt_bf16_s(dest, tcg_env, src1); gen_set_fpr_hs(ctx, a->rd, dest); mark_fs_dirty(ctx); return true; @@ -58,7 +58,7 @@ static bool trans_fcvt_s_bf16(DisasContext *ctx, arg_fcvt_s_bf16 *a) TCGv_i64 src1 = get_fpr_hs(ctx, a->rs1); gen_set_rm(ctx, a->rm); - gen_helper_fcvt_s_bf16(dest, cpu_env, src1); + gen_helper_fcvt_s_bf16(dest, tcg_env, src1); gen_set_fpr_hs(ctx, a->rd, dest); mark_fs_dirty(ctx); return true; @@ -82,7 +82,7 @@ static bool trans_vfncvtbf16_f_f_w(DisasContext *ctx, arg_vfncvtbf16_f_f_w *a) data = FIELD_DP32(data, VDATA, VTA, ctx->vta); data = FIELD_DP32(data, VDATA, VMA, ctx->vma); tcg_gen_gvec_3_ptr(vreg_ofs(ctx, a->rd), vreg_ofs(ctx, 0), - vreg_ofs(ctx, a->rs2), cpu_env, + vreg_ofs(ctx, a->rs2), tcg_env, ctx->cfg_ptr->vlen / 8, ctx->cfg_ptr->vlen / 8, data, gen_helper_vfncvtbf16_f_f_w); @@ -111,7 +111,7 @@ static bool trans_vfwcvtbf16_f_f_v(DisasContext *ctx, arg_vfwcvtbf16_f_f_v *a) data = FIELD_DP32(data, VDATA, VTA, ctx->vta); data = FIELD_DP32(data, VDATA, VMA, ctx->vma); tcg_gen_gvec_3_ptr(vreg_ofs(ctx, a->rd), vreg_ofs(ctx, 0), - vreg_ofs(ctx, a->rs2), cpu_env, + vreg_ofs(ctx, a->rs2), tcg_env, ctx->cfg_ptr->vlen / 8, ctx->cfg_ptr->vlen / 8, data, gen_helper_vfwcvtbf16_f_f_v); @@ -142,7 +142,7 @@ static bool trans_vfwmaccbf16_vv(DisasContext *ctx, arg_vfwmaccbf16_vv *a) data = FIELD_DP32(data, VDATA, VMA, ctx->vma); tcg_gen_gvec_4_ptr(vreg_ofs(ctx, a->rd), vreg_ofs(ctx, 0), vreg_ofs(ctx, a->rs1), - vreg_ofs(ctx, a->rs2), cpu_env, + vreg_ofs(ctx, a->rs2), tcg_env, ctx->cfg_ptr->vlen / 8, ctx->cfg_ptr->vlen / 8, data, gen_helper_vfwmaccbf16_vv); diff --git a/target/riscv/insn_trans/trans_rvd.c.inc b/target/riscv/insn_trans/trans_rvd.c.inc index 6bdb55ef43..d9ce9e407f 100644 --- a/target/riscv/insn_trans/trans_rvd.c.inc +++ b/target/riscv/insn_trans/trans_rvd.c.inc @@ -91,7 +91,7 @@ static bool trans_fmadd_d(DisasContext *ctx, arg_fmadd_d *a) TCGv_i64 src3 = get_fpr_d(ctx, a->rs3); gen_set_rm(ctx, a->rm); - gen_helper_fmadd_d(dest, cpu_env, src1, src2, src3); + gen_helper_fmadd_d(dest, tcg_env, src1, src2, src3); gen_set_fpr_d(ctx, a->rd, dest); mark_fs_dirty(ctx); return true; @@ -109,7 +109,7 @@ static bool trans_fmsub_d(DisasContext *ctx, arg_fmsub_d *a) TCGv_i64 src3 = get_fpr_d(ctx, a->rs3); gen_set_rm(ctx, a->rm); - gen_helper_fmsub_d(dest, cpu_env, src1, src2, src3); + gen_helper_fmsub_d(dest, tcg_env, src1, src2, src3); gen_set_fpr_d(ctx, a->rd, dest); mark_fs_dirty(ctx); return true; @@ -127,7 +127,7 @@ static bool trans_fnmsub_d(DisasContext *ctx, arg_fnmsub_d *a) TCGv_i64 src3 = get_fpr_d(ctx, a->rs3); gen_set_rm(ctx, a->rm); - gen_helper_fnmsub_d(dest, cpu_env, src1, src2, src3); + gen_helper_fnmsub_d(dest, tcg_env, src1, src2, src3); gen_set_fpr_d(ctx, a->rd, dest); mark_fs_dirty(ctx); return true; @@ -145,7 +145,7 @@ static bool trans_fnmadd_d(DisasContext *ctx, arg_fnmadd_d *a) TCGv_i64 src3 = get_fpr_d(ctx, a->rs3); gen_set_rm(ctx, a->rm); - gen_helper_fnmadd_d(dest, cpu_env, src1, src2, src3); + gen_helper_fnmadd_d(dest, tcg_env, src1, src2, src3); gen_set_fpr_d(ctx, a->rd, dest); mark_fs_dirty(ctx); return true; @@ -162,7 +162,7 @@ static bool trans_fadd_d(DisasContext *ctx, arg_fadd_d *a) TCGv_i64 src2 = get_fpr_d(ctx, a->rs2); gen_set_rm(ctx, a->rm); - gen_helper_fadd_d(dest, cpu_env, src1, src2); + gen_helper_fadd_d(dest, tcg_env, src1, src2); gen_set_fpr_d(ctx, a->rd, dest); mark_fs_dirty(ctx); return true; @@ -179,7 +179,7 @@ static bool trans_fsub_d(DisasContext *ctx, arg_fsub_d *a) TCGv_i64 src2 = get_fpr_d(ctx, a->rs2); gen_set_rm(ctx, a->rm); - gen_helper_fsub_d(dest, cpu_env, src1, src2); + gen_helper_fsub_d(dest, tcg_env, src1, src2); gen_set_fpr_d(ctx, a->rd, dest); mark_fs_dirty(ctx); return true; @@ -196,7 +196,7 @@ static bool trans_fmul_d(DisasContext *ctx, arg_fmul_d *a) TCGv_i64 src2 = get_fpr_d(ctx, a->rs2); gen_set_rm(ctx, a->rm); - gen_helper_fmul_d(dest, cpu_env, src1, src2); + gen_helper_fmul_d(dest, tcg_env, src1, src2); gen_set_fpr_d(ctx, a->rd, dest); mark_fs_dirty(ctx); return true; @@ -213,7 +213,7 @@ static bool trans_fdiv_d(DisasContext *ctx, arg_fdiv_d *a) TCGv_i64 src2 = get_fpr_d(ctx, a->rs2); gen_set_rm(ctx, a->rm); - gen_helper_fdiv_d(dest, cpu_env, src1, src2); + gen_helper_fdiv_d(dest, tcg_env, src1, src2); gen_set_fpr_d(ctx, a->rd, dest); mark_fs_dirty(ctx); return true; @@ -229,7 +229,7 @@ static bool trans_fsqrt_d(DisasContext *ctx, arg_fsqrt_d *a) TCGv_i64 src1 = get_fpr_d(ctx, a->rs1); gen_set_rm(ctx, a->rm); - gen_helper_fsqrt_d(dest, cpu_env, src1); + gen_helper_fsqrt_d(dest, tcg_env, src1); gen_set_fpr_d(ctx, a->rd, dest); mark_fs_dirty(ctx); return true; @@ -308,7 +308,7 @@ static bool trans_fmin_d(DisasContext *ctx, arg_fmin_d *a) TCGv_i64 src1 = get_fpr_d(ctx, a->rs1); TCGv_i64 src2 = get_fpr_d(ctx, a->rs2); - gen_helper_fmin_d(dest, cpu_env, src1, src2); + gen_helper_fmin_d(dest, tcg_env, src1, src2); gen_set_fpr_d(ctx, a->rd, dest); mark_fs_dirty(ctx); return true; @@ -324,7 +324,7 @@ static bool trans_fmax_d(DisasContext *ctx, arg_fmax_d *a) TCGv_i64 src1 = get_fpr_d(ctx, a->rs1); TCGv_i64 src2 = get_fpr_d(ctx, a->rs2); - gen_helper_fmax_d(dest, cpu_env, src1, src2); + gen_helper_fmax_d(dest, tcg_env, src1, src2); gen_set_fpr_d(ctx, a->rd, dest); mark_fs_dirty(ctx); return true; @@ -340,7 +340,7 @@ static bool trans_fcvt_s_d(DisasContext *ctx, arg_fcvt_s_d *a) TCGv_i64 src1 = get_fpr_d(ctx, a->rs1); gen_set_rm(ctx, a->rm); - gen_helper_fcvt_s_d(dest, cpu_env, src1); + gen_helper_fcvt_s_d(dest, tcg_env, src1); gen_set_fpr_hs(ctx, a->rd, dest); mark_fs_dirty(ctx); return true; @@ -356,7 +356,7 @@ static bool trans_fcvt_d_s(DisasContext *ctx, arg_fcvt_d_s *a) TCGv_i64 src1 = get_fpr_hs(ctx, a->rs1); gen_set_rm(ctx, a->rm); - gen_helper_fcvt_d_s(dest, cpu_env, src1); + gen_helper_fcvt_d_s(dest, tcg_env, src1); gen_set_fpr_d(ctx, a->rd, dest); mark_fs_dirty(ctx); return true; @@ -372,7 +372,7 @@ static bool trans_feq_d(DisasContext *ctx, arg_feq_d *a) TCGv_i64 src1 = get_fpr_d(ctx, a->rs1); TCGv_i64 src2 = get_fpr_d(ctx, a->rs2); - gen_helper_feq_d(dest, cpu_env, src1, src2); + gen_helper_feq_d(dest, tcg_env, src1, src2); gen_set_gpr(ctx, a->rd, dest); return true; } @@ -387,7 +387,7 @@ static bool trans_flt_d(DisasContext *ctx, arg_flt_d *a) TCGv_i64 src1 = get_fpr_d(ctx, a->rs1); TCGv_i64 src2 = get_fpr_d(ctx, a->rs2); - gen_helper_flt_d(dest, cpu_env, src1, src2); + gen_helper_flt_d(dest, tcg_env, src1, src2); gen_set_gpr(ctx, a->rd, dest); return true; } @@ -402,7 +402,7 @@ static bool trans_fle_d(DisasContext *ctx, arg_fle_d *a) TCGv_i64 src1 = get_fpr_d(ctx, a->rs1); TCGv_i64 src2 = get_fpr_d(ctx, a->rs2); - gen_helper_fle_d(dest, cpu_env, src1, src2); + gen_helper_fle_d(dest, tcg_env, src1, src2); gen_set_gpr(ctx, a->rd, dest); return true; } @@ -431,7 +431,7 @@ static bool trans_fcvt_w_d(DisasContext *ctx, arg_fcvt_w_d *a) TCGv_i64 src1 = get_fpr_d(ctx, a->rs1); gen_set_rm(ctx, a->rm); - gen_helper_fcvt_w_d(dest, cpu_env, src1); + gen_helper_fcvt_w_d(dest, tcg_env, src1); gen_set_gpr(ctx, a->rd, dest); return true; } @@ -446,7 +446,7 @@ static bool trans_fcvt_wu_d(DisasContext *ctx, arg_fcvt_wu_d *a) TCGv_i64 src1 = get_fpr_d(ctx, a->rs1); gen_set_rm(ctx, a->rm); - gen_helper_fcvt_wu_d(dest, cpu_env, src1); + gen_helper_fcvt_wu_d(dest, tcg_env, src1); gen_set_gpr(ctx, a->rd, dest); return true; } @@ -461,7 +461,7 @@ static bool trans_fcvt_d_w(DisasContext *ctx, arg_fcvt_d_w *a) TCGv src = get_gpr(ctx, a->rs1, EXT_SIGN); gen_set_rm(ctx, a->rm); - gen_helper_fcvt_d_w(dest, cpu_env, src); + gen_helper_fcvt_d_w(dest, tcg_env, src); gen_set_fpr_d(ctx, a->rd, dest); mark_fs_dirty(ctx); @@ -478,7 +478,7 @@ static bool trans_fcvt_d_wu(DisasContext *ctx, arg_fcvt_d_wu *a) TCGv src = get_gpr(ctx, a->rs1, EXT_ZERO); gen_set_rm(ctx, a->rm); - gen_helper_fcvt_d_wu(dest, cpu_env, src); + gen_helper_fcvt_d_wu(dest, tcg_env, src); gen_set_fpr_d(ctx, a->rd, dest); mark_fs_dirty(ctx); @@ -496,7 +496,7 @@ static bool trans_fcvt_l_d(DisasContext *ctx, arg_fcvt_l_d *a) TCGv_i64 src1 = get_fpr_d(ctx, a->rs1); gen_set_rm(ctx, a->rm); - gen_helper_fcvt_l_d(dest, cpu_env, src1); + gen_helper_fcvt_l_d(dest, tcg_env, src1); gen_set_gpr(ctx, a->rd, dest); return true; } @@ -512,7 +512,7 @@ static bool trans_fcvt_lu_d(DisasContext *ctx, arg_fcvt_lu_d *a) TCGv_i64 src1 = get_fpr_d(ctx, a->rs1); gen_set_rm(ctx, a->rm); - gen_helper_fcvt_lu_d(dest, cpu_env, src1); + gen_helper_fcvt_lu_d(dest, tcg_env, src1); gen_set_gpr(ctx, a->rd, dest); return true; } @@ -542,7 +542,7 @@ static bool trans_fcvt_d_l(DisasContext *ctx, arg_fcvt_d_l *a) TCGv src = get_gpr(ctx, a->rs1, EXT_SIGN); gen_set_rm(ctx, a->rm); - gen_helper_fcvt_d_l(dest, cpu_env, src); + gen_helper_fcvt_d_l(dest, tcg_env, src); gen_set_fpr_d(ctx, a->rd, dest); mark_fs_dirty(ctx); @@ -560,7 +560,7 @@ static bool trans_fcvt_d_lu(DisasContext *ctx, arg_fcvt_d_lu *a) TCGv src = get_gpr(ctx, a->rs1, EXT_ZERO); gen_set_rm(ctx, a->rm); - gen_helper_fcvt_d_lu(dest, cpu_env, src); + gen_helper_fcvt_d_lu(dest, tcg_env, src); gen_set_fpr_d(ctx, a->rd, dest); mark_fs_dirty(ctx); diff --git a/target/riscv/insn_trans/trans_rvf.c.inc b/target/riscv/insn_trans/trans_rvf.c.inc index e7ab84cd9a..97a368970b 100644 --- a/target/riscv/insn_trans/trans_rvf.c.inc +++ b/target/riscv/insn_trans/trans_rvf.c.inc @@ -93,7 +93,7 @@ static bool trans_fmadd_s(DisasContext *ctx, arg_fmadd_s *a) TCGv_i64 src3 = get_fpr_hs(ctx, a->rs3); gen_set_rm(ctx, a->rm); - gen_helper_fmadd_s(dest, cpu_env, src1, src2, src3); + gen_helper_fmadd_s(dest, tcg_env, src1, src2, src3); gen_set_fpr_hs(ctx, a->rd, dest); mark_fs_dirty(ctx); return true; @@ -110,7 +110,7 @@ static bool trans_fmsub_s(DisasContext *ctx, arg_fmsub_s *a) TCGv_i64 src3 = get_fpr_hs(ctx, a->rs3); gen_set_rm(ctx, a->rm); - gen_helper_fmsub_s(dest, cpu_env, src1, src2, src3); + gen_helper_fmsub_s(dest, tcg_env, src1, src2, src3); gen_set_fpr_hs(ctx, a->rd, dest); mark_fs_dirty(ctx); return true; @@ -127,7 +127,7 @@ static bool trans_fnmsub_s(DisasContext *ctx, arg_fnmsub_s *a) TCGv_i64 src3 = get_fpr_hs(ctx, a->rs3); gen_set_rm(ctx, a->rm); - gen_helper_fnmsub_s(dest, cpu_env, src1, src2, src3); + gen_helper_fnmsub_s(dest, tcg_env, src1, src2, src3); gen_set_fpr_hs(ctx, a->rd, dest); mark_fs_dirty(ctx); return true; @@ -144,7 +144,7 @@ static bool trans_fnmadd_s(DisasContext *ctx, arg_fnmadd_s *a) TCGv_i64 src3 = get_fpr_hs(ctx, a->rs3); gen_set_rm(ctx, a->rm); - gen_helper_fnmadd_s(dest, cpu_env, src1, src2, src3); + gen_helper_fnmadd_s(dest, tcg_env, src1, src2, src3); gen_set_fpr_hs(ctx, a->rd, dest); mark_fs_dirty(ctx); return true; @@ -160,7 +160,7 @@ static bool trans_fadd_s(DisasContext *ctx, arg_fadd_s *a) TCGv_i64 src2 = get_fpr_hs(ctx, a->rs2); gen_set_rm(ctx, a->rm); - gen_helper_fadd_s(dest, cpu_env, src1, src2); + gen_helper_fadd_s(dest, tcg_env, src1, src2); gen_set_fpr_hs(ctx, a->rd, dest); mark_fs_dirty(ctx); return true; @@ -176,7 +176,7 @@ static bool trans_fsub_s(DisasContext *ctx, arg_fsub_s *a) TCGv_i64 src2 = get_fpr_hs(ctx, a->rs2); gen_set_rm(ctx, a->rm); - gen_helper_fsub_s(dest, cpu_env, src1, src2); + gen_helper_fsub_s(dest, tcg_env, src1, src2); gen_set_fpr_hs(ctx, a->rd, dest); mark_fs_dirty(ctx); return true; @@ -192,7 +192,7 @@ static bool trans_fmul_s(DisasContext *ctx, arg_fmul_s *a) TCGv_i64 src2 = get_fpr_hs(ctx, a->rs2); gen_set_rm(ctx, a->rm); - gen_helper_fmul_s(dest, cpu_env, src1, src2); + gen_helper_fmul_s(dest, tcg_env, src1, src2); gen_set_fpr_hs(ctx, a->rd, dest); mark_fs_dirty(ctx); return true; @@ -208,7 +208,7 @@ static bool trans_fdiv_s(DisasContext *ctx, arg_fdiv_s *a) TCGv_i64 src2 = get_fpr_hs(ctx, a->rs2); gen_set_rm(ctx, a->rm); - gen_helper_fdiv_s(dest, cpu_env, src1, src2); + gen_helper_fdiv_s(dest, tcg_env, src1, src2); gen_set_fpr_hs(ctx, a->rd, dest); mark_fs_dirty(ctx); return true; @@ -223,7 +223,7 @@ static bool trans_fsqrt_s(DisasContext *ctx, arg_fsqrt_s *a) TCGv_i64 src1 = get_fpr_hs(ctx, a->rs1); gen_set_rm(ctx, a->rm); - gen_helper_fsqrt_s(dest, cpu_env, src1); + gen_helper_fsqrt_s(dest, tcg_env, src1); gen_set_fpr_hs(ctx, a->rd, dest); mark_fs_dirty(ctx); return true; @@ -363,7 +363,7 @@ static bool trans_fmin_s(DisasContext *ctx, arg_fmin_s *a) TCGv_i64 src1 = get_fpr_hs(ctx, a->rs1); TCGv_i64 src2 = get_fpr_hs(ctx, a->rs2); - gen_helper_fmin_s(dest, cpu_env, src1, src2); + gen_helper_fmin_s(dest, tcg_env, src1, src2); gen_set_fpr_hs(ctx, a->rd, dest); mark_fs_dirty(ctx); return true; @@ -378,7 +378,7 @@ static bool trans_fmax_s(DisasContext *ctx, arg_fmax_s *a) TCGv_i64 src1 = get_fpr_hs(ctx, a->rs1); TCGv_i64 src2 = get_fpr_hs(ctx, a->rs2); - gen_helper_fmax_s(dest, cpu_env, src1, src2); + gen_helper_fmax_s(dest, tcg_env, src1, src2); gen_set_fpr_hs(ctx, a->rd, dest); mark_fs_dirty(ctx); return true; @@ -393,7 +393,7 @@ static bool trans_fcvt_w_s(DisasContext *ctx, arg_fcvt_w_s *a) TCGv_i64 src1 = get_fpr_hs(ctx, a->rs1); gen_set_rm(ctx, a->rm); - gen_helper_fcvt_w_s(dest, cpu_env, src1); + gen_helper_fcvt_w_s(dest, tcg_env, src1); gen_set_gpr(ctx, a->rd, dest); return true; } @@ -407,7 +407,7 @@ static bool trans_fcvt_wu_s(DisasContext *ctx, arg_fcvt_wu_s *a) TCGv_i64 src1 = get_fpr_hs(ctx, a->rs1); gen_set_rm(ctx, a->rm); - gen_helper_fcvt_wu_s(dest, cpu_env, src1); + gen_helper_fcvt_wu_s(dest, tcg_env, src1); gen_set_gpr(ctx, a->rd, dest); return true; } @@ -439,7 +439,7 @@ static bool trans_feq_s(DisasContext *ctx, arg_feq_s *a) TCGv_i64 src1 = get_fpr_hs(ctx, a->rs1); TCGv_i64 src2 = get_fpr_hs(ctx, a->rs2); - gen_helper_feq_s(dest, cpu_env, src1, src2); + gen_helper_feq_s(dest, tcg_env, src1, src2); gen_set_gpr(ctx, a->rd, dest); return true; } @@ -453,7 +453,7 @@ static bool trans_flt_s(DisasContext *ctx, arg_flt_s *a) TCGv_i64 src1 = get_fpr_hs(ctx, a->rs1); TCGv_i64 src2 = get_fpr_hs(ctx, a->rs2); - gen_helper_flt_s(dest, cpu_env, src1, src2); + gen_helper_flt_s(dest, tcg_env, src1, src2); gen_set_gpr(ctx, a->rd, dest); return true; } @@ -467,7 +467,7 @@ static bool trans_fle_s(DisasContext *ctx, arg_fle_s *a) TCGv_i64 src1 = get_fpr_hs(ctx, a->rs1); TCGv_i64 src2 = get_fpr_hs(ctx, a->rs2); - gen_helper_fle_s(dest, cpu_env, src1, src2); + gen_helper_fle_s(dest, tcg_env, src1, src2); gen_set_gpr(ctx, a->rd, dest); return true; } @@ -480,7 +480,7 @@ static bool trans_fclass_s(DisasContext *ctx, arg_fclass_s *a) TCGv dest = dest_gpr(ctx, a->rd); TCGv_i64 src1 = get_fpr_hs(ctx, a->rs1); - gen_helper_fclass_s(dest, cpu_env, src1); + gen_helper_fclass_s(dest, tcg_env, src1); gen_set_gpr(ctx, a->rd, dest); return true; } @@ -494,7 +494,7 @@ static bool trans_fcvt_s_w(DisasContext *ctx, arg_fcvt_s_w *a) TCGv src = get_gpr(ctx, a->rs1, EXT_SIGN); gen_set_rm(ctx, a->rm); - gen_helper_fcvt_s_w(dest, cpu_env, src); + gen_helper_fcvt_s_w(dest, tcg_env, src); gen_set_fpr_hs(ctx, a->rd, dest); mark_fs_dirty(ctx); return true; @@ -509,7 +509,7 @@ static bool trans_fcvt_s_wu(DisasContext *ctx, arg_fcvt_s_wu *a) TCGv src = get_gpr(ctx, a->rs1, EXT_ZERO); gen_set_rm(ctx, a->rm); - gen_helper_fcvt_s_wu(dest, cpu_env, src); + gen_helper_fcvt_s_wu(dest, tcg_env, src); gen_set_fpr_hs(ctx, a->rd, dest); mark_fs_dirty(ctx); return true; @@ -541,7 +541,7 @@ static bool trans_fcvt_l_s(DisasContext *ctx, arg_fcvt_l_s *a) TCGv_i64 src1 = get_fpr_hs(ctx, a->rs1); gen_set_rm(ctx, a->rm); - gen_helper_fcvt_l_s(dest, cpu_env, src1); + gen_helper_fcvt_l_s(dest, tcg_env, src1); gen_set_gpr(ctx, a->rd, dest); return true; } @@ -556,7 +556,7 @@ static bool trans_fcvt_lu_s(DisasContext *ctx, arg_fcvt_lu_s *a) TCGv_i64 src1 = get_fpr_hs(ctx, a->rs1); gen_set_rm(ctx, a->rm); - gen_helper_fcvt_lu_s(dest, cpu_env, src1); + gen_helper_fcvt_lu_s(dest, tcg_env, src1); gen_set_gpr(ctx, a->rd, dest); return true; } @@ -571,7 +571,7 @@ static bool trans_fcvt_s_l(DisasContext *ctx, arg_fcvt_s_l *a) TCGv src = get_gpr(ctx, a->rs1, EXT_SIGN); gen_set_rm(ctx, a->rm); - gen_helper_fcvt_s_l(dest, cpu_env, src); + gen_helper_fcvt_s_l(dest, tcg_env, src); gen_set_fpr_hs(ctx, a->rd, dest); mark_fs_dirty(ctx); return true; @@ -587,7 +587,7 @@ static bool trans_fcvt_s_lu(DisasContext *ctx, arg_fcvt_s_lu *a) TCGv src = get_gpr(ctx, a->rs1, EXT_ZERO); gen_set_rm(ctx, a->rm); - gen_helper_fcvt_s_lu(dest, cpu_env, src); + gen_helper_fcvt_s_lu(dest, tcg_env, src); gen_set_fpr_hs(ctx, a->rd, dest); mark_fs_dirty(ctx); return true; diff --git a/target/riscv/insn_trans/trans_rvh.c.inc b/target/riscv/insn_trans/trans_rvh.c.inc index 3e9322130f..aa9d41c18c 100644 --- a/target/riscv/insn_trans/trans_rvh.c.inc +++ b/target/riscv/insn_trans/trans_rvh.c.inc @@ -45,7 +45,7 @@ static bool do_hlv(DisasContext *ctx, arg_r2 *a, TCGv addr = get_gpr(ctx, a->rs1, EXT_NONE); decode_save_opc(ctx); - func(dest, cpu_env, addr); + func(dest, tcg_env, addr); gen_set_gpr(ctx, a->rd, dest); return true; } @@ -57,7 +57,7 @@ static bool do_hsv(DisasContext *ctx, arg_r2_s *a, TCGv data = get_gpr(ctx, a->rs2, EXT_NONE); decode_save_opc(ctx); - func(cpu_env, addr, data); + func(tcg_env, addr, data); return true; } #endif /* CONFIG_USER_ONLY */ @@ -148,7 +148,7 @@ static bool trans_hfence_gvma(DisasContext *ctx, arg_sfence_vma *a) REQUIRE_EXT(ctx, RVH); #ifndef CONFIG_USER_ONLY decode_save_opc(ctx); - gen_helper_hyp_gvma_tlb_flush(cpu_env); + gen_helper_hyp_gvma_tlb_flush(tcg_env); return true; #endif return false; @@ -159,7 +159,7 @@ static bool trans_hfence_vvma(DisasContext *ctx, arg_sfence_vma *a) REQUIRE_EXT(ctx, RVH); #ifndef CONFIG_USER_ONLY decode_save_opc(ctx); - gen_helper_hyp_tlb_flush(cpu_env); + gen_helper_hyp_tlb_flush(tcg_env); return true; #endif return false; diff --git a/target/riscv/insn_trans/trans_rvi.c.inc b/target/riscv/insn_trans/trans_rvi.c.inc index 297142208e..25cb60558a 100644 --- a/target/riscv/insn_trans/trans_rvi.c.inc +++ b/target/riscv/insn_trans/trans_rvi.c.inc @@ -830,7 +830,7 @@ static bool do_csrr(DisasContext *ctx, int rd, int rc) TCGv_i32 csr = tcg_constant_i32(rc); translator_io_start(&ctx->base); - gen_helper_csrr(dest, cpu_env, csr); + gen_helper_csrr(dest, tcg_env, csr); gen_set_gpr(ctx, rd, dest); return do_csr_post(ctx); } @@ -840,7 +840,7 @@ static bool do_csrw(DisasContext *ctx, int rc, TCGv src) TCGv_i32 csr = tcg_constant_i32(rc); translator_io_start(&ctx->base); - gen_helper_csrw(cpu_env, csr, src); + gen_helper_csrw(tcg_env, csr, src); return do_csr_post(ctx); } @@ -850,7 +850,7 @@ static bool do_csrrw(DisasContext *ctx, int rd, int rc, TCGv src, TCGv mask) TCGv_i32 csr = tcg_constant_i32(rc); translator_io_start(&ctx->base); - gen_helper_csrrw(dest, cpu_env, csr, src, mask); + gen_helper_csrrw(dest, tcg_env, csr, src, mask); gen_set_gpr(ctx, rd, dest); return do_csr_post(ctx); } @@ -862,8 +862,8 @@ static bool do_csrr_i128(DisasContext *ctx, int rd, int rc) TCGv_i32 csr = tcg_constant_i32(rc); translator_io_start(&ctx->base); - gen_helper_csrr_i128(destl, cpu_env, csr); - tcg_gen_ld_tl(desth, cpu_env, offsetof(CPURISCVState, retxh)); + gen_helper_csrr_i128(destl, tcg_env, csr); + tcg_gen_ld_tl(desth, tcg_env, offsetof(CPURISCVState, retxh)); gen_set_gpr128(ctx, rd, destl, desth); return do_csr_post(ctx); } @@ -873,7 +873,7 @@ static bool do_csrw_i128(DisasContext *ctx, int rc, TCGv srcl, TCGv srch) TCGv_i32 csr = tcg_constant_i32(rc); translator_io_start(&ctx->base); - gen_helper_csrw_i128(cpu_env, csr, srcl, srch); + gen_helper_csrw_i128(tcg_env, csr, srcl, srch); return do_csr_post(ctx); } @@ -885,8 +885,8 @@ static bool do_csrrw_i128(DisasContext *ctx, int rd, int rc, TCGv_i32 csr = tcg_constant_i32(rc); translator_io_start(&ctx->base); - gen_helper_csrrw_i128(destl, cpu_env, csr, srcl, srch, maskl, maskh); - tcg_gen_ld_tl(desth, cpu_env, offsetof(CPURISCVState, retxh)); + gen_helper_csrrw_i128(destl, tcg_env, csr, srcl, srch, maskl, maskh); + tcg_gen_ld_tl(desth, tcg_env, offsetof(CPURISCVState, retxh)); gen_set_gpr128(ctx, rd, destl, desth); return do_csr_post(ctx); } diff --git a/target/riscv/insn_trans/trans_rvm.c.inc b/target/riscv/insn_trans/trans_rvm.c.inc index 2f0fd1f700..795f0ccf14 100644 --- a/target/riscv/insn_trans/trans_rvm.c.inc +++ b/target/riscv/insn_trans/trans_rvm.c.inc @@ -169,8 +169,8 @@ static bool trans_mulhu(DisasContext *ctx, arg_mulhu *a) static void gen_div_i128(TCGv rdl, TCGv rdh, TCGv rs1l, TCGv rs1h, TCGv rs2l, TCGv rs2h) { - gen_helper_divs_i128(rdl, cpu_env, rs1l, rs1h, rs2l, rs2h); - tcg_gen_ld_tl(rdh, cpu_env, offsetof(CPURISCVState, retxh)); + gen_helper_divs_i128(rdl, tcg_env, rs1l, rs1h, rs2l, rs2h); + tcg_gen_ld_tl(rdh, tcg_env, offsetof(CPURISCVState, retxh)); } static void gen_div(TCGv ret, TCGv source1, TCGv source2) @@ -212,8 +212,8 @@ static bool trans_div(DisasContext *ctx, arg_div *a) static void gen_divu_i128(TCGv rdl, TCGv rdh, TCGv rs1l, TCGv rs1h, TCGv rs2l, TCGv rs2h) { - gen_helper_divu_i128(rdl, cpu_env, rs1l, rs1h, rs2l, rs2h); - tcg_gen_ld_tl(rdh, cpu_env, offsetof(CPURISCVState, retxh)); + gen_helper_divu_i128(rdl, tcg_env, rs1l, rs1h, rs2l, rs2h); + tcg_gen_ld_tl(rdh, tcg_env, offsetof(CPURISCVState, retxh)); } static void gen_divu(TCGv ret, TCGv source1, TCGv source2) @@ -244,8 +244,8 @@ static bool trans_divu(DisasContext *ctx, arg_divu *a) static void gen_rem_i128(TCGv rdl, TCGv rdh, TCGv rs1l, TCGv rs1h, TCGv rs2l, TCGv rs2h) { - gen_helper_rems_i128(rdl, cpu_env, rs1l, rs1h, rs2l, rs2h); - tcg_gen_ld_tl(rdh, cpu_env, offsetof(CPURISCVState, retxh)); + gen_helper_rems_i128(rdl, tcg_env, rs1l, rs1h, rs2l, rs2h); + tcg_gen_ld_tl(rdh, tcg_env, offsetof(CPURISCVState, retxh)); } static void gen_rem(TCGv ret, TCGv source1, TCGv source2) @@ -289,8 +289,8 @@ static bool trans_rem(DisasContext *ctx, arg_rem *a) static void gen_remu_i128(TCGv rdl, TCGv rdh, TCGv rs1l, TCGv rs1h, TCGv rs2l, TCGv rs2h) { - gen_helper_remu_i128(rdl, cpu_env, rs1l, rs1h, rs2l, rs2h); - tcg_gen_ld_tl(rdh, cpu_env, offsetof(CPURISCVState, retxh)); + gen_helper_remu_i128(rdl, tcg_env, rs1l, rs1h, rs2l, rs2h); + tcg_gen_ld_tl(rdh, tcg_env, offsetof(CPURISCVState, retxh)); } static void gen_remu(TCGv ret, TCGv source1, TCGv source2) diff --git a/target/riscv/insn_trans/trans_rvv.c.inc b/target/riscv/insn_trans/trans_rvv.c.inc index 63404f61fc..78bd363310 100644 --- a/target/riscv/insn_trans/trans_rvv.c.inc +++ b/target/riscv/insn_trans/trans_rvv.c.inc @@ -165,7 +165,7 @@ static bool do_vsetvl(DisasContext *s, int rd, int rs1, TCGv s2) s1 = get_gpr(s, rs1, EXT_ZERO); } - gen_helper_vsetvl(dst, cpu_env, s1, s2); + gen_helper_vsetvl(dst, tcg_env, s1, s2); gen_set_gpr(s, rd, dst); mark_vs_dirty(s); @@ -185,7 +185,7 @@ static bool do_vsetivli(DisasContext *s, int rd, TCGv s1, TCGv s2) dst = dest_gpr(s, rd); - gen_helper_vsetvl(dst, cpu_env, s1, s2); + gen_helper_vsetvl(dst, tcg_env, s1, s2); gen_set_gpr(s, rd, dst); mark_vs_dirty(s); gen_update_pc(s, s->cur_insn_len); @@ -633,10 +633,10 @@ static bool ldst_us_trans(uint32_t vd, uint32_t rs1, uint32_t data, desc = tcg_constant_i32(simd_desc(s->cfg_ptr->vlen / 8, s->cfg_ptr->vlen / 8, data)); - tcg_gen_addi_ptr(dest, cpu_env, vreg_ofs(s, vd)); - tcg_gen_addi_ptr(mask, cpu_env, vreg_ofs(s, 0)); + tcg_gen_addi_ptr(dest, tcg_env, vreg_ofs(s, vd)); + tcg_gen_addi_ptr(mask, tcg_env, vreg_ofs(s, 0)); - fn(dest, mask, base, cpu_env, desc); + fn(dest, mask, base, tcg_env, desc); if (!is_store) { mark_vs_dirty(s); @@ -794,10 +794,10 @@ static bool ldst_stride_trans(uint32_t vd, uint32_t rs1, uint32_t rs2, desc = tcg_constant_i32(simd_desc(s->cfg_ptr->vlen / 8, s->cfg_ptr->vlen / 8, data)); - tcg_gen_addi_ptr(dest, cpu_env, vreg_ofs(s, vd)); - tcg_gen_addi_ptr(mask, cpu_env, vreg_ofs(s, 0)); + tcg_gen_addi_ptr(dest, tcg_env, vreg_ofs(s, vd)); + tcg_gen_addi_ptr(mask, tcg_env, vreg_ofs(s, 0)); - fn(dest, mask, base, stride, cpu_env, desc); + fn(dest, mask, base, stride, tcg_env, desc); if (!is_store) { mark_vs_dirty(s); @@ -900,11 +900,11 @@ static bool ldst_index_trans(uint32_t vd, uint32_t rs1, uint32_t vs2, desc = tcg_constant_i32(simd_desc(s->cfg_ptr->vlen / 8, s->cfg_ptr->vlen / 8, data)); - tcg_gen_addi_ptr(dest, cpu_env, vreg_ofs(s, vd)); - tcg_gen_addi_ptr(index, cpu_env, vreg_ofs(s, vs2)); - tcg_gen_addi_ptr(mask, cpu_env, vreg_ofs(s, 0)); + tcg_gen_addi_ptr(dest, tcg_env, vreg_ofs(s, vd)); + tcg_gen_addi_ptr(index, tcg_env, vreg_ofs(s, vs2)); + tcg_gen_addi_ptr(mask, tcg_env, vreg_ofs(s, 0)); - fn(dest, mask, base, index, cpu_env, desc); + fn(dest, mask, base, index, tcg_env, desc); if (!is_store) { mark_vs_dirty(s); @@ -1039,10 +1039,10 @@ static bool ldff_trans(uint32_t vd, uint32_t rs1, uint32_t data, desc = tcg_constant_i32(simd_desc(s->cfg_ptr->vlen / 8, s->cfg_ptr->vlen / 8, data)); - tcg_gen_addi_ptr(dest, cpu_env, vreg_ofs(s, vd)); - tcg_gen_addi_ptr(mask, cpu_env, vreg_ofs(s, 0)); + tcg_gen_addi_ptr(dest, tcg_env, vreg_ofs(s, vd)); + tcg_gen_addi_ptr(mask, tcg_env, vreg_ofs(s, 0)); - fn(dest, mask, base, cpu_env, desc); + fn(dest, mask, base, tcg_env, desc); mark_vs_dirty(s); gen_set_label(over); @@ -1100,9 +1100,9 @@ static bool ldst_whole_trans(uint32_t vd, uint32_t rs1, uint32_t nf, s->cfg_ptr->vlen / 8, data)); base = get_gpr(s, rs1, EXT_NONE); - tcg_gen_addi_ptr(dest, cpu_env, vreg_ofs(s, vd)); + tcg_gen_addi_ptr(dest, tcg_env, vreg_ofs(s, vd)); - fn(dest, base, cpu_env, desc); + fn(dest, base, tcg_env, desc); if (!is_store) { mark_vs_dirty(s); @@ -1199,7 +1199,7 @@ do_opivv_gvec(DisasContext *s, arg_rmrr *a, GVecGen3Fn *gvec_fn, data = FIELD_DP32(data, VDATA, VMA, s->vma); tcg_gen_gvec_4_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0), vreg_ofs(s, a->rs1), vreg_ofs(s, a->rs2), - cpu_env, s->cfg_ptr->vlen / 8, + tcg_env, s->cfg_ptr->vlen / 8, s->cfg_ptr->vlen / 8, data, fn); } mark_vs_dirty(s); @@ -1251,11 +1251,11 @@ static bool opivx_trans(uint32_t vd, uint32_t rs1, uint32_t vs2, uint32_t vm, desc = tcg_constant_i32(simd_desc(s->cfg_ptr->vlen / 8, s->cfg_ptr->vlen / 8, data)); - tcg_gen_addi_ptr(dest, cpu_env, vreg_ofs(s, vd)); - tcg_gen_addi_ptr(src2, cpu_env, vreg_ofs(s, vs2)); - tcg_gen_addi_ptr(mask, cpu_env, vreg_ofs(s, 0)); + tcg_gen_addi_ptr(dest, tcg_env, vreg_ofs(s, vd)); + tcg_gen_addi_ptr(src2, tcg_env, vreg_ofs(s, vs2)); + tcg_gen_addi_ptr(mask, tcg_env, vreg_ofs(s, 0)); - fn(dest, mask, src1, src2, cpu_env, desc); + fn(dest, mask, src1, src2, tcg_env, desc); mark_vs_dirty(s); gen_set_label(over); @@ -1413,11 +1413,11 @@ static bool opivi_trans(uint32_t vd, uint32_t imm, uint32_t vs2, uint32_t vm, desc = tcg_constant_i32(simd_desc(s->cfg_ptr->vlen / 8, s->cfg_ptr->vlen / 8, data)); - tcg_gen_addi_ptr(dest, cpu_env, vreg_ofs(s, vd)); - tcg_gen_addi_ptr(src2, cpu_env, vreg_ofs(s, vs2)); - tcg_gen_addi_ptr(mask, cpu_env, vreg_ofs(s, 0)); + tcg_gen_addi_ptr(dest, tcg_env, vreg_ofs(s, vd)); + tcg_gen_addi_ptr(src2, tcg_env, vreg_ofs(s, vs2)); + tcg_gen_addi_ptr(mask, tcg_env, vreg_ofs(s, 0)); - fn(dest, mask, src1, src2, cpu_env, desc); + fn(dest, mask, src1, src2, tcg_env, desc); mark_vs_dirty(s); gen_set_label(over); @@ -1492,7 +1492,7 @@ static bool do_opivv_widen(DisasContext *s, arg_rmrr *a, tcg_gen_gvec_4_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0), vreg_ofs(s, a->rs1), vreg_ofs(s, a->rs2), - cpu_env, s->cfg_ptr->vlen / 8, + tcg_env, s->cfg_ptr->vlen / 8, s->cfg_ptr->vlen / 8, data, fn); mark_vs_dirty(s); @@ -1568,7 +1568,7 @@ static bool do_opiwv_widen(DisasContext *s, arg_rmrr *a, tcg_gen_gvec_4_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0), vreg_ofs(s, a->rs1), vreg_ofs(s, a->rs2), - cpu_env, s->cfg_ptr->vlen / 8, + tcg_env, s->cfg_ptr->vlen / 8, s->cfg_ptr->vlen / 8, data, fn); mark_vs_dirty(s); gen_set_label(over); @@ -1639,7 +1639,7 @@ static bool opivv_trans(uint32_t vd, uint32_t vs1, uint32_t vs2, uint32_t vm, data = FIELD_DP32(data, VDATA, VTA_ALL_1S, s->cfg_vta_all_1s); data = FIELD_DP32(data, VDATA, VMA, s->vma); tcg_gen_gvec_4_ptr(vreg_ofs(s, vd), vreg_ofs(s, 0), vreg_ofs(s, vs1), - vreg_ofs(s, vs2), cpu_env, s->cfg_ptr->vlen / 8, + vreg_ofs(s, vs2), tcg_env, s->cfg_ptr->vlen / 8, s->cfg_ptr->vlen / 8, data, fn); mark_vs_dirty(s); gen_set_label(over); @@ -1830,7 +1830,7 @@ static bool trans_##NAME(DisasContext *s, arg_rmrr *a) \ data = FIELD_DP32(data, VDATA, VMA, s->vma); \ tcg_gen_gvec_4_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0), \ vreg_ofs(s, a->rs1), \ - vreg_ofs(s, a->rs2), cpu_env, \ + vreg_ofs(s, a->rs2), tcg_env, \ s->cfg_ptr->vlen / 8, \ s->cfg_ptr->vlen / 8, data, \ fns[s->sew]); \ @@ -2036,7 +2036,7 @@ static bool trans_vmv_v_v(DisasContext *s, arg_vmv_v_v *a) tcg_gen_brcond_tl(TCG_COND_GEU, cpu_vstart, cpu_vl, over); tcg_gen_gvec_2_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, a->rs1), - cpu_env, s->cfg_ptr->vlen / 8, + tcg_env, s->cfg_ptr->vlen / 8, s->cfg_ptr->vlen / 8, data, fns[s->sew]); gen_set_label(over); @@ -2084,8 +2084,8 @@ static bool trans_vmv_v_x(DisasContext *s, arg_vmv_v_x *a) tcg_gen_ext_tl_i64(s1_i64, s1); desc = tcg_constant_i32(simd_desc(s->cfg_ptr->vlen / 8, s->cfg_ptr->vlen / 8, data)); - tcg_gen_addi_ptr(dest, cpu_env, vreg_ofs(s, a->rd)); - fns[s->sew](dest, s1_i64, cpu_env, desc); + tcg_gen_addi_ptr(dest, tcg_env, vreg_ofs(s, a->rd)); + fns[s->sew](dest, s1_i64, tcg_env, desc); } mark_vs_dirty(s); @@ -2123,8 +2123,8 @@ static bool trans_vmv_v_i(DisasContext *s, arg_vmv_v_i *a) dest = tcg_temp_new_ptr(); desc = tcg_constant_i32(simd_desc(s->cfg_ptr->vlen / 8, s->cfg_ptr->vlen / 8, data)); - tcg_gen_addi_ptr(dest, cpu_env, vreg_ofs(s, a->rd)); - fns[s->sew](dest, s1, cpu_env, desc); + tcg_gen_addi_ptr(dest, tcg_env, vreg_ofs(s, a->rd)); + fns[s->sew](dest, s1, tcg_env, desc); mark_vs_dirty(s); gen_set_label(over); @@ -2274,7 +2274,7 @@ static bool trans_##NAME(DisasContext *s, arg_rmrr *a) \ data = FIELD_DP32(data, VDATA, VMA, s->vma); \ tcg_gen_gvec_4_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0), \ vreg_ofs(s, a->rs1), \ - vreg_ofs(s, a->rs2), cpu_env, \ + vreg_ofs(s, a->rs2), tcg_env, \ s->cfg_ptr->vlen / 8, \ s->cfg_ptr->vlen / 8, data, \ fns[s->sew - 1]); \ @@ -2306,15 +2306,15 @@ static bool opfvf_trans(uint32_t vd, uint32_t rs1, uint32_t vs2, desc = tcg_constant_i32(simd_desc(s->cfg_ptr->vlen / 8, s->cfg_ptr->vlen / 8, data)); - tcg_gen_addi_ptr(dest, cpu_env, vreg_ofs(s, vd)); - tcg_gen_addi_ptr(src2, cpu_env, vreg_ofs(s, vs2)); - tcg_gen_addi_ptr(mask, cpu_env, vreg_ofs(s, 0)); + tcg_gen_addi_ptr(dest, tcg_env, vreg_ofs(s, vd)); + tcg_gen_addi_ptr(src2, tcg_env, vreg_ofs(s, vs2)); + tcg_gen_addi_ptr(mask, tcg_env, vreg_ofs(s, 0)); /* NaN-box f[rs1] */ t1 = tcg_temp_new_i64(); do_nanbox(s, t1, cpu_fpr[rs1]); - fn(dest, mask, t1, src2, cpu_env, desc); + fn(dest, mask, t1, src2, tcg_env, desc); mark_vs_dirty(s); gen_set_label(over); @@ -2390,7 +2390,7 @@ static bool trans_##NAME(DisasContext *s, arg_rmrr *a) \ data = FIELD_DP32(data, VDATA, VMA, s->vma); \ tcg_gen_gvec_4_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0), \ vreg_ofs(s, a->rs1), \ - vreg_ofs(s, a->rs2), cpu_env, \ + vreg_ofs(s, a->rs2), tcg_env, \ s->cfg_ptr->vlen / 8, \ s->cfg_ptr->vlen / 8, data, \ fns[s->sew - 1]); \ @@ -2464,7 +2464,7 @@ static bool trans_##NAME(DisasContext *s, arg_rmrr *a) \ data = FIELD_DP32(data, VDATA, VMA, s->vma); \ tcg_gen_gvec_4_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0), \ vreg_ofs(s, a->rs1), \ - vreg_ofs(s, a->rs2), cpu_env, \ + vreg_ofs(s, a->rs2), tcg_env, \ s->cfg_ptr->vlen / 8, \ s->cfg_ptr->vlen / 8, data, \ fns[s->sew - 1]); \ @@ -2580,7 +2580,7 @@ static bool do_opfv(DisasContext *s, arg_rmr *a, data = FIELD_DP32(data, VDATA, VTA, s->vta); data = FIELD_DP32(data, VDATA, VMA, s->vma); tcg_gen_gvec_3_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0), - vreg_ofs(s, a->rs2), cpu_env, + vreg_ofs(s, a->rs2), tcg_env, s->cfg_ptr->vlen / 8, s->cfg_ptr->vlen / 8, data, fn); mark_vs_dirty(s); @@ -2693,9 +2693,9 @@ static bool trans_vfmv_v_f(DisasContext *s, arg_vfmv_v_f *a) dest = tcg_temp_new_ptr(); desc = tcg_constant_i32(simd_desc(s->cfg_ptr->vlen / 8, s->cfg_ptr->vlen / 8, data)); - tcg_gen_addi_ptr(dest, cpu_env, vreg_ofs(s, a->rd)); + tcg_gen_addi_ptr(dest, tcg_env, vreg_ofs(s, a->rd)); - fns[s->sew - 1](dest, t1, cpu_env, desc); + fns[s->sew - 1](dest, t1, tcg_env, desc); mark_vs_dirty(s); gen_set_label(over); @@ -2769,7 +2769,7 @@ static bool trans_##NAME(DisasContext *s, arg_rmr *a) \ data = FIELD_DP32(data, VDATA, VTA, s->vta); \ data = FIELD_DP32(data, VDATA, VMA, s->vma); \ tcg_gen_gvec_3_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0), \ - vreg_ofs(s, a->rs2), cpu_env, \ + vreg_ofs(s, a->rs2), tcg_env, \ s->cfg_ptr->vlen / 8, \ s->cfg_ptr->vlen / 8, data, \ fns[s->sew - 1]); \ @@ -2820,7 +2820,7 @@ static bool trans_##NAME(DisasContext *s, arg_rmr *a) \ data = FIELD_DP32(data, VDATA, VTA, s->vta); \ data = FIELD_DP32(data, VDATA, VMA, s->vma); \ tcg_gen_gvec_3_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0), \ - vreg_ofs(s, a->rs2), cpu_env, \ + vreg_ofs(s, a->rs2), tcg_env, \ s->cfg_ptr->vlen / 8, \ s->cfg_ptr->vlen / 8, data, \ fns[s->sew]); \ @@ -2887,7 +2887,7 @@ static bool trans_##NAME(DisasContext *s, arg_rmr *a) \ data = FIELD_DP32(data, VDATA, VTA, s->vta); \ data = FIELD_DP32(data, VDATA, VMA, s->vma); \ tcg_gen_gvec_3_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0), \ - vreg_ofs(s, a->rs2), cpu_env, \ + vreg_ofs(s, a->rs2), tcg_env, \ s->cfg_ptr->vlen / 8, \ s->cfg_ptr->vlen / 8, data, \ fns[s->sew - 1]); \ @@ -2936,7 +2936,7 @@ static bool trans_##NAME(DisasContext *s, arg_rmr *a) \ data = FIELD_DP32(data, VDATA, VTA, s->vta); \ data = FIELD_DP32(data, VDATA, VMA, s->vma); \ tcg_gen_gvec_3_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0), \ - vreg_ofs(s, a->rs2), cpu_env, \ + vreg_ofs(s, a->rs2), tcg_env, \ s->cfg_ptr->vlen / 8, \ s->cfg_ptr->vlen / 8, data, \ fns[s->sew]); \ @@ -3026,7 +3026,7 @@ static bool trans_##NAME(DisasContext *s, arg_r *a) \ FIELD_DP32(data, VDATA, VTA_ALL_1S, s->cfg_vta_all_1s);\ tcg_gen_gvec_4_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0), \ vreg_ofs(s, a->rs1), \ - vreg_ofs(s, a->rs2), cpu_env, \ + vreg_ofs(s, a->rs2), tcg_env, \ s->cfg_ptr->vlen / 8, \ s->cfg_ptr->vlen / 8, data, fn); \ mark_vs_dirty(s); \ @@ -3064,10 +3064,10 @@ static bool trans_vcpop_m(DisasContext *s, arg_rmr *a) desc = tcg_constant_i32(simd_desc(s->cfg_ptr->vlen / 8, s->cfg_ptr->vlen / 8, data)); - tcg_gen_addi_ptr(src2, cpu_env, vreg_ofs(s, a->rs2)); - tcg_gen_addi_ptr(mask, cpu_env, vreg_ofs(s, 0)); + tcg_gen_addi_ptr(src2, tcg_env, vreg_ofs(s, a->rs2)); + tcg_gen_addi_ptr(mask, tcg_env, vreg_ofs(s, 0)); - gen_helper_vcpop_m(dst, mask, src2, cpu_env, desc); + gen_helper_vcpop_m(dst, mask, src2, tcg_env, desc); gen_set_gpr(s, a->rd, dst); return true; } @@ -3093,10 +3093,10 @@ static bool trans_vfirst_m(DisasContext *s, arg_rmr *a) desc = tcg_constant_i32(simd_desc(s->cfg_ptr->vlen / 8, s->cfg_ptr->vlen / 8, data)); - tcg_gen_addi_ptr(src2, cpu_env, vreg_ofs(s, a->rs2)); - tcg_gen_addi_ptr(mask, cpu_env, vreg_ofs(s, 0)); + tcg_gen_addi_ptr(src2, tcg_env, vreg_ofs(s, a->rs2)); + tcg_gen_addi_ptr(mask, tcg_env, vreg_ofs(s, 0)); - gen_helper_vfirst_m(dst, mask, src2, cpu_env, desc); + gen_helper_vfirst_m(dst, mask, src2, tcg_env, desc); gen_set_gpr(s, a->rd, dst); return true; } @@ -3128,7 +3128,7 @@ static bool trans_##NAME(DisasContext *s, arg_rmr *a) \ data = FIELD_DP32(data, VDATA, VMA, s->vma); \ tcg_gen_gvec_3_ptr(vreg_ofs(s, a->rd), \ vreg_ofs(s, 0), vreg_ofs(s, a->rs2), \ - cpu_env, s->cfg_ptr->vlen / 8, \ + tcg_env, s->cfg_ptr->vlen / 8, \ s->cfg_ptr->vlen / 8, \ data, fn); \ mark_vs_dirty(s); \ @@ -3170,7 +3170,7 @@ static bool trans_viota_m(DisasContext *s, arg_viota_m *a) gen_helper_viota_m_w, gen_helper_viota_m_d, }; tcg_gen_gvec_3_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0), - vreg_ofs(s, a->rs2), cpu_env, + vreg_ofs(s, a->rs2), tcg_env, s->cfg_ptr->vlen / 8, s->cfg_ptr->vlen / 8, data, fns[s->sew]); mark_vs_dirty(s); @@ -3200,7 +3200,7 @@ static bool trans_vid_v(DisasContext *s, arg_vid_v *a) gen_helper_vid_v_w, gen_helper_vid_v_d, }; tcg_gen_gvec_2_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0), - cpu_env, s->cfg_ptr->vlen / 8, + tcg_env, s->cfg_ptr->vlen / 8, s->cfg_ptr->vlen / 8, data, fns[s->sew]); mark_vs_dirty(s); @@ -3288,7 +3288,7 @@ static void vec_element_loadx(DisasContext *s, TCGv_i64 dest, /* Convert the index to a pointer. */ tcg_gen_ext_i32_ptr(base, ofs); - tcg_gen_add_ptr(base, base, cpu_env); + tcg_gen_add_ptr(base, base, tcg_env); /* Perform the load. */ load_element(dest, base, @@ -3306,7 +3306,7 @@ static void vec_element_loadx(DisasContext *s, TCGv_i64 dest, static void vec_element_loadi(DisasContext *s, TCGv_i64 dest, int vreg, int idx, bool sign) { - load_element(dest, cpu_env, endian_ofs(s, vreg, idx), s->sew, sign); + load_element(dest, tcg_env, endian_ofs(s, vreg, idx), s->sew, sign); } /* Integer Scalar Move Instruction */ @@ -3340,7 +3340,7 @@ static void store_element(TCGv_i64 val, TCGv_ptr base, static void vec_element_storei(DisasContext *s, int vreg, int idx, TCGv_i64 val) { - store_element(val, cpu_env, endian_ofs(s, vreg, idx), s->sew); + store_element(val, tcg_env, endian_ofs(s, vreg, idx), s->sew); } /* vmv.x.s rd, vs2 # x[rd] = vs2[0] */ @@ -3620,7 +3620,7 @@ static bool trans_vcompress_vm(DisasContext *s, arg_r *a) data = FIELD_DP32(data, VDATA, VTA, s->vta); tcg_gen_gvec_4_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0), vreg_ofs(s, a->rs1), vreg_ofs(s, a->rs2), - cpu_env, s->cfg_ptr->vlen / 8, + tcg_env, s->cfg_ptr->vlen / 8, s->cfg_ptr->vlen / 8, data, fns[s->sew]); mark_vs_dirty(s); @@ -3650,7 +3650,7 @@ static bool trans_##NAME(DisasContext *s, arg_##NAME * a) \ TCGLabel *over = gen_new_label(); \ tcg_gen_brcondi_tl(TCG_COND_GEU, cpu_vstart, maxsz, over); \ tcg_gen_gvec_2_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, a->rs2), \ - cpu_env, maxsz, maxsz, 0, gen_helper_vmvr_v); \ + tcg_env, maxsz, maxsz, 0, gen_helper_vmvr_v); \ mark_vs_dirty(s); \ gen_set_label(over); \ } \ @@ -3722,7 +3722,7 @@ static bool int_ext_op(DisasContext *s, arg_rmr *a, uint8_t seq) data = FIELD_DP32(data, VDATA, VMA, s->vma); tcg_gen_gvec_3_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0), - vreg_ofs(s, a->rs2), cpu_env, + vreg_ofs(s, a->rs2), tcg_env, s->cfg_ptr->vlen / 8, s->cfg_ptr->vlen / 8, data, fn); diff --git a/target/riscv/insn_trans/trans_rvvk.c.inc b/target/riscv/insn_trans/trans_rvvk.c.inc index c00c70dfc6..e691519ed7 100644 --- a/target/riscv/insn_trans/trans_rvvk.c.inc +++ b/target/riscv/insn_trans/trans_rvvk.c.inc @@ -170,7 +170,7 @@ GEN_OPIVX_GVEC_TRANS_CHECK(vandn_vx, andcs, zvbb_vx_check) data = FIELD_DP32(data, VDATA, VTA_ALL_1S, s->cfg_vta_all_1s); \ data = FIELD_DP32(data, VDATA, VMA, s->vma); \ tcg_gen_gvec_3_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0), \ - vreg_ofs(s, a->rs2), cpu_env, \ + vreg_ofs(s, a->rs2), tcg_env, \ s->cfg_ptr->vlen / 8, s->cfg_ptr->vlen / 8, \ data, fns[s->sew]); \ mark_vs_dirty(s); \ @@ -244,7 +244,7 @@ GEN_OPIVI_WIDEN_TRANS(vwsll_vi, IMM_ZX, vwsll_vx, vwsll_vx_check) /* save opcode for unwinding in case we throw an exception */ \ decode_save_opc(s); \ egs = tcg_constant_i32(EGS); \ - gen_helper_egs_check(egs, cpu_env); \ + gen_helper_egs_check(egs, tcg_env); \ tcg_gen_brcond_tl(TCG_COND_GEU, cpu_vstart, cpu_vl, over); \ } \ \ @@ -257,9 +257,9 @@ GEN_OPIVI_WIDEN_TRANS(vwsll_vi, IMM_ZX, vwsll_vx, vwsll_vx_check) rs2_v = tcg_temp_new_ptr(); \ desc = tcg_constant_i32( \ simd_desc(s->cfg_ptr->vlen / 8, s->cfg_ptr->vlen / 8, data)); \ - tcg_gen_addi_ptr(rd_v, cpu_env, vreg_ofs(s, a->rd)); \ - tcg_gen_addi_ptr(rs2_v, cpu_env, vreg_ofs(s, a->rs2)); \ - gen_helper_##NAME(rd_v, rs2_v, cpu_env, desc); \ + tcg_gen_addi_ptr(rd_v, tcg_env, vreg_ofs(s, a->rd)); \ + tcg_gen_addi_ptr(rs2_v, tcg_env, vreg_ofs(s, a->rs2)); \ + gen_helper_##NAME(rd_v, rs2_v, tcg_env, desc); \ mark_vs_dirty(s); \ gen_set_label(over); \ return true; \ @@ -320,7 +320,7 @@ GEN_V_UNMASKED_TRANS(vaesem_vs, vaes_check_vs, ZVKNED_EGS) /* save opcode for unwinding in case we throw an exception */ \ decode_save_opc(s); \ egs = tcg_constant_i32(EGS); \ - gen_helper_egs_check(egs, cpu_env); \ + gen_helper_egs_check(egs, tcg_env); \ tcg_gen_brcond_tl(TCG_COND_GEU, cpu_vstart, cpu_vl, over); \ } \ \ @@ -335,9 +335,9 @@ GEN_V_UNMASKED_TRANS(vaesem_vs, vaes_check_vs, ZVKNED_EGS) uimm_v = tcg_constant_i32(a->rs1); \ desc = tcg_constant_i32( \ simd_desc(s->cfg_ptr->vlen / 8, s->cfg_ptr->vlen / 8, data)); \ - tcg_gen_addi_ptr(rd_v, cpu_env, vreg_ofs(s, a->rd)); \ - tcg_gen_addi_ptr(rs2_v, cpu_env, vreg_ofs(s, a->rs2)); \ - gen_helper_##NAME(rd_v, rs2_v, uimm_v, cpu_env, desc); \ + tcg_gen_addi_ptr(rd_v, tcg_env, vreg_ofs(s, a->rd)); \ + tcg_gen_addi_ptr(rs2_v, tcg_env, vreg_ofs(s, a->rs2)); \ + gen_helper_##NAME(rd_v, rs2_v, uimm_v, tcg_env, desc); \ mark_vs_dirty(s); \ gen_set_label(over); \ return true; \ @@ -390,7 +390,7 @@ GEN_VI_UNMASKED_TRANS(vaeskf2_vi, vaeskf2_check, ZVKNED_EGS) /* save opcode for unwinding in case we throw an exception */ \ decode_save_opc(s); \ egs = tcg_constant_i32(EGS); \ - gen_helper_egs_check(egs, cpu_env); \ + gen_helper_egs_check(egs, tcg_env); \ tcg_gen_brcond_tl(TCG_COND_GEU, cpu_vstart, cpu_vl, over); \ } \ \ @@ -401,7 +401,7 @@ GEN_VI_UNMASKED_TRANS(vaeskf2_vi, vaeskf2_check, ZVKNED_EGS) data = FIELD_DP32(data, VDATA, VMA, s->vma); \ \ tcg_gen_gvec_3_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, a->rs1), \ - vreg_ofs(s, a->rs2), cpu_env, \ + vreg_ofs(s, a->rs2), tcg_env, \ s->cfg_ptr->vlen / 8, s->cfg_ptr->vlen / 8, \ data, gen_helper_##NAME); \ \ @@ -444,7 +444,7 @@ static bool trans_vsha2cl_vv(DisasContext *s, arg_rmrr *a) /* save opcode for unwinding in case we throw an exception */ decode_save_opc(s); egs = tcg_constant_i32(ZVKNH_EGS); - gen_helper_egs_check(egs, cpu_env); + gen_helper_egs_check(egs, tcg_env); tcg_gen_brcond_tl(TCG_COND_GEU, cpu_vstart, cpu_vl, over); } @@ -455,7 +455,7 @@ static bool trans_vsha2cl_vv(DisasContext *s, arg_rmrr *a) data = FIELD_DP32(data, VDATA, VMA, s->vma); tcg_gen_gvec_3_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, a->rs1), - vreg_ofs(s, a->rs2), cpu_env, s->cfg_ptr->vlen / 8, + vreg_ofs(s, a->rs2), tcg_env, s->cfg_ptr->vlen / 8, s->cfg_ptr->vlen / 8, data, s->sew == MO_32 ? gen_helper_vsha2cl32_vv : gen_helper_vsha2cl64_vv); @@ -478,7 +478,7 @@ static bool trans_vsha2ch_vv(DisasContext *s, arg_rmrr *a) /* save opcode for unwinding in case we throw an exception */ decode_save_opc(s); egs = tcg_constant_i32(ZVKNH_EGS); - gen_helper_egs_check(egs, cpu_env); + gen_helper_egs_check(egs, tcg_env); tcg_gen_brcond_tl(TCG_COND_GEU, cpu_vstart, cpu_vl, over); } @@ -489,7 +489,7 @@ static bool trans_vsha2ch_vv(DisasContext *s, arg_rmrr *a) data = FIELD_DP32(data, VDATA, VMA, s->vma); tcg_gen_gvec_3_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, a->rs1), - vreg_ofs(s, a->rs2), cpu_env, s->cfg_ptr->vlen / 8, + vreg_ofs(s, a->rs2), tcg_env, s->cfg_ptr->vlen / 8, s->cfg_ptr->vlen / 8, data, s->sew == MO_32 ? gen_helper_vsha2ch32_vv : gen_helper_vsha2ch64_vv); diff --git a/target/riscv/insn_trans/trans_rvzce.c.inc b/target/riscv/insn_trans/trans_rvzce.c.inc index 8d8a64f493..2d992e14c4 100644 --- a/target/riscv/insn_trans/trans_rvzce.c.inc +++ b/target/riscv/insn_trans/trans_rvzce.c.inc @@ -298,7 +298,7 @@ static bool trans_cm_jalt(DisasContext *ctx, arg_cm_jalt *a) * that might come from cpu_ld*_code() in the helper. */ gen_update_pc(ctx, 0); - gen_helper_cm_jalt(cpu_pc, cpu_env, tcg_constant_i32(a->index)); + gen_helper_cm_jalt(cpu_pc, tcg_env, tcg_constant_i32(a->index)); /* c.jt vs c.jalt depends on the index. */ if (a->index >= 32) { diff --git a/target/riscv/insn_trans/trans_rvzfa.c.inc b/target/riscv/insn_trans/trans_rvzfa.c.inc index 0fdd2698f6..fd7e2daebf 100644 --- a/target/riscv/insn_trans/trans_rvzfa.c.inc +++ b/target/riscv/insn_trans/trans_rvzfa.c.inc @@ -187,7 +187,7 @@ static bool trans_fminm_s(DisasContext *ctx, arg_fminm_s *a) TCGv_i64 src1 = get_fpr_hs(ctx, a->rs1); TCGv_i64 src2 = get_fpr_hs(ctx, a->rs2); - gen_helper_fminm_s(dest, cpu_env, src1, src2); + gen_helper_fminm_s(dest, tcg_env, src1, src2); gen_set_fpr_hs(ctx, a->rd, dest); mark_fs_dirty(ctx); @@ -204,7 +204,7 @@ static bool trans_fmaxm_s(DisasContext *ctx, arg_fmaxm_s *a) TCGv_i64 src1 = get_fpr_hs(ctx, a->rs1); TCGv_i64 src2 = get_fpr_hs(ctx, a->rs2); - gen_helper_fmaxm_s(dest, cpu_env, src1, src2); + gen_helper_fmaxm_s(dest, tcg_env, src1, src2); gen_set_fpr_hs(ctx, a->rd, dest); mark_fs_dirty(ctx); @@ -221,7 +221,7 @@ static bool trans_fminm_d(DisasContext *ctx, arg_fminm_d *a) TCGv_i64 src1 = get_fpr_d(ctx, a->rs1); TCGv_i64 src2 = get_fpr_d(ctx, a->rs2); - gen_helper_fminm_d(dest, cpu_env, src1, src2); + gen_helper_fminm_d(dest, tcg_env, src1, src2); gen_set_fpr_d(ctx, a->rd, dest); mark_fs_dirty(ctx); @@ -238,7 +238,7 @@ static bool trans_fmaxm_d(DisasContext *ctx, arg_fmaxm_d *a) TCGv_i64 src1 = get_fpr_d(ctx, a->rs1); TCGv_i64 src2 = get_fpr_d(ctx, a->rs2); - gen_helper_fmaxm_d(dest, cpu_env, src1, src2); + gen_helper_fmaxm_d(dest, tcg_env, src1, src2); gen_set_fpr_d(ctx, a->rd, dest); mark_fs_dirty(ctx); @@ -255,7 +255,7 @@ static bool trans_fminm_h(DisasContext *ctx, arg_fminm_h *a) TCGv_i64 src1 = get_fpr_hs(ctx, a->rs1); TCGv_i64 src2 = get_fpr_hs(ctx, a->rs2); - gen_helper_fminm_h(dest, cpu_env, src1, src2); + gen_helper_fminm_h(dest, tcg_env, src1, src2); gen_set_fpr_hs(ctx, a->rd, dest); mark_fs_dirty(ctx); @@ -272,7 +272,7 @@ static bool trans_fmaxm_h(DisasContext *ctx, arg_fmaxm_h *a) TCGv_i64 src1 = get_fpr_hs(ctx, a->rs1); TCGv_i64 src2 = get_fpr_hs(ctx, a->rs2); - gen_helper_fmaxm_h(dest, cpu_env, src1, src2); + gen_helper_fmaxm_h(dest, tcg_env, src1, src2); gen_set_fpr_hs(ctx, a->rd, dest); mark_fs_dirty(ctx); @@ -289,7 +289,7 @@ static bool trans_fround_s(DisasContext *ctx, arg_fround_s *a) TCGv_i64 src1 = get_fpr_hs(ctx, a->rs1); gen_set_rm(ctx, a->rm); - gen_helper_fround_s(dest, cpu_env, src1); + gen_helper_fround_s(dest, tcg_env, src1); gen_set_fpr_hs(ctx, a->rd, dest); mark_fs_dirty(ctx); @@ -306,7 +306,7 @@ static bool trans_froundnx_s(DisasContext *ctx, arg_froundnx_s *a) TCGv_i64 src1 = get_fpr_hs(ctx, a->rs1); gen_set_rm(ctx, a->rm); - gen_helper_froundnx_s(dest, cpu_env, src1); + gen_helper_froundnx_s(dest, tcg_env, src1); gen_set_fpr_hs(ctx, a->rd, dest); mark_fs_dirty(ctx); @@ -323,7 +323,7 @@ static bool trans_fround_d(DisasContext *ctx, arg_fround_d *a) TCGv_i64 src1 = get_fpr_d(ctx, a->rs1); gen_set_rm(ctx, a->rm); - gen_helper_fround_d(dest, cpu_env, src1); + gen_helper_fround_d(dest, tcg_env, src1); gen_set_fpr_hs(ctx, a->rd, dest); mark_fs_dirty(ctx); @@ -340,7 +340,7 @@ static bool trans_froundnx_d(DisasContext *ctx, arg_froundnx_d *a) TCGv_i64 src1 = get_fpr_d(ctx, a->rs1); gen_set_rm(ctx, a->rm); - gen_helper_froundnx_d(dest, cpu_env, src1); + gen_helper_froundnx_d(dest, tcg_env, src1); gen_set_fpr_hs(ctx, a->rd, dest); mark_fs_dirty(ctx); @@ -357,7 +357,7 @@ static bool trans_fround_h(DisasContext *ctx, arg_fround_h *a) TCGv_i64 src1 = get_fpr_hs(ctx, a->rs1); gen_set_rm(ctx, a->rm); - gen_helper_fround_h(dest, cpu_env, src1); + gen_helper_fround_h(dest, tcg_env, src1); gen_set_fpr_hs(ctx, a->rd, dest); mark_fs_dirty(ctx); @@ -374,7 +374,7 @@ static bool trans_froundnx_h(DisasContext *ctx, arg_froundnx_h *a) TCGv_i64 src1 = get_fpr_hs(ctx, a->rs1); gen_set_rm(ctx, a->rm); - gen_helper_froundnx_h(dest, cpu_env, src1); + gen_helper_froundnx_h(dest, tcg_env, src1); gen_set_fpr_hs(ctx, a->rd, dest); mark_fs_dirty(ctx); @@ -393,7 +393,7 @@ bool trans_fcvtmod_w_d(DisasContext *ctx, arg_fcvtmod_w_d *a) /* Rounding mode is RTZ. */ gen_set_rm(ctx, RISCV_FRM_RTZ); - gen_helper_fcvtmod_w_d(t1, cpu_env, src1); + gen_helper_fcvtmod_w_d(t1, tcg_env, src1); tcg_gen_trunc_i64_tl(dst, t1); gen_set_gpr(ctx, a->rd, dst); @@ -440,7 +440,7 @@ bool trans_fleq_s(DisasContext *ctx, arg_fleq_s *a) TCGv_i64 src1 = get_fpr_hs(ctx, a->rs1); TCGv_i64 src2 = get_fpr_hs(ctx, a->rs2); - gen_helper_fleq_s(dest, cpu_env, src1, src2); + gen_helper_fleq_s(dest, tcg_env, src1, src2); gen_set_gpr(ctx, a->rd, dest); return true; } @@ -455,7 +455,7 @@ bool trans_fltq_s(DisasContext *ctx, arg_fltq_s *a) TCGv_i64 src1 = get_fpr_hs(ctx, a->rs1); TCGv_i64 src2 = get_fpr_hs(ctx, a->rs2); - gen_helper_fltq_s(dest, cpu_env, src1, src2); + gen_helper_fltq_s(dest, tcg_env, src1, src2); gen_set_gpr(ctx, a->rd, dest); return true; } @@ -470,7 +470,7 @@ bool trans_fleq_d(DisasContext *ctx, arg_fleq_d *a) TCGv_i64 src1 = get_fpr_hs(ctx, a->rs1); TCGv_i64 src2 = get_fpr_hs(ctx, a->rs2); - gen_helper_fleq_d(dest, cpu_env, src1, src2); + gen_helper_fleq_d(dest, tcg_env, src1, src2); gen_set_gpr(ctx, a->rd, dest); return true; } @@ -485,7 +485,7 @@ bool trans_fltq_d(DisasContext *ctx, arg_fltq_d *a) TCGv_i64 src1 = get_fpr_hs(ctx, a->rs1); TCGv_i64 src2 = get_fpr_hs(ctx, a->rs2); - gen_helper_fltq_d(dest, cpu_env, src1, src2); + gen_helper_fltq_d(dest, tcg_env, src1, src2); gen_set_gpr(ctx, a->rd, dest); return true; } @@ -500,7 +500,7 @@ bool trans_fleq_h(DisasContext *ctx, arg_fleq_h *a) TCGv_i64 src1 = get_fpr_hs(ctx, a->rs1); TCGv_i64 src2 = get_fpr_hs(ctx, a->rs2); - gen_helper_fleq_h(dest, cpu_env, src1, src2); + gen_helper_fleq_h(dest, tcg_env, src1, src2); gen_set_gpr(ctx, a->rd, dest); return true; } @@ -515,7 +515,7 @@ bool trans_fltq_h(DisasContext *ctx, arg_fltq_h *a) TCGv_i64 src1 = get_fpr_hs(ctx, a->rs1); TCGv_i64 src2 = get_fpr_hs(ctx, a->rs2); - gen_helper_fltq_h(dest, cpu_env, src1, src2); + gen_helper_fltq_h(dest, tcg_env, src1, src2); gen_set_gpr(ctx, a->rd, dest); return true; } diff --git a/target/riscv/insn_trans/trans_rvzfh.c.inc b/target/riscv/insn_trans/trans_rvzfh.c.inc index 4b01812fd8..1eb458b491 100644 --- a/target/riscv/insn_trans/trans_rvzfh.c.inc +++ b/target/riscv/insn_trans/trans_rvzfh.c.inc @@ -95,7 +95,7 @@ static bool trans_fmadd_h(DisasContext *ctx, arg_fmadd_h *a) TCGv_i64 src3 = get_fpr_hs(ctx, a->rs3); gen_set_rm(ctx, a->rm); - gen_helper_fmadd_h(dest, cpu_env, src1, src2, src3); + gen_helper_fmadd_h(dest, tcg_env, src1, src2, src3); gen_set_fpr_hs(ctx, a->rd, dest); mark_fs_dirty(ctx); return true; @@ -112,7 +112,7 @@ static bool trans_fmsub_h(DisasContext *ctx, arg_fmsub_h *a) TCGv_i64 src3 = get_fpr_hs(ctx, a->rs3); gen_set_rm(ctx, a->rm); - gen_helper_fmsub_h(dest, cpu_env, src1, src2, src3); + gen_helper_fmsub_h(dest, tcg_env, src1, src2, src3); gen_set_fpr_hs(ctx, a->rd, dest); mark_fs_dirty(ctx); return true; @@ -129,7 +129,7 @@ static bool trans_fnmsub_h(DisasContext *ctx, arg_fnmsub_h *a) TCGv_i64 src3 = get_fpr_hs(ctx, a->rs3); gen_set_rm(ctx, a->rm); - gen_helper_fnmsub_h(dest, cpu_env, src1, src2, src3); + gen_helper_fnmsub_h(dest, tcg_env, src1, src2, src3); gen_set_fpr_hs(ctx, a->rd, dest); mark_fs_dirty(ctx); return true; @@ -146,7 +146,7 @@ static bool trans_fnmadd_h(DisasContext *ctx, arg_fnmadd_h *a) TCGv_i64 src3 = get_fpr_hs(ctx, a->rs3); gen_set_rm(ctx, a->rm); - gen_helper_fnmadd_h(dest, cpu_env, src1, src2, src3); + gen_helper_fnmadd_h(dest, tcg_env, src1, src2, src3); gen_set_fpr_hs(ctx, a->rd, dest); mark_fs_dirty(ctx); return true; @@ -162,7 +162,7 @@ static bool trans_fadd_h(DisasContext *ctx, arg_fadd_h *a) TCGv_i64 src2 = get_fpr_hs(ctx, a->rs2); gen_set_rm(ctx, a->rm); - gen_helper_fadd_h(dest, cpu_env, src1, src2); + gen_helper_fadd_h(dest, tcg_env, src1, src2); gen_set_fpr_hs(ctx, a->rd, dest); mark_fs_dirty(ctx); return true; @@ -178,7 +178,7 @@ static bool trans_fsub_h(DisasContext *ctx, arg_fsub_h *a) TCGv_i64 src2 = get_fpr_hs(ctx, a->rs2); gen_set_rm(ctx, a->rm); - gen_helper_fsub_h(dest, cpu_env, src1, src2); + gen_helper_fsub_h(dest, tcg_env, src1, src2); gen_set_fpr_hs(ctx, a->rd, dest); mark_fs_dirty(ctx); return true; @@ -194,7 +194,7 @@ static bool trans_fmul_h(DisasContext *ctx, arg_fmul_h *a) TCGv_i64 src2 = get_fpr_hs(ctx, a->rs2); gen_set_rm(ctx, a->rm); - gen_helper_fmul_h(dest, cpu_env, src1, src2); + gen_helper_fmul_h(dest, tcg_env, src1, src2); gen_set_fpr_hs(ctx, a->rd, dest); mark_fs_dirty(ctx); return true; @@ -210,7 +210,7 @@ static bool trans_fdiv_h(DisasContext *ctx, arg_fdiv_h *a) TCGv_i64 src2 = get_fpr_hs(ctx, a->rs2); gen_set_rm(ctx, a->rm); - gen_helper_fdiv_h(dest, cpu_env, src1, src2); + gen_helper_fdiv_h(dest, tcg_env, src1, src2); gen_set_fpr_hs(ctx, a->rd, dest); mark_fs_dirty(ctx); return true; @@ -225,7 +225,7 @@ static bool trans_fsqrt_h(DisasContext *ctx, arg_fsqrt_h *a) TCGv_i64 src1 = get_fpr_hs(ctx, a->rs1); gen_set_rm(ctx, a->rm); - gen_helper_fsqrt_h(dest, cpu_env, src1); + gen_helper_fsqrt_h(dest, tcg_env, src1); gen_set_fpr_hs(ctx, a->rd, dest); mark_fs_dirty(ctx); return true; @@ -366,7 +366,7 @@ static bool trans_fmin_h(DisasContext *ctx, arg_fmin_h *a) TCGv_i64 src1 = get_fpr_hs(ctx, a->rs1); TCGv_i64 src2 = get_fpr_hs(ctx, a->rs2); - gen_helper_fmin_h(dest, cpu_env, src1, src2); + gen_helper_fmin_h(dest, tcg_env, src1, src2); gen_set_fpr_hs(ctx, a->rd, dest); mark_fs_dirty(ctx); return true; @@ -381,7 +381,7 @@ static bool trans_fmax_h(DisasContext *ctx, arg_fmax_h *a) TCGv_i64 src1 = get_fpr_hs(ctx, a->rs1); TCGv_i64 src2 = get_fpr_hs(ctx, a->rs2); - gen_helper_fmax_h(dest, cpu_env, src1, src2); + gen_helper_fmax_h(dest, tcg_env, src1, src2); gen_set_fpr_hs(ctx, a->rd, dest); mark_fs_dirty(ctx); return true; @@ -396,7 +396,7 @@ static bool trans_fcvt_s_h(DisasContext *ctx, arg_fcvt_s_h *a) TCGv_i64 src1 = get_fpr_hs(ctx, a->rs1); gen_set_rm(ctx, a->rm); - gen_helper_fcvt_s_h(dest, cpu_env, src1); + gen_helper_fcvt_s_h(dest, tcg_env, src1); gen_set_fpr_hs(ctx, a->rd, dest); mark_fs_dirty(ctx); @@ -414,7 +414,7 @@ static bool trans_fcvt_d_h(DisasContext *ctx, arg_fcvt_d_h *a) TCGv_i64 src1 = get_fpr_hs(ctx, a->rs1); gen_set_rm(ctx, a->rm); - gen_helper_fcvt_d_h(dest, cpu_env, src1); + gen_helper_fcvt_d_h(dest, tcg_env, src1); gen_set_fpr_d(ctx, a->rd, dest); mark_fs_dirty(ctx); @@ -431,7 +431,7 @@ static bool trans_fcvt_h_s(DisasContext *ctx, arg_fcvt_h_s *a) TCGv_i64 src1 = get_fpr_hs(ctx, a->rs1); gen_set_rm(ctx, a->rm); - gen_helper_fcvt_h_s(dest, cpu_env, src1); + gen_helper_fcvt_h_s(dest, tcg_env, src1); gen_set_fpr_hs(ctx, a->rd, dest); mark_fs_dirty(ctx); @@ -448,7 +448,7 @@ static bool trans_fcvt_h_d(DisasContext *ctx, arg_fcvt_h_d *a) TCGv_i64 src1 = get_fpr_d(ctx, a->rs1); gen_set_rm(ctx, a->rm); - gen_helper_fcvt_h_d(dest, cpu_env, src1); + gen_helper_fcvt_h_d(dest, tcg_env, src1); gen_set_fpr_hs(ctx, a->rd, dest); mark_fs_dirty(ctx); @@ -464,7 +464,7 @@ static bool trans_feq_h(DisasContext *ctx, arg_feq_h *a) TCGv_i64 src1 = get_fpr_hs(ctx, a->rs1); TCGv_i64 src2 = get_fpr_hs(ctx, a->rs2); - gen_helper_feq_h(dest, cpu_env, src1, src2); + gen_helper_feq_h(dest, tcg_env, src1, src2); gen_set_gpr(ctx, a->rd, dest); return true; } @@ -478,7 +478,7 @@ static bool trans_flt_h(DisasContext *ctx, arg_flt_h *a) TCGv_i64 src1 = get_fpr_hs(ctx, a->rs1); TCGv_i64 src2 = get_fpr_hs(ctx, a->rs2); - gen_helper_flt_h(dest, cpu_env, src1, src2); + gen_helper_flt_h(dest, tcg_env, src1, src2); gen_set_gpr(ctx, a->rd, dest); return true; @@ -493,7 +493,7 @@ static bool trans_fle_h(DisasContext *ctx, arg_fle_h *a) TCGv_i64 src1 = get_fpr_hs(ctx, a->rs1); TCGv_i64 src2 = get_fpr_hs(ctx, a->rs2); - gen_helper_fle_h(dest, cpu_env, src1, src2); + gen_helper_fle_h(dest, tcg_env, src1, src2); gen_set_gpr(ctx, a->rd, dest); return true; } @@ -506,7 +506,7 @@ static bool trans_fclass_h(DisasContext *ctx, arg_fclass_h *a) TCGv dest = dest_gpr(ctx, a->rd); TCGv_i64 src1 = get_fpr_hs(ctx, a->rs1); - gen_helper_fclass_h(dest, cpu_env, src1); + gen_helper_fclass_h(dest, tcg_env, src1); gen_set_gpr(ctx, a->rd, dest); return true; } @@ -520,7 +520,7 @@ static bool trans_fcvt_w_h(DisasContext *ctx, arg_fcvt_w_h *a) TCGv_i64 src1 = get_fpr_hs(ctx, a->rs1); gen_set_rm(ctx, a->rm); - gen_helper_fcvt_w_h(dest, cpu_env, src1); + gen_helper_fcvt_w_h(dest, tcg_env, src1); gen_set_gpr(ctx, a->rd, dest); return true; } @@ -534,7 +534,7 @@ static bool trans_fcvt_wu_h(DisasContext *ctx, arg_fcvt_wu_h *a) TCGv_i64 src1 = get_fpr_hs(ctx, a->rs1); gen_set_rm(ctx, a->rm); - gen_helper_fcvt_wu_h(dest, cpu_env, src1); + gen_helper_fcvt_wu_h(dest, tcg_env, src1); gen_set_gpr(ctx, a->rd, dest); return true; } @@ -548,7 +548,7 @@ static bool trans_fcvt_h_w(DisasContext *ctx, arg_fcvt_h_w *a) TCGv t0 = get_gpr(ctx, a->rs1, EXT_SIGN); gen_set_rm(ctx, a->rm); - gen_helper_fcvt_h_w(dest, cpu_env, t0); + gen_helper_fcvt_h_w(dest, tcg_env, t0); gen_set_fpr_hs(ctx, a->rd, dest); mark_fs_dirty(ctx); @@ -564,7 +564,7 @@ static bool trans_fcvt_h_wu(DisasContext *ctx, arg_fcvt_h_wu *a) TCGv t0 = get_gpr(ctx, a->rs1, EXT_SIGN); gen_set_rm(ctx, a->rm); - gen_helper_fcvt_h_wu(dest, cpu_env, t0); + gen_helper_fcvt_h_wu(dest, tcg_env, t0); gen_set_fpr_hs(ctx, a->rd, dest); mark_fs_dirty(ctx); @@ -615,7 +615,7 @@ static bool trans_fcvt_l_h(DisasContext *ctx, arg_fcvt_l_h *a) TCGv_i64 src1 = get_fpr_hs(ctx, a->rs1); gen_set_rm(ctx, a->rm); - gen_helper_fcvt_l_h(dest, cpu_env, src1); + gen_helper_fcvt_l_h(dest, tcg_env, src1); gen_set_gpr(ctx, a->rd, dest); return true; } @@ -630,7 +630,7 @@ static bool trans_fcvt_lu_h(DisasContext *ctx, arg_fcvt_lu_h *a) TCGv_i64 src1 = get_fpr_hs(ctx, a->rs1); gen_set_rm(ctx, a->rm); - gen_helper_fcvt_lu_h(dest, cpu_env, src1); + gen_helper_fcvt_lu_h(dest, tcg_env, src1); gen_set_gpr(ctx, a->rd, dest); return true; } @@ -645,7 +645,7 @@ static bool trans_fcvt_h_l(DisasContext *ctx, arg_fcvt_h_l *a) TCGv t0 = get_gpr(ctx, a->rs1, EXT_SIGN); gen_set_rm(ctx, a->rm); - gen_helper_fcvt_h_l(dest, cpu_env, t0); + gen_helper_fcvt_h_l(dest, tcg_env, t0); gen_set_fpr_hs(ctx, a->rd, dest); mark_fs_dirty(ctx); @@ -662,7 +662,7 @@ static bool trans_fcvt_h_lu(DisasContext *ctx, arg_fcvt_h_lu *a) TCGv t0 = get_gpr(ctx, a->rs1, EXT_SIGN); gen_set_rm(ctx, a->rm); - gen_helper_fcvt_h_lu(dest, cpu_env, t0); + gen_helper_fcvt_h_lu(dest, tcg_env, t0); gen_set_fpr_hs(ctx, a->rd, dest); mark_fs_dirty(ctx); diff --git a/target/riscv/insn_trans/trans_rvzicbo.c.inc b/target/riscv/insn_trans/trans_rvzicbo.c.inc index 7df9c30b58..e5a7704f54 100644 --- a/target/riscv/insn_trans/trans_rvzicbo.c.inc +++ b/target/riscv/insn_trans/trans_rvzicbo.c.inc @@ -31,27 +31,27 @@ static bool trans_cbo_clean(DisasContext *ctx, arg_cbo_clean *a) { REQUIRE_ZICBOM(ctx); - gen_helper_cbo_clean_flush(cpu_env, cpu_gpr[a->rs1]); + gen_helper_cbo_clean_flush(tcg_env, cpu_gpr[a->rs1]); return true; } static bool trans_cbo_flush(DisasContext *ctx, arg_cbo_flush *a) { REQUIRE_ZICBOM(ctx); - gen_helper_cbo_clean_flush(cpu_env, cpu_gpr[a->rs1]); + gen_helper_cbo_clean_flush(tcg_env, cpu_gpr[a->rs1]); return true; } static bool trans_cbo_inval(DisasContext *ctx, arg_cbo_inval *a) { REQUIRE_ZICBOM(ctx); - gen_helper_cbo_inval(cpu_env, cpu_gpr[a->rs1]); + gen_helper_cbo_inval(tcg_env, cpu_gpr[a->rs1]); return true; } static bool trans_cbo_zero(DisasContext *ctx, arg_cbo_zero *a) { REQUIRE_ZICBOZ(ctx); - gen_helper_cbo_zero(cpu_env, cpu_gpr[a->rs1]); + gen_helper_cbo_zero(tcg_env, cpu_gpr[a->rs1]); return true; } diff --git a/target/riscv/insn_trans/trans_svinval.c.inc b/target/riscv/insn_trans/trans_svinval.c.inc index f3cd7d5c0b..0f692a1088 100644 --- a/target/riscv/insn_trans/trans_svinval.c.inc +++ b/target/riscv/insn_trans/trans_svinval.c.inc @@ -29,7 +29,7 @@ static bool trans_sinval_vma(DisasContext *ctx, arg_sinval_vma *a) REQUIRE_EXT(ctx, RVS); #ifndef CONFIG_USER_ONLY decode_save_opc(ctx); - gen_helper_tlb_flush(cpu_env); + gen_helper_tlb_flush(tcg_env); return true; #endif return false; @@ -58,7 +58,7 @@ static bool trans_hinval_vvma(DisasContext *ctx, arg_hinval_vvma *a) REQUIRE_EXT(ctx, RVH); #ifndef CONFIG_USER_ONLY decode_save_opc(ctx); - gen_helper_hyp_tlb_flush(cpu_env); + gen_helper_hyp_tlb_flush(tcg_env); return true; #endif return false; @@ -71,7 +71,7 @@ static bool trans_hinval_gvma(DisasContext *ctx, arg_hinval_gvma *a) REQUIRE_EXT(ctx, RVH); #ifndef CONFIG_USER_ONLY decode_save_opc(ctx); - gen_helper_hyp_gvma_tlb_flush(cpu_env); + gen_helper_hyp_gvma_tlb_flush(tcg_env); return true; #endif return false; diff --git a/target/riscv/insn_trans/trans_xthead.c.inc b/target/riscv/insn_trans/trans_xthead.c.inc index da093a4cec..810d76665a 100644 --- a/target/riscv/insn_trans/trans_xthead.c.inc +++ b/target/riscv/insn_trans/trans_xthead.c.inc @@ -985,7 +985,7 @@ static bool trans_th_sfence_vmas(DisasContext *ctx, arg_th_sfence_vmas *a) #ifndef CONFIG_USER_ONLY REQUIRE_PRIV_MS(ctx); - gen_helper_tlb_flush_all(cpu_env); + gen_helper_tlb_flush_all(tcg_env); return true; #else return false; diff --git a/target/riscv/translate.c b/target/riscv/translate.c index 7dbf173adb..2ad5192866 100644 --- a/target/riscv/translate.c +++ b/target/riscv/translate.c @@ -238,13 +238,13 @@ static void gen_update_pc(DisasContext *ctx, target_long diff) static void generate_exception(DisasContext *ctx, int excp) { gen_update_pc(ctx, 0); - gen_helper_raise_exception(cpu_env, tcg_constant_i32(excp)); + gen_helper_raise_exception(tcg_env, tcg_constant_i32(excp)); ctx->base.is_jmp = DISAS_NORETURN; } static void gen_exception_illegal(DisasContext *ctx) { - tcg_gen_st_i32(tcg_constant_i32(ctx->opcode), cpu_env, + tcg_gen_st_i32(tcg_constant_i32(ctx->opcode), tcg_env, offsetof(CPURISCVState, bins)); if (ctx->virt_inst_excp) { generate_exception(ctx, RISCV_EXCP_VIRT_INSTRUCTION_FAULT); @@ -255,7 +255,7 @@ static void gen_exception_illegal(DisasContext *ctx) static void gen_exception_inst_addr_mis(DisasContext *ctx, TCGv target) { - tcg_gen_st_tl(target, cpu_env, offsetof(CPURISCVState, badaddr)); + tcg_gen_st_tl(target, tcg_env, offsetof(CPURISCVState, badaddr)); generate_exception(ctx, RISCV_EXCP_INST_ADDR_MIS); } @@ -263,7 +263,7 @@ static void lookup_and_goto_ptr(DisasContext *ctx) { #ifndef CONFIG_USER_ONLY if (ctx->itrigger) { - gen_helper_itrigger_match(cpu_env); + gen_helper_itrigger_match(tcg_env); } #endif tcg_gen_lookup_and_goto_ptr(); @@ -273,7 +273,7 @@ static void exit_tb(DisasContext *ctx) { #ifndef CONFIG_USER_ONLY if (ctx->itrigger) { - gen_helper_itrigger_match(cpu_env); + gen_helper_itrigger_match(tcg_env); } #endif tcg_gen_exit_tb(NULL, 0); @@ -630,14 +630,14 @@ static void mark_fs_dirty(DisasContext *ctx) ctx->mstatus_fs = EXT_STATUS_DIRTY; tmp = tcg_temp_new(); - tcg_gen_ld_tl(tmp, cpu_env, offsetof(CPURISCVState, mstatus)); + tcg_gen_ld_tl(tmp, tcg_env, offsetof(CPURISCVState, mstatus)); tcg_gen_ori_tl(tmp, tmp, MSTATUS_FS); - tcg_gen_st_tl(tmp, cpu_env, offsetof(CPURISCVState, mstatus)); + tcg_gen_st_tl(tmp, tcg_env, offsetof(CPURISCVState, mstatus)); if (ctx->virt_enabled) { - tcg_gen_ld_tl(tmp, cpu_env, offsetof(CPURISCVState, mstatus_hs)); + tcg_gen_ld_tl(tmp, tcg_env, offsetof(CPURISCVState, mstatus_hs)); tcg_gen_ori_tl(tmp, tmp, MSTATUS_FS); - tcg_gen_st_tl(tmp, cpu_env, offsetof(CPURISCVState, mstatus_hs)); + tcg_gen_st_tl(tmp, tcg_env, offsetof(CPURISCVState, mstatus_hs)); } } } @@ -659,14 +659,14 @@ static void mark_vs_dirty(DisasContext *ctx) ctx->mstatus_vs = EXT_STATUS_DIRTY; tmp = tcg_temp_new(); - tcg_gen_ld_tl(tmp, cpu_env, offsetof(CPURISCVState, mstatus)); + tcg_gen_ld_tl(tmp, tcg_env, offsetof(CPURISCVState, mstatus)); tcg_gen_ori_tl(tmp, tmp, MSTATUS_VS); - tcg_gen_st_tl(tmp, cpu_env, offsetof(CPURISCVState, mstatus)); + tcg_gen_st_tl(tmp, tcg_env, offsetof(CPURISCVState, mstatus)); if (ctx->virt_enabled) { - tcg_gen_ld_tl(tmp, cpu_env, offsetof(CPURISCVState, mstatus_hs)); + tcg_gen_ld_tl(tmp, tcg_env, offsetof(CPURISCVState, mstatus_hs)); tcg_gen_ori_tl(tmp, tmp, MSTATUS_VS); - tcg_gen_st_tl(tmp, cpu_env, offsetof(CPURISCVState, mstatus_hs)); + tcg_gen_st_tl(tmp, tcg_env, offsetof(CPURISCVState, mstatus_hs)); } } } @@ -688,7 +688,7 @@ static void gen_set_rm(DisasContext *ctx, int rm) /* The helper may raise ILLEGAL_INSN -- record binv for unwind. */ decode_save_opc(ctx); - gen_helper_set_rounding_mode(cpu_env, tcg_constant_i32(rm)); + gen_helper_set_rounding_mode(tcg_env, tcg_constant_i32(rm)); } static void gen_set_rm_chkfrm(DisasContext *ctx, int rm) @@ -701,7 +701,7 @@ static void gen_set_rm_chkfrm(DisasContext *ctx, int rm) /* The helper may raise ILLEGAL_INSN -- record binv for unwind. */ decode_save_opc(ctx); - gen_helper_set_rounding_mode_chkfrm(cpu_env, tcg_constant_i32(rm)); + gen_helper_set_rounding_mode_chkfrm(tcg_env, tcg_constant_i32(rm)); } static int ex_plus_1(DisasContext *ctx, int nf) @@ -1306,28 +1306,28 @@ void riscv_translate_init(void) cpu_gprh[0] = NULL; for (i = 1; i < 32; i++) { - cpu_gpr[i] = tcg_global_mem_new(cpu_env, + cpu_gpr[i] = tcg_global_mem_new(tcg_env, offsetof(CPURISCVState, gpr[i]), riscv_int_regnames[i]); - cpu_gprh[i] = tcg_global_mem_new(cpu_env, + cpu_gprh[i] = tcg_global_mem_new(tcg_env, offsetof(CPURISCVState, gprh[i]), riscv_int_regnamesh[i]); } for (i = 0; i < 32; i++) { - cpu_fpr[i] = tcg_global_mem_new_i64(cpu_env, + cpu_fpr[i] = tcg_global_mem_new_i64(tcg_env, offsetof(CPURISCVState, fpr[i]), riscv_fpr_regnames[i]); } - cpu_pc = tcg_global_mem_new(cpu_env, offsetof(CPURISCVState, pc), "pc"); - cpu_vl = tcg_global_mem_new(cpu_env, offsetof(CPURISCVState, vl), "vl"); - cpu_vstart = tcg_global_mem_new(cpu_env, offsetof(CPURISCVState, vstart), + cpu_pc = tcg_global_mem_new(tcg_env, offsetof(CPURISCVState, pc), "pc"); + cpu_vl = tcg_global_mem_new(tcg_env, offsetof(CPURISCVState, vl), "vl"); + cpu_vstart = tcg_global_mem_new(tcg_env, offsetof(CPURISCVState, vstart), "vstart"); - load_res = tcg_global_mem_new(cpu_env, offsetof(CPURISCVState, load_res), + load_res = tcg_global_mem_new(tcg_env, offsetof(CPURISCVState, load_res), "load_res"); - load_val = tcg_global_mem_new(cpu_env, offsetof(CPURISCVState, load_val), + load_val = tcg_global_mem_new(tcg_env, offsetof(CPURISCVState, load_val), "load_val"); /* Assign PM CSRs to tcg globals */ - pm_mask = tcg_global_mem_new(cpu_env, offsetof(CPURISCVState, cur_pmmask), + pm_mask = tcg_global_mem_new(tcg_env, offsetof(CPURISCVState, cur_pmmask), "pmmask"); - pm_base = tcg_global_mem_new(cpu_env, offsetof(CPURISCVState, cur_pmbase), + pm_base = tcg_global_mem_new(tcg_env, offsetof(CPURISCVState, cur_pmbase), "pmbase"); } diff --git a/target/rx/translate.c b/target/rx/translate.c index f552a0319a..9fd4d36b08 100644 --- a/target/rx/translate.c +++ b/target/rx/translate.c @@ -237,7 +237,7 @@ static int is_privileged(DisasContext *ctx, int is_exception) { if (FIELD_EX32(ctx->tb_flags, PSW, PM)) { if (is_exception) { - gen_helper_raise_privilege_violation(cpu_env); + gen_helper_raise_privilege_violation(tcg_env); } return 0; } else { @@ -318,7 +318,7 @@ static void move_from_cr(DisasContext *ctx, TCGv ret, int cr, uint32_t pc) { switch (cr) { case 0: /* PSW */ - gen_helper_pack_psw(ret, cpu_env); + gen_helper_pack_psw(ret, tcg_env); break; case 1: /* PC */ tcg_gen_movi_i32(ret, pc); @@ -370,7 +370,7 @@ static void move_to_cr(DisasContext *ctx, TCGv val, int cr) } switch (cr) { case 0: /* PSW */ - gen_helper_set_psw(cpu_env, val); + gen_helper_set_psw(tcg_env, val); if (is_privileged(ctx, 0)) { /* PSW.{I,U} may be updated here. exit TB. */ ctx->base.is_jmp = DISAS_UPDATE; @@ -385,7 +385,7 @@ static void move_to_cr(DisasContext *ctx, TCGv val, int cr) } break; case 3: /* FPSW */ - gen_helper_set_fpsw(cpu_env, val); + gen_helper_set_fpsw(tcg_env, val); break; case 8: /* BPSW */ tcg_gen_mov_i32(cpu_bpsw, val); @@ -1244,12 +1244,12 @@ static bool trans_EMULU_mr(DisasContext *ctx, arg_EMULU_mr *a) static void rx_div(TCGv ret, TCGv arg1, TCGv arg2) { - gen_helper_div(ret, cpu_env, arg1, arg2); + gen_helper_div(ret, tcg_env, arg1, arg2); } static void rx_divu(TCGv ret, TCGv arg1, TCGv arg2) { - gen_helper_divu(ret, cpu_env, arg1, arg2); + gen_helper_divu(ret, tcg_env, arg1, arg2); } /* div #imm, rd */ @@ -1644,35 +1644,35 @@ static bool trans_NOP(DisasContext *ctx, arg_NOP *a) /* scmpu */ static bool trans_SCMPU(DisasContext *ctx, arg_SCMPU *a) { - gen_helper_scmpu(cpu_env); + gen_helper_scmpu(tcg_env); return true; } /* smovu */ static bool trans_SMOVU(DisasContext *ctx, arg_SMOVU *a) { - gen_helper_smovu(cpu_env); + gen_helper_smovu(tcg_env); return true; } /* smovf */ static bool trans_SMOVF(DisasContext *ctx, arg_SMOVF *a) { - gen_helper_smovf(cpu_env); + gen_helper_smovf(tcg_env); return true; } /* smovb */ static bool trans_SMOVB(DisasContext *ctx, arg_SMOVB *a) { - gen_helper_smovb(cpu_env); + gen_helper_smovb(tcg_env); return true; } #define STRING(op) \ do { \ TCGv size = tcg_constant_i32(a->sz); \ - gen_helper_##op(cpu_env, size); \ + gen_helper_##op(tcg_env, size); \ } while (0) /* suntile. */ @@ -1803,7 +1803,7 @@ static bool trans_MVTACLO(DisasContext *ctx, arg_MVTACLO *a) static bool trans_RACW(DisasContext *ctx, arg_RACW *a) { TCGv imm = tcg_constant_i32(a->imm + 1); - gen_helper_racw(cpu_env, imm); + gen_helper_racw(tcg_env, imm); return true; } @@ -1825,7 +1825,7 @@ static bool trans_SAT(DisasContext *ctx, arg_SAT *a) /* satr */ static bool trans_SATR(DisasContext *ctx, arg_SATR *a) { - gen_helper_satr(cpu_env); + gen_helper_satr(tcg_env); return true; } @@ -1835,7 +1835,7 @@ static bool trans_SATR(DisasContext *ctx, arg_SATR *a) cat3(arg_, name, _ir) * a) \ { \ TCGv imm = tcg_constant_i32(li(ctx, 0)); \ - gen_helper_##op(cpu_regs[a->rd], cpu_env, \ + gen_helper_##op(cpu_regs[a->rd], tcg_env, \ cpu_regs[a->rd], imm); \ return true; \ } \ @@ -1845,7 +1845,7 @@ static bool trans_SATR(DisasContext *ctx, arg_SATR *a) TCGv val, mem; \ mem = tcg_temp_new(); \ val = rx_load_source(ctx, mem, a->ld, MO_32, a->rs); \ - gen_helper_##op(cpu_regs[a->rd], cpu_env, \ + gen_helper_##op(cpu_regs[a->rd], tcg_env, \ cpu_regs[a->rd], val); \ return true; \ } @@ -1856,7 +1856,7 @@ static bool trans_SATR(DisasContext *ctx, arg_SATR *a) TCGv val, mem; \ mem = tcg_temp_new(); \ val = rx_load_source(ctx, mem, a->ld, MO_32, a->rs); \ - gen_helper_##op(cpu_regs[a->rd], cpu_env, val); \ + gen_helper_##op(cpu_regs[a->rd], tcg_env, val); \ return true; \ } @@ -1869,7 +1869,7 @@ FOP(FDIV, fdiv) static bool trans_FCMP_ir(DisasContext *ctx, arg_FCMP_ir * a) { TCGv imm = tcg_constant_i32(li(ctx, 0)); - gen_helper_fcmp(cpu_env, cpu_regs[a->rd], imm); + gen_helper_fcmp(tcg_env, cpu_regs[a->rd], imm); return true; } @@ -1880,7 +1880,7 @@ static bool trans_FCMP_mr(DisasContext *ctx, arg_FCMP_mr *a) TCGv val, mem; mem = tcg_temp_new(); val = rx_load_source(ctx, mem, a->ld, MO_32, a->rs); - gen_helper_fcmp(cpu_env, cpu_regs[a->rd], val); + gen_helper_fcmp(tcg_env, cpu_regs[a->rd], val); return true; } @@ -1894,7 +1894,7 @@ static bool trans_ITOF(DisasContext *ctx, arg_ITOF * a) TCGv val, mem; mem = tcg_temp_new(); val = rx_load_source(ctx, mem, a->ld, a->mi, a->rs); - gen_helper_itof(cpu_regs[a->rd], cpu_env, val); + gen_helper_itof(cpu_regs[a->rd], tcg_env, val); return true; } @@ -2146,7 +2146,7 @@ static bool trans_RTFI(DisasContext *ctx, arg_RTFI *a) psw = tcg_temp_new(); tcg_gen_mov_i32(cpu_pc, cpu_bpc); tcg_gen_mov_i32(psw, cpu_bpsw); - gen_helper_set_psw_rte(cpu_env, psw); + gen_helper_set_psw_rte(tcg_env, psw); ctx->base.is_jmp = DISAS_EXIT; } return true; @@ -2160,7 +2160,7 @@ static bool trans_RTE(DisasContext *ctx, arg_RTE *a) psw = tcg_temp_new(); pop(cpu_pc); pop(psw); - gen_helper_set_psw_rte(cpu_env, psw); + gen_helper_set_psw_rte(tcg_env, psw); ctx->base.is_jmp = DISAS_EXIT; } return true; @@ -2170,7 +2170,7 @@ static bool trans_RTE(DisasContext *ctx, arg_RTE *a) static bool trans_BRK(DisasContext *ctx, arg_BRK *a) { tcg_gen_movi_i32(cpu_pc, ctx->base.pc_next); - gen_helper_rxbrk(cpu_env); + gen_helper_rxbrk(tcg_env); ctx->base.is_jmp = DISAS_NORETURN; return true; } @@ -2183,7 +2183,7 @@ static bool trans_INT(DisasContext *ctx, arg_INT *a) tcg_debug_assert(a->imm < 0x100); vec = tcg_constant_i32(a->imm); tcg_gen_movi_i32(cpu_pc, ctx->base.pc_next); - gen_helper_rxint(cpu_env, vec); + gen_helper_rxint(tcg_env, vec); ctx->base.is_jmp = DISAS_NORETURN; return true; } @@ -2193,7 +2193,7 @@ static bool trans_WAIT(DisasContext *ctx, arg_WAIT *a) { if (is_privileged(ctx, 1)) { tcg_gen_movi_i32(cpu_pc, ctx->base.pc_next); - gen_helper_wait(cpu_env); + gen_helper_wait(tcg_env); } return true; } @@ -2225,7 +2225,7 @@ static void rx_tr_translate_insn(DisasContextBase *dcbase, CPUState *cs) ctx->pc = ctx->base.pc_next; insn = decode_load(ctx); if (!decode(ctx, insn)) { - gen_helper_raise_illegal_instruction(cpu_env); + gen_helper_raise_illegal_instruction(tcg_env); } } @@ -2279,7 +2279,7 @@ void gen_intermediate_code(CPUState *cs, TranslationBlock *tb, int *max_insns, } #define ALLOC_REGISTER(sym, name) \ - cpu_##sym = tcg_global_mem_new_i32(cpu_env, \ + cpu_##sym = tcg_global_mem_new_i32(tcg_env, \ offsetof(CPURXState, sym), name) void rx_translate_init(void) @@ -2291,7 +2291,7 @@ void rx_translate_init(void) int i; for (i = 0; i < NUM_REGS; i++) { - cpu_regs[i] = tcg_global_mem_new_i32(cpu_env, + cpu_regs[i] = tcg_global_mem_new_i32(tcg_env, offsetof(CPURXState, regs[i]), regnames[i]); } @@ -2311,6 +2311,6 @@ void rx_translate_init(void) ALLOC_REGISTER(isp, "ISP"); ALLOC_REGISTER(fintv, "FINTV"); ALLOC_REGISTER(intb, "INTB"); - cpu_acc = tcg_global_mem_new_i64(cpu_env, + cpu_acc = tcg_global_mem_new_i64(tcg_env, offsetof(CPURXState, acc), "ACC"); } diff --git a/target/s390x/tcg/translate.c b/target/s390x/tcg/translate.c index dc7041e1d8..22f43974dd 100644 --- a/target/s390x/tcg/translate.c +++ b/target/s390x/tcg/translate.c @@ -199,28 +199,28 @@ void s390x_translate_init(void) { int i; - psw_addr = tcg_global_mem_new_i64(cpu_env, + psw_addr = tcg_global_mem_new_i64(tcg_env, offsetof(CPUS390XState, psw.addr), "psw_addr"); - psw_mask = tcg_global_mem_new_i64(cpu_env, + psw_mask = tcg_global_mem_new_i64(tcg_env, offsetof(CPUS390XState, psw.mask), "psw_mask"); - gbea = tcg_global_mem_new_i64(cpu_env, + gbea = tcg_global_mem_new_i64(tcg_env, offsetof(CPUS390XState, gbea), "gbea"); - cc_op = tcg_global_mem_new_i32(cpu_env, offsetof(CPUS390XState, cc_op), + cc_op = tcg_global_mem_new_i32(tcg_env, offsetof(CPUS390XState, cc_op), "cc_op"); - cc_src = tcg_global_mem_new_i64(cpu_env, offsetof(CPUS390XState, cc_src), + cc_src = tcg_global_mem_new_i64(tcg_env, offsetof(CPUS390XState, cc_src), "cc_src"); - cc_dst = tcg_global_mem_new_i64(cpu_env, offsetof(CPUS390XState, cc_dst), + cc_dst = tcg_global_mem_new_i64(tcg_env, offsetof(CPUS390XState, cc_dst), "cc_dst"); - cc_vr = tcg_global_mem_new_i64(cpu_env, offsetof(CPUS390XState, cc_vr), + cc_vr = tcg_global_mem_new_i64(tcg_env, offsetof(CPUS390XState, cc_vr), "cc_vr"); for (i = 0; i < 16; i++) { snprintf(cpu_reg_names[i], sizeof(cpu_reg_names[0]), "r%d", i); - regs[i] = tcg_global_mem_new(cpu_env, + regs[i] = tcg_global_mem_new(tcg_env, offsetof(CPUS390XState, regs[i]), cpu_reg_names[i]); } @@ -290,7 +290,7 @@ static TCGv_i64 load_freg(int reg) { TCGv_i64 r = tcg_temp_new_i64(); - tcg_gen_ld_i64(r, cpu_env, freg64_offset(reg)); + tcg_gen_ld_i64(r, tcg_env, freg64_offset(reg)); return r; } @@ -298,7 +298,7 @@ static TCGv_i64 load_freg32_i64(int reg) { TCGv_i64 r = tcg_temp_new_i64(); - tcg_gen_ld32u_i64(r, cpu_env, freg32_offset(reg)); + tcg_gen_ld32u_i64(r, tcg_env, freg32_offset(reg)); return r; } @@ -319,7 +319,7 @@ static void store_reg(int reg, TCGv_i64 v) static void store_freg(int reg, TCGv_i64 v) { - tcg_gen_st_i64(v, cpu_env, freg64_offset(reg)); + tcg_gen_st_i64(v, tcg_env, freg64_offset(reg)); } static void store_reg32_i64(int reg, TCGv_i64 v) @@ -335,7 +335,7 @@ static void store_reg32h_i64(int reg, TCGv_i64 v) static void store_freg32_i64(int reg, TCGv_i64 v) { - tcg_gen_st32_i64(v, cpu_env, freg32_offset(reg)); + tcg_gen_st32_i64(v, tcg_env, freg32_offset(reg)); } static void update_psw_addr(DisasContext *s) @@ -351,7 +351,7 @@ static void per_branch(DisasContext *s, bool to_next) if (s->base.tb->flags & FLAG_MASK_PER) { TCGv_i64 next_pc = to_next ? tcg_constant_i64(s->pc_tmp) : psw_addr; - gen_helper_per_branch(cpu_env, gbea, next_pc); + gen_helper_per_branch(tcg_env, gbea, next_pc); } #endif } @@ -365,7 +365,7 @@ static void per_branch_cond(DisasContext *s, TCGCond cond, tcg_gen_brcond_i64(tcg_invert_cond(cond), arg1, arg2, lab); tcg_gen_movi_i64(gbea, s->base.pc_next); - gen_helper_per_branch(cpu_env, gbea, psw_addr); + gen_helper_per_branch(tcg_env, gbea, psw_addr); gen_set_label(lab); } else { @@ -424,16 +424,16 @@ static int get_mem_index(DisasContext *s) static void gen_exception(int excp) { - gen_helper_exception(cpu_env, tcg_constant_i32(excp)); + gen_helper_exception(tcg_env, tcg_constant_i32(excp)); } static void gen_program_exception(DisasContext *s, int code) { /* Remember what pgm exception this was. */ - tcg_gen_st_i32(tcg_constant_i32(code), cpu_env, + tcg_gen_st_i32(tcg_constant_i32(code), tcg_env, offsetof(CPUS390XState, int_pgm_code)); - tcg_gen_st_i32(tcg_constant_i32(s->ilen), cpu_env, + tcg_gen_st_i32(tcg_constant_i32(s->ilen), tcg_env, offsetof(CPUS390XState, int_pgm_ilen)); /* update the psw */ @@ -453,7 +453,7 @@ static inline void gen_illegal_opcode(DisasContext *s) static inline void gen_data_exception(uint8_t dxc) { - gen_helper_data_exception(cpu_env, tcg_constant_i32(dxc)); + gen_helper_data_exception(tcg_env, tcg_constant_i32(dxc)); } static inline void gen_trap(DisasContext *s) @@ -620,7 +620,7 @@ static void gen_op_calc_cc(DisasContext *s) case CC_OP_LCBB: case CC_OP_MULS_32: /* 1 argument */ - gen_helper_calc_cc(cc_op, cpu_env, local_cc_op, dummy, cc_dst, dummy); + gen_helper_calc_cc(cc_op, tcg_env, local_cc_op, dummy, cc_dst, dummy); break; case CC_OP_ADDU: case CC_OP_ICM: @@ -636,18 +636,18 @@ static void gen_op_calc_cc(DisasContext *s) case CC_OP_VC: case CC_OP_MULS_64: /* 2 arguments */ - gen_helper_calc_cc(cc_op, cpu_env, local_cc_op, cc_src, cc_dst, dummy); + gen_helper_calc_cc(cc_op, tcg_env, local_cc_op, cc_src, cc_dst, dummy); break; case CC_OP_ADD_64: case CC_OP_SUB_64: case CC_OP_ADD_32: case CC_OP_SUB_32: /* 3 arguments */ - gen_helper_calc_cc(cc_op, cpu_env, local_cc_op, cc_src, cc_dst, cc_vr); + gen_helper_calc_cc(cc_op, tcg_env, local_cc_op, cc_src, cc_dst, cc_vr); break; case CC_OP_DYNAMIC: /* unknown operation - assume 3 arguments and cc_op in env */ - gen_helper_calc_cc(cc_op, cpu_env, cc_op, cc_src, cc_dst, cc_vr); + gen_helper_calc_cc(cc_op, tcg_env, cc_op, cc_src, cc_dst, cc_vr); break; default: g_assert_not_reached(); @@ -1398,19 +1398,19 @@ static DisasJumpType op_asiu64(DisasContext *s, DisasOps *o) static DisasJumpType op_aeb(DisasContext *s, DisasOps *o) { - gen_helper_aeb(o->out, cpu_env, o->in1, o->in2); + gen_helper_aeb(o->out, tcg_env, o->in1, o->in2); return DISAS_NEXT; } static DisasJumpType op_adb(DisasContext *s, DisasOps *o) { - gen_helper_adb(o->out, cpu_env, o->in1, o->in2); + gen_helper_adb(o->out, tcg_env, o->in1, o->in2); return DISAS_NEXT; } static DisasJumpType op_axb(DisasContext *s, DisasOps *o) { - gen_helper_axb(o->out_128, cpu_env, o->in1_128, o->in2_128); + gen_helper_axb(o->out_128, tcg_env, o->in1_128, o->in2_128); return DISAS_NEXT; } @@ -1546,7 +1546,7 @@ static DisasJumpType op_bal(DisasContext *s, DisasOps *o) if (have_field(s, ri)) { \ if (unlikely(s->ex_value)) { \ cdest = tcg_temp_new_i64(); \ - tcg_gen_ld_i64(cdest, cpu_env, offsetof(CPUS390XState, ex_target));\ + tcg_gen_ld_i64(cdest, tcg_env, offsetof(CPUS390XState, ex_target));\ tcg_gen_addi_i64(cdest, cdest, (int64_t)get_field(s, ri) * 2); \ is_imm = false; \ } else { \ @@ -1734,21 +1734,21 @@ static DisasJumpType op_cj(DisasContext *s, DisasOps *o) static DisasJumpType op_ceb(DisasContext *s, DisasOps *o) { - gen_helper_ceb(cc_op, cpu_env, o->in1, o->in2); + gen_helper_ceb(cc_op, tcg_env, o->in1, o->in2); set_cc_static(s); return DISAS_NEXT; } static DisasJumpType op_cdb(DisasContext *s, DisasOps *o) { - gen_helper_cdb(cc_op, cpu_env, o->in1, o->in2); + gen_helper_cdb(cc_op, tcg_env, o->in1, o->in2); set_cc_static(s); return DISAS_NEXT; } static DisasJumpType op_cxb(DisasContext *s, DisasOps *o) { - gen_helper_cxb(cc_op, cpu_env, o->in1_128, o->in2_128); + gen_helper_cxb(cc_op, tcg_env, o->in1_128, o->in2_128); set_cc_static(s); return DISAS_NEXT; } @@ -1785,7 +1785,7 @@ static DisasJumpType op_cfeb(DisasContext *s, DisasOps *o) if (!m34) { return DISAS_NORETURN; } - gen_helper_cfeb(o->out, cpu_env, o->in2, m34); + gen_helper_cfeb(o->out, tcg_env, o->in2, m34); set_cc_static(s); return DISAS_NEXT; } @@ -1797,7 +1797,7 @@ static DisasJumpType op_cfdb(DisasContext *s, DisasOps *o) if (!m34) { return DISAS_NORETURN; } - gen_helper_cfdb(o->out, cpu_env, o->in2, m34); + gen_helper_cfdb(o->out, tcg_env, o->in2, m34); set_cc_static(s); return DISAS_NEXT; } @@ -1809,7 +1809,7 @@ static DisasJumpType op_cfxb(DisasContext *s, DisasOps *o) if (!m34) { return DISAS_NORETURN; } - gen_helper_cfxb(o->out, cpu_env, o->in2_128, m34); + gen_helper_cfxb(o->out, tcg_env, o->in2_128, m34); set_cc_static(s); return DISAS_NEXT; } @@ -1821,7 +1821,7 @@ static DisasJumpType op_cgeb(DisasContext *s, DisasOps *o) if (!m34) { return DISAS_NORETURN; } - gen_helper_cgeb(o->out, cpu_env, o->in2, m34); + gen_helper_cgeb(o->out, tcg_env, o->in2, m34); set_cc_static(s); return DISAS_NEXT; } @@ -1833,7 +1833,7 @@ static DisasJumpType op_cgdb(DisasContext *s, DisasOps *o) if (!m34) { return DISAS_NORETURN; } - gen_helper_cgdb(o->out, cpu_env, o->in2, m34); + gen_helper_cgdb(o->out, tcg_env, o->in2, m34); set_cc_static(s); return DISAS_NEXT; } @@ -1845,7 +1845,7 @@ static DisasJumpType op_cgxb(DisasContext *s, DisasOps *o) if (!m34) { return DISAS_NORETURN; } - gen_helper_cgxb(o->out, cpu_env, o->in2_128, m34); + gen_helper_cgxb(o->out, tcg_env, o->in2_128, m34); set_cc_static(s); return DISAS_NEXT; } @@ -1857,7 +1857,7 @@ static DisasJumpType op_clfeb(DisasContext *s, DisasOps *o) if (!m34) { return DISAS_NORETURN; } - gen_helper_clfeb(o->out, cpu_env, o->in2, m34); + gen_helper_clfeb(o->out, tcg_env, o->in2, m34); set_cc_static(s); return DISAS_NEXT; } @@ -1869,7 +1869,7 @@ static DisasJumpType op_clfdb(DisasContext *s, DisasOps *o) if (!m34) { return DISAS_NORETURN; } - gen_helper_clfdb(o->out, cpu_env, o->in2, m34); + gen_helper_clfdb(o->out, tcg_env, o->in2, m34); set_cc_static(s); return DISAS_NEXT; } @@ -1881,7 +1881,7 @@ static DisasJumpType op_clfxb(DisasContext *s, DisasOps *o) if (!m34) { return DISAS_NORETURN; } - gen_helper_clfxb(o->out, cpu_env, o->in2_128, m34); + gen_helper_clfxb(o->out, tcg_env, o->in2_128, m34); set_cc_static(s); return DISAS_NEXT; } @@ -1893,7 +1893,7 @@ static DisasJumpType op_clgeb(DisasContext *s, DisasOps *o) if (!m34) { return DISAS_NORETURN; } - gen_helper_clgeb(o->out, cpu_env, o->in2, m34); + gen_helper_clgeb(o->out, tcg_env, o->in2, m34); set_cc_static(s); return DISAS_NEXT; } @@ -1905,7 +1905,7 @@ static DisasJumpType op_clgdb(DisasContext *s, DisasOps *o) if (!m34) { return DISAS_NORETURN; } - gen_helper_clgdb(o->out, cpu_env, o->in2, m34); + gen_helper_clgdb(o->out, tcg_env, o->in2, m34); set_cc_static(s); return DISAS_NEXT; } @@ -1917,7 +1917,7 @@ static DisasJumpType op_clgxb(DisasContext *s, DisasOps *o) if (!m34) { return DISAS_NORETURN; } - gen_helper_clgxb(o->out, cpu_env, o->in2_128, m34); + gen_helper_clgxb(o->out, tcg_env, o->in2_128, m34); set_cc_static(s); return DISAS_NEXT; } @@ -1929,7 +1929,7 @@ static DisasJumpType op_cegb(DisasContext *s, DisasOps *o) if (!m34) { return DISAS_NORETURN; } - gen_helper_cegb(o->out, cpu_env, o->in2, m34); + gen_helper_cegb(o->out, tcg_env, o->in2, m34); return DISAS_NEXT; } @@ -1940,7 +1940,7 @@ static DisasJumpType op_cdgb(DisasContext *s, DisasOps *o) if (!m34) { return DISAS_NORETURN; } - gen_helper_cdgb(o->out, cpu_env, o->in2, m34); + gen_helper_cdgb(o->out, tcg_env, o->in2, m34); return DISAS_NEXT; } @@ -1951,7 +1951,7 @@ static DisasJumpType op_cxgb(DisasContext *s, DisasOps *o) if (!m34) { return DISAS_NORETURN; } - gen_helper_cxgb(o->out_128, cpu_env, o->in2, m34); + gen_helper_cxgb(o->out_128, tcg_env, o->in2, m34); return DISAS_NEXT; } @@ -1962,7 +1962,7 @@ static DisasJumpType op_celgb(DisasContext *s, DisasOps *o) if (!m34) { return DISAS_NORETURN; } - gen_helper_celgb(o->out, cpu_env, o->in2, m34); + gen_helper_celgb(o->out, tcg_env, o->in2, m34); return DISAS_NEXT; } @@ -1973,7 +1973,7 @@ static DisasJumpType op_cdlgb(DisasContext *s, DisasOps *o) if (!m34) { return DISAS_NORETURN; } - gen_helper_cdlgb(o->out, cpu_env, o->in2, m34); + gen_helper_cdlgb(o->out, tcg_env, o->in2, m34); return DISAS_NEXT; } @@ -1984,7 +1984,7 @@ static DisasJumpType op_cxlgb(DisasContext *s, DisasOps *o) if (!m34) { return DISAS_NORETURN; } - gen_helper_cxlgb(o->out_128, cpu_env, o->in2, m34); + gen_helper_cxlgb(o->out_128, tcg_env, o->in2, m34); return DISAS_NEXT; } @@ -1994,7 +1994,7 @@ static DisasJumpType op_cksm(DisasContext *s, DisasOps *o) TCGv_i128 pair = tcg_temp_new_i128(); TCGv_i64 len = tcg_temp_new_i64(); - gen_helper_cksm(pair, cpu_env, o->in1, o->in2, regs[r2 + 1]); + gen_helper_cksm(pair, tcg_env, o->in1, o->in2, regs[r2 + 1]); set_cc_static(s); tcg_gen_extr_i128_i64(o->out, len, pair); @@ -2022,7 +2022,7 @@ static DisasJumpType op_clc(DisasContext *s, DisasOps *o) return DISAS_NEXT; default: vl = tcg_constant_i32(l); - gen_helper_clc(cc_op, cpu_env, vl, o->addr1, o->in2); + gen_helper_clc(cc_op, tcg_env, vl, o->addr1, o->in2); set_cc_static(s); return DISAS_NEXT; } @@ -2042,7 +2042,7 @@ static DisasJumpType op_clcl(DisasContext *s, DisasOps *o) t1 = tcg_constant_i32(r1); t2 = tcg_constant_i32(r2); - gen_helper_clcl(cc_op, cpu_env, t1, t2); + gen_helper_clcl(cc_op, tcg_env, t1, t2); set_cc_static(s); return DISAS_NEXT; } @@ -2061,7 +2061,7 @@ static DisasJumpType op_clcle(DisasContext *s, DisasOps *o) t1 = tcg_constant_i32(r1); t3 = tcg_constant_i32(r3); - gen_helper_clcle(cc_op, cpu_env, t1, o->in2, t3); + gen_helper_clcle(cc_op, tcg_env, t1, o->in2, t3); set_cc_static(s); return DISAS_NEXT; } @@ -2080,7 +2080,7 @@ static DisasJumpType op_clclu(DisasContext *s, DisasOps *o) t1 = tcg_constant_i32(r1); t3 = tcg_constant_i32(r3); - gen_helper_clclu(cc_op, cpu_env, t1, o->in2, t3); + gen_helper_clclu(cc_op, tcg_env, t1, o->in2, t3); set_cc_static(s); return DISAS_NEXT; } @@ -2091,7 +2091,7 @@ static DisasJumpType op_clm(DisasContext *s, DisasOps *o) TCGv_i32 t1 = tcg_temp_new_i32(); tcg_gen_extrl_i64_i32(t1, o->in1); - gen_helper_clm(cc_op, cpu_env, t1, m3, o->in2); + gen_helper_clm(cc_op, tcg_env, t1, m3, o->in2); set_cc_static(s); return DISAS_NEXT; } @@ -2100,7 +2100,7 @@ static DisasJumpType op_clst(DisasContext *s, DisasOps *o) { TCGv_i128 pair = tcg_temp_new_i128(); - gen_helper_clst(pair, cpu_env, regs[0], o->in1, o->in2); + gen_helper_clst(pair, tcg_env, regs[0], o->in1, o->in2); tcg_gen_extr_i128_i64(o->in2, o->in1, pair); set_cc_static(s); @@ -2169,9 +2169,9 @@ static DisasJumpType op_csst(DisasContext *s, DisasOps *o) TCGv_i32 t_r3 = tcg_constant_i32(r3); if (tb_cflags(s->base.tb) & CF_PARALLEL) { - gen_helper_csst_parallel(cc_op, cpu_env, t_r3, o->addr1, o->in2); + gen_helper_csst_parallel(cc_op, tcg_env, t_r3, o->addr1, o->in2); } else { - gen_helper_csst(cc_op, cpu_env, t_r3, o->addr1, o->in2); + gen_helper_csst(cc_op, tcg_env, t_r3, o->addr1, o->in2); } set_cc_static(s); @@ -2213,7 +2213,7 @@ static DisasJumpType op_csp(DisasContext *s, DisasOps *o) tcg_gen_and_i64(cc, cc, o->in2); tcg_gen_brcondi_i64(TCG_COND_EQ, cc, 0, lab); - gen_helper_purge(cpu_env); + gen_helper_purge(tcg_env); gen_set_label(lab); return DISAS_NEXT; @@ -2271,22 +2271,22 @@ static DisasJumpType op_cuXX(DisasContext *s, DisasOps *o) switch (s->insn->data) { case 12: - gen_helper_cu12(cc_op, cpu_env, tr1, tr2, chk); + gen_helper_cu12(cc_op, tcg_env, tr1, tr2, chk); break; case 14: - gen_helper_cu14(cc_op, cpu_env, tr1, tr2, chk); + gen_helper_cu14(cc_op, tcg_env, tr1, tr2, chk); break; case 21: - gen_helper_cu21(cc_op, cpu_env, tr1, tr2, chk); + gen_helper_cu21(cc_op, tcg_env, tr1, tr2, chk); break; case 24: - gen_helper_cu24(cc_op, cpu_env, tr1, tr2, chk); + gen_helper_cu24(cc_op, tcg_env, tr1, tr2, chk); break; case 41: - gen_helper_cu41(cc_op, cpu_env, tr1, tr2, chk); + gen_helper_cu41(cc_op, tcg_env, tr1, tr2, chk); break; case 42: - gen_helper_cu42(cc_op, cpu_env, tr1, tr2, chk); + gen_helper_cu42(cc_op, tcg_env, tr1, tr2, chk); break; default: g_assert_not_reached(); @@ -2303,21 +2303,21 @@ static DisasJumpType op_diag(DisasContext *s, DisasOps *o) TCGv_i32 r3 = tcg_constant_i32(get_field(s, r3)); TCGv_i32 func_code = tcg_constant_i32(get_field(s, i2)); - gen_helper_diag(cpu_env, r1, r3, func_code); + gen_helper_diag(tcg_env, r1, r3, func_code); return DISAS_NEXT; } #endif static DisasJumpType op_divs32(DisasContext *s, DisasOps *o) { - gen_helper_divs32(o->out, cpu_env, o->in1, o->in2); + gen_helper_divs32(o->out, tcg_env, o->in1, o->in2); tcg_gen_extr32_i64(o->out2, o->out, o->out); return DISAS_NEXT; } static DisasJumpType op_divu32(DisasContext *s, DisasOps *o) { - gen_helper_divu32(o->out, cpu_env, o->in1, o->in2); + gen_helper_divu32(o->out, tcg_env, o->in1, o->in2); tcg_gen_extr32_i64(o->out2, o->out, o->out); return DISAS_NEXT; } @@ -2326,7 +2326,7 @@ static DisasJumpType op_divs64(DisasContext *s, DisasOps *o) { TCGv_i128 t = tcg_temp_new_i128(); - gen_helper_divs64(t, cpu_env, o->in1, o->in2); + gen_helper_divs64(t, tcg_env, o->in1, o->in2); tcg_gen_extr_i128_i64(o->out2, o->out, t); return DISAS_NEXT; } @@ -2335,33 +2335,33 @@ static DisasJumpType op_divu64(DisasContext *s, DisasOps *o) { TCGv_i128 t = tcg_temp_new_i128(); - gen_helper_divu64(t, cpu_env, o->out, o->out2, o->in2); + gen_helper_divu64(t, tcg_env, o->out, o->out2, o->in2); tcg_gen_extr_i128_i64(o->out2, o->out, t); return DISAS_NEXT; } static DisasJumpType op_deb(DisasContext *s, DisasOps *o) { - gen_helper_deb(o->out, cpu_env, o->in1, o->in2); + gen_helper_deb(o->out, tcg_env, o->in1, o->in2); return DISAS_NEXT; } static DisasJumpType op_ddb(DisasContext *s, DisasOps *o) { - gen_helper_ddb(o->out, cpu_env, o->in1, o->in2); + gen_helper_ddb(o->out, tcg_env, o->in1, o->in2); return DISAS_NEXT; } static DisasJumpType op_dxb(DisasContext *s, DisasOps *o) { - gen_helper_dxb(o->out_128, cpu_env, o->in1_128, o->in2_128); + gen_helper_dxb(o->out_128, tcg_env, o->in1_128, o->in2_128); return DISAS_NEXT; } static DisasJumpType op_ear(DisasContext *s, DisasOps *o) { int r2 = get_field(s, r2); - tcg_gen_ld32u_i64(o->out, cpu_env, offsetof(CPUS390XState, aregs[r2])); + tcg_gen_ld32u_i64(o->out, tcg_env, offsetof(CPUS390XState, aregs[r2])); return DISAS_NEXT; } @@ -2374,7 +2374,7 @@ static DisasJumpType op_ecag(DisasContext *s, DisasOps *o) static DisasJumpType op_efpc(DisasContext *s, DisasOps *o) { - tcg_gen_ld32u_i64(o->out, cpu_env, offsetof(CPUS390XState, fpc)); + tcg_gen_ld32u_i64(o->out, tcg_env, offsetof(CPUS390XState, fpc)); return DISAS_NEXT; } @@ -2420,7 +2420,7 @@ static DisasJumpType op_ex(DisasContext *s, DisasOps *o) } ilen = tcg_constant_i32(s->ilen); - gen_helper_ex(cpu_env, ilen, v1, o->in2); + gen_helper_ex(tcg_env, ilen, v1, o->in2); return DISAS_PC_CC_UPDATED; } @@ -2432,7 +2432,7 @@ static DisasJumpType op_fieb(DisasContext *s, DisasOps *o) if (!m34) { return DISAS_NORETURN; } - gen_helper_fieb(o->out, cpu_env, o->in2, m34); + gen_helper_fieb(o->out, tcg_env, o->in2, m34); return DISAS_NEXT; } @@ -2443,7 +2443,7 @@ static DisasJumpType op_fidb(DisasContext *s, DisasOps *o) if (!m34) { return DISAS_NORETURN; } - gen_helper_fidb(o->out, cpu_env, o->in2, m34); + gen_helper_fidb(o->out, tcg_env, o->in2, m34); return DISAS_NEXT; } @@ -2454,7 +2454,7 @@ static DisasJumpType op_fixb(DisasContext *s, DisasOps *o) if (!m34) { return DISAS_NORETURN; } - gen_helper_fixb(o->out_128, cpu_env, o->in2_128, m34); + gen_helper_fixb(o->out_128, tcg_env, o->in2_128, m34); return DISAS_NEXT; } @@ -2575,7 +2575,7 @@ static DisasJumpType op_idte(DisasContext *s, DisasOps *o) } else { m4 = tcg_constant_i32(0); } - gen_helper_idte(cpu_env, o->in1, o->in2, m4); + gen_helper_idte(tcg_env, o->in1, o->in2, m4); return DISAS_NEXT; } @@ -2588,13 +2588,13 @@ static DisasJumpType op_ipte(DisasContext *s, DisasOps *o) } else { m4 = tcg_constant_i32(0); } - gen_helper_ipte(cpu_env, o->in1, o->in2, m4); + gen_helper_ipte(tcg_env, o->in1, o->in2, m4); return DISAS_NEXT; } static DisasJumpType op_iske(DisasContext *s, DisasOps *o) { - gen_helper_iske(o->out, cpu_env, o->in2); + gen_helper_iske(o->out, tcg_env, o->in2); return DISAS_NEXT; } #endif @@ -2648,28 +2648,28 @@ static DisasJumpType op_msa(DisasContext *s, DisasOps *o) t_r2 = tcg_constant_i32(r2); t_r3 = tcg_constant_i32(r3); type = tcg_constant_i32(s->insn->data); - gen_helper_msa(cc_op, cpu_env, t_r1, t_r2, t_r3, type); + gen_helper_msa(cc_op, tcg_env, t_r1, t_r2, t_r3, type); set_cc_static(s); return DISAS_NEXT; } static DisasJumpType op_keb(DisasContext *s, DisasOps *o) { - gen_helper_keb(cc_op, cpu_env, o->in1, o->in2); + gen_helper_keb(cc_op, tcg_env, o->in1, o->in2); set_cc_static(s); return DISAS_NEXT; } static DisasJumpType op_kdb(DisasContext *s, DisasOps *o) { - gen_helper_kdb(cc_op, cpu_env, o->in1, o->in2); + gen_helper_kdb(cc_op, tcg_env, o->in1, o->in2); set_cc_static(s); return DISAS_NEXT; } static DisasJumpType op_kxb(DisasContext *s, DisasOps *o) { - gen_helper_kxb(cc_op, cpu_env, o->in1_128, o->in2_128); + gen_helper_kxb(cc_op, tcg_env, o->in1_128, o->in2_128); set_cc_static(s); return DISAS_NEXT; } @@ -2720,7 +2720,7 @@ static DisasJumpType op_lax(DisasContext *s, DisasOps *o) static DisasJumpType op_ldeb(DisasContext *s, DisasOps *o) { - gen_helper_ldeb(o->out, cpu_env, o->in2); + gen_helper_ldeb(o->out, tcg_env, o->in2); return DISAS_NEXT; } @@ -2731,7 +2731,7 @@ static DisasJumpType op_ledb(DisasContext *s, DisasOps *o) if (!m34) { return DISAS_NORETURN; } - gen_helper_ledb(o->out, cpu_env, o->in2, m34); + gen_helper_ledb(o->out, tcg_env, o->in2, m34); return DISAS_NEXT; } @@ -2742,7 +2742,7 @@ static DisasJumpType op_ldxb(DisasContext *s, DisasOps *o) if (!m34) { return DISAS_NORETURN; } - gen_helper_ldxb(o->out, cpu_env, o->in2_128, m34); + gen_helper_ldxb(o->out, tcg_env, o->in2_128, m34); return DISAS_NEXT; } @@ -2753,19 +2753,19 @@ static DisasJumpType op_lexb(DisasContext *s, DisasOps *o) if (!m34) { return DISAS_NORETURN; } - gen_helper_lexb(o->out, cpu_env, o->in2_128, m34); + gen_helper_lexb(o->out, tcg_env, o->in2_128, m34); return DISAS_NEXT; } static DisasJumpType op_lxdb(DisasContext *s, DisasOps *o) { - gen_helper_lxdb(o->out_128, cpu_env, o->in2); + gen_helper_lxdb(o->out_128, tcg_env, o->in2); return DISAS_NEXT; } static DisasJumpType op_lxeb(DisasContext *s, DisasOps *o) { - gen_helper_lxeb(o->out_128, cpu_env, o->in2); + gen_helper_lxeb(o->out_128, tcg_env, o->in2); return DISAS_NEXT; } @@ -2919,7 +2919,7 @@ static DisasJumpType op_lctl(DisasContext *s, DisasOps *o) TCGv_i32 r1 = tcg_constant_i32(get_field(s, r1)); TCGv_i32 r3 = tcg_constant_i32(get_field(s, r3)); - gen_helper_lctl(cpu_env, r1, o->in2, r3); + gen_helper_lctl(tcg_env, r1, o->in2, r3); /* Exit to main loop to reevaluate s390_cpu_exec_interrupt. */ s->exit_to_mainloop = true; return DISAS_TOO_MANY; @@ -2930,7 +2930,7 @@ static DisasJumpType op_lctlg(DisasContext *s, DisasOps *o) TCGv_i32 r1 = tcg_constant_i32(get_field(s, r1)); TCGv_i32 r3 = tcg_constant_i32(get_field(s, r3)); - gen_helper_lctlg(cpu_env, r1, o->in2, r3); + gen_helper_lctlg(tcg_env, r1, o->in2, r3); /* Exit to main loop to reevaluate s390_cpu_exec_interrupt. */ s->exit_to_mainloop = true; return DISAS_TOO_MANY; @@ -2938,14 +2938,14 @@ static DisasJumpType op_lctlg(DisasContext *s, DisasOps *o) static DisasJumpType op_lra(DisasContext *s, DisasOps *o) { - gen_helper_lra(o->out, cpu_env, o->out, o->in2); + gen_helper_lra(o->out, tcg_env, o->out, o->in2); set_cc_static(s); return DISAS_NEXT; } static DisasJumpType op_lpp(DisasContext *s, DisasOps *o) { - tcg_gen_st_i64(o->in2, cpu_env, offsetof(CPUS390XState, pp)); + tcg_gen_st_i64(o->in2, tcg_env, offsetof(CPUS390XState, pp)); return DISAS_NEXT; } @@ -2965,7 +2965,7 @@ static DisasJumpType op_lpsw(DisasContext *s, DisasOps *o) tcg_gen_andi_i64(addr, mask, PSW_MASK_SHORT_ADDR); tcg_gen_andi_i64(mask, mask, PSW_MASK_SHORT_CTRL); tcg_gen_xori_i64(mask, mask, PSW_MASK_SHORTPSW); - gen_helper_load_psw(cpu_env, mask, addr); + gen_helper_load_psw(tcg_env, mask, addr); return DISAS_NORETURN; } @@ -2981,7 +2981,7 @@ static DisasJumpType op_lpswe(DisasContext *s, DisasOps *o) MO_TEUQ | MO_ALIGN_8); tcg_gen_addi_i64(o->in2, o->in2, 8); tcg_gen_qemu_ld_i64(t2, o->in2, get_mem_index(s), MO_TEUQ); - gen_helper_load_psw(cpu_env, t1, t2); + gen_helper_load_psw(tcg_env, t1, t2); return DISAS_NORETURN; } #endif @@ -2991,7 +2991,7 @@ static DisasJumpType op_lam(DisasContext *s, DisasOps *o) TCGv_i32 r1 = tcg_constant_i32(get_field(s, r1)); TCGv_i32 r3 = tcg_constant_i32(get_field(s, r3)); - gen_helper_lam(cpu_env, r1, o->in2, r3); + gen_helper_lam(tcg_env, r1, o->in2, r3); return DISAS_NEXT; } @@ -3185,7 +3185,7 @@ static DisasJumpType op_mc(DisasContext *s, DisasOps *o) } #if !defined(CONFIG_USER_ONLY) - gen_helper_monitor_call(cpu_env, o->addr1, + gen_helper_monitor_call(tcg_env, o->addr1, tcg_constant_i32(monitor_class)); #endif /* Defaults to a NOP. */ @@ -3216,7 +3216,7 @@ static DisasJumpType op_mov2e(DisasContext *s, DisasOps *o) break; case PSW_ASC_SECONDARY >> FLAG_MASK_PSW_SHIFT: if (b2) { - tcg_gen_ld32u_i64(ar1, cpu_env, offsetof(CPUS390XState, aregs[b2])); + tcg_gen_ld32u_i64(ar1, tcg_env, offsetof(CPUS390XState, aregs[b2])); } else { tcg_gen_movi_i64(ar1, 0); } @@ -3226,7 +3226,7 @@ static DisasJumpType op_mov2e(DisasContext *s, DisasOps *o) break; } - tcg_gen_st32_i64(ar1, cpu_env, offsetof(CPUS390XState, aregs[1])); + tcg_gen_st32_i64(ar1, tcg_env, offsetof(CPUS390XState, aregs[1])); return DISAS_NEXT; } @@ -3243,13 +3243,13 @@ static DisasJumpType op_mvc(DisasContext *s, DisasOps *o) { TCGv_i32 l = tcg_constant_i32(get_field(s, l1)); - gen_helper_mvc(cpu_env, l, o->addr1, o->in2); + gen_helper_mvc(tcg_env, l, o->addr1, o->in2); return DISAS_NEXT; } static DisasJumpType op_mvcrl(DisasContext *s, DisasOps *o) { - gen_helper_mvcrl(cpu_env, regs[0], o->addr1, o->in2); + gen_helper_mvcrl(tcg_env, regs[0], o->addr1, o->in2); return DISAS_NEXT; } @@ -3257,7 +3257,7 @@ static DisasJumpType op_mvcin(DisasContext *s, DisasOps *o) { TCGv_i32 l = tcg_constant_i32(get_field(s, l1)); - gen_helper_mvcin(cpu_env, l, o->addr1, o->in2); + gen_helper_mvcin(tcg_env, l, o->addr1, o->in2); return DISAS_NEXT; } @@ -3275,7 +3275,7 @@ static DisasJumpType op_mvcl(DisasContext *s, DisasOps *o) t1 = tcg_constant_i32(r1); t2 = tcg_constant_i32(r2); - gen_helper_mvcl(cc_op, cpu_env, t1, t2); + gen_helper_mvcl(cc_op, tcg_env, t1, t2); set_cc_static(s); return DISAS_NEXT; } @@ -3294,7 +3294,7 @@ static DisasJumpType op_mvcle(DisasContext *s, DisasOps *o) t1 = tcg_constant_i32(r1); t3 = tcg_constant_i32(r3); - gen_helper_mvcle(cc_op, cpu_env, t1, o->in2, t3); + gen_helper_mvcle(cc_op, tcg_env, t1, o->in2, t3); set_cc_static(s); return DISAS_NEXT; } @@ -3313,7 +3313,7 @@ static DisasJumpType op_mvclu(DisasContext *s, DisasOps *o) t1 = tcg_constant_i32(r1); t3 = tcg_constant_i32(r3); - gen_helper_mvclu(cc_op, cpu_env, t1, o->in2, t3); + gen_helper_mvclu(cc_op, tcg_env, t1, o->in2, t3); set_cc_static(s); return DISAS_NEXT; } @@ -3321,7 +3321,7 @@ static DisasJumpType op_mvclu(DisasContext *s, DisasOps *o) static DisasJumpType op_mvcos(DisasContext *s, DisasOps *o) { int r3 = get_field(s, r3); - gen_helper_mvcos(cc_op, cpu_env, o->addr1, o->in2, regs[r3]); + gen_helper_mvcos(cc_op, tcg_env, o->addr1, o->in2, regs[r3]); set_cc_static(s); return DISAS_NEXT; } @@ -3331,7 +3331,7 @@ static DisasJumpType op_mvcp(DisasContext *s, DisasOps *o) { int r1 = get_field(s, l1); int r3 = get_field(s, r3); - gen_helper_mvcp(cc_op, cpu_env, regs[r1], o->addr1, o->in2, regs[r3]); + gen_helper_mvcp(cc_op, tcg_env, regs[r1], o->addr1, o->in2, regs[r3]); set_cc_static(s); return DISAS_NEXT; } @@ -3340,7 +3340,7 @@ static DisasJumpType op_mvcs(DisasContext *s, DisasOps *o) { int r1 = get_field(s, l1); int r3 = get_field(s, r3); - gen_helper_mvcs(cc_op, cpu_env, regs[r1], o->addr1, o->in2, regs[r3]); + gen_helper_mvcs(cc_op, tcg_env, regs[r1], o->addr1, o->in2, regs[r3]); set_cc_static(s); return DISAS_NEXT; } @@ -3350,7 +3350,7 @@ static DisasJumpType op_mvn(DisasContext *s, DisasOps *o) { TCGv_i32 l = tcg_constant_i32(get_field(s, l1)); - gen_helper_mvn(cpu_env, l, o->addr1, o->in2); + gen_helper_mvn(tcg_env, l, o->addr1, o->in2); return DISAS_NEXT; } @@ -3358,7 +3358,7 @@ static DisasJumpType op_mvo(DisasContext *s, DisasOps *o) { TCGv_i32 l = tcg_constant_i32(get_field(s, l1)); - gen_helper_mvo(cpu_env, l, o->addr1, o->in2); + gen_helper_mvo(tcg_env, l, o->addr1, o->in2); return DISAS_NEXT; } @@ -3367,7 +3367,7 @@ static DisasJumpType op_mvpg(DisasContext *s, DisasOps *o) TCGv_i32 t1 = tcg_constant_i32(get_field(s, r1)); TCGv_i32 t2 = tcg_constant_i32(get_field(s, r2)); - gen_helper_mvpg(cc_op, cpu_env, regs[0], t1, t2); + gen_helper_mvpg(cc_op, tcg_env, regs[0], t1, t2); set_cc_static(s); return DISAS_NEXT; } @@ -3377,7 +3377,7 @@ static DisasJumpType op_mvst(DisasContext *s, DisasOps *o) TCGv_i32 t1 = tcg_constant_i32(get_field(s, r1)); TCGv_i32 t2 = tcg_constant_i32(get_field(s, r2)); - gen_helper_mvst(cc_op, cpu_env, t1, t2); + gen_helper_mvst(cc_op, tcg_env, t1, t2); set_cc_static(s); return DISAS_NEXT; } @@ -3386,7 +3386,7 @@ static DisasJumpType op_mvz(DisasContext *s, DisasOps *o) { TCGv_i32 l = tcg_constant_i32(get_field(s, l1)); - gen_helper_mvz(cpu_env, l, o->addr1, o->in2); + gen_helper_mvz(tcg_env, l, o->addr1, o->in2); return DISAS_NEXT; } @@ -3410,59 +3410,59 @@ static DisasJumpType op_muls128(DisasContext *s, DisasOps *o) static DisasJumpType op_meeb(DisasContext *s, DisasOps *o) { - gen_helper_meeb(o->out, cpu_env, o->in1, o->in2); + gen_helper_meeb(o->out, tcg_env, o->in1, o->in2); return DISAS_NEXT; } static DisasJumpType op_mdeb(DisasContext *s, DisasOps *o) { - gen_helper_mdeb(o->out, cpu_env, o->in1, o->in2); + gen_helper_mdeb(o->out, tcg_env, o->in1, o->in2); return DISAS_NEXT; } static DisasJumpType op_mdb(DisasContext *s, DisasOps *o) { - gen_helper_mdb(o->out, cpu_env, o->in1, o->in2); + gen_helper_mdb(o->out, tcg_env, o->in1, o->in2); return DISAS_NEXT; } static DisasJumpType op_mxb(DisasContext *s, DisasOps *o) { - gen_helper_mxb(o->out_128, cpu_env, o->in1_128, o->in2_128); + gen_helper_mxb(o->out_128, tcg_env, o->in1_128, o->in2_128); return DISAS_NEXT; } static DisasJumpType op_mxdb(DisasContext *s, DisasOps *o) { - gen_helper_mxdb(o->out_128, cpu_env, o->in1, o->in2); + gen_helper_mxdb(o->out_128, tcg_env, o->in1, o->in2); return DISAS_NEXT; } static DisasJumpType op_maeb(DisasContext *s, DisasOps *o) { TCGv_i64 r3 = load_freg32_i64(get_field(s, r3)); - gen_helper_maeb(o->out, cpu_env, o->in1, o->in2, r3); + gen_helper_maeb(o->out, tcg_env, o->in1, o->in2, r3); return DISAS_NEXT; } static DisasJumpType op_madb(DisasContext *s, DisasOps *o) { TCGv_i64 r3 = load_freg(get_field(s, r3)); - gen_helper_madb(o->out, cpu_env, o->in1, o->in2, r3); + gen_helper_madb(o->out, tcg_env, o->in1, o->in2, r3); return DISAS_NEXT; } static DisasJumpType op_mseb(DisasContext *s, DisasOps *o) { TCGv_i64 r3 = load_freg32_i64(get_field(s, r3)); - gen_helper_mseb(o->out, cpu_env, o->in1, o->in2, r3); + gen_helper_mseb(o->out, tcg_env, o->in1, o->in2, r3); return DISAS_NEXT; } static DisasJumpType op_msdb(DisasContext *s, DisasOps *o) { TCGv_i64 r3 = load_freg(get_field(s, r3)); - gen_helper_msdb(o->out, cpu_env, o->in1, o->in2, r3); + gen_helper_msdb(o->out, tcg_env, o->in1, o->in2, r3); return DISAS_NEXT; } @@ -3499,7 +3499,7 @@ static DisasJumpType op_nc(DisasContext *s, DisasOps *o) { TCGv_i32 l = tcg_constant_i32(get_field(s, l1)); - gen_helper_nc(cc_op, cpu_env, l, o->addr1, o->in2); + gen_helper_nc(cc_op, tcg_env, l, o->addr1, o->in2); set_cc_static(s); return DISAS_NEXT; } @@ -3533,7 +3533,7 @@ static DisasJumpType op_oc(DisasContext *s, DisasOps *o) { TCGv_i32 l = tcg_constant_i32(get_field(s, l1)); - gen_helper_oc(cc_op, cpu_env, l, o->addr1, o->in2); + gen_helper_oc(cc_op, tcg_env, l, o->addr1, o->in2); set_cc_static(s); return DISAS_NEXT; } @@ -3585,7 +3585,7 @@ static DisasJumpType op_pack(DisasContext *s, DisasOps *o) { TCGv_i32 l = tcg_constant_i32(get_field(s, l1)); - gen_helper_pack(cpu_env, l, o->addr1, o->in2); + gen_helper_pack(tcg_env, l, o->addr1, o->in2); return DISAS_NEXT; } @@ -3600,7 +3600,7 @@ static DisasJumpType op_pka(DisasContext *s, DisasOps *o) return DISAS_NORETURN; } l = tcg_constant_i32(l2); - gen_helper_pka(cpu_env, o->addr1, o->in2, l); + gen_helper_pka(tcg_env, o->addr1, o->in2, l); return DISAS_NEXT; } @@ -3615,7 +3615,7 @@ static DisasJumpType op_pku(DisasContext *s, DisasOps *o) return DISAS_NORETURN; } l = tcg_constant_i32(l2); - gen_helper_pku(cpu_env, o->addr1, o->in2, l); + gen_helper_pku(tcg_env, o->addr1, o->in2, l); return DISAS_NEXT; } @@ -3634,7 +3634,7 @@ static DisasJumpType op_popcnt(DisasContext *s, DisasOps *o) #ifndef CONFIG_USER_ONLY static DisasJumpType op_ptlb(DisasContext *s, DisasOps *o) { - gen_helper_ptlb(cpu_env); + gen_helper_ptlb(tcg_env); return DISAS_NEXT; } #endif @@ -3822,14 +3822,14 @@ static DisasJumpType op_rll64(DisasContext *s, DisasOps *o) #ifndef CONFIG_USER_ONLY static DisasJumpType op_rrbe(DisasContext *s, DisasOps *o) { - gen_helper_rrbe(cc_op, cpu_env, o->in2); + gen_helper_rrbe(cc_op, tcg_env, o->in2); set_cc_static(s); return DISAS_NEXT; } static DisasJumpType op_sacf(DisasContext *s, DisasOps *o) { - gen_helper_sacf(cpu_env, o->in2); + gen_helper_sacf(tcg_env, o->in2); /* Addressing mode has changed, so end the block. */ return DISAS_TOO_MANY; } @@ -3872,50 +3872,50 @@ static DisasJumpType op_sam(DisasContext *s, DisasOps *o) static DisasJumpType op_sar(DisasContext *s, DisasOps *o) { int r1 = get_field(s, r1); - tcg_gen_st32_i64(o->in2, cpu_env, offsetof(CPUS390XState, aregs[r1])); + tcg_gen_st32_i64(o->in2, tcg_env, offsetof(CPUS390XState, aregs[r1])); return DISAS_NEXT; } static DisasJumpType op_seb(DisasContext *s, DisasOps *o) { - gen_helper_seb(o->out, cpu_env, o->in1, o->in2); + gen_helper_seb(o->out, tcg_env, o->in1, o->in2); return DISAS_NEXT; } static DisasJumpType op_sdb(DisasContext *s, DisasOps *o) { - gen_helper_sdb(o->out, cpu_env, o->in1, o->in2); + gen_helper_sdb(o->out, tcg_env, o->in1, o->in2); return DISAS_NEXT; } static DisasJumpType op_sxb(DisasContext *s, DisasOps *o) { - gen_helper_sxb(o->out_128, cpu_env, o->in1_128, o->in2_128); + gen_helper_sxb(o->out_128, tcg_env, o->in1_128, o->in2_128); return DISAS_NEXT; } static DisasJumpType op_sqeb(DisasContext *s, DisasOps *o) { - gen_helper_sqeb(o->out, cpu_env, o->in2); + gen_helper_sqeb(o->out, tcg_env, o->in2); return DISAS_NEXT; } static DisasJumpType op_sqdb(DisasContext *s, DisasOps *o) { - gen_helper_sqdb(o->out, cpu_env, o->in2); + gen_helper_sqdb(o->out, tcg_env, o->in2); return DISAS_NEXT; } static DisasJumpType op_sqxb(DisasContext *s, DisasOps *o) { - gen_helper_sqxb(o->out_128, cpu_env, o->in2_128); + gen_helper_sqxb(o->out_128, tcg_env, o->in2_128); return DISAS_NEXT; } #ifndef CONFIG_USER_ONLY static DisasJumpType op_servc(DisasContext *s, DisasOps *o) { - gen_helper_servc(cc_op, cpu_env, o->in2, o->in1); + gen_helper_servc(cc_op, tcg_env, o->in2, o->in1); set_cc_static(s); return DISAS_NEXT; } @@ -3925,7 +3925,7 @@ static DisasJumpType op_sigp(DisasContext *s, DisasOps *o) TCGv_i32 r1 = tcg_constant_i32(get_field(s, r1)); TCGv_i32 r3 = tcg_constant_i32(get_field(s, r3)); - gen_helper_sigp(cc_op, cpu_env, o->in2, r1, r3); + gen_helper_sigp(cc_op, tcg_env, o->in2, r1, r3); set_cc_static(s); return DISAS_NEXT; } @@ -4013,13 +4013,13 @@ static DisasJumpType op_srl(DisasContext *s, DisasOps *o) static DisasJumpType op_sfpc(DisasContext *s, DisasOps *o) { - gen_helper_sfpc(cpu_env, o->in2); + gen_helper_sfpc(tcg_env, o->in2); return DISAS_NEXT; } static DisasJumpType op_sfas(DisasContext *s, DisasOps *o) { - gen_helper_sfas(cpu_env, o->in2); + gen_helper_sfas(tcg_env, o->in2); return DISAS_NEXT; } @@ -4027,7 +4027,7 @@ static DisasJumpType op_srnm(DisasContext *s, DisasOps *o) { /* Bits other than 62 and 63 are ignored. Bit 29 is set to zero. */ tcg_gen_andi_i64(o->addr1, o->addr1, 0x3ull); - gen_helper_srnm(cpu_env, o->addr1); + gen_helper_srnm(tcg_env, o->addr1); return DISAS_NEXT; } @@ -4035,7 +4035,7 @@ static DisasJumpType op_srnmb(DisasContext *s, DisasOps *o) { /* Bits 0-55 are are ignored. */ tcg_gen_andi_i64(o->addr1, o->addr1, 0xffull); - gen_helper_srnm(cpu_env, o->addr1); + gen_helper_srnm(tcg_env, o->addr1); return DISAS_NEXT; } @@ -4047,9 +4047,9 @@ static DisasJumpType op_srnmt(DisasContext *s, DisasOps *o) tcg_gen_andi_i64(o->addr1, o->addr1, 0x7ull); /* No need to call a helper, we don't implement dfp */ - tcg_gen_ld32u_i64(tmp, cpu_env, offsetof(CPUS390XState, fpc)); + tcg_gen_ld32u_i64(tmp, tcg_env, offsetof(CPUS390XState, fpc)); tcg_gen_deposit_i64(tmp, tmp, o->addr1, 4, 3); - tcg_gen_st32_i64(tmp, cpu_env, offsetof(CPUS390XState, fpc)); + tcg_gen_st32_i64(tmp, tcg_env, offsetof(CPUS390XState, fpc)); return DISAS_NEXT; } @@ -4085,7 +4085,7 @@ static DisasJumpType op_ectg(DisasContext *s, DisasOps *o) tcg_gen_qemu_ld_i64(regs[r3], o->addr1, get_mem_index(s), MO_TEUQ); /* subtract CPU timer from first operand and store in GR0 */ - gen_helper_stpt(tmp, cpu_env); + gen_helper_stpt(tmp, tcg_env); tcg_gen_sub_i64(regs[0], o->in1, tmp); /* store second operand in GR1 */ @@ -4103,7 +4103,7 @@ static DisasJumpType op_spka(DisasContext *s, DisasOps *o) static DisasJumpType op_sske(DisasContext *s, DisasOps *o) { - gen_helper_sske(cpu_env, o->in1, o->in2); + gen_helper_sske(tcg_env, o->in1, o->in2); return DISAS_NEXT; } @@ -4131,14 +4131,14 @@ static DisasJumpType op_ssm(DisasContext *s, DisasOps *o) static DisasJumpType op_stap(DisasContext *s, DisasOps *o) { - tcg_gen_ld32u_i64(o->out, cpu_env, offsetof(CPUS390XState, core_id)); + tcg_gen_ld32u_i64(o->out, tcg_env, offsetof(CPUS390XState, core_id)); return DISAS_NEXT; } #endif static DisasJumpType op_stck(DisasContext *s, DisasOps *o) { - gen_helper_stck(o->out, cpu_env); + gen_helper_stck(o->out, tcg_env); /* ??? We don't implement clock states. */ gen_op_movi_cc(s, 0); return DISAS_NEXT; @@ -4149,9 +4149,9 @@ static DisasJumpType op_stcke(DisasContext *s, DisasOps *o) TCGv_i64 c1 = tcg_temp_new_i64(); TCGv_i64 c2 = tcg_temp_new_i64(); TCGv_i64 todpr = tcg_temp_new_i64(); - gen_helper_stck(c1, cpu_env); + gen_helper_stck(c1, tcg_env); /* 16 bit value store in an uint32_t (only valid bits set) */ - tcg_gen_ld32u_i64(todpr, cpu_env, offsetof(CPUS390XState, todpr)); + tcg_gen_ld32u_i64(todpr, tcg_env, offsetof(CPUS390XState, todpr)); /* Shift the 64-bit value into its place as a zero-extended 104-bit value. Note that "bit positions 64-103 are always non-zero so that they compare differently to STCK"; we set @@ -4171,26 +4171,26 @@ static DisasJumpType op_stcke(DisasContext *s, DisasOps *o) #ifndef CONFIG_USER_ONLY static DisasJumpType op_sck(DisasContext *s, DisasOps *o) { - gen_helper_sck(cc_op, cpu_env, o->in2); + gen_helper_sck(cc_op, tcg_env, o->in2); set_cc_static(s); return DISAS_NEXT; } static DisasJumpType op_sckc(DisasContext *s, DisasOps *o) { - gen_helper_sckc(cpu_env, o->in2); + gen_helper_sckc(tcg_env, o->in2); return DISAS_NEXT; } static DisasJumpType op_sckpf(DisasContext *s, DisasOps *o) { - gen_helper_sckpf(cpu_env, regs[0]); + gen_helper_sckpf(tcg_env, regs[0]); return DISAS_NEXT; } static DisasJumpType op_stckc(DisasContext *s, DisasOps *o) { - gen_helper_stckc(o->out, cpu_env); + gen_helper_stckc(o->out, tcg_env); return DISAS_NEXT; } @@ -4199,7 +4199,7 @@ static DisasJumpType op_stctg(DisasContext *s, DisasOps *o) TCGv_i32 r1 = tcg_constant_i32(get_field(s, r1)); TCGv_i32 r3 = tcg_constant_i32(get_field(s, r3)); - gen_helper_stctg(cpu_env, r1, o->in2, r3); + gen_helper_stctg(tcg_env, r1, o->in2, r3); return DISAS_NEXT; } @@ -4208,98 +4208,98 @@ static DisasJumpType op_stctl(DisasContext *s, DisasOps *o) TCGv_i32 r1 = tcg_constant_i32(get_field(s, r1)); TCGv_i32 r3 = tcg_constant_i32(get_field(s, r3)); - gen_helper_stctl(cpu_env, r1, o->in2, r3); + gen_helper_stctl(tcg_env, r1, o->in2, r3); return DISAS_NEXT; } static DisasJumpType op_stidp(DisasContext *s, DisasOps *o) { - tcg_gen_ld_i64(o->out, cpu_env, offsetof(CPUS390XState, cpuid)); + tcg_gen_ld_i64(o->out, tcg_env, offsetof(CPUS390XState, cpuid)); return DISAS_NEXT; } static DisasJumpType op_spt(DisasContext *s, DisasOps *o) { - gen_helper_spt(cpu_env, o->in2); + gen_helper_spt(tcg_env, o->in2); return DISAS_NEXT; } static DisasJumpType op_stfl(DisasContext *s, DisasOps *o) { - gen_helper_stfl(cpu_env); + gen_helper_stfl(tcg_env); return DISAS_NEXT; } static DisasJumpType op_stpt(DisasContext *s, DisasOps *o) { - gen_helper_stpt(o->out, cpu_env); + gen_helper_stpt(o->out, tcg_env); return DISAS_NEXT; } static DisasJumpType op_stsi(DisasContext *s, DisasOps *o) { - gen_helper_stsi(cc_op, cpu_env, o->in2, regs[0], regs[1]); + gen_helper_stsi(cc_op, tcg_env, o->in2, regs[0], regs[1]); set_cc_static(s); return DISAS_NEXT; } static DisasJumpType op_spx(DisasContext *s, DisasOps *o) { - gen_helper_spx(cpu_env, o->in2); + gen_helper_spx(tcg_env, o->in2); return DISAS_NEXT; } static DisasJumpType op_xsch(DisasContext *s, DisasOps *o) { - gen_helper_xsch(cpu_env, regs[1]); + gen_helper_xsch(tcg_env, regs[1]); set_cc_static(s); return DISAS_NEXT; } static DisasJumpType op_csch(DisasContext *s, DisasOps *o) { - gen_helper_csch(cpu_env, regs[1]); + gen_helper_csch(tcg_env, regs[1]); set_cc_static(s); return DISAS_NEXT; } static DisasJumpType op_hsch(DisasContext *s, DisasOps *o) { - gen_helper_hsch(cpu_env, regs[1]); + gen_helper_hsch(tcg_env, regs[1]); set_cc_static(s); return DISAS_NEXT; } static DisasJumpType op_msch(DisasContext *s, DisasOps *o) { - gen_helper_msch(cpu_env, regs[1], o->in2); + gen_helper_msch(tcg_env, regs[1], o->in2); set_cc_static(s); return DISAS_NEXT; } static DisasJumpType op_rchp(DisasContext *s, DisasOps *o) { - gen_helper_rchp(cpu_env, regs[1]); + gen_helper_rchp(tcg_env, regs[1]); set_cc_static(s); return DISAS_NEXT; } static DisasJumpType op_rsch(DisasContext *s, DisasOps *o) { - gen_helper_rsch(cpu_env, regs[1]); + gen_helper_rsch(tcg_env, regs[1]); set_cc_static(s); return DISAS_NEXT; } static DisasJumpType op_sal(DisasContext *s, DisasOps *o) { - gen_helper_sal(cpu_env, regs[1]); + gen_helper_sal(tcg_env, regs[1]); return DISAS_NEXT; } static DisasJumpType op_schm(DisasContext *s, DisasOps *o) { - gen_helper_schm(cpu_env, regs[1], regs[2], o->in2); + gen_helper_schm(tcg_env, regs[1], regs[2], o->in2); return DISAS_NEXT; } @@ -4318,49 +4318,49 @@ static DisasJumpType op_stcps(DisasContext *s, DisasOps *o) static DisasJumpType op_ssch(DisasContext *s, DisasOps *o) { - gen_helper_ssch(cpu_env, regs[1], o->in2); + gen_helper_ssch(tcg_env, regs[1], o->in2); set_cc_static(s); return DISAS_NEXT; } static DisasJumpType op_stsch(DisasContext *s, DisasOps *o) { - gen_helper_stsch(cpu_env, regs[1], o->in2); + gen_helper_stsch(tcg_env, regs[1], o->in2); set_cc_static(s); return DISAS_NEXT; } static DisasJumpType op_stcrw(DisasContext *s, DisasOps *o) { - gen_helper_stcrw(cpu_env, o->in2); + gen_helper_stcrw(tcg_env, o->in2); set_cc_static(s); return DISAS_NEXT; } static DisasJumpType op_tpi(DisasContext *s, DisasOps *o) { - gen_helper_tpi(cc_op, cpu_env, o->addr1); + gen_helper_tpi(cc_op, tcg_env, o->addr1); set_cc_static(s); return DISAS_NEXT; } static DisasJumpType op_tsch(DisasContext *s, DisasOps *o) { - gen_helper_tsch(cpu_env, regs[1], o->in2); + gen_helper_tsch(tcg_env, regs[1], o->in2); set_cc_static(s); return DISAS_NEXT; } static DisasJumpType op_chsc(DisasContext *s, DisasOps *o) { - gen_helper_chsc(cpu_env, o->in2); + gen_helper_chsc(tcg_env, o->in2); set_cc_static(s); return DISAS_NEXT; } static DisasJumpType op_stpx(DisasContext *s, DisasOps *o) { - tcg_gen_ld_i64(o->out, cpu_env, offsetof(CPUS390XState, psa)); + tcg_gen_ld_i64(o->out, tcg_env, offsetof(CPUS390XState, psa)); tcg_gen_andi_i64(o->out, o->out, 0x7fffe000); return DISAS_NEXT; } @@ -4397,7 +4397,7 @@ static DisasJumpType op_stura(DisasContext *s, DisasOps *o) if (s->base.tb->flags & FLAG_MASK_PER) { update_psw_addr(s); - gen_helper_per_store_real(cpu_env); + gen_helper_per_store_real(tcg_env); } return DISAS_NEXT; } @@ -4405,7 +4405,7 @@ static DisasJumpType op_stura(DisasContext *s, DisasOps *o) static DisasJumpType op_stfle(DisasContext *s, DisasOps *o) { - gen_helper_stfle(cc_op, cpu_env, o->in2); + gen_helper_stfle(cc_op, tcg_env, o->in2); set_cc_static(s); return DISAS_NEXT; } @@ -4441,7 +4441,7 @@ static DisasJumpType op_stam(DisasContext *s, DisasOps *o) TCGv_i32 r1 = tcg_constant_i32(get_field(s, r1)); TCGv_i32 r3 = tcg_constant_i32(get_field(s, r3)); - gen_helper_stam(cpu_env, r1, o->in2, r3); + gen_helper_stam(tcg_env, r1, o->in2, r3); return DISAS_NEXT; } @@ -4548,7 +4548,7 @@ static DisasJumpType op_srst(DisasContext *s, DisasOps *o) TCGv_i32 r1 = tcg_constant_i32(get_field(s, r1)); TCGv_i32 r2 = tcg_constant_i32(get_field(s, r2)); - gen_helper_srst(cpu_env, r1, r2); + gen_helper_srst(tcg_env, r1, r2); set_cc_static(s); return DISAS_NEXT; } @@ -4558,7 +4558,7 @@ static DisasJumpType op_srstu(DisasContext *s, DisasOps *o) TCGv_i32 r1 = tcg_constant_i32(get_field(s, r1)); TCGv_i32 r2 = tcg_constant_i32(get_field(s, r2)); - gen_helper_srstu(cpu_env, r1, r2); + gen_helper_srstu(tcg_env, r1, r2); set_cc_static(s); return DISAS_NEXT; } @@ -4631,10 +4631,10 @@ static DisasJumpType op_svc(DisasContext *s, DisasOps *o) update_cc_op(s); t = tcg_constant_i32(get_field(s, i1) & 0xff); - tcg_gen_st_i32(t, cpu_env, offsetof(CPUS390XState, int_svc_code)); + tcg_gen_st_i32(t, tcg_env, offsetof(CPUS390XState, int_svc_code)); t = tcg_constant_i32(s->ilen); - tcg_gen_st_i32(t, cpu_env, offsetof(CPUS390XState, int_svc_ilen)); + tcg_gen_st_i32(t, tcg_env, offsetof(CPUS390XState, int_svc_ilen)); gen_exception(EXCP_SVC); return DISAS_NORETURN; @@ -4652,21 +4652,21 @@ static DisasJumpType op_tam(DisasContext *s, DisasOps *o) static DisasJumpType op_tceb(DisasContext *s, DisasOps *o) { - gen_helper_tceb(cc_op, cpu_env, o->in1, o->in2); + gen_helper_tceb(cc_op, tcg_env, o->in1, o->in2); set_cc_static(s); return DISAS_NEXT; } static DisasJumpType op_tcdb(DisasContext *s, DisasOps *o) { - gen_helper_tcdb(cc_op, cpu_env, o->in1, o->in2); + gen_helper_tcdb(cc_op, tcg_env, o->in1, o->in2); set_cc_static(s); return DISAS_NEXT; } static DisasJumpType op_tcxb(DisasContext *s, DisasOps *o) { - gen_helper_tcxb(cc_op, cpu_env, o->in1_128, o->in2); + gen_helper_tcxb(cc_op, tcg_env, o->in1_128, o->in2); set_cc_static(s); return DISAS_NEXT; } @@ -4675,14 +4675,14 @@ static DisasJumpType op_tcxb(DisasContext *s, DisasOps *o) static DisasJumpType op_testblock(DisasContext *s, DisasOps *o) { - gen_helper_testblock(cc_op, cpu_env, o->in2); + gen_helper_testblock(cc_op, tcg_env, o->in2); set_cc_static(s); return DISAS_NEXT; } static DisasJumpType op_tprot(DisasContext *s, DisasOps *o) { - gen_helper_tprot(cc_op, cpu_env, o->addr1, o->in2); + gen_helper_tprot(cc_op, tcg_env, o->addr1, o->in2); set_cc_static(s); return DISAS_NEXT; } @@ -4693,7 +4693,7 @@ static DisasJumpType op_tp(DisasContext *s, DisasOps *o) { TCGv_i32 l1 = tcg_constant_i32(get_field(s, l1) + 1); - gen_helper_tp(cc_op, cpu_env, o->addr1, l1); + gen_helper_tp(cc_op, tcg_env, o->addr1, l1); set_cc_static(s); return DISAS_NEXT; } @@ -4702,7 +4702,7 @@ static DisasJumpType op_tr(DisasContext *s, DisasOps *o) { TCGv_i32 l = tcg_constant_i32(get_field(s, l1)); - gen_helper_tr(cpu_env, l, o->addr1, o->in2); + gen_helper_tr(tcg_env, l, o->addr1, o->in2); set_cc_static(s); return DISAS_NEXT; } @@ -4711,7 +4711,7 @@ static DisasJumpType op_tre(DisasContext *s, DisasOps *o) { TCGv_i128 pair = tcg_temp_new_i128(); - gen_helper_tre(pair, cpu_env, o->out, o->out2, o->in2); + gen_helper_tre(pair, tcg_env, o->out, o->out2, o->in2); tcg_gen_extr_i128_i64(o->out2, o->out, pair); set_cc_static(s); return DISAS_NEXT; @@ -4721,7 +4721,7 @@ static DisasJumpType op_trt(DisasContext *s, DisasOps *o) { TCGv_i32 l = tcg_constant_i32(get_field(s, l1)); - gen_helper_trt(cc_op, cpu_env, l, o->addr1, o->in2); + gen_helper_trt(cc_op, tcg_env, l, o->addr1, o->in2); set_cc_static(s); return DISAS_NEXT; } @@ -4730,7 +4730,7 @@ static DisasJumpType op_trtr(DisasContext *s, DisasOps *o) { TCGv_i32 l = tcg_constant_i32(get_field(s, l1)); - gen_helper_trtr(cc_op, cpu_env, l, o->addr1, o->in2); + gen_helper_trtr(cc_op, tcg_env, l, o->addr1, o->in2); set_cc_static(s); return DISAS_NEXT; } @@ -4756,7 +4756,7 @@ static DisasJumpType op_trXX(DisasContext *s, DisasOps *o) tcg_gen_ext16u_i32(tst, tst); } } - gen_helper_trXX(cc_op, cpu_env, r1, r2, tst, sizes); + gen_helper_trXX(cc_op, tcg_env, r1, r2, tst, sizes); set_cc_static(s); return DISAS_NEXT; @@ -4776,7 +4776,7 @@ static DisasJumpType op_unpk(DisasContext *s, DisasOps *o) { TCGv_i32 l = tcg_constant_i32(get_field(s, l1)); - gen_helper_unpk(cpu_env, l, o->addr1, o->in2); + gen_helper_unpk(tcg_env, l, o->addr1, o->in2); return DISAS_NEXT; } @@ -4791,7 +4791,7 @@ static DisasJumpType op_unpka(DisasContext *s, DisasOps *o) return DISAS_NORETURN; } l = tcg_constant_i32(l1); - gen_helper_unpka(cc_op, cpu_env, o->addr1, l, o->in2); + gen_helper_unpka(cc_op, tcg_env, o->addr1, l, o->in2); set_cc_static(s); return DISAS_NEXT; } @@ -4807,7 +4807,7 @@ static DisasJumpType op_unpku(DisasContext *s, DisasOps *o) return DISAS_NORETURN; } l = tcg_constant_i32(l1); - gen_helper_unpku(cc_op, cpu_env, o->addr1, l, o->in2); + gen_helper_unpku(cc_op, tcg_env, o->addr1, l, o->in2); set_cc_static(s); return DISAS_NEXT; } @@ -4860,7 +4860,7 @@ static DisasJumpType op_xc(DisasContext *s, DisasOps *o) /* But in general we'll defer to a helper. */ o->in2 = get_address(s, 0, b2, d2); t32 = tcg_constant_i32(l); - gen_helper_xc(cc_op, cpu_env, t32, o->addr1, o->in2); + gen_helper_xc(cc_op, tcg_env, t32, o->addr1, o->in2); set_cc_static(s); return DISAS_NEXT; } @@ -4926,7 +4926,7 @@ static DisasJumpType op_clp(DisasContext *s, DisasOps *o) { TCGv_i32 r2 = tcg_constant_i32(get_field(s, r2)); - gen_helper_clp(cpu_env, r2); + gen_helper_clp(tcg_env, r2); set_cc_static(s); return DISAS_NEXT; } @@ -4936,7 +4936,7 @@ static DisasJumpType op_pcilg(DisasContext *s, DisasOps *o) TCGv_i32 r1 = tcg_constant_i32(get_field(s, r1)); TCGv_i32 r2 = tcg_constant_i32(get_field(s, r2)); - gen_helper_pcilg(cpu_env, r1, r2); + gen_helper_pcilg(tcg_env, r1, r2); set_cc_static(s); return DISAS_NEXT; } @@ -4946,7 +4946,7 @@ static DisasJumpType op_pcistg(DisasContext *s, DisasOps *o) TCGv_i32 r1 = tcg_constant_i32(get_field(s, r1)); TCGv_i32 r2 = tcg_constant_i32(get_field(s, r2)); - gen_helper_pcistg(cpu_env, r1, r2); + gen_helper_pcistg(tcg_env, r1, r2); set_cc_static(s); return DISAS_NEXT; } @@ -4956,14 +4956,14 @@ static DisasJumpType op_stpcifc(DisasContext *s, DisasOps *o) TCGv_i32 r1 = tcg_constant_i32(get_field(s, r1)); TCGv_i32 ar = tcg_constant_i32(get_field(s, b2)); - gen_helper_stpcifc(cpu_env, r1, o->addr1, ar); + gen_helper_stpcifc(tcg_env, r1, o->addr1, ar); set_cc_static(s); return DISAS_NEXT; } static DisasJumpType op_sic(DisasContext *s, DisasOps *o) { - gen_helper_sic(cpu_env, o->in1, o->in2); + gen_helper_sic(tcg_env, o->in1, o->in2); return DISAS_NEXT; } @@ -4972,7 +4972,7 @@ static DisasJumpType op_rpcit(DisasContext *s, DisasOps *o) TCGv_i32 r1 = tcg_constant_i32(get_field(s, r1)); TCGv_i32 r2 = tcg_constant_i32(get_field(s, r2)); - gen_helper_rpcit(cpu_env, r1, r2); + gen_helper_rpcit(tcg_env, r1, r2); set_cc_static(s); return DISAS_NEXT; } @@ -4983,7 +4983,7 @@ static DisasJumpType op_pcistb(DisasContext *s, DisasOps *o) TCGv_i32 r3 = tcg_constant_i32(get_field(s, r3)); TCGv_i32 ar = tcg_constant_i32(get_field(s, b2)); - gen_helper_pcistb(cpu_env, r1, r3, o->addr1, ar); + gen_helper_pcistb(tcg_env, r1, r3, o->addr1, ar); set_cc_static(s); return DISAS_NEXT; } @@ -4993,7 +4993,7 @@ static DisasJumpType op_mpcifc(DisasContext *s, DisasOps *o) TCGv_i32 r1 = tcg_constant_i32(get_field(s, r1)); TCGv_i32 ar = tcg_constant_i32(get_field(s, b2)); - gen_helper_mpcifc(cpu_env, r1, o->addr1, ar); + gen_helper_mpcifc(tcg_env, r1, o->addr1, ar); set_cc_static(s); return DISAS_NEXT; } @@ -6176,7 +6176,7 @@ static const DisasInsn *extract_insn(CPUS390XState *env, DisasContext *s) if (unlikely(s->ex_value)) { /* Drop the EX data now, so that it's clear on exception paths. */ - tcg_gen_st_i64(tcg_constant_i64(0), cpu_env, + tcg_gen_st_i64(tcg_constant_i64(0), tcg_env, offsetof(CPUS390XState, ex_value)); /* Extract the values saved by EXECUTE. */ @@ -6310,7 +6310,7 @@ static DisasJumpType translate_one(CPUS390XState *env, DisasContext *s) #ifndef CONFIG_USER_ONLY if (s->base.tb->flags & FLAG_MASK_PER) { TCGv_i64 addr = tcg_constant_i64(s->base.pc_next); - gen_helper_per_ifetch(cpu_env, addr); + gen_helper_per_ifetch(tcg_env, addr); } #endif @@ -6415,7 +6415,7 @@ static DisasJumpType translate_one(CPUS390XState *env, DisasContext *s) } /* Call the helper to check for a possible PER exception. */ - gen_helper_per_check_exception(cpu_env); + gen_helper_per_check_exception(tcg_env); } #endif diff --git a/target/s390x/tcg/translate_vx.c.inc b/target/s390x/tcg/translate_vx.c.inc index ec94d39df0..e073e5ad3a 100644 --- a/target/s390x/tcg/translate_vx.c.inc +++ b/target/s390x/tcg/translate_vx.c.inc @@ -36,7 +36,7 @@ * * CC handling: * As gvec ool-helpers can currently not return values (besides via - * pointers like vectors or cpu_env), whenever we have to set the CC and + * pointers like vectors or tcg_env), whenever we have to set the CC and * can't conclude the value from the result vector, we will directly * set it in "env->cc_op" and mark it as static via set_cc_static()". * Whenever this is done, the helper writes globals (cc_op). @@ -69,26 +69,26 @@ static void read_vec_element_i64(TCGv_i64 dst, uint8_t reg, uint8_t enr, switch ((unsigned)memop) { case ES_8: - tcg_gen_ld8u_i64(dst, cpu_env, offs); + tcg_gen_ld8u_i64(dst, tcg_env, offs); break; case ES_16: - tcg_gen_ld16u_i64(dst, cpu_env, offs); + tcg_gen_ld16u_i64(dst, tcg_env, offs); break; case ES_32: - tcg_gen_ld32u_i64(dst, cpu_env, offs); + tcg_gen_ld32u_i64(dst, tcg_env, offs); break; case ES_8 | MO_SIGN: - tcg_gen_ld8s_i64(dst, cpu_env, offs); + tcg_gen_ld8s_i64(dst, tcg_env, offs); break; case ES_16 | MO_SIGN: - tcg_gen_ld16s_i64(dst, cpu_env, offs); + tcg_gen_ld16s_i64(dst, tcg_env, offs); break; case ES_32 | MO_SIGN: - tcg_gen_ld32s_i64(dst, cpu_env, offs); + tcg_gen_ld32s_i64(dst, tcg_env, offs); break; case ES_64: case ES_64 | MO_SIGN: - tcg_gen_ld_i64(dst, cpu_env, offs); + tcg_gen_ld_i64(dst, tcg_env, offs); break; default: g_assert_not_reached(); @@ -102,20 +102,20 @@ static void read_vec_element_i32(TCGv_i32 dst, uint8_t reg, uint8_t enr, switch (memop) { case ES_8: - tcg_gen_ld8u_i32(dst, cpu_env, offs); + tcg_gen_ld8u_i32(dst, tcg_env, offs); break; case ES_16: - tcg_gen_ld16u_i32(dst, cpu_env, offs); + tcg_gen_ld16u_i32(dst, tcg_env, offs); break; case ES_8 | MO_SIGN: - tcg_gen_ld8s_i32(dst, cpu_env, offs); + tcg_gen_ld8s_i32(dst, tcg_env, offs); break; case ES_16 | MO_SIGN: - tcg_gen_ld16s_i32(dst, cpu_env, offs); + tcg_gen_ld16s_i32(dst, tcg_env, offs); break; case ES_32: case ES_32 | MO_SIGN: - tcg_gen_ld_i32(dst, cpu_env, offs); + tcg_gen_ld_i32(dst, tcg_env, offs); break; default: g_assert_not_reached(); @@ -129,16 +129,16 @@ static void write_vec_element_i64(TCGv_i64 src, int reg, uint8_t enr, switch (memop) { case ES_8: - tcg_gen_st8_i64(src, cpu_env, offs); + tcg_gen_st8_i64(src, tcg_env, offs); break; case ES_16: - tcg_gen_st16_i64(src, cpu_env, offs); + tcg_gen_st16_i64(src, tcg_env, offs); break; case ES_32: - tcg_gen_st32_i64(src, cpu_env, offs); + tcg_gen_st32_i64(src, tcg_env, offs); break; case ES_64: - tcg_gen_st_i64(src, cpu_env, offs); + tcg_gen_st_i64(src, tcg_env, offs); break; default: g_assert_not_reached(); @@ -152,13 +152,13 @@ static void write_vec_element_i32(TCGv_i32 src, int reg, uint8_t enr, switch (memop) { case ES_8: - tcg_gen_st8_i32(src, cpu_env, offs); + tcg_gen_st8_i32(src, tcg_env, offs); break; case ES_16: - tcg_gen_st16_i32(src, cpu_env, offs); + tcg_gen_st16_i32(src, tcg_env, offs); break; case ES_32: - tcg_gen_st_i32(src, cpu_env, offs); + tcg_gen_st_i32(src, tcg_env, offs); break; default: g_assert_not_reached(); @@ -173,16 +173,16 @@ static void get_vec_element_ptr_i64(TCGv_ptr ptr, uint8_t reg, TCGv_i64 enr, /* mask off invalid parts from the element nr */ tcg_gen_andi_i64(tmp, enr, NUM_VEC_ELEMENTS(es) - 1); - /* convert it to an element offset relative to cpu_env (vec_reg_offset() */ + /* convert it to an element offset relative to tcg_env (vec_reg_offset() */ tcg_gen_shli_i64(tmp, tmp, es); #if !HOST_BIG_ENDIAN tcg_gen_xori_i64(tmp, tmp, 8 - NUM_VEC_ELEMENT_BYTES(es)); #endif tcg_gen_addi_i64(tmp, tmp, vec_full_reg_offset(reg)); - /* generate the final ptr by adding cpu_env */ + /* generate the final ptr by adding tcg_env */ tcg_gen_trunc_i64_ptr(ptr, tmp); - tcg_gen_add_ptr(ptr, ptr, cpu_env); + tcg_gen_add_ptr(ptr, ptr, tcg_env); } #define gen_gvec_2(v1, v2, gen) \ @@ -754,8 +754,8 @@ static DisasJumpType op_vlbb(DisasContext *s, DisasOps *o) tcg_gen_ori_i64(bytes, o->addr1, -block_size); tcg_gen_neg_i64(bytes, bytes); - tcg_gen_addi_ptr(a0, cpu_env, v1_offs); - gen_helper_vll(cpu_env, a0, o->addr1, bytes); + tcg_gen_addi_ptr(a0, tcg_env, v1_offs); + gen_helper_vll(tcg_env, a0, o->addr1, bytes); return DISAS_NEXT; } @@ -812,8 +812,8 @@ static DisasJumpType op_vll(DisasContext *s, DisasOps *o) /* convert highest index into an actual length */ tcg_gen_addi_i64(o->in2, o->in2, 1); - tcg_gen_addi_ptr(a0, cpu_env, v1_offs); - gen_helper_vll(cpu_env, a0, o->addr1, o->in2); + tcg_gen_addi_ptr(a0, tcg_env, v1_offs); + gen_helper_vll(tcg_env, a0, o->addr1, o->in2); return DISAS_NEXT; } @@ -898,7 +898,7 @@ static DisasJumpType op_vpk(DisasContext *s, DisasOps *o) switch (s->fields.op2) { case 0x97: if (get_field(s, m5) & 0x1) { - gen_gvec_3_ptr(v1, v2, v3, cpu_env, 0, vpks_cc[es - 1]); + gen_gvec_3_ptr(v1, v2, v3, tcg_env, 0, vpks_cc[es - 1]); set_cc_static(s); } else { gen_gvec_3_ool(v1, v2, v3, 0, vpks[es - 1]); @@ -906,7 +906,7 @@ static DisasJumpType op_vpk(DisasContext *s, DisasOps *o) break; case 0x95: if (get_field(s, m5) & 0x1) { - gen_gvec_3_ptr(v1, v2, v3, cpu_env, 0, vpkls_cc[es - 1]); + gen_gvec_3_ptr(v1, v2, v3, tcg_env, 0, vpkls_cc[es - 1]); set_cc_static(s); } else { gen_gvec_3_ool(v1, v2, v3, 0, vpkls[es - 1]); @@ -1058,7 +1058,7 @@ static DisasJumpType op_vst(DisasContext *s, DisasOps *o) TCGv_i64 tmp; /* Probe write access before actually modifying memory */ - gen_helper_probe_write_access(cpu_env, o->addr1, + gen_helper_probe_write_access(tcg_env, o->addr1, tcg_constant_i64(16)); tmp = tcg_temp_new_i64(); @@ -1098,7 +1098,7 @@ static DisasJumpType op_vstbr(DisasContext *s, DisasOps *o) } /* Probe write access before actually modifying memory */ - gen_helper_probe_write_access(cpu_env, o->addr1, tcg_constant_i64(16)); + gen_helper_probe_write_access(tcg_env, o->addr1, tcg_constant_i64(16)); t0 = tcg_temp_new_i64(); t1 = tcg_temp_new_i64(); @@ -1169,7 +1169,7 @@ static DisasJumpType op_vster(DisasContext *s, DisasOps *o) } /* Probe write access before actually modifying memory */ - gen_helper_probe_write_access(cpu_env, o->addr1, tcg_constant_i64(16)); + gen_helper_probe_write_access(tcg_env, o->addr1, tcg_constant_i64(16)); /* Begin with the two doublewords swapped... */ t0 = tcg_temp_new_i64(); @@ -1211,7 +1211,7 @@ static DisasJumpType op_vstm(DisasContext *s, DisasOps *o) } /* Probe write access before actually modifying memory */ - gen_helper_probe_write_access(cpu_env, o->addr1, + gen_helper_probe_write_access(tcg_env, o->addr1, tcg_constant_i64((v3 - v1 + 1) * 16)); tmp = tcg_temp_new_i64(); @@ -1236,8 +1236,8 @@ static DisasJumpType op_vstl(DisasContext *s, DisasOps *o) /* convert highest index into an actual length */ tcg_gen_addi_i64(o->in2, o->in2, 1); - tcg_gen_addi_ptr(a0, cpu_env, v1_offs); - gen_helper_vstl(cpu_env, a0, o->addr1, o->in2); + tcg_gen_addi_ptr(a0, tcg_env, v1_offs); + gen_helper_vstl(tcg_env, a0, o->addr1, o->in2); return DISAS_NEXT; } @@ -2479,7 +2479,7 @@ static DisasJumpType op_vsum(DisasContext *s, DisasOps *o) static DisasJumpType op_vtm(DisasContext *s, DisasOps *o) { gen_gvec_2_ptr(get_field(s, v1), get_field(s, v2), - cpu_env, 0, gen_helper_gvec_vtm); + tcg_env, 0, gen_helper_gvec_vtm); set_cc_static(s); return DISAS_NEXT; } @@ -2505,7 +2505,7 @@ static DisasJumpType op_vfae(DisasContext *s, DisasOps *o) if (extract32(m5, 0, 1)) { gen_gvec_3_ptr(get_field(s, v1), get_field(s, v2), - get_field(s, v3), cpu_env, m5, g_cc[es]); + get_field(s, v3), tcg_env, m5, g_cc[es]); set_cc_static(s); } else { gen_gvec_3_ool(get_field(s, v1), get_field(s, v2), @@ -2536,7 +2536,7 @@ static DisasJumpType op_vfee(DisasContext *s, DisasOps *o) if (extract32(m5, 0, 1)) { gen_gvec_3_ptr(get_field(s, v1), get_field(s, v2), - get_field(s, v3), cpu_env, m5, g_cc[es]); + get_field(s, v3), tcg_env, m5, g_cc[es]); set_cc_static(s); } else { gen_gvec_3_ool(get_field(s, v1), get_field(s, v2), @@ -2567,7 +2567,7 @@ static DisasJumpType op_vfene(DisasContext *s, DisasOps *o) if (extract32(m5, 0, 1)) { gen_gvec_3_ptr(get_field(s, v1), get_field(s, v2), - get_field(s, v3), cpu_env, m5, g_cc[es]); + get_field(s, v3), tcg_env, m5, g_cc[es]); set_cc_static(s); } else { gen_gvec_3_ool(get_field(s, v1), get_field(s, v2), @@ -2598,7 +2598,7 @@ static DisasJumpType op_vistr(DisasContext *s, DisasOps *o) if (extract32(m5, 0, 1)) { gen_gvec_2_ptr(get_field(s, v1), get_field(s, v2), - cpu_env, 0, g_cc[es]); + tcg_env, 0, g_cc[es]); set_cc_static(s); } else { gen_gvec_2_ool(get_field(s, v1), get_field(s, v2), 0, @@ -2641,11 +2641,11 @@ static DisasJumpType op_vstrc(DisasContext *s, DisasOps *o) if (extract32(m6, 2, 1)) { gen_gvec_4_ptr(get_field(s, v1), get_field(s, v2), get_field(s, v3), get_field(s, v4), - cpu_env, m6, g_cc_rt[es]); + tcg_env, m6, g_cc_rt[es]); } else { gen_gvec_4_ptr(get_field(s, v1), get_field(s, v2), get_field(s, v3), get_field(s, v4), - cpu_env, m6, g_cc[es]); + tcg_env, m6, g_cc[es]); } set_cc_static(s); } else { @@ -2682,7 +2682,7 @@ static DisasJumpType op_vstrs(DisasContext *s, DisasOps *o) gen_gvec_4_ptr(get_field(s, v1), get_field(s, v2), get_field(s, v3), get_field(s, v4), - cpu_env, 0, fns[es][zs]); + tcg_env, 0, fns[es][zs]); set_cc_static(s); return DISAS_NEXT; } @@ -2780,7 +2780,7 @@ static DisasJumpType op_vfa(DisasContext *s, DisasOps *o) } gen_gvec_3_ptr(get_field(s, v1), get_field(s, v2), - get_field(s, v3), cpu_env, m5, fn); + get_field(s, v3), tcg_env, m5, fn); return DISAS_NEXT; } @@ -2822,7 +2822,7 @@ static DisasJumpType op_wfc(DisasContext *s, DisasOps *o) return DISAS_NORETURN; } - gen_gvec_2_ptr(get_field(s, v1), get_field(s, v2), cpu_env, 0, fn); + gen_gvec_2_ptr(get_field(s, v1), get_field(s, v2), tcg_env, 0, fn); set_cc_static(s); return DISAS_NEXT; } @@ -2893,7 +2893,7 @@ static DisasJumpType op_vfc(DisasContext *s, DisasOps *o) } gen_gvec_3_ptr(get_field(s, v1), get_field(s, v2), get_field(s, v3), - cpu_env, m5, fn); + tcg_env, m5, fn); if (cs) { set_cc_static(s); } @@ -3007,7 +3007,7 @@ static DisasJumpType op_vcdg(DisasContext *s, DisasOps *o) return DISAS_NORETURN; } - gen_gvec_2_ptr(get_field(s, v1), get_field(s, v2), cpu_env, + gen_gvec_2_ptr(get_field(s, v1), get_field(s, v2), tcg_env, deposit32(m4, 4, 4, erm), fn); return DISAS_NEXT; } @@ -3036,7 +3036,7 @@ static DisasJumpType op_vfll(DisasContext *s, DisasOps *o) return DISAS_NORETURN; } - gen_gvec_2_ptr(get_field(s, v1), get_field(s, v2), cpu_env, m4, fn); + gen_gvec_2_ptr(get_field(s, v1), get_field(s, v2), tcg_env, m4, fn); return DISAS_NEXT; } @@ -3080,7 +3080,7 @@ static DisasJumpType op_vfmax(DisasContext *s, DisasOps *o) } gen_gvec_3_ptr(get_field(s, v1), get_field(s, v2), get_field(s, v3), - cpu_env, deposit32(m5, 4, 4, m6), fn); + tcg_env, deposit32(m5, 4, 4, m6), fn); return DISAS_NEXT; } @@ -3169,7 +3169,7 @@ static DisasJumpType op_vfma(DisasContext *s, DisasOps *o) } gen_gvec_4_ptr(get_field(s, v1), get_field(s, v2), - get_field(s, v3), get_field(s, v4), cpu_env, m5, fn); + get_field(s, v3), get_field(s, v4), tcg_env, m5, fn); return DISAS_NEXT; } @@ -3291,7 +3291,7 @@ static DisasJumpType op_vfsq(DisasContext *s, DisasOps *o) return DISAS_NORETURN; } - gen_gvec_2_ptr(get_field(s, v1), get_field(s, v2), cpu_env, m4, fn); + gen_gvec_2_ptr(get_field(s, v1), get_field(s, v2), tcg_env, m4, fn); return DISAS_NEXT; } @@ -3325,7 +3325,7 @@ static DisasJumpType op_vftci(DisasContext *s, DisasOps *o) return DISAS_NORETURN; } - gen_gvec_2_ptr(get_field(s, v1), get_field(s, v2), cpu_env, + gen_gvec_2_ptr(get_field(s, v1), get_field(s, v2), tcg_env, deposit32(m5, 4, 12, i3), fn); set_cc_static(s); return DISAS_NEXT; diff --git a/target/sh4/translate.c b/target/sh4/translate.c index c1e590feb3..30e3ea509b 100644 --- a/target/sh4/translate.c +++ b/target/sh4/translate.c @@ -96,63 +96,63 @@ void sh4_translate_init(void) }; for (i = 0; i < 24; i++) { - cpu_gregs[i] = tcg_global_mem_new_i32(cpu_env, + cpu_gregs[i] = tcg_global_mem_new_i32(tcg_env, offsetof(CPUSH4State, gregs[i]), gregnames[i]); } memcpy(cpu_gregs + 24, cpu_gregs + 8, 8 * sizeof(TCGv)); - cpu_pc = tcg_global_mem_new_i32(cpu_env, + cpu_pc = tcg_global_mem_new_i32(tcg_env, offsetof(CPUSH4State, pc), "PC"); - cpu_sr = tcg_global_mem_new_i32(cpu_env, + cpu_sr = tcg_global_mem_new_i32(tcg_env, offsetof(CPUSH4State, sr), "SR"); - cpu_sr_m = tcg_global_mem_new_i32(cpu_env, + cpu_sr_m = tcg_global_mem_new_i32(tcg_env, offsetof(CPUSH4State, sr_m), "SR_M"); - cpu_sr_q = tcg_global_mem_new_i32(cpu_env, + cpu_sr_q = tcg_global_mem_new_i32(tcg_env, offsetof(CPUSH4State, sr_q), "SR_Q"); - cpu_sr_t = tcg_global_mem_new_i32(cpu_env, + cpu_sr_t = tcg_global_mem_new_i32(tcg_env, offsetof(CPUSH4State, sr_t), "SR_T"); - cpu_ssr = tcg_global_mem_new_i32(cpu_env, + cpu_ssr = tcg_global_mem_new_i32(tcg_env, offsetof(CPUSH4State, ssr), "SSR"); - cpu_spc = tcg_global_mem_new_i32(cpu_env, + cpu_spc = tcg_global_mem_new_i32(tcg_env, offsetof(CPUSH4State, spc), "SPC"); - cpu_gbr = tcg_global_mem_new_i32(cpu_env, + cpu_gbr = tcg_global_mem_new_i32(tcg_env, offsetof(CPUSH4State, gbr), "GBR"); - cpu_vbr = tcg_global_mem_new_i32(cpu_env, + cpu_vbr = tcg_global_mem_new_i32(tcg_env, offsetof(CPUSH4State, vbr), "VBR"); - cpu_sgr = tcg_global_mem_new_i32(cpu_env, + cpu_sgr = tcg_global_mem_new_i32(tcg_env, offsetof(CPUSH4State, sgr), "SGR"); - cpu_dbr = tcg_global_mem_new_i32(cpu_env, + cpu_dbr = tcg_global_mem_new_i32(tcg_env, offsetof(CPUSH4State, dbr), "DBR"); - cpu_mach = tcg_global_mem_new_i32(cpu_env, + cpu_mach = tcg_global_mem_new_i32(tcg_env, offsetof(CPUSH4State, mach), "MACH"); - cpu_macl = tcg_global_mem_new_i32(cpu_env, + cpu_macl = tcg_global_mem_new_i32(tcg_env, offsetof(CPUSH4State, macl), "MACL"); - cpu_pr = tcg_global_mem_new_i32(cpu_env, + cpu_pr = tcg_global_mem_new_i32(tcg_env, offsetof(CPUSH4State, pr), "PR"); - cpu_fpscr = tcg_global_mem_new_i32(cpu_env, + cpu_fpscr = tcg_global_mem_new_i32(tcg_env, offsetof(CPUSH4State, fpscr), "FPSCR"); - cpu_fpul = tcg_global_mem_new_i32(cpu_env, + cpu_fpul = tcg_global_mem_new_i32(tcg_env, offsetof(CPUSH4State, fpul), "FPUL"); - cpu_flags = tcg_global_mem_new_i32(cpu_env, + cpu_flags = tcg_global_mem_new_i32(tcg_env, offsetof(CPUSH4State, flags), "_flags_"); - cpu_delayed_pc = tcg_global_mem_new_i32(cpu_env, + cpu_delayed_pc = tcg_global_mem_new_i32(tcg_env, offsetof(CPUSH4State, delayed_pc), "_delayed_pc_"); - cpu_delayed_cond = tcg_global_mem_new_i32(cpu_env, + cpu_delayed_cond = tcg_global_mem_new_i32(tcg_env, offsetof(CPUSH4State, delayed_cond), "_delayed_cond_"); - cpu_lock_addr = tcg_global_mem_new_i32(cpu_env, + cpu_lock_addr = tcg_global_mem_new_i32(tcg_env, offsetof(CPUSH4State, lock_addr), "_lock_addr_"); - cpu_lock_value = tcg_global_mem_new_i32(cpu_env, + cpu_lock_value = tcg_global_mem_new_i32(tcg_env, offsetof(CPUSH4State, lock_value), "_lock_value_"); for (i = 0; i < 32; i++) - cpu_fregs[i] = tcg_global_mem_new_i32(cpu_env, + cpu_fregs[i] = tcg_global_mem_new_i32(tcg_env, offsetof(CPUSH4State, fregs[i]), fregnames[i]); } @@ -416,7 +416,7 @@ static void _decode_opc(DisasContext * ctx) if (opcode != 0x0093 /* ocbi */ && opcode != 0x00c3 /* movca.l */) { - gen_helper_discard_movcal_backup(cpu_env); + gen_helper_discard_movcal_backup(tcg_env); ctx->has_movcal = 0; } } @@ -449,7 +449,7 @@ static void _decode_opc(DisasContext * ctx) return; case 0x0038: /* ldtlb */ CHECK_PRIVILEGED - gen_helper_ldtlb(cpu_env); + gen_helper_ldtlb(tcg_env); return; case 0x002b: /* rte */ CHECK_PRIVILEGED @@ -486,7 +486,7 @@ static void _decode_opc(DisasContext * ctx) case 0x001b: /* sleep */ CHECK_PRIVILEGED tcg_gen_movi_i32(cpu_pc, ctx->base.pc_next + 2); - gen_helper_sleep(cpu_env); + gen_helper_sleep(tcg_env); return; } @@ -807,7 +807,7 @@ static void _decode_opc(DisasContext * ctx) arg1 = tcg_temp_new(); tcg_gen_qemu_ld_i32(arg1, REG(B11_8), ctx->memidx, MO_TESL | MO_ALIGN); - gen_helper_macl(cpu_env, arg0, arg1); + gen_helper_macl(tcg_env, arg0, arg1); tcg_gen_addi_i32(REG(B7_4), REG(B7_4), 4); tcg_gen_addi_i32(REG(B11_8), REG(B11_8), 4); } @@ -821,7 +821,7 @@ static void _decode_opc(DisasContext * ctx) arg1 = tcg_temp_new(); tcg_gen_qemu_ld_i32(arg1, REG(B11_8), ctx->memidx, MO_TESL | MO_ALIGN); - gen_helper_macw(cpu_env, arg0, arg1); + gen_helper_macw(tcg_env, arg0, arg1); tcg_gen_addi_i32(REG(B11_8), REG(B11_8), 2); tcg_gen_addi_i32(REG(B7_4), REG(B7_4), 2); } @@ -1069,49 +1069,49 @@ static void _decode_opc(DisasContext * ctx) gen_load_fpr64(ctx, fp1, B7_4); switch (ctx->opcode & 0xf00f) { case 0xf000: /* fadd Rm,Rn */ - gen_helper_fadd_DT(fp0, cpu_env, fp0, fp1); + gen_helper_fadd_DT(fp0, tcg_env, fp0, fp1); break; case 0xf001: /* fsub Rm,Rn */ - gen_helper_fsub_DT(fp0, cpu_env, fp0, fp1); + gen_helper_fsub_DT(fp0, tcg_env, fp0, fp1); break; case 0xf002: /* fmul Rm,Rn */ - gen_helper_fmul_DT(fp0, cpu_env, fp0, fp1); + gen_helper_fmul_DT(fp0, tcg_env, fp0, fp1); break; case 0xf003: /* fdiv Rm,Rn */ - gen_helper_fdiv_DT(fp0, cpu_env, fp0, fp1); + gen_helper_fdiv_DT(fp0, tcg_env, fp0, fp1); break; case 0xf004: /* fcmp/eq Rm,Rn */ - gen_helper_fcmp_eq_DT(cpu_sr_t, cpu_env, fp0, fp1); + gen_helper_fcmp_eq_DT(cpu_sr_t, tcg_env, fp0, fp1); return; case 0xf005: /* fcmp/gt Rm,Rn */ - gen_helper_fcmp_gt_DT(cpu_sr_t, cpu_env, fp0, fp1); + gen_helper_fcmp_gt_DT(cpu_sr_t, tcg_env, fp0, fp1); return; } gen_store_fpr64(ctx, fp0, B11_8); } else { switch (ctx->opcode & 0xf00f) { case 0xf000: /* fadd Rm,Rn */ - gen_helper_fadd_FT(FREG(B11_8), cpu_env, + gen_helper_fadd_FT(FREG(B11_8), tcg_env, FREG(B11_8), FREG(B7_4)); break; case 0xf001: /* fsub Rm,Rn */ - gen_helper_fsub_FT(FREG(B11_8), cpu_env, + gen_helper_fsub_FT(FREG(B11_8), tcg_env, FREG(B11_8), FREG(B7_4)); break; case 0xf002: /* fmul Rm,Rn */ - gen_helper_fmul_FT(FREG(B11_8), cpu_env, + gen_helper_fmul_FT(FREG(B11_8), tcg_env, FREG(B11_8), FREG(B7_4)); break; case 0xf003: /* fdiv Rm,Rn */ - gen_helper_fdiv_FT(FREG(B11_8), cpu_env, + gen_helper_fdiv_FT(FREG(B11_8), tcg_env, FREG(B11_8), FREG(B7_4)); break; case 0xf004: /* fcmp/eq Rm,Rn */ - gen_helper_fcmp_eq_FT(cpu_sr_t, cpu_env, + gen_helper_fcmp_eq_FT(cpu_sr_t, tcg_env, FREG(B11_8), FREG(B7_4)); return; case 0xf005: /* fcmp/gt Rm,Rn */ - gen_helper_fcmp_gt_FT(cpu_sr_t, cpu_env, + gen_helper_fcmp_gt_FT(cpu_sr_t, tcg_env, FREG(B11_8), FREG(B7_4)); return; } @@ -1121,7 +1121,7 @@ static void _decode_opc(DisasContext * ctx) case 0xf00e: /* fmac FR0,RM,Rn */ CHECK_FPU_ENABLED CHECK_FPSCR_PR_0 - gen_helper_fmac_FT(FREG(B11_8), cpu_env, + gen_helper_fmac_FT(FREG(B11_8), tcg_env, FREG(0), FREG(B7_4), FREG(B11_8)); return; } @@ -1260,7 +1260,7 @@ static void _decode_opc(DisasContext * ctx) CHECK_NOT_DELAY_SLOT gen_save_cpu_state(ctx, true); imm = tcg_constant_i32(B7_0); - gen_helper_trapa(cpu_env, imm); + gen_helper_trapa(tcg_env, imm); ctx->base.is_jmp = DISAS_NORETURN; } return; @@ -1438,7 +1438,7 @@ static void _decode_opc(DisasContext * ctx) LDST(fpul, 0x405a, 0x4056, 0x005a, 0x4052, {CHECK_FPU_ENABLED}) case 0x406a: /* lds Rm,FPSCR */ CHECK_FPU_ENABLED - gen_helper_ld_fpscr(cpu_env, REG(B11_8)); + gen_helper_ld_fpscr(tcg_env, REG(B11_8)); ctx->base.is_jmp = DISAS_STOP; return; case 0x4066: /* lds.l @Rm+,FPSCR */ @@ -1448,7 +1448,7 @@ static void _decode_opc(DisasContext * ctx) tcg_gen_qemu_ld_i32(addr, REG(B11_8), ctx->memidx, MO_TESL | MO_ALIGN); tcg_gen_addi_i32(REG(B11_8), REG(B11_8), 4); - gen_helper_ld_fpscr(cpu_env, addr); + gen_helper_ld_fpscr(tcg_env, addr); ctx->base.is_jmp = DISAS_STOP; } return; @@ -1473,7 +1473,7 @@ static void _decode_opc(DisasContext * ctx) TCGv val = tcg_temp_new(); tcg_gen_qemu_ld_i32(val, REG(B11_8), ctx->memidx, MO_TEUL | MO_ALIGN); - gen_helper_movcal(cpu_env, REG(B11_8), val); + gen_helper_movcal(tcg_env, REG(B11_8), val); tcg_gen_qemu_st_i32(REG(0), REG(B11_8), ctx->memidx, MO_TEUL | MO_ALIGN); } @@ -1560,7 +1560,7 @@ static void _decode_opc(DisasContext * ctx) return; case 0x0093: /* ocbi @Rn */ { - gen_helper_ocbi(cpu_env, REG(B11_8)); + gen_helper_ocbi(tcg_env, REG(B11_8)); } return; case 0x00a3: /* ocbp @Rn */ @@ -1659,11 +1659,11 @@ static void _decode_opc(DisasContext * ctx) goto do_illegal; } fp = tcg_temp_new_i64(); - gen_helper_float_DT(fp, cpu_env, cpu_fpul); + gen_helper_float_DT(fp, tcg_env, cpu_fpul); gen_store_fpr64(ctx, fp, B11_8); } else { - gen_helper_float_FT(FREG(B11_8), cpu_env, cpu_fpul); + gen_helper_float_FT(FREG(B11_8), tcg_env, cpu_fpul); } return; case 0xf03d: /* ftrc FRm/DRm,FPUL - FPSCR: R[PR,Enable.V]/W[Cause,Flag] */ @@ -1675,10 +1675,10 @@ static void _decode_opc(DisasContext * ctx) } fp = tcg_temp_new_i64(); gen_load_fpr64(ctx, fp, B11_8); - gen_helper_ftrc_DT(cpu_fpul, cpu_env, fp); + gen_helper_ftrc_DT(cpu_fpul, tcg_env, fp); } else { - gen_helper_ftrc_FT(cpu_fpul, cpu_env, FREG(B11_8)); + gen_helper_ftrc_FT(cpu_fpul, tcg_env, FREG(B11_8)); } return; case 0xf04d: /* fneg FRn/DRn - FPSCR: Nothing */ @@ -1697,16 +1697,16 @@ static void _decode_opc(DisasContext * ctx) } TCGv_i64 fp = tcg_temp_new_i64(); gen_load_fpr64(ctx, fp, B11_8); - gen_helper_fsqrt_DT(fp, cpu_env, fp); + gen_helper_fsqrt_DT(fp, tcg_env, fp); gen_store_fpr64(ctx, fp, B11_8); } else { - gen_helper_fsqrt_FT(FREG(B11_8), cpu_env, FREG(B11_8)); + gen_helper_fsqrt_FT(FREG(B11_8), tcg_env, FREG(B11_8)); } return; case 0xf07d: /* fsrra FRn */ CHECK_FPU_ENABLED CHECK_FPSCR_PR_0 - gen_helper_fsrra_FT(FREG(B11_8), cpu_env, FREG(B11_8)); + gen_helper_fsrra_FT(FREG(B11_8), tcg_env, FREG(B11_8)); break; case 0xf08d: /* fldi0 FRn - FPSCR: R[PR] */ CHECK_FPU_ENABLED @@ -1722,7 +1722,7 @@ static void _decode_opc(DisasContext * ctx) CHECK_FPU_ENABLED { TCGv_i64 fp = tcg_temp_new_i64(); - gen_helper_fcnvsd_FT_DT(fp, cpu_env, cpu_fpul); + gen_helper_fcnvsd_FT_DT(fp, tcg_env, cpu_fpul); gen_store_fpr64(ctx, fp, B11_8); } return; @@ -1731,7 +1731,7 @@ static void _decode_opc(DisasContext * ctx) { TCGv_i64 fp = tcg_temp_new_i64(); gen_load_fpr64(ctx, fp, B11_8); - gen_helper_fcnvds_DT_FT(cpu_fpul, cpu_env, fp); + gen_helper_fcnvds_DT_FT(cpu_fpul, tcg_env, fp); } return; case 0xf0ed: /* fipr FVm,FVn */ @@ -1740,7 +1740,7 @@ static void _decode_opc(DisasContext * ctx) { TCGv m = tcg_constant_i32((ctx->opcode >> 8) & 3); TCGv n = tcg_constant_i32((ctx->opcode >> 10) & 3); - gen_helper_fipr(cpu_env, m, n); + gen_helper_fipr(tcg_env, m, n); return; } break; @@ -1752,7 +1752,7 @@ static void _decode_opc(DisasContext * ctx) goto do_illegal; } TCGv n = tcg_constant_i32((ctx->opcode >> 10) & 3); - gen_helper_ftrv(cpu_env, n); + gen_helper_ftrv(tcg_env, n); return; } break; @@ -1766,10 +1766,10 @@ static void _decode_opc(DisasContext * ctx) if (ctx->envflags & TB_FLAG_DELAY_SLOT_MASK) { do_illegal_slot: gen_save_cpu_state(ctx, true); - gen_helper_raise_slot_illegal_instruction(cpu_env); + gen_helper_raise_slot_illegal_instruction(tcg_env); } else { gen_save_cpu_state(ctx, true); - gen_helper_raise_illegal_instruction(cpu_env); + gen_helper_raise_illegal_instruction(tcg_env); } ctx->base.is_jmp = DISAS_NORETURN; return; @@ -1777,9 +1777,9 @@ static void _decode_opc(DisasContext * ctx) do_fpu_disabled: gen_save_cpu_state(ctx, true); if (ctx->envflags & TB_FLAG_DELAY_SLOT_MASK) { - gen_helper_raise_slot_fpu_disable(cpu_env); + gen_helper_raise_slot_fpu_disable(tcg_env); } else { - gen_helper_raise_fpu_disable(cpu_env); + gen_helper_raise_fpu_disable(tcg_env); } ctx->base.is_jmp = DISAS_NORETURN; return; @@ -2153,7 +2153,7 @@ static void decode_gusa(DisasContext *ctx, CPUSH4State *env) cpu_exec_step_atomic holding the exclusive lock. */ ctx->envflags |= TB_FLAG_GUSA_EXCLUSIVE; gen_save_cpu_state(ctx, false); - gen_helper_exclusive(cpu_env); + gen_helper_exclusive(tcg_env); ctx->base.is_jmp = DISAS_NORETURN; /* We're not executing an instruction, but we must report one for the diff --git a/target/sparc/translate.c b/target/sparc/translate.c index 3bf0ab8135..71b48cb3b7 100644 --- a/target/sparc/translate.c +++ b/target/sparc/translate.c @@ -187,25 +187,25 @@ static TCGv_i64 gen_dest_fpr_D(DisasContext *dc, unsigned int dst) static void gen_op_load_fpr_QT0(unsigned int src) { - tcg_gen_st_i64(cpu_fpr[src / 2], cpu_env, offsetof(CPUSPARCState, qt0) + + tcg_gen_st_i64(cpu_fpr[src / 2], tcg_env, offsetof(CPUSPARCState, qt0) + offsetof(CPU_QuadU, ll.upper)); - tcg_gen_st_i64(cpu_fpr[src/2 + 1], cpu_env, offsetof(CPUSPARCState, qt0) + + tcg_gen_st_i64(cpu_fpr[src/2 + 1], tcg_env, offsetof(CPUSPARCState, qt0) + offsetof(CPU_QuadU, ll.lower)); } static void gen_op_load_fpr_QT1(unsigned int src) { - tcg_gen_st_i64(cpu_fpr[src / 2], cpu_env, offsetof(CPUSPARCState, qt1) + + tcg_gen_st_i64(cpu_fpr[src / 2], tcg_env, offsetof(CPUSPARCState, qt1) + offsetof(CPU_QuadU, ll.upper)); - tcg_gen_st_i64(cpu_fpr[src/2 + 1], cpu_env, offsetof(CPUSPARCState, qt1) + + tcg_gen_st_i64(cpu_fpr[src/2 + 1], tcg_env, offsetof(CPUSPARCState, qt1) + offsetof(CPU_QuadU, ll.lower)); } static void gen_op_store_QT0_fpr(unsigned int dst) { - tcg_gen_ld_i64(cpu_fpr[dst / 2], cpu_env, offsetof(CPUSPARCState, qt0) + + tcg_gen_ld_i64(cpu_fpr[dst / 2], tcg_env, offsetof(CPUSPARCState, qt0) + offsetof(CPU_QuadU, ll.upper)); - tcg_gen_ld_i64(cpu_fpr[dst/2 + 1], cpu_env, offsetof(CPUSPARCState, qt0) + + tcg_gen_ld_i64(cpu_fpr[dst/2 + 1], tcg_env, offsetof(CPUSPARCState, qt0) + offsetof(CPU_QuadU, ll.lower)); } @@ -443,7 +443,7 @@ static void gen_op_addx_int(DisasContext *dc, TCGv dst, TCGv src1, default: /* We need external help to produce the carry. */ carry_32 = tcg_temp_new_i32(); - gen_helper_compute_C_icc(carry_32, cpu_env); + gen_helper_compute_C_icc(carry_32, tcg_env); break; } @@ -516,7 +516,7 @@ static void gen_op_subx_int(DisasContext *dc, TCGv dst, TCGv src1, default: /* We need external help to produce the carry. */ carry_32 = tcg_temp_new_i32(); - gen_helper_compute_C_icc(carry_32, cpu_env); + gen_helper_compute_C_icc(carry_32, tcg_env); break; } @@ -967,7 +967,7 @@ static void update_psr(DisasContext *dc) { if (dc->cc_op != CC_OP_FLAGS) { dc->cc_op = CC_OP_FLAGS; - gen_helper_compute_psr(cpu_env); + gen_helper_compute_psr(tcg_env); } } @@ -980,13 +980,13 @@ static void save_state(DisasContext *dc) static void gen_exception(DisasContext *dc, int which) { save_state(dc); - gen_helper_raise_exception(cpu_env, tcg_constant_i32(which)); + gen_helper_raise_exception(tcg_env, tcg_constant_i32(which)); dc->base.is_jmp = DISAS_NORETURN; } static void gen_check_align(TCGv addr, int mask) { - gen_helper_check_align(cpu_env, addr, tcg_constant_i32(mask)); + gen_helper_check_align(tcg_env, addr, tcg_constant_i32(mask)); } static void gen_mov_pc_npc(DisasContext *dc) @@ -1120,7 +1120,7 @@ static void gen_compare(DisasCompare *cmp, bool xcc, unsigned int cond, default: do_dynamic: - gen_helper_compute_psr(cpu_env); + gen_helper_compute_psr(tcg_env); dc->cc_op = CC_OP_FLAGS; /* FALLTHRU */ @@ -1425,16 +1425,16 @@ static void gen_op_fcmps(int fccno, TCGv_i32 r_rs1, TCGv_i32 r_rs2) { switch (fccno) { case 0: - gen_helper_fcmps(cpu_fsr, cpu_env, r_rs1, r_rs2); + gen_helper_fcmps(cpu_fsr, tcg_env, r_rs1, r_rs2); break; case 1: - gen_helper_fcmps_fcc1(cpu_fsr, cpu_env, r_rs1, r_rs2); + gen_helper_fcmps_fcc1(cpu_fsr, tcg_env, r_rs1, r_rs2); break; case 2: - gen_helper_fcmps_fcc2(cpu_fsr, cpu_env, r_rs1, r_rs2); + gen_helper_fcmps_fcc2(cpu_fsr, tcg_env, r_rs1, r_rs2); break; case 3: - gen_helper_fcmps_fcc3(cpu_fsr, cpu_env, r_rs1, r_rs2); + gen_helper_fcmps_fcc3(cpu_fsr, tcg_env, r_rs1, r_rs2); break; } } @@ -1443,16 +1443,16 @@ static void gen_op_fcmpd(int fccno, TCGv_i64 r_rs1, TCGv_i64 r_rs2) { switch (fccno) { case 0: - gen_helper_fcmpd(cpu_fsr, cpu_env, r_rs1, r_rs2); + gen_helper_fcmpd(cpu_fsr, tcg_env, r_rs1, r_rs2); break; case 1: - gen_helper_fcmpd_fcc1(cpu_fsr, cpu_env, r_rs1, r_rs2); + gen_helper_fcmpd_fcc1(cpu_fsr, tcg_env, r_rs1, r_rs2); break; case 2: - gen_helper_fcmpd_fcc2(cpu_fsr, cpu_env, r_rs1, r_rs2); + gen_helper_fcmpd_fcc2(cpu_fsr, tcg_env, r_rs1, r_rs2); break; case 3: - gen_helper_fcmpd_fcc3(cpu_fsr, cpu_env, r_rs1, r_rs2); + gen_helper_fcmpd_fcc3(cpu_fsr, tcg_env, r_rs1, r_rs2); break; } } @@ -1461,16 +1461,16 @@ static void gen_op_fcmpq(int fccno) { switch (fccno) { case 0: - gen_helper_fcmpq(cpu_fsr, cpu_env); + gen_helper_fcmpq(cpu_fsr, tcg_env); break; case 1: - gen_helper_fcmpq_fcc1(cpu_fsr, cpu_env); + gen_helper_fcmpq_fcc1(cpu_fsr, tcg_env); break; case 2: - gen_helper_fcmpq_fcc2(cpu_fsr, cpu_env); + gen_helper_fcmpq_fcc2(cpu_fsr, tcg_env); break; case 3: - gen_helper_fcmpq_fcc3(cpu_fsr, cpu_env); + gen_helper_fcmpq_fcc3(cpu_fsr, tcg_env); break; } } @@ -1479,16 +1479,16 @@ static void gen_op_fcmpes(int fccno, TCGv_i32 r_rs1, TCGv_i32 r_rs2) { switch (fccno) { case 0: - gen_helper_fcmpes(cpu_fsr, cpu_env, r_rs1, r_rs2); + gen_helper_fcmpes(cpu_fsr, tcg_env, r_rs1, r_rs2); break; case 1: - gen_helper_fcmpes_fcc1(cpu_fsr, cpu_env, r_rs1, r_rs2); + gen_helper_fcmpes_fcc1(cpu_fsr, tcg_env, r_rs1, r_rs2); break; case 2: - gen_helper_fcmpes_fcc2(cpu_fsr, cpu_env, r_rs1, r_rs2); + gen_helper_fcmpes_fcc2(cpu_fsr, tcg_env, r_rs1, r_rs2); break; case 3: - gen_helper_fcmpes_fcc3(cpu_fsr, cpu_env, r_rs1, r_rs2); + gen_helper_fcmpes_fcc3(cpu_fsr, tcg_env, r_rs1, r_rs2); break; } } @@ -1497,16 +1497,16 @@ static void gen_op_fcmped(int fccno, TCGv_i64 r_rs1, TCGv_i64 r_rs2) { switch (fccno) { case 0: - gen_helper_fcmped(cpu_fsr, cpu_env, r_rs1, r_rs2); + gen_helper_fcmped(cpu_fsr, tcg_env, r_rs1, r_rs2); break; case 1: - gen_helper_fcmped_fcc1(cpu_fsr, cpu_env, r_rs1, r_rs2); + gen_helper_fcmped_fcc1(cpu_fsr, tcg_env, r_rs1, r_rs2); break; case 2: - gen_helper_fcmped_fcc2(cpu_fsr, cpu_env, r_rs1, r_rs2); + gen_helper_fcmped_fcc2(cpu_fsr, tcg_env, r_rs1, r_rs2); break; case 3: - gen_helper_fcmped_fcc3(cpu_fsr, cpu_env, r_rs1, r_rs2); + gen_helper_fcmped_fcc3(cpu_fsr, tcg_env, r_rs1, r_rs2); break; } } @@ -1515,16 +1515,16 @@ static void gen_op_fcmpeq(int fccno) { switch (fccno) { case 0: - gen_helper_fcmpeq(cpu_fsr, cpu_env); + gen_helper_fcmpeq(cpu_fsr, tcg_env); break; case 1: - gen_helper_fcmpeq_fcc1(cpu_fsr, cpu_env); + gen_helper_fcmpeq_fcc1(cpu_fsr, tcg_env); break; case 2: - gen_helper_fcmpeq_fcc2(cpu_fsr, cpu_env); + gen_helper_fcmpeq_fcc2(cpu_fsr, tcg_env); break; case 3: - gen_helper_fcmpeq_fcc3(cpu_fsr, cpu_env); + gen_helper_fcmpeq_fcc3(cpu_fsr, tcg_env); break; } } @@ -1533,32 +1533,32 @@ static void gen_op_fcmpeq(int fccno) static void gen_op_fcmps(int fccno, TCGv r_rs1, TCGv r_rs2) { - gen_helper_fcmps(cpu_fsr, cpu_env, r_rs1, r_rs2); + gen_helper_fcmps(cpu_fsr, tcg_env, r_rs1, r_rs2); } static void gen_op_fcmpd(int fccno, TCGv_i64 r_rs1, TCGv_i64 r_rs2) { - gen_helper_fcmpd(cpu_fsr, cpu_env, r_rs1, r_rs2); + gen_helper_fcmpd(cpu_fsr, tcg_env, r_rs1, r_rs2); } static void gen_op_fcmpq(int fccno) { - gen_helper_fcmpq(cpu_fsr, cpu_env); + gen_helper_fcmpq(cpu_fsr, tcg_env); } static void gen_op_fcmpes(int fccno, TCGv r_rs1, TCGv r_rs2) { - gen_helper_fcmpes(cpu_fsr, cpu_env, r_rs1, r_rs2); + gen_helper_fcmpes(cpu_fsr, tcg_env, r_rs1, r_rs2); } static void gen_op_fcmped(int fccno, TCGv_i64 r_rs1, TCGv_i64 r_rs2) { - gen_helper_fcmped(cpu_fsr, cpu_env, r_rs1, r_rs2); + gen_helper_fcmped(cpu_fsr, tcg_env, r_rs1, r_rs2); } static void gen_op_fcmpeq(int fccno) { - gen_helper_fcmpeq(cpu_fsr, cpu_env); + gen_helper_fcmpeq(cpu_fsr, tcg_env); } #endif @@ -1593,8 +1593,8 @@ static void gen_fop_FF(DisasContext *dc, int rd, int rs, src = gen_load_fpr_F(dc, rs); dst = gen_dest_fpr_F(dc); - gen(dst, cpu_env, src); - gen_helper_check_ieee_exceptions(cpu_fsr, cpu_env); + gen(dst, tcg_env, src); + gen_helper_check_ieee_exceptions(cpu_fsr, tcg_env); gen_store_fpr_F(dc, rd, dst); } @@ -1621,8 +1621,8 @@ static void gen_fop_FFF(DisasContext *dc, int rd, int rs1, int rs2, src2 = gen_load_fpr_F(dc, rs2); dst = gen_dest_fpr_F(dc); - gen(dst, cpu_env, src1, src2); - gen_helper_check_ieee_exceptions(cpu_fsr, cpu_env); + gen(dst, tcg_env, src1, src2); + gen_helper_check_ieee_exceptions(cpu_fsr, tcg_env); gen_store_fpr_F(dc, rd, dst); } @@ -1651,8 +1651,8 @@ static void gen_fop_DD(DisasContext *dc, int rd, int rs, src = gen_load_fpr_D(dc, rs); dst = gen_dest_fpr_D(dc, rd); - gen(dst, cpu_env, src); - gen_helper_check_ieee_exceptions(cpu_fsr, cpu_env); + gen(dst, tcg_env, src); + gen_helper_check_ieee_exceptions(cpu_fsr, tcg_env); gen_store_fpr_D(dc, rd, dst); } @@ -1681,8 +1681,8 @@ static void gen_fop_DDD(DisasContext *dc, int rd, int rs1, int rs2, src2 = gen_load_fpr_D(dc, rs2); dst = gen_dest_fpr_D(dc, rd); - gen(dst, cpu_env, src1, src2); - gen_helper_check_ieee_exceptions(cpu_fsr, cpu_env); + gen(dst, tcg_env, src1, src2); + gen_helper_check_ieee_exceptions(cpu_fsr, tcg_env); gen_store_fpr_D(dc, rd, dst); } @@ -1737,8 +1737,8 @@ static void gen_fop_QQ(DisasContext *dc, int rd, int rs, { gen_op_load_fpr_QT1(QFPREG(rs)); - gen(cpu_env); - gen_helper_check_ieee_exceptions(cpu_fsr, cpu_env); + gen(tcg_env); + gen_helper_check_ieee_exceptions(cpu_fsr, tcg_env); gen_op_store_QT0_fpr(QFPREG(rd)); gen_update_fprs_dirty(dc, QFPREG(rd)); @@ -1750,7 +1750,7 @@ static void gen_ne_fop_QQ(DisasContext *dc, int rd, int rs, { gen_op_load_fpr_QT1(QFPREG(rs)); - gen(cpu_env); + gen(tcg_env); gen_op_store_QT0_fpr(QFPREG(rd)); gen_update_fprs_dirty(dc, QFPREG(rd)); @@ -1763,8 +1763,8 @@ static void gen_fop_QQQ(DisasContext *dc, int rd, int rs1, int rs2, gen_op_load_fpr_QT0(QFPREG(rs1)); gen_op_load_fpr_QT1(QFPREG(rs2)); - gen(cpu_env); - gen_helper_check_ieee_exceptions(cpu_fsr, cpu_env); + gen(tcg_env); + gen_helper_check_ieee_exceptions(cpu_fsr, tcg_env); gen_op_store_QT0_fpr(QFPREG(rd)); gen_update_fprs_dirty(dc, QFPREG(rd)); @@ -1780,8 +1780,8 @@ static void gen_fop_DFF(DisasContext *dc, int rd, int rs1, int rs2, src2 = gen_load_fpr_F(dc, rs2); dst = gen_dest_fpr_D(dc, rd); - gen(dst, cpu_env, src1, src2); - gen_helper_check_ieee_exceptions(cpu_fsr, cpu_env); + gen(dst, tcg_env, src1, src2); + gen_helper_check_ieee_exceptions(cpu_fsr, tcg_env); gen_store_fpr_D(dc, rd, dst); } @@ -1794,8 +1794,8 @@ static void gen_fop_QDD(DisasContext *dc, int rd, int rs1, int rs2, src1 = gen_load_fpr_D(dc, rs1); src2 = gen_load_fpr_D(dc, rs2); - gen(cpu_env, src1, src2); - gen_helper_check_ieee_exceptions(cpu_fsr, cpu_env); + gen(tcg_env, src1, src2); + gen_helper_check_ieee_exceptions(cpu_fsr, tcg_env); gen_op_store_QT0_fpr(QFPREG(rd)); gen_update_fprs_dirty(dc, QFPREG(rd)); @@ -1811,8 +1811,8 @@ static void gen_fop_DF(DisasContext *dc, int rd, int rs, src = gen_load_fpr_F(dc, rs); dst = gen_dest_fpr_D(dc, rd); - gen(dst, cpu_env, src); - gen_helper_check_ieee_exceptions(cpu_fsr, cpu_env); + gen(dst, tcg_env, src); + gen_helper_check_ieee_exceptions(cpu_fsr, tcg_env); gen_store_fpr_D(dc, rd, dst); } @@ -1827,7 +1827,7 @@ static void gen_ne_fop_DF(DisasContext *dc, int rd, int rs, src = gen_load_fpr_F(dc, rs); dst = gen_dest_fpr_D(dc, rd); - gen(dst, cpu_env, src); + gen(dst, tcg_env, src); gen_store_fpr_D(dc, rd, dst); } @@ -1841,8 +1841,8 @@ static void gen_fop_FD(DisasContext *dc, int rd, int rs, src = gen_load_fpr_D(dc, rs); dst = gen_dest_fpr_F(dc); - gen(dst, cpu_env, src); - gen_helper_check_ieee_exceptions(cpu_fsr, cpu_env); + gen(dst, tcg_env, src); + gen_helper_check_ieee_exceptions(cpu_fsr, tcg_env); gen_store_fpr_F(dc, rd, dst); } @@ -1855,8 +1855,8 @@ static void gen_fop_FQ(DisasContext *dc, int rd, int rs, gen_op_load_fpr_QT1(QFPREG(rs)); dst = gen_dest_fpr_F(dc); - gen(dst, cpu_env); - gen_helper_check_ieee_exceptions(cpu_fsr, cpu_env); + gen(dst, tcg_env); + gen_helper_check_ieee_exceptions(cpu_fsr, tcg_env); gen_store_fpr_F(dc, rd, dst); } @@ -1869,8 +1869,8 @@ static void gen_fop_DQ(DisasContext *dc, int rd, int rs, gen_op_load_fpr_QT1(QFPREG(rs)); dst = gen_dest_fpr_D(dc, rd); - gen(dst, cpu_env); - gen_helper_check_ieee_exceptions(cpu_fsr, cpu_env); + gen(dst, tcg_env); + gen_helper_check_ieee_exceptions(cpu_fsr, tcg_env); gen_store_fpr_D(dc, rd, dst); } @@ -1882,7 +1882,7 @@ static void gen_ne_fop_QF(DisasContext *dc, int rd, int rs, src = gen_load_fpr_F(dc, rs); - gen(cpu_env, src); + gen(tcg_env, src); gen_op_store_QT0_fpr(QFPREG(rd)); gen_update_fprs_dirty(dc, QFPREG(rd)); @@ -1895,7 +1895,7 @@ static void gen_ne_fop_QD(DisasContext *dc, int rd, int rs, src = gen_load_fpr_D(dc, rs); - gen(cpu_env, src); + gen(tcg_env, src); gen_op_store_QT0_fpr(QFPREG(rd)); gen_update_fprs_dirty(dc, QFPREG(rd)); @@ -2170,11 +2170,11 @@ static void gen_ld_asi(DisasContext *dc, TCGv dst, TCGv addr, save_state(dc); #ifdef TARGET_SPARC64 - gen_helper_ld_asi(dst, cpu_env, addr, r_asi, r_mop); + gen_helper_ld_asi(dst, tcg_env, addr, r_asi, r_mop); #else { TCGv_i64 t64 = tcg_temp_new_i64(); - gen_helper_ld_asi(t64, cpu_env, addr, r_asi, r_mop); + gen_helper_ld_asi(t64, tcg_env, addr, r_asi, r_mop); tcg_gen_trunc_i64_tl(dst, t64); } #endif @@ -2243,12 +2243,12 @@ static void gen_st_asi(DisasContext *dc, TCGv src, TCGv addr, save_state(dc); #ifdef TARGET_SPARC64 - gen_helper_st_asi(cpu_env, addr, src, r_asi, r_mop); + gen_helper_st_asi(tcg_env, addr, src, r_asi, r_mop); #else { TCGv_i64 t64 = tcg_temp_new_i64(); tcg_gen_extu_tl_i64(t64, src); - gen_helper_st_asi(cpu_env, addr, t64, r_asi, r_mop); + gen_helper_st_asi(tcg_env, addr, t64, r_asi, r_mop); } #endif @@ -2313,7 +2313,7 @@ static void gen_ldstub_asi(DisasContext *dc, TCGv dst, TCGv addr, int insn) /* ??? In theory, this should be raise DAE_invalid_asi. But the SS-20 roms do ldstuba [%l0] #ASI_M_CTL, %o1. */ if (tb_cflags(dc->base.tb) & CF_PARALLEL) { - gen_helper_exit_atomic(cpu_env); + gen_helper_exit_atomic(tcg_env); } else { TCGv_i32 r_asi = tcg_constant_i32(da.asi); TCGv_i32 r_mop = tcg_constant_i32(MO_UB); @@ -2321,10 +2321,10 @@ static void gen_ldstub_asi(DisasContext *dc, TCGv dst, TCGv addr, int insn) save_state(dc); t64 = tcg_temp_new_i64(); - gen_helper_ld_asi(t64, cpu_env, addr, r_asi, r_mop); + gen_helper_ld_asi(t64, tcg_env, addr, r_asi, r_mop); s64 = tcg_constant_i64(0xff); - gen_helper_st_asi(cpu_env, addr, s64, r_asi, r_mop); + gen_helper_st_asi(tcg_env, addr, s64, r_asi, r_mop); tcg_gen_trunc_i64_tl(dst, t64); @@ -2423,19 +2423,19 @@ static void gen_ldf_asi(DisasContext *dc, TCGv addr, switch (size) { case 4: d64 = tcg_temp_new_i64(); - gen_helper_ld_asi(d64, cpu_env, addr, r_asi, r_mop); + gen_helper_ld_asi(d64, tcg_env, addr, r_asi, r_mop); d32 = gen_dest_fpr_F(dc); tcg_gen_extrl_i64_i32(d32, d64); gen_store_fpr_F(dc, rd, d32); break; case 8: - gen_helper_ld_asi(cpu_fpr[rd / 2], cpu_env, addr, r_asi, r_mop); + gen_helper_ld_asi(cpu_fpr[rd / 2], tcg_env, addr, r_asi, r_mop); break; case 16: d64 = tcg_temp_new_i64(); - gen_helper_ld_asi(d64, cpu_env, addr, r_asi, r_mop); + gen_helper_ld_asi(d64, tcg_env, addr, r_asi, r_mop); tcg_gen_addi_tl(addr, addr, 8); - gen_helper_ld_asi(cpu_fpr[rd/2+1], cpu_env, addr, r_asi, r_mop); + gen_helper_ld_asi(cpu_fpr[rd/2+1], tcg_env, addr, r_asi, r_mop); tcg_gen_mov_i64(cpu_fpr[rd / 2], d64); break; default: @@ -2575,7 +2575,7 @@ static void gen_ldda_asi(DisasContext *dc, TCGv addr, int insn, int rd) TCGv_i64 tmp = tcg_temp_new_i64(); save_state(dc); - gen_helper_ld_asi(tmp, cpu_env, addr, r_asi, r_mop); + gen_helper_ld_asi(tmp, tcg_env, addr, r_asi, r_mop); /* See above. */ if ((da.memop & MO_BSWAP) == MO_TE) { @@ -2641,7 +2641,7 @@ static void gen_stda_asi(DisasContext *dc, TCGv hi, TCGv addr, } save_state(dc); - gen_helper_st_asi(cpu_env, addr, t64, r_asi, r_mop); + gen_helper_st_asi(tcg_env, addr, t64, r_asi, r_mop); } break; } @@ -2694,7 +2694,7 @@ static void gen_ldda_asi(DisasContext *dc, TCGv addr, int insn, int rd) TCGv_i32 r_mop = tcg_constant_i32(MO_UQ); save_state(dc); - gen_helper_ld_asi(t64, cpu_env, addr, r_asi, r_mop); + gen_helper_ld_asi(t64, tcg_env, addr, r_asi, r_mop); } break; } @@ -2744,7 +2744,7 @@ static void gen_stda_asi(DisasContext *dc, TCGv hi, TCGv addr, TCGv_i32 r_mop = tcg_constant_i32(MO_UQ); save_state(dc); - gen_helper_st_asi(cpu_env, addr, t64, r_asi, r_mop); + gen_helper_st_asi(tcg_env, addr, t64, r_asi, r_mop); } break; } @@ -2820,19 +2820,19 @@ static void gen_fmovq(DisasContext *dc, DisasCompare *cmp, int rd, int rs) } #ifndef CONFIG_USER_ONLY -static void gen_load_trap_state_at_tl(TCGv_ptr r_tsptr, TCGv_env cpu_env) +static void gen_load_trap_state_at_tl(TCGv_ptr r_tsptr, TCGv_env tcg_env) { TCGv_i32 r_tl = tcg_temp_new_i32(); /* load env->tl into r_tl */ - tcg_gen_ld_i32(r_tl, cpu_env, offsetof(CPUSPARCState, tl)); + tcg_gen_ld_i32(r_tl, tcg_env, offsetof(CPUSPARCState, tl)); /* tl = [0 ... MAXTL_MASK] where MAXTL_MASK must be power of 2 */ tcg_gen_andi_i32(r_tl, r_tl, MAXTL_MASK); /* calculate offset to current trap state from env->ts, reuse r_tl */ tcg_gen_muli_i32(r_tl, r_tl, sizeof (trap_state)); - tcg_gen_addi_ptr(r_tsptr, cpu_env, offsetof(CPUSPARCState, ts)); + tcg_gen_addi_ptr(r_tsptr, tcg_env, offsetof(CPUSPARCState, ts)); /* tsptr = env->ts[env->tl & MAXTL_MASK] */ { @@ -3159,7 +3159,7 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn) tcg_gen_addi_i32(trap, trap, TT_TRAP); } - gen_helper_raise_exception(cpu_env, trap); + gen_helper_raise_exception(tcg_env, trap); if (cond == 8) { /* An unconditional trap ends the TB. */ @@ -3197,7 +3197,7 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn) #ifdef TARGET_SPARC64 case 0x2: /* V9 rdccr */ update_psr(dc); - gen_helper_rdccr(cpu_dst, cpu_env); + gen_helper_rdccr(cpu_dst, tcg_env); gen_store_gpr(dc, rd, cpu_dst); break; case 0x3: /* V9 rdasi */ @@ -3211,12 +3211,12 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn) r_tickptr = tcg_temp_new_ptr(); r_const = tcg_constant_i32(dc->mem_idx); - tcg_gen_ld_ptr(r_tickptr, cpu_env, + tcg_gen_ld_ptr(r_tickptr, tcg_env, offsetof(CPUSPARCState, tick)); if (translator_io_start(&dc->base)) { dc->base.is_jmp = DISAS_EXIT; } - gen_helper_tick_get_count(cpu_dst, cpu_env, r_tickptr, + gen_helper_tick_get_count(cpu_dst, tcg_env, r_tickptr, r_const); gen_store_gpr(dc, rd, cpu_dst); } @@ -3245,7 +3245,7 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn) gen_store_gpr(dc, rd, cpu_gsr); break; case 0x16: /* Softint */ - tcg_gen_ld32s_tl(cpu_dst, cpu_env, + tcg_gen_ld32s_tl(cpu_dst, tcg_env, offsetof(CPUSPARCState, softint)); gen_store_gpr(dc, rd, cpu_dst); break; @@ -3259,12 +3259,12 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn) r_tickptr = tcg_temp_new_ptr(); r_const = tcg_constant_i32(dc->mem_idx); - tcg_gen_ld_ptr(r_tickptr, cpu_env, + tcg_gen_ld_ptr(r_tickptr, tcg_env, offsetof(CPUSPARCState, stick)); if (translator_io_start(&dc->base)) { dc->base.is_jmp = DISAS_EXIT; } - gen_helper_tick_get_count(cpu_dst, cpu_env, r_tickptr, + gen_helper_tick_get_count(cpu_dst, tcg_env, r_tickptr, r_const); gen_store_gpr(dc, rd, cpu_dst); } @@ -3299,7 +3299,7 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn) goto priv_insn; } update_psr(dc); - gen_helper_rdpsr(cpu_dst, cpu_env); + gen_helper_rdpsr(cpu_dst, tcg_env); #else CHECK_IU_FEATURE(dc, HYPV); if (!hypervisor(dc)) @@ -3307,7 +3307,7 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn) rs1 = GET_FIELD(insn, 13, 17); switch (rs1) { case 0: // hpstate - tcg_gen_ld_i64(cpu_dst, cpu_env, + tcg_gen_ld_i64(cpu_dst, tcg_env, offsetof(CPUSPARCState, hpstate)); break; case 1: // htstate @@ -3344,7 +3344,7 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn) TCGv_ptr r_tsptr; r_tsptr = tcg_temp_new_ptr(); - gen_load_trap_state_at_tl(r_tsptr, cpu_env); + gen_load_trap_state_at_tl(r_tsptr, tcg_env); tcg_gen_ld_tl(cpu_tmp0, r_tsptr, offsetof(trap_state, tpc)); } @@ -3354,7 +3354,7 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn) TCGv_ptr r_tsptr; r_tsptr = tcg_temp_new_ptr(); - gen_load_trap_state_at_tl(r_tsptr, cpu_env); + gen_load_trap_state_at_tl(r_tsptr, tcg_env); tcg_gen_ld_tl(cpu_tmp0, r_tsptr, offsetof(trap_state, tnpc)); } @@ -3364,7 +3364,7 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn) TCGv_ptr r_tsptr; r_tsptr = tcg_temp_new_ptr(); - gen_load_trap_state_at_tl(r_tsptr, cpu_env); + gen_load_trap_state_at_tl(r_tsptr, tcg_env); tcg_gen_ld_tl(cpu_tmp0, r_tsptr, offsetof(trap_state, tstate)); } @@ -3373,7 +3373,7 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn) { TCGv_ptr r_tsptr = tcg_temp_new_ptr(); - gen_load_trap_state_at_tl(r_tsptr, cpu_env); + gen_load_trap_state_at_tl(r_tsptr, tcg_env); tcg_gen_ld32s_tl(cpu_tmp0, r_tsptr, offsetof(trap_state, tt)); } @@ -3385,12 +3385,12 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn) r_tickptr = tcg_temp_new_ptr(); r_const = tcg_constant_i32(dc->mem_idx); - tcg_gen_ld_ptr(r_tickptr, cpu_env, + tcg_gen_ld_ptr(r_tickptr, tcg_env, offsetof(CPUSPARCState, tick)); if (translator_io_start(&dc->base)) { dc->base.is_jmp = DISAS_EXIT; } - gen_helper_tick_get_count(cpu_tmp0, cpu_env, + gen_helper_tick_get_count(cpu_tmp0, tcg_env, r_tickptr, r_const); } break; @@ -3398,43 +3398,43 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn) tcg_gen_mov_tl(cpu_tmp0, cpu_tbr); break; case 6: // pstate - tcg_gen_ld32s_tl(cpu_tmp0, cpu_env, + tcg_gen_ld32s_tl(cpu_tmp0, tcg_env, offsetof(CPUSPARCState, pstate)); break; case 7: // tl - tcg_gen_ld32s_tl(cpu_tmp0, cpu_env, + tcg_gen_ld32s_tl(cpu_tmp0, tcg_env, offsetof(CPUSPARCState, tl)); break; case 8: // pil - tcg_gen_ld32s_tl(cpu_tmp0, cpu_env, + tcg_gen_ld32s_tl(cpu_tmp0, tcg_env, offsetof(CPUSPARCState, psrpil)); break; case 9: // cwp - gen_helper_rdcwp(cpu_tmp0, cpu_env); + gen_helper_rdcwp(cpu_tmp0, tcg_env); break; case 10: // cansave - tcg_gen_ld32s_tl(cpu_tmp0, cpu_env, + tcg_gen_ld32s_tl(cpu_tmp0, tcg_env, offsetof(CPUSPARCState, cansave)); break; case 11: // canrestore - tcg_gen_ld32s_tl(cpu_tmp0, cpu_env, + tcg_gen_ld32s_tl(cpu_tmp0, tcg_env, offsetof(CPUSPARCState, canrestore)); break; case 12: // cleanwin - tcg_gen_ld32s_tl(cpu_tmp0, cpu_env, + tcg_gen_ld32s_tl(cpu_tmp0, tcg_env, offsetof(CPUSPARCState, cleanwin)); break; case 13: // otherwin - tcg_gen_ld32s_tl(cpu_tmp0, cpu_env, + tcg_gen_ld32s_tl(cpu_tmp0, tcg_env, offsetof(CPUSPARCState, otherwin)); break; case 14: // wstate - tcg_gen_ld32s_tl(cpu_tmp0, cpu_env, + tcg_gen_ld32s_tl(cpu_tmp0, tcg_env, offsetof(CPUSPARCState, wstate)); break; case 16: // UA2005 gl CHECK_IU_FEATURE(dc, GL); - tcg_gen_ld32s_tl(cpu_tmp0, cpu_env, + tcg_gen_ld32s_tl(cpu_tmp0, tcg_env, offsetof(CPUSPARCState, gl)); break; case 26: // UA2005 strand status @@ -3459,7 +3459,7 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn) #if defined(TARGET_SPARC64) || !defined(CONFIG_USER_ONLY) } else if (xop == 0x2b) { /* rdtbr / V9 flushw */ #ifdef TARGET_SPARC64 - gen_helper_flushw(cpu_env); + gen_helper_flushw(tcg_env); #else if (!supervisor(dc)) goto priv_insn; @@ -4002,28 +4002,28 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn) break; #ifdef TARGET_SPARC64 case 0xd: /* V9 udivx */ - gen_helper_udivx(cpu_dst, cpu_env, cpu_src1, cpu_src2); + gen_helper_udivx(cpu_dst, tcg_env, cpu_src1, cpu_src2); break; #endif case 0xe: /* udiv */ CHECK_IU_FEATURE(dc, DIV); if (xop & 0x10) { - gen_helper_udiv_cc(cpu_dst, cpu_env, cpu_src1, + gen_helper_udiv_cc(cpu_dst, tcg_env, cpu_src1, cpu_src2); dc->cc_op = CC_OP_DIV; } else { - gen_helper_udiv(cpu_dst, cpu_env, cpu_src1, + gen_helper_udiv(cpu_dst, tcg_env, cpu_src1, cpu_src2); } break; case 0xf: /* sdiv */ CHECK_IU_FEATURE(dc, DIV); if (xop & 0x10) { - gen_helper_sdiv_cc(cpu_dst, cpu_env, cpu_src1, + gen_helper_sdiv_cc(cpu_dst, tcg_env, cpu_src1, cpu_src2); dc->cc_op = CC_OP_DIV; } else { - gen_helper_sdiv(cpu_dst, cpu_env, cpu_src1, + gen_helper_sdiv(cpu_dst, tcg_env, cpu_src1, cpu_src2); } break; @@ -4048,13 +4048,13 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn) dc->cc_op = CC_OP_TSUB; break; case 0x22: /* taddcctv */ - gen_helper_taddcctv(cpu_dst, cpu_env, + gen_helper_taddcctv(cpu_dst, tcg_env, cpu_src1, cpu_src2); gen_store_gpr(dc, rd, cpu_dst); dc->cc_op = CC_OP_TADDTV; break; case 0x23: /* tsubcctv */ - gen_helper_tsubcctv(cpu_dst, cpu_env, + gen_helper_tsubcctv(cpu_dst, tcg_env, cpu_src1, cpu_src2); gen_store_gpr(dc, rd, cpu_dst); dc->cc_op = CC_OP_TSUBTV; @@ -4122,20 +4122,20 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn) CPU_FEATURE_POWERDOWN)) { /* LEON3 power-down */ save_state(dc); - gen_helper_power_down(cpu_env); + gen_helper_power_down(tcg_env); } break; #else case 0x2: /* V9 wrccr */ tcg_gen_xor_tl(cpu_tmp0, cpu_src1, cpu_src2); - gen_helper_wrccr(cpu_env, cpu_tmp0); + gen_helper_wrccr(tcg_env, cpu_tmp0); tcg_gen_movi_i32(cpu_cc_op, CC_OP_FLAGS); dc->cc_op = CC_OP_FLAGS; break; case 0x3: /* V9 wrasi */ tcg_gen_xor_tl(cpu_tmp0, cpu_src1, cpu_src2); tcg_gen_andi_tl(cpu_tmp0, cpu_tmp0, 0xff); - tcg_gen_st32_tl(cpu_tmp0, cpu_env, + tcg_gen_st32_tl(cpu_tmp0, tcg_env, offsetof(CPUSPARCState, asi)); /* * End TB to notice changed ASI. @@ -4173,19 +4173,19 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn) if (!supervisor(dc)) goto illegal_insn; tcg_gen_xor_tl(cpu_tmp0, cpu_src1, cpu_src2); - gen_helper_set_softint(cpu_env, cpu_tmp0); + gen_helper_set_softint(tcg_env, cpu_tmp0); break; case 0x15: /* Softint clear */ if (!supervisor(dc)) goto illegal_insn; tcg_gen_xor_tl(cpu_tmp0, cpu_src1, cpu_src2); - gen_helper_clear_softint(cpu_env, cpu_tmp0); + gen_helper_clear_softint(tcg_env, cpu_tmp0); break; case 0x16: /* Softint write */ if (!supervisor(dc)) goto illegal_insn; tcg_gen_xor_tl(cpu_tmp0, cpu_src1, cpu_src2); - gen_helper_write_softint(cpu_env, cpu_tmp0); + gen_helper_write_softint(tcg_env, cpu_tmp0); break; case 0x17: /* Tick compare */ #if !defined(CONFIG_USER_ONLY) @@ -4198,7 +4198,7 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn) tcg_gen_xor_tl(cpu_tick_cmpr, cpu_src1, cpu_src2); r_tickptr = tcg_temp_new_ptr(); - tcg_gen_ld_ptr(r_tickptr, cpu_env, + tcg_gen_ld_ptr(r_tickptr, tcg_env, offsetof(CPUSPARCState, tick)); translator_io_start(&dc->base); gen_helper_tick_set_limit(r_tickptr, @@ -4218,7 +4218,7 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn) tcg_gen_xor_tl(cpu_tmp0, cpu_src1, cpu_src2); r_tickptr = tcg_temp_new_ptr(); - tcg_gen_ld_ptr(r_tickptr, cpu_env, + tcg_gen_ld_ptr(r_tickptr, tcg_env, offsetof(CPUSPARCState, stick)); translator_io_start(&dc->base); gen_helper_tick_set_count(r_tickptr, @@ -4238,7 +4238,7 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn) tcg_gen_xor_tl(cpu_stick_cmpr, cpu_src1, cpu_src2); r_tickptr = tcg_temp_new_ptr(); - tcg_gen_ld_ptr(r_tickptr, cpu_env, + tcg_gen_ld_ptr(r_tickptr, tcg_env, offsetof(CPUSPARCState, stick)); translator_io_start(&dc->base); gen_helper_tick_set_limit(r_tickptr, @@ -4266,10 +4266,10 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn) #ifdef TARGET_SPARC64 switch (rd) { case 0: - gen_helper_saved(cpu_env); + gen_helper_saved(tcg_env); break; case 1: - gen_helper_restored(cpu_env); + gen_helper_restored(tcg_env); break; case 2: /* UA2005 allclean */ case 3: /* UA2005 otherw */ @@ -4282,7 +4282,7 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn) #else cpu_tmp0 = tcg_temp_new(); tcg_gen_xor_tl(cpu_tmp0, cpu_src1, cpu_src2); - gen_helper_wrpsr(cpu_env, cpu_tmp0); + gen_helper_wrpsr(tcg_env, cpu_tmp0); tcg_gen_movi_i32(cpu_cc_op, CC_OP_FLAGS); dc->cc_op = CC_OP_FLAGS; save_state(dc); @@ -4305,7 +4305,7 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn) TCGv_ptr r_tsptr; r_tsptr = tcg_temp_new_ptr(); - gen_load_trap_state_at_tl(r_tsptr, cpu_env); + gen_load_trap_state_at_tl(r_tsptr, tcg_env); tcg_gen_st_tl(cpu_tmp0, r_tsptr, offsetof(trap_state, tpc)); } @@ -4315,7 +4315,7 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn) TCGv_ptr r_tsptr; r_tsptr = tcg_temp_new_ptr(); - gen_load_trap_state_at_tl(r_tsptr, cpu_env); + gen_load_trap_state_at_tl(r_tsptr, tcg_env); tcg_gen_st_tl(cpu_tmp0, r_tsptr, offsetof(trap_state, tnpc)); } @@ -4325,7 +4325,7 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn) TCGv_ptr r_tsptr; r_tsptr = tcg_temp_new_ptr(); - gen_load_trap_state_at_tl(r_tsptr, cpu_env); + gen_load_trap_state_at_tl(r_tsptr, tcg_env); tcg_gen_st_tl(cpu_tmp0, r_tsptr, offsetof(trap_state, tstate)); @@ -4336,7 +4336,7 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn) TCGv_ptr r_tsptr; r_tsptr = tcg_temp_new_ptr(); - gen_load_trap_state_at_tl(r_tsptr, cpu_env); + gen_load_trap_state_at_tl(r_tsptr, tcg_env); tcg_gen_st32_tl(cpu_tmp0, r_tsptr, offsetof(trap_state, tt)); } @@ -4346,7 +4346,7 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn) TCGv_ptr r_tickptr; r_tickptr = tcg_temp_new_ptr(); - tcg_gen_ld_ptr(r_tickptr, cpu_env, + tcg_gen_ld_ptr(r_tickptr, tcg_env, offsetof(CPUSPARCState, tick)); translator_io_start(&dc->base); gen_helper_tick_set_count(r_tickptr, @@ -4363,12 +4363,12 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn) if (translator_io_start(&dc->base)) { dc->base.is_jmp = DISAS_EXIT; } - gen_helper_wrpstate(cpu_env, cpu_tmp0); + gen_helper_wrpstate(tcg_env, cpu_tmp0); dc->npc = DYNAMIC_PC; break; case 7: // tl save_state(dc); - tcg_gen_st32_tl(cpu_tmp0, cpu_env, + tcg_gen_st32_tl(cpu_tmp0, tcg_env, offsetof(CPUSPARCState, tl)); dc->npc = DYNAMIC_PC; break; @@ -4376,39 +4376,39 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn) if (translator_io_start(&dc->base)) { dc->base.is_jmp = DISAS_EXIT; } - gen_helper_wrpil(cpu_env, cpu_tmp0); + gen_helper_wrpil(tcg_env, cpu_tmp0); break; case 9: // cwp - gen_helper_wrcwp(cpu_env, cpu_tmp0); + gen_helper_wrcwp(tcg_env, cpu_tmp0); break; case 10: // cansave - tcg_gen_st32_tl(cpu_tmp0, cpu_env, + tcg_gen_st32_tl(cpu_tmp0, tcg_env, offsetof(CPUSPARCState, cansave)); break; case 11: // canrestore - tcg_gen_st32_tl(cpu_tmp0, cpu_env, + tcg_gen_st32_tl(cpu_tmp0, tcg_env, offsetof(CPUSPARCState, canrestore)); break; case 12: // cleanwin - tcg_gen_st32_tl(cpu_tmp0, cpu_env, + tcg_gen_st32_tl(cpu_tmp0, tcg_env, offsetof(CPUSPARCState, cleanwin)); break; case 13: // otherwin - tcg_gen_st32_tl(cpu_tmp0, cpu_env, + tcg_gen_st32_tl(cpu_tmp0, tcg_env, offsetof(CPUSPARCState, otherwin)); break; case 14: // wstate - tcg_gen_st32_tl(cpu_tmp0, cpu_env, + tcg_gen_st32_tl(cpu_tmp0, tcg_env, offsetof(CPUSPARCState, wstate)); break; case 16: // UA2005 gl CHECK_IU_FEATURE(dc, GL); - gen_helper_wrgl(cpu_env, cpu_tmp0); + gen_helper_wrgl(tcg_env, cpu_tmp0); break; case 26: // UA2005 strand status CHECK_IU_FEATURE(dc, HYPV); @@ -4442,7 +4442,7 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn) tcg_gen_xor_tl(cpu_tmp0, cpu_src1, cpu_src2); switch (rd) { case 0: // hpstate - tcg_gen_st_i64(cpu_tmp0, cpu_env, + tcg_gen_st_i64(cpu_tmp0, tcg_env, offsetof(CPUSPARCState, hpstate)); save_state(dc); @@ -4465,7 +4465,7 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn) tcg_gen_mov_tl(cpu_hstick_cmpr, cpu_tmp0); r_tickptr = tcg_temp_new_ptr(); - tcg_gen_ld_ptr(r_tickptr, cpu_env, + tcg_gen_ld_ptr(r_tickptr, tcg_env, offsetof(CPUSPARCState, hstick)); translator_io_start(&dc->base); gen_helper_tick_set_limit(r_tickptr, @@ -4518,7 +4518,7 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn) break; } case 0x2d: /* V9 sdivx */ - gen_helper_sdivx(cpu_dst, cpu_env, cpu_src1, cpu_src2); + gen_helper_sdivx(cpu_dst, tcg_env, cpu_src1, cpu_src2); gen_store_gpr(dc, rd, cpu_dst); break; case 0x2e: /* V9 popc */ @@ -5019,7 +5019,7 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn) tcg_gen_mov_tl(cpu_tmp0, cpu_src1); } } - gen_helper_restore(cpu_env); + gen_helper_restore(tcg_env); gen_mov_pc_npc(dc); gen_check_align(cpu_tmp0, 3); tcg_gen_mov_tl(cpu_npc, cpu_tmp0); @@ -5064,7 +5064,7 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn) gen_check_align(cpu_tmp0, 3); tcg_gen_mov_tl(cpu_npc, cpu_tmp0); dc->npc = DYNAMIC_PC; - gen_helper_rett(cpu_env); + gen_helper_rett(tcg_env); } goto jmp_insn; #endif @@ -5074,11 +5074,11 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn) /* nop */ break; case 0x3c: /* save */ - gen_helper_save(cpu_env); + gen_helper_save(tcg_env); gen_store_gpr(dc, rd, cpu_tmp0); break; case 0x3d: /* restore */ - gen_helper_restore(cpu_env); + gen_helper_restore(tcg_env); gen_store_gpr(dc, rd, cpu_tmp0); break; #if !defined(CONFIG_USER_ONLY) && defined(TARGET_SPARC64) @@ -5091,7 +5091,7 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn) dc->npc = DYNAMIC_PC; dc->pc = DYNAMIC_PC; translator_io_start(&dc->base); - gen_helper_done(cpu_env); + gen_helper_done(tcg_env); goto jmp_insn; case 1: if (!supervisor(dc)) @@ -5099,7 +5099,7 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn) dc->npc = DYNAMIC_PC; dc->pc = DYNAMIC_PC; translator_io_start(&dc->base); - gen_helper_retry(cpu_env); + gen_helper_retry(tcg_env); goto jmp_insn; default: goto illegal_insn; @@ -5302,14 +5302,14 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn) TCGv_i64 t64 = tcg_temp_new_i64(); tcg_gen_qemu_ld_i64(t64, cpu_addr, dc->mem_idx, MO_TEUQ | MO_ALIGN); - gen_helper_ldxfsr(cpu_fsr, cpu_env, cpu_fsr, t64); + gen_helper_ldxfsr(cpu_fsr, tcg_env, cpu_fsr, t64); break; } #endif cpu_dst_32 = tcg_temp_new_i32(); tcg_gen_qemu_ld_i32(cpu_dst_32, cpu_addr, dc->mem_idx, MO_TEUL | MO_ALIGN); - gen_helper_ldfsr(cpu_fsr, cpu_env, cpu_fsr, cpu_dst_32); + gen_helper_ldfsr(cpu_fsr, tcg_env, cpu_fsr, cpu_dst_32); break; case 0x22: /* ldqf, load quad fpreg */ CHECK_FPU_FEATURE(dc, FLOAT128); @@ -5770,21 +5770,21 @@ void sparc_tcg_init(void) unsigned int i; - cpu_regwptr = tcg_global_mem_new_ptr(cpu_env, + cpu_regwptr = tcg_global_mem_new_ptr(tcg_env, offsetof(CPUSPARCState, regwptr), "regwptr"); for (i = 0; i < ARRAY_SIZE(r32); ++i) { - *r32[i].ptr = tcg_global_mem_new_i32(cpu_env, r32[i].off, r32[i].name); + *r32[i].ptr = tcg_global_mem_new_i32(tcg_env, r32[i].off, r32[i].name); } for (i = 0; i < ARRAY_SIZE(rtl); ++i) { - *rtl[i].ptr = tcg_global_mem_new(cpu_env, rtl[i].off, rtl[i].name); + *rtl[i].ptr = tcg_global_mem_new(tcg_env, rtl[i].off, rtl[i].name); } cpu_regs[0] = NULL; for (i = 1; i < 8; ++i) { - cpu_regs[i] = tcg_global_mem_new(cpu_env, + cpu_regs[i] = tcg_global_mem_new(tcg_env, offsetof(CPUSPARCState, gregs[i]), gregnames[i]); } @@ -5796,7 +5796,7 @@ void sparc_tcg_init(void) } for (i = 0; i < TARGET_DPREGS; i++) { - cpu_fpr[i] = tcg_global_mem_new_i64(cpu_env, + cpu_fpr[i] = tcg_global_mem_new_i64(tcg_env, offsetof(CPUSPARCState, fpr[i]), fregnames[i]); } diff --git a/target/tricore/translate.c b/target/tricore/translate.c index 5e1fc36479..114fdda29f 100644 --- a/target/tricore/translate.c +++ b/target/tricore/translate.c @@ -132,7 +132,7 @@ void tricore_cpu_dump_state(CPUState *cs, FILE *f, int flags) #define gen_helper_1arg(name, arg) do { \ TCGv_i32 helper_tmp = tcg_constant_i32(arg); \ - gen_helper_##name(cpu_env, helper_tmp); \ + gen_helper_##name(tcg_env, helper_tmp); \ } while (0) #define GEN_HELPER_LL(name, ret, arg0, arg1, n) do { \ @@ -191,7 +191,7 @@ void tricore_cpu_dump_state(CPUState *cs, FILE *f, int flags) #define GEN_HELPER_RR(name, rl, rh, arg1, arg2) do { \ TCGv_i64 ret = tcg_temp_new_i64(); \ \ - gen_helper_##name(ret, cpu_env, arg1, arg2); \ + gen_helper_##name(ret, tcg_env, arg1, arg2); \ tcg_gen_extr_i64_i32(rl, rh, ret); \ } while (0) @@ -341,7 +341,7 @@ static void gen_swapmsk(DisasContext *ctx, int reg, TCGv ea) #define R(ADDRESS, REG, FEATURE) \ case ADDRESS: \ if (has_feature(ctx, FEATURE)) { \ - tcg_gen_ld_tl(ret, cpu_env, offsetof(CPUTriCoreState, REG)); \ + tcg_gen_ld_tl(ret, tcg_env, offsetof(CPUTriCoreState, REG)); \ } \ break; #define A(ADDRESS, REG, FEATURE) R(ADDRESS, REG, FEATURE) @@ -350,7 +350,7 @@ static inline void gen_mfcr(DisasContext *ctx, TCGv ret, int32_t offset) { /* since we're caching PSW make this a special case */ if (offset == 0xfe04) { - gen_helper_psw_read(ret, cpu_env); + gen_helper_psw_read(ret, tcg_env); } else { switch (offset) { #include "csfr.h.inc" @@ -366,7 +366,7 @@ static inline void gen_mfcr(DisasContext *ctx, TCGv ret, int32_t offset) #define A(ADDRESS, REG, FEATURE) R(ADDRESS, REG, FEATURE) \ case ADDRESS: \ if (has_feature(ctx, FEATURE)) { \ - tcg_gen_st_tl(r1, cpu_env, offsetof(CPUTriCoreState, REG)); \ + tcg_gen_st_tl(r1, tcg_env, offsetof(CPUTriCoreState, REG)); \ } \ break; /* Endinit protected registers @@ -380,7 +380,7 @@ static inline void gen_mtcr(DisasContext *ctx, TCGv r1, if (ctx->priv == TRICORE_PRIV_SM) { /* since we're caching PSW make this a special case */ if (offset == 0xfe04) { - gen_helper_psw_write(cpu_env, r1); + gen_helper_psw_write(tcg_env, r1); ctx->base.is_jmp = DISAS_EXIT_UPDATE; } else { switch (offset) { @@ -788,7 +788,7 @@ gen_maddsums_h(TCGv ret_low, TCGv ret_high, TCGv r1_low, TCGv r1_high, TCGv r2, tcg_gen_shli_i64(temp64, temp64, 16); tcg_gen_concat_i32_i64(temp64_2, r1_low, r1_high); - gen_helper_add64_ssov(temp64, cpu_env, temp64_2, temp64); + gen_helper_add64_ssov(temp64, tcg_env, temp64_2, temp64); tcg_gen_extr_i64_i32(ret_low, ret_high, temp64); } @@ -843,7 +843,7 @@ gen_maddms_h(TCGv ret_low, TCGv ret_high, TCGv r1_low, TCGv r1_high, TCGv r2, break; } tcg_gen_concat_i32_i64(temp64_2, r1_low, r1_high); - gen_helper_add64_ssov(temp64, cpu_env, temp64_2, temp64); + gen_helper_add64_ssov(temp64, tcg_env, temp64_2, temp64); tcg_gen_extr_i64_i32(ret_low, ret_high, temp64); } @@ -867,7 +867,7 @@ gen_maddr64_h(TCGv ret, TCGv r1_low, TCGv r1_high, TCGv r2, TCGv r3, uint32_t n, GEN_HELPER_UU(mul_h, temp64, r2, r3, t_n); break; } - gen_helper_addr_h(ret, cpu_env, temp64, r1_low, r1_high); + gen_helper_addr_h(ret, tcg_env, temp64, r1_low, r1_high); } static inline void @@ -904,7 +904,7 @@ gen_maddsur32_h(TCGv ret, TCGv r1, TCGv r2, TCGv r3, uint32_t n, uint32_t mode) } tcg_gen_andi_tl(temp2, r1, 0xffff0000); tcg_gen_shli_tl(temp, r1, 16); - gen_helper_addsur_h(ret, cpu_env, temp64, temp, temp2); + gen_helper_addsur_h(ret, tcg_env, temp64, temp, temp2); } @@ -928,7 +928,7 @@ gen_maddr64s_h(TCGv ret, TCGv r1_low, TCGv r1_high, TCGv r2, TCGv r3, GEN_HELPER_UU(mul_h, temp64, r2, r3, t_n); break; } - gen_helper_addr_h_ssov(ret, cpu_env, temp64, r1_low, r1_high); + gen_helper_addr_h_ssov(ret, tcg_env, temp64, r1_low, r1_high); } static inline void @@ -965,21 +965,21 @@ gen_maddsur32s_h(TCGv ret, TCGv r1, TCGv r2, TCGv r3, uint32_t n, uint32_t mode) } tcg_gen_andi_tl(temp2, r1, 0xffff0000); tcg_gen_shli_tl(temp, r1, 16); - gen_helper_addsur_h_ssov(ret, cpu_env, temp64, temp, temp2); + gen_helper_addsur_h_ssov(ret, tcg_env, temp64, temp, temp2); } static inline void gen_maddr_q(TCGv ret, TCGv r1, TCGv r2, TCGv r3, uint32_t n) { TCGv t_n = tcg_constant_i32(n); - gen_helper_maddr_q(ret, cpu_env, r1, r2, r3, t_n); + gen_helper_maddr_q(ret, tcg_env, r1, r2, r3, t_n); } static inline void gen_maddrs_q(TCGv ret, TCGv r1, TCGv r2, TCGv r3, uint32_t n) { TCGv t_n = tcg_constant_i32(n); - gen_helper_maddr_q_ssov(ret, cpu_env, r1, r2, r3, t_n); + gen_helper_maddr_q_ssov(ret, tcg_env, r1, r2, r3, t_n); } static inline void @@ -1115,7 +1115,7 @@ gen_m16adds64_q(TCGv rl, TCGv rh, TCGv arg1_low, TCGv arg1_high, TCGv arg2, tcg_gen_shli_i64(t2, t2, 16); tcg_gen_concat_i32_i64(t1, arg1_low, arg1_high); - gen_helper_add64_ssov(t1, cpu_env, t1, t2); + gen_helper_add64_ssov(t1, tcg_env, t1, t2); tcg_gen_extr_i64_i32(rl, rh, t1); } @@ -1182,7 +1182,7 @@ gen_madds32_q(TCGv ret, TCGv arg1, TCGv arg2, TCGv arg3, uint32_t n, tcg_gen_mul_i64(t2, t2, t3); tcg_gen_sari_i64(t2, t2, up_shift - n); - gen_helper_madd32_q_add_ssov(ret, cpu_env, t1, t2); + gen_helper_madd32_q_add_ssov(ret, tcg_env, t1, t2); } static inline void @@ -1193,7 +1193,7 @@ gen_madds64_q(TCGv rl, TCGv rh, TCGv arg1_low, TCGv arg1_high, TCGv arg2, TCGv t_n = tcg_constant_i32(n); tcg_gen_concat_i32_i64(r1, arg1_low, arg1_high); - gen_helper_madd64_q_ssov(r1, cpu_env, r1, arg2, arg3, t_n); + gen_helper_madd64_q_ssov(r1, tcg_env, r1, arg2, arg3, t_n); tcg_gen_extr_i64_i32(rl, rh, r1); } @@ -1638,7 +1638,7 @@ gen_msubms_h(TCGv ret_low, TCGv ret_high, TCGv r1_low, TCGv r1_high, TCGv r2, break; } tcg_gen_concat_i32_i64(temp64_2, r1_low, r1_high); - gen_helper_sub64_ssov(temp64, cpu_env, temp64_2, temp64); + gen_helper_sub64_ssov(temp64, tcg_env, temp64_2, temp64); tcg_gen_extr_i64_i32(ret_low, ret_high, temp64); } @@ -1662,7 +1662,7 @@ gen_msubr64_h(TCGv ret, TCGv r1_low, TCGv r1_high, TCGv r2, TCGv r3, uint32_t n, GEN_HELPER_UU(mul_h, temp64, r2, r3, t_n); break; } - gen_helper_subr_h(ret, cpu_env, temp64, r1_low, r1_high); + gen_helper_subr_h(ret, tcg_env, temp64, r1_low, r1_high); } static inline void @@ -1696,7 +1696,7 @@ gen_msubr64s_h(TCGv ret, TCGv r1_low, TCGv r1_high, TCGv r2, TCGv r3, GEN_HELPER_UU(mul_h, temp64, r2, r3, t_n); break; } - gen_helper_subr_h_ssov(ret, cpu_env, temp64, r1_low, r1_high); + gen_helper_subr_h_ssov(ret, tcg_env, temp64, r1_low, r1_high); } static inline void @@ -1714,14 +1714,14 @@ static inline void gen_msubr_q(TCGv ret, TCGv r1, TCGv r2, TCGv r3, uint32_t n) { TCGv temp = tcg_constant_i32(n); - gen_helper_msubr_q(ret, cpu_env, r1, r2, r3, temp); + gen_helper_msubr_q(ret, tcg_env, r1, r2, r3, temp); } static inline void gen_msubrs_q(TCGv ret, TCGv r1, TCGv r2, TCGv r3, uint32_t n) { TCGv temp = tcg_constant_i32(n); - gen_helper_msubr_q_ssov(ret, cpu_env, r1, r2, r3, temp); + gen_helper_msubr_q_ssov(ret, tcg_env, r1, r2, r3, temp); } static inline void @@ -1848,7 +1848,7 @@ gen_m16subs64_q(TCGv rl, TCGv rh, TCGv arg1_low, TCGv arg1_high, TCGv arg2, tcg_gen_shli_i64(t2, t2, 16); tcg_gen_concat_i32_i64(t1, arg1_low, arg1_high); - gen_helper_sub64_ssov(t1, cpu_env, t1, t2); + gen_helper_sub64_ssov(t1, tcg_env, t1, t2); tcg_gen_extr_i64_i32(rl, rh, t1); } @@ -1920,7 +1920,7 @@ gen_msubs32_q(TCGv ret, TCGv arg1, TCGv arg2, TCGv arg3, uint32_t n, tcg_gen_sari_i64(t3, t2, up_shift - n); tcg_gen_add_i64(t3, t3, t4); - gen_helper_msub32_q_sub_ssov(ret, cpu_env, t1, t3); + gen_helper_msub32_q_sub_ssov(ret, tcg_env, t1, t3); } static inline void @@ -1931,7 +1931,7 @@ gen_msubs64_q(TCGv rl, TCGv rh, TCGv arg1_low, TCGv arg1_high, TCGv arg2, TCGv t_n = tcg_constant_i32(n); tcg_gen_concat_i32_i64(r1, arg1_low, arg1_high); - gen_helper_msub64_q_ssov(r1, cpu_env, r1, arg2, arg3, t_n); + gen_helper_msub64_q_ssov(r1, tcg_env, r1, arg2, arg3, t_n); tcg_gen_extr_i64_i32(rl, rh, r1); } @@ -2018,7 +2018,7 @@ gen_msubadr32_h(TCGv ret, TCGv r1, TCGv r2, TCGv r3, uint32_t n, uint32_t mode) } tcg_gen_andi_tl(temp2, r1, 0xffff0000); tcg_gen_shli_tl(temp, r1, 16); - gen_helper_subadr_h(ret, cpu_env, temp64, temp, temp2); + gen_helper_subadr_h(ret, tcg_env, temp64, temp, temp2); } static inline void @@ -2084,7 +2084,7 @@ gen_msubadms_h(TCGv ret_low, TCGv ret_high, TCGv r1_low, TCGv r1_high, TCGv r2, tcg_gen_shli_i64(temp64, temp64, 16); tcg_gen_concat_i32_i64(temp64_2, r1_low, r1_high); - gen_helper_sub64_ssov(temp64, cpu_env, temp64_2, temp64); + gen_helper_sub64_ssov(temp64, tcg_env, temp64_2, temp64); tcg_gen_extr_i64_i32(ret_low, ret_high, temp64); } @@ -2111,7 +2111,7 @@ gen_msubadr32s_h(TCGv ret, TCGv r1, TCGv r2, TCGv r3, uint32_t n, uint32_t mode) } tcg_gen_andi_tl(temp2, r1, 0xffff0000); tcg_gen_shli_tl(temp, r1, 16); - gen_helper_subadr_h_ssov(ret, cpu_env, temp64, temp, temp2); + gen_helper_subadr_h_ssov(ret, tcg_env, temp64, temp, temp2); } static inline void gen_abs(TCGv ret, TCGv r1) @@ -2164,7 +2164,7 @@ static inline void gen_absdifi(TCGv ret, TCGv r1, int32_t con) static inline void gen_absdifsi(TCGv ret, TCGv r1, int32_t con) { TCGv temp = tcg_constant_i32(con); - gen_helper_absdif_ssov(ret, cpu_env, r1, temp); + gen_helper_absdif_ssov(ret, tcg_env, r1, temp); } static inline void gen_mul_i32s(TCGv ret, TCGv r1, TCGv r2) @@ -2238,26 +2238,26 @@ static inline void gen_muli_i64u(TCGv ret_low, TCGv ret_high, TCGv r1, static inline void gen_mulsi_i32(TCGv ret, TCGv r1, int32_t con) { TCGv temp = tcg_constant_i32(con); - gen_helper_mul_ssov(ret, cpu_env, r1, temp); + gen_helper_mul_ssov(ret, tcg_env, r1, temp); } static inline void gen_mulsui_i32(TCGv ret, TCGv r1, int32_t con) { TCGv temp = tcg_constant_i32(con); - gen_helper_mul_suov(ret, cpu_env, r1, temp); + gen_helper_mul_suov(ret, tcg_env, r1, temp); } /* gen_maddsi_32(cpu_gpr_d[r4], cpu_gpr_d[r1], cpu_gpr_d[r3], const9); */ static inline void gen_maddsi_32(TCGv ret, TCGv r1, TCGv r2, int32_t con) { TCGv temp = tcg_constant_i32(con); - gen_helper_madd32_ssov(ret, cpu_env, r1, r2, temp); + gen_helper_madd32_ssov(ret, tcg_env, r1, r2, temp); } static inline void gen_maddsui_32(TCGv ret, TCGv r1, TCGv r2, int32_t con) { TCGv temp = tcg_constant_i32(con); - gen_helper_madd32_suov(ret, cpu_env, r1, r2, temp); + gen_helper_madd32_suov(ret, tcg_env, r1, r2, temp); } static void @@ -2371,7 +2371,7 @@ gen_madds_64(TCGv ret_low, TCGv ret_high, TCGv r1, TCGv r2_low, TCGv r2_high, { TCGv_i64 temp64 = tcg_temp_new_i64(); tcg_gen_concat_i32_i64(temp64, r2_low, r2_high); - gen_helper_madd64_ssov(temp64, cpu_env, r1, temp64, r3); + gen_helper_madd64_ssov(temp64, tcg_env, r1, temp64, r3); tcg_gen_extr_i64_i32(ret_low, ret_high, temp64); } @@ -2389,7 +2389,7 @@ gen_maddsu_64(TCGv ret_low, TCGv ret_high, TCGv r1, TCGv r2_low, TCGv r2_high, { TCGv_i64 temp64 = tcg_temp_new_i64(); tcg_gen_concat_i32_i64(temp64, r2_low, r2_high); - gen_helper_madd64_suov(temp64, cpu_env, r1, temp64, r3); + gen_helper_madd64_suov(temp64, tcg_env, r1, temp64, r3); tcg_gen_extr_i64_i32(ret_low, ret_high, temp64); } @@ -2404,13 +2404,13 @@ gen_maddsui_64(TCGv ret_low, TCGv ret_high, TCGv r1, TCGv r2_low, TCGv r2_high, static inline void gen_msubsi_32(TCGv ret, TCGv r1, TCGv r2, int32_t con) { TCGv temp = tcg_constant_i32(con); - gen_helper_msub32_ssov(ret, cpu_env, r1, r2, temp); + gen_helper_msub32_ssov(ret, tcg_env, r1, r2, temp); } static inline void gen_msubsui_32(TCGv ret, TCGv r1, TCGv r2, int32_t con) { TCGv temp = tcg_constant_i32(con); - gen_helper_msub32_suov(ret, cpu_env, r1, r2, temp); + gen_helper_msub32_suov(ret, tcg_env, r1, r2, temp); } static inline void @@ -2419,7 +2419,7 @@ gen_msubs_64(TCGv ret_low, TCGv ret_high, TCGv r1, TCGv r2_low, TCGv r2_high, { TCGv_i64 temp64 = tcg_temp_new_i64(); tcg_gen_concat_i32_i64(temp64, r2_low, r2_high); - gen_helper_msub64_ssov(temp64, cpu_env, r1, temp64, r3); + gen_helper_msub64_ssov(temp64, tcg_env, r1, temp64, r3); tcg_gen_extr_i64_i32(ret_low, ret_high, temp64); } @@ -2437,7 +2437,7 @@ gen_msubsu_64(TCGv ret_low, TCGv ret_high, TCGv r1, TCGv r2_low, TCGv r2_high, { TCGv_i64 temp64 = tcg_temp_new_i64(); tcg_gen_concat_i32_i64(temp64, r2_low, r2_high); - gen_helper_msub64_suov(temp64, cpu_env, r1, temp64, r3); + gen_helper_msub64_suov(temp64, tcg_env, r1, temp64, r3); tcg_gen_extr_i64_i32(ret_low, ret_high, temp64); } @@ -2542,7 +2542,7 @@ static void gen_shaci(TCGv ret, TCGv r1, int32_t shift_count) static void gen_shas(TCGv ret, TCGv r1, TCGv r2) { - gen_helper_sha_ssov(ret, cpu_env, r1, r2); + gen_helper_sha_ssov(ret, tcg_env, r1, r2); } static void gen_shasi(TCGv ret, TCGv r1, int32_t con) @@ -2595,29 +2595,29 @@ static void gen_sh_condi(int cond, TCGv ret, TCGv r1, int32_t con) static inline void gen_adds(TCGv ret, TCGv r1, TCGv r2) { - gen_helper_add_ssov(ret, cpu_env, r1, r2); + gen_helper_add_ssov(ret, tcg_env, r1, r2); } static inline void gen_addsi(TCGv ret, TCGv r1, int32_t con) { TCGv temp = tcg_constant_i32(con); - gen_helper_add_ssov(ret, cpu_env, r1, temp); + gen_helper_add_ssov(ret, tcg_env, r1, temp); } static inline void gen_addsui(TCGv ret, TCGv r1, int32_t con) { TCGv temp = tcg_constant_i32(con); - gen_helper_add_suov(ret, cpu_env, r1, temp); + gen_helper_add_suov(ret, tcg_env, r1, temp); } static inline void gen_subs(TCGv ret, TCGv r1, TCGv r2) { - gen_helper_sub_ssov(ret, cpu_env, r1, r2); + gen_helper_sub_ssov(ret, tcg_env, r1, r2); } static inline void gen_subsu(TCGv ret, TCGv r1, TCGv r2) { - gen_helper_sub_suov(ret, cpu_env, r1, r2); + gen_helper_sub_suov(ret, tcg_env, r1, r2); } static inline void gen_bit_2op(TCGv ret, TCGv r1, TCGv r2, @@ -2767,9 +2767,9 @@ gen_dvinit_b(DisasContext *ctx, TCGv rl, TCGv rh, TCGv r1, TCGv r2) TCGv_i64 ret = tcg_temp_new_i64(); if (!has_feature(ctx, TRICORE_FEATURE_131)) { - gen_helper_dvinit_b_13(ret, cpu_env, r1, r2); + gen_helper_dvinit_b_13(ret, tcg_env, r1, r2); } else { - gen_helper_dvinit_b_131(ret, cpu_env, r1, r2); + gen_helper_dvinit_b_131(ret, tcg_env, r1, r2); } tcg_gen_extr_i64_i32(rl, rh, ret); } @@ -2780,9 +2780,9 @@ gen_dvinit_h(DisasContext *ctx, TCGv rl, TCGv rh, TCGv r1, TCGv r2) TCGv_i64 ret = tcg_temp_new_i64(); if (!has_feature(ctx, TRICORE_FEATURE_131)) { - gen_helper_dvinit_h_13(ret, cpu_env, r1, r2); + gen_helper_dvinit_h_13(ret, tcg_env, r1, r2); } else { - gen_helper_dvinit_h_131(ret, cpu_env, r1, r2); + gen_helper_dvinit_h_131(ret, tcg_env, r1, r2); } tcg_gen_extr_i64_i32(rl, rh, ret); } @@ -2841,7 +2841,7 @@ static void generate_trap(DisasContext *ctx, int class, int tin) TCGv_i32 tintemp = tcg_constant_i32(tin); gen_save_pc(ctx->base.pc_next); - gen_helper_raise_exception_sync(cpu_env, classtemp, tintemp); + gen_helper_raise_exception_sync(tcg_env, classtemp, tintemp); ctx->base.is_jmp = DISAS_NORETURN; } @@ -2996,7 +2996,7 @@ static void gen_compute_branch(DisasContext *ctx, uint32_t opc, int r1, break; case OPC2_32_SYS_RET: case OPC2_16_SR_RET: - gen_helper_ret(cpu_env); + gen_helper_ret(tcg_env); ctx->base.is_jmp = DISAS_EXIT; break; /* B-format */ @@ -3493,7 +3493,7 @@ static void decode_sr_system(DisasContext *ctx) gen_compute_branch(ctx, op2, 0, 0, 0, 0); break; case OPC2_16_SR_RFE: - gen_helper_rfe(cpu_env); + gen_helper_rfe(tcg_env); ctx->base.is_jmp = DISAS_EXIT; break; case OPC2_16_SR_DEBUG: @@ -4741,7 +4741,7 @@ static void decode_bo_addrmode_stctx_post_pre_base(DisasContext *ctx) switch (op2) { case OPC2_32_BO_LDLCX_SHORTOFF: tcg_gen_addi_tl(temp, cpu_gpr_a[r2], off10); - gen_helper_ldlcx(cpu_env, temp); + gen_helper_ldlcx(tcg_env, temp); break; case OPC2_32_BO_LDMST_SHORTOFF: tcg_gen_addi_tl(temp, cpu_gpr_a[r2], off10); @@ -4757,18 +4757,18 @@ static void decode_bo_addrmode_stctx_post_pre_base(DisasContext *ctx) break; case OPC2_32_BO_LDUCX_SHORTOFF: tcg_gen_addi_tl(temp, cpu_gpr_a[r2], off10); - gen_helper_lducx(cpu_env, temp); + gen_helper_lducx(tcg_env, temp); break; case OPC2_32_BO_LEA_SHORTOFF: tcg_gen_addi_tl(cpu_gpr_a[r1], cpu_gpr_a[r2], off10); break; case OPC2_32_BO_STLCX_SHORTOFF: tcg_gen_addi_tl(temp, cpu_gpr_a[r2], off10); - gen_helper_stlcx(cpu_env, temp); + gen_helper_stlcx(tcg_env, temp); break; case OPC2_32_BO_STUCX_SHORTOFF: tcg_gen_addi_tl(temp, cpu_gpr_a[r2], off10); - gen_helper_stucx(cpu_env, temp); + gen_helper_stucx(tcg_env, temp); break; case OPC2_32_BO_SWAP_W_SHORTOFF: tcg_gen_addi_tl(temp, cpu_gpr_a[r2], off10); @@ -5593,44 +5593,44 @@ static void decode_rr_accumulator(DisasContext *ctx) gen_abs(cpu_gpr_d[r3], cpu_gpr_d[r2]); break; case OPC2_32_RR_ABS_B: - gen_helper_abs_b(cpu_gpr_d[r3], cpu_env, cpu_gpr_d[r2]); + gen_helper_abs_b(cpu_gpr_d[r3], tcg_env, cpu_gpr_d[r2]); break; case OPC2_32_RR_ABS_H: - gen_helper_abs_h(cpu_gpr_d[r3], cpu_env, cpu_gpr_d[r2]); + gen_helper_abs_h(cpu_gpr_d[r3], tcg_env, cpu_gpr_d[r2]); break; case OPC2_32_RR_ABSDIF: gen_absdif(cpu_gpr_d[r3], cpu_gpr_d[r1], cpu_gpr_d[r2]); break; case OPC2_32_RR_ABSDIF_B: - gen_helper_absdif_b(cpu_gpr_d[r3], cpu_env, cpu_gpr_d[r1], + gen_helper_absdif_b(cpu_gpr_d[r3], tcg_env, cpu_gpr_d[r1], cpu_gpr_d[r2]); break; case OPC2_32_RR_ABSDIF_H: - gen_helper_absdif_h(cpu_gpr_d[r3], cpu_env, cpu_gpr_d[r1], + gen_helper_absdif_h(cpu_gpr_d[r3], tcg_env, cpu_gpr_d[r1], cpu_gpr_d[r2]); break; case OPC2_32_RR_ABSDIFS: - gen_helper_absdif_ssov(cpu_gpr_d[r3], cpu_env, cpu_gpr_d[r1], + gen_helper_absdif_ssov(cpu_gpr_d[r3], tcg_env, cpu_gpr_d[r1], cpu_gpr_d[r2]); break; case OPC2_32_RR_ABSDIFS_H: - gen_helper_absdif_h_ssov(cpu_gpr_d[r3], cpu_env, cpu_gpr_d[r1], + gen_helper_absdif_h_ssov(cpu_gpr_d[r3], tcg_env, cpu_gpr_d[r1], cpu_gpr_d[r2]); break; case OPC2_32_RR_ABSS: - gen_helper_abs_ssov(cpu_gpr_d[r3], cpu_env, cpu_gpr_d[r2]); + gen_helper_abs_ssov(cpu_gpr_d[r3], tcg_env, cpu_gpr_d[r2]); break; case OPC2_32_RR_ABSS_H: - gen_helper_abs_h_ssov(cpu_gpr_d[r3], cpu_env, cpu_gpr_d[r2]); + gen_helper_abs_h_ssov(cpu_gpr_d[r3], tcg_env, cpu_gpr_d[r2]); break; case OPC2_32_RR_ADD: gen_add_d(cpu_gpr_d[r3], cpu_gpr_d[r1], cpu_gpr_d[r2]); break; case OPC2_32_RR_ADD_B: - gen_helper_add_b(cpu_gpr_d[r3], cpu_env, cpu_gpr_d[r1], cpu_gpr_d[r2]); + gen_helper_add_b(cpu_gpr_d[r3], tcg_env, cpu_gpr_d[r1], cpu_gpr_d[r2]); break; case OPC2_32_RR_ADD_H: - gen_helper_add_h(cpu_gpr_d[r3], cpu_env, cpu_gpr_d[r1], cpu_gpr_d[r2]); + gen_helper_add_h(cpu_gpr_d[r3], tcg_env, cpu_gpr_d[r1], cpu_gpr_d[r2]); break; case OPC2_32_RR_ADDC: gen_addc_CC(cpu_gpr_d[r3], cpu_gpr_d[r1], cpu_gpr_d[r2]); @@ -5639,15 +5639,15 @@ static void decode_rr_accumulator(DisasContext *ctx) gen_adds(cpu_gpr_d[r3], cpu_gpr_d[r1], cpu_gpr_d[r2]); break; case OPC2_32_RR_ADDS_H: - gen_helper_add_h_ssov(cpu_gpr_d[r3], cpu_env, cpu_gpr_d[r1], + gen_helper_add_h_ssov(cpu_gpr_d[r3], tcg_env, cpu_gpr_d[r1], cpu_gpr_d[r2]); break; case OPC2_32_RR_ADDS_HU: - gen_helper_add_h_suov(cpu_gpr_d[r3], cpu_env, cpu_gpr_d[r1], + gen_helper_add_h_suov(cpu_gpr_d[r3], tcg_env, cpu_gpr_d[r1], cpu_gpr_d[r2]); break; case OPC2_32_RR_ADDS_U: - gen_helper_add_suov(cpu_gpr_d[r3], cpu_env, cpu_gpr_d[r1], + gen_helper_add_suov(cpu_gpr_d[r3], tcg_env, cpu_gpr_d[r1], cpu_gpr_d[r2]); break; case OPC2_32_RR_ADDX: @@ -5865,10 +5865,10 @@ static void decode_rr_accumulator(DisasContext *ctx) gen_sub_d(cpu_gpr_d[r3], cpu_gpr_d[r1], cpu_gpr_d[r2]); break; case OPC2_32_RR_SUB_B: - gen_helper_sub_b(cpu_gpr_d[r3], cpu_env, cpu_gpr_d[r1], cpu_gpr_d[r2]); + gen_helper_sub_b(cpu_gpr_d[r3], tcg_env, cpu_gpr_d[r1], cpu_gpr_d[r2]); break; case OPC2_32_RR_SUB_H: - gen_helper_sub_h(cpu_gpr_d[r3], cpu_env, cpu_gpr_d[r1], cpu_gpr_d[r2]); + gen_helper_sub_h(cpu_gpr_d[r3], tcg_env, cpu_gpr_d[r1], cpu_gpr_d[r2]); break; case OPC2_32_RR_SUBC: gen_subc_CC(cpu_gpr_d[r3], cpu_gpr_d[r1], cpu_gpr_d[r2]); @@ -5880,11 +5880,11 @@ static void decode_rr_accumulator(DisasContext *ctx) gen_subsu(cpu_gpr_d[r3], cpu_gpr_d[r1], cpu_gpr_d[r2]); break; case OPC2_32_RR_SUBS_H: - gen_helper_sub_h_ssov(cpu_gpr_d[r3], cpu_env, cpu_gpr_d[r1], + gen_helper_sub_h_ssov(cpu_gpr_d[r3], tcg_env, cpu_gpr_d[r1], cpu_gpr_d[r2]); break; case OPC2_32_RR_SUBS_HU: - gen_helper_sub_h_suov(cpu_gpr_d[r3], cpu_env, cpu_gpr_d[r1], + gen_helper_sub_h_suov(cpu_gpr_d[r3], tcg_env, cpu_gpr_d[r1], cpu_gpr_d[r2]); break; case OPC2_32_RR_SUBX: @@ -5974,7 +5974,7 @@ static void decode_rr_logical_shift(DisasContext *ctx) gen_helper_sh_h(cpu_gpr_d[r3], cpu_gpr_d[r1], cpu_gpr_d[r2]); break; case OPC2_32_RR_SHA: - gen_helper_sha(cpu_gpr_d[r3], cpu_env, cpu_gpr_d[r1], cpu_gpr_d[r2]); + gen_helper_sha(cpu_gpr_d[r3], tcg_env, cpu_gpr_d[r1], cpu_gpr_d[r2]); break; case OPC2_32_RR_SHA_H: gen_helper_sha_h(cpu_gpr_d[r3], cpu_gpr_d[r1], cpu_gpr_d[r2]); @@ -6258,55 +6258,55 @@ static void decode_rr_divide(DisasContext *ctx) } break; case OPC2_32_RR_MUL_F: - gen_helper_fmul(cpu_gpr_d[r3], cpu_env, cpu_gpr_d[r1], cpu_gpr_d[r2]); + gen_helper_fmul(cpu_gpr_d[r3], tcg_env, cpu_gpr_d[r1], cpu_gpr_d[r2]); break; case OPC2_32_RR_DIV_F: - gen_helper_fdiv(cpu_gpr_d[r3], cpu_env, cpu_gpr_d[r1], cpu_gpr_d[r2]); + gen_helper_fdiv(cpu_gpr_d[r3], tcg_env, cpu_gpr_d[r1], cpu_gpr_d[r2]); break; case OPC2_32_RR_FTOHP: if (has_feature(ctx, TRICORE_FEATURE_162)) { - gen_helper_ftohp(cpu_gpr_d[r3], cpu_env, cpu_gpr_d[r1]); + gen_helper_ftohp(cpu_gpr_d[r3], tcg_env, cpu_gpr_d[r1]); } else { generate_trap(ctx, TRAPC_INSN_ERR, TIN2_IOPC); } break; case OPC2_32_RR_HPTOF: if (has_feature(ctx, TRICORE_FEATURE_162)) { - gen_helper_hptof(cpu_gpr_d[r3], cpu_env, cpu_gpr_d[r1]); + gen_helper_hptof(cpu_gpr_d[r3], tcg_env, cpu_gpr_d[r1]); } else { generate_trap(ctx, TRAPC_INSN_ERR, TIN2_IOPC); } break; case OPC2_32_RR_CMP_F: - gen_helper_fcmp(cpu_gpr_d[r3], cpu_env, cpu_gpr_d[r1], cpu_gpr_d[r2]); + gen_helper_fcmp(cpu_gpr_d[r3], tcg_env, cpu_gpr_d[r1], cpu_gpr_d[r2]); break; case OPC2_32_RR_FTOI: - gen_helper_ftoi(cpu_gpr_d[r3], cpu_env, cpu_gpr_d[r1]); + gen_helper_ftoi(cpu_gpr_d[r3], tcg_env, cpu_gpr_d[r1]); break; case OPC2_32_RR_ITOF: - gen_helper_itof(cpu_gpr_d[r3], cpu_env, cpu_gpr_d[r1]); + gen_helper_itof(cpu_gpr_d[r3], tcg_env, cpu_gpr_d[r1]); break; case OPC2_32_RR_FTOU: - gen_helper_ftou(cpu_gpr_d[r3], cpu_env, cpu_gpr_d[r1]); + gen_helper_ftou(cpu_gpr_d[r3], tcg_env, cpu_gpr_d[r1]); break; case OPC2_32_RR_FTOUZ: if (has_feature(ctx, TRICORE_FEATURE_131)) { - gen_helper_ftouz(cpu_gpr_d[r3], cpu_env, cpu_gpr_d[r1]); + gen_helper_ftouz(cpu_gpr_d[r3], tcg_env, cpu_gpr_d[r1]); } else { generate_trap(ctx, TRAPC_INSN_ERR, TIN2_IOPC); } break; case OPC2_32_RR_UPDFL: - gen_helper_updfl(cpu_env, cpu_gpr_d[r1]); + gen_helper_updfl(tcg_env, cpu_gpr_d[r1]); break; case OPC2_32_RR_UTOF: - gen_helper_utof(cpu_gpr_d[r3], cpu_env, cpu_gpr_d[r1]); + gen_helper_utof(cpu_gpr_d[r3], tcg_env, cpu_gpr_d[r1]); break; case OPC2_32_RR_FTOIZ: - gen_helper_ftoiz(cpu_gpr_d[r3], cpu_env, cpu_gpr_d[r1]); + gen_helper_ftoiz(cpu_gpr_d[r3], tcg_env, cpu_gpr_d[r1]); break; case OPC2_32_RR_QSEED_F: - gen_helper_qseed(cpu_gpr_d[r3], cpu_env, cpu_gpr_d[r1]); + gen_helper_qseed(cpu_gpr_d[r3], tcg_env, cpu_gpr_d[r1]); break; default: generate_trap(ctx, TRAPC_INSN_ERR, TIN2_IOPC); @@ -6507,7 +6507,7 @@ static void decode_rr2_mul(DisasContext *ctx) cpu_gpr_d[r2]); break; case OPC2_32_RR2_MULS_32: - gen_helper_mul_ssov(cpu_gpr_d[r3], cpu_env, cpu_gpr_d[r1], + gen_helper_mul_ssov(cpu_gpr_d[r3], tcg_env, cpu_gpr_d[r1], cpu_gpr_d[r2]); break; case OPC2_32_RR2_MUL_U_64: @@ -6516,7 +6516,7 @@ static void decode_rr2_mul(DisasContext *ctx) cpu_gpr_d[r2]); break; case OPC2_32_RR2_MULS_U_32: - gen_helper_mul_suov(cpu_gpr_d[r3], cpu_env, cpu_gpr_d[r1], + gen_helper_mul_suov(cpu_gpr_d[r3], tcg_env, cpu_gpr_d[r1], cpu_gpr_d[r2]); break; default: @@ -6705,17 +6705,17 @@ static void decode_rrr_divide(DisasContext *ctx) } break; case OPC2_32_RRR_ADD_F: - gen_helper_fadd(cpu_gpr_d[r4], cpu_env, cpu_gpr_d[r1], cpu_gpr_d[r3]); + gen_helper_fadd(cpu_gpr_d[r4], tcg_env, cpu_gpr_d[r1], cpu_gpr_d[r3]); break; case OPC2_32_RRR_SUB_F: - gen_helper_fsub(cpu_gpr_d[r4], cpu_env, cpu_gpr_d[r1], cpu_gpr_d[r3]); + gen_helper_fsub(cpu_gpr_d[r4], tcg_env, cpu_gpr_d[r1], cpu_gpr_d[r3]); break; case OPC2_32_RRR_MADD_F: - gen_helper_fmadd(cpu_gpr_d[r4], cpu_env, cpu_gpr_d[r1], + gen_helper_fmadd(cpu_gpr_d[r4], tcg_env, cpu_gpr_d[r1], cpu_gpr_d[r2], cpu_gpr_d[r3]); break; case OPC2_32_RRR_MSUB_F: - gen_helper_fmsub(cpu_gpr_d[r4], cpu_env, cpu_gpr_d[r1], + gen_helper_fmsub(cpu_gpr_d[r4], tcg_env, cpu_gpr_d[r1], cpu_gpr_d[r2], cpu_gpr_d[r3]); break; default: @@ -6746,7 +6746,7 @@ static void decode_rrr2_madd(DisasContext *ctx) cpu_gpr_d[r3], cpu_gpr_d[r3+1], cpu_gpr_d[r2]); break; case OPC2_32_RRR2_MADDS_32: - gen_helper_madd32_ssov(cpu_gpr_d[r4], cpu_env, cpu_gpr_d[r1], + gen_helper_madd32_ssov(cpu_gpr_d[r4], tcg_env, cpu_gpr_d[r1], cpu_gpr_d[r3], cpu_gpr_d[r2]); break; case OPC2_32_RRR2_MADDS_64: @@ -6762,7 +6762,7 @@ static void decode_rrr2_madd(DisasContext *ctx) cpu_gpr_d[r3], cpu_gpr_d[r3+1], cpu_gpr_d[r2]); break; case OPC2_32_RRR2_MADDS_U_32: - gen_helper_madd32_suov(cpu_gpr_d[r4], cpu_env, cpu_gpr_d[r1], + gen_helper_madd32_suov(cpu_gpr_d[r4], tcg_env, cpu_gpr_d[r1], cpu_gpr_d[r3], cpu_gpr_d[r2]); break; case OPC2_32_RRR2_MADDS_U_64: @@ -6799,7 +6799,7 @@ static void decode_rrr2_msub(DisasContext *ctx) cpu_gpr_d[r3], cpu_gpr_d[r3+1], cpu_gpr_d[r2]); break; case OPC2_32_RRR2_MSUBS_32: - gen_helper_msub32_ssov(cpu_gpr_d[r4], cpu_env, cpu_gpr_d[r1], + gen_helper_msub32_ssov(cpu_gpr_d[r4], tcg_env, cpu_gpr_d[r1], cpu_gpr_d[r3], cpu_gpr_d[r2]); break; case OPC2_32_RRR2_MSUBS_64: @@ -6815,7 +6815,7 @@ static void decode_rrr2_msub(DisasContext *ctx) cpu_gpr_d[r3], cpu_gpr_d[r3+1], cpu_gpr_d[r2]); break; case OPC2_32_RRR2_MSUBS_U_32: - gen_helper_msub32_suov(cpu_gpr_d[r4], cpu_env, cpu_gpr_d[r1], + gen_helper_msub32_suov(cpu_gpr_d[r4], tcg_env, cpu_gpr_d[r1], cpu_gpr_d[r3], cpu_gpr_d[r2]); break; case OPC2_32_RRR2_MSUBS_U_64: @@ -7968,7 +7968,7 @@ static void decode_sys_interrupts(DisasContext *ctx) gen_fret(ctx); break; case OPC2_32_SYS_RFE: - gen_helper_rfe(cpu_env); + gen_helper_rfe(tcg_env); ctx->base.is_jmp = DISAS_EXIT; break; case OPC2_32_SYS_RFM: @@ -7976,10 +7976,10 @@ static void decode_sys_interrupts(DisasContext *ctx) tmp = tcg_temp_new(); l1 = gen_new_label(); - tcg_gen_ld32u_tl(tmp, cpu_env, offsetof(CPUTriCoreState, DBGSR)); + tcg_gen_ld32u_tl(tmp, tcg_env, offsetof(CPUTriCoreState, DBGSR)); tcg_gen_andi_tl(tmp, tmp, MASK_DBGSR_DE); tcg_gen_brcondi_tl(TCG_COND_NE, tmp, 1, l1); - gen_helper_rfm(cpu_env); + gen_helper_rfm(tcg_env); gen_set_label(l1); ctx->base.is_jmp = DISAS_EXIT; } else { @@ -7987,10 +7987,10 @@ static void decode_sys_interrupts(DisasContext *ctx) } break; case OPC2_32_SYS_RSLCX: - gen_helper_rslcx(cpu_env); + gen_helper_rslcx(tcg_env); break; case OPC2_32_SYS_SVLCX: - gen_helper_svlcx(cpu_env); + gen_helper_svlcx(tcg_env); break; case OPC2_32_SYS_RESTORE: if (has_feature(ctx, TRICORE_FEATURE_16)) { @@ -8506,13 +8506,13 @@ void cpu_state_reset(CPUTriCoreState *env) static void tricore_tcg_init_csfr(void) { - cpu_PCXI = tcg_global_mem_new(cpu_env, + cpu_PCXI = tcg_global_mem_new(tcg_env, offsetof(CPUTriCoreState, PCXI), "PCXI"); - cpu_PSW = tcg_global_mem_new(cpu_env, + cpu_PSW = tcg_global_mem_new(tcg_env, offsetof(CPUTriCoreState, PSW), "PSW"); - cpu_PC = tcg_global_mem_new(cpu_env, + cpu_PC = tcg_global_mem_new(tcg_env, offsetof(CPUTriCoreState, PC), "PC"); - cpu_ICR = tcg_global_mem_new(cpu_env, + cpu_ICR = tcg_global_mem_new(tcg_env, offsetof(CPUTriCoreState, ICR), "ICR"); } @@ -8522,30 +8522,30 @@ void tricore_tcg_init(void) /* reg init */ for (i = 0 ; i < 16 ; i++) { - cpu_gpr_a[i] = tcg_global_mem_new(cpu_env, + cpu_gpr_a[i] = tcg_global_mem_new(tcg_env, offsetof(CPUTriCoreState, gpr_a[i]), regnames_a[i]); } for (i = 0 ; i < 16 ; i++) { - cpu_gpr_d[i] = tcg_global_mem_new(cpu_env, + cpu_gpr_d[i] = tcg_global_mem_new(tcg_env, offsetof(CPUTriCoreState, gpr_d[i]), regnames_d[i]); } tricore_tcg_init_csfr(); /* init PSW flag cache */ - cpu_PSW_C = tcg_global_mem_new(cpu_env, + cpu_PSW_C = tcg_global_mem_new(tcg_env, offsetof(CPUTriCoreState, PSW_USB_C), "PSW_C"); - cpu_PSW_V = tcg_global_mem_new(cpu_env, + cpu_PSW_V = tcg_global_mem_new(tcg_env, offsetof(CPUTriCoreState, PSW_USB_V), "PSW_V"); - cpu_PSW_SV = tcg_global_mem_new(cpu_env, + cpu_PSW_SV = tcg_global_mem_new(tcg_env, offsetof(CPUTriCoreState, PSW_USB_SV), "PSW_SV"); - cpu_PSW_AV = tcg_global_mem_new(cpu_env, + cpu_PSW_AV = tcg_global_mem_new(tcg_env, offsetof(CPUTriCoreState, PSW_USB_AV), "PSW_AV"); - cpu_PSW_SAV = tcg_global_mem_new(cpu_env, + cpu_PSW_SAV = tcg_global_mem_new(tcg_env, offsetof(CPUTriCoreState, PSW_USB_SAV), "PSW_SAV"); } diff --git a/target/xtensa/translate.c b/target/xtensa/translate.c index b7386ff0f0..fca1b9aba4 100644 --- a/target/xtensa/translate.c +++ b/target/xtensa/translate.c @@ -154,49 +154,49 @@ void xtensa_translate_init(void) }; int i; - cpu_pc = tcg_global_mem_new_i32(cpu_env, + cpu_pc = tcg_global_mem_new_i32(tcg_env, offsetof(CPUXtensaState, pc), "pc"); for (i = 0; i < 16; i++) { - cpu_R[i] = tcg_global_mem_new_i32(cpu_env, + cpu_R[i] = tcg_global_mem_new_i32(tcg_env, offsetof(CPUXtensaState, regs[i]), regnames[i]); } for (i = 0; i < 16; i++) { - cpu_FR[i] = tcg_global_mem_new_i32(cpu_env, + cpu_FR[i] = tcg_global_mem_new_i32(tcg_env, offsetof(CPUXtensaState, fregs[i].f32[FP_F32_LOW]), fregnames[i]); } for (i = 0; i < 16; i++) { - cpu_FRD[i] = tcg_global_mem_new_i64(cpu_env, + cpu_FRD[i] = tcg_global_mem_new_i64(tcg_env, offsetof(CPUXtensaState, fregs[i].f64), fregnames[i]); } for (i = 0; i < 4; i++) { - cpu_MR[i] = tcg_global_mem_new_i32(cpu_env, + cpu_MR[i] = tcg_global_mem_new_i32(tcg_env, offsetof(CPUXtensaState, sregs[MR + i]), mregnames[i]); } for (i = 0; i < 16; i++) { - cpu_BR[i] = tcg_global_mem_new_i32(cpu_env, + cpu_BR[i] = tcg_global_mem_new_i32(tcg_env, offsetof(CPUXtensaState, sregs[BR]), bregnames[i]); if (i % 4 == 0) { - cpu_BR4[i / 4] = tcg_global_mem_new_i32(cpu_env, + cpu_BR4[i / 4] = tcg_global_mem_new_i32(tcg_env, offsetof(CPUXtensaState, sregs[BR]), bregnames[i]); } if (i % 8 == 0) { - cpu_BR8[i / 8] = tcg_global_mem_new_i32(cpu_env, + cpu_BR8[i / 8] = tcg_global_mem_new_i32(tcg_env, offsetof(CPUXtensaState, sregs[BR]), bregnames[i]); @@ -205,7 +205,7 @@ void xtensa_translate_init(void) for (i = 0; i < 256; ++i) { if (sr_name[i]) { - cpu_SR[i] = tcg_global_mem_new_i32(cpu_env, + cpu_SR[i] = tcg_global_mem_new_i32(tcg_env, offsetof(CPUXtensaState, sregs[i]), sr_name[i]); @@ -214,7 +214,7 @@ void xtensa_translate_init(void) for (i = 0; i < 256; ++i) { if (ur_name[i]) { - cpu_UR[i] = tcg_global_mem_new_i32(cpu_env, + cpu_UR[i] = tcg_global_mem_new_i32(tcg_env, offsetof(CPUXtensaState, uregs[i]), ur_name[i]); @@ -222,15 +222,15 @@ void xtensa_translate_init(void) } cpu_windowbase_next = - tcg_global_mem_new_i32(cpu_env, + tcg_global_mem_new_i32(tcg_env, offsetof(CPUXtensaState, windowbase_next), "windowbase_next"); cpu_exclusive_addr = - tcg_global_mem_new_i32(cpu_env, + tcg_global_mem_new_i32(tcg_env, offsetof(CPUXtensaState, exclusive_addr), "exclusive_addr"); cpu_exclusive_val = - tcg_global_mem_new_i32(cpu_env, + tcg_global_mem_new_i32(tcg_env, offsetof(CPUXtensaState, exclusive_val), "exclusive_val"); } @@ -311,13 +311,13 @@ static void gen_left_shift_sar(DisasContext *dc, TCGv_i32 sa) static void gen_exception(DisasContext *dc, int excp) { - gen_helper_exception(cpu_env, tcg_constant_i32(excp)); + gen_helper_exception(tcg_env, tcg_constant_i32(excp)); } static void gen_exception_cause(DisasContext *dc, uint32_t cause) { TCGv_i32 pc = tcg_constant_i32(dc->pc); - gen_helper_exception_cause(cpu_env, pc, tcg_constant_i32(cause)); + gen_helper_exception_cause(tcg_env, pc, tcg_constant_i32(cause)); if (cause == ILLEGAL_INSTRUCTION_CAUSE || cause == SYSCALL_CAUSE) { dc->base.is_jmp = DISAS_NORETURN; @@ -327,7 +327,7 @@ static void gen_exception_cause(DisasContext *dc, uint32_t cause) static void gen_debug_exception(DisasContext *dc, uint32_t cause) { TCGv_i32 pc = tcg_constant_i32(dc->pc); - gen_helper_debug_exception(cpu_env, pc, tcg_constant_i32(cause)); + gen_helper_debug_exception(tcg_env, pc, tcg_constant_i32(cause)); if (cause & (DEBUGCAUSE_IB | DEBUGCAUSE_BI | DEBUGCAUSE_BN)) { dc->base.is_jmp = DISAS_NORETURN; } @@ -536,7 +536,7 @@ static bool gen_window_check(DisasContext *dc, uint32_t mask) TCGv_i32 pc = tcg_constant_i32(dc->pc); TCGv_i32 w = tcg_constant_i32(r / 4); - gen_helper_window_check(cpu_env, pc, w); + gen_helper_window_check(tcg_env, pc, w); dc->base.is_jmp = DISAS_NORETURN; return false; } @@ -576,11 +576,11 @@ static int gen_postprocess(DisasContext *dc, int slot) #ifndef CONFIG_USER_ONLY if (op_flags & XTENSA_OP_CHECK_INTERRUPTS) { translator_io_start(&dc->base); - gen_helper_check_interrupts(cpu_env); + gen_helper_check_interrupts(tcg_env); } #endif if (op_flags & XTENSA_OP_SYNC_REGISTER_WINDOW) { - gen_helper_sync_windowbase(cpu_env); + gen_helper_sync_windowbase(tcg_env); } if (op_flags & XTENSA_OP_EXIT_TB_M1) { slot = -1; @@ -1042,13 +1042,13 @@ static void disas_xtensa_insn(CPUXtensaState *env, DisasContext *dc) if (op_flags & XTENSA_OP_UNDERFLOW) { TCGv_i32 pc = tcg_constant_i32(dc->pc); - gen_helper_test_underflow_retw(cpu_env, pc); + gen_helper_test_underflow_retw(tcg_env, pc); } if (op_flags & XTENSA_OP_ALLOCA) { TCGv_i32 pc = tcg_constant_i32(dc->pc); - gen_helper_movsp(cpu_env, pc); + gen_helper_movsp(tcg_env, pc); } if (coprocessor && !gen_check_cpenable(dc, coprocessor)) { @@ -1589,7 +1589,7 @@ static void translate_entry(DisasContext *dc, const OpcodeArg arg[], TCGv_i32 pc = tcg_constant_i32(dc->pc); TCGv_i32 s = tcg_constant_i32(arg[0].imm); TCGv_i32 imm = tcg_constant_i32(arg[1].imm); - gen_helper_entry(cpu_env, pc, s, imm); + gen_helper_entry(tcg_env, pc, s, imm); } static void translate_extui(DisasContext *dc, const OpcodeArg arg[], @@ -1620,7 +1620,7 @@ static void translate_icache(DisasContext *dc, const OpcodeArg arg[], tcg_gen_movi_i32(cpu_pc, dc->pc); tcg_gen_addi_i32(addr, arg[0].in, arg[1].imm); - gen_helper_itlb_hit_test(cpu_env, addr); + gen_helper_itlb_hit_test(tcg_env, addr); #endif } @@ -1630,7 +1630,7 @@ static void translate_itlb(DisasContext *dc, const OpcodeArg arg[], #ifndef CONFIG_USER_ONLY TCGv_i32 dtlb = tcg_constant_i32(par[0]); - gen_helper_itlb(cpu_env, arg[0].in, dtlb); + gen_helper_itlb(tcg_env, arg[0].in, dtlb); #endif } @@ -1667,7 +1667,7 @@ static void gen_check_exclusive(DisasContext *dc, TCGv_i32 addr, bool is_write) if (!option_enabled(dc, XTENSA_OPTION_MPU)) { TCGv_i32 pc = tcg_constant_i32(dc->pc); - gen_helper_check_exclusive(cpu_env, pc, addr, + gen_helper_check_exclusive(tcg_env, pc, addr, tcg_constant_i32(is_write)); } } @@ -1959,7 +1959,7 @@ static void translate_ptlb(DisasContext *dc, const OpcodeArg arg[], TCGv_i32 dtlb = tcg_constant_i32(par[0]); tcg_gen_movi_i32(cpu_pc, dc->pc); - gen_helper_ptlb(arg[0].out, cpu_env, arg[1].in, dtlb); + gen_helper_ptlb(arg[0].out, tcg_env, arg[1].in, dtlb); #endif } @@ -1968,7 +1968,7 @@ static void translate_pptlb(DisasContext *dc, const OpcodeArg arg[], { #ifndef CONFIG_USER_ONLY tcg_gen_movi_i32(cpu_pc, dc->pc); - gen_helper_pptlb(arg[0].out, cpu_env, arg[1].in); + gen_helper_pptlb(arg[0].out, tcg_env, arg[1].in); #endif } @@ -2020,7 +2020,7 @@ static void translate_remu(DisasContext *dc, const OpcodeArg arg[], static void translate_rer(DisasContext *dc, const OpcodeArg arg[], const uint32_t par[]) { - gen_helper_rer(arg[0].out, cpu_env, arg[1].in); + gen_helper_rer(arg[0].out, tcg_env, arg[1].in); } static void translate_ret(DisasContext *dc, const OpcodeArg arg[], @@ -2039,7 +2039,7 @@ static uint32_t test_exceptions_retw(DisasContext *dc, const OpcodeArg arg[], } else { TCGv_i32 pc = tcg_constant_i32(dc->pc); - gen_helper_test_ill_retw(cpu_env, pc); + gen_helper_test_ill_retw(tcg_env, pc); return 0; } } @@ -2053,7 +2053,7 @@ static void translate_retw(DisasContext *dc, const OpcodeArg arg[], cpu_SR[WINDOW_START], tmp); tcg_gen_movi_i32(tmp, dc->pc); tcg_gen_deposit_i32(tmp, tmp, cpu_R[0], 0, 30); - gen_helper_retw(cpu_env, cpu_R[0]); + gen_helper_retw(tcg_env, cpu_R[0]); gen_jump(dc, tmp); } @@ -2093,7 +2093,7 @@ static void translate_rfw(DisasContext *dc, const OpcodeArg arg[], cpu_SR[WINDOW_START], tmp); } - gen_helper_restore_owb(cpu_env); + gen_helper_restore_owb(tcg_env); gen_jump(dc, cpu_SR[EPC1]); } @@ -2126,7 +2126,7 @@ static void translate_rsr_ccount(DisasContext *dc, const OpcodeArg arg[], { #ifndef CONFIG_USER_ONLY translator_io_start(&dc->base); - gen_helper_update_ccount(cpu_env); + gen_helper_update_ccount(tcg_env); tcg_gen_mov_i32(arg[0].out, cpu_SR[par[0]]); #endif } @@ -2154,7 +2154,7 @@ static void translate_rtlb(DisasContext *dc, const OpcodeArg arg[], }; TCGv_i32 dtlb = tcg_constant_i32(par[0]); - helper[par[1]](arg[0].out, cpu_env, arg[1].in, dtlb); + helper[par[1]](arg[0].out, tcg_env, arg[1].in, dtlb); #endif } @@ -2162,7 +2162,7 @@ static void translate_rptlb0(DisasContext *dc, const OpcodeArg arg[], const uint32_t par[]) { #ifndef CONFIG_USER_ONLY - gen_helper_rptlb0(arg[0].out, cpu_env, arg[1].in); + gen_helper_rptlb0(arg[0].out, tcg_env, arg[1].in); #endif } @@ -2170,7 +2170,7 @@ static void translate_rptlb1(DisasContext *dc, const OpcodeArg arg[], const uint32_t par[]) { #ifndef CONFIG_USER_ONLY - gen_helper_rptlb1(arg[0].out, cpu_env, arg[1].in); + gen_helper_rptlb1(arg[0].out, tcg_env, arg[1].in); #endif } @@ -2196,7 +2196,7 @@ static void gen_check_atomctl(DisasContext *dc, TCGv_i32 addr) { TCGv_i32 pc = tcg_constant_i32(dc->pc); - gen_helper_check_atomctl(cpu_env, pc, addr); + gen_helper_check_atomctl(tcg_env, pc, addr); } #endif @@ -2297,7 +2297,7 @@ static void translate_simcall(DisasContext *dc, const OpcodeArg arg[], { #ifndef CONFIG_USER_ONLY if (semihosting_enabled(dc->cring != 0)) { - gen_helper_simcall(cpu_env); + gen_helper_simcall(tcg_env); } #endif } @@ -2442,7 +2442,7 @@ static void translate_waiti(DisasContext *dc, const OpcodeArg arg[], TCGv_i32 pc = tcg_constant_i32(dc->base.pc_next); translator_io_start(&dc->base); - gen_helper_waiti(cpu_env, pc, tcg_constant_i32(arg[0].imm)); + gen_helper_waiti(tcg_env, pc, tcg_constant_i32(arg[0].imm)); #endif } @@ -2452,7 +2452,7 @@ static void translate_wtlb(DisasContext *dc, const OpcodeArg arg[], #ifndef CONFIG_USER_ONLY TCGv_i32 dtlb = tcg_constant_i32(par[0]); - gen_helper_wtlb(cpu_env, arg[0].in, arg[1].in, dtlb); + gen_helper_wtlb(tcg_env, arg[0].in, arg[1].in, dtlb); #endif } @@ -2460,14 +2460,14 @@ static void translate_wptlb(DisasContext *dc, const OpcodeArg arg[], const uint32_t par[]) { #ifndef CONFIG_USER_ONLY - gen_helper_wptlb(cpu_env, arg[0].in, arg[1].in); + gen_helper_wptlb(tcg_env, arg[0].in, arg[1].in); #endif } static void translate_wer(DisasContext *dc, const OpcodeArg arg[], const uint32_t par[]) { - gen_helper_wer(cpu_env, arg[0].in, arg[1].in); + gen_helper_wer(tcg_env, arg[0].in, arg[1].in); } static void translate_wrmsk_expstate(DisasContext *dc, const OpcodeArg arg[], @@ -2508,7 +2508,7 @@ static void translate_wsr_ccompare(DisasContext *dc, const OpcodeArg arg[], assert(id < dc->config->nccompare); translator_io_start(&dc->base); tcg_gen_mov_i32(cpu_SR[par[0]], arg[0].in); - gen_helper_update_ccompare(cpu_env, tcg_constant_i32(id)); + gen_helper_update_ccompare(tcg_env, tcg_constant_i32(id)); #endif } @@ -2517,7 +2517,7 @@ static void translate_wsr_ccount(DisasContext *dc, const OpcodeArg arg[], { #ifndef CONFIG_USER_ONLY translator_io_start(&dc->base); - gen_helper_wsr_ccount(cpu_env, arg[0].in); + gen_helper_wsr_ccount(tcg_env, arg[0].in); #endif } @@ -2528,7 +2528,7 @@ static void translate_wsr_dbreaka(DisasContext *dc, const OpcodeArg arg[], unsigned id = par[0] - DBREAKA; assert(id < dc->config->ndbreak); - gen_helper_wsr_dbreaka(cpu_env, tcg_constant_i32(id), arg[0].in); + gen_helper_wsr_dbreaka(tcg_env, tcg_constant_i32(id), arg[0].in); #endif } @@ -2539,7 +2539,7 @@ static void translate_wsr_dbreakc(DisasContext *dc, const OpcodeArg arg[], unsigned id = par[0] - DBREAKC; assert(id < dc->config->ndbreak); - gen_helper_wsr_dbreakc(cpu_env, tcg_constant_i32(id), arg[0].in); + gen_helper_wsr_dbreakc(tcg_env, tcg_constant_i32(id), arg[0].in); #endif } @@ -2550,7 +2550,7 @@ static void translate_wsr_ibreaka(DisasContext *dc, const OpcodeArg arg[], unsigned id = par[0] - IBREAKA; assert(id < dc->config->nibreak); - gen_helper_wsr_ibreaka(cpu_env, tcg_constant_i32(id), arg[0].in); + gen_helper_wsr_ibreaka(tcg_env, tcg_constant_i32(id), arg[0].in); #endif } @@ -2558,7 +2558,7 @@ static void translate_wsr_ibreakenable(DisasContext *dc, const OpcodeArg arg[], const uint32_t par[]) { #ifndef CONFIG_USER_ONLY - gen_helper_wsr_ibreakenable(cpu_env, arg[0].in); + gen_helper_wsr_ibreakenable(tcg_env, arg[0].in); #endif } @@ -2578,7 +2578,7 @@ static void translate_wsr_intclear(DisasContext *dc, const OpcodeArg arg[], const uint32_t par[]) { #ifndef CONFIG_USER_ONLY - gen_helper_intclear(cpu_env, arg[0].in); + gen_helper_intclear(tcg_env, arg[0].in); #endif } @@ -2586,7 +2586,7 @@ static void translate_wsr_intset(DisasContext *dc, const OpcodeArg arg[], const uint32_t par[]) { #ifndef CONFIG_USER_ONLY - gen_helper_intset(cpu_env, arg[0].in); + gen_helper_intset(tcg_env, arg[0].in); #endif } @@ -2594,7 +2594,7 @@ static void translate_wsr_memctl(DisasContext *dc, const OpcodeArg arg[], const uint32_t par[]) { #ifndef CONFIG_USER_ONLY - gen_helper_wsr_memctl(cpu_env, arg[0].in); + gen_helper_wsr_memctl(tcg_env, arg[0].in); #endif } @@ -2602,7 +2602,7 @@ static void translate_wsr_mpuenb(DisasContext *dc, const OpcodeArg arg[], const uint32_t par[]) { #ifndef CONFIG_USER_ONLY - gen_helper_wsr_mpuenb(cpu_env, arg[0].in); + gen_helper_wsr_mpuenb(tcg_env, arg[0].in); #endif } @@ -2625,7 +2625,7 @@ static void translate_wsr_rasid(DisasContext *dc, const OpcodeArg arg[], const uint32_t par[]) { #ifndef CONFIG_USER_ONLY - gen_helper_wsr_rasid(cpu_env, arg[0].in); + gen_helper_wsr_rasid(tcg_env, arg[0].in); #endif } @@ -2704,9 +2704,9 @@ static void translate_xsr_ccount(DisasContext *dc, const OpcodeArg arg[], TCGv_i32 tmp = tcg_temp_new_i32(); translator_io_start(&dc->base); - gen_helper_update_ccount(cpu_env); + gen_helper_update_ccount(tcg_env); tcg_gen_mov_i32(tmp, cpu_SR[par[0]]); - gen_helper_wsr_ccount(cpu_env, arg[0].in); + gen_helper_wsr_ccount(tcg_env, arg[0].in); tcg_gen_mov_i32(arg[0].out, tmp); #endif @@ -6295,7 +6295,7 @@ static void translate_abs_s(DisasContext *dc, const OpcodeArg arg[], static void translate_fpu2k_add_s(DisasContext *dc, const OpcodeArg arg[], const uint32_t par[]) { - gen_helper_fpu2k_add_s(arg[0].out, cpu_env, + gen_helper_fpu2k_add_s(arg[0].out, tcg_env, arg[1].in, arg[2].in); } @@ -6330,7 +6330,7 @@ static void translate_compare_d(DisasContext *dc, const OpcodeArg arg[], tcg_gen_ori_i32(set_br, arg[0].in, 1 << arg[0].imm); tcg_gen_andi_i32(clr_br, arg[0].in, ~(1 << arg[0].imm)); - helper[par[0]](res, cpu_env, arg[1].in, arg[2].in); + helper[par[0]](res, tcg_env, arg[1].in, arg[2].in); tcg_gen_movcond_i32(TCG_COND_NE, arg[0].out, res, zero, set_br, clr_br); @@ -6359,7 +6359,7 @@ static void translate_compare_s(DisasContext *dc, const OpcodeArg arg[], tcg_gen_andi_i32(clr_br, arg[0].in, ~(1 << arg[0].imm)); get_f32_i2(arg, arg32, 1, 2); - helper[par[0]](res, cpu_env, arg32[1].in, arg32[2].in); + helper[par[0]](res, tcg_env, arg32[1].in, arg32[2].in); tcg_gen_movcond_i32(TCG_COND_NE, arg[0].out, res, zero, set_br, clr_br); @@ -6412,9 +6412,9 @@ static void translate_float_d(DisasContext *dc, const OpcodeArg arg[], TCGv_i32 scale = tcg_constant_i32(-arg[2].imm); if (par[0]) { - gen_helper_uitof_d(arg[0].out, cpu_env, arg[1].in, scale); + gen_helper_uitof_d(arg[0].out, tcg_env, arg[1].in, scale); } else { - gen_helper_itof_d(arg[0].out, cpu_env, arg[1].in, scale); + gen_helper_itof_d(arg[0].out, tcg_env, arg[1].in, scale); } } @@ -6426,9 +6426,9 @@ static void translate_float_s(DisasContext *dc, const OpcodeArg arg[], get_f32_o1(arg, arg32, 0); if (par[0]) { - gen_helper_uitof_s(arg32[0].out, cpu_env, arg[1].in, scale); + gen_helper_uitof_s(arg32[0].out, tcg_env, arg[1].in, scale); } else { - gen_helper_itof_s(arg32[0].out, cpu_env, arg[1].in, scale); + gen_helper_itof_s(arg32[0].out, tcg_env, arg[1].in, scale); } put_f32_o1(arg, arg32, 0); } @@ -6440,10 +6440,10 @@ static void translate_ftoi_d(DisasContext *dc, const OpcodeArg arg[], TCGv_i32 scale = tcg_constant_i32(arg[2].imm); if (par[1]) { - gen_helper_ftoui_d(arg[0].out, cpu_env, arg[1].in, + gen_helper_ftoui_d(arg[0].out, tcg_env, arg[1].in, rounding_mode, scale); } else { - gen_helper_ftoi_d(arg[0].out, cpu_env, arg[1].in, + gen_helper_ftoi_d(arg[0].out, tcg_env, arg[1].in, rounding_mode, scale); } } @@ -6457,10 +6457,10 @@ static void translate_ftoi_s(DisasContext *dc, const OpcodeArg arg[], get_f32_i1(arg, arg32, 1); if (par[1]) { - gen_helper_ftoui_s(arg[0].out, cpu_env, arg32[1].in, + gen_helper_ftoui_s(arg[0].out, tcg_env, arg32[1].in, rounding_mode, scale); } else { - gen_helper_ftoi_s(arg[0].out, cpu_env, arg32[1].in, + gen_helper_ftoi_s(arg[0].out, tcg_env, arg32[1].in, rounding_mode, scale); } put_f32_i1(arg, arg32, 1); @@ -6505,7 +6505,7 @@ static void translate_ldstx(DisasContext *dc, const OpcodeArg arg[], static void translate_fpu2k_madd_s(DisasContext *dc, const OpcodeArg arg[], const uint32_t par[]) { - gen_helper_fpu2k_madd_s(arg[0].out, cpu_env, + gen_helper_fpu2k_madd_s(arg[0].out, tcg_env, arg[0].in, arg[1].in, arg[2].in); } @@ -6584,14 +6584,14 @@ static void translate_movp_s(DisasContext *dc, const OpcodeArg arg[], static void translate_fpu2k_mul_s(DisasContext *dc, const OpcodeArg arg[], const uint32_t par[]) { - gen_helper_fpu2k_mul_s(arg[0].out, cpu_env, + gen_helper_fpu2k_mul_s(arg[0].out, tcg_env, arg[1].in, arg[2].in); } static void translate_fpu2k_msub_s(DisasContext *dc, const OpcodeArg arg[], const uint32_t par[]) { - gen_helper_fpu2k_msub_s(arg[0].out, cpu_env, + gen_helper_fpu2k_msub_s(arg[0].out, tcg_env, arg[0].in, arg[1].in, arg[2].in); } @@ -6630,7 +6630,7 @@ static void translate_rfr_s(DisasContext *dc, const OpcodeArg arg[], static void translate_fpu2k_sub_s(DisasContext *dc, const OpcodeArg arg[], const uint32_t par[]) { - gen_helper_fpu2k_sub_s(arg[0].out, cpu_env, + gen_helper_fpu2k_sub_s(arg[0].out, tcg_env, arg[1].in, arg[2].in); } @@ -6653,7 +6653,7 @@ static void translate_wfr_s(DisasContext *dc, const OpcodeArg arg[], static void translate_wur_fpu2k_fcr(DisasContext *dc, const OpcodeArg arg[], const uint32_t par[]) { - gen_helper_wur_fpu2k_fcr(cpu_env, arg[0].in); + gen_helper_wur_fpu2k_fcr(tcg_env, arg[0].in); } static void translate_wur_fpu2k_fsr(DisasContext *dc, const OpcodeArg arg[], @@ -6882,20 +6882,20 @@ const XtensaOpcodeTranslators xtensa_fpu2000_opcodes = { static void translate_add_d(DisasContext *dc, const OpcodeArg arg[], const uint32_t par[]) { - gen_helper_add_d(arg[0].out, cpu_env, arg[1].in, arg[2].in); + gen_helper_add_d(arg[0].out, tcg_env, arg[1].in, arg[2].in); } static void translate_add_s(DisasContext *dc, const OpcodeArg arg[], const uint32_t par[]) { if (option_enabled(dc, XTENSA_OPTION_DFPU_SINGLE_ONLY)) { - gen_helper_fpu2k_add_s(arg[0].out, cpu_env, + gen_helper_fpu2k_add_s(arg[0].out, tcg_env, arg[1].in, arg[2].in); } else { OpcodeArg arg32[3]; get_f32_o1_i2(arg, arg32, 0, 1, 2); - gen_helper_add_s(arg32[0].out, cpu_env, arg32[1].in, arg32[2].in); + gen_helper_add_s(arg32[0].out, tcg_env, arg32[1].in, arg32[2].in); put_f32_o1_i2(arg, arg32, 0, 1, 2); } } @@ -6906,7 +6906,7 @@ static void translate_cvtd_s(DisasContext *dc, const OpcodeArg arg[], TCGv_i32 v = tcg_temp_new_i32(); tcg_gen_extrl_i64_i32(v, arg[1].in); - gen_helper_cvtd_s(arg[0].out, cpu_env, v); + gen_helper_cvtd_s(arg[0].out, tcg_env, v); } static void translate_cvts_d(DisasContext *dc, const OpcodeArg arg[], @@ -6914,7 +6914,7 @@ static void translate_cvts_d(DisasContext *dc, const OpcodeArg arg[], { TCGv_i32 v = tcg_temp_new_i32(); - gen_helper_cvts_d(v, cpu_env, arg[1].in); + gen_helper_cvts_d(v, tcg_env, arg[1].in); tcg_gen_extu_i32_i64(arg[0].out, v); } @@ -7039,7 +7039,7 @@ static void translate_ldstx_s(DisasContext *dc, const OpcodeArg arg[], static void translate_madd_d(DisasContext *dc, const OpcodeArg arg[], const uint32_t par[]) { - gen_helper_madd_d(arg[0].out, cpu_env, + gen_helper_madd_d(arg[0].out, tcg_env, arg[0].in, arg[1].in, arg[2].in); } @@ -7047,13 +7047,13 @@ static void translate_madd_s(DisasContext *dc, const OpcodeArg arg[], const uint32_t par[]) { if (option_enabled(dc, XTENSA_OPTION_DFPU_SINGLE_ONLY)) { - gen_helper_fpu2k_madd_s(arg[0].out, cpu_env, + gen_helper_fpu2k_madd_s(arg[0].out, tcg_env, arg[0].in, arg[1].in, arg[2].in); } else { OpcodeArg arg32[3]; get_f32_o1_i3(arg, arg32, 0, 0, 1, 2); - gen_helper_madd_s(arg32[0].out, cpu_env, + gen_helper_madd_s(arg32[0].out, tcg_env, arg32[0].in, arg32[1].in, arg32[2].in); put_f32_o1_i3(arg, arg32, 0, 0, 1, 2); } @@ -7062,20 +7062,20 @@ static void translate_madd_s(DisasContext *dc, const OpcodeArg arg[], static void translate_mul_d(DisasContext *dc, const OpcodeArg arg[], const uint32_t par[]) { - gen_helper_mul_d(arg[0].out, cpu_env, arg[1].in, arg[2].in); + gen_helper_mul_d(arg[0].out, tcg_env, arg[1].in, arg[2].in); } static void translate_mul_s(DisasContext *dc, const OpcodeArg arg[], const uint32_t par[]) { if (option_enabled(dc, XTENSA_OPTION_DFPU_SINGLE_ONLY)) { - gen_helper_fpu2k_mul_s(arg[0].out, cpu_env, + gen_helper_fpu2k_mul_s(arg[0].out, tcg_env, arg[1].in, arg[2].in); } else { OpcodeArg arg32[3]; get_f32_o1_i2(arg, arg32, 0, 1, 2); - gen_helper_mul_s(arg32[0].out, cpu_env, arg32[1].in, arg32[2].in); + gen_helper_mul_s(arg32[0].out, tcg_env, arg32[1].in, arg32[2].in); put_f32_o1_i2(arg, arg32, 0, 1, 2); } } @@ -7083,7 +7083,7 @@ static void translate_mul_s(DisasContext *dc, const OpcodeArg arg[], static void translate_msub_d(DisasContext *dc, const OpcodeArg arg[], const uint32_t par[]) { - gen_helper_msub_d(arg[0].out, cpu_env, + gen_helper_msub_d(arg[0].out, tcg_env, arg[0].in, arg[1].in, arg[2].in); } @@ -7091,13 +7091,13 @@ static void translate_msub_s(DisasContext *dc, const OpcodeArg arg[], const uint32_t par[]) { if (option_enabled(dc, XTENSA_OPTION_DFPU_SINGLE_ONLY)) { - gen_helper_fpu2k_msub_s(arg[0].out, cpu_env, + gen_helper_fpu2k_msub_s(arg[0].out, tcg_env, arg[0].in, arg[1].in, arg[2].in); } else { OpcodeArg arg32[3]; get_f32_o1_i3(arg, arg32, 0, 0, 1, 2); - gen_helper_msub_s(arg32[0].out, cpu_env, + gen_helper_msub_s(arg32[0].out, tcg_env, arg32[0].in, arg32[1].in, arg32[2].in); put_f32_o1_i3(arg, arg32, 0, 0, 1, 2); } @@ -7106,20 +7106,20 @@ static void translate_msub_s(DisasContext *dc, const OpcodeArg arg[], static void translate_sub_d(DisasContext *dc, const OpcodeArg arg[], const uint32_t par[]) { - gen_helper_sub_d(arg[0].out, cpu_env, arg[1].in, arg[2].in); + gen_helper_sub_d(arg[0].out, tcg_env, arg[1].in, arg[2].in); } static void translate_sub_s(DisasContext *dc, const OpcodeArg arg[], const uint32_t par[]) { if (option_enabled(dc, XTENSA_OPTION_DFPU_SINGLE_ONLY)) { - gen_helper_fpu2k_sub_s(arg[0].out, cpu_env, + gen_helper_fpu2k_sub_s(arg[0].out, tcg_env, arg[1].in, arg[2].in); } else { OpcodeArg arg32[3]; get_f32_o1_i2(arg, arg32, 0, 1, 2); - gen_helper_sub_s(arg32[0].out, cpu_env, arg32[1].in, arg32[2].in); + gen_helper_sub_s(arg32[0].out, tcg_env, arg32[1].in, arg32[2].in); put_f32_o1_i2(arg, arg32, 0, 1, 2); } } @@ -7127,7 +7127,7 @@ static void translate_sub_s(DisasContext *dc, const OpcodeArg arg[], static void translate_mkdadj_d(DisasContext *dc, const OpcodeArg arg[], const uint32_t par[]) { - gen_helper_mkdadj_d(arg[0].out, cpu_env, arg[0].in, arg[1].in); + gen_helper_mkdadj_d(arg[0].out, tcg_env, arg[0].in, arg[1].in); } static void translate_mkdadj_s(DisasContext *dc, const OpcodeArg arg[], @@ -7136,14 +7136,14 @@ static void translate_mkdadj_s(DisasContext *dc, const OpcodeArg arg[], OpcodeArg arg32[2]; get_f32_o1_i2(arg, arg32, 0, 0, 1); - gen_helper_mkdadj_s(arg32[0].out, cpu_env, arg32[0].in, arg32[1].in); + gen_helper_mkdadj_s(arg32[0].out, tcg_env, arg32[0].in, arg32[1].in); put_f32_o1_i2(arg, arg32, 0, 0, 1); } static void translate_mksadj_d(DisasContext *dc, const OpcodeArg arg[], const uint32_t par[]) { - gen_helper_mksadj_d(arg[0].out, cpu_env, arg[1].in); + gen_helper_mksadj_d(arg[0].out, tcg_env, arg[1].in); } static void translate_mksadj_s(DisasContext *dc, const OpcodeArg arg[], @@ -7152,26 +7152,26 @@ static void translate_mksadj_s(DisasContext *dc, const OpcodeArg arg[], OpcodeArg arg32[2]; get_f32_o1_i1(arg, arg32, 0, 1); - gen_helper_mksadj_s(arg32[0].out, cpu_env, arg32[1].in); + gen_helper_mksadj_s(arg32[0].out, tcg_env, arg32[1].in); put_f32_o1_i1(arg, arg32, 0, 1); } static void translate_wur_fpu_fcr(DisasContext *dc, const OpcodeArg arg[], const uint32_t par[]) { - gen_helper_wur_fpu_fcr(cpu_env, arg[0].in); + gen_helper_wur_fpu_fcr(tcg_env, arg[0].in); } static void translate_rur_fpu_fsr(DisasContext *dc, const OpcodeArg arg[], const uint32_t par[]) { - gen_helper_rur_fpu_fsr(arg[0].out, cpu_env); + gen_helper_rur_fpu_fsr(arg[0].out, tcg_env); } static void translate_wur_fpu_fsr(DisasContext *dc, const OpcodeArg arg[], const uint32_t par[]) { - gen_helper_wur_fpu_fsr(cpu_env, arg[0].in); + gen_helper_wur_fpu_fsr(tcg_env, arg[0].in); } static const XtensaOpcodeOps fpu_ops[] = { diff --git a/tcg/tcg-op-gvec.c b/tcg/tcg-op-gvec.c index 41b1ae18e4..feb2d3686b 100644 --- a/tcg/tcg-op-gvec.c +++ b/tcg/tcg-op-gvec.c @@ -120,8 +120,8 @@ void tcg_gen_gvec_2_ool(uint32_t dofs, uint32_t aofs, a0 = tcg_temp_ebb_new_ptr(); a1 = tcg_temp_ebb_new_ptr(); - tcg_gen_addi_ptr(a0, cpu_env, dofs); - tcg_gen_addi_ptr(a1, cpu_env, aofs); + tcg_gen_addi_ptr(a0, tcg_env, dofs); + tcg_gen_addi_ptr(a1, tcg_env, aofs); fn(a0, a1, desc); @@ -141,8 +141,8 @@ void tcg_gen_gvec_2i_ool(uint32_t dofs, uint32_t aofs, TCGv_i64 c, a0 = tcg_temp_ebb_new_ptr(); a1 = tcg_temp_ebb_new_ptr(); - tcg_gen_addi_ptr(a0, cpu_env, dofs); - tcg_gen_addi_ptr(a1, cpu_env, aofs); + tcg_gen_addi_ptr(a0, tcg_env, dofs); + tcg_gen_addi_ptr(a1, tcg_env, aofs); fn(a0, a1, c, desc); @@ -162,9 +162,9 @@ void tcg_gen_gvec_3_ool(uint32_t dofs, uint32_t aofs, uint32_t bofs, a1 = tcg_temp_ebb_new_ptr(); a2 = tcg_temp_ebb_new_ptr(); - tcg_gen_addi_ptr(a0, cpu_env, dofs); - tcg_gen_addi_ptr(a1, cpu_env, aofs); - tcg_gen_addi_ptr(a2, cpu_env, bofs); + tcg_gen_addi_ptr(a0, tcg_env, dofs); + tcg_gen_addi_ptr(a1, tcg_env, aofs); + tcg_gen_addi_ptr(a2, tcg_env, bofs); fn(a0, a1, a2, desc); @@ -186,10 +186,10 @@ void tcg_gen_gvec_4_ool(uint32_t dofs, uint32_t aofs, uint32_t bofs, a2 = tcg_temp_ebb_new_ptr(); a3 = tcg_temp_ebb_new_ptr(); - tcg_gen_addi_ptr(a0, cpu_env, dofs); - tcg_gen_addi_ptr(a1, cpu_env, aofs); - tcg_gen_addi_ptr(a2, cpu_env, bofs); - tcg_gen_addi_ptr(a3, cpu_env, cofs); + tcg_gen_addi_ptr(a0, tcg_env, dofs); + tcg_gen_addi_ptr(a1, tcg_env, aofs); + tcg_gen_addi_ptr(a2, tcg_env, bofs); + tcg_gen_addi_ptr(a3, tcg_env, cofs); fn(a0, a1, a2, a3, desc); @@ -213,11 +213,11 @@ void tcg_gen_gvec_5_ool(uint32_t dofs, uint32_t aofs, uint32_t bofs, a3 = tcg_temp_ebb_new_ptr(); a4 = tcg_temp_ebb_new_ptr(); - tcg_gen_addi_ptr(a0, cpu_env, dofs); - tcg_gen_addi_ptr(a1, cpu_env, aofs); - tcg_gen_addi_ptr(a2, cpu_env, bofs); - tcg_gen_addi_ptr(a3, cpu_env, cofs); - tcg_gen_addi_ptr(a4, cpu_env, xofs); + tcg_gen_addi_ptr(a0, tcg_env, dofs); + tcg_gen_addi_ptr(a1, tcg_env, aofs); + tcg_gen_addi_ptr(a2, tcg_env, bofs); + tcg_gen_addi_ptr(a3, tcg_env, cofs); + tcg_gen_addi_ptr(a4, tcg_env, xofs); fn(a0, a1, a2, a3, a4, desc); @@ -240,8 +240,8 @@ void tcg_gen_gvec_2_ptr(uint32_t dofs, uint32_t aofs, a0 = tcg_temp_ebb_new_ptr(); a1 = tcg_temp_ebb_new_ptr(); - tcg_gen_addi_ptr(a0, cpu_env, dofs); - tcg_gen_addi_ptr(a1, cpu_env, aofs); + tcg_gen_addi_ptr(a0, tcg_env, dofs); + tcg_gen_addi_ptr(a1, tcg_env, aofs); fn(a0, a1, ptr, desc); @@ -262,9 +262,9 @@ void tcg_gen_gvec_3_ptr(uint32_t dofs, uint32_t aofs, uint32_t bofs, a1 = tcg_temp_ebb_new_ptr(); a2 = tcg_temp_ebb_new_ptr(); - tcg_gen_addi_ptr(a0, cpu_env, dofs); - tcg_gen_addi_ptr(a1, cpu_env, aofs); - tcg_gen_addi_ptr(a2, cpu_env, bofs); + tcg_gen_addi_ptr(a0, tcg_env, dofs); + tcg_gen_addi_ptr(a1, tcg_env, aofs); + tcg_gen_addi_ptr(a2, tcg_env, bofs); fn(a0, a1, a2, ptr, desc); @@ -288,10 +288,10 @@ void tcg_gen_gvec_4_ptr(uint32_t dofs, uint32_t aofs, uint32_t bofs, a2 = tcg_temp_ebb_new_ptr(); a3 = tcg_temp_ebb_new_ptr(); - tcg_gen_addi_ptr(a0, cpu_env, dofs); - tcg_gen_addi_ptr(a1, cpu_env, aofs); - tcg_gen_addi_ptr(a2, cpu_env, bofs); - tcg_gen_addi_ptr(a3, cpu_env, cofs); + tcg_gen_addi_ptr(a0, tcg_env, dofs); + tcg_gen_addi_ptr(a1, tcg_env, aofs); + tcg_gen_addi_ptr(a2, tcg_env, bofs); + tcg_gen_addi_ptr(a3, tcg_env, cofs); fn(a0, a1, a2, a3, ptr, desc); @@ -317,11 +317,11 @@ void tcg_gen_gvec_5_ptr(uint32_t dofs, uint32_t aofs, uint32_t bofs, a3 = tcg_temp_ebb_new_ptr(); a4 = tcg_temp_ebb_new_ptr(); - tcg_gen_addi_ptr(a0, cpu_env, dofs); - tcg_gen_addi_ptr(a1, cpu_env, aofs); - tcg_gen_addi_ptr(a2, cpu_env, bofs); - tcg_gen_addi_ptr(a3, cpu_env, cofs); - tcg_gen_addi_ptr(a4, cpu_env, eofs); + tcg_gen_addi_ptr(a0, tcg_env, dofs); + tcg_gen_addi_ptr(a1, tcg_env, aofs); + tcg_gen_addi_ptr(a2, tcg_env, bofs); + tcg_gen_addi_ptr(a3, tcg_env, cofs); + tcg_gen_addi_ptr(a4, tcg_env, eofs); fn(a0, a1, a2, a3, a4, ptr, desc); @@ -482,7 +482,7 @@ static void do_dup_store(TCGType type, uint32_t dofs, uint32_t oprsz, * are misaligned wrt the maximum vector size, so do that first. */ if (dofs & 8) { - tcg_gen_stl_vec(t_vec, cpu_env, dofs + i, TCG_TYPE_V64); + tcg_gen_stl_vec(t_vec, tcg_env, dofs + i, TCG_TYPE_V64); i += 8; } @@ -494,17 +494,17 @@ static void do_dup_store(TCGType type, uint32_t dofs, uint32_t oprsz, * that e.g. size == 80 would be expanded with 2x32 + 1x16. */ for (; i + 32 <= oprsz; i += 32) { - tcg_gen_stl_vec(t_vec, cpu_env, dofs + i, TCG_TYPE_V256); + tcg_gen_stl_vec(t_vec, tcg_env, dofs + i, TCG_TYPE_V256); } /* fallthru */ case TCG_TYPE_V128: for (; i + 16 <= oprsz; i += 16) { - tcg_gen_stl_vec(t_vec, cpu_env, dofs + i, TCG_TYPE_V128); + tcg_gen_stl_vec(t_vec, tcg_env, dofs + i, TCG_TYPE_V128); } break; case TCG_TYPE_V64: for (; i < oprsz; i += 8) { - tcg_gen_stl_vec(t_vec, cpu_env, dofs + i, TCG_TYPE_V64); + tcg_gen_stl_vec(t_vec, tcg_env, dofs + i, TCG_TYPE_V64); } break; default: @@ -605,14 +605,14 @@ static void do_dup(unsigned vece, uint32_t dofs, uint32_t oprsz, /* Implement inline if we picked an implementation size above. */ if (t_32) { for (i = 0; i < oprsz; i += 4) { - tcg_gen_st_i32(t_32, cpu_env, dofs + i); + tcg_gen_st_i32(t_32, tcg_env, dofs + i); } tcg_temp_free_i32(t_32); goto done; } if (t_64) { for (i = 0; i < oprsz; i += 8) { - tcg_gen_st_i64(t_64, cpu_env, dofs + i); + tcg_gen_st_i64(t_64, tcg_env, dofs + i); } tcg_temp_free_i64(t_64); goto done; @@ -621,7 +621,7 @@ static void do_dup(unsigned vece, uint32_t dofs, uint32_t oprsz, /* Otherwise implement out of line. */ t_ptr = tcg_temp_ebb_new_ptr(); - tcg_gen_addi_ptr(t_ptr, cpu_env, dofs); + tcg_gen_addi_ptr(t_ptr, tcg_env, dofs); /* * This may be expand_clr for the tail of an operation, e.g. @@ -709,12 +709,12 @@ static void expand_2_i32(uint32_t dofs, uint32_t aofs, uint32_t oprsz, uint32_t i; for (i = 0; i < oprsz; i += 4) { - tcg_gen_ld_i32(t0, cpu_env, aofs + i); + tcg_gen_ld_i32(t0, tcg_env, aofs + i); if (load_dest) { - tcg_gen_ld_i32(t1, cpu_env, dofs + i); + tcg_gen_ld_i32(t1, tcg_env, dofs + i); } fni(t1, t0); - tcg_gen_st_i32(t1, cpu_env, dofs + i); + tcg_gen_st_i32(t1, tcg_env, dofs + i); } tcg_temp_free_i32(t0); tcg_temp_free_i32(t1); @@ -729,12 +729,12 @@ static void expand_2i_i32(uint32_t dofs, uint32_t aofs, uint32_t oprsz, uint32_t i; for (i = 0; i < oprsz; i += 4) { - tcg_gen_ld_i32(t0, cpu_env, aofs + i); + tcg_gen_ld_i32(t0, tcg_env, aofs + i); if (load_dest) { - tcg_gen_ld_i32(t1, cpu_env, dofs + i); + tcg_gen_ld_i32(t1, tcg_env, dofs + i); } fni(t1, t0, c); - tcg_gen_st_i32(t1, cpu_env, dofs + i); + tcg_gen_st_i32(t1, tcg_env, dofs + i); } tcg_temp_free_i32(t0); tcg_temp_free_i32(t1); @@ -749,13 +749,13 @@ static void expand_2s_i32(uint32_t dofs, uint32_t aofs, uint32_t oprsz, uint32_t i; for (i = 0; i < oprsz; i += 4) { - tcg_gen_ld_i32(t0, cpu_env, aofs + i); + tcg_gen_ld_i32(t0, tcg_env, aofs + i); if (scalar_first) { fni(t1, c, t0); } else { fni(t1, t0, c); } - tcg_gen_st_i32(t1, cpu_env, dofs + i); + tcg_gen_st_i32(t1, tcg_env, dofs + i); } tcg_temp_free_i32(t0); tcg_temp_free_i32(t1); @@ -772,13 +772,13 @@ static void expand_3_i32(uint32_t dofs, uint32_t aofs, uint32_t i; for (i = 0; i < oprsz; i += 4) { - tcg_gen_ld_i32(t0, cpu_env, aofs + i); - tcg_gen_ld_i32(t1, cpu_env, bofs + i); + tcg_gen_ld_i32(t0, tcg_env, aofs + i); + tcg_gen_ld_i32(t1, tcg_env, bofs + i); if (load_dest) { - tcg_gen_ld_i32(t2, cpu_env, dofs + i); + tcg_gen_ld_i32(t2, tcg_env, dofs + i); } fni(t2, t0, t1); - tcg_gen_st_i32(t2, cpu_env, dofs + i); + tcg_gen_st_i32(t2, tcg_env, dofs + i); } tcg_temp_free_i32(t2); tcg_temp_free_i32(t1); @@ -795,13 +795,13 @@ static void expand_3i_i32(uint32_t dofs, uint32_t aofs, uint32_t bofs, uint32_t i; for (i = 0; i < oprsz; i += 4) { - tcg_gen_ld_i32(t0, cpu_env, aofs + i); - tcg_gen_ld_i32(t1, cpu_env, bofs + i); + tcg_gen_ld_i32(t0, tcg_env, aofs + i); + tcg_gen_ld_i32(t1, tcg_env, bofs + i); if (load_dest) { - tcg_gen_ld_i32(t2, cpu_env, dofs + i); + tcg_gen_ld_i32(t2, tcg_env, dofs + i); } fni(t2, t0, t1, c); - tcg_gen_st_i32(t2, cpu_env, dofs + i); + tcg_gen_st_i32(t2, tcg_env, dofs + i); } tcg_temp_free_i32(t0); tcg_temp_free_i32(t1); @@ -820,13 +820,13 @@ static void expand_4_i32(uint32_t dofs, uint32_t aofs, uint32_t bofs, uint32_t i; for (i = 0; i < oprsz; i += 4) { - tcg_gen_ld_i32(t1, cpu_env, aofs + i); - tcg_gen_ld_i32(t2, cpu_env, bofs + i); - tcg_gen_ld_i32(t3, cpu_env, cofs + i); + tcg_gen_ld_i32(t1, tcg_env, aofs + i); + tcg_gen_ld_i32(t2, tcg_env, bofs + i); + tcg_gen_ld_i32(t3, tcg_env, cofs + i); fni(t0, t1, t2, t3); - tcg_gen_st_i32(t0, cpu_env, dofs + i); + tcg_gen_st_i32(t0, tcg_env, dofs + i); if (write_aofs) { - tcg_gen_st_i32(t1, cpu_env, aofs + i); + tcg_gen_st_i32(t1, tcg_env, aofs + i); } } tcg_temp_free_i32(t3); @@ -847,11 +847,11 @@ static void expand_4i_i32(uint32_t dofs, uint32_t aofs, uint32_t bofs, uint32_t i; for (i = 0; i < oprsz; i += 4) { - tcg_gen_ld_i32(t1, cpu_env, aofs + i); - tcg_gen_ld_i32(t2, cpu_env, bofs + i); - tcg_gen_ld_i32(t3, cpu_env, cofs + i); + tcg_gen_ld_i32(t1, tcg_env, aofs + i); + tcg_gen_ld_i32(t2, tcg_env, bofs + i); + tcg_gen_ld_i32(t3, tcg_env, cofs + i); fni(t0, t1, t2, t3, c); - tcg_gen_st_i32(t0, cpu_env, dofs + i); + tcg_gen_st_i32(t0, tcg_env, dofs + i); } tcg_temp_free_i32(t3); tcg_temp_free_i32(t2); @@ -868,12 +868,12 @@ static void expand_2_i64(uint32_t dofs, uint32_t aofs, uint32_t oprsz, uint32_t i; for (i = 0; i < oprsz; i += 8) { - tcg_gen_ld_i64(t0, cpu_env, aofs + i); + tcg_gen_ld_i64(t0, tcg_env, aofs + i); if (load_dest) { - tcg_gen_ld_i64(t1, cpu_env, dofs + i); + tcg_gen_ld_i64(t1, tcg_env, dofs + i); } fni(t1, t0); - tcg_gen_st_i64(t1, cpu_env, dofs + i); + tcg_gen_st_i64(t1, tcg_env, dofs + i); } tcg_temp_free_i64(t0); tcg_temp_free_i64(t1); @@ -888,12 +888,12 @@ static void expand_2i_i64(uint32_t dofs, uint32_t aofs, uint32_t oprsz, uint32_t i; for (i = 0; i < oprsz; i += 8) { - tcg_gen_ld_i64(t0, cpu_env, aofs + i); + tcg_gen_ld_i64(t0, tcg_env, aofs + i); if (load_dest) { - tcg_gen_ld_i64(t1, cpu_env, dofs + i); + tcg_gen_ld_i64(t1, tcg_env, dofs + i); } fni(t1, t0, c); - tcg_gen_st_i64(t1, cpu_env, dofs + i); + tcg_gen_st_i64(t1, tcg_env, dofs + i); } tcg_temp_free_i64(t0); tcg_temp_free_i64(t1); @@ -908,13 +908,13 @@ static void expand_2s_i64(uint32_t dofs, uint32_t aofs, uint32_t oprsz, uint32_t i; for (i = 0; i < oprsz; i += 8) { - tcg_gen_ld_i64(t0, cpu_env, aofs + i); + tcg_gen_ld_i64(t0, tcg_env, aofs + i); if (scalar_first) { fni(t1, c, t0); } else { fni(t1, t0, c); } - tcg_gen_st_i64(t1, cpu_env, dofs + i); + tcg_gen_st_i64(t1, tcg_env, dofs + i); } tcg_temp_free_i64(t0); tcg_temp_free_i64(t1); @@ -931,13 +931,13 @@ static void expand_3_i64(uint32_t dofs, uint32_t aofs, uint32_t i; for (i = 0; i < oprsz; i += 8) { - tcg_gen_ld_i64(t0, cpu_env, aofs + i); - tcg_gen_ld_i64(t1, cpu_env, bofs + i); + tcg_gen_ld_i64(t0, tcg_env, aofs + i); + tcg_gen_ld_i64(t1, tcg_env, bofs + i); if (load_dest) { - tcg_gen_ld_i64(t2, cpu_env, dofs + i); + tcg_gen_ld_i64(t2, tcg_env, dofs + i); } fni(t2, t0, t1); - tcg_gen_st_i64(t2, cpu_env, dofs + i); + tcg_gen_st_i64(t2, tcg_env, dofs + i); } tcg_temp_free_i64(t2); tcg_temp_free_i64(t1); @@ -954,13 +954,13 @@ static void expand_3i_i64(uint32_t dofs, uint32_t aofs, uint32_t bofs, uint32_t i; for (i = 0; i < oprsz; i += 8) { - tcg_gen_ld_i64(t0, cpu_env, aofs + i); - tcg_gen_ld_i64(t1, cpu_env, bofs + i); + tcg_gen_ld_i64(t0, tcg_env, aofs + i); + tcg_gen_ld_i64(t1, tcg_env, bofs + i); if (load_dest) { - tcg_gen_ld_i64(t2, cpu_env, dofs + i); + tcg_gen_ld_i64(t2, tcg_env, dofs + i); } fni(t2, t0, t1, c); - tcg_gen_st_i64(t2, cpu_env, dofs + i); + tcg_gen_st_i64(t2, tcg_env, dofs + i); } tcg_temp_free_i64(t0); tcg_temp_free_i64(t1); @@ -979,13 +979,13 @@ static void expand_4_i64(uint32_t dofs, uint32_t aofs, uint32_t bofs, uint32_t i; for (i = 0; i < oprsz; i += 8) { - tcg_gen_ld_i64(t1, cpu_env, aofs + i); - tcg_gen_ld_i64(t2, cpu_env, bofs + i); - tcg_gen_ld_i64(t3, cpu_env, cofs + i); + tcg_gen_ld_i64(t1, tcg_env, aofs + i); + tcg_gen_ld_i64(t2, tcg_env, bofs + i); + tcg_gen_ld_i64(t3, tcg_env, cofs + i); fni(t0, t1, t2, t3); - tcg_gen_st_i64(t0, cpu_env, dofs + i); + tcg_gen_st_i64(t0, tcg_env, dofs + i); if (write_aofs) { - tcg_gen_st_i64(t1, cpu_env, aofs + i); + tcg_gen_st_i64(t1, tcg_env, aofs + i); } } tcg_temp_free_i64(t3); @@ -1006,11 +1006,11 @@ static void expand_4i_i64(uint32_t dofs, uint32_t aofs, uint32_t bofs, uint32_t i; for (i = 0; i < oprsz; i += 8) { - tcg_gen_ld_i64(t1, cpu_env, aofs + i); - tcg_gen_ld_i64(t2, cpu_env, bofs + i); - tcg_gen_ld_i64(t3, cpu_env, cofs + i); + tcg_gen_ld_i64(t1, tcg_env, aofs + i); + tcg_gen_ld_i64(t2, tcg_env, bofs + i); + tcg_gen_ld_i64(t3, tcg_env, cofs + i); fni(t0, t1, t2, t3, c); - tcg_gen_st_i64(t0, cpu_env, dofs + i); + tcg_gen_st_i64(t0, tcg_env, dofs + i); } tcg_temp_free_i64(t3); tcg_temp_free_i64(t2); @@ -1029,12 +1029,12 @@ static void expand_2_vec(unsigned vece, uint32_t dofs, uint32_t aofs, uint32_t i; for (i = 0; i < oprsz; i += tysz) { - tcg_gen_ld_vec(t0, cpu_env, aofs + i); + tcg_gen_ld_vec(t0, tcg_env, aofs + i); if (load_dest) { - tcg_gen_ld_vec(t1, cpu_env, dofs + i); + tcg_gen_ld_vec(t1, tcg_env, dofs + i); } fni(vece, t1, t0); - tcg_gen_st_vec(t1, cpu_env, dofs + i); + tcg_gen_st_vec(t1, tcg_env, dofs + i); } tcg_temp_free_vec(t0); tcg_temp_free_vec(t1); @@ -1052,12 +1052,12 @@ static void expand_2i_vec(unsigned vece, uint32_t dofs, uint32_t aofs, uint32_t i; for (i = 0; i < oprsz; i += tysz) { - tcg_gen_ld_vec(t0, cpu_env, aofs + i); + tcg_gen_ld_vec(t0, tcg_env, aofs + i); if (load_dest) { - tcg_gen_ld_vec(t1, cpu_env, dofs + i); + tcg_gen_ld_vec(t1, tcg_env, dofs + i); } fni(vece, t1, t0, c); - tcg_gen_st_vec(t1, cpu_env, dofs + i); + tcg_gen_st_vec(t1, tcg_env, dofs + i); } tcg_temp_free_vec(t0); tcg_temp_free_vec(t1); @@ -1073,13 +1073,13 @@ static void expand_2s_vec(unsigned vece, uint32_t dofs, uint32_t aofs, uint32_t i; for (i = 0; i < oprsz; i += tysz) { - tcg_gen_ld_vec(t0, cpu_env, aofs + i); + tcg_gen_ld_vec(t0, tcg_env, aofs + i); if (scalar_first) { fni(vece, t1, c, t0); } else { fni(vece, t1, t0, c); } - tcg_gen_st_vec(t1, cpu_env, dofs + i); + tcg_gen_st_vec(t1, tcg_env, dofs + i); } tcg_temp_free_vec(t0); tcg_temp_free_vec(t1); @@ -1097,13 +1097,13 @@ static void expand_3_vec(unsigned vece, uint32_t dofs, uint32_t aofs, uint32_t i; for (i = 0; i < oprsz; i += tysz) { - tcg_gen_ld_vec(t0, cpu_env, aofs + i); - tcg_gen_ld_vec(t1, cpu_env, bofs + i); + tcg_gen_ld_vec(t0, tcg_env, aofs + i); + tcg_gen_ld_vec(t1, tcg_env, bofs + i); if (load_dest) { - tcg_gen_ld_vec(t2, cpu_env, dofs + i); + tcg_gen_ld_vec(t2, tcg_env, dofs + i); } fni(vece, t2, t0, t1); - tcg_gen_st_vec(t2, cpu_env, dofs + i); + tcg_gen_st_vec(t2, tcg_env, dofs + i); } tcg_temp_free_vec(t2); tcg_temp_free_vec(t1); @@ -1126,13 +1126,13 @@ static void expand_3i_vec(unsigned vece, uint32_t dofs, uint32_t aofs, uint32_t i; for (i = 0; i < oprsz; i += tysz) { - tcg_gen_ld_vec(t0, cpu_env, aofs + i); - tcg_gen_ld_vec(t1, cpu_env, bofs + i); + tcg_gen_ld_vec(t0, tcg_env, aofs + i); + tcg_gen_ld_vec(t1, tcg_env, bofs + i); if (load_dest) { - tcg_gen_ld_vec(t2, cpu_env, dofs + i); + tcg_gen_ld_vec(t2, tcg_env, dofs + i); } fni(vece, t2, t0, t1, c); - tcg_gen_st_vec(t2, cpu_env, dofs + i); + tcg_gen_st_vec(t2, tcg_env, dofs + i); } tcg_temp_free_vec(t0); tcg_temp_free_vec(t1); @@ -1153,13 +1153,13 @@ static void expand_4_vec(unsigned vece, uint32_t dofs, uint32_t aofs, uint32_t i; for (i = 0; i < oprsz; i += tysz) { - tcg_gen_ld_vec(t1, cpu_env, aofs + i); - tcg_gen_ld_vec(t2, cpu_env, bofs + i); - tcg_gen_ld_vec(t3, cpu_env, cofs + i); + tcg_gen_ld_vec(t1, tcg_env, aofs + i); + tcg_gen_ld_vec(t2, tcg_env, bofs + i); + tcg_gen_ld_vec(t3, tcg_env, cofs + i); fni(vece, t0, t1, t2, t3); - tcg_gen_st_vec(t0, cpu_env, dofs + i); + tcg_gen_st_vec(t0, tcg_env, dofs + i); if (write_aofs) { - tcg_gen_st_vec(t1, cpu_env, aofs + i); + tcg_gen_st_vec(t1, tcg_env, aofs + i); } } tcg_temp_free_vec(t3); @@ -1185,11 +1185,11 @@ static void expand_4i_vec(unsigned vece, uint32_t dofs, uint32_t aofs, uint32_t i; for (i = 0; i < oprsz; i += tysz) { - tcg_gen_ld_vec(t1, cpu_env, aofs + i); - tcg_gen_ld_vec(t2, cpu_env, bofs + i); - tcg_gen_ld_vec(t3, cpu_env, cofs + i); + tcg_gen_ld_vec(t1, tcg_env, aofs + i); + tcg_gen_ld_vec(t2, tcg_env, bofs + i); + tcg_gen_ld_vec(t3, tcg_env, cofs + i); fni(vece, t0, t1, t2, t3, c); - tcg_gen_st_vec(t0, cpu_env, dofs + i); + tcg_gen_st_vec(t0, tcg_env, dofs + i); } tcg_temp_free_vec(t3); tcg_temp_free_vec(t2); @@ -1730,27 +1730,27 @@ void tcg_gen_gvec_dup_mem(unsigned vece, uint32_t dofs, uint32_t aofs, TCGType type = choose_vector_type(NULL, vece, oprsz, 0); if (type != 0) { TCGv_vec t_vec = tcg_temp_new_vec(type); - tcg_gen_dup_mem_vec(vece, t_vec, cpu_env, aofs); + tcg_gen_dup_mem_vec(vece, t_vec, tcg_env, aofs); do_dup_store(type, dofs, oprsz, maxsz, t_vec); tcg_temp_free_vec(t_vec); } else if (vece <= MO_32) { TCGv_i32 in = tcg_temp_ebb_new_i32(); switch (vece) { case MO_8: - tcg_gen_ld8u_i32(in, cpu_env, aofs); + tcg_gen_ld8u_i32(in, tcg_env, aofs); break; case MO_16: - tcg_gen_ld16u_i32(in, cpu_env, aofs); + tcg_gen_ld16u_i32(in, tcg_env, aofs); break; default: - tcg_gen_ld_i32(in, cpu_env, aofs); + tcg_gen_ld_i32(in, tcg_env, aofs); break; } do_dup(vece, dofs, oprsz, maxsz, in, NULL, 0); tcg_temp_free_i32(in); } else { TCGv_i64 in = tcg_temp_ebb_new_i64(); - tcg_gen_ld_i64(in, cpu_env, aofs); + tcg_gen_ld_i64(in, tcg_env, aofs); do_dup(vece, dofs, oprsz, maxsz, NULL, in, 0); tcg_temp_free_i64(in); } @@ -1762,20 +1762,20 @@ void tcg_gen_gvec_dup_mem(unsigned vece, uint32_t dofs, uint32_t aofs, if (TCG_TARGET_HAS_v128) { TCGv_vec in = tcg_temp_new_vec(TCG_TYPE_V128); - tcg_gen_ld_vec(in, cpu_env, aofs); + tcg_gen_ld_vec(in, tcg_env, aofs); for (i = (aofs == dofs) * 16; i < oprsz; i += 16) { - tcg_gen_st_vec(in, cpu_env, dofs + i); + tcg_gen_st_vec(in, tcg_env, dofs + i); } tcg_temp_free_vec(in); } else { TCGv_i64 in0 = tcg_temp_ebb_new_i64(); TCGv_i64 in1 = tcg_temp_ebb_new_i64(); - tcg_gen_ld_i64(in0, cpu_env, aofs); - tcg_gen_ld_i64(in1, cpu_env, aofs + 8); + tcg_gen_ld_i64(in0, tcg_env, aofs); + tcg_gen_ld_i64(in1, tcg_env, aofs + 8); for (i = (aofs == dofs) * 16; i < oprsz; i += 16) { - tcg_gen_st_i64(in0, cpu_env, dofs + i); - tcg_gen_st_i64(in1, cpu_env, dofs + i + 8); + tcg_gen_st_i64(in0, tcg_env, dofs + i); + tcg_gen_st_i64(in1, tcg_env, dofs + i + 8); } tcg_temp_free_i64(in0); tcg_temp_free_i64(in1); @@ -1792,20 +1792,20 @@ void tcg_gen_gvec_dup_mem(unsigned vece, uint32_t dofs, uint32_t aofs, if (TCG_TARGET_HAS_v256) { TCGv_vec in = tcg_temp_new_vec(TCG_TYPE_V256); - tcg_gen_ld_vec(in, cpu_env, aofs); + tcg_gen_ld_vec(in, tcg_env, aofs); for (i = (aofs == dofs) * 32; i < oprsz; i += 32) { - tcg_gen_st_vec(in, cpu_env, dofs + i); + tcg_gen_st_vec(in, tcg_env, dofs + i); } tcg_temp_free_vec(in); } else if (TCG_TARGET_HAS_v128) { TCGv_vec in0 = tcg_temp_new_vec(TCG_TYPE_V128); TCGv_vec in1 = tcg_temp_new_vec(TCG_TYPE_V128); - tcg_gen_ld_vec(in0, cpu_env, aofs); - tcg_gen_ld_vec(in1, cpu_env, aofs + 16); + tcg_gen_ld_vec(in0, tcg_env, aofs); + tcg_gen_ld_vec(in1, tcg_env, aofs + 16); for (i = (aofs == dofs) * 32; i < oprsz; i += 32) { - tcg_gen_st_vec(in0, cpu_env, dofs + i); - tcg_gen_st_vec(in1, cpu_env, dofs + i + 16); + tcg_gen_st_vec(in0, tcg_env, dofs + i); + tcg_gen_st_vec(in1, tcg_env, dofs + i + 16); } tcg_temp_free_vec(in0); tcg_temp_free_vec(in1); @@ -1815,11 +1815,11 @@ void tcg_gen_gvec_dup_mem(unsigned vece, uint32_t dofs, uint32_t aofs, for (j = 0; j < 4; ++j) { in[j] = tcg_temp_ebb_new_i64(); - tcg_gen_ld_i64(in[j], cpu_env, aofs + j * 8); + tcg_gen_ld_i64(in[j], tcg_env, aofs + j * 8); } for (i = (aofs == dofs) * 32; i < oprsz; i += 32) { for (j = 0; j < 4; ++j) { - tcg_gen_st_i64(in[j], cpu_env, dofs + i + j * 8); + tcg_gen_st_i64(in[j], tcg_env, dofs + i + j * 8); } } for (j = 0; j < 4; ++j) { @@ -3140,9 +3140,9 @@ static void expand_2sh_vec(unsigned vece, uint32_t dofs, uint32_t aofs, uint32_t i; for (i = 0; i < oprsz; i += tysz) { - tcg_gen_ld_vec(t0, cpu_env, aofs + i); + tcg_gen_ld_vec(t0, tcg_env, aofs + i); fni(vece, t0, t0, shift); - tcg_gen_st_vec(t0, cpu_env, dofs + i); + tcg_gen_st_vec(t0, tcg_env, dofs + i); } tcg_temp_free_vec(t0); } @@ -3248,8 +3248,8 @@ do_gvec_shifts(unsigned vece, uint32_t dofs, uint32_t aofs, TCGv_i32 shift, tcg_gen_shli_i32(desc, shift, SIMD_DATA_SHIFT); tcg_gen_ori_i32(desc, desc, simd_desc(oprsz, maxsz, 0)); - tcg_gen_addi_ptr(a0, cpu_env, dofs); - tcg_gen_addi_ptr(a1, cpu_env, aofs); + tcg_gen_addi_ptr(a0, tcg_env, dofs); + tcg_gen_addi_ptr(a1, tcg_env, aofs); g->fno[vece](a0, a1, desc); @@ -3690,10 +3690,10 @@ static void expand_cmp_i32(uint32_t dofs, uint32_t aofs, uint32_t bofs, uint32_t i; for (i = 0; i < oprsz; i += 4) { - tcg_gen_ld_i32(t0, cpu_env, aofs + i); - tcg_gen_ld_i32(t1, cpu_env, bofs + i); + tcg_gen_ld_i32(t0, tcg_env, aofs + i); + tcg_gen_ld_i32(t1, tcg_env, bofs + i); tcg_gen_negsetcond_i32(cond, t0, t0, t1); - tcg_gen_st_i32(t0, cpu_env, dofs + i); + tcg_gen_st_i32(t0, tcg_env, dofs + i); } tcg_temp_free_i32(t1); tcg_temp_free_i32(t0); @@ -3707,10 +3707,10 @@ static void expand_cmp_i64(uint32_t dofs, uint32_t aofs, uint32_t bofs, uint32_t i; for (i = 0; i < oprsz; i += 8) { - tcg_gen_ld_i64(t0, cpu_env, aofs + i); - tcg_gen_ld_i64(t1, cpu_env, bofs + i); + tcg_gen_ld_i64(t0, tcg_env, aofs + i); + tcg_gen_ld_i64(t1, tcg_env, bofs + i); tcg_gen_negsetcond_i64(cond, t0, t0, t1); - tcg_gen_st_i64(t0, cpu_env, dofs + i); + tcg_gen_st_i64(t0, tcg_env, dofs + i); } tcg_temp_free_i64(t1); tcg_temp_free_i64(t0); @@ -3725,10 +3725,10 @@ static void expand_cmp_vec(unsigned vece, uint32_t dofs, uint32_t aofs, uint32_t i; for (i = 0; i < oprsz; i += tysz) { - tcg_gen_ld_vec(t0, cpu_env, aofs + i); - tcg_gen_ld_vec(t1, cpu_env, bofs + i); + tcg_gen_ld_vec(t0, tcg_env, aofs + i); + tcg_gen_ld_vec(t1, tcg_env, bofs + i); tcg_gen_cmp_vec(cond, vece, t0, t0, t1); - tcg_gen_st_vec(t0, cpu_env, dofs + i); + tcg_gen_st_vec(t0, tcg_env, dofs + i); } tcg_temp_free_vec(t1); tcg_temp_free_vec(t0); @@ -3855,9 +3855,9 @@ static void expand_cmps_vec(unsigned vece, uint32_t dofs, uint32_t aofs, uint32_t i; for (i = 0; i < oprsz; i += tysz) { - tcg_gen_ld_vec(t1, cpu_env, aofs + i); + tcg_gen_ld_vec(t1, tcg_env, aofs + i); tcg_gen_cmp_vec(cond, vece, t0, t1, c); - tcg_gen_st_vec(t0, cpu_env, dofs + i); + tcg_gen_st_vec(t0, tcg_env, dofs + i); } } @@ -3950,9 +3950,9 @@ void tcg_gen_gvec_cmps(TCGCond cond, unsigned vece, uint32_t dofs, uint32_t i; for (i = 0; i < oprsz; i += 8) { - tcg_gen_ld_i64(t0, cpu_env, aofs + i); + tcg_gen_ld_i64(t0, tcg_env, aofs + i); tcg_gen_negsetcond_i64(cond, t0, t0, c); - tcg_gen_st_i64(t0, cpu_env, dofs + i); + tcg_gen_st_i64(t0, tcg_env, dofs + i); } tcg_temp_free_i64(t0); } else if (vece == MO_32 && check_size_impl(oprsz, 4)) { @@ -3962,9 +3962,9 @@ void tcg_gen_gvec_cmps(TCGCond cond, unsigned vece, uint32_t dofs, 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_ld_i32(t0, tcg_env, aofs + i); tcg_gen_negsetcond_i32(cond, t0, t0, t1); - tcg_gen_st_i32(t0, cpu_env, dofs + i); + tcg_gen_st_i32(t0, tcg_env, dofs + i); } tcg_temp_free_i32(t0); tcg_temp_free_i32(t1); diff --git a/tcg/tcg-op-ldst.c b/tcg/tcg-op-ldst.c index d54c305598..df4f22c427 100644 --- a/tcg/tcg-op-ldst.c +++ b/tcg/tcg-op-ldst.c @@ -589,7 +589,7 @@ static void tcg_gen_qemu_ld_i128_int(TCGv_i128 val, TCGTemp *addr, tcg_gen_extu_i32_i64(ext_addr, temp_tcgv_i32(addr)); addr = tcgv_i64_temp(ext_addr); } - gen_helper_ld_i128(val, cpu_env, temp_tcgv_i64(addr), + gen_helper_ld_i128(val, tcg_env, temp_tcgv_i64(addr), tcg_constant_i32(orig_oi)); } @@ -698,7 +698,7 @@ static void tcg_gen_qemu_st_i128_int(TCGv_i128 val, TCGTemp *addr, tcg_gen_extu_i32_i64(ext_addr, temp_tcgv_i32(addr)); addr = tcgv_i64_temp(ext_addr); } - gen_helper_st_i128(cpu_env, temp_tcgv_i64(addr), val, + gen_helper_st_i128(tcg_env, temp_tcgv_i64(addr), val, tcg_constant_i32(orig_oi)); } @@ -847,7 +847,7 @@ static void tcg_gen_atomic_cmpxchg_i32_int(TCGv_i32 retv, TCGTemp *addr, oi = make_memop_idx(memop & ~MO_SIGN, idx); a64 = maybe_extend_addr64(addr); - gen(retv, cpu_env, a64, cmpv, newv, tcg_constant_i32(oi)); + gen(retv, tcg_env, a64, cmpv, newv, tcg_constant_i32(oi)); maybe_free_addr64(a64); if (memop & MO_SIGN) { @@ -927,12 +927,12 @@ static void tcg_gen_atomic_cmpxchg_i64_int(TCGv_i64 retv, TCGTemp *addr, if (gen) { MemOpIdx oi = make_memop_idx(memop, idx); TCGv_i64 a64 = maybe_extend_addr64(addr); - gen(retv, cpu_env, a64, cmpv, newv, tcg_constant_i32(oi)); + gen(retv, tcg_env, a64, cmpv, newv, tcg_constant_i32(oi)); maybe_free_addr64(a64); return; } - gen_helper_exit_atomic(cpu_env); + gen_helper_exit_atomic(tcg_env); /* * Produce a result for a well-formed opcode stream. This satisfies @@ -990,7 +990,7 @@ static void tcg_gen_nonatomic_cmpxchg_i128_int(TCGv_i128 retv, TCGTemp *addr, MemOpIdx oi = make_memop_idx(memop, idx); TCGv_i64 a64 = maybe_extend_addr64(addr); - gen_helper_nonatomic_cmpxchgo(retv, cpu_env, a64, cmpv, newv, + gen_helper_nonatomic_cmpxchgo(retv, tcg_env, a64, cmpv, newv, tcg_constant_i32(oi)); maybe_free_addr64(a64); } else { @@ -1049,12 +1049,12 @@ static void tcg_gen_atomic_cmpxchg_i128_int(TCGv_i128 retv, TCGTemp *addr, if (gen) { MemOpIdx oi = make_memop_idx(memop, idx); TCGv_i64 a64 = maybe_extend_addr64(addr); - gen(retv, cpu_env, a64, cmpv, newv, tcg_constant_i32(oi)); + gen(retv, tcg_env, a64, cmpv, newv, tcg_constant_i32(oi)); maybe_free_addr64(a64); return; } - gen_helper_exit_atomic(cpu_env); + gen_helper_exit_atomic(tcg_env); /* * Produce a result for a well-formed opcode stream. This satisfies @@ -1108,7 +1108,7 @@ static void do_atomic_op_i32(TCGv_i32 ret, TCGTemp *addr, TCGv_i32 val, oi = make_memop_idx(memop & ~MO_SIGN, idx); a64 = maybe_extend_addr64(addr); - gen(ret, cpu_env, a64, val, tcg_constant_i32(oi)); + gen(ret, tcg_env, a64, val, tcg_constant_i32(oi)); maybe_free_addr64(a64); if (memop & MO_SIGN) { @@ -1146,12 +1146,12 @@ static void do_atomic_op_i64(TCGv_i64 ret, TCGTemp *addr, TCGv_i64 val, if (gen) { MemOpIdx oi = make_memop_idx(memop & ~MO_SIGN, idx); TCGv_i64 a64 = maybe_extend_addr64(addr); - gen(ret, cpu_env, a64, val, tcg_constant_i32(oi)); + gen(ret, tcg_env, a64, val, tcg_constant_i32(oi)); maybe_free_addr64(a64); return; } - gen_helper_exit_atomic(cpu_env); + gen_helper_exit_atomic(tcg_env); /* Produce a result, so that we have a well-formed opcode stream with respect to uses of the result in the (dead) code following. */ tcg_gen_movi_i64(ret, 0); diff --git a/tcg/tcg-op.c b/tcg/tcg-op.c index 02a8cadcc0..393dbcd01c 100644 --- a/tcg/tcg-op.c +++ b/tcg/tcg-op.c @@ -2939,7 +2939,7 @@ void tcg_gen_lookup_and_goto_ptr(void) plugin_gen_disable_mem_helpers(); ptr = tcg_temp_ebb_new_ptr(); - gen_helper_lookup_tb_ptr(ptr, cpu_env); + gen_helper_lookup_tb_ptr(ptr, tcg_env); tcg_gen_op1i(INDEX_op_goto_ptr, tcgv_ptr_arg(ptr)); tcg_temp_free_ptr(ptr); } diff --git a/tcg/tcg.c b/tcg/tcg.c index ea94d0fbff..ec3f93a52f 100644 --- a/tcg/tcg.c +++ b/tcg/tcg.c @@ -231,7 +231,7 @@ __thread TCGContext *tcg_ctx; TCGContext **tcg_ctxs; unsigned int tcg_cur_ctxs; unsigned int tcg_max_ctxs; -TCGv_env cpu_env = 0; +TCGv_env tcg_env; const void *tcg_code_gen_epilogue; uintptr_t tcg_splitwx_diff; @@ -1353,7 +1353,7 @@ static void tcg_context_init(unsigned max_cpus) tcg_debug_assert(!tcg_regset_test_reg(s->reserved_regs, TCG_AREG0)); ts = tcg_global_reg_new_internal(s, TCG_TYPE_PTR, TCG_AREG0, "env"); - cpu_env = temp_tcgv_ptr(ts); + tcg_env = temp_tcgv_ptr(ts); } void tcg_init(size_t tb_size, int splitwx, unsigned max_cpus) From 5783a530166c0881df6fe680e095e28d962fc198 Mon Sep 17 00:00:00 2001 From: Karim Taha Date: Mon, 25 Sep 2023 21:23:58 +0300 Subject: [PATCH 0161/1077] bsd-user: define TARGET_RFSPAWN for rfork to use vfork(2) semantics, and fix RLIM_INFINITY RLIM_INFINITY on FreeBSD, OpenBSD and NetBSD has value of ~(1<<63), caculated one way or another. Signed-off-by: Kyle Evans Signed-off-by: Karim Taha Reviewed-by: Richard Henderson Reviewed-by: Warner Losh Message-Id: <20230925182425.3163-2-kariem.taha2.7@gmail.com> --- bsd-user/syscall_defs.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/bsd-user/syscall_defs.h b/bsd-user/syscall_defs.h index 9c90616baa..ddd38c13e0 100644 --- a/bsd-user/syscall_defs.h +++ b/bsd-user/syscall_defs.h @@ -130,11 +130,7 @@ struct target_freebsd_timeval { /* * sys/resource.h */ -#if defined(__FreeBSD__) #define TARGET_RLIM_INFINITY RLIM_INFINITY -#else -#define TARGET_RLIM_INFINITY ((abi_ulong)-1) -#endif #define TARGET_RLIMIT_CPU 0 #define TARGET_RLIMIT_FSIZE 1 @@ -390,6 +386,10 @@ struct target_freebsd_flock { int32_t l_sysid; } QEMU_PACKED; +/* sys/unistd.h */ +/* user: vfork(2) semantics, clear signals */ +#define TARGET_RFSPAWN (1U << 31) + #define safe_syscall0(type, name) \ type safe_##name(void) \ { \ From d314ae93f1724fa2f5e9636aa6483acf9fa7505f Mon Sep 17 00:00:00 2001 From: Stacey Son Date: Mon, 25 Sep 2023 21:23:59 +0300 Subject: [PATCH 0162/1077] bsd-user: Define procctl(2) related structs Implement procctl flags and related structs: struct target_procctl_reaper_status struct target_procctl_reaper_pidinfo struct target_procctl_reaper_pids struct target_procctl_reaper_kill Signed-off-by: Stacey Son Signed-off-by: Karim Taha Reviewed-by: Richard Henderson Reviewed-by: Warner Losh Message-Id: <20230925182425.3163-3-kariem.taha2.7@gmail.com> --- bsd-user/syscall_defs.h | 42 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) diff --git a/bsd-user/syscall_defs.h b/bsd-user/syscall_defs.h index ddd38c13e0..a3bc738ff8 100644 --- a/bsd-user/syscall_defs.h +++ b/bsd-user/syscall_defs.h @@ -390,6 +390,48 @@ struct target_freebsd_flock { /* user: vfork(2) semantics, clear signals */ #define TARGET_RFSPAWN (1U << 31) +/* + * from sys/procctl.h + */ +#define TARGET_PROC_SPROTECT 1 +#define TARGET_PROC_REAP_ACQUIRE 2 +#define TARGET_PROC_REAP_RELEASE 3 +#define TARGET_PROC_REAP_STATUS 4 +#define TARGET_PROC_REAP_GETPIDS 5 +#define TARGET_PROC_REAP_KILL 6 + +struct target_procctl_reaper_status { + uint32_t rs_flags; + uint32_t rs_children; + uint32_t rs_descendants; + uint32_t rs_reaper; + uint32_t rs_pid; + uint32_t rs_pad0[15]; +}; + +struct target_procctl_reaper_pidinfo { + uint32_t pi_pid; + uint32_t pi_subtree; + uint32_t pi_flags; + uint32_t pi_pad0[15]; +}; + +struct target_procctl_reaper_pids { + uint32_t rp_count; + uint32_t rp_pad0[15]; + abi_ulong rp_pids; +}; + +struct target_procctl_reaper_kill { + int32_t rk_sig; + uint32_t rk_flags; + uint32_t rk_subtree; + uint32_t rk_killed; + uint32_t rk_fpid; + uint32_t rk_pad0[15]; +}; + + #define safe_syscall0(type, name) \ type safe_##name(void) \ { \ From 3f254cf203e7bebc3758058802f834d9ba6ca3dc Mon Sep 17 00:00:00 2001 From: Stacey Son Date: Mon, 25 Sep 2023 21:24:00 +0300 Subject: [PATCH 0163/1077] bsd-user: Implement host_to_target_siginfo. Used in wait6 system call Signed-off-by: Stacey Son Signed-off-by: Karim Taha Reviewed-by: Richard Henderson Reviewed-by: Warner Losh Message-Id: <20230925182425.3163-4-kariem.taha2.7@gmail.com> --- bsd-user/signal-common.h | 1 + bsd-user/signal.c | 6 ++++++ 2 files changed, 7 insertions(+) diff --git a/bsd-user/signal-common.h b/bsd-user/signal-common.h index c044e81165..77d7c7a78b 100644 --- a/bsd-user/signal-common.h +++ b/bsd-user/signal-common.h @@ -35,6 +35,7 @@ int do_sigaction(int sig, const struct target_sigaction *act, abi_long do_sigaltstack(abi_ulong uss_addr, abi_ulong uoss_addr, abi_ulong sp); long do_sigreturn(CPUArchState *env, abi_ulong addr); void force_sig_fault(int sig, int code, abi_ulong addr); +void host_to_target_siginfo(target_siginfo_t *tinfo, const siginfo_t *info); int host_to_target_signal(int sig); void host_to_target_sigset(target_sigset_t *d, const sigset_t *s); void process_pending_signals(CPUArchState *env); diff --git a/bsd-user/signal.c b/bsd-user/signal.c index b6beab659e..ea82241b70 100644 --- a/bsd-user/signal.c +++ b/bsd-user/signal.c @@ -311,6 +311,12 @@ static void tswap_siginfo(target_siginfo_t *tinfo, const target_siginfo_t *info) } } +void host_to_target_siginfo(target_siginfo_t *tinfo, const siginfo_t *info) +{ + host_to_target_siginfo_noswap(tinfo, info); + tswap_siginfo(tinfo, tinfo); +} + int block_signals(void) { TaskState *ts = (TaskState *)thread_cpu->opaque; From cc47390ce7553b29bc8fb12f171836ce5dbf61f5 Mon Sep 17 00:00:00 2001 From: Stacey Son Date: Mon, 25 Sep 2023 21:24:01 +0300 Subject: [PATCH 0164/1077] bsd-user: Add freebsd_exec_common and do_freebsd_procctl to qemu.h. Signed-off-by: Stacey Son Signed-off-by: Karim Taha Reviewed-by: Richard Henderson Reviewed-by: Warner Losh Message-Id: <20230925182425.3163-5-kariem.taha2.7@gmail.com> --- bsd-user/qemu.h | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/bsd-user/qemu.h b/bsd-user/qemu.h index d9507137cc..41c7bd31d3 100644 --- a/bsd-user/qemu.h +++ b/bsd-user/qemu.h @@ -249,6 +249,12 @@ abi_long get_errno(abi_long ret); bool is_error(abi_long ret); int host_to_target_errno(int err); +/* os-proc.c */ +abi_long freebsd_exec_common(abi_ulong path_or_fd, abi_ulong guest_argp, + abi_ulong guest_envp, int do_fexec); +abi_long do_freebsd_procctl(void *cpu_env, int idtype, abi_ulong arg2, + abi_ulong arg3, abi_ulong arg4, abi_ulong arg5, abi_ulong arg6); + /* os-sys.c */ abi_long do_freebsd_sysctl(CPUArchState *env, abi_ulong namep, int32_t namelen, abi_ulong oldp, abi_ulong oldlenp, abi_ulong newp, abi_ulong newlen); From 00bff01fc09c5e3aed4d35842ebc3dbc36a56ee9 Mon Sep 17 00:00:00 2001 From: Stacey Son Date: Mon, 25 Sep 2023 21:24:02 +0300 Subject: [PATCH 0165/1077] bsd-user: add extern declarations for bsd-proc.c conversion functions Signed-off-by: Stacey Son Signed-off-by: Karim Taha Reviewed-by: Richard Henderson Reviewed-by: Warner Losh Message-Id: <20230925182425.3163-6-kariem.taha2.7@gmail.com> --- bsd-user/qemu-bsd.h | 38 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) create mode 100644 bsd-user/qemu-bsd.h diff --git a/bsd-user/qemu-bsd.h b/bsd-user/qemu-bsd.h new file mode 100644 index 0000000000..b93a0b7fd5 --- /dev/null +++ b/bsd-user/qemu-bsd.h @@ -0,0 +1,38 @@ +/* + * BSD conversion extern declarations + * + * Copyright (c) 2013 Stacey D. Son + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + */ + +#ifndef QEMU_BSD_H +#define QEMU_BSD_H + +#include +#include + +/* bsd-proc.c */ +int target_to_host_resource(int code); +rlim_t target_to_host_rlim(abi_llong target_rlim); +abi_llong host_to_target_rlim(rlim_t rlim); +abi_long host_to_target_rusage(abi_ulong target_addr, + const struct rusage *rusage); +abi_long host_to_target_wrusage(abi_ulong target_addr, + const struct __wrusage *wrusage); +int host_to_target_waitstatus(int status); +void h2g_rusage(const struct rusage *rusage, + struct target_freebsd_rusage *target_rusage); + +#endif /* QEMU_BSD_H */ From 0caa37687882569163ed5984d554938fb327ea3c Mon Sep 17 00:00:00 2001 From: Stacey Son Date: Mon, 25 Sep 2023 21:24:03 +0300 Subject: [PATCH 0166/1077] bsd-user: Implement target_to_host_resource conversion function Signed-off-by: Stacey Son Signed-off-by: Karim Taha Reviewed-by: Warner Losh Message-Id: <20230925182425.3163-7-kariem.taha2.7@gmail.com> --- bsd-user/bsd-proc.c | 40 ++++++++++++++++++++++++++++++++++++++++ bsd-user/bsd-proc.h | 4 ++++ bsd-user/meson.build | 6 ++++++ 3 files changed, 50 insertions(+) create mode 100644 bsd-user/bsd-proc.c diff --git a/bsd-user/bsd-proc.c b/bsd-user/bsd-proc.c new file mode 100644 index 0000000000..68410a0aa9 --- /dev/null +++ b/bsd-user/bsd-proc.c @@ -0,0 +1,40 @@ +/* + * BSD process related system call helpers + * + * Copyright (c) 2013-14 Stacey D. Son + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + */ +#include "qemu/osdep.h" + +#include +#include +#include +#include +#include + +#include "qemu.h" +#include "qemu-bsd.h" +#include "signal-common.h" + +#include "bsd-proc.h" + +/* + * resource/rusage conversion + */ +int target_to_host_resource(int code) +{ + return code; +} + diff --git a/bsd-user/bsd-proc.h b/bsd-user/bsd-proc.h index a1061bffb8..048773a75d 100644 --- a/bsd-user/bsd-proc.h +++ b/bsd-user/bsd-proc.h @@ -22,6 +22,10 @@ #include +#include "qemu-bsd.h" +#include "gdbstub/syscalls.h" +#include "qemu/plugin.h" + /* exit(2) */ static inline abi_long do_bsd_exit(void *cpu_env, abi_long arg1) { diff --git a/bsd-user/meson.build b/bsd-user/meson.build index 5243122fc5..b97fce1472 100644 --- a/bsd-user/meson.build +++ b/bsd-user/meson.build @@ -7,6 +7,7 @@ bsd_user_ss = ss.source_set() common_user_inc += include_directories('include') bsd_user_ss.add(files( + 'bsd-proc.c', 'bsdload.c', 'elfload.c', 'main.c', @@ -16,6 +17,11 @@ bsd_user_ss.add(files( 'uaccess.c', )) +elf = cc.find_library('elf', required: true) +procstat = cc.find_library('procstat', required: true) +kvm = cc.find_library('kvm', required: true) +bsd_user_ss.add(elf, procstat, kvm) + # Pull in the OS-specific build glue, if any subdir(targetos) From 550fc7018993d4c21092d6882e4846fc3151d3ed Mon Sep 17 00:00:00 2001 From: Stacey Son Date: Mon, 25 Sep 2023 21:24:04 +0300 Subject: [PATCH 0167/1077] bsd-user: Implement target_to_host_rlim and host_to_target_rlim conversion. Signed-off-by: Stacey Son Signed-off-by: Karim Taha Reviewed-by: Richard Henderson Reviewed-by: Warner Losh Message-Id: <20230925182425.3163-8-kariem.taha2.7@gmail.com> --- bsd-user/bsd-proc.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/bsd-user/bsd-proc.c b/bsd-user/bsd-proc.c index 68410a0aa9..19e39a2f76 100644 --- a/bsd-user/bsd-proc.c +++ b/bsd-user/bsd-proc.c @@ -38,3 +38,13 @@ int target_to_host_resource(int code) return code; } +rlim_t target_to_host_rlim(abi_llong target_rlim) +{ + return tswap64(target_rlim); +} + +abi_llong host_to_target_rlim(rlim_t rlim) +{ + return tswap64(rlim); +} + From 66c51d63d408fe4130d3fb63524d7a009e1e01a6 Mon Sep 17 00:00:00 2001 From: Stacey Son Date: Mon, 25 Sep 2023 21:24:05 +0300 Subject: [PATCH 0168/1077] bsd-user: Implement host_to_target_rusage and host_to_target_wrusage. Signed-off-by: Stacey Son Signed-off-by: Karim Taha Reviewed-by: Richard Henderson Reviewed-by: Warner Losh Message-Id: <20230925182425.3163-9-kariem.taha2.7@gmail.com> --- bsd-user/bsd-proc.c | 54 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 54 insertions(+) diff --git a/bsd-user/bsd-proc.c b/bsd-user/bsd-proc.c index 19e39a2f76..aa386ff482 100644 --- a/bsd-user/bsd-proc.c +++ b/bsd-user/bsd-proc.c @@ -48,3 +48,57 @@ abi_llong host_to_target_rlim(rlim_t rlim) return tswap64(rlim); } +void h2g_rusage(const struct rusage *rusage, + struct target_freebsd_rusage *target_rusage) +{ + __put_user(rusage->ru_utime.tv_sec, &target_rusage->ru_utime.tv_sec); + __put_user(rusage->ru_utime.tv_usec, &target_rusage->ru_utime.tv_usec); + + __put_user(rusage->ru_stime.tv_sec, &target_rusage->ru_stime.tv_sec); + __put_user(rusage->ru_stime.tv_usec, &target_rusage->ru_stime.tv_usec); + + __put_user(rusage->ru_maxrss, &target_rusage->ru_maxrss); + __put_user(rusage->ru_idrss, &target_rusage->ru_idrss); + __put_user(rusage->ru_idrss, &target_rusage->ru_idrss); + __put_user(rusage->ru_isrss, &target_rusage->ru_isrss); + __put_user(rusage->ru_minflt, &target_rusage->ru_minflt); + __put_user(rusage->ru_majflt, &target_rusage->ru_majflt); + __put_user(rusage->ru_nswap, &target_rusage->ru_nswap); + __put_user(rusage->ru_inblock, &target_rusage->ru_inblock); + __put_user(rusage->ru_oublock, &target_rusage->ru_oublock); + __put_user(rusage->ru_msgsnd, &target_rusage->ru_msgsnd); + __put_user(rusage->ru_msgrcv, &target_rusage->ru_msgrcv); + __put_user(rusage->ru_nsignals, &target_rusage->ru_nsignals); + __put_user(rusage->ru_nvcsw, &target_rusage->ru_nvcsw); + __put_user(rusage->ru_nivcsw, &target_rusage->ru_nivcsw); +} + +abi_long host_to_target_rusage(abi_ulong target_addr, + const struct rusage *rusage) +{ + struct target_freebsd_rusage *target_rusage; + + if (!lock_user_struct(VERIFY_WRITE, target_rusage, target_addr, 0)) { + return -TARGET_EFAULT; + } + h2g_rusage(rusage, target_rusage); + unlock_user_struct(target_rusage, target_addr, 1); + + return 0; +} + +abi_long host_to_target_wrusage(abi_ulong target_addr, + const struct __wrusage *wrusage) +{ + struct target_freebsd__wrusage *target_wrusage; + + if (!lock_user_struct(VERIFY_WRITE, target_wrusage, target_addr, 0)) { + return -TARGET_EFAULT; + } + h2g_rusage(&wrusage->wru_self, &target_wrusage->wru_self); + h2g_rusage(&wrusage->wru_children, &target_wrusage->wru_children); + unlock_user_struct(target_wrusage, target_addr, 1); + + return 0; +} + From 3f44e273ff530ae9885b64791779ced571233d1d Mon Sep 17 00:00:00 2001 From: Stacey Son Date: Mon, 25 Sep 2023 21:24:06 +0300 Subject: [PATCH 0169/1077] bsd-user: Implement host_to_target_waitstatus conversion. Signed-off-by: Stacey Son Signed-off-by: Karim Taha Reviewed-by: Richard Henderson Reviewed-by: Warner Losh Message-Id: <20230925182425.3163-10-kariem.taha2.7@gmail.com> --- bsd-user/bsd-proc.c | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/bsd-user/bsd-proc.c b/bsd-user/bsd-proc.c index aa386ff482..19f6efe1f7 100644 --- a/bsd-user/bsd-proc.c +++ b/bsd-user/bsd-proc.c @@ -102,3 +102,20 @@ abi_long host_to_target_wrusage(abi_ulong target_addr, return 0; } +/* + * wait status conversion. + * + * Map host to target signal numbers for the wait family of syscalls. + * Assume all other status bits are the same. + */ +int host_to_target_waitstatus(int status) +{ + if (WIFSIGNALED(status)) { + return host_to_target_signal(WTERMSIG(status)) | (status & ~0x7f); + } + if (WIFSTOPPED(status)) { + return (host_to_target_signal(WSTOPSIG(status)) << 8) | (status & 0xff); + } + return status; +} + From b623031ca60b23dbb8a573306495e7d99821a9af Mon Sep 17 00:00:00 2001 From: Kyle Evans Date: Mon, 25 Sep 2023 21:24:07 +0300 Subject: [PATCH 0170/1077] bsd-user: Get number of cpus. Signed-off-by: Kyle Evans Signed-off-by: Karim Taha Reviewed-by: Warner Losh Message-Id: <20230925182425.3163-11-kariem.taha2.7@gmail.com> --- bsd-user/bsd-proc.c | 24 ++++++++++++++++++++++++ bsd-user/bsd-proc.h | 2 ++ 2 files changed, 26 insertions(+) diff --git a/bsd-user/bsd-proc.c b/bsd-user/bsd-proc.c index 19f6efe1f7..ca3c1bf94f 100644 --- a/bsd-user/bsd-proc.c +++ b/bsd-user/bsd-proc.c @@ -119,3 +119,27 @@ int host_to_target_waitstatus(int status) return status; } +int bsd_get_ncpu(void) +{ + int ncpu = -1; + cpuset_t mask; + + CPU_ZERO(&mask); + + if (cpuset_getaffinity(CPU_LEVEL_WHICH, CPU_WHICH_TID, -1, sizeof(mask), + &mask) == 0) { + ncpu = CPU_COUNT(&mask); + } + + if (ncpu == -1) { + ncpu = sysconf(_SC_NPROCESSORS_ONLN); + } + + if (ncpu == -1) { + gemu_log("XXX Missing bsd_get_ncpu() implementation\n"); + ncpu = 1; + } + + return ncpu; +} + diff --git a/bsd-user/bsd-proc.h b/bsd-user/bsd-proc.h index 048773a75d..b6225e520e 100644 --- a/bsd-user/bsd-proc.h +++ b/bsd-user/bsd-proc.h @@ -26,6 +26,8 @@ #include "gdbstub/syscalls.h" #include "qemu/plugin.h" +int bsd_get_ncpu(void); + /* exit(2) */ static inline abi_long do_bsd_exit(void *cpu_env, abi_long arg1) { From a478416dc89f9eaceb8d6550efd8417a965153a2 Mon Sep 17 00:00:00 2001 From: Stacey Son Date: Mon, 25 Sep 2023 21:24:08 +0300 Subject: [PATCH 0171/1077] bsd-user: Implement getgroups(2) and setgroups(2) system calls. Signed-off-by: Stacey Son Signed-off-by: Karim Taha Reviewed-by: Warner Losh Message-Id: <20230925182425.3163-12-kariem.taha2.7@gmail.com> --- bsd-user/bsd-proc.h | 44 +++++++++++++++++++++++++++++++++++ bsd-user/freebsd/os-syscall.c | 9 +++++++ 2 files changed, 53 insertions(+) diff --git a/bsd-user/bsd-proc.h b/bsd-user/bsd-proc.h index b6225e520e..7b25aa1982 100644 --- a/bsd-user/bsd-proc.h +++ b/bsd-user/bsd-proc.h @@ -41,4 +41,48 @@ static inline abi_long do_bsd_exit(void *cpu_env, abi_long arg1) return 0; } +/* getgroups(2) */ +static inline abi_long do_bsd_getgroups(abi_long gidsetsize, abi_long arg2) +{ + abi_long ret; + uint32_t *target_grouplist; + g_autofree gid_t *grouplist; + int i; + + grouplist = g_try_new(gid_t, gidsetsize); + ret = get_errno(getgroups(gidsetsize, grouplist)); + if (gidsetsize != 0) { + if (!is_error(ret)) { + target_grouplist = lock_user(VERIFY_WRITE, arg2, gidsetsize * 2, 0); + if (!target_grouplist) { + return -TARGET_EFAULT; + } + for (i = 0; i < ret; i++) { + target_grouplist[i] = tswap32(grouplist[i]); + } + unlock_user(target_grouplist, arg2, gidsetsize * 2); + } + } + return ret; +} + +/* setgroups(2) */ +static inline abi_long do_bsd_setgroups(abi_long gidsetsize, abi_long arg2) +{ + uint32_t *target_grouplist; + g_autofree gid_t *grouplist; + int i; + + grouplist = g_try_new(gid_t, gidsetsize); + target_grouplist = lock_user(VERIFY_READ, arg2, gidsetsize * 2, 1); + if (!target_grouplist) { + return -TARGET_EFAULT; + } + for (i = 0; i < gidsetsize; i++) { + grouplist[i] = tswap32(target_grouplist[i]); + } + unlock_user(target_grouplist, arg2, 0); + return get_errno(setgroups(gidsetsize, grouplist)); +} + #endif /* !BSD_PROC_H_ */ diff --git a/bsd-user/freebsd/os-syscall.c b/bsd-user/freebsd/os-syscall.c index fa60df529e..535e6287bd 100644 --- a/bsd-user/freebsd/os-syscall.c +++ b/bsd-user/freebsd/os-syscall.c @@ -223,6 +223,15 @@ static abi_long freebsd_syscall(void *cpu_env, int num, abi_long arg1, ret = do_bsd_exit(cpu_env, arg1); break; + case TARGET_FREEBSD_NR_getgroups: /* getgroups(2) */ + ret = do_bsd_getgroups(arg1, arg2); + break; + + case TARGET_FREEBSD_NR_setgroups: /* setgroups(2) */ + ret = do_bsd_setgroups(arg1, arg2); + break; + + /* * File system calls. */ From 82fe5f3a3454fe19cfff1b52430ef783da10719a Mon Sep 17 00:00:00 2001 From: Stacey Son Date: Mon, 25 Sep 2023 21:24:09 +0300 Subject: [PATCH 0172/1077] bsd-user: Implement umask(2), setlogin(2) and getlogin(2) Signed-off-by: Stacey Son Signed-off-by: Karim Taha Reviewed-by: Warner Losh Message-Id: <20230925182425.3163-13-kariem.taha2.7@gmail.com> --- bsd-user/bsd-proc.h | 39 +++++++++++++++++++++++++++++++++++ bsd-user/freebsd/os-syscall.c | 12 +++++++++++ 2 files changed, 51 insertions(+) diff --git a/bsd-user/bsd-proc.h b/bsd-user/bsd-proc.h index 7b25aa1982..cb7c69acb0 100644 --- a/bsd-user/bsd-proc.h +++ b/bsd-user/bsd-proc.h @@ -26,6 +26,7 @@ #include "gdbstub/syscalls.h" #include "qemu/plugin.h" +extern int _getlogin(char*, int); int bsd_get_ncpu(void); /* exit(2) */ @@ -85,4 +86,42 @@ static inline abi_long do_bsd_setgroups(abi_long gidsetsize, abi_long arg2) return get_errno(setgroups(gidsetsize, grouplist)); } +/* umask(2) */ +static inline abi_long do_bsd_umask(abi_long arg1) +{ + return get_errno(umask(arg1)); +} + +/* setlogin(2) */ +static inline abi_long do_bsd_setlogin(abi_long arg1) +{ + abi_long ret; + void *p; + + p = lock_user_string(arg1); + if (p == NULL) { + return -TARGET_EFAULT; + } + ret = get_errno(setlogin(p)); + unlock_user(p, arg1, 0); + + return ret; +} + +/* getlogin(2) */ +static inline abi_long do_bsd_getlogin(abi_long arg1, abi_long arg2) +{ + abi_long ret; + void *p; + + p = lock_user(VERIFY_WRITE, arg1, arg2, 0); + if (p == NULL) { + return -TARGET_EFAULT; + } + ret = get_errno(_getlogin(p, arg2)); + unlock_user(p, arg1, arg2); + + return ret; +} + #endif /* !BSD_PROC_H_ */ diff --git a/bsd-user/freebsd/os-syscall.c b/bsd-user/freebsd/os-syscall.c index 535e6287bd..44cbf52f08 100644 --- a/bsd-user/freebsd/os-syscall.c +++ b/bsd-user/freebsd/os-syscall.c @@ -231,6 +231,18 @@ static abi_long freebsd_syscall(void *cpu_env, int num, abi_long arg1, ret = do_bsd_setgroups(arg1, arg2); break; + case TARGET_FREEBSD_NR_umask: /* umask(2) */ + ret = do_bsd_umask(arg1); + break; + + case TARGET_FREEBSD_NR_setlogin: /* setlogin(2) */ + ret = do_bsd_setlogin(arg1); + break; + + case TARGET_FREEBSD_NR_getlogin: /* getlogin(2) */ + ret = do_bsd_getlogin(arg1, arg2); + break; + /* * File system calls. From 59e801efdfce31b62d09793d35e85d3bdad0230c Mon Sep 17 00:00:00 2001 From: Stacey Son Date: Mon, 25 Sep 2023 21:24:10 +0300 Subject: [PATCH 0173/1077] bsd-user: Implement getrusage(2). Signed-off-by: Stacey Son Signed-off-by: Karim Taha Reviewed-by: Richard Henderson Reviewed-by: Warner Losh Message-Id: <20230925182425.3163-14-kariem.taha2.7@gmail.com> --- bsd-user/bsd-proc.h | 13 +++++++++++++ bsd-user/freebsd/os-syscall.c | 4 ++++ 2 files changed, 17 insertions(+) diff --git a/bsd-user/bsd-proc.h b/bsd-user/bsd-proc.h index cb7c69acb0..133c1b0eaf 100644 --- a/bsd-user/bsd-proc.h +++ b/bsd-user/bsd-proc.h @@ -124,4 +124,17 @@ static inline abi_long do_bsd_getlogin(abi_long arg1, abi_long arg2) return ret; } +/* getrusage(2) */ +static inline abi_long do_bsd_getrusage(abi_long who, abi_ulong target_addr) +{ + abi_long ret; + struct rusage rusage; + + ret = get_errno(getrusage(who, &rusage)); + if (!is_error(ret)) { + host_to_target_rusage(target_addr, &rusage); + } + return ret; +} + #endif /* !BSD_PROC_H_ */ diff --git a/bsd-user/freebsd/os-syscall.c b/bsd-user/freebsd/os-syscall.c index 44cbf52f08..5d8693ed55 100644 --- a/bsd-user/freebsd/os-syscall.c +++ b/bsd-user/freebsd/os-syscall.c @@ -243,6 +243,10 @@ static abi_long freebsd_syscall(void *cpu_env, int num, abi_long arg1, ret = do_bsd_getlogin(arg1, arg2); break; + case TARGET_FREEBSD_NR_getrusage: /* getrusage(2) */ + ret = do_bsd_getrusage(arg1, arg2); + break; + /* * File system calls. From faba8e123f41902edf762bb12054f096713a5338 Mon Sep 17 00:00:00 2001 From: Stacey Son Date: Mon, 25 Sep 2023 21:24:11 +0300 Subject: [PATCH 0174/1077] bsd-user: Implement getrlimit(2) and setrlimit(2) Signed-off-by: Stacey Son Signed-off-by: Karim Taha Reviewed-by: Richard Henderson Reviewed-by: Warner Losh Message-Id: <20230925182425.3163-15-kariem.taha2.7@gmail.com> --- bsd-user/bsd-proc.h | 59 +++++++++++++++++++++++++++++++++++ bsd-user/freebsd/os-syscall.c | 8 +++++ 2 files changed, 67 insertions(+) diff --git a/bsd-user/bsd-proc.h b/bsd-user/bsd-proc.h index 133c1b0eaf..38d1324034 100644 --- a/bsd-user/bsd-proc.h +++ b/bsd-user/bsd-proc.h @@ -137,4 +137,63 @@ static inline abi_long do_bsd_getrusage(abi_long who, abi_ulong target_addr) return ret; } +/* getrlimit(2) */ +static inline abi_long do_bsd_getrlimit(abi_long arg1, abi_ulong arg2) +{ + abi_long ret; + int resource = target_to_host_resource(arg1); + struct target_rlimit *target_rlim; + struct rlimit rlim; + + switch (resource) { + case RLIMIT_STACK: + rlim.rlim_cur = target_dflssiz; + rlim.rlim_max = target_maxssiz; + ret = 0; + break; + + case RLIMIT_DATA: + rlim.rlim_cur = target_dfldsiz; + rlim.rlim_max = target_maxdsiz; + ret = 0; + break; + + default: + ret = get_errno(getrlimit(resource, &rlim)); + break; + } + if (!is_error(ret)) { + if (!lock_user_struct(VERIFY_WRITE, target_rlim, arg2, 0)) { + return -TARGET_EFAULT; + } + target_rlim->rlim_cur = host_to_target_rlim(rlim.rlim_cur); + target_rlim->rlim_max = host_to_target_rlim(rlim.rlim_max); + unlock_user_struct(target_rlim, arg2, 1); + } + return ret; +} + +/* setrlimit(2) */ +static inline abi_long do_bsd_setrlimit(abi_long arg1, abi_ulong arg2) +{ + abi_long ret; + int resource = target_to_host_resource(arg1); + struct target_rlimit *target_rlim; + struct rlimit rlim; + + if (RLIMIT_STACK == resource) { + /* XXX We should, maybe, allow the stack size to shrink */ + ret = -TARGET_EPERM; + } else { + if (!lock_user_struct(VERIFY_READ, target_rlim, arg2, 1)) { + return -TARGET_EFAULT; + } + rlim.rlim_cur = target_to_host_rlim(target_rlim->rlim_cur); + rlim.rlim_max = target_to_host_rlim(target_rlim->rlim_max); + unlock_user_struct(target_rlim, arg2, 0); + ret = get_errno(setrlimit(resource, &rlim)); + } + return ret; +} + #endif /* !BSD_PROC_H_ */ diff --git a/bsd-user/freebsd/os-syscall.c b/bsd-user/freebsd/os-syscall.c index 5d8693ed55..5cb6086230 100644 --- a/bsd-user/freebsd/os-syscall.c +++ b/bsd-user/freebsd/os-syscall.c @@ -247,6 +247,14 @@ static abi_long freebsd_syscall(void *cpu_env, int num, abi_long arg1, ret = do_bsd_getrusage(arg1, arg2); break; + case TARGET_FREEBSD_NR_getrlimit: /* getrlimit(2) */ + ret = do_bsd_getrlimit(arg1, arg2); + break; + + case TARGET_FREEBSD_NR_setrlimit: /* setrlimit(2) */ + ret = do_bsd_setrlimit(arg1, arg2); + break; + /* * File system calls. From e4446e0a2c8b4f32d53694a85ebdedc06cb69499 Mon Sep 17 00:00:00 2001 From: Stacey Son Date: Mon, 25 Sep 2023 21:24:12 +0300 Subject: [PATCH 0175/1077] bsd-user: Implement several get/set system calls: getpid(2), getppid(2), getpgrp(2) setreuid(2), setregid(2) getuid(2), geteuid(2), getgid(2), getegid(2), getpgid(2) setuid(2), seteuid(2), setgid(2), setegid(2), setpgid(2) Signed-off-by: Stacey Son Signed-off-by: Karim Taha Reviewed-by: Richard Henderson Reviewed-by: Warner Losh Message-Id: <20230925182425.3163-16-kariem.taha2.7@gmail.com> --- bsd-user/bsd-proc.h | 90 +++++++++++++++++++++++++++++++++++ bsd-user/freebsd/os-syscall.c | 60 +++++++++++++++++++++++ 2 files changed, 150 insertions(+) diff --git a/bsd-user/bsd-proc.h b/bsd-user/bsd-proc.h index 38d1324034..6ff07c0ac3 100644 --- a/bsd-user/bsd-proc.h +++ b/bsd-user/bsd-proc.h @@ -196,4 +196,94 @@ static inline abi_long do_bsd_setrlimit(abi_long arg1, abi_ulong arg2) return ret; } +/* getpid(2) */ +static inline abi_long do_bsd_getpid(void) +{ + return get_errno(getpid()); +} + +/* getppid(2) */ +static inline abi_long do_bsd_getppid(void) +{ + return get_errno(getppid()); +} + +/* getuid(2) */ +static inline abi_long do_bsd_getuid(void) +{ + return get_errno(getuid()); +} + +/* geteuid(2) */ +static inline abi_long do_bsd_geteuid(void) +{ + return get_errno(geteuid()); +} + +/* getgid(2) */ +static inline abi_long do_bsd_getgid(void) +{ + return get_errno(getgid()); +} + +/* getegid(2) */ +static inline abi_long do_bsd_getegid(void) +{ + return get_errno(getegid()); +} + +/* setuid(2) */ +static inline abi_long do_bsd_setuid(abi_long arg1) +{ + return get_errno(setuid(arg1)); +} + +/* seteuid(2) */ +static inline abi_long do_bsd_seteuid(abi_long arg1) +{ + return get_errno(seteuid(arg1)); +} + +/* setgid(2) */ +static inline abi_long do_bsd_setgid(abi_long arg1) +{ + return get_errno(setgid(arg1)); +} + +/* setegid(2) */ +static inline abi_long do_bsd_setegid(abi_long arg1) +{ + return get_errno(setegid(arg1)); +} + +/* getpgid(2) */ +static inline abi_long do_bsd_getpgid(pid_t pid) +{ + return get_errno(getpgid(pid)); +} + +/* setpgid(2) */ +static inline abi_long do_bsd_setpgid(int pid, int pgrp) +{ + return get_errno(setpgid(pid, pgrp)); +} + +/* getpgrp(2) */ +static inline abi_long do_bsd_getpgrp(void) +{ + return get_errno(getpgrp()); +} + +/* setreuid(2) */ +static inline abi_long do_bsd_setreuid(abi_long arg1, abi_long arg2) +{ + return get_errno(setreuid(arg1, arg2)); +} + +/* setregid(2) */ +static inline abi_long do_bsd_setregid(abi_long arg1, abi_long arg2) +{ + return get_errno(setregid(arg1, arg2)); +} + #endif /* !BSD_PROC_H_ */ diff --git a/bsd-user/freebsd/os-syscall.c b/bsd-user/freebsd/os-syscall.c index 5cb6086230..7565e69e76 100644 --- a/bsd-user/freebsd/os-syscall.c +++ b/bsd-user/freebsd/os-syscall.c @@ -255,6 +255,66 @@ static abi_long freebsd_syscall(void *cpu_env, int num, abi_long arg1, ret = do_bsd_setrlimit(arg1, arg2); break; + case TARGET_FREEBSD_NR_getpid: /* getpid(2) */ + ret = do_bsd_getpid(); + break; + + case TARGET_FREEBSD_NR_getppid: /* getppid(2) */ + ret = do_bsd_getppid(); + break; + + case TARGET_FREEBSD_NR_getuid: /* getuid(2) */ + ret = do_bsd_getuid(); + break; + + case TARGET_FREEBSD_NR_geteuid: /* geteuid(2) */ + ret = do_bsd_geteuid(); + break; + + case TARGET_FREEBSD_NR_getgid: /* getgid(2) */ + ret = do_bsd_getgid(); + break; + + case TARGET_FREEBSD_NR_getegid: /* getegid(2) */ + ret = do_bsd_getegid(); + break; + + case TARGET_FREEBSD_NR_setuid: /* setuid(2) */ + ret = do_bsd_setuid(arg1); + break; + + case TARGET_FREEBSD_NR_seteuid: /* seteuid(2) */ + ret = do_bsd_seteuid(arg1); + break; + + case TARGET_FREEBSD_NR_setgid: /* setgid(2) */ + ret = do_bsd_setgid(arg1); + break; + + case TARGET_FREEBSD_NR_setegid: /* setegid(2) */ + ret = do_bsd_setegid(arg1); + break; + + case TARGET_FREEBSD_NR_getpgrp: /* getpgrp(2) */ + ret = do_bsd_getpgrp(); + break; + + case TARGET_FREEBSD_NR_getpgid: /* getpgid(2) */ + ret = do_bsd_getpgid(arg1); + break; + + case TARGET_FREEBSD_NR_setpgid: /* setpgid(2) */ + ret = do_bsd_setpgid(arg1, arg2); + break; + + case TARGET_FREEBSD_NR_setreuid: /* setreuid(2) */ + ret = do_bsd_setreuid(arg1, arg2); + break; + + case TARGET_FREEBSD_NR_setregid: /* setregid(2) */ + ret = do_bsd_setregid(arg1, arg2); + break; + /* * File system calls. From 932683c3d421a2057e15cd7f87ad781c3d65fc95 Mon Sep 17 00:00:00 2001 From: Stacey Son Date: Mon, 25 Sep 2023 21:24:13 +0300 Subject: [PATCH 0176/1077] bsd-user: Implement get/set[resuid/resgid/sid] and issetugid. Signed-off-by: Stacey Son Signed-off-by: Karim Taha Reviewed-by: Richard Henderson Reviewed-by: Warner Losh Message-Id: <20230925182425.3163-17-kariem.taha2.7@gmail.com> --- bsd-user/bsd-proc.h | 76 +++++++++++++++++++++++++++++++++++ bsd-user/freebsd/os-syscall.c | 28 +++++++++++++ 2 files changed, 104 insertions(+) diff --git a/bsd-user/bsd-proc.h b/bsd-user/bsd-proc.h index 6ff07c0ac3..a5f301c72f 100644 --- a/bsd-user/bsd-proc.h +++ b/bsd-user/bsd-proc.h @@ -286,4 +286,80 @@ static inline abi_long do_bsd_setregid(abi_long arg1, abi_long arg2) return get_errno(setregid(arg1, arg2)); } +/* setresgid(2) */ +static inline abi_long do_bsd_setresgid(gid_t rgid, gid_t egid, gid_t sgid) +{ + return get_errno(setresgid(rgid, egid, sgid)); +} + +/* setresuid(2) */ +static inline abi_long do_bsd_setresuid(uid_t ruid, uid_t euid, uid_t suid) +{ + return get_errno(setresuid(ruid, euid, suid)); +} + +/* getresuid(2) */ +static inline abi_long do_bsd_getresuid(abi_ulong arg1, abi_ulong arg2, + abi_ulong arg3) +{ + abi_long ret; + uid_t ruid, euid, suid; + + ret = get_errno(getresuid(&ruid, &euid, &suid)); + if (is_error(ret)) { + return ret; + } + if (put_user_s32(ruid, arg1)) { + return -TARGET_EFAULT; + } + if (put_user_s32(euid, arg2)) { + return -TARGET_EFAULT; + } + if (put_user_s32(suid, arg3)) { + return -TARGET_EFAULT; + } + return ret; +} + +/* getresgid(2) */ +static inline abi_long do_bsd_getresgid(abi_ulong arg1, abi_ulong arg2, + abi_ulong arg3) +{ + abi_long ret; + uid_t ruid, euid, suid; + + ret = get_errno(getresgid(&ruid, &euid, &suid)); + if (is_error(ret)) { + return ret; + } + if (put_user_s32(ruid, arg1)) { + return -TARGET_EFAULT; + } + if (put_user_s32(euid, arg2)) { + return -TARGET_EFAULT; + } + if (put_user_s32(suid, arg3)) { + return -TARGET_EFAULT; + } + return ret; +} + +/* getsid(2) */ +static inline abi_long do_bsd_getsid(abi_long arg1) +{ + return get_errno(getsid(arg1)); +} + +/* setsid(2) */ +static inline abi_long do_bsd_setsid(void) +{ + return get_errno(setsid()); +} + +/* issetugid(2) */ +static inline abi_long do_bsd_issetugid(void) +{ + return get_errno(issetugid()); +} + #endif /* !BSD_PROC_H_ */ diff --git a/bsd-user/freebsd/os-syscall.c b/bsd-user/freebsd/os-syscall.c index 7565e69e76..7b51f4f16e 100644 --- a/bsd-user/freebsd/os-syscall.c +++ b/bsd-user/freebsd/os-syscall.c @@ -315,6 +315,34 @@ static abi_long freebsd_syscall(void *cpu_env, int num, abi_long arg1, ret = do_bsd_setregid(arg1, arg2); break; + case TARGET_FREEBSD_NR_getresuid: /* getresuid(2) */ + ret = do_bsd_getresuid(arg1, arg2, arg3); + break; + + case TARGET_FREEBSD_NR_getresgid: /* getresgid(2) */ + ret = do_bsd_getresgid(arg1, arg2, arg3); + break; + + case TARGET_FREEBSD_NR_setresuid: /* setresuid(2) */ + ret = do_bsd_setresuid(arg1, arg2, arg3); + break; + + case TARGET_FREEBSD_NR_setresgid: /* setresgid(2) */ + ret = do_bsd_setresgid(arg1, arg2, arg3); + break; + + case TARGET_FREEBSD_NR_getsid: /* getsid(2) */ + ret = do_bsd_getsid(arg1); + break; + + case TARGET_FREEBSD_NR_setsid: /* setsid(2) */ + ret = do_bsd_setsid(); + break; + + case TARGET_FREEBSD_NR_issetugid: /* issetugid(2) */ + ret = do_bsd_issetugid(); + break; + /* * File system calls. From 615ad41c614bf0f2011bba43116434b66e40abc0 Mon Sep 17 00:00:00 2001 From: Stacey Son Date: Mon, 25 Sep 2023 21:24:14 +0300 Subject: [PATCH 0177/1077] bsd-user: Add stubs for profil(2), ktrace(2), utrace(2) and ptrace(2). Signed-off-by: Stacey Son Signed-off-by: Karim Taha Reviewed-by: Richard Henderson Reviewed-by: Warner Losh Message-Id: <20230925182425.3163-18-kariem.taha2.7@gmail.com> --- bsd-user/bsd-proc.h | 28 ++++++++++++++++++++++++++++ bsd-user/freebsd/os-syscall.c | 16 ++++++++++++++++ 2 files changed, 44 insertions(+) diff --git a/bsd-user/bsd-proc.h b/bsd-user/bsd-proc.h index a5f301c72f..2c1a9ae22f 100644 --- a/bsd-user/bsd-proc.h +++ b/bsd-user/bsd-proc.h @@ -362,4 +362,32 @@ static inline abi_long do_bsd_issetugid(void) return get_errno(issetugid()); } +/* profil(2) */ +static inline abi_long do_bsd_profil(abi_long arg1, abi_long arg2, + abi_long arg3, abi_long arg4) +{ + return -TARGET_ENOSYS; +} + +/* ktrace(2) */ +static inline abi_long do_bsd_ktrace(abi_long arg1, abi_long arg2, + abi_long arg3, abi_long arg4) +{ + return -TARGET_ENOSYS; +} + +/* utrace(2) */ +static inline abi_long do_bsd_utrace(abi_long arg1, abi_long arg2) +{ + return -TARGET_ENOSYS; +} + + +/* ptrace(2) */ +static inline abi_long do_bsd_ptrace(abi_long arg1, abi_long arg2, + abi_long arg3, abi_long arg4) +{ + return -TARGET_ENOSYS; +} + #endif /* !BSD_PROC_H_ */ diff --git a/bsd-user/freebsd/os-syscall.c b/bsd-user/freebsd/os-syscall.c index 7b51f4f16e..1a760b1380 100644 --- a/bsd-user/freebsd/os-syscall.c +++ b/bsd-user/freebsd/os-syscall.c @@ -343,6 +343,22 @@ static abi_long freebsd_syscall(void *cpu_env, int num, abi_long arg1, ret = do_bsd_issetugid(); break; + case TARGET_FREEBSD_NR_profil: /* profil(2) */ + ret = do_bsd_profil(arg1, arg2, arg3, arg4); + break; + + case TARGET_FREEBSD_NR_ktrace: /* ktrace(2) */ + ret = do_bsd_ktrace(arg1, arg2, arg3, arg4); + break; + + case TARGET_FREEBSD_NR_utrace: /* utrace(2) */ + ret = do_bsd_utrace(arg1, arg2); + break; + + case TARGET_FREEBSD_NR_ptrace: /* ptrace(2) */ + ret = do_bsd_ptrace(arg1, arg2, arg3, arg4); + break; + /* * File system calls. From ff26637260d059f5b37d32f00d7881a8c21a06f9 Mon Sep 17 00:00:00 2001 From: Stacey Son Date: Mon, 25 Sep 2023 21:24:15 +0300 Subject: [PATCH 0178/1077] bsd-user: Implement getpriority(2) and setpriority(2). Signed-off-by: Stacey Son Signed-off-by: Karim Taha Reviewed-by: Warner Losh Message-Id: <20230925182425.3163-19-kariem.taha2.7@gmail.com> --- bsd-user/bsd-proc.h | 24 ++++++++++++++++++++++++ bsd-user/freebsd/os-syscall.c | 8 ++++++++ 2 files changed, 32 insertions(+) diff --git a/bsd-user/bsd-proc.h b/bsd-user/bsd-proc.h index 2c1a9ae22f..9a8912361f 100644 --- a/bsd-user/bsd-proc.h +++ b/bsd-user/bsd-proc.h @@ -390,4 +390,28 @@ static inline abi_long do_bsd_ptrace(abi_long arg1, abi_long arg2, return -TARGET_ENOSYS; } +/* getpriority(2) */ +static inline abi_long do_bsd_getpriority(abi_long which, abi_long who) +{ + abi_long ret; + /* + * Note that negative values are valid for getpriority, so we must + * differentiate based on errno settings. + */ + errno = 0; + ret = getpriority(which, who); + if (ret == -1 && errno != 0) { + return -host_to_target_errno(errno); + } + + return ret; +} + +/* setpriority(2) */ +static inline abi_long do_bsd_setpriority(abi_long which, abi_long who, + abi_long prio) +{ + return get_errno(setpriority(which, who, prio)); +} + #endif /* !BSD_PROC_H_ */ diff --git a/bsd-user/freebsd/os-syscall.c b/bsd-user/freebsd/os-syscall.c index 1a760b1380..71a2657dd0 100644 --- a/bsd-user/freebsd/os-syscall.c +++ b/bsd-user/freebsd/os-syscall.c @@ -359,6 +359,14 @@ static abi_long freebsd_syscall(void *cpu_env, int num, abi_long arg1, ret = do_bsd_ptrace(arg1, arg2, arg3, arg4); break; + case TARGET_FREEBSD_NR_getpriority: /* getpriority(2) */ + ret = do_bsd_getpriority(arg1, arg2); + break; + + case TARGET_FREEBSD_NR_setpriority: /* setpriority(2) */ + ret = do_bsd_setpriority(arg1, arg2, arg3); + break; + /* * File system calls. From 84d41c5e6dc69be9b3e0fb8ad5f1ff2007e0e8a1 Mon Sep 17 00:00:00 2001 From: Karim Taha Date: Mon, 25 Sep 2023 21:24:16 +0300 Subject: [PATCH 0179/1077] bsd-user: Implement get_filename_from_fd. Signed-off-by: Stacey Son Signed-off-by: Karim Taha Reviewed-by: Richard Henderson Reviewed-by: Warner Losh Message-Id: <20230925182425.3163-20-kariem.taha2.7@gmail.com> --- bsd-user/freebsd/meson.build | 1 + bsd-user/freebsd/os-proc.c | 82 ++++++++++++++++++++++++++++++++++++ 2 files changed, 83 insertions(+) create mode 100644 bsd-user/freebsd/os-proc.c diff --git a/bsd-user/freebsd/meson.build b/bsd-user/freebsd/meson.build index f2f047cca3..8fd6c7cfb8 100644 --- a/bsd-user/freebsd/meson.build +++ b/bsd-user/freebsd/meson.build @@ -1,5 +1,6 @@ bsd_user_ss.add(files( 'os-stat.c', + 'os-proc.c', 'os-sys.c', 'os-syscall.c', )) diff --git a/bsd-user/freebsd/os-proc.c b/bsd-user/freebsd/os-proc.c new file mode 100644 index 0000000000..2603c5c653 --- /dev/null +++ b/bsd-user/freebsd/os-proc.c @@ -0,0 +1,82 @@ +/* + * FreeBSD process related emulation code + * + * Copyright (c) 2013-15 Stacey D. Son + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + */ +#include "qemu/osdep.h" + +#include +#include +#include +struct kinfo_proc; +#include + +#include "qemu.h" + +/* + * Get the filename for the given file descriptor. + * Note that this may return NULL (fail) if no longer cached in the kernel. + */ +char * +get_filename_from_fd(pid_t pid, int fd, char *filename, size_t len); +char * +get_filename_from_fd(pid_t pid, int fd, char *filename, size_t len) +{ + char *ret = NULL; + unsigned int cnt; + struct procstat *procstat = NULL; + struct kinfo_proc *kp = NULL; + struct filestat_list *head = NULL; + struct filestat *fst; + + procstat = procstat_open_sysctl(); + if (procstat == NULL) { + goto out; + } + + kp = procstat_getprocs(procstat, KERN_PROC_PID, pid, &cnt); + if (kp == NULL) { + goto out; + } + + head = procstat_getfiles(procstat, kp, 0); + if (head == NULL) { + goto out; + } + + STAILQ_FOREACH(fst, head, next) { + if (fd == fst->fs_fd) { + if (fst->fs_path != NULL) { + (void)strlcpy(filename, fst->fs_path, len); + ret = filename; + } + break; + } + } + +out: + if (head != NULL) { + procstat_freefiles(procstat, head); + } + if (kp != NULL) { + procstat_freeprocs(procstat, kp); + } + if (procstat != NULL) { + procstat_close(procstat); + } + return ret; +} + From 8632729060bf840560215c91c8611bd6769deff9 Mon Sep 17 00:00:00 2001 From: Stacey Son Date: Mon, 25 Sep 2023 21:24:17 +0300 Subject: [PATCH 0180/1077] bsd-user: Implement freebsd_exec_common, used in implementing execve/fexecve. Signed-off-by: Stacey Son Signed-off-by: Karim Taha Reviewed-by: Warner Losh Message-Id: <20230925182425.3163-21-kariem.taha2.7@gmail.com> --- bsd-user/freebsd/os-proc.c | 181 ++++++++++++++++++++++++++++++++++++- bsd-user/main.c | 2 +- bsd-user/qemu.h | 1 + 3 files changed, 180 insertions(+), 4 deletions(-) diff --git a/bsd-user/freebsd/os-proc.c b/bsd-user/freebsd/os-proc.c index 2603c5c653..12d78b7fc9 100644 --- a/bsd-user/freebsd/os-proc.c +++ b/bsd-user/freebsd/os-proc.c @@ -30,9 +30,7 @@ struct kinfo_proc; * Get the filename for the given file descriptor. * Note that this may return NULL (fail) if no longer cached in the kernel. */ -char * -get_filename_from_fd(pid_t pid, int fd, char *filename, size_t len); -char * +static char * get_filename_from_fd(pid_t pid, int fd, char *filename, size_t len) { char *ret = NULL; @@ -80,3 +78,180 @@ out: return ret; } +/* + * execve/fexecve + */ +abi_long freebsd_exec_common(abi_ulong path_or_fd, abi_ulong guest_argp, + abi_ulong guest_envp, int do_fexec) +{ + char **argp, **envp, **qargp, **qarg1, **qarg0, **qargend; + int argc, envc; + abi_ulong gp; + abi_ulong addr; + char **q; + int total_size = 0; + void *p; + abi_long ret; + + argc = 0; + for (gp = guest_argp; gp; gp += sizeof(abi_ulong)) { + if (get_user_ual(addr, gp)) { + return -TARGET_EFAULT; + } + if (!addr) { + break; + } + argc++; + } + envc = 0; + for (gp = guest_envp; gp; gp += sizeof(abi_ulong)) { + if (get_user_ual(addr, gp)) { + return -TARGET_EFAULT; + } + if (!addr) { + break; + } + envc++; + } + + qarg0 = argp = g_new0(char *, argc + 9); + /* save the first agrument for the emulator */ + *argp++ = (char *)getprogname(); + qargp = argp; + *argp++ = (char *)getprogname(); + qarg1 = argp; + envp = g_new0(char *, envc + 1); + for (gp = guest_argp, q = argp; gp; gp += sizeof(abi_ulong), q++) { + if (get_user_ual(addr, gp)) { + ret = -TARGET_EFAULT; + goto execve_end; + } + if (!addr) { + break; + } + *q = lock_user_string(addr); + if (*q == NULL) { + ret = -TARGET_EFAULT; + goto execve_end; + } + total_size += strlen(*q) + 1; + } + *q++ = NULL; + qargend = q; + + for (gp = guest_envp, q = envp; gp; gp += sizeof(abi_ulong), q++) { + if (get_user_ual(addr, gp)) { + ret = -TARGET_EFAULT; + goto execve_end; + } + if (!addr) { + break; + } + *q = lock_user_string(addr); + if (*q == NULL) { + ret = -TARGET_EFAULT; + goto execve_end; + } + total_size += strlen(*q) + 1; + } + *q = NULL; + + /* + * This case will not be caught by the host's execve() if its + * page size is bigger than the target's. + */ + if (total_size > MAX_ARG_PAGES * TARGET_PAGE_SIZE) { + ret = -TARGET_E2BIG; + goto execve_end; + } + + if (do_fexec) { + if (((int)path_or_fd > 0 && + is_target_elf_binary((int)path_or_fd)) == 1) { + char execpath[PATH_MAX]; + + /* + * The executable is an elf binary for the target + * arch. execve() it using the emulator if we can + * determine the filename path from the fd. + */ + if (get_filename_from_fd(getpid(), (int)path_or_fd, execpath, + sizeof(execpath)) != NULL) { + memmove(qarg1 + 2, qarg1, (qargend - qarg1) * sizeof(*qarg1)); + qarg1[1] = qarg1[0]; + qarg1[0] = (char *)"-0"; + qarg1 += 2; + qargend += 2; + *qarg1 = execpath; +#ifndef DONT_INHERIT_INTERP_PREFIX + memmove(qarg1 + 2, qarg1, (qargend - qarg1) * sizeof(*qarg1)); + *qarg1++ = (char *)"-L"; + *qarg1++ = (char *)interp_prefix; +#endif + ret = get_errno(execve(qemu_proc_pathname, qargp, envp)); + } else { + /* Getting the filename path failed. */ + ret = -TARGET_EBADF; + goto execve_end; + } + } else { + ret = get_errno(fexecve((int)path_or_fd, argp, envp)); + } + } else { + int fd; + + p = lock_user_string(path_or_fd); + if (p == NULL) { + ret = -TARGET_EFAULT; + goto execve_end; + } + + /* + * Check the header and see if it a target elf binary. If so + * then execute using qemu user mode emulator. + */ + fd = open(p, O_RDONLY | O_CLOEXEC); + if (fd > 0 && is_target_elf_binary(fd) == 1) { + close(fd); + /* execve() as a target binary using emulator. */ + memmove(qarg1 + 2, qarg1, (qargend - qarg1) * sizeof(*qarg1)); + qarg1[1] = qarg1[0]; + qarg1[0] = (char *)"-0"; + qarg1 += 2; + qargend += 2; + *qarg1 = (char *)p; +#ifndef DONT_INHERIT_INTERP_PREFIX + memmove(qarg1 + 2, qarg1, (qargend - qarg1) * sizeof(*qarg1)); + *qarg1++ = (char *)"-L"; + *qarg1++ = (char *)interp_prefix; +#endif + ret = get_errno(execve(qemu_proc_pathname, qargp, envp)); + } else { + close(fd); + /* Execve() as a host native binary. */ + ret = get_errno(execve(p, argp, envp)); + } + unlock_user(p, path_or_fd, 0); + } + +execve_end: + for (gp = guest_argp, q = argp; *q; gp += sizeof(abi_ulong), q++) { + if (get_user_ual(addr, gp) || !addr) { + break; + } + unlock_user(*q, addr, 0); + } + + for (gp = guest_envp, q = envp; *q; gp += sizeof(abi_ulong), q++) { + if (get_user_ual(addr, gp) || !addr) { + break; + } + unlock_user(*q, addr, 0); + } + + g_free(qarg0); + g_free(envp); + + return ret; +} + diff --git a/bsd-user/main.c b/bsd-user/main.c index f913cb55a7..a12b4be80f 100644 --- a/bsd-user/main.c +++ b/bsd-user/main.c @@ -88,7 +88,7 @@ unsigned long reserved_va = MAX_RESERVED_VA; unsigned long reserved_va; #endif -static const char *interp_prefix = CONFIG_QEMU_INTERP_PREFIX; +const char *interp_prefix = CONFIG_QEMU_INTERP_PREFIX; const char *qemu_uname_release; char qemu_proc_pathname[PATH_MAX]; /* full path to exeutable */ diff --git a/bsd-user/qemu.h b/bsd-user/qemu.h index 41c7bd31d3..6047805ae3 100644 --- a/bsd-user/qemu.h +++ b/bsd-user/qemu.h @@ -111,6 +111,7 @@ typedef struct TaskState { } __attribute__((aligned(16))) TaskState; void stop_all_tasks(void); +extern const char *interp_prefix; extern const char *qemu_uname_release; /* From dcaa3dfda379157a1e5148e112a77aa7e1d79c58 Mon Sep 17 00:00:00 2001 From: Stacey Son Date: Mon, 25 Sep 2023 21:24:18 +0300 Subject: [PATCH 0181/1077] bsd-user: Implement procctl(2) along with necessary conversion functions. Implement t2h_procctl_cmd, h2t_reaper_status, h2t_reaper_pidinfo and h2t/t2h reaper_kill conversion functions. Signed-off-by: Stacey Son Signed-off-by: Karim Taha Reviewed-by: Warner Losh Message-Id: <20230925182425.3163-22-kariem.taha2.7@gmail.com> --- bsd-user/freebsd/os-proc.c | 223 ++++++++++++++++++++++++++++++++++ bsd-user/freebsd/os-syscall.c | 3 + 2 files changed, 226 insertions(+) diff --git a/bsd-user/freebsd/os-proc.c b/bsd-user/freebsd/os-proc.c index 12d78b7fc9..4e67ae4d56 100644 --- a/bsd-user/freebsd/os-proc.c +++ b/bsd-user/freebsd/os-proc.c @@ -255,3 +255,226 @@ execve_end: return ret; } +#include + +static abi_long +t2h_procctl_cmd(int target_cmd, int *host_cmd) +{ + switch (target_cmd) { + case TARGET_PROC_SPROTECT: + *host_cmd = PROC_SPROTECT; + break; + + case TARGET_PROC_REAP_ACQUIRE: + *host_cmd = PROC_REAP_ACQUIRE; + break; + + case TARGET_PROC_REAP_RELEASE: + *host_cmd = PROC_REAP_RELEASE; + break; + + case TARGET_PROC_REAP_STATUS: + *host_cmd = PROC_REAP_STATUS; + break; + + case TARGET_PROC_REAP_KILL: + *host_cmd = PROC_REAP_KILL; + break; + + default: + return -TARGET_EINVAL; + } + + return 0; +} + +static abi_long +h2t_reaper_status(struct procctl_reaper_status *host_rs, + abi_ulong target_rs_addr) +{ + struct target_procctl_reaper_status *target_rs; + + if (!lock_user_struct(VERIFY_WRITE, target_rs, target_rs_addr, 0)) { + return -TARGET_EFAULT; + } + __put_user(host_rs->rs_flags, &target_rs->rs_flags); + __put_user(host_rs->rs_children, &target_rs->rs_children); + __put_user(host_rs->rs_descendants, &target_rs->rs_descendants); + __put_user(host_rs->rs_reaper, &target_rs->rs_reaper); + __put_user(host_rs->rs_pid, &target_rs->rs_pid); + unlock_user_struct(target_rs, target_rs_addr, 1); + + return 0; +} + +static abi_long +t2h_reaper_kill(abi_ulong target_rk_addr, struct procctl_reaper_kill *host_rk) +{ + struct target_procctl_reaper_kill *target_rk; + + if (!lock_user_struct(VERIFY_READ, target_rk, target_rk_addr, 1)) { + return -TARGET_EFAULT; + } + __get_user(host_rk->rk_sig, &target_rk->rk_sig); + __get_user(host_rk->rk_flags, &target_rk->rk_flags); + __get_user(host_rk->rk_subtree, &target_rk->rk_subtree); + __get_user(host_rk->rk_killed, &target_rk->rk_killed); + __get_user(host_rk->rk_fpid, &target_rk->rk_fpid); + unlock_user_struct(target_rk, target_rk_addr, 0); + + return 0; +} + +static abi_long +h2t_reaper_kill(struct procctl_reaper_kill *host_rk, abi_ulong target_rk_addr) +{ + struct target_procctl_reaper_kill *target_rk; + + if (!lock_user_struct(VERIFY_WRITE, target_rk, target_rk_addr, 0)) { + return -TARGET_EFAULT; + } + __put_user(host_rk->rk_sig, &target_rk->rk_sig); + __put_user(host_rk->rk_flags, &target_rk->rk_flags); + __put_user(host_rk->rk_subtree, &target_rk->rk_subtree); + __put_user(host_rk->rk_killed, &target_rk->rk_killed); + __put_user(host_rk->rk_fpid, &target_rk->rk_fpid); + unlock_user_struct(target_rk, target_rk_addr, 1); + + return 0; +} + +static abi_long +h2t_procctl_reaper_pidinfo(struct procctl_reaper_pidinfo *host_pi, + abi_ulong target_pi_addr) +{ + struct target_procctl_reaper_pidinfo *target_pi; + + if (!lock_user_struct(VERIFY_WRITE, target_pi, target_pi_addr, 0)) { + return -TARGET_EFAULT; + } + __put_user(host_pi->pi_pid, &target_pi->pi_pid); + __put_user(host_pi->pi_subtree, &target_pi->pi_subtree); + __put_user(host_pi->pi_flags, &target_pi->pi_flags); + unlock_user_struct(target_pi, target_pi_addr, 1); + + return 0; +} + +abi_long +do_freebsd_procctl(void *cpu_env, int idtype, abi_ulong arg2, abi_ulong arg3, + abi_ulong arg4, abi_ulong arg5, abi_ulong arg6) +{ + abi_long error = 0, target_rp_pids; + void *data; + int host_cmd, flags; + uint32_t u, target_rp_count; + g_autofree union { + struct procctl_reaper_status rs; + struct procctl_reaper_pids rp; + struct procctl_reaper_kill rk; + } host; + struct target_procctl_reaper_pids *target_rp; + id_t id; /* 64-bit */ + int target_cmd; + abi_ulong target_arg; + +#if TARGET_ABI_BITS == 32 + /* See if we need to align the register pairs. */ + if (regpairs_aligned(cpu_env)) { + id = (id_t)target_arg64(arg3, arg4); + target_cmd = (int)arg5; + target_arg = arg6; + } else { + id = (id_t)target_arg64(arg2, arg3); + target_cmd = (int)arg4; + target_arg = arg5; + } +#else + id = (id_t)arg2; + target_cmd = (int)arg3; + target_arg = arg4; +#endif + + error = t2h_procctl_cmd(target_cmd, &host_cmd); + if (error) { + return error; + } + switch (host_cmd) { + case PROC_SPROTECT: + data = &flags; + break; + + case PROC_REAP_ACQUIRE: + case PROC_REAP_RELEASE: + if (target_arg == 0) { + data = NULL; + } else { + error = -TARGET_EINVAL; + } + break; + + case PROC_REAP_STATUS: + data = &host.rs; + break; + + case PROC_REAP_GETPIDS: + if (!lock_user_struct(VERIFY_READ, target_rp, target_arg, 1)) { + return -TARGET_EFAULT; + } + __get_user(target_rp_count, &target_rp->rp_count); + __get_user(target_rp_pids, &target_rp->rp_pids); + unlock_user_struct(target_rp, target_arg, 0); + host.rp.rp_count = target_rp_count; + host.rp.rp_pids = g_try_new(struct procctl_reaper_pidinfo, + target_rp_count); + + if (host.rp.rp_pids == NULL) { + error = -TARGET_ENOMEM; + } else { + data = &host.rp; + } + break; + + case PROC_REAP_KILL: + error = t2h_reaper_kill(target_arg, &host.rk); + break; + } + + if (error) { + return error; + } + error = get_errno(procctl(idtype, id, host_cmd, data)); + + if (error) { + return error; + } + switch (host_cmd) { + case PROC_SPROTECT: + if (put_user_s32(flags, target_arg)) { + return -TARGET_EFAULT; + } + break; + + case PROC_REAP_STATUS: + error = h2t_reaper_status(&host.rs, target_arg); + break; + + case PROC_REAP_GETPIDS: + /* copyout reaper pidinfo */ + for (u = 0; u < target_rp_count; u++) { + error = h2t_procctl_reaper_pidinfo(&host.rp.rp_pids[u], + target_rp_pids + + (u * sizeof(struct target_procctl_reaper_pidinfo))); + if (error) { + break; + } + } + break; + + case PROC_REAP_KILL: + error = h2t_reaper_kill(&host.rk, target_arg); + break; + } + + return error; +} diff --git a/bsd-user/freebsd/os-syscall.c b/bsd-user/freebsd/os-syscall.c index 71a2657dd0..b7bd0b92a6 100644 --- a/bsd-user/freebsd/os-syscall.c +++ b/bsd-user/freebsd/os-syscall.c @@ -367,6 +367,9 @@ static abi_long freebsd_syscall(void *cpu_env, int num, abi_long arg1, ret = do_bsd_setpriority(arg1, arg2, arg3); break; + case TARGET_FREEBSD_NR_procctl: /* procctl(2) */ + ret = do_freebsd_procctl(cpu_env, arg1, arg2, arg3, arg4, arg5, arg6); + break; /* * File system calls. From 36999e6a6bb1e3c7d7d40c751b67d5886f023ee9 Mon Sep 17 00:00:00 2001 From: Karim Taha Date: Mon, 25 Sep 2023 21:24:19 +0300 Subject: [PATCH 0182/1077] bsd-user: Implement execve(2) and fexecve(2) system calls. Signed-off-by: Stacey Son Signed-off-by: Karim Taha Reviewed-by: Richard Henderson Reviewed-by: Warner Losh Message-Id: <20230925182425.3163-23-kariem.taha2.7@gmail.com> --- bsd-user/freebsd/os-proc.h | 49 +++++++++++++++++++++++++++++++++++ bsd-user/freebsd/os-syscall.c | 11 +++++++- 2 files changed, 59 insertions(+), 1 deletion(-) create mode 100644 bsd-user/freebsd/os-proc.h diff --git a/bsd-user/freebsd/os-proc.h b/bsd-user/freebsd/os-proc.h new file mode 100644 index 0000000000..75ed39f8dd --- /dev/null +++ b/bsd-user/freebsd/os-proc.h @@ -0,0 +1,49 @@ +/* + * process related system call shims and definitions + * + * Copyright (c) 2013-14 Stacey D. Son + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + */ + +#ifndef BSD_USER_FREEBSD_OS_PROC_H +#define BSD_USER_FREEBSD_OS_PROC_H + +#include +#include +#include +#include +#include +#include +#include + +#include "target_arch_cpu.h" + +/* execve(2) */ +static inline abi_long do_freebsd_execve(abi_ulong path_or_fd, abi_ulong argp, + abi_ulong envp) +{ + + return freebsd_exec_common(path_or_fd, argp, envp, 0); +} + +/* fexecve(2) */ +static inline abi_long do_freebsd_fexecve(abi_ulong path_or_fd, abi_ulong argp, + abi_ulong envp) +{ + + return freebsd_exec_common(path_or_fd, argp, envp, 1); +} + +#endif /* BSD_USER_FREEBSD_OS_PROC_H */ diff --git a/bsd-user/freebsd/os-syscall.c b/bsd-user/freebsd/os-syscall.c index b7bd0b92a6..515eaaf31f 100644 --- a/bsd-user/freebsd/os-syscall.c +++ b/bsd-user/freebsd/os-syscall.c @@ -36,8 +36,9 @@ #include "bsd-file.h" #include "bsd-proc.h" -/* *BSD dependent syscall shims */ +/* BSD dependent syscall shims */ #include "os-stat.h" +#include "os-proc.h" /* I/O */ safe_syscall3(int, open, const char *, path, int, flags, mode_t, mode); @@ -219,6 +220,14 @@ static abi_long freebsd_syscall(void *cpu_env, int num, abi_long arg1, /* * process system calls */ + case TARGET_FREEBSD_NR_execve: /* execve(2) */ + ret = do_freebsd_execve(arg1, arg2, arg3); + break; + + case TARGET_FREEBSD_NR_fexecve: /* fexecve(2) */ + ret = do_freebsd_fexecve(arg1, arg2, arg3); + break; + case TARGET_FREEBSD_NR_exit: /* exit(2) */ ret = do_bsd_exit(cpu_env, arg1); break; From ae502887cb3e3aa38bc0837cd7580f7a6768a649 Mon Sep 17 00:00:00 2001 From: Stacey Son Date: Mon, 25 Sep 2023 21:24:20 +0300 Subject: [PATCH 0183/1077] bsd-user: Implement wait4(2) and wait6(2) system calls. Signed-off-by: Stacey Son Signed-off-by: Karim Taha Reviewed-by: Warner Losh Message-Id: <20230925182425.3163-24-kariem.taha2.7@gmail.com> --- bsd-user/freebsd/os-proc.h | 84 +++++++++++++++++++++++++++++++++++ bsd-user/freebsd/os-syscall.c | 15 +++++++ 2 files changed, 99 insertions(+) diff --git a/bsd-user/freebsd/os-proc.h b/bsd-user/freebsd/os-proc.h index 75ed39f8dd..04bce755e5 100644 --- a/bsd-user/freebsd/os-proc.h +++ b/bsd-user/freebsd/os-proc.h @@ -30,6 +30,10 @@ #include "target_arch_cpu.h" +pid_t safe_wait4(pid_t wpid, int *status, int options, struct rusage *rusage); +pid_t safe_wait6(idtype_t idtype, id_t id, int *status, int options, + struct __wrusage *wrusage, siginfo_t *infop); + /* execve(2) */ static inline abi_long do_freebsd_execve(abi_ulong path_or_fd, abi_ulong argp, abi_ulong envp) @@ -46,4 +50,84 @@ static inline abi_long do_freebsd_fexecve(abi_ulong path_or_fd, abi_ulong argp, return freebsd_exec_common(path_or_fd, argp, envp, 1); } +/* wait4(2) */ +static inline abi_long do_freebsd_wait4(abi_long arg1, abi_ulong target_status, + abi_long arg3, abi_ulong target_rusage) +{ + abi_long ret; + int status; + struct rusage rusage, *rusage_ptr = NULL; + + if (target_rusage) { + rusage_ptr = &rusage; + } + ret = get_errno(safe_wait4(arg1, &status, arg3, rusage_ptr)); + + if (ret < 0) { + return ret; + } + if (target_status != 0) { + status = host_to_target_waitstatus(status); + if (put_user_s32(status, target_status) != 0) { + return -TARGET_EFAULT; + } + } + if (target_rusage != 0) { + host_to_target_rusage(target_rusage, &rusage); + } + return ret; +} + +/* wait6(2) */ +static inline abi_long do_freebsd_wait6(void *cpu_env, abi_long idtype, + abi_long id1, abi_long id2, + abi_ulong target_status, abi_long options, abi_ulong target_wrusage, + abi_ulong target_infop, abi_ulong pad1) +{ + abi_long ret; + int status; + struct __wrusage wrusage, *wrusage_ptr = NULL; + siginfo_t info; + void *p; + + if (regpairs_aligned(cpu_env) != 0) { + /* printf("shifting args\n"); */ + /* 64-bit id is aligned, so shift all the arguments over by one */ + id1 = id2; + id2 = target_status; + target_status = options; + options = target_wrusage; + target_wrusage = target_infop; + target_infop = pad1; + } + + if (target_wrusage) { + wrusage_ptr = &wrusage; + } + ret = get_errno(safe_wait6(idtype, target_arg64(id1, id2), + &status, options, wrusage_ptr, &info)); + + if (ret < 0) { + return ret; + } + if (target_status != 0) { + status = host_to_target_waitstatus(status); + if (put_user_s32(status, target_status) != 0) { + return -TARGET_EFAULT; + } + } + if (target_wrusage != 0) { + host_to_target_wrusage(target_wrusage, &wrusage); + } + if (target_infop != 0) { + p = lock_user(VERIFY_WRITE, target_infop, sizeof(target_siginfo_t), 0); + if (p == NULL) { + return -TARGET_EFAULT; + } + host_to_target_siginfo(p, &info); + unlock_user(p, target_infop, sizeof(target_siginfo_t)); + } + return ret; +} + #endif /* BSD_USER_FREEBSD_OS_PROC_H */ diff --git a/bsd-user/freebsd/os-syscall.c b/bsd-user/freebsd/os-syscall.c index 515eaaf31f..55e68e4815 100644 --- a/bsd-user/freebsd/os-syscall.c +++ b/bsd-user/freebsd/os-syscall.c @@ -40,6 +40,12 @@ #include "os-stat.h" #include "os-proc.h" +/* used in os-proc */ +safe_syscall4(pid_t, wait4, pid_t, wpid, int *, status, int, options, + struct rusage *, rusage); +safe_syscall6(pid_t, wait6, idtype_t, idtype, id_t, id, int *, status, int, + options, struct __wrusage *, wrusage, siginfo_t *, infop); + /* I/O */ safe_syscall3(int, open, const char *, path, int, flags, mode_t, mode); safe_syscall4(int, openat, int, fd, const char *, path, int, flags, mode_t, @@ -228,6 +234,15 @@ static abi_long freebsd_syscall(void *cpu_env, int num, abi_long arg1, ret = do_freebsd_fexecve(arg1, arg2, arg3); break; + case TARGET_FREEBSD_NR_wait4: /* wait4(2) */ + ret = do_freebsd_wait4(arg1, arg2, arg3, arg4); + break; + + case TARGET_FREEBSD_NR_wait6: /* wait6(2) */ + ret = do_freebsd_wait6(cpu_env, arg1, arg2, arg3, + arg4, arg5, arg6, arg7, arg8); + break; + case TARGET_FREEBSD_NR_exit: /* exit(2) */ ret = do_bsd_exit(cpu_env, arg1); break; From 159e5b0c4bb00ade2d53e6c482ecda59f69fbdde Mon Sep 17 00:00:00 2001 From: Stacey Son Date: Mon, 25 Sep 2023 21:24:21 +0300 Subject: [PATCH 0184/1077] bsd-user: Implement setloginclass(2) and getloginclass(2) system calls. Signed-off-by: Stacey Son Signed-off-by: Karim Taha Reviewed-by: Warner Losh Message-Id: <20230925182425.3163-25-kariem.taha2.7@gmail.com> --- bsd-user/freebsd/os-proc.h | 32 ++++++++++++++++++++++++++++++++ bsd-user/freebsd/os-syscall.c | 8 ++++++++ 2 files changed, 40 insertions(+) diff --git a/bsd-user/freebsd/os-proc.h b/bsd-user/freebsd/os-proc.h index 04bce755e5..2eaba141dc 100644 --- a/bsd-user/freebsd/os-proc.h +++ b/bsd-user/freebsd/os-proc.h @@ -130,4 +130,36 @@ static inline abi_long do_freebsd_wait6(void *cpu_env, abi_long idtype, return ret; } +/* setloginclass(2) */ +static inline abi_long do_freebsd_setloginclass(abi_ulong arg1) +{ + abi_long ret; + void *p; + + p = lock_user_string(arg1); + if (p == NULL) { + return -TARGET_EFAULT; + } + ret = get_errno(setloginclass(p)); + unlock_user(p, arg1, 0); + + return ret; +} + +/* getloginclass(2) */ +static inline abi_long do_freebsd_getloginclass(abi_ulong arg1, abi_ulong arg2) +{ + abi_long ret; + void *p; + + p = lock_user(VERIFY_WRITE, arg1, arg2, 0); + if (p == NULL) { + return -TARGET_EFAULT; + } + ret = get_errno(getloginclass(p, arg2)); + unlock_user(p, arg1, arg2); + + return ret; +} + #endif /* BSD_USER_FREEBSD_OS_PROC_H */ diff --git a/bsd-user/freebsd/os-syscall.c b/bsd-user/freebsd/os-syscall.c index 55e68e4815..d614409e69 100644 --- a/bsd-user/freebsd/os-syscall.c +++ b/bsd-user/freebsd/os-syscall.c @@ -375,6 +375,14 @@ static abi_long freebsd_syscall(void *cpu_env, int num, abi_long arg1, ret = do_bsd_ktrace(arg1, arg2, arg3, arg4); break; + case TARGET_FREEBSD_NR_setloginclass: /* setloginclass(2) */ + ret = do_freebsd_setloginclass(arg1); + break; + + case TARGET_FREEBSD_NR_getloginclass: /* getloginclass(2) */ + ret = do_freebsd_getloginclass(arg1, arg2); + break; + case TARGET_FREEBSD_NR_utrace: /* utrace(2) */ ret = do_bsd_utrace(arg1, arg2); break; From 0571e3f5e20e4a93b0d59c948bcd89b60033d0be Mon Sep 17 00:00:00 2001 From: Stacey Son Date: Mon, 25 Sep 2023 21:24:22 +0300 Subject: [PATCH 0185/1077] bsd-user: Implement pdgetpid(2) and the undocumented setugid. Signed-off-by: Stacey Son Signed-off-by: Karim Taha Reviewed-by: Richard Henderson Reviewed-by: Warner Losh Message-Id: <20230925182425.3163-26-kariem.taha2.7@gmail.com> --- bsd-user/freebsd/os-proc.h | 23 +++++++++++++++++++++++ bsd-user/freebsd/os-syscall.c | 8 ++++++++ 2 files changed, 31 insertions(+) diff --git a/bsd-user/freebsd/os-proc.h b/bsd-user/freebsd/os-proc.h index 2eaba141dc..42bdd61904 100644 --- a/bsd-user/freebsd/os-proc.h +++ b/bsd-user/freebsd/os-proc.h @@ -34,6 +34,8 @@ pid_t safe_wait4(pid_t wpid, int *status, int options, struct rusage *rusage); pid_t safe_wait6(idtype_t idtype, id_t id, int *status, int options, struct __wrusage *wrusage, siginfo_t *infop); +extern int __setugid(int flag); + /* execve(2) */ static inline abi_long do_freebsd_execve(abi_ulong path_or_fd, abi_ulong argp, abi_ulong envp) @@ -162,4 +164,25 @@ static inline abi_long do_freebsd_getloginclass(abi_ulong arg1, abi_ulong arg2) return ret; } +/* pdgetpid(2) */ +static inline abi_long do_freebsd_pdgetpid(abi_long fd, abi_ulong target_pidp) +{ + abi_long ret; + pid_t pid; + + ret = get_errno(pdgetpid(fd, &pid)); + if (!is_error(ret)) { + if (put_user_u32(pid, target_pidp)) { + return -TARGET_EFAULT; + } + } + return ret; +} + +/* undocumented __setugid */ +static inline abi_long do_freebsd___setugid(abi_long arg1) +{ + return -TARGET_ENOSYS; +} + #endif /* BSD_USER_FREEBSD_OS_PROC_H */ diff --git a/bsd-user/freebsd/os-syscall.c b/bsd-user/freebsd/os-syscall.c index d614409e69..99af0f6b15 100644 --- a/bsd-user/freebsd/os-syscall.c +++ b/bsd-user/freebsd/os-syscall.c @@ -383,6 +383,14 @@ static abi_long freebsd_syscall(void *cpu_env, int num, abi_long arg1, ret = do_freebsd_getloginclass(arg1, arg2); break; + case TARGET_FREEBSD_NR_pdgetpid: /* pdgetpid(2) */ + ret = do_freebsd_pdgetpid(arg1, arg2); + break; + + case TARGET_FREEBSD_NR___setugid: /* undocumented */ + ret = do_freebsd___setugid(arg1); + break; + case TARGET_FREEBSD_NR_utrace: /* utrace(2) */ ret = do_bsd_utrace(arg1, arg2); break; From 831a5a7fcbb3bfc36e8e7ed511817e8390344f87 Mon Sep 17 00:00:00 2001 From: Stacey Son Date: Mon, 25 Sep 2023 21:24:23 +0300 Subject: [PATCH 0186/1077] bsd-user: Implement fork(2) and vfork(2) system calls. Signed-off-by: Stacey Son Signed-off-by: Karim Taha Reviewed-by: Richard Henderson Reviewed-by: Warner Losh Message-Id: <20230925182425.3163-27-kariem.taha2.7@gmail.com> --- bsd-user/freebsd/os-proc.h | 34 ++++++++++++++++++++++++++++++++++ bsd-user/freebsd/os-syscall.c | 8 ++++++++ 2 files changed, 42 insertions(+) diff --git a/bsd-user/freebsd/os-proc.h b/bsd-user/freebsd/os-proc.h index 42bdd61904..7b2e6a9f79 100644 --- a/bsd-user/freebsd/os-proc.h +++ b/bsd-user/freebsd/os-proc.h @@ -185,4 +185,38 @@ static inline abi_long do_freebsd___setugid(abi_long arg1) return -TARGET_ENOSYS; } +/* fork(2) */ +static inline abi_long do_freebsd_fork(void *cpu_env) +{ + abi_long ret; + abi_ulong child_flag; + + fork_start(); + ret = fork(); + if (ret == 0) { + /* child */ + child_flag = 1; + target_cpu_clone_regs(cpu_env, 0); + } else { + /* parent */ + child_flag = 0; + } + + /* + * The fork system call sets a child flag in the second return + * value: 0 for parent process, 1 for child process. + */ + set_second_rval(cpu_env, child_flag); + + fork_end(child_flag); + + return ret; +} + +/* vfork(2) */ +static inline abi_long do_freebsd_vfork(void *cpu_env) +{ + return do_freebsd_fork(cpu_env); +} + #endif /* BSD_USER_FREEBSD_OS_PROC_H */ diff --git a/bsd-user/freebsd/os-syscall.c b/bsd-user/freebsd/os-syscall.c index 99af0f6b15..cb9425c9ba 100644 --- a/bsd-user/freebsd/os-syscall.c +++ b/bsd-user/freebsd/os-syscall.c @@ -226,6 +226,14 @@ static abi_long freebsd_syscall(void *cpu_env, int num, abi_long arg1, /* * process system calls */ + case TARGET_FREEBSD_NR_fork: /* fork(2) */ + ret = do_freebsd_fork(cpu_env); + break; + + case TARGET_FREEBSD_NR_vfork: /* vfork(2) */ + ret = do_freebsd_vfork(cpu_env); + break; + case TARGET_FREEBSD_NR_execve: /* execve(2) */ ret = do_freebsd_execve(arg1, arg2, arg3); break; From 510eecbc86e1aa93c17e9e0a3acced366b0258e1 Mon Sep 17 00:00:00 2001 From: Stacey Son Date: Mon, 25 Sep 2023 21:24:24 +0300 Subject: [PATCH 0187/1077] bsd-user: Implement rfork(2) system call. Signed-off-by: Stacey Son Signed-off-by: Karim Taha Reviewed-by: Richard Henderson Reviewed-by: Warner Losh Message-Id: <20230925182425.3163-28-kariem.taha2.7@gmail.com> --- bsd-user/freebsd/os-proc.h | 39 +++++++++++++++++++++++++++++++++++ bsd-user/freebsd/os-syscall.c | 4 ++++ 2 files changed, 43 insertions(+) diff --git a/bsd-user/freebsd/os-proc.h b/bsd-user/freebsd/os-proc.h index 7b2e6a9f79..0a3cd0ef57 100644 --- a/bsd-user/freebsd/os-proc.h +++ b/bsd-user/freebsd/os-proc.h @@ -219,4 +219,43 @@ static inline abi_long do_freebsd_vfork(void *cpu_env) return do_freebsd_fork(cpu_env); } +/* rfork(2) */ +static inline abi_long do_freebsd_rfork(void *cpu_env, abi_long flags) +{ + abi_long ret; + abi_ulong child_flag; + + /* + * XXX We need to handle RFMEM here, as well. Neither are safe to execute + * as-is on x86 hosts because they'll split memory but not the stack, + * wreaking havoc on host architectures that use the stack to store the + * return address as both threads try to pop it off. Rejecting RFSPAWN + * entirely for now is ok, the only consumer at the moment is posix_spawn + * and it will fall back to classic vfork(2) if we return EINVAL. + */ + if ((flags & TARGET_RFSPAWN) != 0) { + return -TARGET_EINVAL; + } + fork_start(); + ret = rfork(flags); + if (ret == 0) { + /* child */ + child_flag = 1; + target_cpu_clone_regs(cpu_env, 0); + } else { + /* parent */ + child_flag = 0; + } + + /* + * The fork system call sets a child flag in the second return + * value: 0 for parent process, 1 for child process. + */ + set_second_rval(cpu_env, child_flag); + fork_end(child_flag); + + return ret; + +} + #endif /* BSD_USER_FREEBSD_OS_PROC_H */ diff --git a/bsd-user/freebsd/os-syscall.c b/bsd-user/freebsd/os-syscall.c index cb9425c9ba..4c4e773d1d 100644 --- a/bsd-user/freebsd/os-syscall.c +++ b/bsd-user/freebsd/os-syscall.c @@ -234,6 +234,10 @@ static abi_long freebsd_syscall(void *cpu_env, int num, abi_long arg1, ret = do_freebsd_vfork(cpu_env); break; + case TARGET_FREEBSD_NR_rfork: /* rfork(2) */ + ret = do_freebsd_rfork(cpu_env, arg1); + break; + case TARGET_FREEBSD_NR_execve: /* execve(2) */ ret = do_freebsd_execve(arg1, arg2, arg3); break; From 6756ae283ac7fe43b8bbc1d8662dfe238f667032 Mon Sep 17 00:00:00 2001 From: Stacey Son Date: Mon, 25 Sep 2023 21:24:25 +0300 Subject: [PATCH 0188/1077] bsd-user: Implement pdfork(2) system call. Signed-off-by: Stacey Son Signed-off-by: Karim Taha Acked-by: Richard Henderson Reviewed-by: Warner Losh Message-Id: <20230925182425.3163-29-kariem.taha2.7@gmail.com> --- bsd-user/freebsd/os-proc.h | 32 ++++++++++++++++++++++++++++++++ bsd-user/freebsd/os-syscall.c | 4 ++++ 2 files changed, 36 insertions(+) diff --git a/bsd-user/freebsd/os-proc.h b/bsd-user/freebsd/os-proc.h index 0a3cd0ef57..d641878034 100644 --- a/bsd-user/freebsd/os-proc.h +++ b/bsd-user/freebsd/os-proc.h @@ -258,4 +258,36 @@ static inline abi_long do_freebsd_rfork(void *cpu_env, abi_long flags) } +/* pdfork(2) */ +static inline abi_long do_freebsd_pdfork(void *cpu_env, abi_ulong target_fdp, + abi_long flags) +{ + abi_long ret; + abi_ulong child_flag; + int fd; + + fork_start(); + ret = pdfork(&fd, flags); + if (ret == 0) { + /* child */ + child_flag = 1; + target_cpu_clone_regs(cpu_env, 0); + } else { + /* parent */ + child_flag = 0; + if (put_user_s32(fd, target_fdp)) { + return -TARGET_EFAULT; + } + } + + /* + * The fork system call sets a child flag in the second return + * value: 0 for parent process, 1 for child process. + */ + set_second_rval(cpu_env, child_flag); + fork_end(child_flag); + + return ret; +} + #endif /* BSD_USER_FREEBSD_OS_PROC_H */ diff --git a/bsd-user/freebsd/os-syscall.c b/bsd-user/freebsd/os-syscall.c index 4c4e773d1d..d04712f0a7 100644 --- a/bsd-user/freebsd/os-syscall.c +++ b/bsd-user/freebsd/os-syscall.c @@ -238,6 +238,10 @@ static abi_long freebsd_syscall(void *cpu_env, int num, abi_long arg1, ret = do_freebsd_rfork(cpu_env, arg1); break; + case TARGET_FREEBSD_NR_pdfork: /* pdfork(2) */ + ret = do_freebsd_pdfork(cpu_env, arg1, arg2); + break; + case TARGET_FREEBSD_NR_execve: /* execve(2) */ ret = do_freebsd_execve(arg1, arg2, arg3); break; From 61a8f1100759a320940e8c53eaaefb37a4c603fb Mon Sep 17 00:00:00 2001 From: Stacey Son Date: Mon, 25 Sep 2023 21:26:47 +0300 Subject: [PATCH 0189/1077] bsd-user: Implement struct target_ipc_perm Signed-off-by: Stacey Son Signed-off-by: Karim Taha Reviewed-by: Richard Henderson Reviewed-by: Warner Losh Message-Id: <20230925182709.4834-2-kariem.taha2.7@gmail.com> --- bsd-user/syscall_defs.h | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/bsd-user/syscall_defs.h b/bsd-user/syscall_defs.h index a3bc738ff8..0e54d7df69 100644 --- a/bsd-user/syscall_defs.h +++ b/bsd-user/syscall_defs.h @@ -55,6 +55,23 @@ struct target_iovec { abi_long iov_len; /* Number of bytes */ }; +/* + * sys/ipc.h + */ +struct target_ipc_perm { + uint32_t cuid; /* creator user id */ + uint32_t cgid; /* creator group id */ + uint32_t uid; /* user id */ + uint32_t gid; /* group id */ + uint16_t mode; /* r/w permission */ + uint16_t seq; /* sequence # */ + abi_long key; /* user specified msg/sem/shm key */ +}; + +#define TARGET_IPC_RMID 0 /* remove identifier */ +#define TARGET_IPC_SET 1 /* set options */ +#define TARGET_IPC_STAT 2 /* get options */ + /* * sys/mman.h */ From 695cb9137f6c1b1bf940d303b2f26a46241056b8 Mon Sep 17 00:00:00 2001 From: Stacey Son Date: Mon, 25 Sep 2023 21:26:48 +0300 Subject: [PATCH 0190/1077] bsd-user: Implement struct target_shmid_ds Signed-off-by: Stacey Son Signed-off-by: Karim Taha Reviewed-by: Richard Henderson Reviewed-by: Warner Losh Message-Id: <20230925182709.4834-3-kariem.taha2.7@gmail.com> --- bsd-user/syscall_defs.h | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/bsd-user/syscall_defs.h b/bsd-user/syscall_defs.h index 0e54d7df69..ff69281433 100644 --- a/bsd-user/syscall_defs.h +++ b/bsd-user/syscall_defs.h @@ -72,6 +72,26 @@ struct target_ipc_perm { #define TARGET_IPC_SET 1 /* set options */ #define TARGET_IPC_STAT 2 /* get options */ +/* + * sys/shm.h + */ +struct target_shmid_ds { + struct target_ipc_perm shm_perm; /* peration permission structure */ + abi_ulong shm_segsz; /* size of segment in bytes */ + int32_t shm_lpid; /* process ID of last shared memory op */ + int32_t shm_cpid; /* process ID of creator */ + int32_t shm_nattch; /* number of current attaches */ + target_time_t shm_atime; /* time of last shmat() */ + target_time_t shm_dtime; /* time of last shmdt() */ + target_time_t shm_ctime; /* time of last change by shmctl() */ +}; + +#define N_BSD_SHM_REGIONS 32 +struct bsd_shm_regions { + abi_long start; + abi_long size; +}; + /* * sys/mman.h */ From 1d4c4026b15045e45de5c6f64e4b6322274680e7 Mon Sep 17 00:00:00 2001 From: Stacey Son Date: Mon, 25 Sep 2023 21:26:49 +0300 Subject: [PATCH 0191/1077] bsd-user: Declarations for ipc_perm and shmid_ds conversion functions Signed-off-by: Stacey Son Signed-off-by: Karim Taha Reviewed-by: Richard Henderson Reviewed-by: Warner Losh Message-Id: <20230925182709.4834-4-kariem.taha2.7@gmail.com> --- bsd-user/qemu-bsd.h | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/bsd-user/qemu-bsd.h b/bsd-user/qemu-bsd.h index b93a0b7fd5..ffc64bb244 100644 --- a/bsd-user/qemu-bsd.h +++ b/bsd-user/qemu-bsd.h @@ -22,6 +22,16 @@ #include #include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include /* bsd-proc.c */ int target_to_host_resource(int code); @@ -35,4 +45,14 @@ int host_to_target_waitstatus(int status); void h2g_rusage(const struct rusage *rusage, struct target_freebsd_rusage *target_rusage); +/* bsd-mem.c */ +void target_to_host_ipc_perm__locked(struct ipc_perm *host_ip, + struct target_ipc_perm *target_ip); +void host_to_target_ipc_perm__locked(struct target_ipc_perm *target_ip, + struct ipc_perm *host_ip); +abi_long target_to_host_shmid_ds(struct shmid_ds *host_sd, + abi_ulong target_addr); +abi_long host_to_target_shmid_ds(abi_ulong target_addr, + struct shmid_ds *host_sd); + #endif /* QEMU_BSD_H */ From 137d963cfb1c9f0d9e76a40229df2996809b746b Mon Sep 17 00:00:00 2001 From: Stacey Son Date: Mon, 25 Sep 2023 21:26:50 +0300 Subject: [PATCH 0192/1077] bsd-user: Introduce freebsd/os-misc.h to the source tree To preserve the copyright notice and help with the 'Author' info for subsequent changes to the file. Signed-off-by: Stacey Son Signed-off-by: Karim Taha Reviewed-by: Richard Henderson Reviewed-by: Warner Losh Message-Id: <20230925182709.4834-5-kariem.taha2.7@gmail.com> --- bsd-user/freebsd/os-misc.h | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) create mode 100644 bsd-user/freebsd/os-misc.h diff --git a/bsd-user/freebsd/os-misc.h b/bsd-user/freebsd/os-misc.h new file mode 100644 index 0000000000..8436ccb2f7 --- /dev/null +++ b/bsd-user/freebsd/os-misc.h @@ -0,0 +1,28 @@ +/* + * miscellaneous FreeBSD system call shims + * + * Copyright (c) 2013-14 Stacey D. Son + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + */ + +#ifndef OS_MISC_H +#define OS_MISC_H + +#include +#include +#include + + +#endif /* OS_MISC_H */ From 0c3529888a427cefe248227423f7a89c8f665fab Mon Sep 17 00:00:00 2001 From: Karim Taha Date: Mon, 25 Sep 2023 21:26:51 +0300 Subject: [PATCH 0193/1077] bsd-user: Implement shm_open2(2) system call Signed-off-by: Kyle Evans Signed-off-by: Karim Taha Reviewed-by: Richard Henderson Message-Id: <20230925182709.4834-6-kariem.taha2.7@gmail.com> --- bsd-user/freebsd/os-misc.h | 46 +++++++++++++++++++++++++++++++++++ bsd-user/freebsd/os-syscall.c | 22 ++++++++++++----- 2 files changed, 62 insertions(+), 6 deletions(-) diff --git a/bsd-user/freebsd/os-misc.h b/bsd-user/freebsd/os-misc.h index 8436ccb2f7..d5e8b5484c 100644 --- a/bsd-user/freebsd/os-misc.h +++ b/bsd-user/freebsd/os-misc.h @@ -24,5 +24,51 @@ #include #include +/* + * shm_open2 isn't exported, but the __sys_ alias is. We can use either for the + * static version, but to dynamically link we have to use the sys version. + */ +int __sys_shm_open2(const char *path, int flags, mode_t mode, int shmflags, + const char *); + +#if defined(__FreeBSD_version) && __FreeBSD_version >= 1300048 +/* shm_open2(2) */ +static inline abi_long do_freebsd_shm_open2(abi_ulong pathptr, abi_ulong flags, + abi_long mode, abi_ulong shmflags, abi_ulong nameptr) +{ + int ret; + void *uname, *upath; + + if (pathptr == (uintptr_t)SHM_ANON) { + upath = SHM_ANON; + } else { + upath = lock_user_string(pathptr); + if (upath == NULL) { + return -TARGET_EFAULT; + } + } + + uname = NULL; + if (nameptr != 0) { + uname = lock_user_string(nameptr); + if (uname == NULL) { + unlock_user(upath, pathptr, 0); + return -TARGET_EFAULT; + } + } + ret = get_errno(__sys_shm_open2(upath, + target_to_host_bitmask(flags, fcntl_flags_tbl), mode, + target_to_host_bitmask(shmflags, shmflag_flags_tbl), uname)); + + if (upath != SHM_ANON) { + unlock_user(upath, pathptr, 0); + } + if (uname != NULL) { + unlock_user(uname, nameptr, 0); + } + return ret; +} +#endif /* __FreeBSD_version >= 1300048 */ + #endif /* OS_MISC_H */ diff --git a/bsd-user/freebsd/os-syscall.c b/bsd-user/freebsd/os-syscall.c index d04712f0a7..122e186b50 100644 --- a/bsd-user/freebsd/os-syscall.c +++ b/bsd-user/freebsd/os-syscall.c @@ -33,18 +33,14 @@ #include "signal-common.h" #include "user/syscall-trace.h" +/* BSD independent syscall shims */ #include "bsd-file.h" #include "bsd-proc.h" /* BSD dependent syscall shims */ #include "os-stat.h" #include "os-proc.h" - -/* used in os-proc */ -safe_syscall4(pid_t, wait4, pid_t, wpid, int *, status, int, options, - struct rusage *, rusage); -safe_syscall6(pid_t, wait6, idtype_t, idtype, id_t, id, int *, status, int, - options, struct __wrusage *, wrusage, siginfo_t *, infop); +#include "os-misc.h" /* I/O */ safe_syscall3(int, open, const char *, path, int, flags, mode_t, mode); @@ -65,6 +61,12 @@ safe_syscall3(ssize_t, writev, int, fd, const struct iovec *, iov, int, iovcnt); safe_syscall4(ssize_t, pwritev, int, fd, const struct iovec *, iov, int, iovcnt, off_t, offset); +/* used in os-proc */ +safe_syscall4(pid_t, wait4, pid_t, wpid, int *, status, int, options, + struct rusage *, rusage); +safe_syscall6(pid_t, wait6, idtype_t, idtype, id_t, id, int *, status, int, + options, struct __wrusage *, wrusage, siginfo_t *, infop); + void target_set_brk(abi_ulong new_brk) { } @@ -796,6 +798,14 @@ static abi_long freebsd_syscall(void *cpu_env, int num, abi_long arg1, ret = do_freebsd_fcntl(arg1, arg2, arg3); break; + /* + * Memory management system calls. + */ +#if defined(__FreeBSD_version) && __FreeBSD_version >= 1300048 + case TARGET_FREEBSD_NR_shm_open2: /* shm_open2(2) */ + ret = do_freebsd_shm_open2(arg1, arg2, arg3, arg4, arg5); + break; +#endif /* * sys{ctl, arch, call} From 182ea728e06a09e6ceaa9d62a279e883459d36dd Mon Sep 17 00:00:00 2001 From: Kyle Evans Date: Mon, 25 Sep 2023 21:26:52 +0300 Subject: [PATCH 0194/1077] bsd-user: Implement shm_rename(2) system call Signed-off-by: Kyle Evans Signed-off-by: Karim Taha Reviewed-by: Richard Henderson Reviewed-by: Warner Losh Message-Id: <20230925182709.4834-7-kariem.taha2.7@gmail.com> --- bsd-user/freebsd/os-misc.h | 24 ++++++++++++++++++++++++ bsd-user/freebsd/os-syscall.c | 6 ++++++ 2 files changed, 30 insertions(+) diff --git a/bsd-user/freebsd/os-misc.h b/bsd-user/freebsd/os-misc.h index d5e8b5484c..71145764a4 100644 --- a/bsd-user/freebsd/os-misc.h +++ b/bsd-user/freebsd/os-misc.h @@ -70,5 +70,29 @@ static inline abi_long do_freebsd_shm_open2(abi_ulong pathptr, abi_ulong flags, } #endif /* __FreeBSD_version >= 1300048 */ +#if defined(__FreeBSD_version) && __FreeBSD_version >= 1300049 +/* shm_rename(2) */ +static inline abi_long do_freebsd_shm_rename(abi_ulong fromptr, abi_ulong toptr, + abi_ulong flags) +{ + int ret; + void *ufrom, *uto; + + ufrom = lock_user_string(fromptr); + if (ufrom == NULL) { + return -TARGET_EFAULT; + } + uto = lock_user_string(toptr); + if (uto == NULL) { + unlock_user(ufrom, fromptr, 0); + return -TARGET_EFAULT; + } + ret = get_errno(shm_rename(ufrom, uto, flags)); + unlock_user(ufrom, fromptr, 0); + unlock_user(uto, toptr, 0); + + return ret; +} +#endif /* __FreeBSD_version >= 1300049 */ #endif /* OS_MISC_H */ diff --git a/bsd-user/freebsd/os-syscall.c b/bsd-user/freebsd/os-syscall.c index 122e186b50..5fb42b2c21 100644 --- a/bsd-user/freebsd/os-syscall.c +++ b/bsd-user/freebsd/os-syscall.c @@ -807,6 +807,12 @@ static abi_long freebsd_syscall(void *cpu_env, int num, abi_long arg1, break; #endif +#if defined(__FreeBSD_version) && __FreeBSD_version >= 1300049 + case TARGET_FREEBSD_NR_shm_rename: /* shm_rename(2) */ + ret = do_freebsd_shm_rename(arg1, arg2, arg3); + break; +#endif + /* * sys{ctl, arch, call} */ From dde5f40dc38d61e80a91c482d9faf45eacdceed8 Mon Sep 17 00:00:00 2001 From: Karim Taha Date: Mon, 25 Sep 2023 21:26:53 +0300 Subject: [PATCH 0195/1077] bsd-user: Add bsd-mem.c to meson.build Signed-off-by: Karim Taha Reviewed-by: Richard Henderson Reviewed-by: Warner Losh Message-Id: <20230925182709.4834-8-kariem.taha2.7@gmail.com> --- bsd-user/bsd-mem.c | 0 bsd-user/meson.build | 1 + 2 files changed, 1 insertion(+) create mode 100644 bsd-user/bsd-mem.c diff --git a/bsd-user/bsd-mem.c b/bsd-user/bsd-mem.c new file mode 100644 index 0000000000..e69de29bb2 diff --git a/bsd-user/meson.build b/bsd-user/meson.build index b97fce1472..c6bfd3b2b5 100644 --- a/bsd-user/meson.build +++ b/bsd-user/meson.build @@ -7,6 +7,7 @@ bsd_user_ss = ss.source_set() common_user_inc += include_directories('include') bsd_user_ss.add(files( + 'bsd-mem.c', 'bsd-proc.c', 'bsdload.c', 'elfload.c', From c9cdf0a5ecfd16176e48a8cec6fc4a22d9d7b229 Mon Sep 17 00:00:00 2001 From: Stacey Son Date: Mon, 25 Sep 2023 21:26:54 +0300 Subject: [PATCH 0196/1077] bsd-user: Implement target_set_brk function in bsd-mem.c instead of os-syscall.c MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The definitions and variables names matches the corresponding ones in linux-user/syscall.c, for making later implementation of do_obreak easier Co-authored-by: Mikaël Urankar Signed-off-by: Mikaël Urankar Signed-off-by: Karim Taha Reviewed-by: Warner Losh Reviewed-by: Richard Henderson Message-Id: <20230925182709.4834-9-kariem.taha2.7@gmail.com> --- bsd-user/bsd-mem.c | 32 ++++++++++++++++++++++++++++++++ bsd-user/freebsd/os-syscall.c | 4 ---- 2 files changed, 32 insertions(+), 4 deletions(-) diff --git a/bsd-user/bsd-mem.c b/bsd-user/bsd-mem.c index e69de29bb2..8834ab2e58 100644 --- a/bsd-user/bsd-mem.c +++ b/bsd-user/bsd-mem.c @@ -0,0 +1,32 @@ +/* + * memory management system conversion routines + * + * Copyright (c) 2013 Stacey D. Son + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + */ +#include "qemu/osdep.h" +#include "qemu.h" +#include "qemu-bsd.h" + +struct bsd_shm_regions bsd_shm_regions[N_BSD_SHM_REGIONS]; + +abi_ulong target_brk; +abi_ulong initial_target_brk; + +void target_set_brk(abi_ulong new_brk) +{ + target_brk = TARGET_PAGE_ALIGN(new_brk); + initial_target_brk = target_brk; +} diff --git a/bsd-user/freebsd/os-syscall.c b/bsd-user/freebsd/os-syscall.c index 5fb42b2c21..c9d34b59bb 100644 --- a/bsd-user/freebsd/os-syscall.c +++ b/bsd-user/freebsd/os-syscall.c @@ -67,10 +67,6 @@ safe_syscall4(pid_t, wait4, pid_t, wpid, int *, status, int, options, safe_syscall6(pid_t, wait6, idtype_t, idtype, id_t, id, int *, status, int, options, struct __wrusage *, wrusage, siginfo_t *, infop); -void target_set_brk(abi_ulong new_brk) -{ -} - /* * errno conversion. */ From 86fbb4436bd09c5006c1f07d4cb007b2e91b595a Mon Sep 17 00:00:00 2001 From: Stacey Son Date: Mon, 25 Sep 2023 21:26:55 +0300 Subject: [PATCH 0197/1077] bsd-user: Implement ipc_perm conversion between host and target. Signed-off-by: Stacey Son Signed-off-by: Karim Taha Reviewed-by: Richard Henderson Message-Id: <20230925182709.4834-10-kariem.taha2.7@gmail.com> --- bsd-user/bsd-mem.c | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/bsd-user/bsd-mem.c b/bsd-user/bsd-mem.c index 8834ab2e58..46cda8eb5c 100644 --- a/bsd-user/bsd-mem.c +++ b/bsd-user/bsd-mem.c @@ -30,3 +30,28 @@ void target_set_brk(abi_ulong new_brk) target_brk = TARGET_PAGE_ALIGN(new_brk); initial_target_brk = target_brk; } + +void target_to_host_ipc_perm__locked(struct ipc_perm *host_ip, + struct target_ipc_perm *target_ip) +{ + __get_user(host_ip->cuid, &target_ip->cuid); + __get_user(host_ip->cgid, &target_ip->cgid); + __get_user(host_ip->uid, &target_ip->uid); + __get_user(host_ip->gid, &target_ip->gid); + __get_user(host_ip->mode, &target_ip->mode); + __get_user(host_ip->seq, &target_ip->seq); + __get_user(host_ip->key, &target_ip->key); +} + +void host_to_target_ipc_perm__locked(struct target_ipc_perm *target_ip, + struct ipc_perm *host_ip) +{ + __put_user(host_ip->cuid, &target_ip->cuid); + __put_user(host_ip->cgid, &target_ip->cgid); + __put_user(host_ip->uid, &target_ip->uid); + __put_user(host_ip->gid, &target_ip->gid); + __put_user(host_ip->mode, &target_ip->mode); + __put_user(host_ip->seq, &target_ip->seq); + __put_user(host_ip->key, &target_ip->key); +} + From bd2b73182f5a793c1b226a2846c847faaa7b3e9d Mon Sep 17 00:00:00 2001 From: Stacey Son Date: Mon, 25 Sep 2023 21:26:56 +0300 Subject: [PATCH 0198/1077] bsd-user: Implement shmid_ds conversion between host and target. Signed-off-by: Stacey Son Signed-off-by: Karim Taha Reviewed-by: Richard Henderson Message-Id: <20230925182709.4834-11-kariem.taha2.7@gmail.com> --- bsd-user/bsd-mem.c | 47 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 47 insertions(+) diff --git a/bsd-user/bsd-mem.c b/bsd-user/bsd-mem.c index 46cda8eb5c..2ab1334b70 100644 --- a/bsd-user/bsd-mem.c +++ b/bsd-user/bsd-mem.c @@ -43,6 +43,30 @@ void target_to_host_ipc_perm__locked(struct ipc_perm *host_ip, __get_user(host_ip->key, &target_ip->key); } +abi_long target_to_host_shmid_ds(struct shmid_ds *host_sd, + abi_ulong target_addr) +{ + struct target_shmid_ds *target_sd; + + if (!lock_user_struct(VERIFY_READ, target_sd, target_addr, 1)) { + return -TARGET_EFAULT; + } + + target_to_host_ipc_perm__locked(&(host_sd->shm_perm), + &(target_sd->shm_perm)); + + __get_user(host_sd->shm_segsz, &target_sd->shm_segsz); + __get_user(host_sd->shm_lpid, &target_sd->shm_lpid); + __get_user(host_sd->shm_cpid, &target_sd->shm_cpid); + __get_user(host_sd->shm_nattch, &target_sd->shm_nattch); + __get_user(host_sd->shm_atime, &target_sd->shm_atime); + __get_user(host_sd->shm_dtime, &target_sd->shm_dtime); + __get_user(host_sd->shm_ctime, &target_sd->shm_ctime); + unlock_user_struct(target_sd, target_addr, 0); + + return 0; +} + void host_to_target_ipc_perm__locked(struct target_ipc_perm *target_ip, struct ipc_perm *host_ip) { @@ -55,3 +79,26 @@ void host_to_target_ipc_perm__locked(struct target_ipc_perm *target_ip, __put_user(host_ip->key, &target_ip->key); } +abi_long host_to_target_shmid_ds(abi_ulong target_addr, + struct shmid_ds *host_sd) +{ + struct target_shmid_ds *target_sd; + + if (!lock_user_struct(VERIFY_WRITE, target_sd, target_addr, 0)) { + return -TARGET_EFAULT; + } + + host_to_target_ipc_perm__locked(&(target_sd->shm_perm), + &(host_sd->shm_perm)); + + __put_user(host_sd->shm_segsz, &target_sd->shm_segsz); + __put_user(host_sd->shm_lpid, &target_sd->shm_lpid); + __put_user(host_sd->shm_cpid, &target_sd->shm_cpid); + __put_user(host_sd->shm_nattch, &target_sd->shm_nattch); + __put_user(host_sd->shm_atime, &target_sd->shm_atime); + __put_user(host_sd->shm_dtime, &target_sd->shm_dtime); + __put_user(host_sd->shm_ctime, &target_sd->shm_ctime); + unlock_user_struct(target_sd, target_addr, 1); + + return 0; +} From 6765e988e12825e9464a10b6451aeb25b29bfbc3 Mon Sep 17 00:00:00 2001 From: Stacey Son Date: Mon, 25 Sep 2023 21:26:57 +0300 Subject: [PATCH 0199/1077] bsd-user: Introduce bsd-mem.h to the source tree Preserve the copyright notice and help with the 'Author' info for subsequent changes to the file. Signed-off-by: Stacey Son Signed-off-by: Karim Taha Reviewed-by: Warner Losh Reviewed-by: Richard Henderson Message-Id: <20230925182709.4834-12-kariem.taha2.7@gmail.com> --- bsd-user/bsd-mem.h | 64 +++++++++++++++++++++++++++++++++++ bsd-user/freebsd/os-syscall.c | 1 + 2 files changed, 65 insertions(+) create mode 100644 bsd-user/bsd-mem.h diff --git a/bsd-user/bsd-mem.h b/bsd-user/bsd-mem.h new file mode 100644 index 0000000000..d865e0807d --- /dev/null +++ b/bsd-user/bsd-mem.h @@ -0,0 +1,64 @@ +/* + * memory management system call shims and definitions + * + * Copyright (c) 2013-15 Stacey D. Son + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + */ + +/* + * Copyright (c) 1982, 1986, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef BSD_USER_BSD_MEM_H +#define BSD_USER_BSD_MEM_H + +#include +#include +#include +#include +#include + +#include "qemu-bsd.h" + +extern struct bsd_shm_regions bsd_shm_regions[]; +extern abi_ulong target_brk; +extern abi_ulong initial_target_brk; + +#endif /* BSD_USER_BSD_MEM_H */ diff --git a/bsd-user/freebsd/os-syscall.c b/bsd-user/freebsd/os-syscall.c index c9d34b59bb..7887ad4c0c 100644 --- a/bsd-user/freebsd/os-syscall.c +++ b/bsd-user/freebsd/os-syscall.c @@ -35,6 +35,7 @@ /* BSD independent syscall shims */ #include "bsd-file.h" +#include "bsd-mem.h" #include "bsd-proc.h" /* BSD dependent syscall shims */ From 87dcb4ad485424dcbfedbc7a298279e8738f1a40 Mon Sep 17 00:00:00 2001 From: Stacey Son Date: Mon, 25 Sep 2023 21:26:58 +0300 Subject: [PATCH 0200/1077] bsd-user: Implement mmap(2) and munmap(2) Signed-off-by: Stacey Son Signed-off-by: Karim Taha Reviewed-by: Warner Losh Reviewed-by: Richard Henderson Message-Id: <20230925182709.4834-13-kariem.taha2.7@gmail.com> --- bsd-user/bsd-mem.h | 20 ++++++++++++++++++++ bsd-user/freebsd/os-syscall.c | 9 +++++++++ 2 files changed, 29 insertions(+) diff --git a/bsd-user/bsd-mem.h b/bsd-user/bsd-mem.h index d865e0807d..76b504f70c 100644 --- a/bsd-user/bsd-mem.h +++ b/bsd-user/bsd-mem.h @@ -61,4 +61,24 @@ extern struct bsd_shm_regions bsd_shm_regions[]; extern abi_ulong target_brk; extern abi_ulong initial_target_brk; +/* mmap(2) */ +static inline abi_long do_bsd_mmap(void *cpu_env, abi_long arg1, abi_long arg2, + abi_long arg3, abi_long arg4, abi_long arg5, abi_long arg6, abi_long arg7, + abi_long arg8) +{ + if (regpairs_aligned(cpu_env) != 0) { + arg6 = arg7; + arg7 = arg8; + } + return get_errno(target_mmap(arg1, arg2, arg3, + target_to_host_bitmask(arg4, mmap_flags_tbl), + arg5, target_arg64(arg6, arg7))); +} + +/* munmap(2) */ +static inline abi_long do_bsd_munmap(abi_long arg1, abi_long arg2) +{ + return get_errno(target_munmap(arg1, arg2)); +} + #endif /* BSD_USER_BSD_MEM_H */ diff --git a/bsd-user/freebsd/os-syscall.c b/bsd-user/freebsd/os-syscall.c index 7887ad4c0c..b03837d032 100644 --- a/bsd-user/freebsd/os-syscall.c +++ b/bsd-user/freebsd/os-syscall.c @@ -798,6 +798,15 @@ static abi_long freebsd_syscall(void *cpu_env, int num, abi_long arg1, /* * Memory management system calls. */ + case TARGET_FREEBSD_NR_mmap: /* mmap(2) */ + ret = do_bsd_mmap(cpu_env, arg1, arg2, arg3, arg4, arg5, arg6, arg7, + arg8); + break; + + case TARGET_FREEBSD_NR_munmap: /* munmap(2) */ + ret = do_bsd_munmap(arg1, arg2); + break; + #if defined(__FreeBSD_version) && __FreeBSD_version >= 1300048 case TARGET_FREEBSD_NR_shm_open2: /* shm_open2(2) */ ret = do_freebsd_shm_open2(arg1, arg2, arg3, arg4, arg5); From ecbe22494d970b7811a1764d2f98e083b02f73d0 Mon Sep 17 00:00:00 2001 From: Stacey Son Date: Mon, 25 Sep 2023 21:26:59 +0300 Subject: [PATCH 0201/1077] bsd-user: Implement mprotect(2) Signed-off-by: Stacey Son Signed-off-by: Karim Taha Reviewed-by: Richard Henderson Reviewed-by: Warner Losh Message-Id: <20230925182709.4834-14-kariem.taha2.7@gmail.com> --- bsd-user/bsd-mem.h | 7 +++++++ bsd-user/freebsd/os-syscall.c | 4 ++++ 2 files changed, 11 insertions(+) diff --git a/bsd-user/bsd-mem.h b/bsd-user/bsd-mem.h index 76b504f70c..0f9e4a1d4b 100644 --- a/bsd-user/bsd-mem.h +++ b/bsd-user/bsd-mem.h @@ -81,4 +81,11 @@ static inline abi_long do_bsd_munmap(abi_long arg1, abi_long arg2) return get_errno(target_munmap(arg1, arg2)); } +/* mprotect(2) */ +static inline abi_long do_bsd_mprotect(abi_long arg1, abi_long arg2, + abi_long arg3) +{ + return get_errno(target_mprotect(arg1, arg2, arg3)); +} + #endif /* BSD_USER_BSD_MEM_H */ diff --git a/bsd-user/freebsd/os-syscall.c b/bsd-user/freebsd/os-syscall.c index b03837d032..2d8f1a953b 100644 --- a/bsd-user/freebsd/os-syscall.c +++ b/bsd-user/freebsd/os-syscall.c @@ -807,6 +807,10 @@ static abi_long freebsd_syscall(void *cpu_env, int num, abi_long arg1, ret = do_bsd_munmap(arg1, arg2); break; + case TARGET_FREEBSD_NR_mprotect: /* mprotect(2) */ + ret = do_bsd_mprotect(arg1, arg2, arg3); + break; + #if defined(__FreeBSD_version) && __FreeBSD_version >= 1300048 case TARGET_FREEBSD_NR_shm_open2: /* shm_open2(2) */ ret = do_freebsd_shm_open2(arg1, arg2, arg3, arg4, arg5); From f28a1e4bab4cfdd067bde3d958529575aa8e8f6b Mon Sep 17 00:00:00 2001 From: Stacey Son Date: Mon, 25 Sep 2023 21:27:00 +0300 Subject: [PATCH 0202/1077] bsd-user: Implement msync(2) Co-authored-by: Kyle Evans Signed-off-by: Stacey Son Signed-off-by: Kyle Evans Signed-off-by: Karim Taha Reviewed-by: Warner Losh Reviewed-by: Richard Henderson Message-Id: <20230925182709.4834-15-kariem.taha2.7@gmail.com> --- bsd-user/bsd-mem.h | 11 +++++++++++ bsd-user/freebsd/os-syscall.c | 4 ++++ 2 files changed, 15 insertions(+) diff --git a/bsd-user/bsd-mem.h b/bsd-user/bsd-mem.h index 0f9e4a1d4b..5e885823a7 100644 --- a/bsd-user/bsd-mem.h +++ b/bsd-user/bsd-mem.h @@ -88,4 +88,15 @@ static inline abi_long do_bsd_mprotect(abi_long arg1, abi_long arg2, return get_errno(target_mprotect(arg1, arg2, arg3)); } +/* msync(2) */ +static inline abi_long do_bsd_msync(abi_long addr, abi_long len, abi_long flags) +{ + if (!guest_range_valid_untagged(addr, len)) { + /* It seems odd, but POSIX wants this to be ENOMEM */ + return -TARGET_ENOMEM; + } + + return get_errno(msync(g2h_untagged(addr), len, flags)); +} + #endif /* BSD_USER_BSD_MEM_H */ diff --git a/bsd-user/freebsd/os-syscall.c b/bsd-user/freebsd/os-syscall.c index 2d8f1a953b..2525e0bc31 100644 --- a/bsd-user/freebsd/os-syscall.c +++ b/bsd-user/freebsd/os-syscall.c @@ -811,6 +811,10 @@ static abi_long freebsd_syscall(void *cpu_env, int num, abi_long arg1, ret = do_bsd_mprotect(arg1, arg2, arg3); break; + case TARGET_FREEBSD_NR_msync: /* msync(2) */ + ret = do_bsd_msync(arg1, arg2, arg3); + break; + #if defined(__FreeBSD_version) && __FreeBSD_version >= 1300048 case TARGET_FREEBSD_NR_shm_open2: /* shm_open2(2) */ ret = do_freebsd_shm_open2(arg1, arg2, arg3, arg4, arg5); From 0a49ef02a643864a9c6a36ebaf452e0d30c96b0b Mon Sep 17 00:00:00 2001 From: Stacey Son Date: Mon, 25 Sep 2023 21:27:01 +0300 Subject: [PATCH 0203/1077] bsd-user: Implement mlock(2), munlock(2), mlockall(2), munlockall(2), minherit(2) Signed-off-by: Stacey Son Signed-off-by: Karim Taha Reviewed-by: Richard Henderson Message-Id: <20230925182709.4834-16-kariem.taha2.7@gmail.com> --- bsd-user/bsd-mem.h | 37 +++++++++++++++++++++++++++++++++++ bsd-user/freebsd/os-syscall.c | 20 +++++++++++++++++++ 2 files changed, 57 insertions(+) diff --git a/bsd-user/bsd-mem.h b/bsd-user/bsd-mem.h index 5e885823a7..16c22593bf 100644 --- a/bsd-user/bsd-mem.h +++ b/bsd-user/bsd-mem.h @@ -99,4 +99,41 @@ static inline abi_long do_bsd_msync(abi_long addr, abi_long len, abi_long flags) return get_errno(msync(g2h_untagged(addr), len, flags)); } +/* mlock(2) */ +static inline abi_long do_bsd_mlock(abi_long arg1, abi_long arg2) +{ + if (!guest_range_valid_untagged(arg1, arg2)) { + return -TARGET_EINVAL; + } + return get_errno(mlock(g2h_untagged(arg1), arg2)); +} + +/* munlock(2) */ +static inline abi_long do_bsd_munlock(abi_long arg1, abi_long arg2) +{ + if (!guest_range_valid_untagged(arg1, arg2)) { + return -TARGET_EINVAL; + } + return get_errno(munlock(g2h_untagged(arg1), arg2)); +} + +/* mlockall(2) */ +static inline abi_long do_bsd_mlockall(abi_long arg1) +{ + return get_errno(mlockall(arg1)); +} + +/* munlockall(2) */ +static inline abi_long do_bsd_munlockall(void) +{ + return get_errno(munlockall()); +} + +/* minherit(2) */ +static inline abi_long do_bsd_minherit(abi_long addr, abi_long len, + abi_long inherit) +{ + return get_errno(minherit(g2h_untagged(addr), len, inherit)); +} + #endif /* BSD_USER_BSD_MEM_H */ diff --git a/bsd-user/freebsd/os-syscall.c b/bsd-user/freebsd/os-syscall.c index 2525e0bc31..7a7ae26793 100644 --- a/bsd-user/freebsd/os-syscall.c +++ b/bsd-user/freebsd/os-syscall.c @@ -815,6 +815,26 @@ static abi_long freebsd_syscall(void *cpu_env, int num, abi_long arg1, ret = do_bsd_msync(arg1, arg2, arg3); break; + case TARGET_FREEBSD_NR_mlock: /* mlock(2) */ + ret = do_bsd_mlock(arg1, arg2); + break; + + case TARGET_FREEBSD_NR_munlock: /* munlock(2) */ + ret = do_bsd_munlock(arg1, arg2); + break; + + case TARGET_FREEBSD_NR_mlockall: /* mlockall(2) */ + ret = do_bsd_mlockall(arg1); + break; + + case TARGET_FREEBSD_NR_munlockall: /* munlockall(2) */ + ret = do_bsd_munlockall(); + break; + + case TARGET_FREEBSD_NR_minherit: /* minherit(2) */ + ret = do_bsd_minherit(arg1, arg2, arg3); + break; + #if defined(__FreeBSD_version) && __FreeBSD_version >= 1300048 case TARGET_FREEBSD_NR_shm_open2: /* shm_open2(2) */ ret = do_freebsd_shm_open2(arg1, arg2, arg3, arg4, arg5); From 0c1ced42c84bdd8beeef6c40dff8d143cf409f15 Mon Sep 17 00:00:00 2001 From: Karim Taha Date: Mon, 25 Sep 2023 21:27:02 +0300 Subject: [PATCH 0204/1077] bsd-user: Implment madvise(2) to match the linux-user implementation. Signed-off-by: Karim Taha Reviewed-by: Richard Henderson Message-Id: <20230925182709.4834-17-kariem.taha2.7@gmail.com> --- bsd-user/bsd-mem.h | 53 +++++++++++++++++++++++++++++++++++ bsd-user/freebsd/os-syscall.c | 4 +++ bsd-user/syscall_defs.h | 2 ++ 3 files changed, 59 insertions(+) diff --git a/bsd-user/bsd-mem.h b/bsd-user/bsd-mem.h index 16c22593bf..b00ab3aed8 100644 --- a/bsd-user/bsd-mem.h +++ b/bsd-user/bsd-mem.h @@ -129,6 +129,59 @@ static inline abi_long do_bsd_munlockall(void) return get_errno(munlockall()); } +/* madvise(2) */ +static inline abi_long do_bsd_madvise(abi_long arg1, abi_long arg2, + abi_long arg3) +{ + abi_ulong len; + int ret = 0; + abi_long start = arg1; + abi_long len_in = arg2; + abi_long advice = arg3; + + if (start & ~TARGET_PAGE_MASK) { + return -TARGET_EINVAL; + } + if (len_in == 0) { + return 0; + } + len = TARGET_PAGE_ALIGN(len_in); + if (len == 0 || !guest_range_valid_untagged(start, len)) { + return -TARGET_EINVAL; + } + + /* + * Most advice values are hints, so ignoring and returning success is ok. + * + * However, some advice values such as MADV_DONTNEED, are not hints and + * need to be emulated. + * + * A straight passthrough for those may not be safe because qemu sometimes + * turns private file-backed mappings into anonymous mappings. + * If all guest pages have PAGE_PASSTHROUGH set, mappings have the + * same semantics for the host as for the guest. + * + * MADV_DONTNEED is passed through, if possible. + * If passthrough isn't possible, we nevertheless (wrongly!) return + * success, which is broken but some userspace programs fail to work + * otherwise. Completely implementing such emulation is quite complicated + * though. + */ + mmap_lock(); + switch (advice) { + case MADV_DONTNEED: + if (page_check_range(start, len, PAGE_PASSTHROUGH)) { + ret = get_errno(madvise(g2h_untagged(start), len, advice)); + if (ret == 0) { + page_reset_target_data(start, start + len - 1); + } + } + } + mmap_unlock(); + + return ret; +} + /* minherit(2) */ static inline abi_long do_bsd_minherit(abi_long addr, abi_long len, abi_long inherit) diff --git a/bsd-user/freebsd/os-syscall.c b/bsd-user/freebsd/os-syscall.c index 7a7ae26793..b8c44cea0f 100644 --- a/bsd-user/freebsd/os-syscall.c +++ b/bsd-user/freebsd/os-syscall.c @@ -831,6 +831,10 @@ static abi_long freebsd_syscall(void *cpu_env, int num, abi_long arg1, ret = do_bsd_munlockall(); break; + case TARGET_FREEBSD_NR_madvise: /* madvise(2) */ + ret = do_bsd_madvise(arg1, arg2, arg3); + break; + case TARGET_FREEBSD_NR_minherit: /* minherit(2) */ ret = do_bsd_minherit(arg1, arg2, arg3); break; diff --git a/bsd-user/syscall_defs.h b/bsd-user/syscall_defs.h index ff69281433..52f84d5dd1 100644 --- a/bsd-user/syscall_defs.h +++ b/bsd-user/syscall_defs.h @@ -95,6 +95,8 @@ struct bsd_shm_regions { /* * sys/mman.h */ +#define TARGET_MADV_DONTNEED 4 /* dont need these pages */ + #define TARGET_FREEBSD_MAP_RESERVED0080 0x0080 /* previously misimplemented */ /* MAP_INHERIT */ #define TARGET_FREEBSD_MAP_RESERVED0100 0x0100 /* previously unimplemented */ From 83b045ad4e0106836963185ed696991883104359 Mon Sep 17 00:00:00 2001 From: Stacey Son Date: Mon, 25 Sep 2023 21:27:03 +0300 Subject: [PATCH 0205/1077] bsd-user: Implement mincore(2) Signed-off-by: Stacey Son Signed-off-by: Karim Taha Reviewed-by: Richard Henderson Message-Id: <20230925182709.4834-18-kariem.taha2.7@gmail.com> --- bsd-user/bsd-mem.h | 23 +++++++++++++++++++++++ bsd-user/freebsd/os-syscall.c | 4 ++++ 2 files changed, 27 insertions(+) diff --git a/bsd-user/bsd-mem.h b/bsd-user/bsd-mem.h index b00ab3aed8..0c8d96d9a4 100644 --- a/bsd-user/bsd-mem.h +++ b/bsd-user/bsd-mem.h @@ -189,4 +189,27 @@ static inline abi_long do_bsd_minherit(abi_long addr, abi_long len, return get_errno(minherit(g2h_untagged(addr), len, inherit)); } +/* mincore(2) */ +static inline abi_long do_bsd_mincore(abi_ulong target_addr, abi_ulong len, + abi_ulong target_vec) +{ + abi_long ret; + void *p; + abi_ulong vec_len = DIV_ROUND_UP(len, TARGET_PAGE_SIZE); + + if (!guest_range_valid_untagged(target_addr, len) + || !page_check_range(target_addr, len, PAGE_VALID)) { + return -TARGET_EFAULT; + } + + p = lock_user(VERIFY_WRITE, target_vec, vec_len, 0); + if (p == NULL) { + return -TARGET_EFAULT; + } + ret = get_errno(mincore(g2h_untagged(target_addr), len, p)); + unlock_user(p, target_vec, vec_len); + + return ret; +} + #endif /* BSD_USER_BSD_MEM_H */ diff --git a/bsd-user/freebsd/os-syscall.c b/bsd-user/freebsd/os-syscall.c index b8c44cea0f..f054241cd6 100644 --- a/bsd-user/freebsd/os-syscall.c +++ b/bsd-user/freebsd/os-syscall.c @@ -839,6 +839,10 @@ static abi_long freebsd_syscall(void *cpu_env, int num, abi_long arg1, ret = do_bsd_minherit(arg1, arg2, arg3); break; + case TARGET_FREEBSD_NR_mincore: /* mincore(2) */ + ret = do_bsd_mincore(arg1, arg2, arg3); + break; + #if defined(__FreeBSD_version) && __FreeBSD_version >= 1300048 case TARGET_FREEBSD_NR_shm_open2: /* shm_open2(2) */ ret = do_freebsd_shm_open2(arg1, arg2, arg3, arg4, arg5); From a99d74034754b1d8735d814cf17db6bf0eb4bfd1 Mon Sep 17 00:00:00 2001 From: Stacey Son Date: Mon, 25 Sep 2023 21:27:04 +0300 Subject: [PATCH 0206/1077] bsd-user: Implement do_obreak function Match linux-user, by manually applying the following commits, in order: d28b3c90cfad1a7e211ae2bce36ecb9071086129 linux-user: Make sure initial brk(0) is page-aligned 15ad98536ad9410fb32ddf1ff09389b677643faa linux-user: Fix qemu brk() to not zero bytes on current page dfe49864afb06e7e452a4366051697bc4fcfc1a5 linux-user: Prohibit brk() to to shrink below initial heap address eac78a4b0b7da4de2c0a297f4d528ca9cc6256a3 linux-user: Fix signed math overflow in brk() syscall c6cc059eca18d9f6e4e26bb8b6d1135ddb35d81a linux-user: Do not call get_errno() in do_brk() e69e032d1a8ee8d754ca119009a3c2c997f8bb30 linux-user: Use MAP_FIXED_NOREPLACE for do_brk() cb9d5d1fda0bc2312fc0c779b4ea1d7bf826f31f linux-user: Do nothing if too small brk is specified 2aea137a425a87b930a33590177b04368fd7cc12 linux-user: Do not align brk with host page size Signed-off-by: Stacey Son Signed-off-by: Karim Taha Reviewed-by: Richard Henderson Message-Id: <20230925182709.4834-19-kariem.taha2.7@gmail.com> --- bsd-user/bsd-mem.h | 45 +++++++++++++++++++++++++++++++++++ bsd-user/freebsd/os-syscall.c | 7 ++++++ 2 files changed, 52 insertions(+) diff --git a/bsd-user/bsd-mem.h b/bsd-user/bsd-mem.h index 0c8d96d9a4..b296c5c6f0 100644 --- a/bsd-user/bsd-mem.h +++ b/bsd-user/bsd-mem.h @@ -212,4 +212,49 @@ static inline abi_long do_bsd_mincore(abi_ulong target_addr, abi_ulong len, return ret; } +/* do_brk() must return target values and target errnos. */ +static inline abi_long do_obreak(abi_ulong brk_val) +{ + abi_long mapped_addr; + abi_ulong new_brk; + abi_ulong old_brk; + + /* brk pointers are always untagged */ + + /* do not allow to shrink below initial brk value */ + if (brk_val < initial_target_brk) { + return target_brk; + } + + new_brk = TARGET_PAGE_ALIGN(brk_val); + old_brk = TARGET_PAGE_ALIGN(target_brk); + + /* new and old target_brk might be on the same page */ + if (new_brk == old_brk) { + target_brk = brk_val; + return target_brk; + } + + /* Release heap if necesary */ + if (new_brk < old_brk) { + target_munmap(new_brk, old_brk - new_brk); + + target_brk = brk_val; + return target_brk; + } + + mapped_addr = target_mmap(old_brk, new_brk - old_brk, + PROT_READ | PROT_WRITE, + MAP_FIXED | MAP_EXCL | MAP_ANON | MAP_PRIVATE, + -1, 0); + + if (mapped_addr == old_brk) { + target_brk = brk_val; + return target_brk; + } + + /* For everything else, return the previous break. */ + return target_brk; +} + #endif /* BSD_USER_BSD_MEM_H */ diff --git a/bsd-user/freebsd/os-syscall.c b/bsd-user/freebsd/os-syscall.c index f054241cd6..92793ab1fb 100644 --- a/bsd-user/freebsd/os-syscall.c +++ b/bsd-user/freebsd/os-syscall.c @@ -855,6 +855,13 @@ static abi_long freebsd_syscall(void *cpu_env, int num, abi_long arg1, break; #endif + /* + * Misc + */ + case TARGET_FREEBSD_NR_break: + ret = do_obreak(arg1); + break; + /* * sys{ctl, arch, call} */ From 4f0be683e399e7685608b83240da099ea45d84e6 Mon Sep 17 00:00:00 2001 From: Stacey Son Date: Mon, 25 Sep 2023 21:27:05 +0300 Subject: [PATCH 0207/1077] bsd-user: Implement shm_open(2) Co-authored-by: Kyle Evans Signed-off-by: Stacey Son Signed-off-by: Kyle Evans Signed-off-by: Karim Taha Reviewed-by: Richard Henderson Message-Id: <20230925182709.4834-20-kariem.taha2.7@gmail.com> --- bsd-user/bsd-mem.h | 25 +++++++++++++++++++++++++ bsd-user/freebsd/os-syscall.c | 4 ++++ 2 files changed, 29 insertions(+) diff --git a/bsd-user/bsd-mem.h b/bsd-user/bsd-mem.h index b296c5c6f0..f8dc943c23 100644 --- a/bsd-user/bsd-mem.h +++ b/bsd-user/bsd-mem.h @@ -257,4 +257,29 @@ static inline abi_long do_obreak(abi_ulong brk_val) return target_brk; } +/* shm_open(2) */ +static inline abi_long do_bsd_shm_open(abi_ulong arg1, abi_long arg2, + abi_long arg3) +{ + int ret; + void *p; + + if (arg1 == (uintptr_t)SHM_ANON) { + p = SHM_ANON; + } else { + p = lock_user_string(arg1); + if (p == NULL) { + return -TARGET_EFAULT; + } + } + ret = get_errno(shm_open(p, target_to_host_bitmask(arg2, fcntl_flags_tbl), + arg3)); + + if (p != SHM_ANON) { + unlock_user(p, arg1, 0); + } + + return ret; +} + #endif /* BSD_USER_BSD_MEM_H */ diff --git a/bsd-user/freebsd/os-syscall.c b/bsd-user/freebsd/os-syscall.c index 92793ab1fb..0d4c3118f0 100644 --- a/bsd-user/freebsd/os-syscall.c +++ b/bsd-user/freebsd/os-syscall.c @@ -843,6 +843,10 @@ static abi_long freebsd_syscall(void *cpu_env, int num, abi_long arg1, ret = do_bsd_mincore(arg1, arg2, arg3); break; + case TARGET_FREEBSD_NR_freebsd12_shm_open: /* shm_open(2) */ + ret = do_bsd_shm_open(arg1, arg2, arg3); + break; + #if defined(__FreeBSD_version) && __FreeBSD_version >= 1300048 case TARGET_FREEBSD_NR_shm_open2: /* shm_open2(2) */ ret = do_freebsd_shm_open2(arg1, arg2, arg3, arg4, arg5); From 9d14db15b121c81a008098c46053d98cd6a0da6b Mon Sep 17 00:00:00 2001 From: Stacey Son Date: Mon, 25 Sep 2023 21:27:06 +0300 Subject: [PATCH 0208/1077] bsd-user: Implement shm_unlink(2) and shmget(2) Signed-off-by: Stacey Son Signed-off-by: Karim Taha Reviewed-by: Warner Losh Reviewed-by: Richard Henderson Message-Id: <20230925182709.4834-21-kariem.taha2.7@gmail.com> --- bsd-user/bsd-mem.h | 23 +++++++++++++++++++++++ bsd-user/freebsd/os-syscall.c | 8 ++++++++ 2 files changed, 31 insertions(+) diff --git a/bsd-user/bsd-mem.h b/bsd-user/bsd-mem.h index f8dc943c23..c362cc07a3 100644 --- a/bsd-user/bsd-mem.h +++ b/bsd-user/bsd-mem.h @@ -282,4 +282,27 @@ static inline abi_long do_bsd_shm_open(abi_ulong arg1, abi_long arg2, return ret; } +/* shm_unlink(2) */ +static inline abi_long do_bsd_shm_unlink(abi_ulong arg1) +{ + int ret; + void *p; + + p = lock_user_string(arg1); + if (p == NULL) { + return -TARGET_EFAULT; + } + ret = get_errno(shm_unlink(p)); /* XXX path(p)? */ + unlock_user(p, arg1, 0); + + return ret; +} + +/* shmget(2) */ +static inline abi_long do_bsd_shmget(abi_long arg1, abi_ulong arg2, + abi_long arg3) +{ + return get_errno(shmget(arg1, arg2, arg3)); +} + #endif /* BSD_USER_BSD_MEM_H */ diff --git a/bsd-user/freebsd/os-syscall.c b/bsd-user/freebsd/os-syscall.c index 0d4c3118f0..4f67677eb9 100644 --- a/bsd-user/freebsd/os-syscall.c +++ b/bsd-user/freebsd/os-syscall.c @@ -859,6 +859,14 @@ static abi_long freebsd_syscall(void *cpu_env, int num, abi_long arg1, break; #endif + case TARGET_FREEBSD_NR_shm_unlink: /* shm_unlink(2) */ + ret = do_bsd_shm_unlink(arg1); + break; + + case TARGET_FREEBSD_NR_shmget: /* shmget(2) */ + ret = do_bsd_shmget(arg1, arg2, arg3); + break; + /* * Misc */ From f9bbe3cf28ae7157724a364da6f4a7231f2fdfb3 Mon Sep 17 00:00:00 2001 From: Stacey Son Date: Mon, 25 Sep 2023 21:27:07 +0300 Subject: [PATCH 0209/1077] bsd-user: Implement shmctl(2) Signed-off-by: Stacey Son Signed-off-by: Karim Taha Reviewed-by: Richard Henderson Message-Id: <20230925182709.4834-22-kariem.taha2.7@gmail.com> --- bsd-user/bsd-mem.h | 39 +++++++++++++++++++++++++++++++++++ bsd-user/freebsd/os-syscall.c | 4 ++++ 2 files changed, 43 insertions(+) diff --git a/bsd-user/bsd-mem.h b/bsd-user/bsd-mem.h index c362cc07a3..b82f3eaa25 100644 --- a/bsd-user/bsd-mem.h +++ b/bsd-user/bsd-mem.h @@ -305,4 +305,43 @@ static inline abi_long do_bsd_shmget(abi_long arg1, abi_ulong arg2, return get_errno(shmget(arg1, arg2, arg3)); } +/* shmctl(2) */ +static inline abi_long do_bsd_shmctl(abi_long shmid, abi_long cmd, + abi_ulong buff) +{ + struct shmid_ds dsarg; + abi_long ret = -TARGET_EINVAL; + + cmd &= 0xff; + + switch (cmd) { + case IPC_STAT: + if (target_to_host_shmid_ds(&dsarg, buff)) { + return -TARGET_EFAULT; + } + ret = get_errno(shmctl(shmid, cmd, &dsarg)); + if (host_to_target_shmid_ds(buff, &dsarg)) { + return -TARGET_EFAULT; + } + break; + + case IPC_SET: + if (target_to_host_shmid_ds(&dsarg, buff)) { + return -TARGET_EFAULT; + } + ret = get_errno(shmctl(shmid, cmd, &dsarg)); + break; + + case IPC_RMID: + ret = get_errno(shmctl(shmid, cmd, NULL)); + break; + + default: + ret = -TARGET_EINVAL; + break; + } + + return ret; +} + #endif /* BSD_USER_BSD_MEM_H */ diff --git a/bsd-user/freebsd/os-syscall.c b/bsd-user/freebsd/os-syscall.c index 4f67677eb9..0512d41db7 100644 --- a/bsd-user/freebsd/os-syscall.c +++ b/bsd-user/freebsd/os-syscall.c @@ -867,6 +867,10 @@ static abi_long freebsd_syscall(void *cpu_env, int num, abi_long arg1, ret = do_bsd_shmget(arg1, arg2, arg3); break; + case TARGET_FREEBSD_NR_shmctl: /* shmctl(2) */ + ret = do_bsd_shmctl(arg1, arg2, arg3); + break; + /* * Misc */ From 4e00b7d85d0dcc2064c68168163d3a411e32798f Mon Sep 17 00:00:00 2001 From: Stacey Son Date: Mon, 25 Sep 2023 21:27:08 +0300 Subject: [PATCH 0210/1077] bsd-user: Implement shmat(2) and shmdt(2) Use `WITH_MMAP_LOCK_GUARD` instead of mmap_lock() and mmap_unlock(), to match linux-user implementation, according to the following commits: 69fa2708a216df715ba5102a0f98468b540a464e linux-user: Use WITH_MMAP_LOCK_GUARD in target_{shmat,shmdt} ceda5688b650646248f269a992c06b11148c5759 linux-user: Fix shmdt Signed-off-by: Stacey Son Signed-off-by: Karim Taha Message-Id: <20230925182709.4834-23-kariem.taha2.7@gmail.com> --- bsd-user/bsd-mem.h | 87 +++++++++++++++++++++++++++++++++++ bsd-user/freebsd/os-syscall.c | 8 ++++ bsd-user/mmap.c | 2 +- bsd-user/qemu.h | 1 + 4 files changed, 97 insertions(+), 1 deletion(-) diff --git a/bsd-user/bsd-mem.h b/bsd-user/bsd-mem.h index b82f3eaa25..c512a4e375 100644 --- a/bsd-user/bsd-mem.h +++ b/bsd-user/bsd-mem.h @@ -344,4 +344,91 @@ static inline abi_long do_bsd_shmctl(abi_long shmid, abi_long cmd, return ret; } +/* shmat(2) */ +static inline abi_long do_bsd_shmat(int shmid, abi_ulong shmaddr, int shmflg) +{ + abi_ulong raddr; + abi_long ret; + struct shmid_ds shm_info; + + /* Find out the length of the shared memory segment. */ + ret = get_errno(shmctl(shmid, IPC_STAT, &shm_info)); + if (is_error(ret)) { + /* Can't get the length */ + return ret; + } + + if (!guest_range_valid_untagged(shmaddr, shm_info.shm_segsz)) { + return -TARGET_EINVAL; + } + + WITH_MMAP_LOCK_GUARD() { + void *host_raddr; + + if (shmaddr) { + host_raddr = shmat(shmid, (void *)g2h_untagged(shmaddr), shmflg); + } else { + abi_ulong mmap_start; + + mmap_start = mmap_find_vma(0, shm_info.shm_segsz); + + if (mmap_start == -1) { + return -TARGET_ENOMEM; + } + host_raddr = shmat(shmid, g2h_untagged(mmap_start), + shmflg | SHM_REMAP); + } + + if (host_raddr == (void *)-1) { + return get_errno(-1); + } + raddr = h2g(host_raddr); + + page_set_flags(raddr, raddr + shm_info.shm_segsz - 1, + PAGE_VALID | PAGE_RESET | PAGE_READ | + (shmflg & SHM_RDONLY ? 0 : PAGE_WRITE)); + + for (int i = 0; i < N_BSD_SHM_REGIONS; i++) { + if (bsd_shm_regions[i].start == 0) { + bsd_shm_regions[i].start = raddr; + bsd_shm_regions[i].size = shm_info.shm_segsz; + break; + } + } + } + + return raddr; +} + +/* shmdt(2) */ +static inline abi_long do_bsd_shmdt(abi_ulong shmaddr) +{ + abi_long ret; + + WITH_MMAP_LOCK_GUARD() { + int i; + + for (i = 0; i < N_BSD_SHM_REGIONS; ++i) { + if (bsd_shm_regions[i].start == shmaddr) { + break; + } + } + + if (i == N_BSD_SHM_REGIONS) { + return -TARGET_EINVAL; + } + + ret = get_errno(shmdt(g2h_untagged(shmaddr))); + if (ret == 0) { + abi_ulong size = bsd_shm_regions[i].size; + + bsd_shm_regions[i].start = 0; + page_set_flags(shmaddr, shmaddr + size - 1, 0); + mmap_reserve(shmaddr, size); + } + } + + return ret; +} + #endif /* BSD_USER_BSD_MEM_H */ diff --git a/bsd-user/freebsd/os-syscall.c b/bsd-user/freebsd/os-syscall.c index 0512d41db7..39e66312da 100644 --- a/bsd-user/freebsd/os-syscall.c +++ b/bsd-user/freebsd/os-syscall.c @@ -871,6 +871,14 @@ static abi_long freebsd_syscall(void *cpu_env, int num, abi_long arg1, ret = do_bsd_shmctl(arg1, arg2, arg3); break; + case TARGET_FREEBSD_NR_shmat: /* shmat(2) */ + ret = do_bsd_shmat(arg1, arg2, arg3); + break; + + case TARGET_FREEBSD_NR_shmdt: /* shmdt(2) */ + ret = do_bsd_shmdt(arg1); + break; + /* * Misc */ diff --git a/bsd-user/mmap.c b/bsd-user/mmap.c index 8e148a2ea3..3ef11b2807 100644 --- a/bsd-user/mmap.c +++ b/bsd-user/mmap.c @@ -636,7 +636,7 @@ fail: return -1; } -static void mmap_reserve(abi_ulong start, abi_ulong size) +void mmap_reserve(abi_ulong start, abi_ulong size) { abi_ulong real_start; abi_ulong real_end; diff --git a/bsd-user/qemu.h b/bsd-user/qemu.h index 6047805ae3..dc842fffa7 100644 --- a/bsd-user/qemu.h +++ b/bsd-user/qemu.h @@ -233,6 +233,7 @@ abi_long target_mremap(abi_ulong old_addr, abi_ulong old_size, int target_msync(abi_ulong start, abi_ulong len, int flags); extern abi_ulong mmap_next_start; abi_ulong mmap_find_vma(abi_ulong start, abi_ulong size); +void mmap_reserve(abi_ulong start, abi_ulong size); void TSA_NO_TSA mmap_fork_start(void); void TSA_NO_TSA mmap_fork_end(int child); From dfa1d915756b2d9d22946cbd7d2587f30cdcb7a3 Mon Sep 17 00:00:00 2001 From: Warner Losh Date: Mon, 25 Sep 2023 21:27:09 +0300 Subject: [PATCH 0211/1077] bsd-user: Add stubs for vadvise(), sbrk() and sstk() The above system calls are not supported by qemu. Signed-off-by: Warner Losh Signed-off-by: Karim Taha Reviewed-by: Richard Henderson Message-Id: <20230925182709.4834-24-kariem.taha2.7@gmail.com> --- bsd-user/bsd-mem.h | 18 ++++++++++++++++++ bsd-user/freebsd/os-syscall.c | 12 ++++++++++++ 2 files changed, 30 insertions(+) diff --git a/bsd-user/bsd-mem.h b/bsd-user/bsd-mem.h index c512a4e375..c3e72e3b86 100644 --- a/bsd-user/bsd-mem.h +++ b/bsd-user/bsd-mem.h @@ -431,4 +431,22 @@ static inline abi_long do_bsd_shmdt(abi_ulong shmaddr) return ret; } +static inline abi_long do_bsd_vadvise(void) +{ + /* See sys_ovadvise() in vm_unix.c */ + return -TARGET_EINVAL; +} + +static inline abi_long do_bsd_sbrk(void) +{ + /* see sys_sbrk() in vm_mmap.c */ + return -TARGET_EOPNOTSUPP; +} + +static inline abi_long do_bsd_sstk(void) +{ + /* see sys_sstk() in vm_mmap.c */ + return -TARGET_EOPNOTSUPP; +} + #endif /* BSD_USER_BSD_MEM_H */ diff --git a/bsd-user/freebsd/os-syscall.c b/bsd-user/freebsd/os-syscall.c index 39e66312da..ca2f6fdb66 100644 --- a/bsd-user/freebsd/os-syscall.c +++ b/bsd-user/freebsd/os-syscall.c @@ -879,6 +879,18 @@ static abi_long freebsd_syscall(void *cpu_env, int num, abi_long arg1, ret = do_bsd_shmdt(arg1); break; + case TARGET_FREEBSD_NR_freebsd11_vadvise: + ret = do_bsd_vadvise(); + break; + + case TARGET_FREEBSD_NR_sbrk: + ret = do_bsd_sbrk(); + break; + + case TARGET_FREEBSD_NR_sstk: + ret = do_bsd_sstk(); + break; + /* * Misc */ From 4565917bb034479a29c04f0b44124e7f61585ccf Mon Sep 17 00:00:00 2001 From: "Michael S. Tsirkin" Date: Tue, 29 Aug 2023 16:14:29 -0400 Subject: [PATCH 0212/1077] pci: SLT must be RO current code sets PCI_SEC_LATENCY_TIMER to RW, but for pcie to pcie bridges it must be RO 0 according to pci express spec which says: This register does not apply to PCI Express. It must be read-only and hardwired to 00h. For PCI Express to PCI/PCI-X Bridges, refer to the [PCIe-to-PCI-PCI-X-Bridge] for requirements for this register. also, fix typo in comment where it's made writeable - this typo is likely what prevented us noticing we violate this requirement in the 1st place. Reported-by: Marcin Juszkiewicz Message-Id: Tested-by: Marcin Juszkiewicz Signed-off-by: Michael S. Tsirkin --- hw/core/machine.c | 5 ++++- hw/pci/pci.c | 2 +- hw/pci/pci_bridge.c | 14 ++++++++++++++ include/hw/pci/pci_bridge.h | 3 +++ 4 files changed, 22 insertions(+), 2 deletions(-) diff --git a/hw/core/machine.c b/hw/core/machine.c index cb38b8cf4c..9ae8f793ae 100644 --- a/hw/core/machine.c +++ b/hw/core/machine.c @@ -32,6 +32,7 @@ #include "qemu/error-report.h" #include "sysemu/qtest.h" #include "hw/pci/pci.h" +#include "hw/pci/pci_bridge.h" #include "hw/mem/nvdimm.h" #include "migration/global_state.h" #include "migration/vmstate.h" @@ -40,7 +41,9 @@ #include "hw/virtio/virtio-pci.h" #include "hw/virtio/virtio-net.h" -GlobalProperty hw_compat_8_1[] = {}; +GlobalProperty hw_compat_8_1[] = { + { TYPE_PCI_BRIDGE, "x-pci-express-writeable-slt-bug", "true" }, +}; const size_t hw_compat_8_1_len = G_N_ELEMENTS(hw_compat_8_1); GlobalProperty hw_compat_8_0[] = { diff --git a/hw/pci/pci.c b/hw/pci/pci.c index 881d774fb6..b0d21bf43a 100644 --- a/hw/pci/pci.c +++ b/hw/pci/pci.c @@ -893,7 +893,7 @@ static void pci_init_w1cmask(PCIDevice *dev) static void pci_init_mask_bridge(PCIDevice *d) { /* PCI_PRIMARY_BUS, PCI_SECONDARY_BUS, PCI_SUBORDINATE_BUS and - PCI_SEC_LETENCY_TIMER */ + PCI_SEC_LATENCY_TIMER */ memset(d->wmask + PCI_PRIMARY_BUS, 0xff, 4); /* base and limit */ diff --git a/hw/pci/pci_bridge.c b/hw/pci/pci_bridge.c index e7b9345615..6a4e38856d 100644 --- a/hw/pci/pci_bridge.c +++ b/hw/pci/pci_bridge.c @@ -38,6 +38,7 @@ #include "qapi/error.h" #include "hw/acpi/acpi_aml_interface.h" #include "hw/acpi/pci.h" +#include "hw/qdev-properties.h" /* PCI bridge subsystem vendor ID helper functions */ #define PCI_SSVID_SIZEOF 8 @@ -385,6 +386,11 @@ void pci_bridge_initfn(PCIDevice *dev, const char *typename) pci_bridge_region_init(br); QLIST_INIT(&sec_bus->child); QLIST_INSERT_HEAD(&parent->child, sec_bus, sibling); + + /* For express secondary buses, secondary latency timer is RO 0 */ + if (pci_bus_is_express(sec_bus) && !br->pcie_writeable_slt_bug) { + dev->wmask[PCI_SEC_LATENCY_TIMER] = 0; + } } /* default qdev clean up function for PCI-to-PCI bridge */ @@ -466,10 +472,18 @@ int pci_bridge_qemu_reserve_cap_init(PCIDevice *dev, int cap_offset, return 0; } +static Property pci_bridge_properties[] = { + DEFINE_PROP_BOOL("x-pci-express-writeable-slt-bug", PCIBridge, + pcie_writeable_slt_bug, false), + DEFINE_PROP_END_OF_LIST(), +}; + static void pci_bridge_class_init(ObjectClass *klass, void *data) { AcpiDevAmlIfClass *adevc = ACPI_DEV_AML_IF_CLASS(klass); + DeviceClass *k = DEVICE_CLASS(klass); + device_class_set_props(k, pci_bridge_properties); adevc->build_dev_aml = build_pci_bridge_aml; } diff --git a/include/hw/pci/pci_bridge.h b/include/hw/pci/pci_bridge.h index ea54a81a15..5cd452115a 100644 --- a/include/hw/pci/pci_bridge.h +++ b/include/hw/pci/pci_bridge.h @@ -77,6 +77,9 @@ struct PCIBridge { pci_map_irq_fn map_irq; const char *bus_name; + + /* SLT is RO for PCIE to PCIE bridges, but old QEMU versions had it RW */ + bool pcie_writeable_slt_bug; }; #define PCI_BRIDGE_DEV_PROP_CHASSIS_NR "chassis_nr" From 961d60e934e793a6065fb17d2312d5bced25031e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Mon, 10 Jul 2023 11:49:26 +0200 Subject: [PATCH 0213/1077] hw/virtio: Propagate page_mask to vhost_vdpa_listener_skipped_section() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In order to make vhost-vdpa.c a target-agnostic source unit, we need to remove the TARGET_PAGE_SIZE / TARGET_PAGE_MASK / TARGET_PAGE_ALIGN uses. TARGET_PAGE_SIZE will be replaced by the runtime qemu_target_page_size(). The other ones will be deduced from TARGET_PAGE_SIZE. Since the 3 macros are used in 3 related functions (sharing the same call tree), we'll refactor them to only depend on TARGET_PAGE_MASK. Having the following call tree: vhost_vdpa_listener_region_del() -> vhost_vdpa_listener_skipped_section() -> vhost_vdpa_section_end() The first step is to propagate TARGET_PAGE_MASK to vhost_vdpa_listener_skipped_section(). Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Richard Henderson Message-Id: <20230710094931.84402-2-philmd@linaro.org> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/virtio/vhost-vdpa.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/hw/virtio/vhost-vdpa.c b/hw/virtio/vhost-vdpa.c index 42f2a4bae9..118c588205 100644 --- a/hw/virtio/vhost-vdpa.c +++ b/hw/virtio/vhost-vdpa.c @@ -42,7 +42,8 @@ static Int128 vhost_vdpa_section_end(const MemoryRegionSection *section) static bool vhost_vdpa_listener_skipped_section(MemoryRegionSection *section, uint64_t iova_min, - uint64_t iova_max) + uint64_t iova_max, + int page_mask) { Int128 llend; @@ -313,7 +314,7 @@ static void vhost_vdpa_listener_region_add(MemoryListener *listener, int ret; if (vhost_vdpa_listener_skipped_section(section, v->iova_range.first, - v->iova_range.last)) { + v->iova_range.last, TARGET_PAGE_MASK)) { return; } if (memory_region_is_iommu(section->mr)) { @@ -398,7 +399,7 @@ static void vhost_vdpa_listener_region_del(MemoryListener *listener, int ret; if (vhost_vdpa_listener_skipped_section(section, v->iova_range.first, - v->iova_range.last)) { + v->iova_range.last, TARGET_PAGE_MASK)) { return; } if (memory_region_is_iommu(section->mr)) { From 8b1a8884c6aacd9a35863d18a757be17ec7b1369 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Mon, 10 Jul 2023 11:49:27 +0200 Subject: [PATCH 0214/1077] hw/virtio: Propagate page_mask to vhost_vdpa_section_end() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Propagate TARGET_PAGE_MASK (see the previous commit for rationale). Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Richard Henderson Message-Id: <20230710094931.84402-3-philmd@linaro.org> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/virtio/vhost-vdpa.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/hw/virtio/vhost-vdpa.c b/hw/virtio/vhost-vdpa.c index 118c588205..3ab0dc0b5b 100644 --- a/hw/virtio/vhost-vdpa.c +++ b/hw/virtio/vhost-vdpa.c @@ -31,11 +31,12 @@ * Return one past the end of the end of section. Be careful with uint64_t * conversions! */ -static Int128 vhost_vdpa_section_end(const MemoryRegionSection *section) +static Int128 vhost_vdpa_section_end(const MemoryRegionSection *section, + int page_mask) { Int128 llend = int128_make64(section->offset_within_address_space); llend = int128_add(llend, section->size); - llend = int128_and(llend, int128_exts64(TARGET_PAGE_MASK)); + llend = int128_and(llend, int128_exts64(page_mask)); return llend; } @@ -69,7 +70,7 @@ static bool vhost_vdpa_listener_skipped_section(MemoryRegionSection *section, */ if (!memory_region_is_iommu(section->mr)) { - llend = vhost_vdpa_section_end(section); + llend = vhost_vdpa_section_end(section, page_mask); if (int128_gt(llend, int128_make64(iova_max))) { error_report("RAM section out of device range (max=0x%" PRIx64 ", end addr=0x%" PRIx64 ")", @@ -331,7 +332,7 @@ static void vhost_vdpa_listener_region_add(MemoryListener *listener, } iova = TARGET_PAGE_ALIGN(section->offset_within_address_space); - llend = vhost_vdpa_section_end(section); + llend = vhost_vdpa_section_end(section, TARGET_PAGE_MASK); if (int128_ge(int128_make64(iova), llend)) { return; } @@ -415,7 +416,7 @@ static void vhost_vdpa_listener_region_del(MemoryListener *listener, } iova = TARGET_PAGE_ALIGN(section->offset_within_address_space); - llend = vhost_vdpa_section_end(section); + llend = vhost_vdpa_section_end(section, TARGET_PAGE_MASK); trace_vhost_vdpa_listener_region_del(v, iova, int128_get64(int128_sub(llend, int128_one()))); From 1dca36fb3d4f07354c9f6bc38b6e5c72fe1e9855 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Mon, 10 Jul 2023 11:49:28 +0200 Subject: [PATCH 0215/1077] hw/virtio/vhost-vdpa: Inline TARGET_PAGE_ALIGN() macro MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use TARGET_PAGE_SIZE to calculate TARGET_PAGE_ALIGN (see the rationale in previous commits). Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Richard Henderson Message-Id: <20230710094931.84402-4-philmd@linaro.org> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/virtio/vhost-vdpa.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/hw/virtio/vhost-vdpa.c b/hw/virtio/vhost-vdpa.c index 3ab0dc0b5b..0e0ed6d7ac 100644 --- a/hw/virtio/vhost-vdpa.c +++ b/hw/virtio/vhost-vdpa.c @@ -331,7 +331,7 @@ static void vhost_vdpa_listener_region_add(MemoryListener *listener, return; } - iova = TARGET_PAGE_ALIGN(section->offset_within_address_space); + iova = ROUND_UP(section->offset_within_address_space, TARGET_PAGE_SIZE); llend = vhost_vdpa_section_end(section, TARGET_PAGE_MASK); if (int128_ge(int128_make64(iova), llend)) { return; @@ -415,7 +415,7 @@ static void vhost_vdpa_listener_region_del(MemoryListener *listener, return; } - iova = TARGET_PAGE_ALIGN(section->offset_within_address_space); + iova = ROUND_UP(section->offset_within_address_space, TARGET_PAGE_SIZE); llend = vhost_vdpa_section_end(section, TARGET_PAGE_MASK); trace_vhost_vdpa_listener_region_del(v, iova, From 33f21860b766701f92c01094dcfc5390974d4020 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Mon, 10 Jul 2023 11:49:29 +0200 Subject: [PATCH 0216/1077] hw/virtio/vhost-vdpa: Use target-agnostic qemu_target_page_mask() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Similarly to commit e414ed2c47 ("virtio-iommu: Use target-agnostic qemu_target_page_mask"), Replace the target-specific TARGET_PAGE_SIZE and TARGET_PAGE_MASK definitions by a call to the runtime qemu_target_page_size() helper which is target agnostic. Signed-off-by: Philippe Mathieu-Daudé Message-Id: <20230710094931.84402-5-philmd@linaro.org> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/virtio/vhost-vdpa.c | 34 +++++++++++++++++++--------------- 1 file changed, 19 insertions(+), 15 deletions(-) diff --git a/hw/virtio/vhost-vdpa.c b/hw/virtio/vhost-vdpa.c index 0e0ed6d7ac..50b932a930 100644 --- a/hw/virtio/vhost-vdpa.c +++ b/hw/virtio/vhost-vdpa.c @@ -14,6 +14,7 @@ #include #include #include +#include "exec/target_page.h" #include "hw/virtio/vhost.h" #include "hw/virtio/vhost-backend.h" #include "hw/virtio/virtio-net.h" @@ -23,7 +24,6 @@ #include "migration/blocker.h" #include "qemu/cutils.h" #include "qemu/main-loop.h" -#include "cpu.h" #include "trace.h" #include "qapi/error.h" @@ -313,9 +313,11 @@ static void vhost_vdpa_listener_region_add(MemoryListener *listener, Int128 llend, llsize; void *vaddr; int ret; + int page_size = qemu_target_page_size(); + int page_mask = -page_size; if (vhost_vdpa_listener_skipped_section(section, v->iova_range.first, - v->iova_range.last, TARGET_PAGE_MASK)) { + v->iova_range.last, page_mask)) { return; } if (memory_region_is_iommu(section->mr)) { @@ -323,16 +325,16 @@ static void vhost_vdpa_listener_region_add(MemoryListener *listener, return; } - if (unlikely((section->offset_within_address_space & ~TARGET_PAGE_MASK) != - (section->offset_within_region & ~TARGET_PAGE_MASK))) { + if (unlikely((section->offset_within_address_space & ~page_mask) != + (section->offset_within_region & ~page_mask))) { trace_vhost_vdpa_listener_region_add_unaligned(v, section->mr->name, - section->offset_within_address_space & ~TARGET_PAGE_MASK, - section->offset_within_region & ~TARGET_PAGE_MASK); + section->offset_within_address_space & ~page_mask, + section->offset_within_region & ~page_mask); return; } - iova = ROUND_UP(section->offset_within_address_space, TARGET_PAGE_SIZE); - llend = vhost_vdpa_section_end(section, TARGET_PAGE_MASK); + iova = ROUND_UP(section->offset_within_address_space, page_size); + llend = vhost_vdpa_section_end(section, page_mask); if (int128_ge(int128_make64(iova), llend)) { return; } @@ -398,25 +400,27 @@ static void vhost_vdpa_listener_region_del(MemoryListener *listener, hwaddr iova; Int128 llend, llsize; int ret; + int page_size = qemu_target_page_size(); + int page_mask = -page_size; if (vhost_vdpa_listener_skipped_section(section, v->iova_range.first, - v->iova_range.last, TARGET_PAGE_MASK)) { + v->iova_range.last, page_mask)) { return; } if (memory_region_is_iommu(section->mr)) { vhost_vdpa_iommu_region_del(listener, section); } - if (unlikely((section->offset_within_address_space & ~TARGET_PAGE_MASK) != - (section->offset_within_region & ~TARGET_PAGE_MASK))) { + if (unlikely((section->offset_within_address_space & ~page_mask) != + (section->offset_within_region & ~page_mask))) { trace_vhost_vdpa_listener_region_del_unaligned(v, section->mr->name, - section->offset_within_address_space & ~TARGET_PAGE_MASK, - section->offset_within_region & ~TARGET_PAGE_MASK); + section->offset_within_address_space & ~page_mask, + section->offset_within_region & ~page_mask); return; } - iova = ROUND_UP(section->offset_within_address_space, TARGET_PAGE_SIZE); - llend = vhost_vdpa_section_end(section, TARGET_PAGE_MASK); + iova = ROUND_UP(section->offset_within_address_space, page_size); + llend = vhost_vdpa_section_end(section, page_mask); trace_vhost_vdpa_listener_region_del(v, iova, int128_get64(int128_sub(llend, int128_one()))); From 05632635f84311f241ad4dbffdb591f97339a5dc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Mon, 10 Jul 2023 12:04:32 +0200 Subject: [PATCH 0217/1077] hw/virtio: Build vhost-vdpa.o once MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The previous commit removed the dependencies on the target-specific TARGET_PAGE_FOO macros. We can now move vhost-vdpa.c to the 'softmmu_virtio_ss' source set to build it once for all our targets. Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Richard Henderson Message-Id: <20230710100432.84819-1-philmd@linaro.org> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/virtio/meson.build | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/hw/virtio/meson.build b/hw/virtio/meson.build index 13e7c6c272..9737450afd 100644 --- a/hw/virtio/meson.build +++ b/hw/virtio/meson.build @@ -18,7 +18,8 @@ if have_vhost specific_virtio_ss.add(files('vhost-user.c')) endif if have_vhost_vdpa - specific_virtio_ss.add(files('vhost-vdpa.c', 'vhost-shadow-virtqueue.c')) + softmmu_virtio_ss.add(files('vhost-vdpa.c')) + specific_virtio_ss.add(files('vhost-shadow-virtqueue.c')) endif else softmmu_virtio_ss.add(files('vhost-stub.c')) From f05356f84d2e3cb4f6437716cc9b5dc59baf769d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Mon, 10 Jul 2023 12:05:10 +0200 Subject: [PATCH 0218/1077] hw/virtio/meson: Rename softmmu_virtio_ss[] -> system_virtio_ss[] MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Similarly to commit de6cd7599b ("meson: Replace softmmu_ss -> system_ss"), rename the virtio source set common to all system emulation as 'system_virtio_ss[]'. This is clearer because softmmu can be used for user emulation. Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Richard Henderson Message-Id: <20230710100510.84862-1-philmd@linaro.org> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/virtio/meson.build | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/hw/virtio/meson.build b/hw/virtio/meson.build index 9737450afd..4e81d10834 100644 --- a/hw/virtio/meson.build +++ b/hw/virtio/meson.build @@ -1,28 +1,28 @@ -softmmu_virtio_ss = ss.source_set() -softmmu_virtio_ss.add(files('virtio-bus.c')) -softmmu_virtio_ss.add(when: 'CONFIG_VIRTIO_PCI', if_true: files('virtio-pci.c')) -softmmu_virtio_ss.add(when: 'CONFIG_VIRTIO_MMIO', if_true: files('virtio-mmio.c')) -softmmu_virtio_ss.add(when: 'CONFIG_VIRTIO_CRYPTO', if_true: files('virtio-crypto.c')) -softmmu_virtio_ss.add(when: 'CONFIG_VHOST_VSOCK_COMMON', if_true: files('vhost-vsock-common.c')) -softmmu_virtio_ss.add(when: 'CONFIG_VIRTIO_IOMMU', if_true: files('virtio-iommu.c')) -softmmu_virtio_ss.add(when: 'CONFIG_VHOST_VDPA_DEV', if_true: files('vdpa-dev.c')) +system_virtio_ss = ss.source_set() +system_virtio_ss.add(files('virtio-bus.c')) +system_virtio_ss.add(when: 'CONFIG_VIRTIO_PCI', if_true: files('virtio-pci.c')) +system_virtio_ss.add(when: 'CONFIG_VIRTIO_MMIO', if_true: files('virtio-mmio.c')) +system_virtio_ss.add(when: 'CONFIG_VIRTIO_CRYPTO', if_true: files('virtio-crypto.c')) +system_virtio_ss.add(when: 'CONFIG_VHOST_VSOCK_COMMON', if_true: files('vhost-vsock-common.c')) +system_virtio_ss.add(when: 'CONFIG_VIRTIO_IOMMU', if_true: files('virtio-iommu.c')) +system_virtio_ss.add(when: 'CONFIG_VHOST_VDPA_DEV', if_true: files('vdpa-dev.c')) specific_virtio_ss = ss.source_set() specific_virtio_ss.add(files('virtio.c')) specific_virtio_ss.add(files('virtio-config-io.c', 'virtio-qmp.c')) if have_vhost - softmmu_virtio_ss.add(files('vhost.c')) + system_virtio_ss.add(files('vhost.c')) specific_virtio_ss.add(files('vhost-backend.c', 'vhost-iova-tree.c')) if have_vhost_user specific_virtio_ss.add(files('vhost-user.c')) endif if have_vhost_vdpa - softmmu_virtio_ss.add(files('vhost-vdpa.c')) + system_virtio_ss.add(files('vhost-vdpa.c')) specific_virtio_ss.add(files('vhost-shadow-virtqueue.c')) endif else - softmmu_virtio_ss.add(files('vhost-stub.c')) + system_virtio_ss.add(files('vhost-stub.c')) endif specific_virtio_ss.add(when: 'CONFIG_VIRTIO_BALLOON', if_true: files('virtio-balloon.c')) @@ -68,7 +68,7 @@ virtio_pci_ss.add(when: 'CONFIG_VIRTIO_MD', if_true: files('virtio-md-pci.c')) specific_virtio_ss.add_all(when: 'CONFIG_VIRTIO_PCI', if_true: virtio_pci_ss) -system_ss.add_all(when: 'CONFIG_VIRTIO', if_true: softmmu_virtio_ss) +system_ss.add_all(when: 'CONFIG_VIRTIO', if_true: system_virtio_ss) system_ss.add(when: 'CONFIG_VIRTIO', if_false: files('vhost-stub.c')) system_ss.add(when: 'CONFIG_VIRTIO', if_false: files('virtio-stub.c')) system_ss.add(when: 'CONFIG_ALL', if_true: files('vhost-stub.c')) From eee77809733d3a94c0d78a29a93d032c1faefd2c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20Benn=C3=A9e?= Date: Mon, 10 Jul 2023 16:35:09 +0100 Subject: [PATCH 0219/1077] virtio: add vhost-user-base and a generic vhost-user-device MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In theory we shouldn't need to repeat so much boilerplate to support vhost-user backends. This provides a generic vhost-user-base QOM object and a derived vhost-user-device for which the user needs to provide the few bits of information that aren't currently provided by the vhost-user protocol. This should provide a baseline implementation from which the other vhost-user stub can specialise. Signed-off-by: Alex Bennée Message-Id: <20230710153522.3469097-8-alex.bennee@linaro.org> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/virtio/meson.build | 3 + hw/virtio/vhost-user-device-pci.c | 71 ++++++ hw/virtio/vhost-user-device.c | 324 ++++++++++++++++++++++++++ include/hw/virtio/vhost-user-device.h | 45 ++++ 4 files changed, 443 insertions(+) create mode 100644 hw/virtio/vhost-user-device-pci.c create mode 100644 hw/virtio/vhost-user-device.c create mode 100644 include/hw/virtio/vhost-user-device.h diff --git a/hw/virtio/meson.build b/hw/virtio/meson.build index 4e81d10834..c0055a7832 100644 --- a/hw/virtio/meson.build +++ b/hw/virtio/meson.build @@ -15,7 +15,10 @@ if have_vhost system_virtio_ss.add(files('vhost.c')) specific_virtio_ss.add(files('vhost-backend.c', 'vhost-iova-tree.c')) if have_vhost_user + # fixme - this really should be generic specific_virtio_ss.add(files('vhost-user.c')) + system_virtio_ss.add(files('vhost-user-device.c')) + system_virtio_ss.add(when: 'CONFIG_VIRTIO_PCI', if_true: files('vhost-user-device-pci.c')) endif if have_vhost_vdpa system_virtio_ss.add(files('vhost-vdpa.c')) diff --git a/hw/virtio/vhost-user-device-pci.c b/hw/virtio/vhost-user-device-pci.c new file mode 100644 index 0000000000..41f9b7905b --- /dev/null +++ b/hw/virtio/vhost-user-device-pci.c @@ -0,0 +1,71 @@ +/* + * Vhost-user generic virtio device PCI glue + * + * Copyright (c) 2023 Linaro Ltd + * Author: Alex Bennée + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +#include "qemu/osdep.h" +#include "hw/qdev-properties.h" +#include "hw/virtio/vhost-user-device.h" +#include "hw/virtio/virtio-pci.h" + +struct VHostUserDevicePCI { + VirtIOPCIProxy parent_obj; + VHostUserBase vub; +}; + +typedef struct VHostUserDevicePCI VHostUserDevicePCI; + +#define TYPE_VHOST_USER_DEVICE_PCI "vhost-user-device-pci-base" + +DECLARE_INSTANCE_CHECKER(VHostUserDevicePCI, + VHOST_USER_DEVICE_PCI, + TYPE_VHOST_USER_DEVICE_PCI) + +static void vhost_user_device_pci_realize(VirtIOPCIProxy *vpci_dev, Error **errp) +{ + VHostUserDevicePCI *dev = VHOST_USER_DEVICE_PCI(vpci_dev); + DeviceState *vdev = DEVICE(&dev->vub); + + vpci_dev->nvectors = 1; + qdev_realize(vdev, BUS(&vpci_dev->bus), errp); +} + +static void vhost_user_device_pci_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + VirtioPCIClass *k = VIRTIO_PCI_CLASS(klass); + PCIDeviceClass *pcidev_k = PCI_DEVICE_CLASS(klass); + k->realize = vhost_user_device_pci_realize; + set_bit(DEVICE_CATEGORY_INPUT, dc->categories); + pcidev_k->vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET; + pcidev_k->device_id = 0; /* Set by virtio-pci based on virtio id */ + pcidev_k->revision = 0x00; + pcidev_k->class_id = PCI_CLASS_COMMUNICATION_OTHER; +} + +static void vhost_user_device_pci_instance_init(Object *obj) +{ + VHostUserDevicePCI *dev = VHOST_USER_DEVICE_PCI(obj); + + virtio_instance_init_common(obj, &dev->vub, sizeof(dev->vub), + TYPE_VHOST_USER_DEVICE); +} + +static const VirtioPCIDeviceTypeInfo vhost_user_device_pci_info = { + .base_name = TYPE_VHOST_USER_DEVICE_PCI, + .non_transitional_name = "vhost-user-device-pci", + .instance_size = sizeof(VHostUserDevicePCI), + .instance_init = vhost_user_device_pci_instance_init, + .class_init = vhost_user_device_pci_class_init, +}; + +static void vhost_user_device_pci_register(void) +{ + virtio_pci_types_register(&vhost_user_device_pci_info); +} + +type_init(vhost_user_device_pci_register); diff --git a/hw/virtio/vhost-user-device.c b/hw/virtio/vhost-user-device.c new file mode 100644 index 0000000000..b0239fa033 --- /dev/null +++ b/hw/virtio/vhost-user-device.c @@ -0,0 +1,324 @@ +/* + * Generic vhost-user stub. This can be used to connect to any + * vhost-user backend. All configuration details must be handled by + * the vhost-user daemon itself + * + * Copyright (c) 2023 Linaro Ltd + * Author: Alex Bennée + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +#include "qemu/osdep.h" +#include "qapi/error.h" +#include "hw/qdev-properties.h" +#include "hw/virtio/virtio-bus.h" +#include "hw/virtio/vhost-user-device.h" +#include "qemu/error-report.h" + +static void vub_start(VirtIODevice *vdev) +{ + BusState *qbus = BUS(qdev_get_parent_bus(DEVICE(vdev))); + VirtioBusClass *k = VIRTIO_BUS_GET_CLASS(qbus); + VHostUserBase *vub = VHOST_USER_BASE(vdev); + int ret, i; + + if (!k->set_guest_notifiers) { + error_report("binding does not support guest notifiers"); + return; + } + + ret = vhost_dev_enable_notifiers(&vub->vhost_dev, vdev); + if (ret < 0) { + error_report("Error enabling host notifiers: %d", -ret); + return; + } + + ret = k->set_guest_notifiers(qbus->parent, vub->vhost_dev.nvqs, true); + if (ret < 0) { + error_report("Error binding guest notifier: %d", -ret); + goto err_host_notifiers; + } + + vub->vhost_dev.acked_features = vdev->guest_features; + + ret = vhost_dev_start(&vub->vhost_dev, vdev, true); + if (ret < 0) { + error_report("Error starting vhost-user-device: %d", -ret); + goto err_guest_notifiers; + } + + /* + * guest_notifier_mask/pending not used yet, so just unmask + * everything here. virtio-pci will do the right thing by + * enabling/disabling irqfd. + */ + for (i = 0; i < vub->vhost_dev.nvqs; i++) { + vhost_virtqueue_mask(&vub->vhost_dev, vdev, i, false); + } + + return; + +err_guest_notifiers: + k->set_guest_notifiers(qbus->parent, vub->vhost_dev.nvqs, false); +err_host_notifiers: + vhost_dev_disable_notifiers(&vub->vhost_dev, vdev); +} + +static void vub_stop(VirtIODevice *vdev) +{ + VHostUserBase *vub = VHOST_USER_BASE(vdev); + BusState *qbus = BUS(qdev_get_parent_bus(DEVICE(vdev))); + VirtioBusClass *k = VIRTIO_BUS_GET_CLASS(qbus); + int ret; + + if (!k->set_guest_notifiers) { + return; + } + + vhost_dev_stop(&vub->vhost_dev, vdev, true); + + ret = k->set_guest_notifiers(qbus->parent, vub->vhost_dev.nvqs, false); + if (ret < 0) { + error_report("vhost guest notifier cleanup failed: %d", ret); + return; + } + + vhost_dev_disable_notifiers(&vub->vhost_dev, vdev); +} + +static void vub_set_status(VirtIODevice *vdev, uint8_t status) +{ + VHostUserBase *vub = VHOST_USER_BASE(vdev); + bool should_start = virtio_device_should_start(vdev, status); + + if (vhost_dev_is_started(&vub->vhost_dev) == should_start) { + return; + } + + if (should_start) { + vub_start(vdev); + } else { + vub_stop(vdev); + } +} + +/* + * For an implementation where everything is delegated to the backend + * we don't do anything other than return the full feature set offered + * by the daemon (module the reserved feature bit). + */ +static uint64_t vub_get_features(VirtIODevice *vdev, + uint64_t requested_features, Error **errp) +{ + VHostUserBase *vub = VHOST_USER_BASE(vdev); + /* This should be set when the vhost connection initialises */ + g_assert(vub->vhost_dev.features); + return vub->vhost_dev.features & ~(1ULL << VHOST_USER_F_PROTOCOL_FEATURES); +} + +static void vub_handle_output(VirtIODevice *vdev, VirtQueue *vq) +{ + /* + * Not normally called; it's the daemon that handles the queue; + * however virtio's cleanup path can call this. + */ +} + +static void do_vhost_user_cleanup(VirtIODevice *vdev, VHostUserBase *vub) +{ + vhost_user_cleanup(&vub->vhost_user); + + for (int i = 0; i < vub->num_vqs; i++) { + VirtQueue *vq = g_ptr_array_index(vub->vqs, i); + virtio_delete_queue(vq); + } + + virtio_cleanup(vdev); +} + +static int vub_connect(DeviceState *dev) +{ + VirtIODevice *vdev = VIRTIO_DEVICE(dev); + VHostUserBase *vub = VHOST_USER_BASE(vdev); + + if (vub->connected) { + return 0; + } + vub->connected = true; + + /* restore vhost state */ + if (virtio_device_started(vdev, vdev->status)) { + vub_start(vdev); + } + + return 0; +} + +static void vub_disconnect(DeviceState *dev) +{ + VirtIODevice *vdev = VIRTIO_DEVICE(dev); + VHostUserBase *vub = VHOST_USER_BASE(vdev); + + if (!vub->connected) { + return; + } + vub->connected = false; + + if (vhost_dev_is_started(&vub->vhost_dev)) { + vub_stop(vdev); + } +} + +static void vub_event(void *opaque, QEMUChrEvent event) +{ + DeviceState *dev = opaque; + VirtIODevice *vdev = VIRTIO_DEVICE(dev); + VHostUserBase *vub = VHOST_USER_BASE(vdev); + + switch (event) { + case CHR_EVENT_OPENED: + if (vub_connect(dev) < 0) { + qemu_chr_fe_disconnect(&vub->chardev); + return; + } + break; + case CHR_EVENT_CLOSED: + vub_disconnect(dev); + break; + case CHR_EVENT_BREAK: + case CHR_EVENT_MUX_IN: + case CHR_EVENT_MUX_OUT: + /* Ignore */ + break; + } +} + +static void vub_device_realize(DeviceState *dev, Error **errp) +{ + VirtIODevice *vdev = VIRTIO_DEVICE(dev); + VHostUserBase *vub = VHOST_USER_BASE(dev); + int ret; + + if (!vub->chardev.chr) { + error_setg(errp, "vhost-user-device: missing chardev"); + return; + } + + if (!vub->virtio_id) { + error_setg(errp, "vhost-user-device: need to define device id"); + return; + } + + if (!vub->num_vqs) { + vub->num_vqs = 1; /* reasonable default? */ + } + + if (!vhost_user_init(&vub->vhost_user, &vub->chardev, errp)) { + return; + } + + virtio_init(vdev, vub->virtio_id, 0); + + /* + * Disable guest notifiers, by default all notifications will be via the + * asynchronous vhost-user socket. + */ + vdev->use_guest_notifier_mask = false; + + /* Allocate queues */ + vub->vqs = g_ptr_array_sized_new(vub->num_vqs); + for (int i = 0; i < vub->num_vqs; i++) { + g_ptr_array_add(vub->vqs, + virtio_add_queue(vdev, 4, vub_handle_output)); + } + + vub->vhost_dev.nvqs = vub->num_vqs; + vub->vhost_dev.vqs = g_new0(struct vhost_virtqueue, vub->vhost_dev.nvqs); + + /* connect to backend */ + ret = vhost_dev_init(&vub->vhost_dev, &vub->vhost_user, + VHOST_BACKEND_TYPE_USER, 0, errp); + + if (ret < 0) { + do_vhost_user_cleanup(vdev, vub); + } + + qemu_chr_fe_set_handlers(&vub->chardev, NULL, NULL, vub_event, NULL, + dev, NULL, true); +} + +static void vub_device_unrealize(DeviceState *dev) +{ + VirtIODevice *vdev = VIRTIO_DEVICE(dev); + VHostUserBase *vub = VHOST_USER_BASE(dev); + struct vhost_virtqueue *vhost_vqs = vub->vhost_dev.vqs; + + /* This will stop vhost backend if appropriate. */ + vub_set_status(vdev, 0); + vhost_dev_cleanup(&vub->vhost_dev); + g_free(vhost_vqs); + do_vhost_user_cleanup(vdev, vub); +} + +static void vub_class_init(ObjectClass *klass, void *data) +{ + VirtioDeviceClass *vdc = VIRTIO_DEVICE_CLASS(klass); + + vdc->realize = vub_device_realize; + vdc->unrealize = vub_device_unrealize; + vdc->get_features = vub_get_features; + vdc->set_status = vub_set_status; +} + +static const TypeInfo vub_info = { + .name = TYPE_VHOST_USER_BASE, + .parent = TYPE_VIRTIO_DEVICE, + .instance_size = sizeof(VHostUserBase), + .class_init = vub_class_init, + .class_size = sizeof(VHostUserBaseClass), + .abstract = true +}; + + +/* + * The following is a concrete implementation of the base class which + * allows the user to define the key parameters via the command line. + */ + +static const VMStateDescription vud_vmstate = { + .name = "vhost-user-device", + .unmigratable = 1, +}; + +static Property vud_properties[] = { + DEFINE_PROP_CHR("chardev", VHostUserBase, chardev), + DEFINE_PROP_UINT16("virtio-id", VHostUserBase, virtio_id, 0), + DEFINE_PROP_UINT32("num_vqs", VHostUserBase, num_vqs, 1), + DEFINE_PROP_END_OF_LIST(), +}; + +static void vud_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + + device_class_set_props(dc, vud_properties); + dc->vmsd = &vud_vmstate; + set_bit(DEVICE_CATEGORY_INPUT, dc->categories); +} + +static const TypeInfo vud_info = { + .name = TYPE_VHOST_USER_DEVICE, + .parent = TYPE_VHOST_USER_BASE, + .instance_size = sizeof(VHostUserBase), + .class_init = vud_class_init, + .class_size = sizeof(VHostUserBaseClass), +}; + +static void vu_register_types(void) +{ + type_register_static(&vub_info); + type_register_static(&vud_info); +} + +type_init(vu_register_types) diff --git a/include/hw/virtio/vhost-user-device.h b/include/hw/virtio/vhost-user-device.h new file mode 100644 index 0000000000..9105011e25 --- /dev/null +++ b/include/hw/virtio/vhost-user-device.h @@ -0,0 +1,45 @@ +/* + * Vhost-user generic virtio device + * + * Copyright (c) 2023 Linaro Ltd + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +#ifndef QEMU_VHOST_USER_DEVICE_H +#define QEMU_VHOST_USER_DEVICE_H + +#include "hw/virtio/vhost.h" +#include "hw/virtio/vhost-user.h" + +#define TYPE_VHOST_USER_BASE "vhost-user-base" + +OBJECT_DECLARE_TYPE(VHostUserBase, VHostUserBaseClass, VHOST_USER_BASE) + +struct VHostUserBase { + VirtIODevice parent; + /* Properties */ + CharBackend chardev; + uint16_t virtio_id; + uint32_t num_vqs; + /* State tracking */ + VhostUserState vhost_user; + struct vhost_virtqueue *vhost_vq; + struct vhost_dev vhost_dev; + GPtrArray *vqs; + bool connected; +}; + + /* needed so we can use the base realize after specialisation + tweaks */ +struct VHostUserBaseClass { + /*< private >*/ + VirtioDeviceClass parent_class; + /*< public >*/ + DeviceRealize parent_realize; +}; + +/* shared for the benefit of the derived pci class */ +#define TYPE_VHOST_USER_DEVICE "vhost-user-device" + +#endif /* QEMU_VHOST_USER_DEVICE_H */ From f92a2d61cd86fd585b1b2a57295fcde278aebd78 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20Benn=C3=A9e?= Date: Mon, 10 Jul 2023 16:35:12 +0100 Subject: [PATCH 0220/1077] hw/virtio: add config support to vhost-user-device MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit To use the generic device the user will need to provide the config region size via the command line. We also add a notifier so the guest can be pinged if the remote daemon updates the config. With these changes: -device vhost-user-device-pci,virtio-id=41,num_vqs=2,config_size=8 is equivalent to: -device vhost-user-gpio-pci Signed-off-by: Alex Bennée Message-Id: <20230710153522.3469097-11-alex.bennee@linaro.org> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/virtio/vhost-user-device.c | 58 ++++++++++++++++++++++++++- include/hw/virtio/vhost-user-device.h | 1 + 2 files changed, 58 insertions(+), 1 deletion(-) diff --git a/hw/virtio/vhost-user-device.c b/hw/virtio/vhost-user-device.c index b0239fa033..2b028cae08 100644 --- a/hw/virtio/vhost-user-device.c +++ b/hw/virtio/vhost-user-device.c @@ -117,6 +117,42 @@ static uint64_t vub_get_features(VirtIODevice *vdev, return vub->vhost_dev.features & ~(1ULL << VHOST_USER_F_PROTOCOL_FEATURES); } +/* + * To handle VirtIO config we need to know the size of the config + * space. We don't cache the config but re-fetch it from the guest + * every time in case something has changed. + */ +static void vub_get_config(VirtIODevice *vdev, uint8_t *config) +{ + VHostUserBase *vub = VHOST_USER_BASE(vdev); + Error *local_err = NULL; + + /* + * There will have been a warning during vhost_dev_init, but lets + * assert here as nothing will go right now. + */ + g_assert(vub->config_size && vub->vhost_user.supports_config == true); + + if (vhost_dev_get_config(&vub->vhost_dev, config, + vub->config_size, &local_err)) { + error_report_err(local_err); + } +} + +/* + * When the daemon signals an update to the config we just need to + * signal the guest as we re-read the config on demand above. + */ +static int vub_config_notifier(struct vhost_dev *dev) +{ + virtio_notify_config(dev->vdev); + return 0; +} + +const VhostDevConfigOps vub_config_ops = { + .vhost_dev_config_notifier = vub_config_notifier, +}; + static void vub_handle_output(VirtIODevice *vdev, VirtQueue *vq) { /* @@ -141,12 +177,21 @@ static int vub_connect(DeviceState *dev) { VirtIODevice *vdev = VIRTIO_DEVICE(dev); VHostUserBase *vub = VHOST_USER_BASE(vdev); + struct vhost_dev *vhost_dev = &vub->vhost_dev; if (vub->connected) { return 0; } vub->connected = true; + /* + * If we support VHOST_USER_GET_CONFIG we must enable the notifier + * so we can ping the guest when it updates. + */ + if (vub->vhost_user.supports_config) { + vhost_dev_set_config_notifier(vhost_dev, &vub_config_ops); + } + /* restore vhost state */ if (virtio_device_started(vdev, vdev->status)) { vub_start(vdev); @@ -214,11 +259,20 @@ static void vub_device_realize(DeviceState *dev, Error **errp) vub->num_vqs = 1; /* reasonable default? */ } + /* + * We can't handle config requests unless we know the size of the + * config region, specialisations of the vhost-user-device will be + * able to set this. + */ + if (vub->config_size) { + vub->vhost_user.supports_config = true; + } + if (!vhost_user_init(&vub->vhost_user, &vub->chardev, errp)) { return; } - virtio_init(vdev, vub->virtio_id, 0); + virtio_init(vdev, vub->virtio_id, vub->config_size); /* * Disable guest notifiers, by default all notifications will be via the @@ -268,6 +322,7 @@ static void vub_class_init(ObjectClass *klass, void *data) vdc->realize = vub_device_realize; vdc->unrealize = vub_device_unrealize; vdc->get_features = vub_get_features; + vdc->get_config = vub_get_config; vdc->set_status = vub_set_status; } @@ -295,6 +350,7 @@ static Property vud_properties[] = { DEFINE_PROP_CHR("chardev", VHostUserBase, chardev), DEFINE_PROP_UINT16("virtio-id", VHostUserBase, virtio_id, 0), DEFINE_PROP_UINT32("num_vqs", VHostUserBase, num_vqs, 1), + DEFINE_PROP_UINT32("config_size", VHostUserBase, config_size, 0), DEFINE_PROP_END_OF_LIST(), }; diff --git a/include/hw/virtio/vhost-user-device.h b/include/hw/virtio/vhost-user-device.h index 9105011e25..3ddf88a146 100644 --- a/include/hw/virtio/vhost-user-device.h +++ b/include/hw/virtio/vhost-user-device.h @@ -22,6 +22,7 @@ struct VHostUserBase { CharBackend chardev; uint16_t virtio_id; uint32_t num_vqs; + uint32_t config_size; /* State tracking */ VhostUserState vhost_user; struct vhost_virtqueue *vhost_vq; From 06b636a1e2ad12ab130edcbb0ccf995118440706 Mon Sep 17 00:00:00 2001 From: Hawkins Jiawei Date: Sun, 23 Jul 2023 20:09:11 +0800 Subject: [PATCH 0221/1077] virtio-net: do not reset vlan filtering at set_features MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This function is called after virtio_load, so all vlan configuration is lost in migration case. Just allow all the vlan-tagged packets if vlan is not configured, and trust device reset to clear all filtered vlans. Fixes: 0b1eaa8803 ("virtio-net: Do not filter VLANs without F_CTRL_VLAN") Signed-off-by: Eugenio Pérez Reviewed-by: Hawkins Jiawei Signed-off-by: Hawkins Jiawei Message-Id: <95af0d013281282f48ad3f47f6ad1ac4ca9e52eb.1690106284.git.yin31149@gmail.com> Tested-by: Lei Yang Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/net/virtio-net.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c index 5a0201c423..1c31374334 100644 --- a/hw/net/virtio-net.c +++ b/hw/net/virtio-net.c @@ -1029,9 +1029,7 @@ static void virtio_net_set_features(VirtIODevice *vdev, uint64_t features) vhost_net_save_acked_features(nc->peer); } - if (virtio_has_feature(features, VIRTIO_NET_F_CTRL_VLAN)) { - memset(n->vlans, 0, MAX_VLAN >> 3); - } else { + if (!virtio_has_feature(features, VIRTIO_NET_F_CTRL_VLAN)) { memset(n->vlans, 0xff, MAX_VLAN >> 3); } From e19751a32f140a232fafb037e703abb961a94abb Mon Sep 17 00:00:00 2001 From: Hawkins Jiawei Date: Sun, 23 Jul 2023 20:09:12 +0800 Subject: [PATCH 0222/1077] virtio-net: Expose MAX_VLAN MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit vhost-vdpa shadowed CVQ needs to know the maximum number of vlans supported by the virtio-net device, so QEMU can restore the VLAN state in a migration. Co-developed-by: Eugenio Pérez Signed-off-by: Eugenio Pérez Signed-off-by: Hawkins Jiawei Message-Id: Tested-by: Lei Yang Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/net/virtio-net.c | 2 -- include/hw/virtio/virtio-net.h | 6 ++++++ 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c index 1c31374334..29e33ea5ed 100644 --- a/hw/net/virtio-net.c +++ b/hw/net/virtio-net.c @@ -49,8 +49,6 @@ #define VIRTIO_NET_VM_VERSION 11 -#define MAX_VLAN (1 << 12) /* Per 802.1Q definition */ - /* previously fixed value */ #define VIRTIO_NET_RX_QUEUE_DEFAULT_SIZE 256 #define VIRTIO_NET_TX_QUEUE_DEFAULT_SIZE 256 diff --git a/include/hw/virtio/virtio-net.h b/include/hw/virtio/virtio-net.h index e07a723027..55977f01f0 100644 --- a/include/hw/virtio/virtio-net.h +++ b/include/hw/virtio/virtio-net.h @@ -38,6 +38,12 @@ OBJECT_DECLARE_SIMPLE_TYPE(VirtIONet, VIRTIO_NET) /* Maximum VIRTIO_NET_CTRL_MAC_TABLE_SET unicast + multicast entries. */ #define MAC_TABLE_ENTRIES 64 +/* + * The maximum number of VLANs in the VLAN filter table + * added by VIRTIO_NET_CTRL_VLAN_ADD + */ +#define MAX_VLAN (1 << 12) /* Per 802.1Q definition */ + typedef struct virtio_net_conf { uint32_t txtimer; From 8f7e9967484dec2a727c24a509962ca3a4f5dad4 Mon Sep 17 00:00:00 2001 From: Hawkins Jiawei Date: Sun, 23 Jul 2023 20:09:13 +0800 Subject: [PATCH 0223/1077] vdpa: Restore vlan filtering state MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This patch introduces vhost_vdpa_net_load_single_vlan() and vhost_vdpa_net_load_vlan() to restore the vlan filtering state at device's startup. Co-developed-by: Eugenio Pérez Signed-off-by: Eugenio Pérez Signed-off-by: Hawkins Jiawei Message-Id: Tested-by: Lei Yang Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- net/vhost-vdpa.c | 48 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) diff --git a/net/vhost-vdpa.c b/net/vhost-vdpa.c index 4e94c50bc7..8648d86f64 100644 --- a/net/vhost-vdpa.c +++ b/net/vhost-vdpa.c @@ -968,6 +968,50 @@ static int vhost_vdpa_net_load_rx(VhostVDPAState *s, return 0; } +static int vhost_vdpa_net_load_single_vlan(VhostVDPAState *s, + const VirtIONet *n, + uint16_t vid) +{ + const struct iovec data = { + .iov_base = &vid, + .iov_len = sizeof(vid), + }; + ssize_t dev_written = vhost_vdpa_net_load_cmd(s, VIRTIO_NET_CTRL_VLAN, + VIRTIO_NET_CTRL_VLAN_ADD, + &data, 1); + if (unlikely(dev_written < 0)) { + return dev_written; + } + if (unlikely(*s->status != VIRTIO_NET_OK)) { + return -EIO; + } + + return 0; +} + +static int vhost_vdpa_net_load_vlan(VhostVDPAState *s, + const VirtIONet *n) +{ + int r; + + if (!virtio_vdev_has_feature(&n->parent_obj, VIRTIO_NET_F_CTRL_VLAN)) { + return 0; + } + + for (int i = 0; i < MAX_VLAN >> 5; i++) { + for (int j = 0; n->vlans[i] && j <= 0x1f; j++) { + if (n->vlans[i] & (1U << j)) { + r = vhost_vdpa_net_load_single_vlan(s, n, (i << 5) + j); + if (unlikely(r != 0)) { + return r; + } + } + } + } + + return 0; +} + static int vhost_vdpa_net_load(NetClientState *nc) { VhostVDPAState *s = DO_UPCAST(VhostVDPAState, nc, nc); @@ -998,6 +1042,10 @@ static int vhost_vdpa_net_load(NetClientState *nc) if (unlikely(r)) { return r; } + r = vhost_vdpa_net_load_vlan(s, n); + if (unlikely(r)) { + return r; + } return 0; } From e213c45a042db2506b5e8f16293f1f1c5083a577 Mon Sep 17 00:00:00 2001 From: Hawkins Jiawei Date: Sun, 23 Jul 2023 20:09:14 +0800 Subject: [PATCH 0224/1077] vdpa: Allow VIRTIO_NET_F_CTRL_VLAN in SVQ MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Enable SVQ with VIRTIO_NET_F_CTRL_VLAN feature. Co-developed-by: Eugenio Pérez Signed-off-by: Eugenio Pérez Signed-off-by: Hawkins Jiawei Message-Id: <38dc63102a42c31c72fd293d0e6e2828fd54c86e.1690106284.git.yin31149@gmail.com> Tested-by: Lei Yang Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- net/vhost-vdpa.c | 1 + 1 file changed, 1 insertion(+) diff --git a/net/vhost-vdpa.c b/net/vhost-vdpa.c index 8648d86f64..144b33f997 100644 --- a/net/vhost-vdpa.c +++ b/net/vhost-vdpa.c @@ -114,6 +114,7 @@ static const uint64_t vdpa_svq_device_features = BIT_ULL(VIRTIO_NET_F_STATUS) | BIT_ULL(VIRTIO_NET_F_CTRL_VQ) | BIT_ULL(VIRTIO_NET_F_CTRL_RX) | + BIT_ULL(VIRTIO_NET_F_CTRL_VLAN) | BIT_ULL(VIRTIO_NET_F_CTRL_RX_EXTRA) | BIT_ULL(VIRTIO_NET_F_MQ) | BIT_ULL(VIRTIO_F_ANY_LAYOUT) | From 43d6376980d5567f2a6d00cfb30d10c0961671e6 Mon Sep 17 00:00:00 2001 From: Ilya Maximets Date: Fri, 11 Aug 2023 16:34:23 +0200 Subject: [PATCH 0225/1077] virtio: don't zero out memory region cache for indirect descriptors Lots of virtio functions that are on a hot path in data transmission are initializing indirect descriptor cache at the point of stack allocation. It's a 112 byte structure that is getting zeroed out on each call adding unnecessary overhead. It's going to be correctly initialized later via special init function. The only reason to actually initialize right away is the ability to safely destruct it. Replacing a designated initializer with a function to only initialize what is necessary. Removal of the unnecessary stack initializations improves throughput of virtio-net devices in terms of 64B packets per second by 6-14 % depending on the case. Tested with a proposed af-xdp network backend and a dpdk testpmd application in the guest, but should be beneficial for other virtio devices as well. Signed-off-by: Ilya Maximets Message-Id: <20230811143423.3258788-1-i.maximets@ovn.org> Reviewed-by: Stefan Hajnoczi Acked-by: Jason Wang Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/virtio/virtio.c | 20 +++++++++++++++----- include/exec/memory.h | 16 +++++++++++++--- 2 files changed, 28 insertions(+), 8 deletions(-) diff --git a/hw/virtio/virtio.c b/hw/virtio/virtio.c index 4577f3f5b3..d3a22e3d36 100644 --- a/hw/virtio/virtio.c +++ b/hw/virtio/virtio.c @@ -1071,10 +1071,12 @@ static void virtqueue_split_get_avail_bytes(VirtQueue *vq, VirtIODevice *vdev = vq->vdev; unsigned int idx; unsigned int total_bufs, in_total, out_total; - MemoryRegionCache indirect_desc_cache = MEMORY_REGION_CACHE_INVALID; + MemoryRegionCache indirect_desc_cache; int64_t len = 0; int rc; + address_space_cache_init_empty(&indirect_desc_cache); + idx = vq->last_avail_idx; total_bufs = in_total = out_total = 0; @@ -1207,12 +1209,14 @@ static void virtqueue_packed_get_avail_bytes(VirtQueue *vq, VirtIODevice *vdev = vq->vdev; unsigned int idx; unsigned int total_bufs, in_total, out_total; + MemoryRegionCache indirect_desc_cache; MemoryRegionCache *desc_cache; - MemoryRegionCache indirect_desc_cache = MEMORY_REGION_CACHE_INVALID; int64_t len = 0; VRingPackedDesc desc; bool wrap_counter; + address_space_cache_init_empty(&indirect_desc_cache); + idx = vq->last_avail_idx; wrap_counter = vq->last_avail_wrap_counter; total_bufs = in_total = out_total = 0; @@ -1487,7 +1491,7 @@ static void *virtqueue_split_pop(VirtQueue *vq, size_t sz) { unsigned int i, head, max; VRingMemoryRegionCaches *caches; - MemoryRegionCache indirect_desc_cache = MEMORY_REGION_CACHE_INVALID; + MemoryRegionCache indirect_desc_cache; MemoryRegionCache *desc_cache; int64_t len; VirtIODevice *vdev = vq->vdev; @@ -1498,6 +1502,8 @@ static void *virtqueue_split_pop(VirtQueue *vq, size_t sz) VRingDesc desc; int rc; + address_space_cache_init_empty(&indirect_desc_cache); + RCU_READ_LOCK_GUARD(); if (virtio_queue_empty_rcu(vq)) { goto done; @@ -1624,7 +1630,7 @@ static void *virtqueue_packed_pop(VirtQueue *vq, size_t sz) { unsigned int i, max; VRingMemoryRegionCaches *caches; - MemoryRegionCache indirect_desc_cache = MEMORY_REGION_CACHE_INVALID; + MemoryRegionCache indirect_desc_cache; MemoryRegionCache *desc_cache; int64_t len; VirtIODevice *vdev = vq->vdev; @@ -1636,6 +1642,8 @@ static void *virtqueue_packed_pop(VirtQueue *vq, size_t sz) uint16_t id; int rc; + address_space_cache_init_empty(&indirect_desc_cache); + RCU_READ_LOCK_GUARD(); if (virtio_queue_packed_empty_rcu(vq)) { goto done; @@ -3970,13 +3978,15 @@ VirtioQueueElement *qmp_x_query_virtio_queue_element(const char *path, } else { unsigned int head, i, max; VRingMemoryRegionCaches *caches; - MemoryRegionCache indirect_desc_cache = MEMORY_REGION_CACHE_INVALID; + MemoryRegionCache indirect_desc_cache; MemoryRegionCache *desc_cache; VRingDesc desc; VirtioRingDescList *list = NULL; VirtioRingDescList *node; int rc; int ndescs; + address_space_cache_init_empty(&indirect_desc_cache); + RCU_READ_LOCK_GUARD(); max = vq->vring.num; diff --git a/include/exec/memory.h b/include/exec/memory.h index ef23d65afc..c99842d2fc 100644 --- a/include/exec/memory.h +++ b/include/exec/memory.h @@ -2671,9 +2671,6 @@ struct MemoryRegionCache { bool is_write; }; -#define MEMORY_REGION_CACHE_INVALID ((MemoryRegionCache) { .mrs.mr = NULL }) - - /* address_space_ld*_cached: load from a cached #MemoryRegion * address_space_st*_cached: store into a cached #MemoryRegion * @@ -2762,6 +2759,19 @@ int64_t address_space_cache_init(MemoryRegionCache *cache, hwaddr len, bool is_write); +/** + * address_space_cache_init_empty: Initialize empty #MemoryRegionCache + * + * @cache: The #MemoryRegionCache to operate on. + * + * Initializes #MemoryRegionCache structure without memory region attached. + * Cache initialized this way can only be safely destroyed, but not used. + */ +static inline void address_space_cache_init_empty(MemoryRegionCache *cache) +{ + cache->mrs.mr = NULL; +} + /** * address_space_cache_invalidate: complete a write to a #MemoryRegionCache * From b40eba9cdde3b041f02a9cbaa23ca0eeda9bd9c1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Eugenio=20P=C3=A9rez?= Date: Tue, 22 Aug 2023 10:53:26 +0200 Subject: [PATCH 0226/1077] vdpa: use first queue SVQ state for CVQ default MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Previous to this patch the only way CVQ would be shadowed is if it does support to isolate CVQ group or if all vqs were shadowed from the beginning. The second condition was checked at the beginning, and no more configuration was done. After this series we need to check if data queues are shadowed because they are in the middle of the migration. As checking if they are shadowed already covers the previous case, let's just mimic it. Signed-off-by: Eugenio Pérez Acked-by: Jason Wang Message-Id: <20230822085330.3978829-2-eperezma@redhat.com> Tested-by: Lei Yang Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- net/vhost-vdpa.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/vhost-vdpa.c b/net/vhost-vdpa.c index 144b33f997..30dc7e77c9 100644 --- a/net/vhost-vdpa.c +++ b/net/vhost-vdpa.c @@ -509,7 +509,7 @@ static int vhost_vdpa_net_cvq_start(NetClientState *nc) s0 = vhost_vdpa_net_first_nc_vdpa(s); v->shadow_data = s0->vhost_vdpa.shadow_vqs_enabled; - v->shadow_vqs_enabled = s->always_svq; + v->shadow_vqs_enabled = s0->vhost_vdpa.shadow_vqs_enabled; s->vhost_vdpa.address_space_id = VHOST_VDPA_GUEST_PA_ASID; if (s->vhost_vdpa.shadow_data) { From d7ce0841767d01c226fc0e22436ce22a0ec74226 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Eugenio=20P=C3=A9rez?= Date: Tue, 22 Aug 2023 10:53:27 +0200 Subject: [PATCH 0227/1077] vdpa: export vhost_vdpa_set_vring_ready MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The vhost-vdpa net backend needs to enable vrings in a different order than default, so export it. No functional change intended except for tracing, that now includes the (virtio) index being enabled and the return value of the ioctl. Still ignoring return value of this function if called from vhost_vdpa_dev_start, as reorganize calling code around it is out of the scope of this series. Signed-off-by: Eugenio Pérez Acked-by: Jason Wang Message-Id: <20230822085330.3978829-3-eperezma@redhat.com> Tested-by: Lei Yang Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/virtio/trace-events | 2 +- hw/virtio/vhost-vdpa.c | 25 +++++++++++++------------ include/hw/virtio/vhost-vdpa.h | 1 + 3 files changed, 15 insertions(+), 13 deletions(-) diff --git a/hw/virtio/trace-events b/hw/virtio/trace-events index 7109cf1a3b..1cb9027d1e 100644 --- a/hw/virtio/trace-events +++ b/hw/virtio/trace-events @@ -48,7 +48,7 @@ vhost_vdpa_set_features(void *dev, uint64_t features) "dev: %p features: 0x%"PRI vhost_vdpa_get_device_id(void *dev, uint32_t device_id) "dev: %p device_id %"PRIu32 vhost_vdpa_reset_device(void *dev) "dev: %p" vhost_vdpa_get_vq_index(void *dev, int idx, int vq_idx) "dev: %p idx: %d vq idx: %d" -vhost_vdpa_set_vring_ready(void *dev) "dev: %p" +vhost_vdpa_set_vring_ready(void *dev, unsigned i, int r) "dev: %p, idx: %u, r: %d" vhost_vdpa_dump_config(void *dev, const char *line) "dev: %p %s" vhost_vdpa_set_config(void *dev, uint32_t offset, uint32_t size, uint32_t flags) "dev: %p offset: %"PRIu32" size: %"PRIu32" flags: 0x%"PRIx32 vhost_vdpa_get_config(void *dev, void *config, uint32_t config_len) "dev: %p config: %p config_len: %"PRIu32 diff --git a/hw/virtio/vhost-vdpa.c b/hw/virtio/vhost-vdpa.c index 50b932a930..e7de880d51 100644 --- a/hw/virtio/vhost-vdpa.c +++ b/hw/virtio/vhost-vdpa.c @@ -882,18 +882,17 @@ static int vhost_vdpa_get_vq_index(struct vhost_dev *dev, int idx) return idx; } -static int vhost_vdpa_set_vring_ready(struct vhost_dev *dev) +int vhost_vdpa_set_vring_ready(struct vhost_vdpa *v, unsigned idx) { - int i; - trace_vhost_vdpa_set_vring_ready(dev); - for (i = 0; i < dev->nvqs; ++i) { - struct vhost_vring_state state = { - .index = dev->vq_index + i, - .num = 1, - }; - vhost_vdpa_call(dev, VHOST_VDPA_SET_VRING_ENABLE, &state); - } - return 0; + struct vhost_dev *dev = v->dev; + struct vhost_vring_state state = { + .index = idx, + .num = 1, + }; + int r = vhost_vdpa_call(dev, VHOST_VDPA_SET_VRING_ENABLE, &state); + + trace_vhost_vdpa_set_vring_ready(dev, idx, r); + return r; } static int vhost_vdpa_set_config_call(struct vhost_dev *dev, @@ -1304,7 +1303,9 @@ static int vhost_vdpa_dev_start(struct vhost_dev *dev, bool started) if (unlikely(!ok)) { return -1; } - vhost_vdpa_set_vring_ready(dev); + for (int i = 0; i < dev->nvqs; ++i) { + vhost_vdpa_set_vring_ready(v, dev->vq_index + i); + } } else { vhost_vdpa_suspend(dev); vhost_vdpa_svqs_stop(dev); diff --git a/include/hw/virtio/vhost-vdpa.h b/include/hw/virtio/vhost-vdpa.h index e64bfc7f98..5407d54fd7 100644 --- a/include/hw/virtio/vhost-vdpa.h +++ b/include/hw/virtio/vhost-vdpa.h @@ -57,6 +57,7 @@ typedef struct vhost_vdpa { } VhostVDPA; int vhost_vdpa_get_iova_range(int fd, struct vhost_vdpa_iova_range *iova_range); +int vhost_vdpa_set_vring_ready(struct vhost_vdpa *v, unsigned idx); int vhost_vdpa_dma_map(struct vhost_vdpa *v, uint32_t asid, hwaddr iova, hwaddr size, void *vaddr, bool readonly); From f3fada598c909bac12bd18da36437d9bed0b9f06 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Eugenio=20P=C3=A9rez?= Date: Tue, 22 Aug 2023 10:53:28 +0200 Subject: [PATCH 0228/1077] vdpa: rename vhost_vdpa_net_load to vhost_vdpa_net_cvq_load MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Next patches will add the corresponding data load. Signed-off-by: Eugenio Pérez Acked-by: Jason Wang Message-Id: <20230822085330.3978829-4-eperezma@redhat.com> Tested-by: Lei Yang Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- net/vhost-vdpa.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/net/vhost-vdpa.c b/net/vhost-vdpa.c index 30dc7e77c9..008c0cf8b3 100644 --- a/net/vhost-vdpa.c +++ b/net/vhost-vdpa.c @@ -1013,7 +1013,7 @@ static int vhost_vdpa_net_load_vlan(VhostVDPAState *s, return 0; } -static int vhost_vdpa_net_load(NetClientState *nc) +static int vhost_vdpa_net_cvq_load(NetClientState *nc) { VhostVDPAState *s = DO_UPCAST(VhostVDPAState, nc, nc); struct vhost_vdpa *v = &s->vhost_vdpa; @@ -1056,7 +1056,7 @@ static NetClientInfo net_vhost_vdpa_cvq_info = { .size = sizeof(VhostVDPAState), .receive = vhost_vdpa_receive, .start = vhost_vdpa_net_cvq_start, - .load = vhost_vdpa_net_load, + .load = vhost_vdpa_net_cvq_load, .stop = vhost_vdpa_net_cvq_stop, .cleanup = vhost_vdpa_cleanup, .has_vnet_hdr = vhost_vdpa_has_vnet_hdr, From 6c4825476a4351530bcac17abab72295b75ffe98 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Eugenio=20P=C3=A9rez?= Date: Tue, 22 Aug 2023 10:53:29 +0200 Subject: [PATCH 0229/1077] vdpa: move vhost_vdpa_set_vring_ready to the caller MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Doing that way allows CVQ to be enabled before the dataplane vqs, restoring the state as MQ or MAC addresses properly in the case of a migration. The patch does it by defining a ->load NetClientInfo callback also for dataplane. Ideally, this should be done by an independent patch, but the function is already static so it would only add an empty vhost_vdpa_net_data_load stub. Signed-off-by: Eugenio Pérez Message-Id: <20230822085330.3978829-5-eperezma@redhat.com> Acked-by: Jason Wang Tested-by: Lei Yang Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/virtio/vdpa-dev.c | 3 ++ hw/virtio/vhost-vdpa.c | 3 -- net/vhost-vdpa.c | 65 ++++++++++++++++++++++++++++-------------- 3 files changed, 46 insertions(+), 25 deletions(-) diff --git a/hw/virtio/vdpa-dev.c b/hw/virtio/vdpa-dev.c index 363b625243..f22d5d5bc0 100644 --- a/hw/virtio/vdpa-dev.c +++ b/hw/virtio/vdpa-dev.c @@ -255,6 +255,9 @@ static int vhost_vdpa_device_start(VirtIODevice *vdev, Error **errp) error_setg_errno(errp, -ret, "Error starting vhost"); goto err_guest_notifiers; } + for (i = 0; i < s->dev.nvqs; ++i) { + vhost_vdpa_set_vring_ready(&s->vdpa, i); + } s->started = true; /* diff --git a/hw/virtio/vhost-vdpa.c b/hw/virtio/vhost-vdpa.c index e7de880d51..89ff02a999 100644 --- a/hw/virtio/vhost-vdpa.c +++ b/hw/virtio/vhost-vdpa.c @@ -1303,9 +1303,6 @@ static int vhost_vdpa_dev_start(struct vhost_dev *dev, bool started) if (unlikely(!ok)) { return -1; } - for (int i = 0; i < dev->nvqs; ++i) { - vhost_vdpa_set_vring_ready(v, dev->vq_index + i); - } } else { vhost_vdpa_suspend(dev); vhost_vdpa_svqs_stop(dev); diff --git a/net/vhost-vdpa.c b/net/vhost-vdpa.c index 008c0cf8b3..0715bed8e6 100644 --- a/net/vhost-vdpa.c +++ b/net/vhost-vdpa.c @@ -375,6 +375,22 @@ static int vhost_vdpa_net_data_start(NetClientState *nc) return 0; } +static int vhost_vdpa_net_data_load(NetClientState *nc) +{ + VhostVDPAState *s = DO_UPCAST(VhostVDPAState, nc, nc); + struct vhost_vdpa *v = &s->vhost_vdpa; + bool has_cvq = v->dev->vq_index_end % 2; + + if (has_cvq) { + return 0; + } + + for (int i = 0; i < v->dev->nvqs; ++i) { + vhost_vdpa_set_vring_ready(v, i + v->dev->vq_index); + } + return 0; +} + static void vhost_vdpa_net_client_stop(NetClientState *nc) { VhostVDPAState *s = DO_UPCAST(VhostVDPAState, nc, nc); @@ -397,6 +413,7 @@ static NetClientInfo net_vhost_vdpa_info = { .size = sizeof(VhostVDPAState), .receive = vhost_vdpa_receive, .start = vhost_vdpa_net_data_start, + .load = vhost_vdpa_net_data_load, .stop = vhost_vdpa_net_client_stop, .cleanup = vhost_vdpa_cleanup, .has_vnet_hdr = vhost_vdpa_has_vnet_hdr, @@ -1022,30 +1039,34 @@ static int vhost_vdpa_net_cvq_load(NetClientState *nc) assert(nc->info->type == NET_CLIENT_DRIVER_VHOST_VDPA); - if (!v->shadow_vqs_enabled) { - return 0; + vhost_vdpa_set_vring_ready(v, v->dev->vq_index); + + if (v->shadow_vqs_enabled) { + n = VIRTIO_NET(v->dev->vdev); + r = vhost_vdpa_net_load_mac(s, n); + if (unlikely(r < 0)) { + return r; + } + r = vhost_vdpa_net_load_mq(s, n); + if (unlikely(r)) { + return r; + } + r = vhost_vdpa_net_load_offloads(s, n); + if (unlikely(r)) { + return r; + } + r = vhost_vdpa_net_load_rx(s, n); + if (unlikely(r)) { + return r; + } + r = vhost_vdpa_net_load_vlan(s, n); + if (unlikely(r)) { + return r; + } } - n = VIRTIO_NET(v->dev->vdev); - r = vhost_vdpa_net_load_mac(s, n); - if (unlikely(r < 0)) { - return r; - } - r = vhost_vdpa_net_load_mq(s, n); - if (unlikely(r)) { - return r; - } - r = vhost_vdpa_net_load_offloads(s, n); - if (unlikely(r)) { - return r; - } - r = vhost_vdpa_net_load_rx(s, n); - if (unlikely(r)) { - return r; - } - r = vhost_vdpa_net_load_vlan(s, n); - if (unlikely(r)) { - return r; + for (int i = 0; i < v->dev->vq_index; ++i) { + vhost_vdpa_set_vring_ready(v, i); } return 0; From f13f5f6412fc51574c961f39dbd625357948282b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Eugenio=20P=C3=A9rez?= Date: Tue, 22 Aug 2023 10:53:30 +0200 Subject: [PATCH 0230/1077] vdpa: remove net cvq migration blocker MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Now that we have add migration blockers if the device does not support all the needed features, remove the general blocker applied to all net devices with CVQ. Signed-off-by: Eugenio Pérez Acked-by: Jason Wang Message-Id: <20230822085330.3978829-6-eperezma@redhat.com> Tested-by: Lei Yang Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- net/vhost-vdpa.c | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/net/vhost-vdpa.c b/net/vhost-vdpa.c index 0715bed8e6..90beda42e0 100644 --- a/net/vhost-vdpa.c +++ b/net/vhost-vdpa.c @@ -1465,18 +1465,6 @@ static NetClientState *net_vhost_vdpa_init(NetClientState *peer, s->vhost_vdpa.shadow_vq_ops = &vhost_vdpa_net_svq_ops; s->vhost_vdpa.shadow_vq_ops_opaque = s; s->cvq_isolated = cvq_isolated; - - /* - * TODO: We cannot migrate devices with CVQ and no x-svq enabled as - * there is no way to set the device state (MAC, MQ, etc) before - * starting the datapath. - * - * Migration blocker ownership now belongs to s->vhost_vdpa. - */ - if (!svq) { - error_setg(&s->vhost_vdpa.migration_blocker, - "net vdpa cannot migrate with CVQ feature"); - } } ret = vhost_vdpa_add(nc, (void *)&s->vhost_vdpa, queue_pair_index, nvqs); if (ret) { From b0de17a2e28de477e09e77a587fcbeafbbc897c4 Mon Sep 17 00:00:00 2001 From: Hawkins Jiawei Date: Tue, 29 Aug 2023 13:54:43 +0800 Subject: [PATCH 0231/1077] vhost: Add count argument to vhost_svq_poll() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Next patches in this series will no longer perform an immediate poll and check of the device's used buffers for each CVQ state load command. Instead, they will send CVQ state load commands in parallel by polling multiple pending buffers at once. To achieve this, this patch refactoring vhost_svq_poll() to accept a new argument `num`, which allows vhost_svq_poll() to wait for the device to use multiple elements, rather than polling for a single element. Signed-off-by: Hawkins Jiawei Acked-by: Eugenio Pérez Message-Id: <950b3bfcfc5d446168b9d6a249d554a013a691d4.1693287885.git.yin31149@gmail.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/virtio/vhost-shadow-virtqueue.c | 36 ++++++++++++++++++------------ hw/virtio/vhost-shadow-virtqueue.h | 2 +- net/vhost-vdpa.c | 2 +- 3 files changed, 24 insertions(+), 16 deletions(-) diff --git a/hw/virtio/vhost-shadow-virtqueue.c b/hw/virtio/vhost-shadow-virtqueue.c index 49e5aed931..e731b1d2ea 100644 --- a/hw/virtio/vhost-shadow-virtqueue.c +++ b/hw/virtio/vhost-shadow-virtqueue.c @@ -514,29 +514,37 @@ static void vhost_svq_flush(VhostShadowVirtqueue *svq, } /** - * Poll the SVQ for one device used buffer. + * Poll the SVQ to wait for the device to use the specified number + * of elements and return the total length written by the device. * * This function race with main event loop SVQ polling, so extra * synchronization is needed. * - * Return the length written by the device. + * @svq: The svq + * @num: The number of elements that need to be used */ -size_t vhost_svq_poll(VhostShadowVirtqueue *svq) +size_t vhost_svq_poll(VhostShadowVirtqueue *svq, size_t num) { - int64_t start_us = g_get_monotonic_time(); - uint32_t len = 0; + size_t len = 0; + uint32_t r; - do { - if (vhost_svq_more_used(svq)) { - break; - } + while (num--) { + int64_t start_us = g_get_monotonic_time(); - if (unlikely(g_get_monotonic_time() - start_us > 10e6)) { - return 0; - } - } while (true); + do { + if (vhost_svq_more_used(svq)) { + break; + } + + if (unlikely(g_get_monotonic_time() - start_us > 10e6)) { + return len; + } + } while (true); + + vhost_svq_get_buf(svq, &r); + len += r; + } - vhost_svq_get_buf(svq, &len); return len; } diff --git a/hw/virtio/vhost-shadow-virtqueue.h b/hw/virtio/vhost-shadow-virtqueue.h index 6efe051a70..5bce67837b 100644 --- a/hw/virtio/vhost-shadow-virtqueue.h +++ b/hw/virtio/vhost-shadow-virtqueue.h @@ -119,7 +119,7 @@ void vhost_svq_push_elem(VhostShadowVirtqueue *svq, int vhost_svq_add(VhostShadowVirtqueue *svq, const struct iovec *out_sg, size_t out_num, const struct iovec *in_sg, size_t in_num, VirtQueueElement *elem); -size_t vhost_svq_poll(VhostShadowVirtqueue *svq); +size_t vhost_svq_poll(VhostShadowVirtqueue *svq, size_t num); void vhost_svq_set_svq_kick_fd(VhostShadowVirtqueue *svq, int svq_kick_fd); void vhost_svq_set_svq_call_fd(VhostShadowVirtqueue *svq, int call_fd); diff --git a/net/vhost-vdpa.c b/net/vhost-vdpa.c index 90beda42e0..5808d1b60c 100644 --- a/net/vhost-vdpa.c +++ b/net/vhost-vdpa.c @@ -645,7 +645,7 @@ static ssize_t vhost_vdpa_net_cvq_add(VhostVDPAState *s, size_t out_len, * descriptor. Also, we need to take the answer before SVQ pulls by itself, * when BQL is released */ - return vhost_svq_poll(svq); + return vhost_svq_poll(svq, 1); } static ssize_t vhost_vdpa_net_load_cmd(VhostVDPAState *s, uint8_t class, From b532c684e0d71bc69fa56a30f1c7588101aa086a Mon Sep 17 00:00:00 2001 From: Jonah Palmer Date: Tue, 26 Sep 2023 18:41:05 -0400 Subject: [PATCH 0232/1077] qmp: remove virtio_list, search QOM tree instead MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The virtio_list duplicates information about virtio devices that already exist in the QOM composition tree. Instead of creating this list of realized virtio devices, search the QOM composition tree instead. This patch modifies the QMP command qmp_x_query_virtio to instead recursively search the QOM composition tree for devices of type 'TYPE_VIRTIO_DEVICE'. The device is also checked to ensure it's realized. Signed-off-by: Jonah Palmer Reviewed-by: Daniel P. Berrangé Message-Id: <20230926224107.2951144-2-jonah.palmer@oracle.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/virtio/virtio-qmp.c | 85 ++++++++++++++---------------------------- hw/virtio/virtio-qmp.h | 7 ---- hw/virtio/virtio.c | 6 --- 3 files changed, 29 insertions(+), 69 deletions(-) diff --git a/hw/virtio/virtio-qmp.c b/hw/virtio/virtio-qmp.c index 7515b0947b..adebf87e9b 100644 --- a/hw/virtio/virtio-qmp.c +++ b/hw/virtio/virtio-qmp.c @@ -667,70 +667,43 @@ VirtioDeviceFeatures *qmp_decode_features(uint16_t device_id, uint64_t bitmap) return features; } +static int query_dev_child(Object *child, void *opaque) +{ + VirtioInfoList **vdevs = opaque; + Object *dev = object_dynamic_cast(child, TYPE_VIRTIO_DEVICE); + if (dev != NULL && DEVICE(dev)->realized) { + VirtIODevice *vdev = VIRTIO_DEVICE(dev); + VirtioInfo *info = g_new(VirtioInfo, 1); + + /* Get canonical path & name of device */ + info->path = object_get_canonical_path(dev); + info->name = g_strdup(vdev->name); + QAPI_LIST_PREPEND(*vdevs, info); + } + return 0; +} + VirtioInfoList *qmp_x_query_virtio(Error **errp) { - VirtioInfoList *list = NULL; - VirtioInfo *node; - VirtIODevice *vdev; + VirtioInfoList *vdevs = NULL; - QTAILQ_FOREACH(vdev, &virtio_list, next) { - DeviceState *dev = DEVICE(vdev); - Error *err = NULL; - QObject *obj = qmp_qom_get(dev->canonical_path, "realized", &err); - - if (err == NULL) { - GString *is_realized = qobject_to_json_pretty(obj, true); - /* virtio device is NOT realized, remove it from list */ - if (!strncmp(is_realized->str, "false", 4)) { - QTAILQ_REMOVE(&virtio_list, vdev, next); - } else { - node = g_new(VirtioInfo, 1); - node->path = g_strdup(dev->canonical_path); - node->name = g_strdup(vdev->name); - QAPI_LIST_PREPEND(list, node); - } - g_string_free(is_realized, true); - } - qobject_unref(obj); + /* Query the QOM composition tree recursively for virtio devices */ + object_child_foreach_recursive(object_get_root(), query_dev_child, &vdevs); + if (vdevs == NULL) { + error_setg(errp, "No virtio devices found"); } - - return list; + return vdevs; } VirtIODevice *qmp_find_virtio_device(const char *path) { - VirtIODevice *vdev; - - QTAILQ_FOREACH(vdev, &virtio_list, next) { - DeviceState *dev = DEVICE(vdev); - - if (strcmp(dev->canonical_path, path) != 0) { - continue; - } - - Error *err = NULL; - QObject *obj = qmp_qom_get(dev->canonical_path, "realized", &err); - if (err == NULL) { - GString *is_realized = qobject_to_json_pretty(obj, true); - /* virtio device is NOT realized, remove it from list */ - if (!strncmp(is_realized->str, "false", 4)) { - g_string_free(is_realized, true); - qobject_unref(obj); - QTAILQ_REMOVE(&virtio_list, vdev, next); - return NULL; - } - g_string_free(is_realized, true); - } else { - /* virtio device doesn't exist in QOM tree */ - QTAILQ_REMOVE(&virtio_list, vdev, next); - qobject_unref(obj); - return NULL; - } - /* device exists in QOM tree & is realized */ - qobject_unref(obj); - return vdev; + /* Verify the canonical path is a realized virtio device */ + Object *dev = object_dynamic_cast(object_resolve_path(path, NULL), + TYPE_VIRTIO_DEVICE); + if (!dev || !DEVICE(dev)->realized) { + return NULL; } - return NULL; + return VIRTIO_DEVICE(dev); } VirtioStatus *qmp_x_query_virtio_status(const char *path, Error **errp) @@ -740,7 +713,7 @@ VirtioStatus *qmp_x_query_virtio_status(const char *path, Error **errp) vdev = qmp_find_virtio_device(path); if (vdev == NULL) { - error_setg(errp, "Path %s is not a VirtIODevice", path); + error_setg(errp, "Path %s is not a realized VirtIODevice", path); return NULL; } diff --git a/hw/virtio/virtio-qmp.h b/hw/virtio/virtio-qmp.h index 8af5f5e65a..245a446a56 100644 --- a/hw/virtio/virtio-qmp.h +++ b/hw/virtio/virtio-qmp.h @@ -15,13 +15,6 @@ #include "hw/virtio/virtio.h" #include "hw/virtio/vhost.h" -#include "qemu/queue.h" - -typedef QTAILQ_HEAD(QmpVirtIODeviceList, VirtIODevice) QmpVirtIODeviceList; - -/* QAPI list of realized VirtIODevices */ -extern QmpVirtIODeviceList virtio_list; - VirtIODevice *qmp_find_virtio_device(const char *path); VirtioDeviceStatus *qmp_decode_status(uint8_t bitmap); VhostDeviceProtocols *qmp_decode_protocols(uint64_t bitmap); diff --git a/hw/virtio/virtio.c b/hw/virtio/virtio.c index d3a22e3d36..c727e9201b 100644 --- a/hw/virtio/virtio.c +++ b/hw/virtio/virtio.c @@ -45,8 +45,6 @@ #include "standard-headers/linux/virtio_mem.h" #include "standard-headers/linux/virtio_vsock.h" -QmpVirtIODeviceList virtio_list; - /* * Maximum size of virtio device config space */ @@ -3659,7 +3657,6 @@ static void virtio_device_realize(DeviceState *dev, Error **errp) vdev->listener.commit = virtio_memory_listener_commit; vdev->listener.name = "virtio"; memory_listener_register(&vdev->listener, vdev->dma_as); - QTAILQ_INSERT_TAIL(&virtio_list, vdev, next); } static void virtio_device_unrealize(DeviceState *dev) @@ -3674,7 +3671,6 @@ static void virtio_device_unrealize(DeviceState *dev) vdc->unrealize(dev); } - QTAILQ_REMOVE(&virtio_list, vdev, next); g_free(vdev->bus_name); vdev->bus_name = NULL; } @@ -3848,8 +3844,6 @@ static void virtio_device_class_init(ObjectClass *klass, void *data) vdc->stop_ioeventfd = virtio_device_stop_ioeventfd_impl; vdc->legacy_features |= VIRTIO_LEGACY_FEATURES; - - QTAILQ_INIT(&virtio_list); } bool virtio_device_ioeventfd_enabled(VirtIODevice *vdev) From 58f81689789f63853d7585c5168f687f1633893a Mon Sep 17 00:00:00 2001 From: Jonah Palmer Date: Tue, 26 Sep 2023 18:41:06 -0400 Subject: [PATCH 0233/1077] qmp: update virtio feature maps, vhost-user-gpio introspection Add new vhost-user protocol feature to vhost-user protocol feature map and enumeration: - VHOST_USER_PROTOCOL_F_STATUS Add new virtio device features for several virtio devices to their respective feature mappings: virtio-blk: - VIRTIO_BLK_F_SECURE_ERASE virtio-net: - VIRTIO_NET_F_NOTF_COAL - VIRTIO_NET_F_GUEST_USO4 - VIRTIO_NET_F_GUEST_USO6 - VIRTIO_NET_F_HOST_USO virtio/vhost-user-gpio: - VIRTIO_GPIO_F_IRQ - VHOST_USER_F_PROTOCOL_FEATURES Add support for introspection on vhost-user-gpio devices. Signed-off-by: Jonah Palmer Reviewed-by: Emmanouil Pitsidianakis Message-Id: <20230926224107.2951144-3-jonah.palmer@oracle.com> Acked-by: Viresh Kumar Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/virtio/vhost-user-gpio.c | 7 +++++++ hw/virtio/virtio-qmp.c | 34 +++++++++++++++++++++++++++++++++- 2 files changed, 40 insertions(+), 1 deletion(-) diff --git a/hw/virtio/vhost-user-gpio.c b/hw/virtio/vhost-user-gpio.c index 3b013f2d0f..3d7fae3984 100644 --- a/hw/virtio/vhost-user-gpio.c +++ b/hw/virtio/vhost-user-gpio.c @@ -205,6 +205,12 @@ static void vu_gpio_guest_notifier_mask(VirtIODevice *vdev, int idx, bool mask) vhost_virtqueue_mask(&gpio->vhost_dev, vdev, idx, mask); } +static struct vhost_dev *vu_gpio_get_vhost(VirtIODevice *vdev) +{ + VHostUserGPIO *gpio = VHOST_USER_GPIO(vdev); + return &gpio->vhost_dev; +} + static void do_vhost_user_cleanup(VirtIODevice *vdev, VHostUserGPIO *gpio) { virtio_delete_queue(gpio->command_vq); @@ -413,6 +419,7 @@ static void vu_gpio_class_init(ObjectClass *klass, void *data) vdc->get_config = vu_gpio_get_config; vdc->set_status = vu_gpio_set_status; vdc->guest_notifier_mask = vu_gpio_guest_notifier_mask; + vdc->get_vhost = vu_gpio_get_vhost; } static const TypeInfo vu_gpio_info = { diff --git a/hw/virtio/virtio-qmp.c b/hw/virtio/virtio-qmp.c index adebf87e9b..3431711db5 100644 --- a/hw/virtio/virtio-qmp.c +++ b/hw/virtio/virtio-qmp.c @@ -30,6 +30,7 @@ #include "standard-headers/linux/virtio_iommu.h" #include "standard-headers/linux/virtio_mem.h" #include "standard-headers/linux/virtio_vsock.h" +#include "standard-headers/linux/virtio_gpio.h" #include CONFIG_DEVICES @@ -53,6 +54,7 @@ enum VhostUserProtocolFeature { VHOST_USER_PROTOCOL_F_RESET_DEVICE = 13, VHOST_USER_PROTOCOL_F_INBAND_NOTIFICATIONS = 14, VHOST_USER_PROTOCOL_F_CONFIGURE_MEM_SLOTS = 15, + VHOST_USER_PROTOCOL_F_STATUS = 16, VHOST_USER_PROTOCOL_F_MAX }; @@ -136,6 +138,9 @@ static const qmp_virtio_feature_map_t vhost_user_protocol_map[] = { FEATURE_ENTRY(VHOST_USER_PROTOCOL_F_CONFIGURE_MEM_SLOTS, \ "VHOST_USER_PROTOCOL_F_CONFIGURE_MEM_SLOTS: Configuration for " "memory slots supported"), + FEATURE_ENTRY(VHOST_USER_PROTOCOL_F_STATUS, \ + "VHOST_USER_PROTOCOL_F_STATUS: Querying and notifying back-end " + "device status supported"), { -1, "" } }; @@ -178,6 +183,8 @@ static const qmp_virtio_feature_map_t virtio_blk_feature_map[] = { "VIRTIO_BLK_F_DISCARD: Discard command supported"), FEATURE_ENTRY(VIRTIO_BLK_F_WRITE_ZEROES, \ "VIRTIO_BLK_F_WRITE_ZEROES: Write zeroes command supported"), + FEATURE_ENTRY(VIRTIO_BLK_F_SECURE_ERASE, \ + "VIRTIO_BLK_F_SECURE_ERASE: Secure erase supported"), FEATURE_ENTRY(VIRTIO_BLK_F_ZONED, \ "VIRTIO_BLK_F_ZONED: Zoned block devices"), #ifndef VIRTIO_BLK_NO_LEGACY @@ -301,6 +308,14 @@ static const qmp_virtio_feature_map_t virtio_net_feature_map[] = { FEATURE_ENTRY(VIRTIO_NET_F_CTRL_MAC_ADDR, \ "VIRTIO_NET_F_CTRL_MAC_ADDR: MAC address set through control " "channel"), + FEATURE_ENTRY(VIRTIO_NET_F_NOTF_COAL, \ + "VIRTIO_NET_F_NOTF_COAL: Device supports coalescing notifications"), + FEATURE_ENTRY(VIRTIO_NET_F_GUEST_USO4, \ + "VIRTIO_NET_F_GUEST_USO4: Driver can receive USOv4"), + FEATURE_ENTRY(VIRTIO_NET_F_GUEST_USO6, \ + "VIRTIO_NET_F_GUEST_USO4: Driver can receive USOv6"), + FEATURE_ENTRY(VIRTIO_NET_F_HOST_USO, \ + "VIRTIO_NET_F_HOST_USO: Device can receive USO"), FEATURE_ENTRY(VIRTIO_NET_F_HASH_REPORT, \ "VIRTIO_NET_F_HASH_REPORT: Hash reporting supported"), FEATURE_ENTRY(VIRTIO_NET_F_RSS, \ @@ -471,6 +486,18 @@ static const qmp_virtio_feature_map_t virtio_rng_feature_map[] = { }; #endif +/* virtio/vhost-gpio features mapping */ +#ifdef CONFIG_VHOST_USER_GPIO +static const qmp_virtio_feature_map_t virtio_gpio_feature_map[] = { + FEATURE_ENTRY(VIRTIO_GPIO_F_IRQ, \ + "VIRTIO_GPIO_F_IRQ: Device supports interrupts on GPIO lines"), + FEATURE_ENTRY(VHOST_USER_F_PROTOCOL_FEATURES, \ + "VHOST_USER_F_PROTOCOL_FEATURES: Vhost-user protocol features " + "negotiation supported"), + { -1, "" } +}; +#endif + #define CONVERT_FEATURES(type, map, is_status, bitmap) \ ({ \ type *list = NULL; \ @@ -627,6 +654,12 @@ VirtioDeviceFeatures *qmp_decode_features(uint16_t device_id, uint64_t bitmap) features->dev_features = CONVERT_FEATURES(strList, virtio_rng_feature_map, 0, bitmap); break; +#endif +#ifdef CONFIG_VHOST_USER_GPIO + case VIRTIO_ID_GPIO: + features->dev_features = + CONVERT_FEATURES(strList, virtio_gpio_feature_map, 0, bitmap); + break; #endif /* No features */ case VIRTIO_ID_9P: @@ -653,7 +686,6 @@ VirtioDeviceFeatures *qmp_decode_features(uint16_t device_id, uint64_t bitmap) case VIRTIO_ID_DMABUF: case VIRTIO_ID_PARAM_SERV: case VIRTIO_ID_AUDIO_POLICY: - case VIRTIO_ID_GPIO: break; default: g_assert_not_reached(); From 3d123a8b411706423581db7d26a7bbe548360751 Mon Sep 17 00:00:00 2001 From: Jonah Palmer Date: Tue, 26 Sep 2023 18:41:07 -0400 Subject: [PATCH 0234/1077] vhost-user: move VhostUserProtocolFeature definition to header file Move the definition of VhostUserProtocolFeature to include/hw/virtio/vhost-user.h. Remove previous definitions in hw/scsi/vhost-user-scsi.c, hw/virtio/vhost-user.c, and hw/virtio/virtio-qmp.c. Previously there were 3 separate definitions of this over 3 different files. Now only 1 definition of this will be present for these 3 files. Signed-off-by: Jonah Palmer Reviewed-by: Emmanouil Pitsidianakis Message-Id: <20230926224107.2951144-4-jonah.palmer@oracle.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/scsi/vhost-user-scsi.c | 4 ---- hw/virtio/vhost-user.c | 21 --------------------- hw/virtio/virtio-qmp.c | 22 +--------------------- include/hw/virtio/vhost-user.h | 21 +++++++++++++++++++++ 4 files changed, 22 insertions(+), 46 deletions(-) diff --git a/hw/scsi/vhost-user-scsi.c b/hw/scsi/vhost-user-scsi.c index ee99b19e7a..df6b66cc1a 100644 --- a/hw/scsi/vhost-user-scsi.c +++ b/hw/scsi/vhost-user-scsi.c @@ -39,10 +39,6 @@ static const int user_feature_bits[] = { VHOST_INVALID_FEATURE_BIT }; -enum VhostUserProtocolFeature { - VHOST_USER_PROTOCOL_F_RESET_DEVICE = 13, -}; - static void vhost_user_scsi_set_status(VirtIODevice *vdev, uint8_t status) { VHostUserSCSI *s = (VHostUserSCSI *)vdev; diff --git a/hw/virtio/vhost-user.c b/hw/virtio/vhost-user.c index 8dcf049d42..a096335921 100644 --- a/hw/virtio/vhost-user.c +++ b/hw/virtio/vhost-user.c @@ -56,27 +56,6 @@ */ #define VHOST_USER_MAX_CONFIG_SIZE 256 -enum VhostUserProtocolFeature { - VHOST_USER_PROTOCOL_F_MQ = 0, - VHOST_USER_PROTOCOL_F_LOG_SHMFD = 1, - VHOST_USER_PROTOCOL_F_RARP = 2, - VHOST_USER_PROTOCOL_F_REPLY_ACK = 3, - VHOST_USER_PROTOCOL_F_NET_MTU = 4, - VHOST_USER_PROTOCOL_F_BACKEND_REQ = 5, - VHOST_USER_PROTOCOL_F_CROSS_ENDIAN = 6, - VHOST_USER_PROTOCOL_F_CRYPTO_SESSION = 7, - VHOST_USER_PROTOCOL_F_PAGEFAULT = 8, - VHOST_USER_PROTOCOL_F_CONFIG = 9, - VHOST_USER_PROTOCOL_F_BACKEND_SEND_FD = 10, - VHOST_USER_PROTOCOL_F_HOST_NOTIFIER = 11, - VHOST_USER_PROTOCOL_F_INFLIGHT_SHMFD = 12, - VHOST_USER_PROTOCOL_F_RESET_DEVICE = 13, - /* Feature 14 reserved for VHOST_USER_PROTOCOL_F_INBAND_NOTIFICATIONS. */ - VHOST_USER_PROTOCOL_F_CONFIGURE_MEM_SLOTS = 15, - VHOST_USER_PROTOCOL_F_STATUS = 16, - VHOST_USER_PROTOCOL_F_MAX -}; - #define VHOST_USER_PROTOCOL_FEATURE_MASK ((1 << VHOST_USER_PROTOCOL_F_MAX) - 1) typedef enum VhostUserRequest { diff --git a/hw/virtio/virtio-qmp.c b/hw/virtio/virtio-qmp.c index 3431711db5..1dd96ed20f 100644 --- a/hw/virtio/virtio-qmp.c +++ b/hw/virtio/virtio-qmp.c @@ -17,6 +17,7 @@ #include "qapi/qapi-commands-qom.h" #include "qapi/qmp/qobject.h" #include "qapi/qmp/qjson.h" +#include "hw/virtio/vhost-user.h" #include "standard-headers/linux/virtio_ids.h" #include "standard-headers/linux/vhost_types.h" @@ -37,27 +38,6 @@ #define FEATURE_ENTRY(name, desc) (qmp_virtio_feature_map_t) \ { .virtio_bit = name, .feature_desc = desc } -enum VhostUserProtocolFeature { - VHOST_USER_PROTOCOL_F_MQ = 0, - VHOST_USER_PROTOCOL_F_LOG_SHMFD = 1, - VHOST_USER_PROTOCOL_F_RARP = 2, - VHOST_USER_PROTOCOL_F_REPLY_ACK = 3, - VHOST_USER_PROTOCOL_F_NET_MTU = 4, - VHOST_USER_PROTOCOL_F_BACKEND_REQ = 5, - VHOST_USER_PROTOCOL_F_CROSS_ENDIAN = 6, - VHOST_USER_PROTOCOL_F_CRYPTO_SESSION = 7, - VHOST_USER_PROTOCOL_F_PAGEFAULT = 8, - VHOST_USER_PROTOCOL_F_CONFIG = 9, - VHOST_USER_PROTOCOL_F_BACKEND_SEND_FD = 10, - VHOST_USER_PROTOCOL_F_HOST_NOTIFIER = 11, - VHOST_USER_PROTOCOL_F_INFLIGHT_SHMFD = 12, - VHOST_USER_PROTOCOL_F_RESET_DEVICE = 13, - VHOST_USER_PROTOCOL_F_INBAND_NOTIFICATIONS = 14, - VHOST_USER_PROTOCOL_F_CONFIGURE_MEM_SLOTS = 15, - VHOST_USER_PROTOCOL_F_STATUS = 16, - VHOST_USER_PROTOCOL_F_MAX -}; - /* Virtio transport features mapping */ static const qmp_virtio_feature_map_t virtio_transport_map[] = { /* Virtio device transport features */ diff --git a/include/hw/virtio/vhost-user.h b/include/hw/virtio/vhost-user.h index 191216a74f..80e2b4a463 100644 --- a/include/hw/virtio/vhost-user.h +++ b/include/hw/virtio/vhost-user.h @@ -11,6 +11,27 @@ #include "chardev/char-fe.h" #include "hw/virtio/virtio.h" +enum VhostUserProtocolFeature { + VHOST_USER_PROTOCOL_F_MQ = 0, + VHOST_USER_PROTOCOL_F_LOG_SHMFD = 1, + VHOST_USER_PROTOCOL_F_RARP = 2, + VHOST_USER_PROTOCOL_F_REPLY_ACK = 3, + VHOST_USER_PROTOCOL_F_NET_MTU = 4, + VHOST_USER_PROTOCOL_F_BACKEND_REQ = 5, + VHOST_USER_PROTOCOL_F_CROSS_ENDIAN = 6, + VHOST_USER_PROTOCOL_F_CRYPTO_SESSION = 7, + VHOST_USER_PROTOCOL_F_PAGEFAULT = 8, + VHOST_USER_PROTOCOL_F_CONFIG = 9, + VHOST_USER_PROTOCOL_F_BACKEND_SEND_FD = 10, + VHOST_USER_PROTOCOL_F_HOST_NOTIFIER = 11, + VHOST_USER_PROTOCOL_F_INFLIGHT_SHMFD = 12, + VHOST_USER_PROTOCOL_F_RESET_DEVICE = 13, + VHOST_USER_PROTOCOL_F_INBAND_NOTIFICATIONS = 14, + VHOST_USER_PROTOCOL_F_CONFIGURE_MEM_SLOTS = 15, + VHOST_USER_PROTOCOL_F_STATUS = 16, + VHOST_USER_PROTOCOL_F_MAX +}; + /** * VhostUserHostNotifier - notifier information for one queue * @rcu: rcu_head for cleanup From 969298f9d7ed0ccad39203bc3656805cbf0893d4 Mon Sep 17 00:00:00 2001 From: Tejus GK Date: Tue, 3 Oct 2023 06:55:37 +0000 Subject: [PATCH 0235/1077] migration/vmstate: Introduce vmstate_save_state_with_err Currently, a few code paths exist in the function vmstate_save_state_v, which ultimately leads to a migration failure. However, an update in the current MigrationState for the error description is never done. vmstate.c somehow doesn't seem to allow the use of migrate_set_error due to some dependencies for unit tests. Hence, this patch introduces a new function vmstate_save_state_with_err, which will eventually propagate the error message to savevm.c where a migrate_set_error call can be eventually done. Acked-by: Peter Xu Reviewed-by: Juan Quintela Signed-off-by: Tejus GK Signed-off-by: Juan Quintela Message-ID: <20231003065538.244752-2-tejus.gk@nutanix.com> --- include/migration/vmstate.h | 4 +++- migration/savevm.c | 2 +- migration/vmstate.c | 12 +++++++++--- 3 files changed, 13 insertions(+), 5 deletions(-) diff --git a/include/migration/vmstate.h b/include/migration/vmstate.h index e4db910339..1a31fb7293 100644 --- a/include/migration/vmstate.h +++ b/include/migration/vmstate.h @@ -1196,9 +1196,11 @@ int vmstate_load_state(QEMUFile *f, const VMStateDescription *vmsd, void *opaque, int version_id); int vmstate_save_state(QEMUFile *f, const VMStateDescription *vmsd, void *opaque, JSONWriter *vmdesc); +int vmstate_save_state_with_err(QEMUFile *f, const VMStateDescription *vmsd, + void *opaque, JSONWriter *vmdesc, Error **errp); int vmstate_save_state_v(QEMUFile *f, const VMStateDescription *vmsd, void *opaque, JSONWriter *vmdesc, - int version_id); + int version_id, Error **errp); bool vmstate_save_needed(const VMStateDescription *vmsd, void *opaque); diff --git a/migration/savevm.c b/migration/savevm.c index bb3e99194c..1f65294bf4 100644 --- a/migration/savevm.c +++ b/migration/savevm.c @@ -1000,7 +1000,7 @@ static int vmstate_save(QEMUFile *f, SaveStateEntry *se, JSONWriter *vmdesc) if (!se->vmsd) { vmstate_save_old_style(f, se, vmdesc); } else { - ret = vmstate_save_state(f, se->vmsd, se->opaque, vmdesc); + ret = vmstate_save_state_with_err(f, se->vmsd, se->opaque, vmdesc, &local_err); if (ret) { return ret; } diff --git a/migration/vmstate.c b/migration/vmstate.c index 438ea77cfa..dd9c76dbeb 100644 --- a/migration/vmstate.c +++ b/migration/vmstate.c @@ -315,11 +315,17 @@ bool vmstate_save_needed(const VMStateDescription *vmsd, void *opaque) int vmstate_save_state(QEMUFile *f, const VMStateDescription *vmsd, void *opaque, JSONWriter *vmdesc_id) { - return vmstate_save_state_v(f, vmsd, opaque, vmdesc_id, vmsd->version_id); + return vmstate_save_state_v(f, vmsd, opaque, vmdesc_id, vmsd->version_id, NULL); +} + +int vmstate_save_state_with_err(QEMUFile *f, const VMStateDescription *vmsd, + void *opaque, JSONWriter *vmdesc_id, Error **errp) +{ + return vmstate_save_state_v(f, vmsd, opaque, vmdesc_id, vmsd->version_id, errp); } int vmstate_save_state_v(QEMUFile *f, const VMStateDescription *vmsd, - void *opaque, JSONWriter *vmdesc, int version_id) + void *opaque, JSONWriter *vmdesc, int version_id, Error **errp) { int ret = 0; const VMStateField *field = vmsd->fields; @@ -377,7 +383,7 @@ int vmstate_save_state_v(QEMUFile *f, const VMStateDescription *vmsd, } else if (field->flags & VMS_VSTRUCT) { ret = vmstate_save_state_v(f, field->vmsd, curr_elem, vmdesc_loop, - field->struct_version_id); + field->struct_version_id, errp); } else { ret = field->info->put(f, curr_elem, size, field, vmdesc_loop); From 848a0503422d043d541130d5e3e2f7bc147cdef9 Mon Sep 17 00:00:00 2001 From: Tejus GK Date: Tue, 3 Oct 2023 06:55:38 +0000 Subject: [PATCH 0236/1077] migration: Update error description outside migration.c A few code paths exist in the source code,where a migration is marked as failed via MIGRATION_STATUS_FAILED, but the failure happens outside of migration.c In such cases, an error_report() call is made, however the current MigrationState is never updated with the error description, and hence clients like libvirt never know the actual reason for the failure. This patch covers such cases outside of migration.c and updates the error description at the appropriate places. Acked-by: Peter Xu Reviewed-by: Juan Quintela Signed-off-by: Tejus GK Signed-off-by: Juan Quintela Message-ID: <20231003065538.244752-3-tejus.gk@nutanix.com> --- migration/savevm.c | 17 ++++++++++++++--- migration/vmstate.c | 7 ++++--- 2 files changed, 18 insertions(+), 6 deletions(-) diff --git a/migration/savevm.c b/migration/savevm.c index 1f65294bf4..60eec7c31f 100644 --- a/migration/savevm.c +++ b/migration/savevm.c @@ -979,6 +979,8 @@ static void save_section_footer(QEMUFile *f, SaveStateEntry *se) static int vmstate_save(QEMUFile *f, SaveStateEntry *se, JSONWriter *vmdesc) { int ret; + Error *local_err = NULL; + MigrationState *s = migrate_get_current(); if ((!se->ops || !se->ops->save_state) && !se->vmsd) { return 0; @@ -1002,6 +1004,8 @@ static int vmstate_save(QEMUFile *f, SaveStateEntry *se, JSONWriter *vmdesc) } else { ret = vmstate_save_state_with_err(f, se->vmsd, se->opaque, vmdesc, &local_err); if (ret) { + migrate_set_error(s, local_err); + error_report_err(local_err); return ret; } } @@ -1068,10 +1072,14 @@ void qemu_savevm_send_open_return_path(QEMUFile *f) int qemu_savevm_send_packaged(QEMUFile *f, const uint8_t *buf, size_t len) { uint32_t tmp; + MigrationState *ms = migrate_get_current(); + Error *local_err = NULL; if (len > MAX_VM_CMD_PACKAGED_SIZE) { - error_report("%s: Unreasonably large packaged state: %zu", + error_setg(&local_err, "%s: Unreasonably large packaged state: %zu", __func__, len); + migrate_set_error(ms, local_err); + error_report_err(local_err); return -1; } @@ -1499,8 +1507,11 @@ int qemu_savevm_state_complete_precopy_non_iterable(QEMUFile *f, * bdrv_activate_all() on the other end won't fail. */ ret = bdrv_inactivate_all(); if (ret) { - error_report("%s: bdrv_inactivate_all() failed (%d)", - __func__, ret); + Error *local_err = NULL; + error_setg(&local_err, "%s: bdrv_inactivate_all() failed (%d)", + __func__, ret); + migrate_set_error(ms, local_err); + error_report_err(local_err); qemu_file_set_error(f, ret); return ret; } diff --git a/migration/vmstate.c b/migration/vmstate.c index dd9c76dbeb..4cde30bf2d 100644 --- a/migration/vmstate.c +++ b/migration/vmstate.c @@ -14,6 +14,7 @@ #include "migration.h" #include "migration/vmstate.h" #include "savevm.h" +#include "qapi/error.h" #include "qapi/qmp/json-writer.h" #include "qemu-file.h" #include "qemu/bitops.h" @@ -336,7 +337,7 @@ int vmstate_save_state_v(QEMUFile *f, const VMStateDescription *vmsd, ret = vmsd->pre_save(opaque); trace_vmstate_save_state_pre_save_res(vmsd->name, ret); if (ret) { - error_report("pre-save failed: %s", vmsd->name); + error_setg(errp, "pre-save failed: %s", vmsd->name); return ret; } } @@ -389,8 +390,8 @@ int vmstate_save_state_v(QEMUFile *f, const VMStateDescription *vmsd, vmdesc_loop); } if (ret) { - error_report("Save of field %s/%s failed", - vmsd->name, field->name); + error_setg(errp, "Save of field %s/%s failed", + vmsd->name, field->name); if (vmsd->post_save) { vmsd->post_save(opaque); } From 8ebcb4b31264a1b2e87f7c61c2d746be1974b333 Mon Sep 17 00:00:00 2001 From: Peter Xu Date: Mon, 25 Sep 2023 09:34:41 -0400 Subject: [PATCH 0237/1077] MAINTAINERS: Add entry for rdma migration MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit It's not obvious to many that RDMA migration is in Odd Fixes stage for a long time. Add an explicit sub entry for it (besides migration, which already covers the rdma files) to be clear on that, meanwhile add Zhijian as Reviewer, so Zhijian can see the patches and review when he still has the bandwidth. Cc: Daniel P. Berrangé Cc: Juan Quintela Cc: Markus Armbruster Cc: Zhijian Li (Fujitsu) Cc: Fabiano Rosas Acked-by: Li Zhijian Reviewed-by: Juan Quintela Signed-off-by: Peter Xu Signed-off-by: Juan Quintela Message-ID: <20230925133441.265455-1-peterx@redhat.com> --- MAINTAINERS | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/MAINTAINERS b/MAINTAINERS index 81625f036b..af730a327c 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -3222,6 +3222,15 @@ F: docs/devel/migration.rst F: qapi/migration.json F: tests/migration/ F: util/userfaultfd.c +X: migration/rdma* + +RDMA Migration +M: Juan Quintela +R: Li Zhijian +R: Peter Xu +R: Leonardo Bras +S: Odd Fixes +F: migration/rdma* Migration dirty limit and dirty page rate M: Hyman Huang From 2bace555b3bd7bb38a58b9862016c4528b331fdb Mon Sep 17 00:00:00 2001 From: Peter Xu Date: Tue, 3 Oct 2023 10:38:47 -0400 Subject: [PATCH 0238/1077] migration: Add co-maintainers for migration MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Per the qemu upstream call a few hours ago, proposing Fabiano and myself as the co-maintainer for migration subsystem to help Juan. Cc: Fabiano Rosas Cc: Juan Quintela Acked-by: Fabiano Rosas Reviewed-by: Juan Quintela Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Peter Xu Signed-off-by: Juan Quintela Message-ID: <20231003143847.9245-1-peterx@redhat.com> --- MAINTAINERS | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/MAINTAINERS b/MAINTAINERS index af730a327c..79db298787 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -3207,7 +3207,8 @@ F: scripts/checkpatch.pl Migration M: Juan Quintela -R: Peter Xu +M: Peter Xu +M: Fabiano Rosas R: Leonardo Bras S: Maintained F: hw/core/vmstate-if.c From 2ada4b63f1764d13a2b9ca9cbeb5feda46ab6851 Mon Sep 17 00:00:00 2001 From: Li Zhijian Date: Tue, 26 Sep 2023 18:01:03 +0800 Subject: [PATCH 0239/1077] migration/rdma: zore out head.repeat to make the error more clear Previously, we got a confusion error that complains the RDMAControlHeader.repeat: qemu-system-x86_64: rdma: Too many requests in this message (3638950032).Bailing. Actually, it's caused by an unexpected RDMAControlHeader.type. After this patch, error will become: qemu-system-x86_64: Unknown control message QEMU FILE Reviewed-by: Fabiano Rosas Reviewed-by: Peter Xu Reviewed-by: Juan Quintela Signed-off-by: Li Zhijian Signed-off-by: Juan Quintela Message-ID: <20230926100103.201564-2-lizhijian@fujitsu.com> --- migration/rdma.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/migration/rdma.c b/migration/rdma.c index 7d2726d5b6..cd5e1afe60 100644 --- a/migration/rdma.c +++ b/migration/rdma.c @@ -2831,7 +2831,7 @@ static ssize_t qio_channel_rdma_writev(QIOChannel *ioc, size_t remaining = iov[i].iov_len; uint8_t * data = (void *)iov[i].iov_base; while (remaining) { - RDMAControlHeader head; + RDMAControlHeader head = {}; len = MIN(remaining, RDMA_SEND_INCREMENT); remaining -= len; From 67aeae794e51b3238ced158218edf443f8607626 Mon Sep 17 00:00:00 2001 From: Daniil Tatianin Date: Tue, 19 Sep 2023 13:23:44 +0300 Subject: [PATCH 0240/1077] i386/a-b-bootblock: factor test memory addresses out into constants So that we have less magic numbers to deal with. This also allows us to reuse these in the following commits. Reviewed-by: Peter Xu Reviewed-by: Vladimir Sementsov-Ogievskiy Reviewed-by: Juan Quintela Signed-off-by: Daniil Tatianin Signed-off-by: Juan Quintela Message-ID: <20230919102346.2117963-2-d-tatianin@yandex-team.ru> --- tests/migration/i386/a-b-bootblock.S | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/tests/migration/i386/a-b-bootblock.S b/tests/migration/i386/a-b-bootblock.S index 3d464c7568..036216e4a7 100644 --- a/tests/migration/i386/a-b-bootblock.S +++ b/tests/migration/i386/a-b-bootblock.S @@ -34,6 +34,10 @@ start: # at 0x7c00 ? mov $16,%eax mov %eax,%ds +# Start from 1MB +.set TEST_MEM_START, (1024*1024) +.set TEST_MEM_END, (100*1024*1024) + mov $65,%ax mov $0x3f8,%dx outb %al,%dx @@ -41,12 +45,11 @@ start: # at 0x7c00 ? # bl keeps a counter so we limit the output speed mov $0, %bl mainloop: - # Start from 1MB - mov $(1024*1024),%eax + mov $TEST_MEM_START,%eax innerloop: incb (%eax) add $4096,%eax - cmp $(100*1024*1024),%eax + cmp $TEST_MEM_END,%eax jl innerloop inc %bl From adc1914a403e0ec89ebec4761ec8427668261c5b Mon Sep 17 00:00:00 2001 From: Daniil Tatianin Date: Tue, 19 Sep 2023 13:23:45 +0300 Subject: [PATCH 0241/1077] i386/a-b-bootblock: zero the first byte of each page on start The migration qtest all the way up to this point used to work by sheer luck relying on the contents of all pages from 1MiB to 100MiB to contain the same one value in the first byte initially. This easily breaks if we reduce the amount of RAM for the test instances from 150MiB to e.g 110MiB since that makes SeaBIOS dirty some of the pages starting at about 0x5dd2000 (~93 MiB) as it reuses those for the HighMemory allocator since commit dc88f9b72df ("malloc: use large ZoneHigh when there is enough memory"). This would result in the following errors: 12/60 qemu:qtest+qtest-x86_64 / qtest-x86_64/migration-test ERROR 2.74s killed by signal 6 SIGABRT stderr: Memory content inconsistency at 5dd2000 first_byte = cc last_byte = cb current = 9e hit_edge = 1 Memory content inconsistency at 5dd3000 first_byte = cc last_byte = cb current = 89 hit_edge = 1 Memory content inconsistency at 5dd4000 first_byte = cc last_byte = cb current = 23 hit_edge = 1 Memory content inconsistency at 5dd5000 first_byte = cc last_byte = cb current = 31 hit_edge = 1 Memory content inconsistency at 5dd6000 first_byte = cc last_byte = cb current = 70 hit_edge = 1 Memory content inconsistency at 5dd7000 first_byte = cc last_byte = cb current = ff hit_edge = 1 Memory content inconsistency at 5dd8000 first_byte = cc last_byte = cb current = 54 hit_edge = 1 Memory content inconsistency at 5dd9000 first_byte = cc last_byte = cb current = 64 hit_edge = 1 Memory content inconsistency at 5dda000 first_byte = cc last_byte = cb current = 1d hit_edge = 1 Memory content inconsistency at 5ddb000 first_byte = cc last_byte = cb current = 1a hit_edge = 1 and in another 26 pages** ERROR:../tests/qtest/migration-test.c:300:check_guests_ram: assertion failed: (bad == 0) Fix this by always zeroing the first byte of each page in the range so that we get consistent results no matter the initial contents. Fixes: ea0c6d62391 ("test: Postcopy") Signed-off-by: Daniil Tatianin Reviewed-by: Peter Xu Reviewed-by: Vladimir Sementsov-Ogievskiy Reviewed-by: Juan Quintela Signed-off-by: Juan Quintela Message-ID: <20230919102346.2117963-3-d-tatianin@yandex-team.ru> --- tests/migration/i386/a-b-bootblock.S | 9 +++++++++ tests/migration/i386/a-b-bootblock.h | 16 ++++++++-------- 2 files changed, 17 insertions(+), 8 deletions(-) diff --git a/tests/migration/i386/a-b-bootblock.S b/tests/migration/i386/a-b-bootblock.S index 036216e4a7..6bb9999d60 100644 --- a/tests/migration/i386/a-b-bootblock.S +++ b/tests/migration/i386/a-b-bootblock.S @@ -44,6 +44,15 @@ start: # at 0x7c00 ? # bl keeps a counter so we limit the output speed mov $0, %bl + +pre_zero: + mov $TEST_MEM_START,%eax +do_zero: + movb $0, (%eax) + add $4096,%eax + cmp $TEST_MEM_END,%eax + jl do_zero + mainloop: mov $TEST_MEM_START,%eax innerloop: diff --git a/tests/migration/i386/a-b-bootblock.h b/tests/migration/i386/a-b-bootblock.h index b7b0fce2ee..5b523917ce 100644 --- a/tests/migration/i386/a-b-bootblock.h +++ b/tests/migration/i386/a-b-bootblock.h @@ -4,18 +4,18 @@ * the header and the assembler differences in your patch submission. */ unsigned char x86_bootsect[] = { - 0xfa, 0x0f, 0x01, 0x16, 0x78, 0x7c, 0x66, 0xb8, 0x01, 0x00, 0x00, 0x00, + 0xfa, 0x0f, 0x01, 0x16, 0x8c, 0x7c, 0x66, 0xb8, 0x01, 0x00, 0x00, 0x00, 0x0f, 0x22, 0xc0, 0x66, 0xea, 0x20, 0x7c, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe4, 0x92, 0x0c, 0x02, 0xe6, 0x92, 0xb8, 0x10, 0x00, 0x00, 0x00, 0x8e, 0xd8, 0x66, 0xb8, 0x41, 0x00, 0x66, 0xba, 0xf8, 0x03, 0xee, 0xb3, 0x00, 0xb8, 0x00, 0x00, 0x10, - 0x00, 0xfe, 0x00, 0x05, 0x00, 0x10, 0x00, 0x00, 0x3d, 0x00, 0x00, 0x40, - 0x06, 0x7c, 0xf2, 0xfe, 0xc3, 0x80, 0xe3, 0x3f, 0x75, 0xe6, 0x66, 0xb8, - 0x42, 0x00, 0x66, 0xba, 0xf8, 0x03, 0xee, 0xeb, 0xdb, 0x8d, 0x76, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, - 0x00, 0x9a, 0xcf, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x92, 0xcf, 0x00, - 0x27, 0x00, 0x60, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xc6, 0x00, 0x00, 0x05, 0x00, 0x10, 0x00, 0x00, 0x3d, 0x00, 0x00, + 0x40, 0x06, 0x7c, 0xf1, 0xb8, 0x00, 0x00, 0x10, 0x00, 0xfe, 0x00, 0x05, + 0x00, 0x10, 0x00, 0x00, 0x3d, 0x00, 0x00, 0x40, 0x06, 0x7c, 0xf2, 0xfe, + 0xc3, 0x80, 0xe3, 0x3f, 0x75, 0xe6, 0x66, 0xb8, 0x42, 0x00, 0x66, 0xba, + 0xf8, 0x03, 0xee, 0xeb, 0xdb, 0x8d, 0x76, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x9a, 0xcf, 0x00, + 0xff, 0xff, 0x00, 0x00, 0x00, 0x92, 0xcf, 0x00, 0x27, 0x00, 0x74, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, From b28e3ecf0de1bc77b6a1a520e3c223f37b5afce2 Mon Sep 17 00:00:00 2001 From: Daniil Tatianin Date: Tue, 19 Sep 2023 13:23:46 +0300 Subject: [PATCH 0242/1077] s390x/a-b-bios: zero the first byte of each page on start Same as with the x86 verison of this test, we relied on the contents of all pages in RAM to be the same across the entire test range, which is very fragile. Zero the first byte of each page before running the increment loop to fix this. Fixes: 5571dc824b ("tests/migration: Enable the migration test on s390x, too") Reviewed-by: Vladimir Sementsov-Ogievskiy Reviewed-by: Peter Xu Reviewed-by: Juan Quintela Signed-off-by: Daniil Tatianin Signed-off-by: Juan Quintela Message-ID: <20230919102346.2117963-4-d-tatianin@yandex-team.ru> --- tests/migration/s390x/a-b-bios.c | 8 + tests/migration/s390x/a-b-bios.h | 398 ++++++++++++++++--------------- 2 files changed, 220 insertions(+), 186 deletions(-) diff --git a/tests/migration/s390x/a-b-bios.c b/tests/migration/s390x/a-b-bios.c index a0327cd153..ff99a3ef57 100644 --- a/tests/migration/s390x/a-b-bios.c +++ b/tests/migration/s390x/a-b-bios.c @@ -27,6 +27,14 @@ void main(void) sclp_setup(); sclp_print("A"); + /* + * Make sure all of the pages have consistent contents before incrementing + * the first byte below. + */ + for (addr = START_ADDRESS; addr < END_ADDRESS; addr += 4096) { + *(volatile char *)addr = 0; + } + while (1) { for (addr = START_ADDRESS; addr < END_ADDRESS; addr += 4096) { *(volatile char *)addr += 1; /* Change pages */ diff --git a/tests/migration/s390x/a-b-bios.h b/tests/migration/s390x/a-b-bios.h index e722dc7c40..96103dadbb 100644 --- a/tests/migration/s390x/a-b-bios.h +++ b/tests/migration/s390x/a-b-bios.h @@ -6,10 +6,10 @@ unsigned char s390x_elf[] = { 0x7f, 0x45, 0x4c, 0x46, 0x02, 0x02, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x16, 0x00, 0x00, 0x00, 0x01, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x78, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x80, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xa8, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x38, 0x00, 0x07, 0x00, 0x40, - 0x00, 0x0c, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x04, + 0x00, 0x0d, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x88, 0x00, 0x00, 0x00, 0x00, @@ -21,140 +21,154 @@ unsigned char s390x_elf[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x0c, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x0c, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xac, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xac, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x06, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x10, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x17, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x17, 0x10, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe8, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x98, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xb8, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x17, 0xb8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x17, 0xb8, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x38, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x01, 0x18, 0x48, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x07, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x17, 0x10, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x17, 0x10, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0xd0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd0, + 0x00, 0x00, 0x07, 0xb8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x17, 0xb8, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x17, 0xb8, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x01, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x64, 0x74, 0xe5, 0x51, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x64, 0x74, 0xe5, 0x52, 0x00, 0x00, 0x00, 0x04, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x10, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x17, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x17, 0x10, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd0, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0xd0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xb8, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x17, 0xb8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x17, 0xb8, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x38, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x01, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x2f, 0x6c, 0x69, 0x62, 0x2f, 0x6c, 0x64, 0x36, 0x34, 0x2e, 0x73, 0x6f, 0x2e, 0x31, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x02, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xeb, 0xef, 0xf0, 0x70, - 0x00, 0x24, 0xa7, 0xfb, 0xff, 0x60, 0xc0, 0xe5, 0x00, 0x00, 0x01, 0x1f, - 0xc0, 0x20, 0x00, 0x00, 0x02, 0x64, 0xc0, 0xe5, 0x00, 0x00, 0x01, 0x35, - 0xa5, 0x1e, 0x00, 0x10, 0xa7, 0x29, 0x63, 0x00, 0xe3, 0x30, 0x10, 0x00, - 0x00, 0x90, 0xa7, 0x3a, 0x00, 0x01, 0x42, 0x30, 0x10, 0x00, 0xa7, 0x1b, - 0x10, 0x00, 0xa7, 0x27, 0xff, 0xf7, 0xc0, 0x20, 0x00, 0x00, 0x02, 0x50, - 0xa7, 0xf4, 0xff, 0xeb, 0x07, 0x07, 0x07, 0x07, 0xc0, 0xf0, 0x00, 0x00, - 0x56, 0xc4, 0xc0, 0x20, 0x00, 0x00, 0x0a, 0xbd, 0xc0, 0x30, 0x00, 0x00, - 0x56, 0xbe, 0xb9, 0x0b, 0x00, 0x32, 0xb9, 0x02, 0x00, 0x33, 0xa7, 0x84, - 0x00, 0x19, 0xa7, 0x3b, 0xff, 0xff, 0xeb, 0x43, 0x00, 0x08, 0x00, 0x0c, - 0xb9, 0x02, 0x00, 0x44, 0xb9, 0x04, 0x00, 0x12, 0xa7, 0x84, 0x00, 0x09, - 0xd7, 0xff, 0x10, 0x00, 0x10, 0x00, 0x41, 0x10, 0x11, 0x00, 0xa7, 0x47, - 0xff, 0xfb, 0xc0, 0x20, 0x00, 0x00, 0x00, 0x07, 0x44, 0x30, 0x20, 0x00, - 0xa7, 0xf4, 0xff, 0xb6, 0xd7, 0x00, 0x10, 0x00, 0x10, 0x00, 0xc0, 0x10, - 0x00, 0x00, 0x00, 0x29, 0xb2, 0xb2, 0x10, 0x00, 0xeb, 0x00, 0xf0, 0x00, - 0x00, 0x25, 0x96, 0x02, 0xf0, 0x06, 0xeb, 0x00, 0xf0, 0x00, 0x00, 0x2f, - 0xc0, 0x10, 0x00, 0x00, 0x00, 0x11, 0xe3, 0x10, 0x01, 0xb8, 0x00, 0x24, - 0xc0, 0x10, 0x00, 0x00, 0x00, 0x26, 0xd2, 0x07, 0x01, 0xb0, 0x10, 0x00, - 0xc0, 0x10, 0x00, 0x00, 0x00, 0x18, 0xb2, 0xb2, 0x10, 0x00, 0xeb, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x02, 0x48, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x03, 0xa8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0xf0, 0xeb, 0xef, 0xf0, 0x70, + 0x00, 0x24, 0xa7, 0xfb, 0xff, 0x60, 0xc0, 0xe5, 0x00, 0x00, 0x01, 0x5f, + 0xc0, 0x20, 0x00, 0x00, 0x02, 0xa8, 0xc0, 0xe5, 0x00, 0x00, 0x01, 0x75, + 0xa5, 0x2e, 0x00, 0x10, 0xa7, 0x19, 0x63, 0x00, 0x92, 0x00, 0x20, 0x00, + 0xa7, 0x2b, 0x10, 0x00, 0xa7, 0x17, 0xff, 0xfc, 0xa5, 0x1e, 0x00, 0x10, + 0xa7, 0x29, 0x63, 0x00, 0xe3, 0x30, 0x10, 0x00, 0x00, 0x90, 0xa7, 0x3a, + 0x00, 0x01, 0x42, 0x30, 0x10, 0x00, 0xa7, 0x1b, 0x10, 0x00, 0xa7, 0x27, + 0xff, 0xf7, 0xc0, 0x20, 0x00, 0x00, 0x02, 0x8a, 0xc0, 0xe5, 0x00, 0x00, + 0x01, 0x56, 0xa7, 0xf4, 0xff, 0xeb, 0x07, 0x07, 0xc0, 0xf0, 0x00, 0x00, + 0x4e, 0x5c, 0xc0, 0x20, 0x00, 0x00, 0x00, 0x7d, 0xe3, 0x20, 0x20, 0x00, + 0x00, 0x04, 0xc0, 0x30, 0x00, 0x00, 0x96, 0xa3, 0xb9, 0x0b, 0x00, 0x32, + 0xb9, 0x02, 0x00, 0x33, 0xa7, 0x84, 0x00, 0x19, 0xa7, 0x3b, 0xff, 0xff, + 0xeb, 0x43, 0x00, 0x08, 0x00, 0x0c, 0xb9, 0x02, 0x00, 0x44, 0xb9, 0x04, + 0x00, 0x12, 0xa7, 0x84, 0x00, 0x09, 0xd7, 0xff, 0x10, 0x00, 0x10, 0x00, + 0x41, 0x10, 0x11, 0x00, 0xa7, 0x47, 0xff, 0xfb, 0xc0, 0x20, 0x00, 0x00, + 0x00, 0x0d, 0x44, 0x30, 0x20, 0x00, 0xc0, 0x20, 0x00, 0x00, 0x00, 0x5b, + 0xd2, 0x0f, 0x01, 0xd0, 0x20, 0x00, 0xa7, 0xf4, 0xff, 0xa1, 0xd7, 0x00, + 0x10, 0x00, 0x10, 0x00, 0xc0, 0x10, 0x00, 0x00, 0x00, 0x50, 0xb2, 0xb2, + 0x10, 0x00, 0xa7, 0xf4, 0x00, 0x00, 0xeb, 0x00, 0xf0, 0x00, 0x00, 0x25, + 0x96, 0x02, 0xf0, 0x06, 0xeb, 0x00, 0xf0, 0x00, 0x00, 0x2f, 0xc0, 0x10, + 0x00, 0x00, 0x00, 0x2a, 0xe3, 0x10, 0x01, 0xb8, 0x00, 0x24, 0xc0, 0x10, + 0x00, 0x00, 0x00, 0x4b, 0xd2, 0x07, 0x01, 0xb0, 0x10, 0x00, 0xc0, 0x10, + 0x00, 0x00, 0x00, 0x3d, 0xb2, 0xb2, 0x10, 0x00, 0xeb, 0x66, 0xf0, 0x00, + 0x00, 0x25, 0x96, 0xff, 0xf0, 0x04, 0xeb, 0x66, 0xf0, 0x00, 0x00, 0x2f, + 0xc0, 0x10, 0x00, 0x00, 0x00, 0x1a, 0xe3, 0x10, 0x01, 0xf8, 0x00, 0x24, + 0xc0, 0x10, 0x00, 0x00, 0x00, 0x36, 0xd2, 0x07, 0x01, 0xf0, 0x10, 0x00, + 0xc0, 0x10, 0x00, 0x00, 0x00, 0x24, 0xb2, 0xb2, 0x10, 0x00, 0xeb, 0x00, 0xf0, 0x00, 0x00, 0x25, 0x94, 0xfd, 0xf0, 0x06, 0xeb, 0x00, 0xf0, 0x00, - 0x00, 0x2f, 0x07, 0xfe, 0x07, 0x07, 0x07, 0x07, 0x00, 0x02, 0x00, 0x01, + 0x00, 0x2f, 0x07, 0xfe, 0xeb, 0x66, 0xf0, 0x00, 0x00, 0x25, 0x94, 0x00, + 0xf0, 0x04, 0xeb, 0x66, 0xf0, 0x00, 0x00, 0x2f, 0x07, 0xfe, 0x07, 0x07, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0xf0, 0x00, 0x02, 0x00, 0x01, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x02, 0x00, 0x01, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x80, 0x00, 0x00, 0x00, - 0xeb, 0xbf, 0xf0, 0x58, 0x00, 0x24, 0xc0, 0x10, 0x00, 0x00, 0x0e, 0x59, - 0xa7, 0xfb, 0xff, 0x60, 0xb2, 0x20, 0x00, 0x21, 0xb2, 0x22, 0x00, 0xb0, - 0x88, 0xb0, 0x00, 0x1c, 0xc0, 0xe5, 0xff, 0xff, 0xff, 0xba, 0xa7, 0xbe, - 0x00, 0x03, 0xa7, 0x84, 0x00, 0x13, 0xa7, 0xbe, 0x00, 0x02, 0xa7, 0x28, - 0x00, 0x00, 0xa7, 0x74, 0x00, 0x04, 0xa7, 0x28, 0xff, 0xfe, 0xe3, 0x40, - 0xf1, 0x10, 0x00, 0x04, 0xb9, 0x14, 0x00, 0x22, 0xeb, 0xbf, 0xf0, 0xf8, - 0x00, 0x04, 0x07, 0xf4, 0xa7, 0x28, 0xff, 0xff, 0xa7, 0xf4, 0xff, 0xf5, - 0x07, 0x07, 0x07, 0x07, 0xeb, 0xbf, 0xf0, 0x58, 0x00, 0x24, 0xc0, 0xd0, - 0x00, 0x00, 0x01, 0x21, 0xa7, 0xfb, 0xff, 0x60, 0xa7, 0xb9, 0x00, 0x00, - 0xa7, 0x19, 0x00, 0x00, 0xc0, 0x40, 0x00, 0x00, 0x0e, 0x24, 0xa7, 0x3b, - 0x00, 0x01, 0xa7, 0x37, 0x00, 0x23, 0xc0, 0x20, 0x00, 0x00, 0x0e, 0x1d, - 0x18, 0x31, 0xa7, 0x1a, 0x00, 0x06, 0x40, 0x10, 0x20, 0x08, 0xa7, 0x3a, - 0x00, 0x0e, 0xa7, 0x18, 0x1a, 0x00, 0x40, 0x30, 0x20, 0x00, 0x92, 0x00, - 0x20, 0x02, 0x40, 0x10, 0x20, 0x0a, 0xe3, 0x20, 0xd0, 0x00, 0x00, 0x04, - 0xc0, 0xe5, 0xff, 0xff, 0xff, 0xac, 0xe3, 0x40, 0xf1, 0x10, 0x00, 0x04, - 0xb9, 0x04, 0x00, 0x2b, 0xeb, 0xbf, 0xf0, 0xf8, 0x00, 0x04, 0x07, 0xf4, - 0xb9, 0x04, 0x00, 0x51, 0xa7, 0x5b, 0x00, 0x01, 0xa7, 0x09, 0x0f, 0xf7, - 0xb9, 0x21, 0x00, 0x50, 0xa7, 0x24, 0xff, 0xd7, 0x41, 0xeb, 0x20, 0x00, - 0x95, 0x0a, 0xe0, 0x00, 0xa7, 0x74, 0x00, 0x08, 0x41, 0x11, 0x40, 0x0e, - 0x92, 0x0d, 0x10, 0x00, 0xb9, 0x04, 0x00, 0x15, 0x43, 0x5b, 0x20, 0x00, - 0x42, 0x51, 0x40, 0x0e, 0xa7, 0xbb, 0x00, 0x01, 0x41, 0x10, 0x10, 0x01, - 0xa7, 0xf4, 0xff, 0xbf, 0xc0, 0x50, 0x00, 0x00, 0x00, 0xd4, 0xc0, 0x10, - 0x00, 0x00, 0x0d, 0xd9, 0xa7, 0x48, 0x00, 0x1c, 0x40, 0x40, 0x10, 0x00, - 0x50, 0x20, 0x10, 0x0c, 0xa7, 0x48, 0x00, 0x04, 0xe3, 0x20, 0x50, 0x00, - 0x00, 0x04, 0x40, 0x40, 0x10, 0x0a, 0x50, 0x30, 0x10, 0x10, 0xc0, 0xf4, - 0xff, 0xff, 0xff, 0x6b, 0xa7, 0x39, 0x00, 0x40, 0xa7, 0x29, 0x00, 0x00, - 0xc0, 0xf4, 0xff, 0xff, 0xff, 0xe4, 0x07, 0x07, 0xb9, 0x04, 0x00, 0x13, - 0xa7, 0x2a, 0xff, 0xff, 0xb9, 0x04, 0x00, 0x34, 0xa7, 0x48, 0x00, 0x01, - 0x15, 0x24, 0xa7, 0x24, 0x00, 0x07, 0xb9, 0x04, 0x00, 0x21, 0xc0, 0xf4, - 0xff, 0xff, 0xff, 0x7f, 0xa7, 0x29, 0xff, 0xff, 0x07, 0xfe, 0x07, 0x07, - 0xa7, 0x39, 0x00, 0x00, 0x41, 0x13, 0x20, 0x00, 0x95, 0x00, 0x10, 0x00, - 0xa7, 0x74, 0x00, 0x05, 0xc0, 0xf4, 0xff, 0xff, 0xff, 0x70, 0xa7, 0x3b, - 0x00, 0x01, 0xa7, 0xf4, 0xff, 0xf5, 0x07, 0x07, 0xeb, 0xbf, 0xf0, 0x58, - 0x00, 0x24, 0xc0, 0xd0, 0x00, 0x00, 0x00, 0x91, 0xa7, 0xfb, 0xff, 0x60, - 0xb9, 0x04, 0x00, 0xb2, 0xa7, 0x19, 0x00, 0x20, 0xc0, 0x20, 0x00, 0x00, - 0x0d, 0x8c, 0x92, 0x00, 0x20, 0x00, 0xa7, 0x2b, 0x00, 0x01, 0xa7, 0x17, - 0xff, 0xfc, 0xc0, 0x10, 0x00, 0x00, 0x0d, 0x83, 0xa7, 0x28, 0x00, 0x20, - 0x40, 0x20, 0x10, 0x00, 0xe3, 0x20, 0xd0, 0x00, 0x00, 0x04, 0xc0, 0xe5, - 0xff, 0xff, 0xff, 0x1d, 0x12, 0x22, 0xa7, 0x74, 0x00, 0x17, 0xa7, 0x19, - 0x00, 0x00, 0xc0, 0x40, 0x00, 0x00, 0x00, 0x75, 0xc0, 0x50, 0x00, 0x00, - 0x0d, 0x7a, 0xa7, 0x29, 0x00, 0x08, 0xe3, 0x31, 0x50, 0x00, 0x00, 0x90, - 0x43, 0x33, 0x40, 0x00, 0x42, 0x31, 0xb0, 0x00, 0xa7, 0x1b, 0x00, 0x01, - 0xa7, 0x27, 0xff, 0xf7, 0xe3, 0x40, 0xf1, 0x10, 0x00, 0x04, 0xeb, 0xbf, - 0xf0, 0xf8, 0x00, 0x04, 0x07, 0xf4, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, - 0xeb, 0xaf, 0xf0, 0x50, 0x00, 0x24, 0xc0, 0xd0, 0x00, 0x00, 0x00, 0x51, - 0xa7, 0xfb, 0xff, 0x60, 0xa7, 0x19, 0x0f, 0xf8, 0xb9, 0x21, 0x00, 0x31, - 0xb9, 0x04, 0x00, 0xa2, 0xa7, 0xc4, 0x00, 0x2d, 0xa7, 0xb9, 0x0f, 0xf8, - 0xc0, 0x10, 0x00, 0x00, 0x0d, 0x42, 0xa7, 0x28, 0x10, 0x00, 0x40, 0x20, - 0x10, 0x00, 0x92, 0x00, 0x10, 0x02, 0xe3, 0x20, 0xd0, 0x00, 0x00, 0x04, - 0xc0, 0xe5, 0xff, 0xff, 0xfe, 0xda, 0xa7, 0xbb, 0x00, 0x01, 0xa7, 0x19, - 0x00, 0x00, 0xc0, 0x20, 0x00, 0x00, 0x0d, 0x2f, 0xa7, 0xb7, 0x00, 0x17, - 0xc0, 0x10, 0x00, 0x00, 0x0d, 0x2a, 0xe3, 0x40, 0xf1, 0x10, 0x00, 0x04, - 0xe3, 0x20, 0x10, 0x08, 0x00, 0x91, 0xa7, 0x2a, 0xff, 0xf9, 0xb9, 0x14, - 0x00, 0x22, 0xeb, 0xaf, 0xf0, 0xf0, 0x00, 0x04, 0x07, 0xf4, 0xb9, 0x04, - 0x00, 0xb3, 0xa7, 0xf4, 0xff, 0xd5, 0x43, 0x31, 0x20, 0x0f, 0x42, 0x31, - 0xa0, 0x00, 0xa7, 0x1b, 0x00, 0x01, 0xa7, 0xf4, 0xff, 0xe3, 0x07, 0x07, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x76, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x78, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x01, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, 0x00, 0x05, 0x2e, 0x2e, 0x2e, 0x2e, + 0x00, 0x00, 0x00, 0x01, 0x80, 0x00, 0x00, 0x00, 0xeb, 0xbf, 0xf0, 0x58, + 0x00, 0x24, 0xc0, 0x10, 0x00, 0x00, 0x4e, 0x0d, 0xa7, 0xfb, 0xff, 0x60, + 0xb2, 0x20, 0x00, 0x21, 0xb2, 0x22, 0x00, 0xb0, 0x88, 0xb0, 0x00, 0x1c, + 0xc0, 0xe5, 0xff, 0xff, 0xff, 0x91, 0xa7, 0xbe, 0x00, 0x03, 0xa7, 0x84, + 0x00, 0x13, 0xa7, 0xbe, 0x00, 0x02, 0xa7, 0x28, 0x00, 0x00, 0xa7, 0x74, + 0x00, 0x04, 0xa7, 0x28, 0xff, 0xfe, 0xe3, 0x40, 0xf1, 0x10, 0x00, 0x04, + 0xb9, 0x14, 0x00, 0x22, 0xeb, 0xbf, 0xf0, 0xf8, 0x00, 0x04, 0x07, 0xf4, + 0xa7, 0x28, 0xff, 0xff, 0xa7, 0xf4, 0xff, 0xf5, 0x07, 0x07, 0x07, 0x07, + 0xeb, 0xbf, 0xf0, 0x58, 0x00, 0x24, 0xc0, 0xd0, 0x00, 0x00, 0x01, 0x25, + 0xa7, 0xfb, 0xff, 0x60, 0xa7, 0xb9, 0x00, 0x00, 0xa7, 0x19, 0x00, 0x00, + 0xc0, 0x40, 0x00, 0x00, 0x4d, 0xd8, 0xa7, 0x3b, 0x00, 0x01, 0xa7, 0x37, + 0x00, 0x23, 0xc0, 0x20, 0x00, 0x00, 0x4d, 0xd1, 0x18, 0x31, 0xa7, 0x1a, + 0x00, 0x06, 0x40, 0x10, 0x20, 0x08, 0xa7, 0x3a, 0x00, 0x0e, 0xa7, 0x18, + 0x1a, 0x00, 0x40, 0x30, 0x20, 0x00, 0x92, 0x00, 0x20, 0x02, 0x40, 0x10, + 0x20, 0x0a, 0xe3, 0x20, 0xd0, 0x00, 0x00, 0x04, 0xc0, 0xe5, 0xff, 0xff, + 0xff, 0xac, 0xe3, 0x40, 0xf1, 0x10, 0x00, 0x04, 0xb9, 0x04, 0x00, 0x2b, + 0xeb, 0xbf, 0xf0, 0xf8, 0x00, 0x04, 0x07, 0xf4, 0xb9, 0x04, 0x00, 0x51, + 0xa7, 0x5b, 0x00, 0x01, 0xa7, 0x09, 0x0f, 0xf7, 0xb9, 0x21, 0x00, 0x50, + 0xa7, 0x24, 0xff, 0xd7, 0x41, 0xeb, 0x20, 0x00, 0x95, 0x0a, 0xe0, 0x00, + 0xa7, 0x74, 0x00, 0x08, 0x41, 0x11, 0x40, 0x0e, 0x92, 0x0d, 0x10, 0x00, + 0xb9, 0x04, 0x00, 0x15, 0x43, 0x5b, 0x20, 0x00, 0x42, 0x51, 0x40, 0x0e, + 0xa7, 0xbb, 0x00, 0x01, 0x41, 0x10, 0x10, 0x01, 0xa7, 0xf4, 0xff, 0xbf, + 0xc0, 0x50, 0x00, 0x00, 0x00, 0xd8, 0xc0, 0x10, 0x00, 0x00, 0x4d, 0x8d, + 0xa7, 0x48, 0x00, 0x1c, 0x40, 0x40, 0x10, 0x00, 0x50, 0x20, 0x10, 0x0c, + 0xa7, 0x48, 0x00, 0x04, 0xe3, 0x20, 0x50, 0x00, 0x00, 0x04, 0x40, 0x40, + 0x10, 0x0a, 0x50, 0x30, 0x10, 0x10, 0xc0, 0xf4, 0xff, 0xff, 0xff, 0x6b, + 0xa7, 0x39, 0x00, 0x40, 0xa7, 0x29, 0x00, 0x00, 0xc0, 0xf4, 0xff, 0xff, + 0xff, 0xe4, 0x07, 0x07, 0xb9, 0x04, 0x00, 0x13, 0xa7, 0x2a, 0xff, 0xff, + 0xb9, 0x04, 0x00, 0x34, 0xa7, 0x48, 0x00, 0x01, 0x15, 0x24, 0xa7, 0x24, + 0x00, 0x07, 0xb9, 0x04, 0x00, 0x21, 0xc0, 0xf4, 0xff, 0xff, 0xff, 0x7f, + 0xa7, 0x29, 0xff, 0xff, 0x07, 0xfe, 0x07, 0x07, 0xa7, 0x39, 0x00, 0x00, + 0x41, 0x13, 0x20, 0x00, 0x95, 0x00, 0x10, 0x00, 0xa7, 0x74, 0x00, 0x05, + 0xc0, 0xf4, 0xff, 0xff, 0xff, 0x70, 0xa7, 0x3b, 0x00, 0x01, 0xa7, 0xf4, + 0xff, 0xf5, 0x07, 0x07, 0xeb, 0xbf, 0xf0, 0x58, 0x00, 0x24, 0xc0, 0xd0, + 0x00, 0x00, 0x00, 0x95, 0xa7, 0xfb, 0xff, 0x60, 0xb9, 0x04, 0x00, 0xb2, + 0xa7, 0x19, 0x00, 0x20, 0xc0, 0x20, 0x00, 0x00, 0x4d, 0x40, 0x92, 0x00, + 0x20, 0x00, 0xa7, 0x2b, 0x00, 0x01, 0xa7, 0x17, 0xff, 0xfc, 0xc0, 0x10, + 0x00, 0x00, 0x4d, 0x37, 0xa7, 0x28, 0x10, 0x00, 0x40, 0x20, 0x10, 0x00, + 0xe3, 0x20, 0xd0, 0x00, 0x00, 0x04, 0xc0, 0xe5, 0xff, 0xff, 0xff, 0x1d, + 0x12, 0x22, 0xa7, 0x74, 0x00, 0x19, 0xa7, 0x19, 0x00, 0x00, 0xc0, 0x40, + 0x00, 0x00, 0x00, 0x79, 0xa7, 0x39, 0x00, 0x08, 0xc0, 0x20, 0x00, 0x00, + 0x4d, 0x2c, 0x41, 0x21, 0x20, 0x00, 0xe3, 0x20, 0x20, 0x00, 0x00, 0x90, + 0x43, 0x22, 0x40, 0x00, 0x42, 0x21, 0xb0, 0x00, 0xa7, 0x1b, 0x00, 0x01, + 0xa7, 0x37, 0xff, 0xf2, 0xe3, 0x40, 0xf1, 0x10, 0x00, 0x04, 0xeb, 0xbf, + 0xf0, 0xf8, 0x00, 0x04, 0x07, 0xf4, 0x07, 0x07, 0xeb, 0xaf, 0xf0, 0x50, + 0x00, 0x24, 0xc0, 0xd0, 0x00, 0x00, 0x00, 0x55, 0xa7, 0xfb, 0xff, 0x60, + 0xa7, 0x19, 0x0f, 0xf8, 0xb9, 0x21, 0x00, 0x31, 0xb9, 0x04, 0x00, 0xa2, + 0xa7, 0xc4, 0x00, 0x2a, 0xa7, 0xb9, 0x0f, 0xf8, 0xc0, 0x10, 0x00, 0x00, + 0x4c, 0xf6, 0xa7, 0x28, 0x10, 0x00, 0x40, 0x20, 0x10, 0x00, 0x92, 0x00, + 0x10, 0x02, 0xe3, 0x20, 0xd0, 0x00, 0x00, 0x04, 0xc0, 0xe5, 0xff, 0xff, + 0xfe, 0xda, 0xa7, 0xbb, 0x00, 0x01, 0xa7, 0x19, 0x00, 0x00, 0xa7, 0xb7, + 0x00, 0x17, 0xc0, 0x10, 0x00, 0x00, 0x4c, 0xe1, 0xe3, 0x40, 0xf1, 0x10, + 0x00, 0x04, 0xe3, 0x20, 0x10, 0x08, 0x00, 0x91, 0xa7, 0x2a, 0xff, 0xf9, + 0xb9, 0x14, 0x00, 0x22, 0xeb, 0xaf, 0xf0, 0xf0, 0x00, 0x04, 0x07, 0xf4, + 0xb9, 0x04, 0x00, 0xb3, 0xa7, 0xf4, 0xff, 0xd8, 0xc0, 0x20, 0x00, 0x00, + 0x4c, 0xcc, 0x41, 0x31, 0xa0, 0x00, 0x41, 0x21, 0x20, 0x00, 0xa7, 0x1b, + 0x00, 0x01, 0xd2, 0x00, 0x30, 0x00, 0x20, 0x0f, 0xa7, 0xf4, 0xff, 0xdd, + 0x07, 0x07, 0x07, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x76, 0x00, 0x05, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, 0x00, 0x05, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, - 0x20, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, - 0x3c, 0x28, 0x2b, 0x7c, 0x26, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, - 0x2e, 0x2e, 0x21, 0x24, 0x2a, 0x29, 0x3b, 0x2e, 0x2d, 0x2f, 0x2e, 0x2e, - 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2c, 0x25, 0x5f, 0x3e, 0x3f, - 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x60, 0x3a, 0x23, - 0x40, 0x27, 0x3d, 0x22, 0x2e, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, - 0x68, 0x69, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x6a, 0x6b, 0x6c, - 0x6d, 0x6e, 0x6f, 0x70, 0x71, 0x72, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, - 0x2e, 0x2e, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x2e, 0x2e, + 0x2e, 0x2e, 0x2e, 0x2e, 0x20, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, + 0x2e, 0x2e, 0x2e, 0x2e, 0x3c, 0x28, 0x2b, 0x7c, 0x26, 0x2e, 0x2e, 0x2e, + 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x21, 0x24, 0x2a, 0x29, 0x3b, 0x2e, + 0x2d, 0x2f, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2c, + 0x25, 0x5f, 0x3e, 0x3f, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, + 0x2e, 0x60, 0x3a, 0x23, 0x40, 0x27, 0x3d, 0x22, 0x2e, 0x61, 0x62, 0x63, + 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, + 0x2e, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, 0x70, 0x71, 0x72, 0x2e, 0x2e, + 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, + 0x79, 0x7a, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, - 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x41, 0x42, 0x43, - 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, - 0x2e, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, 0x50, 0x51, 0x52, 0x2e, 0x2e, - 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, - 0x59, 0x5a, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x30, 0x31, 0x32, 0x33, - 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, - 0x41, 0x00, 0x42, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x2e, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x2e, 0x2e, + 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, 0x50, + 0x51, 0x52, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x53, 0x54, + 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, + 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x2e, 0x2e, + 0x2e, 0x2e, 0x2e, 0x2e, 0x41, 0x00, 0x42, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6f, 0xff, 0xfe, 0xf5, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xd8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x28, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, @@ -163,7 +177,15 @@ unsigned char s390x_elf[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x6f, 0xff, 0xff, 0xfb, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x30, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x6f, 0xff, 0xff, 0xfb, + 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, + 0x6f, 0xff, 0xff, 0xf9, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, @@ -171,83 +193,87 @@ unsigned char s390x_elf[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x17, 0x10, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x47, 0x43, 0x43, 0x3a, 0x20, 0x28, 0x47, 0x4e, 0x55, 0x29, 0x20, 0x38, - 0x2e, 0x32, 0x2e, 0x31, 0x20, 0x32, 0x30, 0x31, 0x38, 0x30, 0x39, 0x30, - 0x35, 0x20, 0x28, 0x52, 0x65, 0x64, 0x20, 0x48, 0x61, 0x74, 0x20, 0x38, - 0x2e, 0x32, 0x2e, 0x31, 0x2d, 0x33, 0x29, 0x00, 0x00, 0x2e, 0x73, 0x68, - 0x73, 0x74, 0x72, 0x74, 0x61, 0x62, 0x00, 0x2e, 0x69, 0x6e, 0x74, 0x65, - 0x72, 0x70, 0x00, 0x2e, 0x67, 0x6e, 0x75, 0x2e, 0x68, 0x61, 0x73, 0x68, - 0x00, 0x2e, 0x64, 0x79, 0x6e, 0x73, 0x79, 0x6d, 0x00, 0x2e, 0x64, 0x79, - 0x6e, 0x73, 0x74, 0x72, 0x00, 0x2e, 0x74, 0x65, 0x78, 0x74, 0x00, 0x2e, - 0x72, 0x6f, 0x64, 0x61, 0x74, 0x61, 0x00, 0x2e, 0x64, 0x79, 0x6e, 0x61, - 0x6d, 0x69, 0x63, 0x00, 0x2e, 0x67, 0x6f, 0x74, 0x00, 0x2e, 0x62, 0x73, - 0x73, 0x00, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x65, 0x6e, 0x74, 0x00, 0x00, + 0x00, 0x00, 0x17, 0xb8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x47, 0x43, 0x43, 0x3a, + 0x20, 0x28, 0x55, 0x62, 0x75, 0x6e, 0x74, 0x75, 0x20, 0x31, 0x31, 0x2e, + 0x34, 0x2e, 0x30, 0x2d, 0x31, 0x75, 0x62, 0x75, 0x6e, 0x74, 0x75, 0x31, + 0x7e, 0x32, 0x32, 0x2e, 0x30, 0x34, 0x29, 0x20, 0x31, 0x31, 0x2e, 0x34, + 0x2e, 0x30, 0x00, 0x00, 0x2e, 0x73, 0x68, 0x73, 0x74, 0x72, 0x74, 0x61, + 0x62, 0x00, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x70, 0x00, 0x2e, 0x67, + 0x6e, 0x75, 0x2e, 0x68, 0x61, 0x73, 0x68, 0x00, 0x2e, 0x64, 0x79, 0x6e, + 0x73, 0x79, 0x6d, 0x00, 0x2e, 0x64, 0x79, 0x6e, 0x73, 0x74, 0x72, 0x00, + 0x2e, 0x72, 0x65, 0x6c, 0x61, 0x2e, 0x64, 0x79, 0x6e, 0x00, 0x2e, 0x74, + 0x65, 0x78, 0x74, 0x00, 0x2e, 0x72, 0x6f, 0x64, 0x61, 0x74, 0x61, 0x00, + 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x00, 0x2e, 0x67, 0x6f, + 0x74, 0x00, 0x2e, 0x62, 0x73, 0x73, 0x00, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, + 0x65, 0x6e, 0x74, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0b, - 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, + 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xc8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xc8, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x01, 0xc8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x13, 0x6f, 0xff, 0xff, 0xf6, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xd8, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xd8, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1d, 0x00, 0x00, 0x00, 0x0b, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x01, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xf8, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x04, - 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x25, - 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x28, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x02, 0x28, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x2d, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x30, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x30, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x03, 0xb8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x33, 0x00, 0x00, 0x00, 0x01, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x05, 0xe8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0xe8, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x24, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3b, - 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x17, 0x10, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x07, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd0, - 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, - 0x00, 0x00, 0x00, 0x44, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x17, 0xe0, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xe0, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x49, 0x00, 0x00, 0x00, 0x08, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xf8, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x90, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4e, - 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x07, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2c, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, - 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x24, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x57, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x13, 0x6f, 0xff, 0xff, 0xf6, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x01, 0xd8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xd8, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x03, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1d, + 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xf8, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x01, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, + 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, + 0x00, 0x00, 0x00, 0x25, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x28, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x28, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2d, 0x00, 0x00, 0x00, 0x04, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x02, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x30, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x03, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x37, + 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x48, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x02, 0x48, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x40, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x3d, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x88, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x88, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x01, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x45, 0x00, 0x00, 0x00, 0x06, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x17, 0xb8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xb8, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x20, 0x00, 0x00, 0x00, 0x04, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x4e, + 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0xd8, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x08, 0xd8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x53, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0xf0, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x01, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x58, 0x00, 0x00, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0xf0, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x09, 0x1b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x61, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; From 2a9e2e595f2bc81c07e2f06ef9ba7d4c68897f1c Mon Sep 17 00:00:00 2001 From: Steve Sistare Date: Fri, 8 Sep 2023 07:22:10 -0700 Subject: [PATCH 0243/1077] migration: file URI MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Extend the migration URI to support file:. This can be used for any migration scenario that does not require a reverse path. It can be used as an alternative to 'exec:cat > file' in minimized containers that do not contain /bin/sh, and it is easier to use than the fd: URI. It can be used in HMP commands, and as a qemu command-line parameter. For best performance, guest ram should be shared and x-ignore-shared should be true, so guest pages are not written to the file, in which case the guest may remain running. If ram is not so configured, then the user is advised to stop the guest first. Otherwise, a busy guest may re-dirty the same page, causing it to be appended to the file multiple times, and the file may grow unboundedly. That issue is being addressed in the "fixed-ram" patch series. Signed-off-by: Steve Sistare Tested-by: Michael Galaxy Reviewed-by: Michael Galaxy Reviewed-by: Fabiano Rosas Reviewed-by: Peter Xu Reviewed-by: Daniel P. Berrangé Reviewed-by: Juan Quintela Signed-off-by: Juan Quintela Message-ID: <1694182931-61390-2-git-send-email-steven.sistare@oracle.com> --- migration/file.c | 62 ++++++++++++++++++++++++++++++++++++++++++ migration/file.h | 14 ++++++++++ migration/meson.build | 1 + migration/migration.c | 5 ++++ migration/trace-events | 4 +++ qemu-options.hx | 6 +++- 6 files changed, 91 insertions(+), 1 deletion(-) create mode 100644 migration/file.c create mode 100644 migration/file.h diff --git a/migration/file.c b/migration/file.c new file mode 100644 index 0000000000..0a65c43fdd --- /dev/null +++ b/migration/file.c @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2021-2023 Oracle and/or its affiliates. + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + */ + +#include "qemu/osdep.h" +#include "channel.h" +#include "file.h" +#include "migration.h" +#include "io/channel-file.h" +#include "io/channel-util.h" +#include "trace.h" + +void file_start_outgoing_migration(MigrationState *s, const char *filename, + Error **errp) +{ + g_autoptr(QIOChannelFile) fioc = NULL; + QIOChannel *ioc; + + trace_migration_file_outgoing(filename); + + fioc = qio_channel_file_new_path(filename, O_CREAT | O_WRONLY | O_TRUNC, + 0600, errp); + if (!fioc) { + return; + } + + ioc = QIO_CHANNEL(fioc); + qio_channel_set_name(ioc, "migration-file-outgoing"); + migration_channel_connect(s, ioc, NULL, NULL); +} + +static gboolean file_accept_incoming_migration(QIOChannel *ioc, + GIOCondition condition, + gpointer opaque) +{ + migration_channel_process_incoming(ioc); + object_unref(OBJECT(ioc)); + return G_SOURCE_REMOVE; +} + +void file_start_incoming_migration(const char *filename, Error **errp) +{ + QIOChannelFile *fioc = NULL; + QIOChannel *ioc; + + trace_migration_file_incoming(filename); + + fioc = qio_channel_file_new_path(filename, O_RDONLY, 0, errp); + if (!fioc) { + return; + } + + ioc = QIO_CHANNEL(fioc); + qio_channel_set_name(QIO_CHANNEL(ioc), "migration-file-incoming"); + qio_channel_add_watch_full(ioc, G_IO_IN, + file_accept_incoming_migration, + NULL, NULL, + g_main_context_get_thread_default()); +} diff --git a/migration/file.h b/migration/file.h new file mode 100644 index 0000000000..90fa4849e0 --- /dev/null +++ b/migration/file.h @@ -0,0 +1,14 @@ +/* + * Copyright (c) 2021-2023 Oracle and/or its affiliates. + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + */ + +#ifndef QEMU_MIGRATION_FILE_H +#define QEMU_MIGRATION_FILE_H +void file_start_incoming_migration(const char *filename, Error **errp); + +void file_start_outgoing_migration(MigrationState *s, const char *filename, + Error **errp); +#endif diff --git a/migration/meson.build b/migration/meson.build index 1ae28523a1..92b1cc4297 100644 --- a/migration/meson.build +++ b/migration/meson.build @@ -16,6 +16,7 @@ system_ss.add(files( 'dirtyrate.c', 'exec.c', 'fd.c', + 'file.c', 'global_state.c', 'migration-hmp-cmds.c', 'migration.c', diff --git a/migration/migration.c b/migration/migration.c index 6d3cf5d5cd..585d3c8f55 100644 --- a/migration/migration.c +++ b/migration/migration.c @@ -20,6 +20,7 @@ #include "migration/blocker.h" #include "exec.h" #include "fd.h" +#include "file.h" #include "socket.h" #include "sysemu/runstate.h" #include "sysemu/sysemu.h" @@ -449,6 +450,8 @@ static void qemu_start_incoming_migration(const char *uri, Error **errp) exec_start_incoming_migration(p, errp); } else if (strstart(uri, "fd:", &p)) { fd_start_incoming_migration(p, errp); + } else if (strstart(uri, "file:", &p)) { + file_start_incoming_migration(p, errp); } else { error_setg(errp, "unknown migration protocol: %s", uri); } @@ -1702,6 +1705,8 @@ void qmp_migrate(const char *uri, bool has_blk, bool blk, exec_start_outgoing_migration(s, p, &local_err); } else if (strstart(uri, "fd:", &p)) { fd_start_outgoing_migration(s, p, &local_err); + } else if (strstart(uri, "file:", &p)) { + file_start_outgoing_migration(s, p, &local_err); } else { error_setg(&local_err, QERR_INVALID_PARAMETER_VALUE, "uri", "a valid migration protocol"); diff --git a/migration/trace-events b/migration/trace-events index 63483732ce..3e9649ab2a 100644 --- a/migration/trace-events +++ b/migration/trace-events @@ -311,6 +311,10 @@ migration_exec_incoming(const char *cmd) "cmd=%s" migration_fd_outgoing(int fd) "fd=%d" migration_fd_incoming(int fd) "fd=%d" +# file.c +migration_file_outgoing(const char *filename) "filename=%s" +migration_file_incoming(const char *filename) "filename=%s" + # socket.c migration_socket_incoming_accepted(void) "" migration_socket_outgoing_connected(const char *hostname) "hostname=%s" diff --git a/qemu-options.hx b/qemu-options.hx index 9ce8a5b957..93e638c097 100644 --- a/qemu-options.hx +++ b/qemu-options.hx @@ -4706,6 +4706,7 @@ DEF("incoming", HAS_ARG, QEMU_OPTION_incoming, \ " prepare for incoming migration, listen on\n" \ " specified protocol and socket address\n" \ "-incoming fd:fd\n" \ + "-incoming file:filename\n" \ "-incoming exec:cmdline\n" \ " accept incoming migration on given file descriptor\n" \ " or from given external command\n" \ @@ -4722,7 +4723,10 @@ SRST Prepare for incoming migration, listen on a given unix socket. ``-incoming fd:fd`` - Accept incoming migration from a given filedescriptor. + Accept incoming migration from a given file descriptor. + +``-incoming file:filename`` + Accept incoming migration from a given file. ``-incoming exec:cmdline`` Accept incoming migration as an output from specified external From 385f510df5f6a7f3998b3ff01deca33b0027ff29 Mon Sep 17 00:00:00 2001 From: Steve Sistare Date: Fri, 8 Sep 2023 07:22:11 -0700 Subject: [PATCH 0244/1077] migration: file URI offset MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Allow an offset option to be specified as part of the file URI, in the form "file:filename,offset=offset", where offset accepts the common size suffixes, or the 0x prefix, but not both. Migration data is written to and read from the file starting at offset. If unspecified, it defaults to 0. This is needed by libvirt to store its own data at the head of the file. Suggested-by: Daniel P. Berrange Reviewed-by: Peter Xu Reviewed-by: Daniel P. Berrangé Reviewed-by: Juan Quintela Signed-off-by: Steve Sistare Signed-off-by: Juan Quintela Message-ID: <1694182931-61390-3-git-send-email-steven.sistare@oracle.com> --- migration/file.c | 45 +++++++++++++++++++++++++++++++++++++++++++-- qemu-options.hx | 7 ++++--- 2 files changed, 47 insertions(+), 5 deletions(-) diff --git a/migration/file.c b/migration/file.c index 0a65c43fdd..cf5b1bf365 100644 --- a/migration/file.c +++ b/migration/file.c @@ -6,6 +6,8 @@ */ #include "qemu/osdep.h" +#include "qemu/cutils.h" +#include "qapi/error.h" #include "channel.h" #include "file.h" #include "migration.h" @@ -13,14 +15,41 @@ #include "io/channel-util.h" #include "trace.h" -void file_start_outgoing_migration(MigrationState *s, const char *filename, +#define OFFSET_OPTION ",offset=" + +/* Remove the offset option from @filespec and return it in @offsetp. */ + +static int file_parse_offset(char *filespec, uint64_t *offsetp, Error **errp) +{ + char *option = strstr(filespec, OFFSET_OPTION); + int ret; + + if (option) { + *option = 0; + option += sizeof(OFFSET_OPTION) - 1; + ret = qemu_strtosz(option, NULL, offsetp); + if (ret) { + error_setg_errno(errp, -ret, "file URI has bad offset %s", option); + return -1; + } + } + return 0; +} + +void file_start_outgoing_migration(MigrationState *s, const char *filespec, Error **errp) { + g_autofree char *filename = g_strdup(filespec); g_autoptr(QIOChannelFile) fioc = NULL; + uint64_t offset = 0; QIOChannel *ioc; trace_migration_file_outgoing(filename); + if (file_parse_offset(filename, &offset, errp)) { + return; + } + fioc = qio_channel_file_new_path(filename, O_CREAT | O_WRONLY | O_TRUNC, 0600, errp); if (!fioc) { @@ -28,6 +57,9 @@ void file_start_outgoing_migration(MigrationState *s, const char *filename, } ioc = QIO_CHANNEL(fioc); + if (offset && qio_channel_io_seek(ioc, offset, SEEK_SET, errp) < 0) { + return; + } qio_channel_set_name(ioc, "migration-file-outgoing"); migration_channel_connect(s, ioc, NULL, NULL); } @@ -41,19 +73,28 @@ static gboolean file_accept_incoming_migration(QIOChannel *ioc, return G_SOURCE_REMOVE; } -void file_start_incoming_migration(const char *filename, Error **errp) +void file_start_incoming_migration(const char *filespec, Error **errp) { + g_autofree char *filename = g_strdup(filespec); QIOChannelFile *fioc = NULL; + uint64_t offset = 0; QIOChannel *ioc; trace_migration_file_incoming(filename); + if (file_parse_offset(filename, &offset, errp)) { + return; + } + fioc = qio_channel_file_new_path(filename, O_RDONLY, 0, errp); if (!fioc) { return; } ioc = QIO_CHANNEL(fioc); + if (offset && qio_channel_io_seek(ioc, offset, SEEK_SET, errp) < 0) { + return; + } qio_channel_set_name(QIO_CHANNEL(ioc), "migration-file-incoming"); qio_channel_add_watch_full(ioc, G_IO_IN, file_accept_incoming_migration, diff --git a/qemu-options.hx b/qemu-options.hx index 93e638c097..840b83d237 100644 --- a/qemu-options.hx +++ b/qemu-options.hx @@ -4706,7 +4706,7 @@ DEF("incoming", HAS_ARG, QEMU_OPTION_incoming, \ " prepare for incoming migration, listen on\n" \ " specified protocol and socket address\n" \ "-incoming fd:fd\n" \ - "-incoming file:filename\n" \ + "-incoming file:filename[,offset=offset]\n" \ "-incoming exec:cmdline\n" \ " accept incoming migration on given file descriptor\n" \ " or from given external command\n" \ @@ -4725,8 +4725,9 @@ SRST ``-incoming fd:fd`` Accept incoming migration from a given file descriptor. -``-incoming file:filename`` - Accept incoming migration from a given file. +``-incoming file:filename[,offset=offset]`` + Accept incoming migration from a given file starting at offset. + offset allows the common size suffixes, or a 0x prefix, but not both. ``-incoming exec:cmdline`` Accept incoming migration as an output from specified external From 579cedf430582b37f804f6b6ed131554cebb11b5 Mon Sep 17 00:00:00 2001 From: Peter Xu Date: Wed, 6 Sep 2023 16:47:22 -0400 Subject: [PATCH 0245/1077] migration: Unify and trace vmstate field_exists() checks For both save/load we actually share the logic on deciding whether a field should exist. Merge the checks into a helper and use it for both save and load. When doing so, add documentations and reformat the code to make it much easier to read. The real benefit here (besides code cleanups) is we add a trace-point for this; this is a known spot where we can easily break migration compatibilities between binaries, and this trace point will be critical for us to identify such issues. For example, this will be handy when debugging things like: https://gitlab.com/qemu-project/qemu/-/issues/932 Reviewed-by: Fabiano Rosas Reviewed-by: Juan Quintela Signed-off-by: Peter Xu Signed-off-by: Juan Quintela Message-ID: <20230906204722.514474-1-peterx@redhat.com> --- migration/trace-events | 1 + migration/vmstate.c | 34 ++++++++++++++++++++++++++-------- 2 files changed, 27 insertions(+), 8 deletions(-) diff --git a/migration/trace-events b/migration/trace-events index 3e9649ab2a..002abe3a4e 100644 --- a/migration/trace-events +++ b/migration/trace-events @@ -66,6 +66,7 @@ vmstate_save_state_loop(const char *name, const char *field, int n_elems) "%s/%s vmstate_save_state_top(const char *idstr) "%s" vmstate_subsection_save_loop(const char *name, const char *sub) "%s/%s" vmstate_subsection_save_top(const char *idstr) "%s" +vmstate_field_exists(const char *vmsd, const char *name, int field_version, int version, int result) "%s:%s field_version %d version %d result %d" # vmstate-types.c get_qtailq(const char *name, int version_id) "%s v%d" diff --git a/migration/vmstate.c b/migration/vmstate.c index 4cde30bf2d..1cf9e45b85 100644 --- a/migration/vmstate.c +++ b/migration/vmstate.c @@ -26,6 +26,30 @@ static int vmstate_subsection_save(QEMUFile *f, const VMStateDescription *vmsd, static int vmstate_subsection_load(QEMUFile *f, const VMStateDescription *vmsd, void *opaque); +/* Whether this field should exist for either save or load the VM? */ +static bool +vmstate_field_exists(const VMStateDescription *vmsd, const VMStateField *field, + void *opaque, int version_id) +{ + bool result; + + if (field->field_exists) { + /* If there's the function checker, that's the solo truth */ + result = field->field_exists(opaque, version_id); + trace_vmstate_field_exists(vmsd->name, field->name, field->version_id, + version_id, result); + } else { + /* + * Otherwise, we only save/load if field version is same or older. + * For example, when loading from an old binary with old version, + * we ignore new fields with newer version_ids. + */ + result = field->version_id <= version_id; + } + + return result; +} + static int vmstate_n_elems(void *opaque, const VMStateField *field) { int n_elems = 1; @@ -105,10 +129,7 @@ int vmstate_load_state(QEMUFile *f, const VMStateDescription *vmsd, } while (field->name) { trace_vmstate_load_state_field(vmsd->name, field->name); - if ((field->field_exists && - field->field_exists(opaque, version_id)) || - (!field->field_exists && - field->version_id <= version_id)) { + if (vmstate_field_exists(vmsd, field, opaque, version_id)) { void *first_elem = opaque + field->offset; int i, n_elems = vmstate_n_elems(opaque, field); int size = vmstate_size(opaque, field); @@ -349,10 +370,7 @@ int vmstate_save_state_v(QEMUFile *f, const VMStateDescription *vmsd, } while (field->name) { - if ((field->field_exists && - field->field_exists(opaque, version_id)) || - (!field->field_exists && - field->version_id <= version_id)) { + if (vmstate_field_exists(vmsd, field, opaque, version_id)) { void *first_elem = opaque + field->offset; int i, n_elems = vmstate_n_elems(opaque, field); int size = vmstate_size(opaque, field); From 9afa888ce0f816d0f2cfc95eebe4f49244c518af Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20P=2E=20Berrang=C3=A9?= Date: Tue, 3 Oct 2023 10:15:49 +0100 Subject: [PATCH 0246/1077] osdep: set _FORTIFY_SOURCE=2 when optimization is enabled MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Currently we set _FORTIFY_SOURCE=2 as a compiler argument when the meson 'optimization' setting is non-zero, the compiler is GCC and the target is Linux. While the default QEMU optimization level is 2, user could override this by setting CFLAGS="-O0" or --extra-cflags="-O0" when running configure and this won't be reflected in the meson 'optimization' setting. As a result we try to enable _FORTIFY_SOURCE=2 and then the user gets compile errors as it only works with optimization. Rather than trying to improve detection in meson, it is simpler to just check the __OPTIMIZE__ define from osdep.h. The comment about being incompatible with clang appears to be outdated, as compilation works fine without excluding clang. In the coroutine code we must set _FORTIFY_SOURCE=0 to stop the logic in osdep.h then enabling it. Signed-off-by: Daniel P. Berrangé Message-id: 20231003091549.223020-1-berrange@redhat.com Signed-off-by: Stefan Hajnoczi --- include/qemu/osdep.h | 4 ++++ meson.build | 10 ---------- util/coroutine-sigaltstack.c | 4 ++-- util/coroutine-ucontext.c | 4 ++-- 4 files changed, 8 insertions(+), 14 deletions(-) diff --git a/include/qemu/osdep.h b/include/qemu/osdep.h index 18b940db75..475a1c62ff 100644 --- a/include/qemu/osdep.h +++ b/include/qemu/osdep.h @@ -27,6 +27,10 @@ #ifndef QEMU_OSDEP_H #define QEMU_OSDEP_H +#if !defined _FORTIFY_SOURCE && defined __OPTIMIZE__ && __OPTIMIZE__ && defined __linux__ +# define _FORTIFY_SOURCE 2 +#endif + #include "config-host.h" #ifdef NEED_CPU_H #include CONFIG_TARGET diff --git a/meson.build b/meson.build index 21a1bc03f8..20ceeb8158 100644 --- a/meson.build +++ b/meson.build @@ -479,16 +479,6 @@ if 'cpp' in all_languages qemu_cxxflags = ['-D__STDC_LIMIT_MACROS', '-D__STDC_CONSTANT_MACROS', '-D__STDC_FORMAT_MACROS'] + qemu_cflags endif -# clang does not support glibc + FORTIFY_SOURCE (is it still true?) -if get_option('optimization') != '0' and targetos == 'linux' - if cc.get_id() == 'gcc' - qemu_cflags += ['-U_FORTIFY_SOURCE', '-D_FORTIFY_SOURCE=2'] - endif - if 'cpp' in all_languages and cxx.get_id() == 'gcc' - qemu_cxxflags += ['-U_FORTIFY_SOURCE', '-D_FORTIFY_SOURCE=2'] - endif -endif - add_project_arguments(qemu_cflags, native: false, language: 'c') add_project_arguments(cc.get_supported_arguments(warn_flags), native: false, language: 'c') if 'cpp' in all_languages diff --git a/util/coroutine-sigaltstack.c b/util/coroutine-sigaltstack.c index e2690c5f41..037d6416c4 100644 --- a/util/coroutine-sigaltstack.c +++ b/util/coroutine-sigaltstack.c @@ -22,9 +22,9 @@ */ /* XXX Is there a nicer way to disable glibc's stack check for longjmp? */ -#ifdef _FORTIFY_SOURCE #undef _FORTIFY_SOURCE -#endif +#define _FORTIFY_SOURCE 0 + #include "qemu/osdep.h" #include #include "qemu/coroutine_int.h" diff --git a/util/coroutine-ucontext.c b/util/coroutine-ucontext.c index ddc98fb4f8..7b304c79d9 100644 --- a/util/coroutine-ucontext.c +++ b/util/coroutine-ucontext.c @@ -19,9 +19,9 @@ */ /* XXX Is there a nicer way to disable glibc's stack check for longjmp? */ -#ifdef _FORTIFY_SOURCE #undef _FORTIFY_SOURCE -#endif +#define _FORTIFY_SOURCE 0 + #include "qemu/osdep.h" #include #include "qemu/coroutine_int.h" From 886e0a5f31bf3d40dd8d9199674a4bad64942fde Mon Sep 17 00:00:00 2001 From: David Woodhouse Date: Wed, 30 Aug 2023 20:59:43 +0100 Subject: [PATCH 0247/1077] hw/isa/ich9: Add comment on imperfect emulation of PIC vs. I/O APIC routing As noted in the comment, the PCI INTx lines are supposed to be routed to *both* the PIC and the I/O APIC. It's just that we don't cope with the concept of an IRQ being asserted to two *different* pins on the two irqchips. So we have this hack of routing to I/O APIC only if the PIRQ routing to the PIC is disabled. Which seems to work well enough, even when I try hard to break it with kexec. But should be explicitly documented and understood. Signed-off-by: David Woodhouse Message-Id: <112a09643b8191c4eae7d92fa247a861ab90a9ee.camel@infradead.org> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/isa/lpc_ich9.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/hw/isa/lpc_ich9.c b/hw/isa/lpc_ich9.c index 9c47a2f6c7..bce487ac4e 100644 --- a/hw/isa/lpc_ich9.c +++ b/hw/isa/lpc_ich9.c @@ -304,6 +304,21 @@ static PCIINTxRoute ich9_route_intx_pin_to_irq(void *opaque, int pirq_pin) route.irq = -1; } } else { + /* + * Strictly speaking, this is wrong. The PIRQ should be routed + * to *both* the I/O APIC and the PIC, on different pins. The + * I/O APIC has a fixed mapping to IRQ16-23, while the PIC is + * routed according to the PIRQx_ROUT configuration. But QEMU + * doesn't (yet) cope with the concept of pin numbers differing + * between PIC and I/O APIC, and neither does the in-kernel KVM + * irqchip support. So we route to the I/O APIC *only* if the + * routing to the PIC is disabled in the PIRQx_ROUT settings. + * + * This seems to work even if we boot a Linux guest with 'noapic' + * to make it use the legacy PIC, and then kexec directly into a + * new kernel which uses the I/O APIC. The new kernel explicitly + * disables the PIRQ routing even though it doesn't need to care. + */ route.irq = ich9_pirq_to_gsi(pirq_pin); } From b77af26e973705e8fd96cff102fc978ee44043da Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 13 Sep 2023 17:22:49 -0700 Subject: [PATCH 0248/1077] accel/tcg: Replace CPUState.env_ptr with cpu_env() Reviewed-by: Anton Johansson Signed-off-by: Richard Henderson --- accel/tcg/cpu-exec.c | 8 ++++---- accel/tcg/cputlb.c | 20 ++++++++++---------- accel/tcg/plugin-gen.c | 2 +- accel/tcg/translate-all.c | 4 ++-- bsd-user/main.c | 2 +- bsd-user/signal.c | 9 ++++----- gdbstub/gdbstub.c | 4 ++-- gdbstub/user-target.c | 2 +- hw/i386/kvm/clock.c | 2 +- hw/intc/mips_gic.c | 2 +- hw/intc/riscv_aclint.c | 12 ++++++------ hw/intc/riscv_imsic.c | 2 +- hw/ppc/e500.c | 4 ++-- hw/ppc/spapr.c | 2 +- include/exec/cpu-all.h | 1 - include/hw/core/cpu.h | 9 ++++++--- linux-user/elfload.c | 4 ++-- linux-user/i386/cpu_loop.c | 2 +- linux-user/main.c | 4 ++-- linux-user/signal.c | 15 +++++++-------- monitor/hmp-cmds-target.c | 2 +- semihosting/arm-compat-semi.c | 6 +++--- semihosting/syscalls.c | 28 ++++++++++++++-------------- target/alpha/translate.c | 4 ++-- target/arm/common-semi-target.h | 2 +- target/arm/cpu.c | 8 ++++---- target/arm/helper.c | 2 +- target/arm/tcg/translate-a64.c | 4 ++-- target/arm/tcg/translate.c | 6 +++--- target/avr/translate.c | 2 +- target/cris/translate.c | 4 ++-- target/hexagon/translate.c | 4 ++-- target/hppa/mem_helper.c | 2 +- target/hppa/translate.c | 4 ++-- target/i386/nvmm/nvmm-all.c | 14 +++++++------- target/i386/tcg/decode-new.c.inc | 2 +- target/i386/tcg/sysemu/excp_helper.c | 2 +- target/i386/tcg/tcg-cpu.c | 2 +- target/i386/tcg/translate.c | 4 ++-- target/i386/whpx/whpx-all.c | 26 +++++++++++++------------- target/loongarch/translate.c | 4 ++-- target/m68k/translate.c | 4 ++-- target/microblaze/translate.c | 2 +- target/mips/tcg/sysemu/mips-semi.c | 4 ++-- target/mips/tcg/translate.c | 4 ++-- target/nios2/translate.c | 4 ++-- target/openrisc/translate.c | 2 +- target/ppc/excp_helper.c | 10 +++++----- target/ppc/translate.c | 4 ++-- target/riscv/translate.c | 6 +++--- target/rx/cpu.c | 3 --- target/rx/translate.c | 2 +- target/s390x/tcg/translate.c | 2 +- target/sh4/op_helper.c | 2 +- target/sh4/translate.c | 4 ++-- target/sparc/translate.c | 4 ++-- target/tricore/translate.c | 4 ++-- target/xtensa/translate.c | 4 ++-- 58 files changed, 152 insertions(+), 155 deletions(-) diff --git a/accel/tcg/cpu-exec.c b/accel/tcg/cpu-exec.c index 3a18dd84ef..fe01d937d9 100644 --- a/accel/tcg/cpu-exec.c +++ b/accel/tcg/cpu-exec.c @@ -222,7 +222,7 @@ static TranslationBlock *tb_htable_lookup(CPUState *cpu, vaddr pc, struct tb_desc desc; uint32_t h; - desc.env = cpu->env_ptr; + desc.env = cpu_env(cpu); desc.cs_base = cs_base; desc.flags = flags; desc.cflags = cflags; @@ -444,7 +444,7 @@ const void *HELPER(lookup_tb_ptr)(CPUArchState *env) static inline TranslationBlock * QEMU_DISABLE_CFI cpu_tb_exec(CPUState *cpu, TranslationBlock *itb, int *tb_exit) { - CPUArchState *env = cpu->env_ptr; + CPUArchState *env = cpu_env(cpu); uintptr_t ret; TranslationBlock *last_tb; const void *tb_ptr = itb->tc.ptr; @@ -565,7 +565,7 @@ static void cpu_exec_longjmp_cleanup(CPUState *cpu) void cpu_exec_step_atomic(CPUState *cpu) { - CPUArchState *env = cpu->env_ptr; + CPUArchState *env = cpu_env(cpu); TranslationBlock *tb; vaddr pc; uint64_t cs_base; @@ -976,7 +976,7 @@ cpu_exec_loop(CPUState *cpu, SyncClocks *sc) uint64_t cs_base; uint32_t flags, cflags; - cpu_get_tb_cpu_state(cpu->env_ptr, &pc, &cs_base, &flags); + cpu_get_tb_cpu_state(cpu_env(cpu), &pc, &cs_base, &flags); /* * When requested, use an exact setting for cflags for the next diff --git a/accel/tcg/cputlb.c b/accel/tcg/cputlb.c index d69e046b80..f790be5b6e 100644 --- a/accel/tcg/cputlb.c +++ b/accel/tcg/cputlb.c @@ -274,7 +274,7 @@ static inline void tlb_n_used_entries_dec(CPUArchState *env, uintptr_t mmu_idx) void tlb_init(CPUState *cpu) { - CPUArchState *env = cpu->env_ptr; + CPUArchState *env = cpu_env(cpu); int64_t now = get_clock_realtime(); int i; @@ -290,7 +290,7 @@ void tlb_init(CPUState *cpu) void tlb_destroy(CPUState *cpu) { - CPUArchState *env = cpu->env_ptr; + CPUArchState *env = cpu_env(cpu); int i; qemu_spin_destroy(&env_tlb(env)->c.lock); @@ -328,7 +328,7 @@ void tlb_flush_counts(size_t *pfull, size_t *ppart, size_t *pelide) size_t full = 0, part = 0, elide = 0; CPU_FOREACH(cpu) { - CPUArchState *env = cpu->env_ptr; + CPUArchState *env = cpu_env(cpu); full += qatomic_read(&env_tlb(env)->c.full_flush_count); part += qatomic_read(&env_tlb(env)->c.part_flush_count); @@ -341,7 +341,7 @@ void tlb_flush_counts(size_t *pfull, size_t *ppart, size_t *pelide) static void tlb_flush_by_mmuidx_async_work(CPUState *cpu, run_on_cpu_data data) { - CPUArchState *env = cpu->env_ptr; + CPUArchState *env = cpu_env(cpu); uint16_t asked = data.host_int; uint16_t all_dirty, work, to_clean; int64_t now = get_clock_realtime(); @@ -523,7 +523,7 @@ static void tlb_flush_page_by_mmuidx_async_0(CPUState *cpu, vaddr addr, uint16_t idxmap) { - CPUArchState *env = cpu->env_ptr; + CPUArchState *env = cpu_env(cpu); int mmu_idx; assert_cpu_is_self(cpu); @@ -769,7 +769,7 @@ typedef struct { static void tlb_flush_range_by_mmuidx_async_0(CPUState *cpu, TLBFlushRangeData d) { - CPUArchState *env = cpu->env_ptr; + CPUArchState *env = cpu_env(cpu); int mmu_idx; assert_cpu_is_self(cpu); @@ -1032,7 +1032,7 @@ void tlb_reset_dirty(CPUState *cpu, ram_addr_t start1, ram_addr_t length) int mmu_idx; - env = cpu->env_ptr; + env = cpu_env(cpu); qemu_spin_lock(&env_tlb(env)->c.lock); for (mmu_idx = 0; mmu_idx < NB_MMU_MODES; mmu_idx++) { unsigned int i; @@ -1064,7 +1064,7 @@ static inline void tlb_set_dirty1_locked(CPUTLBEntry *tlb_entry, so that it is no longer dirty */ void tlb_set_dirty(CPUState *cpu, vaddr addr) { - CPUArchState *env = cpu->env_ptr; + CPUArchState *env = cpu_env(cpu); int mmu_idx; assert_cpu_is_self(cpu); @@ -1137,7 +1137,7 @@ static inline void tlb_set_compare(CPUTLBEntryFull *full, CPUTLBEntry *ent, void tlb_set_page_full(CPUState *cpu, int mmu_idx, vaddr addr, CPUTLBEntryFull *full) { - CPUArchState *env = cpu->env_ptr; + CPUArchState *env = cpu_env(cpu); CPUTLB *tlb = env_tlb(env); CPUTLBDesc *desc = &tlb->d[mmu_idx]; MemoryRegionSection *section; @@ -1662,7 +1662,7 @@ tb_page_addr_t get_page_addr_code_hostp(CPUArchState *env, vaddr addr, bool tlb_plugin_lookup(CPUState *cpu, vaddr addr, int mmu_idx, bool is_store, struct qemu_plugin_hwaddr *data) { - CPUArchState *env = cpu->env_ptr; + CPUArchState *env = cpu_env(cpu); CPUTLBEntry *tlbe = tlb_entry(env, mmu_idx, addr); uintptr_t index = tlb_index(env, mmu_idx, addr); MMUAccessType access_type = is_store ? MMU_DATA_STORE : MMU_DATA_LOAD; diff --git a/accel/tcg/plugin-gen.c b/accel/tcg/plugin-gen.c index 985c980c92..d31c9993ea 100644 --- a/accel/tcg/plugin-gen.c +++ b/accel/tcg/plugin-gen.c @@ -849,7 +849,7 @@ void plugin_gen_insn_start(CPUState *cpu, const DisasContextBase *db) } else { if (ptb->vaddr2 == -1) { ptb->vaddr2 = TARGET_PAGE_ALIGN(db->pc_first); - get_page_addr_code_hostp(cpu->env_ptr, ptb->vaddr2, &ptb->haddr2); + get_page_addr_code_hostp(cpu_env(cpu), ptb->vaddr2, &ptb->haddr2); } pinsn->haddr = ptb->haddr2 + pinsn->vaddr - ptb->vaddr2; } diff --git a/accel/tcg/translate-all.c b/accel/tcg/translate-all.c index ed0c7ef7ce..6fac5b7e29 100644 --- a/accel/tcg/translate-all.c +++ b/accel/tcg/translate-all.c @@ -288,7 +288,7 @@ TranslationBlock *tb_gen_code(CPUState *cpu, vaddr pc, uint64_t cs_base, uint32_t flags, int cflags) { - CPUArchState *env = cpu->env_ptr; + CPUArchState *env = cpu_env(cpu); TranslationBlock *tb, *existing_tb; tb_page_addr_t phys_pc, phys_p2; tcg_insn_unit *gen_code_buf; @@ -580,7 +580,7 @@ void tb_check_watchpoint(CPUState *cpu, uintptr_t retaddr) } else { /* The exception probably happened in a helper. The CPU state should have been saved before calling it. Fetch the PC from there. */ - CPUArchState *env = cpu->env_ptr; + CPUArchState *env = cpu_env(cpu); vaddr pc; uint64_t cs_base; tb_page_addr_t addr; diff --git a/bsd-user/main.c b/bsd-user/main.c index f913cb55a7..6c9addb75a 100644 --- a/bsd-user/main.c +++ b/bsd-user/main.c @@ -462,7 +462,7 @@ int main(int argc, char **argv) ac->init_machine(NULL); } cpu = cpu_create(cpu_type); - env = cpu->env_ptr; + env = cpu_env(cpu); cpu_reset(cpu); thread_cpu = cpu; diff --git a/bsd-user/signal.c b/bsd-user/signal.c index b6beab659e..4109aa5043 100644 --- a/bsd-user/signal.c +++ b/bsd-user/signal.c @@ -351,8 +351,8 @@ static int core_dump_signal(int sig) static G_NORETURN void dump_core_and_abort(int target_sig) { - CPUArchState *env = thread_cpu->env_ptr; - CPUState *cpu = env_cpu(env); + CPUState *cpu = thread_cpu; + CPUArchState *env = cpu_env(cpu); TaskState *ts = cpu->opaque; int core_dumped = 0; int host_sig; @@ -457,7 +457,7 @@ static int fatal_signal(int sig) void force_sig_fault(int sig, int code, abi_ulong addr) { CPUState *cpu = thread_cpu; - CPUArchState *env = cpu->env_ptr; + CPUArchState *env = cpu_env(cpu); target_siginfo_t info = {}; info.si_signo = sig; @@ -469,8 +469,7 @@ void force_sig_fault(int sig, int code, abi_ulong addr) static void host_signal_handler(int host_sig, siginfo_t *info, void *puc) { - CPUArchState *env = thread_cpu->env_ptr; - CPUState *cpu = env_cpu(env); + CPUState *cpu = thread_cpu; TaskState *ts = cpu->opaque; target_siginfo_t tinfo; ucontext_t *uc = puc; diff --git a/gdbstub/gdbstub.c b/gdbstub/gdbstub.c index 349d348c7b..8eea21450c 100644 --- a/gdbstub/gdbstub.c +++ b/gdbstub/gdbstub.c @@ -423,7 +423,7 @@ static const char *get_feature_xml(const char *p, const char **newp, static int gdb_read_register(CPUState *cpu, GByteArray *buf, int reg) { CPUClass *cc = CPU_GET_CLASS(cpu); - CPUArchState *env = cpu->env_ptr; + CPUArchState *env = cpu_env(cpu); GDBRegisterState *r; if (reg < cc->gdb_num_core_regs) { @@ -441,7 +441,7 @@ static int gdb_read_register(CPUState *cpu, GByteArray *buf, int reg) static int gdb_write_register(CPUState *cpu, uint8_t *mem_buf, int reg) { CPUClass *cc = CPU_GET_CLASS(cpu); - CPUArchState *env = cpu->env_ptr; + CPUArchState *env = cpu_env(cpu); GDBRegisterState *r; if (reg < cc->gdb_num_core_regs) { diff --git a/gdbstub/user-target.c b/gdbstub/user-target.c index 6e21c3161c..c4bba4c72c 100644 --- a/gdbstub/user-target.c +++ b/gdbstub/user-target.c @@ -310,7 +310,7 @@ void gdb_handle_v_file_open(GArray *params, void *user_ctx) uint64_t mode = get_param(params, 2)->val_ull; #ifdef CONFIG_LINUX - int fd = do_guest_openat(gdbserver_state.g_cpu->env_ptr, 0, filename, + int fd = do_guest_openat(cpu_env(gdbserver_state.g_cpu), 0, filename, flags, mode, false); #else int fd = open(filename, flags, mode); diff --git a/hw/i386/kvm/clock.c b/hw/i386/kvm/clock.c index 34348a3324..f25977d3f6 100644 --- a/hw/i386/kvm/clock.c +++ b/hw/i386/kvm/clock.c @@ -66,7 +66,7 @@ struct pvclock_vcpu_time_info { static uint64_t kvmclock_current_nsec(KVMClockState *s) { CPUState *cpu = first_cpu; - CPUX86State *env = cpu->env_ptr; + CPUX86State *env = cpu_env(cpu); hwaddr kvmclock_struct_pa; uint64_t migration_tsc = env->tsc; struct pvclock_vcpu_time_info time; diff --git a/hw/intc/mips_gic.c b/hw/intc/mips_gic.c index 4bdc3b1bd1..77ba7348a3 100644 --- a/hw/intc/mips_gic.c +++ b/hw/intc/mips_gic.c @@ -423,7 +423,7 @@ static void mips_gic_realize(DeviceState *dev, Error **errp) /* Register the env for all VPs with the GIC */ for (i = 0; i < s->num_vps; i++) { if (cs != NULL) { - s->vps[i].env = cs->env_ptr; + s->vps[i].env = cpu_env(cs); cs = CPU_NEXT(cs); } else { error_setg(errp, diff --git a/hw/intc/riscv_aclint.c b/hw/intc/riscv_aclint.c index 25cf7a5d9d..ab1a0b4b3a 100644 --- a/hw/intc/riscv_aclint.c +++ b/hw/intc/riscv_aclint.c @@ -131,7 +131,7 @@ static uint64_t riscv_aclint_mtimer_read(void *opaque, hwaddr addr, size_t hartid = mtimer->hartid_base + ((addr - mtimer->timecmp_base) >> 3); CPUState *cpu = cpu_by_arch_id(hartid); - CPURISCVState *env = cpu ? cpu->env_ptr : NULL; + CPURISCVState *env = cpu ? cpu_env(cpu) : NULL; if (!env) { qemu_log_mask(LOG_GUEST_ERROR, "aclint-mtimer: invalid hartid: %zu", hartid); @@ -174,7 +174,7 @@ static void riscv_aclint_mtimer_write(void *opaque, hwaddr addr, size_t hartid = mtimer->hartid_base + ((addr - mtimer->timecmp_base) >> 3); CPUState *cpu = cpu_by_arch_id(hartid); - CPURISCVState *env = cpu ? cpu->env_ptr : NULL; + CPURISCVState *env = cpu ? cpu_env(cpu) : NULL; if (!env) { qemu_log_mask(LOG_GUEST_ERROR, "aclint-mtimer: invalid hartid: %zu", hartid); @@ -233,7 +233,7 @@ static void riscv_aclint_mtimer_write(void *opaque, hwaddr addr, /* Check if timer interrupt is triggered for each hart. */ for (i = 0; i < mtimer->num_harts; i++) { CPUState *cpu = cpu_by_arch_id(mtimer->hartid_base + i); - CPURISCVState *env = cpu ? cpu->env_ptr : NULL; + CPURISCVState *env = cpu ? cpu_env(cpu) : NULL; if (!env) { continue; } @@ -375,7 +375,7 @@ DeviceState *riscv_aclint_mtimer_create(hwaddr addr, hwaddr size, for (i = 0; i < num_harts; i++) { CPUState *cpu = cpu_by_arch_id(hartid_base + i); RISCVCPU *rvcpu = RISCV_CPU(cpu); - CPURISCVState *env = cpu ? cpu->env_ptr : NULL; + CPURISCVState *env = cpu ? cpu_env(cpu) : NULL; riscv_aclint_mtimer_callback *cb = g_new0(riscv_aclint_mtimer_callback, 1); @@ -409,7 +409,7 @@ static uint64_t riscv_aclint_swi_read(void *opaque, hwaddr addr, if (addr < (swi->num_harts << 2)) { size_t hartid = swi->hartid_base + (addr >> 2); CPUState *cpu = cpu_by_arch_id(hartid); - CPURISCVState *env = cpu ? cpu->env_ptr : NULL; + CPURISCVState *env = cpu ? cpu_env(cpu) : NULL; if (!env) { qemu_log_mask(LOG_GUEST_ERROR, "aclint-swi: invalid hartid: %zu", hartid); @@ -432,7 +432,7 @@ static void riscv_aclint_swi_write(void *opaque, hwaddr addr, uint64_t value, if (addr < (swi->num_harts << 2)) { size_t hartid = swi->hartid_base + (addr >> 2); CPUState *cpu = cpu_by_arch_id(hartid); - CPURISCVState *env = cpu ? cpu->env_ptr : NULL; + CPURISCVState *env = cpu ? cpu_env(cpu) : NULL; if (!env) { qemu_log_mask(LOG_GUEST_ERROR, "aclint-swi: invalid hartid: %zu", hartid); diff --git a/hw/intc/riscv_imsic.c b/hw/intc/riscv_imsic.c index 760dbddcf7..b31d07980c 100644 --- a/hw/intc/riscv_imsic.c +++ b/hw/intc/riscv_imsic.c @@ -333,7 +333,7 @@ static void riscv_imsic_realize(DeviceState *dev, Error **errp) RISCVIMSICState *imsic = RISCV_IMSIC(dev); RISCVCPU *rcpu = RISCV_CPU(cpu_by_arch_id(imsic->hartid)); CPUState *cpu = cpu_by_arch_id(imsic->hartid); - CPURISCVState *env = cpu ? cpu->env_ptr : NULL; + CPURISCVState *env = cpu ? cpu_env(cpu) : NULL; if (!kvm_irqchip_in_kernel()) { imsic->num_eistate = imsic->num_pages * imsic->num_irqs; diff --git a/hw/ppc/e500.c b/hw/ppc/e500.c index d5b6820d1d..e04114fb3c 100644 --- a/hw/ppc/e500.c +++ b/hw/ppc/e500.c @@ -373,7 +373,7 @@ static int ppce500_load_device_tree(PPCE500MachineState *pms, MachineState *machine = MACHINE(pms); unsigned int smp_cpus = machine->smp.cpus; const PPCE500MachineClass *pmc = PPCE500_MACHINE_GET_CLASS(pms); - CPUPPCState *env = first_cpu->env_ptr; + CPUPPCState *env = cpu_env(first_cpu); int ret = -1; uint64_t mem_reg_property[] = { 0, cpu_to_be64(machine->ram_size) }; int fdt_size; @@ -499,7 +499,7 @@ static int ppce500_load_device_tree(PPCE500MachineState *pms, if (cpu == NULL) { continue; } - env = cpu->env_ptr; + env = cpu_env(cpu); cpu_name = g_strdup_printf("/cpus/PowerPC,8544@%x", i); qemu_fdt_add_subnode(fdt, cpu_name); diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c index d4230d3647..cb840676d3 100644 --- a/hw/ppc/spapr.c +++ b/hw/ppc/spapr.c @@ -1125,7 +1125,7 @@ static void spapr_dt_hypervisor(SpaprMachineState *spapr, void *fdt) * Older KVM versions with older guest kernels were broken * with the magic page, don't allow the guest to map it. */ - if (!kvmppc_get_hypercall(first_cpu->env_ptr, hypercall, + if (!kvmppc_get_hypercall(cpu_env(first_cpu), hypercall, sizeof(hypercall))) { _FDT(fdt_setprop(fdt, hypervisor, "hcall-instructions", hypercall, sizeof(hypercall))); diff --git a/include/exec/cpu-all.h b/include/exec/cpu-all.h index 114ec70359..b5116c827c 100644 --- a/include/exec/cpu-all.h +++ b/include/exec/cpu-all.h @@ -431,7 +431,6 @@ int cpu_exec(CPUState *cpu); */ static inline void cpu_set_cpustate_pointers(ArchCPU *cpu) { - cpu->parent_obj.env_ptr = &cpu->env; } /* Validate correct placement of CPUArchState. */ diff --git a/include/hw/core/cpu.h b/include/hw/core/cpu.h index 293cedd9b5..e02bc5980f 100644 --- a/include/hw/core/cpu.h +++ b/include/hw/core/cpu.h @@ -427,7 +427,6 @@ struct qemu_work_item; * @num_ases: number of CPUAddressSpaces in @cpu_ases * @as: Pointer to the first AddressSpace, for the convenience of targets which * only have a single AddressSpace - * @env_ptr: Pointer to subclass-specific CPUArchState field. * @gdb_regs: Additional GDB registers. * @gdb_num_regs: Number of total registers accessible to GDB. * @gdb_num_g_regs: Number of registers in GDB 'g' packets. @@ -501,8 +500,6 @@ struct CPUState { AddressSpace *as; MemoryRegion *memory; - CPUArchState *env_ptr; - CPUJumpCache *tb_jmp_cache; struct GDBRegisterState *gdb_regs; @@ -582,6 +579,12 @@ struct CPUState { QEMU_BUILD_BUG_ON(offsetof(CPUState, neg) != sizeof(CPUState) - sizeof(CPUNegativeOffsetState)); +static inline CPUArchState *cpu_env(CPUState *cpu) +{ + /* We validate that CPUArchState follows CPUState in cpu-all.h. */ + return (CPUArchState *)(cpu + 1); +} + typedef QTAILQ_HEAD(CPUTailQ, CPUState) CPUTailQ; extern CPUTailQ cpus; diff --git a/linux-user/elfload.c b/linux-user/elfload.c index db75cd4b33..f21e2e0c3d 100644 --- a/linux-user/elfload.c +++ b/linux-user/elfload.c @@ -593,7 +593,7 @@ const char *elf_hwcap2_str(uint32_t bit) static const char *get_elf_platform(void) { - CPUARMState *env = thread_cpu->env_ptr; + CPUARMState *env = cpu_env(thread_cpu); #if TARGET_BIG_ENDIAN # define END "b" @@ -4430,7 +4430,7 @@ static int fill_note_info(struct elf_note_info *info, if (cpu == thread_cpu) { continue; } - fill_thread_info(info, cpu->env_ptr); + fill_thread_info(info, cpu_env(cpu)); } } diff --git a/linux-user/i386/cpu_loop.c b/linux-user/i386/cpu_loop.c index ef2dcb3d76..42ecb4bf0a 100644 --- a/linux-user/i386/cpu_loop.c +++ b/linux-user/i386/cpu_loop.c @@ -323,7 +323,7 @@ void cpu_loop(CPUX86State *env) static void target_cpu_free(void *obj) { - CPUArchState *env = ((CPUState *)obj)->env_ptr; + CPUArchState *env = cpu_env(obj); target_munmap(env->gdt.base, sizeof(uint64_t) * TARGET_GDT_ENTRIES); g_free(obj); } diff --git a/linux-user/main.c b/linux-user/main.c index 96be354897..0a62e2be47 100644 --- a/linux-user/main.c +++ b/linux-user/main.c @@ -229,7 +229,7 @@ CPUArchState *cpu_copy(CPUArchState *env) { CPUState *cpu = env_cpu(env); CPUState *new_cpu = cpu_create(cpu_type); - CPUArchState *new_env = new_cpu->env_ptr; + CPUArchState *new_env = cpu_env(new_cpu); CPUBreakpoint *bp; /* Reset non arch specific state */ @@ -794,7 +794,7 @@ int main(int argc, char **argv, char **envp) ac->init_machine(NULL); } cpu = cpu_create(cpu_type); - env = cpu->env_ptr; + env = cpu_env(cpu); cpu_reset(cpu); thread_cpu = cpu; diff --git a/linux-user/signal.c b/linux-user/signal.c index 748a98f3e5..a7ba2ccaf4 100644 --- a/linux-user/signal.c +++ b/linux-user/signal.c @@ -618,7 +618,7 @@ void signal_init(void) void force_sig(int sig) { CPUState *cpu = thread_cpu; - CPUArchState *env = cpu->env_ptr; + CPUArchState *env = cpu_env(cpu); target_siginfo_t info = {}; info.si_signo = sig; @@ -636,7 +636,7 @@ void force_sig(int sig) void force_sig_fault(int sig, int code, abi_ulong addr) { CPUState *cpu = thread_cpu; - CPUArchState *env = cpu->env_ptr; + CPUArchState *env = cpu_env(cpu); target_siginfo_t info = {}; info.si_signo = sig; @@ -695,10 +695,9 @@ void cpu_loop_exit_sigbus(CPUState *cpu, target_ulong addr, /* abort execution with signal */ static G_NORETURN -void dump_core_and_abort(CPUArchState *cpu_env, int target_sig) +void dump_core_and_abort(CPUArchState *env, int target_sig) { - CPUState *cpu = thread_cpu; - CPUArchState *env = cpu->env_ptr; + CPUState *cpu = env_cpu(env); TaskState *ts = (TaskState *)cpu->opaque; int host_sig, core_dumped = 0; struct sigaction act; @@ -724,7 +723,7 @@ void dump_core_and_abort(CPUArchState *cpu_env, int target_sig) target_sig, strsignal(host_sig), "core dumped" ); } - preexit_cleanup(cpu_env, 128 + target_sig); + preexit_cleanup(env, 128 + target_sig); /* The proper exit code for dying from an uncaught signal is * -. The kernel doesn't allow exit() or _exit() to pass @@ -783,8 +782,8 @@ static inline void rewind_if_in_safe_syscall(void *puc) static void host_signal_handler(int host_sig, siginfo_t *info, void *puc) { - CPUArchState *env = thread_cpu->env_ptr; - CPUState *cpu = env_cpu(env); + CPUState *cpu = thread_cpu; + CPUArchState *env = cpu_env(cpu); TaskState *ts = cpu->opaque; target_siginfo_t tinfo; host_sigcontext *uc = puc; diff --git a/monitor/hmp-cmds-target.c b/monitor/hmp-cmds-target.c index 0d3e84d960..d9fbcac08d 100644 --- a/monitor/hmp-cmds-target.c +++ b/monitor/hmp-cmds-target.c @@ -81,7 +81,7 @@ CPUArchState *mon_get_cpu_env(Monitor *mon) { CPUState *cs = mon_get_cpu(mon); - return cs ? cs->env_ptr : NULL; + return cs ? cpu_env(cs) : NULL; } int monitor_get_cpu_index(Monitor *mon) diff --git a/semihosting/arm-compat-semi.c b/semihosting/arm-compat-semi.c index 564fe17f75..29c5670fdf 100644 --- a/semihosting/arm-compat-semi.c +++ b/semihosting/arm-compat-semi.c @@ -251,7 +251,7 @@ static void common_semi_dead_cb(CPUState *cs, uint64_t ret, int err) static void common_semi_rw_cb(CPUState *cs, uint64_t ret, int err) { /* Recover the original length from the third argument. */ - CPUArchState *env G_GNUC_UNUSED = cs->env_ptr; + CPUArchState *env G_GNUC_UNUSED = cpu_env(cs); target_ulong args = common_semi_arg(cs, 1); target_ulong arg2; GET_ARG(2); @@ -322,7 +322,7 @@ static void common_semi_readc_cb(CPUState *cs, uint64_t ret, int err) { if (!err) { - CPUArchState *env G_GNUC_UNUSED = cs->env_ptr; + CPUArchState *env G_GNUC_UNUSED = cpu_env(cs); uint8_t ch; if (get_user_u8(ch, common_semi_stack_bottom(cs) - 1)) { @@ -361,7 +361,7 @@ static const uint8_t featurefile_data[] = { */ void do_common_semihosting(CPUState *cs) { - CPUArchState *env = cs->env_ptr; + CPUArchState *env = cpu_env(cs); target_ulong args; target_ulong arg0, arg1, arg2, arg3; target_ulong ul_ret; diff --git a/semihosting/syscalls.c b/semihosting/syscalls.c index d27574a1e2..1ab4809567 100644 --- a/semihosting/syscalls.c +++ b/semihosting/syscalls.c @@ -24,7 +24,7 @@ */ static int validate_strlen(CPUState *cs, target_ulong str, target_ulong tlen) { - CPUArchState *env G_GNUC_UNUSED = cs->env_ptr; + CPUArchState *env G_GNUC_UNUSED = cpu_env(cs); char c; if (tlen == 0) { @@ -54,7 +54,7 @@ static int validate_lock_user_string(char **pstr, CPUState *cs, target_ulong tstr, target_ulong tlen) { int ret = validate_strlen(cs, tstr, tlen); - CPUArchState *env G_GNUC_UNUSED = cs->env_ptr; + CPUArchState *env G_GNUC_UNUSED = cpu_env(cs); char *str = NULL; if (ret > 0) { @@ -74,7 +74,7 @@ static int validate_lock_user_string(char **pstr, CPUState *cs, static int copy_stat_to_user(CPUState *cs, target_ulong addr, const struct stat *s) { - CPUArchState *env G_GNUC_UNUSED = cs->env_ptr; + CPUArchState *env G_GNUC_UNUSED = cpu_env(cs); struct gdb_stat *p; if (s->st_dev != (uint32_t)s->st_dev || @@ -258,7 +258,7 @@ static void host_open(CPUState *cs, gdb_syscall_complete_cb complete, target_ulong fname, target_ulong fname_len, int gdb_flags, int mode) { - CPUArchState *env G_GNUC_UNUSED = cs->env_ptr; + CPUArchState *env G_GNUC_UNUSED = cpu_env(cs); char *p; int ret, host_flags = O_BINARY; @@ -316,7 +316,7 @@ static void host_close(CPUState *cs, gdb_syscall_complete_cb complete, static void host_read(CPUState *cs, gdb_syscall_complete_cb complete, GuestFD *gf, target_ulong buf, target_ulong len) { - CPUArchState *env G_GNUC_UNUSED = cs->env_ptr; + CPUArchState *env G_GNUC_UNUSED = cpu_env(cs); void *ptr = lock_user(VERIFY_WRITE, buf, len, 0); ssize_t ret; @@ -337,7 +337,7 @@ static void host_read(CPUState *cs, gdb_syscall_complete_cb complete, static void host_write(CPUState *cs, gdb_syscall_complete_cb complete, GuestFD *gf, target_ulong buf, target_ulong len) { - CPUArchState *env G_GNUC_UNUSED = cs->env_ptr; + CPUArchState *env G_GNUC_UNUSED = cpu_env(cs); void *ptr = lock_user(VERIFY_READ, buf, len, 1); ssize_t ret; @@ -411,7 +411,7 @@ static void host_stat(CPUState *cs, gdb_syscall_complete_cb complete, target_ulong fname, target_ulong fname_len, target_ulong addr) { - CPUArchState *env G_GNUC_UNUSED = cs->env_ptr; + CPUArchState *env G_GNUC_UNUSED = cpu_env(cs); struct stat buf; char *name; int ret, err; @@ -440,7 +440,7 @@ static void host_stat(CPUState *cs, gdb_syscall_complete_cb complete, static void host_remove(CPUState *cs, gdb_syscall_complete_cb complete, target_ulong fname, target_ulong fname_len) { - CPUArchState *env G_GNUC_UNUSED = cs->env_ptr; + CPUArchState *env G_GNUC_UNUSED = cpu_env(cs); char *p; int ret; @@ -459,7 +459,7 @@ static void host_rename(CPUState *cs, gdb_syscall_complete_cb complete, target_ulong oname, target_ulong oname_len, target_ulong nname, target_ulong nname_len) { - CPUArchState *env G_GNUC_UNUSED = cs->env_ptr; + CPUArchState *env G_GNUC_UNUSED = cpu_env(cs); char *ostr, *nstr; int ret; @@ -484,7 +484,7 @@ static void host_rename(CPUState *cs, gdb_syscall_complete_cb complete, static void host_system(CPUState *cs, gdb_syscall_complete_cb complete, target_ulong cmd, target_ulong cmd_len) { - CPUArchState *env G_GNUC_UNUSED = cs->env_ptr; + CPUArchState *env G_GNUC_UNUSED = cpu_env(cs); char *p; int ret; @@ -502,7 +502,7 @@ static void host_system(CPUState *cs, gdb_syscall_complete_cb complete, static void host_gettimeofday(CPUState *cs, gdb_syscall_complete_cb complete, target_ulong tv_addr, target_ulong tz_addr) { - CPUArchState *env G_GNUC_UNUSED = cs->env_ptr; + CPUArchState *env G_GNUC_UNUSED = cpu_env(cs); struct gdb_timeval *p; int64_t rt; @@ -547,7 +547,7 @@ static void host_poll_one(CPUState *cs, gdb_syscall_complete_cb complete, static void staticfile_read(CPUState *cs, gdb_syscall_complete_cb complete, GuestFD *gf, target_ulong buf, target_ulong len) { - CPUArchState *env G_GNUC_UNUSED = cs->env_ptr; + CPUArchState *env G_GNUC_UNUSED = cpu_env(cs); target_ulong rest = gf->staticfile.len - gf->staticfile.off; void *ptr; @@ -605,7 +605,7 @@ static void staticfile_flen(CPUState *cs, gdb_syscall_complete_cb complete, static void console_read(CPUState *cs, gdb_syscall_complete_cb complete, GuestFD *gf, target_ulong buf, target_ulong len) { - CPUArchState *env G_GNUC_UNUSED = cs->env_ptr; + CPUArchState *env G_GNUC_UNUSED = cpu_env(cs); char *ptr; int ret; @@ -622,7 +622,7 @@ static void console_read(CPUState *cs, gdb_syscall_complete_cb complete, static void console_write(CPUState *cs, gdb_syscall_complete_cb complete, GuestFD *gf, target_ulong buf, target_ulong len) { - CPUArchState *env G_GNUC_UNUSED = cs->env_ptr; + CPUArchState *env G_GNUC_UNUSED = cpu_env(cs); char *ptr = lock_user(VERIFY_READ, buf, len, 1); int ret; diff --git a/target/alpha/translate.c b/target/alpha/translate.c index 46af6574bf..32333081d8 100644 --- a/target/alpha/translate.c +++ b/target/alpha/translate.c @@ -2871,7 +2871,7 @@ static DisasJumpType translate_one(DisasContext *ctx, uint32_t insn) static void alpha_tr_init_disas_context(DisasContextBase *dcbase, CPUState *cpu) { DisasContext *ctx = container_of(dcbase, DisasContext, base); - CPUAlphaState *env = cpu->env_ptr; + CPUAlphaState *env = cpu_env(cpu); int64_t bound; ctx->tbflags = ctx->base.tb->flags; @@ -2917,7 +2917,7 @@ static void alpha_tr_insn_start(DisasContextBase *dcbase, CPUState *cpu) static void alpha_tr_translate_insn(DisasContextBase *dcbase, CPUState *cpu) { DisasContext *ctx = container_of(dcbase, DisasContext, base); - CPUAlphaState *env = cpu->env_ptr; + CPUAlphaState *env = cpu_env(cpu); uint32_t insn = translator_ldl(env, &ctx->base, ctx->base.pc_next); ctx->base.pc_next += 4; diff --git a/target/arm/common-semi-target.h b/target/arm/common-semi-target.h index 629d75ca5a..19438ed8cd 100644 --- a/target/arm/common-semi-target.h +++ b/target/arm/common-semi-target.h @@ -38,7 +38,7 @@ static inline void common_semi_set_ret(CPUState *cs, target_ulong ret) static inline bool common_semi_sys_exit_extended(CPUState *cs, int nr) { - return (nr == TARGET_SYS_EXIT_EXTENDED || is_a64(cs->env_ptr)); + return nr == TARGET_SYS_EXIT_EXTENDED || is_a64(cpu_env(cs)); } static inline bool is_64bit_semihosting(CPUArchState *env) diff --git a/target/arm/cpu.c b/target/arm/cpu.c index d48a70c039..36797c2dd3 100644 --- a/target/arm/cpu.c +++ b/target/arm/cpu.c @@ -80,7 +80,7 @@ void arm_cpu_synchronize_from_tb(CPUState *cs, { /* The program counter is always up to date with CF_PCREL. */ if (!(tb_cflags(tb) & CF_PCREL)) { - CPUARMState *env = cs->env_ptr; + CPUARMState *env = cpu_env(cs); /* * It's OK to look at env for the current mode here, because it's * never possible for an AArch64 TB to chain to an AArch32 TB. @@ -97,7 +97,7 @@ void arm_restore_state_to_opc(CPUState *cs, const TranslationBlock *tb, const uint64_t *data) { - CPUARMState *env = cs->env_ptr; + CPUARMState *env = cpu_env(cs); if (is_a64(env)) { if (tb_cflags(tb) & CF_PCREL) { @@ -560,7 +560,7 @@ static inline bool arm_excp_unmasked(CPUState *cs, unsigned int excp_idx, unsigned int cur_el, bool secure, uint64_t hcr_el2) { - CPUARMState *env = cs->env_ptr; + CPUARMState *env = cpu_env(cs); bool pstate_unmasked; bool unmasked = false; @@ -690,7 +690,7 @@ static inline bool arm_excp_unmasked(CPUState *cs, unsigned int excp_idx, static bool arm_cpu_exec_interrupt(CPUState *cs, int interrupt_request) { CPUClass *cc = CPU_GET_CLASS(cs); - CPUARMState *env = cs->env_ptr; + CPUARMState *env = cpu_env(cs); uint32_t cur_el = arm_current_el(env); bool secure = arm_is_secure(env); uint64_t hcr_el2 = arm_hcr_el2_eff(env); diff --git a/target/arm/helper.c b/target/arm/helper.c index 83620787b4..74fbb6e1d7 100644 --- a/target/arm/helper.c +++ b/target/arm/helper.c @@ -10297,7 +10297,7 @@ static const int8_t target_el_table[2][2][2][2][2][4] = { uint32_t arm_phys_excp_target_el(CPUState *cs, uint32_t excp_idx, uint32_t cur_el, bool secure) { - CPUARMState *env = cs->env_ptr; + CPUARMState *env = cpu_env(cs); bool rw; bool scr; bool hcr; diff --git a/target/arm/tcg/translate-a64.c b/target/arm/tcg/translate-a64.c index 66a010ecca..10e8dcf743 100644 --- a/target/arm/tcg/translate-a64.c +++ b/target/arm/tcg/translate-a64.c @@ -13982,7 +13982,7 @@ static void aarch64_tr_init_disas_context(DisasContextBase *dcbase, CPUState *cpu) { DisasContext *dc = container_of(dcbase, DisasContext, base); - CPUARMState *env = cpu->env_ptr; + CPUARMState *env = cpu_env(cpu); ARMCPU *arm_cpu = env_archcpu(env); CPUARMTBFlags tb_flags = arm_tbflags_from_tb(dc->base.tb); int bound, core_mmu_idx; @@ -14089,7 +14089,7 @@ static void aarch64_tr_insn_start(DisasContextBase *dcbase, CPUState *cpu) static void aarch64_tr_translate_insn(DisasContextBase *dcbase, CPUState *cpu) { DisasContext *s = container_of(dcbase, DisasContext, base); - CPUARMState *env = cpu->env_ptr; + CPUARMState *env = cpu_env(cpu); uint64_t pc = s->base.pc_next; uint32_t insn; diff --git a/target/arm/tcg/translate.c b/target/arm/tcg/translate.c index 2524d8f3fb..48927fbb8c 100644 --- a/target/arm/tcg/translate.c +++ b/target/arm/tcg/translate.c @@ -9089,7 +9089,7 @@ static bool insn_crosses_page(CPUARMState *env, DisasContext *s) static void arm_tr_init_disas_context(DisasContextBase *dcbase, CPUState *cs) { DisasContext *dc = container_of(dcbase, DisasContext, base); - CPUARMState *env = cs->env_ptr; + CPUARMState *env = cpu_env(cs); ARMCPU *cpu = env_archcpu(env); CPUARMTBFlags tb_flags = arm_tbflags_from_tb(dc->base.tb); uint32_t condexec, core_mmu_idx; @@ -9317,7 +9317,7 @@ static void arm_post_translate_insn(DisasContext *dc) static void arm_tr_translate_insn(DisasContextBase *dcbase, CPUState *cpu) { DisasContext *dc = container_of(dcbase, DisasContext, base); - CPUARMState *env = cpu->env_ptr; + CPUARMState *env = cpu_env(cpu); uint32_t pc = dc->base.pc_next; unsigned int insn; @@ -9407,7 +9407,7 @@ static bool thumb_insn_is_unconditional(DisasContext *s, uint32_t insn) static void thumb_tr_translate_insn(DisasContextBase *dcbase, CPUState *cpu) { DisasContext *dc = container_of(dcbase, DisasContext, base); - CPUARMState *env = cpu->env_ptr; + CPUARMState *env = cpu_env(cpu); uint32_t pc = dc->base.pc_next; uint32_t insn; bool is_16bit; diff --git a/target/avr/translate.c b/target/avr/translate.c index 8d67570d17..cdffa04519 100644 --- a/target/avr/translate.c +++ b/target/avr/translate.c @@ -2657,7 +2657,7 @@ static bool canonicalize_skip(DisasContext *ctx) static void avr_tr_init_disas_context(DisasContextBase *dcbase, CPUState *cs) { DisasContext *ctx = container_of(dcbase, DisasContext, base); - CPUAVRState *env = cs->env_ptr; + CPUAVRState *env = cpu_env(cs); uint32_t tb_flags = ctx->base.tb->flags; ctx->cs = cs; diff --git a/target/cris/translate.c b/target/cris/translate.c index 395ba12bea..b3974ba0bb 100644 --- a/target/cris/translate.c +++ b/target/cris/translate.c @@ -2948,7 +2948,7 @@ static unsigned int crisv32_decoder(CPUCRISState *env, DisasContext *dc) static void cris_tr_init_disas_context(DisasContextBase *dcbase, CPUState *cs) { DisasContext *dc = container_of(dcbase, DisasContext, base); - CPUCRISState *env = cs->env_ptr; + CPUCRISState *env = cpu_env(cs); uint32_t tb_flags = dc->base.tb->flags; uint32_t pc_start; @@ -3006,7 +3006,7 @@ static void cris_tr_insn_start(DisasContextBase *dcbase, CPUState *cpu) static void cris_tr_translate_insn(DisasContextBase *dcbase, CPUState *cs) { DisasContext *dc = container_of(dcbase, DisasContext, base); - CPUCRISState *env = cs->env_ptr; + CPUCRISState *env = cpu_env(cs); unsigned int insn_len; /* Pretty disas. */ diff --git a/target/hexagon/translate.c b/target/hexagon/translate.c index 012c3c68ec..663b7bbc3a 100644 --- a/target/hexagon/translate.c +++ b/target/hexagon/translate.c @@ -1053,7 +1053,7 @@ static void hexagon_tr_init_disas_context(DisasContextBase *dcbase, CPUState *cs) { DisasContext *ctx = container_of(dcbase, DisasContext, base); - HexagonCPU *hex_cpu = env_archcpu(cs->env_ptr); + HexagonCPU *hex_cpu = env_archcpu(cpu_env(cs)); uint32_t hex_flags = dcbase->tb->flags; ctx->mem_idx = MMU_USER_IDX; @@ -1094,7 +1094,7 @@ static bool pkt_crosses_page(CPUHexagonState *env, DisasContext *ctx) static void hexagon_tr_translate_packet(DisasContextBase *dcbase, CPUState *cpu) { DisasContext *ctx = container_of(dcbase, DisasContext, base); - CPUHexagonState *env = cpu->env_ptr; + CPUHexagonState *env = cpu_env(cpu); decode_and_translate_packet(env, ctx); diff --git a/target/hppa/mem_helper.c b/target/hppa/mem_helper.c index 520fd311f8..350485f619 100644 --- a/target/hppa/mem_helper.c +++ b/target/hppa/mem_helper.c @@ -335,7 +335,7 @@ void HELPER(itlbp)(CPUHPPAState *env, target_ulong addr, target_ureg reg) synchronous across all processors. */ static void ptlb_work(CPUState *cpu, run_on_cpu_data data) { - CPUHPPAState *env = cpu->env_ptr; + CPUHPPAState *env = cpu_env(cpu); target_ulong addr = (target_ulong) data.target_ptr; hppa_tlb_entry *ent = hppa_find_tlb(env, addr); diff --git a/target/hppa/translate.c b/target/hppa/translate.c index 0c67d71c75..9f3ba9f42f 100644 --- a/target/hppa/translate.c +++ b/target/hppa/translate.c @@ -3450,7 +3450,7 @@ static bool trans_b_gate(DisasContext *ctx, arg_b_gate *a) #ifndef CONFIG_USER_ONLY if (ctx->tb_flags & PSW_C) { - CPUHPPAState *env = ctx->cs->env_ptr; + CPUHPPAState *env = cpu_env(ctx->cs); int type = hppa_artype_for_page(env, ctx->base.pc_next); /* If we could not find a TLB entry, then we need to generate an ITLB miss exception so the kernel will provide it. @@ -4119,7 +4119,7 @@ static void hppa_tr_insn_start(DisasContextBase *dcbase, CPUState *cs) static void hppa_tr_translate_insn(DisasContextBase *dcbase, CPUState *cs) { DisasContext *ctx = container_of(dcbase, DisasContext, base); - CPUHPPAState *env = cs->env_ptr; + CPUHPPAState *env = cpu_env(cs); DisasJumpType ret; int i, n; diff --git a/target/i386/nvmm/nvmm-all.c b/target/i386/nvmm/nvmm-all.c index 066a173d26..fb769868f2 100644 --- a/target/i386/nvmm/nvmm-all.c +++ b/target/i386/nvmm/nvmm-all.c @@ -78,7 +78,7 @@ nvmm_set_segment(struct nvmm_x64_state_seg *nseg, const SegmentCache *qseg) static void nvmm_set_registers(CPUState *cpu) { - CPUX86State *env = cpu->env_ptr; + CPUX86State *env = cpu_env(cpu); struct nvmm_machine *mach = get_nvmm_mach(); AccelCPUState *qcpu = cpu->accel; struct nvmm_vcpu *vcpu = &qcpu->vcpu; @@ -215,7 +215,7 @@ nvmm_get_segment(SegmentCache *qseg, const struct nvmm_x64_state_seg *nseg) static void nvmm_get_registers(CPUState *cpu) { - CPUX86State *env = cpu->env_ptr; + CPUX86State *env = cpu_env(cpu); struct nvmm_machine *mach = get_nvmm_mach(); AccelCPUState *qcpu = cpu->accel; struct nvmm_vcpu *vcpu = &qcpu->vcpu; @@ -340,7 +340,7 @@ nvmm_get_registers(CPUState *cpu) static bool nvmm_can_take_int(CPUState *cpu) { - CPUX86State *env = cpu->env_ptr; + CPUX86State *env = cpu_env(cpu); AccelCPUState *qcpu = cpu->accel; struct nvmm_vcpu *vcpu = &qcpu->vcpu; struct nvmm_machine *mach = get_nvmm_mach(); @@ -387,7 +387,7 @@ nvmm_can_take_nmi(CPUState *cpu) static void nvmm_vcpu_pre_run(CPUState *cpu) { - CPUX86State *env = cpu->env_ptr; + CPUX86State *env = cpu_env(cpu); struct nvmm_machine *mach = get_nvmm_mach(); AccelCPUState *qcpu = cpu->accel; struct nvmm_vcpu *vcpu = &qcpu->vcpu; @@ -473,8 +473,8 @@ static void nvmm_vcpu_post_run(CPUState *cpu, struct nvmm_vcpu_exit *exit) { AccelCPUState *qcpu = cpu->accel; - CPUX86State *env = cpu->env_ptr; X86CPU *x86_cpu = X86_CPU(cpu); + CPUX86State *env = &x86_cpu->env; uint64_t tpr; env->eflags = exit->exitstate.rflags; @@ -645,7 +645,7 @@ static int nvmm_handle_halted(struct nvmm_machine *mach, CPUState *cpu, struct nvmm_vcpu_exit *exit) { - CPUX86State *env = cpu->env_ptr; + CPUX86State *env = cpu_env(cpu); int ret = 0; qemu_mutex_lock_iothread(); @@ -678,11 +678,11 @@ nvmm_inject_ud(struct nvmm_machine *mach, struct nvmm_vcpu *vcpu) static int nvmm_vcpu_loop(CPUState *cpu) { - CPUX86State *env = cpu->env_ptr; struct nvmm_machine *mach = get_nvmm_mach(); AccelCPUState *qcpu = cpu->accel; struct nvmm_vcpu *vcpu = &qcpu->vcpu; X86CPU *x86_cpu = X86_CPU(cpu); + CPUX86State *env = &x86_cpu->env; struct nvmm_vcpu_exit *exit = vcpu->exit; int ret; diff --git a/target/i386/tcg/decode-new.c.inc b/target/i386/tcg/decode-new.c.inc index af1878c38a..7d76f15275 100644 --- a/target/i386/tcg/decode-new.c.inc +++ b/target/i386/tcg/decode-new.c.inc @@ -1595,7 +1595,7 @@ illegal: */ static void disas_insn_new(DisasContext *s, CPUState *cpu, int b) { - CPUX86State *env = cpu->env_ptr; + CPUX86State *env = cpu_env(cpu); bool first = true; X86DecodedInsn decode; X86DecodeFunc decode_func = decode_root; diff --git a/target/i386/tcg/sysemu/excp_helper.c b/target/i386/tcg/sysemu/excp_helper.c index 226689a4f2..5b86f439ad 100644 --- a/target/i386/tcg/sysemu/excp_helper.c +++ b/target/i386/tcg/sysemu/excp_helper.c @@ -597,7 +597,7 @@ bool x86_cpu_tlb_fill(CPUState *cs, vaddr addr, int size, MMUAccessType access_type, int mmu_idx, bool probe, uintptr_t retaddr) { - CPUX86State *env = cs->env_ptr; + CPUX86State *env = cpu_env(cs); TranslateResult out; TranslateFault err; diff --git a/target/i386/tcg/tcg-cpu.c b/target/i386/tcg/tcg-cpu.c index 5c3a508ddc..2c6a12c835 100644 --- a/target/i386/tcg/tcg-cpu.c +++ b/target/i386/tcg/tcg-cpu.c @@ -51,7 +51,7 @@ static void x86_cpu_synchronize_from_tb(CPUState *cs, { /* The instruction pointer is always up to date with CF_PCREL. */ if (!(tb_cflags(tb) & CF_PCREL)) { - CPUX86State *env = cs->env_ptr; + CPUX86State *env = cpu_env(cs); env->eip = tb->pc - tb->cs_base; } } diff --git a/target/i386/tcg/translate.c b/target/i386/tcg/translate.c index 4db91d11d8..4f1287311d 100644 --- a/target/i386/tcg/translate.c +++ b/target/i386/tcg/translate.c @@ -3079,7 +3079,7 @@ static void gen_cmpxchg16b(DisasContext *s, CPUX86State *env, int modrm) be stopped. Return the next pc value */ static bool disas_insn(DisasContext *s, CPUState *cpu) { - CPUX86State *env = cpu->env_ptr; + CPUX86State *env = cpu_env(cpu); int b, prefixes; int shift; MemOp ot, aflag, dflag; @@ -6918,7 +6918,7 @@ void tcg_x86_init(void) static void i386_tr_init_disas_context(DisasContextBase *dcbase, CPUState *cpu) { DisasContext *dc = container_of(dcbase, DisasContext, base); - CPUX86State *env = cpu->env_ptr; + CPUX86State *env = cpu_env(cpu); uint32_t flags = dc->base.tb->flags; uint32_t cflags = tb_cflags(dc->base.tb); int cpl = (flags >> HF_CPL_SHIFT) & 3; diff --git a/target/i386/whpx/whpx-all.c b/target/i386/whpx/whpx-all.c index 3de0dc1d46..df3aba2642 100644 --- a/target/i386/whpx/whpx-all.c +++ b/target/i386/whpx/whpx-all.c @@ -300,7 +300,7 @@ static SegmentCache whpx_seg_h2q(const WHV_X64_SEGMENT_REGISTER *hs) /* X64 Extended Control Registers */ static void whpx_set_xcrs(CPUState *cpu) { - CPUX86State *env = cpu->env_ptr; + CPUX86State *env = cpu_env(cpu); HRESULT hr; struct whpx_state *whpx = &whpx_global; WHV_REGISTER_VALUE xcr0; @@ -321,7 +321,7 @@ static void whpx_set_xcrs(CPUState *cpu) static int whpx_set_tsc(CPUState *cpu) { - CPUX86State *env = cpu->env_ptr; + CPUX86State *env = cpu_env(cpu); WHV_REGISTER_NAME tsc_reg = WHvX64RegisterTsc; WHV_REGISTER_VALUE tsc_val; HRESULT hr; @@ -382,8 +382,8 @@ static void whpx_set_registers(CPUState *cpu, int level) { struct whpx_state *whpx = &whpx_global; AccelCPUState *vcpu = cpu->accel; - CPUX86State *env = cpu->env_ptr; X86CPU *x86_cpu = X86_CPU(cpu); + CPUX86State *env = &x86_cpu->env; struct whpx_register_set vcxt; HRESULT hr; int idx; @@ -556,7 +556,7 @@ static void whpx_set_registers(CPUState *cpu, int level) static int whpx_get_tsc(CPUState *cpu) { - CPUX86State *env = cpu->env_ptr; + CPUX86State *env = cpu_env(cpu); WHV_REGISTER_NAME tsc_reg = WHvX64RegisterTsc; WHV_REGISTER_VALUE tsc_val; HRESULT hr; @@ -576,7 +576,7 @@ static int whpx_get_tsc(CPUState *cpu) /* X64 Extended Control Registers */ static void whpx_get_xcrs(CPUState *cpu) { - CPUX86State *env = cpu->env_ptr; + CPUX86State *env = cpu_env(cpu); HRESULT hr; struct whpx_state *whpx = &whpx_global; WHV_REGISTER_VALUE xcr0; @@ -601,8 +601,8 @@ static void whpx_get_registers(CPUState *cpu) { struct whpx_state *whpx = &whpx_global; AccelCPUState *vcpu = cpu->accel; - CPUX86State *env = cpu->env_ptr; X86CPU *x86_cpu = X86_CPU(cpu); + CPUX86State *env = &x86_cpu->env; struct whpx_register_set vcxt; uint64_t tpr, apic_base; HRESULT hr; @@ -1400,7 +1400,7 @@ static vaddr whpx_vcpu_get_pc(CPUState *cpu, bool exit_context_valid) { if (cpu->vcpu_dirty) { /* The CPU registers have been modified by other parts of QEMU. */ - CPUArchState *env = (CPUArchState *)(cpu->env_ptr); + CPUArchState *env = cpu_env(cpu); return env->eip; } else if (exit_context_valid) { /* @@ -1439,7 +1439,7 @@ static vaddr whpx_vcpu_get_pc(CPUState *cpu, bool exit_context_valid) static int whpx_handle_halt(CPUState *cpu) { - CPUX86State *env = cpu->env_ptr; + CPUX86State *env = cpu_env(cpu); int ret = 0; qemu_mutex_lock_iothread(); @@ -1460,8 +1460,8 @@ static void whpx_vcpu_pre_run(CPUState *cpu) HRESULT hr; struct whpx_state *whpx = &whpx_global; AccelCPUState *vcpu = cpu->accel; - CPUX86State *env = cpu->env_ptr; X86CPU *x86_cpu = X86_CPU(cpu); + CPUX86State *env = &x86_cpu->env; int irq; uint8_t tpr; WHV_X64_PENDING_INTERRUPTION_REGISTER new_int; @@ -1582,8 +1582,8 @@ static void whpx_vcpu_pre_run(CPUState *cpu) static void whpx_vcpu_post_run(CPUState *cpu) { AccelCPUState *vcpu = cpu->accel; - CPUX86State *env = cpu->env_ptr; X86CPU *x86_cpu = X86_CPU(cpu); + CPUX86State *env = &x86_cpu->env; env->eflags = vcpu->exit_ctx.VpContext.Rflags; @@ -1606,8 +1606,8 @@ static void whpx_vcpu_post_run(CPUState *cpu) static void whpx_vcpu_process_async_events(CPUState *cpu) { - CPUX86State *env = cpu->env_ptr; X86CPU *x86_cpu = X86_CPU(cpu); + CPUX86State *env = &x86_cpu->env; AccelCPUState *vcpu = cpu->accel; if ((cpu->interrupt_request & CPU_INTERRUPT_INIT) && @@ -2147,8 +2147,8 @@ int whpx_init_vcpu(CPUState *cpu) struct whpx_state *whpx = &whpx_global; AccelCPUState *vcpu = NULL; Error *local_error = NULL; - CPUX86State *env = cpu->env_ptr; X86CPU *x86_cpu = X86_CPU(cpu); + CPUX86State *env = &x86_cpu->env; UINT64 freq = 0; int ret; @@ -2245,7 +2245,7 @@ int whpx_init_vcpu(CPUState *cpu) cpu->vcpu_dirty = true; cpu->accel = vcpu; max_vcpu_index = max(max_vcpu_index, cpu->cpu_index); - qemu_add_vm_change_state_handler(whpx_cpu_update_state, cpu->env_ptr); + qemu_add_vm_change_state_handler(whpx_cpu_update_state, env); return 0; diff --git a/target/loongarch/translate.c b/target/loongarch/translate.c index 47598a9373..21f4db6fbd 100644 --- a/target/loongarch/translate.c +++ b/target/loongarch/translate.c @@ -117,7 +117,7 @@ static void loongarch_tr_init_disas_context(DisasContextBase *dcbase, CPUState *cs) { int64_t bound; - CPULoongArchState *env = cs->env_ptr; + CPULoongArchState *env = cpu_env(cs); DisasContext *ctx = container_of(dcbase, DisasContext, base); ctx->page_start = ctx->base.pc_first & TARGET_PAGE_MASK; @@ -282,7 +282,7 @@ static uint64_t make_address_pc(DisasContext *ctx, uint64_t addr) static void loongarch_tr_translate_insn(DisasContextBase *dcbase, CPUState *cs) { - CPULoongArchState *env = cs->env_ptr; + CPULoongArchState *env = cpu_env(cs); DisasContext *ctx = container_of(dcbase, DisasContext, base); ctx->opcode = translator_ldl(env, &ctx->base, ctx->base.pc_next); diff --git a/target/m68k/translate.c b/target/m68k/translate.c index 587fe36356..4d0110de95 100644 --- a/target/m68k/translate.c +++ b/target/m68k/translate.c @@ -5990,7 +5990,7 @@ void register_m68k_insns (CPUM68KState *env) static void m68k_tr_init_disas_context(DisasContextBase *dcbase, CPUState *cpu) { DisasContext *dc = container_of(dcbase, DisasContext, base); - CPUM68KState *env = cpu->env_ptr; + CPUM68KState *env = cpu_env(cpu); dc->env = env; dc->pc = dc->base.pc_first; @@ -6021,7 +6021,7 @@ static void m68k_tr_insn_start(DisasContextBase *dcbase, CPUState *cpu) static void m68k_tr_translate_insn(DisasContextBase *dcbase, CPUState *cpu) { DisasContext *dc = container_of(dcbase, DisasContext, base); - CPUM68KState *env = cpu->env_ptr; + CPUM68KState *env = cpu_env(cpu); uint16_t insn = read_im16(env, dc); opcode_table[insn](env, dc, insn); diff --git a/target/microblaze/translate.c b/target/microblaze/translate.c index bb178219f1..49bfb4a0ea 100644 --- a/target/microblaze/translate.c +++ b/target/microblaze/translate.c @@ -1630,7 +1630,7 @@ static void mb_tr_insn_start(DisasContextBase *dcb, CPUState *cs) static void mb_tr_translate_insn(DisasContextBase *dcb, CPUState *cs) { DisasContext *dc = container_of(dcb, DisasContext, base); - CPUMBState *env = cs->env_ptr; + CPUMBState *env = cpu_env(cs); uint32_t ir; /* TODO: This should raise an exception, not terminate qemu. */ diff --git a/target/mips/tcg/sysemu/mips-semi.c b/target/mips/tcg/sysemu/mips-semi.c index f3735df7b9..b3e4e49ff7 100644 --- a/target/mips/tcg/sysemu/mips-semi.c +++ b/target/mips/tcg/sysemu/mips-semi.c @@ -126,7 +126,7 @@ static void report_fault(CPUMIPSState *env) static void uhi_cb(CPUState *cs, uint64_t ret, int err) { - CPUMIPSState *env = cs->env_ptr; + CPUMIPSState *env = cpu_env(cs); #define E(N) case E##N: err = UHI_E##N; break @@ -167,7 +167,7 @@ static void uhi_fstat_cb(CPUState *cs, uint64_t ret, int err) QEMU_BUILD_BUG_ON(sizeof(UHIStat) < sizeof(struct gdb_stat)); if (!err) { - CPUMIPSState *env = cs->env_ptr; + CPUMIPSState *env = cpu_env(cs); target_ulong addr = env->active_tc.gpr[5]; UHIStat *dst = lock_user(VERIFY_WRITE, addr, sizeof(UHIStat), 1); struct gdb_stat s; diff --git a/target/mips/tcg/translate.c b/target/mips/tcg/translate.c index 6d5a552b2e..13e43fa3b6 100644 --- a/target/mips/tcg/translate.c +++ b/target/mips/tcg/translate.c @@ -15376,7 +15376,7 @@ static void decode_opc(CPUMIPSState *env, DisasContext *ctx) static void mips_tr_init_disas_context(DisasContextBase *dcbase, CPUState *cs) { DisasContext *ctx = container_of(dcbase, DisasContext, base); - CPUMIPSState *env = cs->env_ptr; + CPUMIPSState *env = cpu_env(cs); ctx->page_start = ctx->base.pc_first & TARGET_PAGE_MASK; ctx->saved_pc = -1; @@ -15447,7 +15447,7 @@ static void mips_tr_insn_start(DisasContextBase *dcbase, CPUState *cs) static void mips_tr_translate_insn(DisasContextBase *dcbase, CPUState *cs) { - CPUMIPSState *env = cs->env_ptr; + CPUMIPSState *env = cpu_env(cs); DisasContext *ctx = container_of(dcbase, DisasContext, base); int insn_bytes; int is_slot; diff --git a/target/nios2/translate.c b/target/nios2/translate.c index 93ded65f9a..e806623594 100644 --- a/target/nios2/translate.c +++ b/target/nios2/translate.c @@ -944,7 +944,7 @@ static const char * const cr_regnames[NUM_CR_REGS] = { static void nios2_tr_init_disas_context(DisasContextBase *dcbase, CPUState *cs) { DisasContext *dc = container_of(dcbase, DisasContext, base); - CPUNios2State *env = cs->env_ptr; + CPUNios2State *env = cpu_env(cs); Nios2CPU *cpu = env_archcpu(env); int page_insns; @@ -970,7 +970,7 @@ static void nios2_tr_insn_start(DisasContextBase *dcbase, CPUState *cs) static void nios2_tr_translate_insn(DisasContextBase *dcbase, CPUState *cs) { DisasContext *dc = container_of(dcbase, DisasContext, base); - CPUNios2State *env = cs->env_ptr; + CPUNios2State *env = cpu_env(cs); const Nios2Instruction *instr; uint32_t code, pc; uint8_t op; diff --git a/target/openrisc/translate.c b/target/openrisc/translate.c index 1b4df1c214..ecff4412b7 100644 --- a/target/openrisc/translate.c +++ b/target/openrisc/translate.c @@ -1525,7 +1525,7 @@ static bool trans_lf_sfun_d(DisasContext *dc, arg_ab_pair *a) static void openrisc_tr_init_disas_context(DisasContextBase *dcb, CPUState *cs) { DisasContext *dc = container_of(dcb, DisasContext, base); - CPUOpenRISCState *env = cs->env_ptr; + CPUOpenRISCState *env = cpu_env(cs); int bound; dc->mem_idx = cpu_mmu_index(env, false); diff --git a/target/ppc/excp_helper.c b/target/ppc/excp_helper.c index 99099cb1f6..7926114d5c 100644 --- a/target/ppc/excp_helper.c +++ b/target/ppc/excp_helper.c @@ -3189,7 +3189,7 @@ void ppc_cpu_do_unaligned_access(CPUState *cs, vaddr vaddr, MMUAccessType access_type, int mmu_idx, uintptr_t retaddr) { - CPUPPCState *env = cs->env_ptr; + CPUPPCState *env = cpu_env(cs); uint32_t insn; /* Restore state and reload the insn we executed, for filling in DSISR. */ @@ -3220,7 +3220,7 @@ void ppc_cpu_do_transaction_failed(CPUState *cs, hwaddr physaddr, int mmu_idx, MemTxAttrs attrs, MemTxResult response, uintptr_t retaddr) { - CPUPPCState *env = cs->env_ptr; + CPUPPCState *env = cpu_env(cs); switch (env->excp_model) { #if defined(TARGET_PPC64) @@ -3264,7 +3264,7 @@ void ppc_cpu_do_transaction_failed(CPUState *cs, hwaddr physaddr, void ppc_cpu_debug_excp_handler(CPUState *cs) { #if defined(TARGET_PPC64) - CPUPPCState *env = cs->env_ptr; + CPUPPCState *env = cpu_env(cs); if (env->insns_flags2 & PPC2_ISA207S) { if (cs->watchpoint_hit) { @@ -3286,7 +3286,7 @@ void ppc_cpu_debug_excp_handler(CPUState *cs) bool ppc_cpu_debug_check_breakpoint(CPUState *cs) { #if defined(TARGET_PPC64) - CPUPPCState *env = cs->env_ptr; + CPUPPCState *env = cpu_env(cs); if (env->insns_flags2 & PPC2_ISA207S) { target_ulong priv; @@ -3313,7 +3313,7 @@ bool ppc_cpu_debug_check_breakpoint(CPUState *cs) bool ppc_cpu_debug_check_watchpoint(CPUState *cs, CPUWatchpoint *wp) { #if defined(TARGET_PPC64) - CPUPPCState *env = cs->env_ptr; + CPUPPCState *env = cpu_env(cs); if (env->insns_flags2 & PPC2_ISA207S) { if (wp == env->dawr0_watchpoint) { diff --git a/target/ppc/translate.c b/target/ppc/translate.c index e20a1bea62..329da4d518 100644 --- a/target/ppc/translate.c +++ b/target/ppc/translate.c @@ -7320,7 +7320,7 @@ static bool decode_legacy(PowerPCCPU *cpu, DisasContext *ctx, uint32_t insn) static void ppc_tr_init_disas_context(DisasContextBase *dcbase, CPUState *cs) { DisasContext *ctx = container_of(dcbase, DisasContext, base); - CPUPPCState *env = cs->env_ptr; + CPUPPCState *env = cpu_env(cs); uint32_t hflags = ctx->base.tb->flags; ctx->spr_cb = env->spr_cb; @@ -7384,7 +7384,7 @@ static void ppc_tr_translate_insn(DisasContextBase *dcbase, CPUState *cs) { DisasContext *ctx = container_of(dcbase, DisasContext, base); PowerPCCPU *cpu = POWERPC_CPU(cs); - CPUPPCState *env = cs->env_ptr; + CPUPPCState *env = cpu_env(cs); target_ulong pc; uint32_t insn; bool ok; diff --git a/target/riscv/translate.c b/target/riscv/translate.c index 2ad5192866..f0be79bb16 100644 --- a/target/riscv/translate.c +++ b/target/riscv/translate.c @@ -1074,7 +1074,7 @@ static uint32_t opcode_at(DisasContextBase *dcbase, target_ulong pc) { DisasContext *ctx = container_of(dcbase, DisasContext, base); CPUState *cpu = ctx->cs; - CPURISCVState *env = cpu->env_ptr; + CPURISCVState *env = cpu_env(cpu); return cpu_ldl_code(env, pc); } @@ -1166,7 +1166,7 @@ static void decode_opc(CPURISCVState *env, DisasContext *ctx, uint16_t opcode) static void riscv_tr_init_disas_context(DisasContextBase *dcbase, CPUState *cs) { DisasContext *ctx = container_of(dcbase, DisasContext, base); - CPURISCVState *env = cs->env_ptr; + CPURISCVState *env = cpu_env(cs); RISCVCPU *cpu = RISCV_CPU(cs); uint32_t tb_flags = ctx->base.tb->flags; @@ -1219,7 +1219,7 @@ static void riscv_tr_insn_start(DisasContextBase *dcbase, CPUState *cpu) static void riscv_tr_translate_insn(DisasContextBase *dcbase, CPUState *cpu) { DisasContext *ctx = container_of(dcbase, DisasContext, base); - CPURISCVState *env = cpu->env_ptr; + CPURISCVState *env = cpu_env(cpu); uint16_t opcode16 = translator_lduw(env, &ctx->base, ctx->base.pc_next); ctx->ol = ctx->xl; diff --git a/target/rx/cpu.c b/target/rx/cpu.c index 51559943fb..2e7a736590 100644 --- a/target/rx/cpu.c +++ b/target/rx/cpu.c @@ -183,12 +183,9 @@ static bool rx_cpu_tlb_fill(CPUState *cs, vaddr addr, int size, static void rx_cpu_init(Object *obj) { - CPUState *cs = CPU(obj); RXCPU *cpu = RX_CPU(obj); - CPURXState *env = &cpu->env; cpu_set_cpustate_pointers(cpu); - cs->env_ptr = env; qdev_init_gpio_in(DEVICE(cpu), rx_cpu_set_irq, 2); } diff --git a/target/rx/translate.c b/target/rx/translate.c index 9fd4d36b08..f8860830ae 100644 --- a/target/rx/translate.c +++ b/target/rx/translate.c @@ -2200,7 +2200,7 @@ static bool trans_WAIT(DisasContext *ctx, arg_WAIT *a) static void rx_tr_init_disas_context(DisasContextBase *dcbase, CPUState *cs) { - CPURXState *env = cs->env_ptr; + CPURXState *env = cpu_env(cs); DisasContext *ctx = container_of(dcbase, DisasContext, base); ctx->env = env; ctx->tb_flags = ctx->base.tb->flags; diff --git a/target/s390x/tcg/translate.c b/target/s390x/tcg/translate.c index 22f43974dd..4bae1509f5 100644 --- a/target/s390x/tcg/translate.c +++ b/target/s390x/tcg/translate.c @@ -6463,7 +6463,7 @@ static target_ulong get_next_pc(CPUS390XState *env, DisasContext *s, static void s390x_tr_translate_insn(DisasContextBase *dcbase, CPUState *cs) { - CPUS390XState *env = cs->env_ptr; + CPUS390XState *env = cpu_env(cs); DisasContext *dc = container_of(dcbase, DisasContext, base); dc->base.is_jmp = translate_one(env, dc); diff --git a/target/sh4/op_helper.c b/target/sh4/op_helper.c index a663335c39..ada41ba0a2 100644 --- a/target/sh4/op_helper.c +++ b/target/sh4/op_helper.c @@ -29,7 +29,7 @@ void superh_cpu_do_unaligned_access(CPUState *cs, vaddr addr, MMUAccessType access_type, int mmu_idx, uintptr_t retaddr) { - CPUSH4State *env = cs->env_ptr; + CPUSH4State *env = cpu_env(cs); env->tea = addr; switch (access_type) { diff --git a/target/sh4/translate.c b/target/sh4/translate.c index 30e3ea509b..cbd8dfc02f 100644 --- a/target/sh4/translate.c +++ b/target/sh4/translate.c @@ -2179,7 +2179,7 @@ static void decode_gusa(DisasContext *ctx, CPUSH4State *env) static void sh4_tr_init_disas_context(DisasContextBase *dcbase, CPUState *cs) { DisasContext *ctx = container_of(dcbase, DisasContext, base); - CPUSH4State *env = cs->env_ptr; + CPUSH4State *env = cpu_env(cs); uint32_t tbflags; int bound; @@ -2236,7 +2236,7 @@ static void sh4_tr_insn_start(DisasContextBase *dcbase, CPUState *cs) static void sh4_tr_translate_insn(DisasContextBase *dcbase, CPUState *cs) { - CPUSH4State *env = cs->env_ptr; + CPUSH4State *env = cpu_env(cs); DisasContext *ctx = container_of(dcbase, DisasContext, base); #ifdef CONFIG_USER_ONLY diff --git a/target/sparc/translate.c b/target/sparc/translate.c index 71b48cb3b7..f92ff80ac8 100644 --- a/target/sparc/translate.c +++ b/target/sparc/translate.c @@ -5568,7 +5568,7 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn) static void sparc_tr_init_disas_context(DisasContextBase *dcbase, CPUState *cs) { DisasContext *dc = container_of(dcbase, DisasContext, base); - CPUSPARCState *env = cs->env_ptr; + CPUSPARCState *env = cpu_env(cs); int bound; dc->pc = dc->base.pc_first; @@ -5625,7 +5625,7 @@ static void sparc_tr_insn_start(DisasContextBase *dcbase, CPUState *cs) static void sparc_tr_translate_insn(DisasContextBase *dcbase, CPUState *cs) { DisasContext *dc = container_of(dcbase, DisasContext, base); - CPUSPARCState *env = cs->env_ptr; + CPUSPARCState *env = cpu_env(cs); unsigned int insn; insn = translator_ldl(env, &dc->base, dc->pc); diff --git a/target/tricore/translate.c b/target/tricore/translate.c index 114fdda29f..dd812ec0f0 100644 --- a/target/tricore/translate.c +++ b/target/tricore/translate.c @@ -8366,7 +8366,7 @@ static void tricore_tr_init_disas_context(DisasContextBase *dcbase, CPUState *cs) { DisasContext *ctx = container_of(dcbase, DisasContext, base); - CPUTriCoreState *env = cs->env_ptr; + CPUTriCoreState *env = cpu_env(cs); ctx->mem_idx = cpu_mmu_index(env, false); uint32_t tb_flags = (uint32_t)ctx->base.tb->flags; @@ -8411,7 +8411,7 @@ static bool insn_crosses_page(CPUTriCoreState *env, DisasContext *ctx) static void tricore_tr_translate_insn(DisasContextBase *dcbase, CPUState *cpu) { DisasContext *ctx = container_of(dcbase, DisasContext, base); - CPUTriCoreState *env = cpu->env_ptr; + CPUTriCoreState *env = cpu_env(cpu); uint16_t insn_lo; bool is_16bit; diff --git a/target/xtensa/translate.c b/target/xtensa/translate.c index fca1b9aba4..54bee7ddba 100644 --- a/target/xtensa/translate.c +++ b/target/xtensa/translate.c @@ -1140,7 +1140,7 @@ static void xtensa_tr_init_disas_context(DisasContextBase *dcbase, CPUState *cpu) { DisasContext *dc = container_of(dcbase, DisasContext, base); - CPUXtensaState *env = cpu->env_ptr; + CPUXtensaState *env = cpu_env(cpu); uint32_t tb_flags = dc->base.tb->flags; dc->config = env->config; @@ -1180,7 +1180,7 @@ static void xtensa_tr_insn_start(DisasContextBase *dcbase, CPUState *cpu) static void xtensa_tr_translate_insn(DisasContextBase *dcbase, CPUState *cpu) { DisasContext *dc = container_of(dcbase, DisasContext, base); - CPUXtensaState *env = cpu->env_ptr; + CPUXtensaState *env = cpu_env(cpu); target_ulong page_start; /* These two conditions only apply to the first insn in the TB, From 8fa08d7ec7d8c36fc2c96bd135cb09c086b26a14 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 13 Sep 2023 17:36:27 -0700 Subject: [PATCH 0249/1077] accel/tcg: Remove cpu_set_cpustate_pointers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This function is now empty, so remove it. In the case of m68k and tricore, this empties the class instance initfn, so remove those as well. Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Richard Henderson --- include/exec/cpu-all.h | 10 ---------- target/alpha/cpu.c | 2 -- target/arm/cpu.c | 1 - target/avr/cpu.c | 2 -- target/cris/cpu.c | 2 -- target/hexagon/cpu.c | 3 --- target/hppa/cpu.c | 1 - target/i386/cpu.c | 1 - target/loongarch/cpu.c | 8 +++----- target/m68k/cpu.c | 8 -------- target/microblaze/cpu.c | 1 - target/mips/cpu.c | 1 - target/nios2/cpu.c | 4 +--- target/openrisc/cpu.c | 6 +----- target/ppc/cpu_init.c | 1 - target/riscv/cpu.c | 6 +----- target/rx/cpu.c | 1 - target/s390x/cpu.c | 2 -- target/sh4/cpu.c | 2 -- target/sparc/cpu.c | 2 -- target/tricore/cpu.c | 9 --------- target/xtensa/cpu.c | 1 - 22 files changed, 6 insertions(+), 68 deletions(-) diff --git a/include/exec/cpu-all.h b/include/exec/cpu-all.h index b5116c827c..9d8ab050c2 100644 --- a/include/exec/cpu-all.h +++ b/include/exec/cpu-all.h @@ -423,16 +423,6 @@ void dump_exec_info(GString *buf); /* accel/tcg/cpu-exec.c */ int cpu_exec(CPUState *cpu); -/** - * cpu_set_cpustate_pointers(cpu) - * @cpu: The cpu object - * - * Set the generic pointers in CPUState into the outer object. - */ -static inline void cpu_set_cpustate_pointers(ArchCPU *cpu) -{ -} - /* Validate correct placement of CPUArchState. */ QEMU_BUILD_BUG_ON(offsetof(ArchCPU, parent_obj) != 0); QEMU_BUILD_BUG_ON(offsetof(ArchCPU, env) != sizeof(CPUState)); diff --git a/target/alpha/cpu.c b/target/alpha/cpu.c index e2156fcb41..51b7d8d1bf 100644 --- a/target/alpha/cpu.c +++ b/target/alpha/cpu.c @@ -209,8 +209,6 @@ static void alpha_cpu_initfn(Object *obj) AlphaCPU *cpu = ALPHA_CPU(obj); CPUAlphaState *env = &cpu->env; - cpu_set_cpustate_pointers(cpu); - env->lock_addr = -1; #if defined(CONFIG_USER_ONLY) env->flags = ENV_FLAG_PS_USER | ENV_FLAG_FEN; diff --git a/target/arm/cpu.c b/target/arm/cpu.c index 36797c2dd3..831295d7cd 100644 --- a/target/arm/cpu.c +++ b/target/arm/cpu.c @@ -1215,7 +1215,6 @@ static void arm_cpu_initfn(Object *obj) { ARMCPU *cpu = ARM_CPU(obj); - cpu_set_cpustate_pointers(cpu); cpu->cp_regs = g_hash_table_new_full(g_direct_hash, g_direct_equal, NULL, g_free); diff --git a/target/avr/cpu.c b/target/avr/cpu.c index c5a6436336..14d8b9d1f0 100644 --- a/target/avr/cpu.c +++ b/target/avr/cpu.c @@ -147,8 +147,6 @@ static void avr_cpu_initfn(Object *obj) { AVRCPU *cpu = AVR_CPU(obj); - cpu_set_cpustate_pointers(cpu); - /* Set the number of interrupts supported by the CPU. */ qdev_init_gpio_in(DEVICE(cpu), avr_cpu_set_int, sizeof(cpu->env.intsrc) * 8); diff --git a/target/cris/cpu.c b/target/cris/cpu.c index 8ab8a30b8d..be4a44c218 100644 --- a/target/cris/cpu.c +++ b/target/cris/cpu.c @@ -201,8 +201,6 @@ static void cris_cpu_initfn(Object *obj) CRISCPUClass *ccc = CRIS_CPU_GET_CLASS(obj); CPUCRISState *env = &cpu->env; - cpu_set_cpustate_pointers(cpu); - env->pregs[PR_VR] = ccc->vr; #ifndef CONFIG_USER_ONLY diff --git a/target/hexagon/cpu.c b/target/hexagon/cpu.c index 65f198b956..1adc11b713 100644 --- a/target/hexagon/cpu.c +++ b/target/hexagon/cpu.c @@ -353,9 +353,6 @@ static void hexagon_cpu_realize(DeviceState *dev, Error **errp) static void hexagon_cpu_init(Object *obj) { - HexagonCPU *cpu = HEXAGON_CPU(obj); - - cpu_set_cpustate_pointers(cpu); qdev_property_add_static(DEVICE(obj), &hexagon_lldb_compat_property); qdev_property_add_static(DEVICE(obj), &hexagon_lldb_stack_adjust_property); qdev_property_add_static(DEVICE(obj), &hexagon_short_circuit_property); diff --git a/target/hppa/cpu.c b/target/hppa/cpu.c index 17fa901f6a..1644297bf8 100644 --- a/target/hppa/cpu.c +++ b/target/hppa/cpu.c @@ -149,7 +149,6 @@ static void hppa_cpu_initfn(Object *obj) HPPACPU *cpu = HPPA_CPU(obj); CPUHPPAState *env = &cpu->env; - cpu_set_cpustate_pointers(cpu); cs->exception_index = -1; cpu_hppa_loaded_fr0(env); cpu_hppa_put_psw(env, PSW_W); diff --git a/target/i386/cpu.c b/target/i386/cpu.c index 187ebb0dbc..9fad31b8db 100644 --- a/target/i386/cpu.c +++ b/target/i386/cpu.c @@ -7590,7 +7590,6 @@ static void x86_cpu_initfn(Object *obj) CPUX86State *env = &cpu->env; env->nr_dies = 1; - cpu_set_cpustate_pointers(cpu); object_property_add(obj, "feature-words", "X86CPUFeatureWordInfo", x86_cpu_get_feature_words, diff --git a/target/loongarch/cpu.c b/target/loongarch/cpu.c index d5e403bbb7..2bea7ca5d5 100644 --- a/target/loongarch/cpu.c +++ b/target/loongarch/cpu.c @@ -618,17 +618,15 @@ static const MemoryRegionOps loongarch_qemu_ops = { static void loongarch_cpu_init(Object *obj) { - LoongArchCPU *cpu = LOONGARCH_CPU(obj); - - cpu_set_cpustate_pointers(cpu); - #ifndef CONFIG_USER_ONLY + LoongArchCPU *cpu = LOONGARCH_CPU(obj); CPULoongArchState *env = &cpu->env; + qdev_init_gpio_in(DEVICE(cpu), loongarch_cpu_set_irq, N_IRQS); timer_init_ns(&cpu->timer, QEMU_CLOCK_VIRTUAL, &loongarch_constant_timer_cb, cpu); memory_region_init_io(&env->system_iocsr, OBJECT(cpu), NULL, - env, "iocsr", UINT64_MAX); + env, "iocsr", UINT64_MAX); address_space_init(&env->address_space_iocsr, &env->system_iocsr, "IOCSR"); memory_region_init_io(&env->iocsr_mem, OBJECT(cpu), &loongarch_qemu_ops, NULL, "iocsr_misc", 0x428); diff --git a/target/m68k/cpu.c b/target/m68k/cpu.c index d34d1b57d0..538d9473c2 100644 --- a/target/m68k/cpu.c +++ b/target/m68k/cpu.c @@ -327,13 +327,6 @@ static void m68k_cpu_realizefn(DeviceState *dev, Error **errp) mcc->parent_realize(dev, errp); } -static void m68k_cpu_initfn(Object *obj) -{ - M68kCPU *cpu = M68K_CPU(obj); - - cpu_set_cpustate_pointers(cpu); -} - #if !defined(CONFIG_USER_ONLY) static bool fpu_needed(void *opaque) { @@ -612,7 +605,6 @@ static const TypeInfo m68k_cpus_type_infos[] = { .parent = TYPE_CPU, .instance_size = sizeof(M68kCPU), .instance_align = __alignof(M68kCPU), - .instance_init = m68k_cpu_initfn, .abstract = true, .class_size = sizeof(M68kCPUClass), .class_init = m68k_cpu_class_init, diff --git a/target/microblaze/cpu.c b/target/microblaze/cpu.c index c53711da52..bbb3335cad 100644 --- a/target/microblaze/cpu.c +++ b/target/microblaze/cpu.c @@ -296,7 +296,6 @@ static void mb_cpu_initfn(Object *obj) MicroBlazeCPU *cpu = MICROBLAZE_CPU(obj); CPUMBState *env = &cpu->env; - cpu_set_cpustate_pointers(cpu); gdb_register_coprocessor(CPU(cpu), mb_cpu_gdb_read_stack_protect, mb_cpu_gdb_write_stack_protect, 2, "microblaze-stack-protect.xml", 0); diff --git a/target/mips/cpu.c b/target/mips/cpu.c index fee791aa44..a0023edd43 100644 --- a/target/mips/cpu.c +++ b/target/mips/cpu.c @@ -504,7 +504,6 @@ static void mips_cpu_initfn(Object *obj) CPUMIPSState *env = &cpu->env; MIPSCPUClass *mcc = MIPS_CPU_GET_CLASS(obj); - cpu_set_cpustate_pointers(cpu); cpu->clock = qdev_init_clock_in(DEVICE(obj), "clk-in", NULL, cpu, 0); cpu->count_div = clock_new(OBJECT(obj), "clk-div-count"); env->count_clock = clock_new(OBJECT(obj), "clk-count"); diff --git a/target/nios2/cpu.c b/target/nios2/cpu.c index 598976305f..15e499f828 100644 --- a/target/nios2/cpu.c +++ b/target/nios2/cpu.c @@ -113,11 +113,9 @@ static void iic_set_irq(void *opaque, int irq, int level) static void nios2_cpu_initfn(Object *obj) { +#if !defined(CONFIG_USER_ONLY) Nios2CPU *cpu = NIOS2_CPU(obj); - cpu_set_cpustate_pointers(cpu); - -#if !defined(CONFIG_USER_ONLY) mmu_init(&cpu->env); #endif } diff --git a/target/openrisc/cpu.c b/target/openrisc/cpu.c index be067709b8..f5a3d5273b 100644 --- a/target/openrisc/cpu.c +++ b/target/openrisc/cpu.c @@ -149,12 +149,8 @@ static void openrisc_cpu_realizefn(DeviceState *dev, Error **errp) static void openrisc_cpu_initfn(Object *obj) { - OpenRISCCPU *cpu = OPENRISC_CPU(obj); - - cpu_set_cpustate_pointers(cpu); - #ifndef CONFIG_USER_ONLY - qdev_init_gpio_in_named(DEVICE(cpu), openrisc_cpu_set_irq, "IRQ", NR_IRQS); + qdev_init_gpio_in_named(DEVICE(obj), openrisc_cpu_set_irq, "IRQ", NR_IRQS); #endif } diff --git a/target/ppc/cpu_init.c b/target/ppc/cpu_init.c index c62bf0e437..40fe14a6c2 100644 --- a/target/ppc/cpu_init.c +++ b/target/ppc/cpu_init.c @@ -7246,7 +7246,6 @@ static void ppc_cpu_instance_init(Object *obj) PowerPCCPUClass *pcc = POWERPC_CPU_GET_CLASS(cpu); CPUPPCState *env = &cpu->env; - cpu_set_cpustate_pointers(cpu); cpu->vcpu_id = UNASSIGNED_CPU_INDEX; env->msr_mask = pcc->msr_mask; diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c index d69c40d380..ac2b94b6a6 100644 --- a/target/riscv/cpu.c +++ b/target/riscv/cpu.c @@ -1649,12 +1649,8 @@ static void riscv_cpu_set_irq(void *opaque, int irq, int level) static void riscv_cpu_init(Object *obj) { - RISCVCPU *cpu = RISCV_CPU(obj); - - cpu_set_cpustate_pointers(cpu); - #ifndef CONFIG_USER_ONLY - qdev_init_gpio_in(DEVICE(cpu), riscv_cpu_set_irq, + qdev_init_gpio_in(DEVICE(obj), riscv_cpu_set_irq, IRQ_LOCAL_MAX + IRQ_LOCAL_GUEST_MAX); #endif /* CONFIG_USER_ONLY */ } diff --git a/target/rx/cpu.c b/target/rx/cpu.c index 2e7a736590..4d0d3a0c8c 100644 --- a/target/rx/cpu.c +++ b/target/rx/cpu.c @@ -185,7 +185,6 @@ static void rx_cpu_init(Object *obj) { RXCPU *cpu = RX_CPU(obj); - cpu_set_cpustate_pointers(cpu); qdev_init_gpio_in(DEVICE(cpu), rx_cpu_set_irq, 2); } diff --git a/target/s390x/cpu.c b/target/s390x/cpu.c index df167493c3..4f7599d72c 100644 --- a/target/s390x/cpu.c +++ b/target/s390x/cpu.c @@ -274,9 +274,7 @@ out: static void s390_cpu_initfn(Object *obj) { CPUState *cs = CPU(obj); - S390CPU *cpu = S390_CPU(obj); - cpu_set_cpustate_pointers(cpu); cs->exception_index = EXCP_HLT; #if !defined(CONFIG_USER_ONLY) diff --git a/target/sh4/cpu.c b/target/sh4/cpu.c index a90e41c4ec..788e41fea6 100644 --- a/target/sh4/cpu.c +++ b/target/sh4/cpu.c @@ -239,8 +239,6 @@ static void superh_cpu_initfn(Object *obj) SuperHCPU *cpu = SUPERH_CPU(obj); CPUSH4State *env = &cpu->env; - cpu_set_cpustate_pointers(cpu); - env->movcal_backup_tail = &(env->movcal_backup); } diff --git a/target/sparc/cpu.c b/target/sparc/cpu.c index d6d3c4b031..8ba96ae225 100644 --- a/target/sparc/cpu.c +++ b/target/sparc/cpu.c @@ -793,8 +793,6 @@ static void sparc_cpu_initfn(Object *obj) SPARCCPUClass *scc = SPARC_CPU_GET_CLASS(obj); CPUSPARCState *env = &cpu->env; - cpu_set_cpustate_pointers(cpu); - if (scc->cpu_def) { env->def = *scc->cpu_def; } diff --git a/target/tricore/cpu.c b/target/tricore/cpu.c index 50aec6cf10..d1477622e6 100644 --- a/target/tricore/cpu.c +++ b/target/tricore/cpu.c @@ -124,14 +124,6 @@ static void tricore_cpu_realizefn(DeviceState *dev, Error **errp) tcc->parent_realize(dev, errp); } - -static void tricore_cpu_initfn(Object *obj) -{ - TriCoreCPU *cpu = TRICORE_CPU(obj); - - cpu_set_cpustate_pointers(cpu); -} - static ObjectClass *tricore_cpu_class_by_name(const char *cpu_model) { ObjectClass *oc; @@ -231,7 +223,6 @@ static const TypeInfo tricore_cpu_type_infos[] = { .parent = TYPE_CPU, .instance_size = sizeof(TriCoreCPU), .instance_align = __alignof(TriCoreCPU), - .instance_init = tricore_cpu_initfn, .abstract = true, .class_size = sizeof(TriCoreCPUClass), .class_init = tricore_cpu_class_init, diff --git a/target/xtensa/cpu.c b/target/xtensa/cpu.c index 281872d7ca..ea1dae7390 100644 --- a/target/xtensa/cpu.c +++ b/target/xtensa/cpu.c @@ -185,7 +185,6 @@ static void xtensa_cpu_initfn(Object *obj) XtensaCPUClass *xcc = XTENSA_CPU_GET_CLASS(obj); CPUXtensaState *env = &cpu->env; - cpu_set_cpustate_pointers(cpu); env->config = xcc->config; #ifndef CONFIG_USER_ONLY From 06ddecff244a7fbb2c98352cdfed44fea66608bc Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 13 Sep 2023 17:41:13 -0700 Subject: [PATCH 0250/1077] accel/tcg: Remove env_neg() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Replace the single use within env_tlb() and remove. Reviewed-by: Anton Johansson Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Richard Henderson --- include/exec/cpu-all.h | 13 +------------ 1 file changed, 1 insertion(+), 12 deletions(-) diff --git a/include/exec/cpu-all.h b/include/exec/cpu-all.h index 9d8ab050c2..46e494eeba 100644 --- a/include/exec/cpu-all.h +++ b/include/exec/cpu-all.h @@ -449,17 +449,6 @@ static inline CPUState *env_cpu(CPUArchState *env) return (void *)env - sizeof(CPUState); } -/** - * env_neg(env) - * @env: The architecture environment - * - * Return the CPUNegativeOffsetState associated with the environment. - */ -static inline CPUNegativeOffsetState *env_neg(CPUArchState *env) -{ - return &env_cpu(env)->neg; -} - /** * env_tlb(env) * @env: The architecture environment @@ -468,7 +457,7 @@ static inline CPUNegativeOffsetState *env_neg(CPUArchState *env) */ static inline CPUTLB *env_tlb(CPUArchState *env) { - return &env_neg(env)->tlb; + return &env_cpu(env)->neg.tlb; } #endif /* CPU_ALL_H */ From 7857ee114c6518165653d3ba87f24a1815c26f6f Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 13 Sep 2023 17:56:21 -0700 Subject: [PATCH 0251/1077] tcg: Remove TCGContext.tlb_fast_offset Now that there is no padding between CPUNegativeOffsetState and CPUArchState, this value is constant across all targets. Reviewed-by: Anton Johansson Signed-off-by: Richard Henderson --- accel/tcg/translate-all.c | 2 -- include/tcg/tcg.h | 1 - tcg/tcg.c | 15 +++++++++------ 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/accel/tcg/translate-all.c b/accel/tcg/translate-all.c index 6fac5b7e29..83e07b830f 100644 --- a/accel/tcg/translate-all.c +++ b/accel/tcg/translate-all.c @@ -344,8 +344,6 @@ TranslationBlock *tb_gen_code(CPUState *cpu, tcg_ctx->page_bits = TARGET_PAGE_BITS; tcg_ctx->page_mask = TARGET_PAGE_MASK; tcg_ctx->tlb_dyn_max_bits = CPU_TLB_DYN_MAX_BITS; - tcg_ctx->tlb_fast_offset = (int)offsetof(ArchCPU, parent_obj.neg.tlb.f) - - (int)offsetof(ArchCPU, env); #endif tcg_ctx->insn_start_words = TARGET_INSN_START_WORDS; #ifdef TCG_GUEST_DEFAULT_MO diff --git a/include/tcg/tcg.h b/include/tcg/tcg.h index 3cdbeaf460..7743868dc9 100644 --- a/include/tcg/tcg.h +++ b/include/tcg/tcg.h @@ -489,7 +489,6 @@ struct TCGContext { TCGType addr_type; /* TCG_TYPE_I32 or TCG_TYPE_I64 */ #ifdef CONFIG_SOFTMMU - int tlb_fast_offset; int page_mask; uint8_t page_bits; uint8_t tlb_dyn_max_bits; diff --git a/tcg/tcg.c b/tcg/tcg.c index ec3f93a52f..9256217b8f 100644 --- a/tcg/tcg.c +++ b/tcg/tcg.c @@ -406,7 +406,8 @@ static uintptr_t G_GNUC_UNUSED get_jmp_target_addr(TCGContext *s, int which) #if defined(CONFIG_SOFTMMU) && !defined(CONFIG_TCG_INTERPRETER) static int tlb_mask_table_ofs(TCGContext *s, int which) { - return s->tlb_fast_offset + which * sizeof(CPUTLBDescFast); + return (offsetof(CPUNegativeOffsetState, tlb.f[which]) - + sizeof(CPUNegativeOffsetState)); } #endif @@ -734,6 +735,13 @@ static const TCGTargetOpDef constraint_sets[] = { #include "tcg-target.c.inc" +#ifndef CONFIG_TCG_INTERPRETER +/* Validate CPUTLBDescFast placement. */ +QEMU_BUILD_BUG_ON((int)(offsetof(CPUNegativeOffsetState, tlb.f[0]) - + sizeof(CPUNegativeOffsetState)) + < MIN_TLB_MASK_TABLE_OFS); +#endif + static void alloc_tcg_plugin_context(TCGContext *s) { #ifdef CONFIG_PLUGIN @@ -1497,11 +1505,6 @@ void tcg_func_start(TCGContext *s) tcg_debug_assert(s->addr_type == TCG_TYPE_I32 || s->addr_type == TCG_TYPE_I64); -#if defined(CONFIG_SOFTMMU) && !defined(CONFIG_TCG_INTERPRETER) - tcg_debug_assert(s->tlb_fast_offset < 0); - tcg_debug_assert(s->tlb_fast_offset >= MIN_TLB_MASK_TABLE_OFS); -#endif - tcg_debug_assert(s->insn_start_words > 0); } From 10b32e2cd9ab203c1643fbb0522550e64be8376f Mon Sep 17 00:00:00 2001 From: Anton Johansson Date: Tue, 12 Sep 2023 17:34:20 +0200 Subject: [PATCH 0252/1077] accel/tcg: Modify tlb_*() to use CPUState MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Changes tlb_*() functions to take CPUState instead of CPUArchState, as they don't require the full CPUArchState. This makes it easier to decouple target-(in)dependent code. Signed-off-by: Anton Johansson Message-Id: <20230912153428.17816-4-anjo@rev.ng> Reviewed-by: Richard Henderson Reviewed-by: Philippe Mathieu-Daudé [rth: Use cpu->neg.tlb instead of cpu_tlb()] Signed-off-by: Richard Henderson --- accel/tcg/cputlb.c | 220 +++++++++++++++++++--------------------- include/exec/cpu_ldst.h | 8 +- 2 files changed, 108 insertions(+), 120 deletions(-) diff --git a/accel/tcg/cputlb.c b/accel/tcg/cputlb.c index f790be5b6e..f88c394594 100644 --- a/accel/tcg/cputlb.c +++ b/accel/tcg/cputlb.c @@ -240,11 +240,11 @@ static void tlb_mmu_flush_locked(CPUTLBDesc *desc, CPUTLBDescFast *fast) memset(desc->vtable, -1, sizeof(desc->vtable)); } -static void tlb_flush_one_mmuidx_locked(CPUArchState *env, int mmu_idx, +static void tlb_flush_one_mmuidx_locked(CPUState *cpu, int mmu_idx, int64_t now) { - CPUTLBDesc *desc = &env_tlb(env)->d[mmu_idx]; - CPUTLBDescFast *fast = &env_tlb(env)->f[mmu_idx]; + CPUTLBDesc *desc = &cpu->neg.tlb.d[mmu_idx]; + CPUTLBDescFast *fast = &cpu->neg.tlb.f[mmu_idx]; tlb_mmu_resize_locked(desc, fast, now); tlb_mmu_flush_locked(desc, fast); @@ -262,41 +262,39 @@ static void tlb_mmu_init(CPUTLBDesc *desc, CPUTLBDescFast *fast, int64_t now) tlb_mmu_flush_locked(desc, fast); } -static inline void tlb_n_used_entries_inc(CPUArchState *env, uintptr_t mmu_idx) +static inline void tlb_n_used_entries_inc(CPUState *cpu, uintptr_t mmu_idx) { - env_tlb(env)->d[mmu_idx].n_used_entries++; + cpu->neg.tlb.d[mmu_idx].n_used_entries++; } -static inline void tlb_n_used_entries_dec(CPUArchState *env, uintptr_t mmu_idx) +static inline void tlb_n_used_entries_dec(CPUState *cpu, uintptr_t mmu_idx) { - env_tlb(env)->d[mmu_idx].n_used_entries--; + cpu->neg.tlb.d[mmu_idx].n_used_entries--; } void tlb_init(CPUState *cpu) { - CPUArchState *env = cpu_env(cpu); int64_t now = get_clock_realtime(); int i; - qemu_spin_init(&env_tlb(env)->c.lock); + qemu_spin_init(&cpu->neg.tlb.c.lock); /* All tlbs are initialized flushed. */ - env_tlb(env)->c.dirty = 0; + cpu->neg.tlb.c.dirty = 0; for (i = 0; i < NB_MMU_MODES; i++) { - tlb_mmu_init(&env_tlb(env)->d[i], &env_tlb(env)->f[i], now); + tlb_mmu_init(&cpu->neg.tlb.d[i], &cpu->neg.tlb.f[i], now); } } void tlb_destroy(CPUState *cpu) { - CPUArchState *env = cpu_env(cpu); int i; - qemu_spin_destroy(&env_tlb(env)->c.lock); + qemu_spin_destroy(&cpu->neg.tlb.c.lock); for (i = 0; i < NB_MMU_MODES; i++) { - CPUTLBDesc *desc = &env_tlb(env)->d[i]; - CPUTLBDescFast *fast = &env_tlb(env)->f[i]; + CPUTLBDesc *desc = &cpu->neg.tlb.d[i]; + CPUTLBDescFast *fast = &cpu->neg.tlb.f[i]; g_free(fast->table); g_free(desc->fulltlb); @@ -328,11 +326,9 @@ void tlb_flush_counts(size_t *pfull, size_t *ppart, size_t *pelide) size_t full = 0, part = 0, elide = 0; CPU_FOREACH(cpu) { - CPUArchState *env = cpu_env(cpu); - - full += qatomic_read(&env_tlb(env)->c.full_flush_count); - part += qatomic_read(&env_tlb(env)->c.part_flush_count); - elide += qatomic_read(&env_tlb(env)->c.elide_flush_count); + full += qatomic_read(&cpu->neg.tlb.c.full_flush_count); + part += qatomic_read(&cpu->neg.tlb.c.part_flush_count); + elide += qatomic_read(&cpu->neg.tlb.c.elide_flush_count); } *pfull = full; *ppart = part; @@ -341,7 +337,6 @@ void tlb_flush_counts(size_t *pfull, size_t *ppart, size_t *pelide) static void tlb_flush_by_mmuidx_async_work(CPUState *cpu, run_on_cpu_data data) { - CPUArchState *env = cpu_env(cpu); uint16_t asked = data.host_int; uint16_t all_dirty, work, to_clean; int64_t now = get_clock_realtime(); @@ -350,32 +345,32 @@ static void tlb_flush_by_mmuidx_async_work(CPUState *cpu, run_on_cpu_data data) tlb_debug("mmu_idx:0x%04" PRIx16 "\n", asked); - qemu_spin_lock(&env_tlb(env)->c.lock); + qemu_spin_lock(&cpu->neg.tlb.c.lock); - all_dirty = env_tlb(env)->c.dirty; + all_dirty = cpu->neg.tlb.c.dirty; to_clean = asked & all_dirty; all_dirty &= ~to_clean; - env_tlb(env)->c.dirty = all_dirty; + cpu->neg.tlb.c.dirty = all_dirty; for (work = to_clean; work != 0; work &= work - 1) { int mmu_idx = ctz32(work); - tlb_flush_one_mmuidx_locked(env, mmu_idx, now); + tlb_flush_one_mmuidx_locked(cpu, mmu_idx, now); } - qemu_spin_unlock(&env_tlb(env)->c.lock); + qemu_spin_unlock(&cpu->neg.tlb.c.lock); tcg_flush_jmp_cache(cpu); if (to_clean == ALL_MMUIDX_BITS) { - qatomic_set(&env_tlb(env)->c.full_flush_count, - env_tlb(env)->c.full_flush_count + 1); + qatomic_set(&cpu->neg.tlb.c.full_flush_count, + cpu->neg.tlb.c.full_flush_count + 1); } else { - qatomic_set(&env_tlb(env)->c.part_flush_count, - env_tlb(env)->c.part_flush_count + ctpop16(to_clean)); + qatomic_set(&cpu->neg.tlb.c.part_flush_count, + cpu->neg.tlb.c.part_flush_count + ctpop16(to_clean)); if (to_clean != asked) { - qatomic_set(&env_tlb(env)->c.elide_flush_count, - env_tlb(env)->c.elide_flush_count + - ctpop16(asked & ~to_clean)); + qatomic_set(&cpu->neg.tlb.c.elide_flush_count, + cpu->neg.tlb.c.elide_flush_count + + ctpop16(asked & ~to_clean)); } } } @@ -470,43 +465,43 @@ static inline bool tlb_flush_entry_locked(CPUTLBEntry *tlb_entry, vaddr page) } /* Called with tlb_c.lock held */ -static void tlb_flush_vtlb_page_mask_locked(CPUArchState *env, int mmu_idx, +static void tlb_flush_vtlb_page_mask_locked(CPUState *cpu, int mmu_idx, vaddr page, vaddr mask) { - CPUTLBDesc *d = &env_tlb(env)->d[mmu_idx]; + CPUTLBDesc *d = &cpu->neg.tlb.d[mmu_idx]; int k; - assert_cpu_is_self(env_cpu(env)); + assert_cpu_is_self(cpu); for (k = 0; k < CPU_VTLB_SIZE; k++) { if (tlb_flush_entry_mask_locked(&d->vtable[k], page, mask)) { - tlb_n_used_entries_dec(env, mmu_idx); + tlb_n_used_entries_dec(cpu, mmu_idx); } } } -static inline void tlb_flush_vtlb_page_locked(CPUArchState *env, int mmu_idx, +static inline void tlb_flush_vtlb_page_locked(CPUState *cpu, int mmu_idx, vaddr page) { - tlb_flush_vtlb_page_mask_locked(env, mmu_idx, page, -1); + tlb_flush_vtlb_page_mask_locked(cpu, mmu_idx, page, -1); } -static void tlb_flush_page_locked(CPUArchState *env, int midx, vaddr page) +static void tlb_flush_page_locked(CPUState *cpu, int midx, vaddr page) { - vaddr lp_addr = env_tlb(env)->d[midx].large_page_addr; - vaddr lp_mask = env_tlb(env)->d[midx].large_page_mask; + vaddr lp_addr = cpu->neg.tlb.d[midx].large_page_addr; + vaddr lp_mask = cpu->neg.tlb.d[midx].large_page_mask; /* Check if we need to flush due to large pages. */ if ((page & lp_mask) == lp_addr) { tlb_debug("forcing full flush midx %d (%016" VADDR_PRIx "/%016" VADDR_PRIx ")\n", midx, lp_addr, lp_mask); - tlb_flush_one_mmuidx_locked(env, midx, get_clock_realtime()); + tlb_flush_one_mmuidx_locked(cpu, midx, get_clock_realtime()); } else { - if (tlb_flush_entry_locked(tlb_entry(env, midx, page), page)) { - tlb_n_used_entries_dec(env, midx); + if (tlb_flush_entry_locked(tlb_entry(cpu, midx, page), page)) { + tlb_n_used_entries_dec(cpu, midx); } - tlb_flush_vtlb_page_locked(env, midx, page); + tlb_flush_vtlb_page_locked(cpu, midx, page); } } @@ -523,20 +518,19 @@ static void tlb_flush_page_by_mmuidx_async_0(CPUState *cpu, vaddr addr, uint16_t idxmap) { - CPUArchState *env = cpu_env(cpu); int mmu_idx; assert_cpu_is_self(cpu); tlb_debug("page addr: %016" VADDR_PRIx " mmu_map:0x%x\n", addr, idxmap); - qemu_spin_lock(&env_tlb(env)->c.lock); + qemu_spin_lock(&cpu->neg.tlb.c.lock); for (mmu_idx = 0; mmu_idx < NB_MMU_MODES; mmu_idx++) { if ((idxmap >> mmu_idx) & 1) { - tlb_flush_page_locked(env, mmu_idx, addr); + tlb_flush_page_locked(cpu, mmu_idx, addr); } } - qemu_spin_unlock(&env_tlb(env)->c.lock); + qemu_spin_unlock(&cpu->neg.tlb.c.lock); /* * Discard jump cache entries for any tb which might potentially @@ -709,12 +703,12 @@ void tlb_flush_page_all_cpus_synced(CPUState *src, vaddr addr) tlb_flush_page_by_mmuidx_all_cpus_synced(src, addr, ALL_MMUIDX_BITS); } -static void tlb_flush_range_locked(CPUArchState *env, int midx, +static void tlb_flush_range_locked(CPUState *cpu, int midx, vaddr addr, vaddr len, unsigned bits) { - CPUTLBDesc *d = &env_tlb(env)->d[midx]; - CPUTLBDescFast *f = &env_tlb(env)->f[midx]; + CPUTLBDesc *d = &cpu->neg.tlb.d[midx]; + CPUTLBDescFast *f = &cpu->neg.tlb.f[midx]; vaddr mask = MAKE_64BIT_MASK(0, bits); /* @@ -731,7 +725,7 @@ static void tlb_flush_range_locked(CPUArchState *env, int midx, tlb_debug("forcing full flush midx %d (" "%016" VADDR_PRIx "/%016" VADDR_PRIx "+%016" VADDR_PRIx ")\n", midx, addr, mask, len); - tlb_flush_one_mmuidx_locked(env, midx, get_clock_realtime()); + tlb_flush_one_mmuidx_locked(cpu, midx, get_clock_realtime()); return; } @@ -744,18 +738,18 @@ static void tlb_flush_range_locked(CPUArchState *env, int midx, tlb_debug("forcing full flush midx %d (" "%016" VADDR_PRIx "/%016" VADDR_PRIx ")\n", midx, d->large_page_addr, d->large_page_mask); - tlb_flush_one_mmuidx_locked(env, midx, get_clock_realtime()); + tlb_flush_one_mmuidx_locked(cpu, midx, get_clock_realtime()); return; } for (vaddr i = 0; i < len; i += TARGET_PAGE_SIZE) { vaddr page = addr + i; - CPUTLBEntry *entry = tlb_entry(env, midx, page); + CPUTLBEntry *entry = tlb_entry(cpu, midx, page); if (tlb_flush_entry_mask_locked(entry, page, mask)) { - tlb_n_used_entries_dec(env, midx); + tlb_n_used_entries_dec(cpu, midx); } - tlb_flush_vtlb_page_mask_locked(env, midx, page, mask); + tlb_flush_vtlb_page_mask_locked(cpu, midx, page, mask); } } @@ -769,7 +763,6 @@ typedef struct { static void tlb_flush_range_by_mmuidx_async_0(CPUState *cpu, TLBFlushRangeData d) { - CPUArchState *env = cpu_env(cpu); int mmu_idx; assert_cpu_is_self(cpu); @@ -777,13 +770,13 @@ static void tlb_flush_range_by_mmuidx_async_0(CPUState *cpu, tlb_debug("range: %016" VADDR_PRIx "/%u+%016" VADDR_PRIx " mmu_map:0x%x\n", d.addr, d.bits, d.len, d.idxmap); - qemu_spin_lock(&env_tlb(env)->c.lock); + qemu_spin_lock(&cpu->neg.tlb.c.lock); for (mmu_idx = 0; mmu_idx < NB_MMU_MODES; mmu_idx++) { if ((d.idxmap >> mmu_idx) & 1) { - tlb_flush_range_locked(env, mmu_idx, d.addr, d.len, d.bits); + tlb_flush_range_locked(cpu, mmu_idx, d.addr, d.len, d.bits); } } - qemu_spin_unlock(&env_tlb(env)->c.lock); + qemu_spin_unlock(&cpu->neg.tlb.c.lock); /* * If the length is larger than the jump cache size, then it will take @@ -1028,27 +1021,24 @@ static inline void copy_tlb_helper_locked(CPUTLBEntry *d, const CPUTLBEntry *s) */ void tlb_reset_dirty(CPUState *cpu, ram_addr_t start1, ram_addr_t length) { - CPUArchState *env; - int mmu_idx; - env = cpu_env(cpu); - qemu_spin_lock(&env_tlb(env)->c.lock); + qemu_spin_lock(&cpu->neg.tlb.c.lock); for (mmu_idx = 0; mmu_idx < NB_MMU_MODES; mmu_idx++) { unsigned int i; - unsigned int n = tlb_n_entries(&env_tlb(env)->f[mmu_idx]); + unsigned int n = tlb_n_entries(&cpu->neg.tlb.f[mmu_idx]); for (i = 0; i < n; i++) { - tlb_reset_dirty_range_locked(&env_tlb(env)->f[mmu_idx].table[i], + tlb_reset_dirty_range_locked(&cpu->neg.tlb.f[mmu_idx].table[i], start1, length); } for (i = 0; i < CPU_VTLB_SIZE; i++) { - tlb_reset_dirty_range_locked(&env_tlb(env)->d[mmu_idx].vtable[i], + tlb_reset_dirty_range_locked(&cpu->neg.tlb.d[mmu_idx].vtable[i], start1, length); } } - qemu_spin_unlock(&env_tlb(env)->c.lock); + qemu_spin_unlock(&cpu->neg.tlb.c.lock); } /* Called with tlb_c.lock held */ @@ -1064,32 +1054,31 @@ static inline void tlb_set_dirty1_locked(CPUTLBEntry *tlb_entry, so that it is no longer dirty */ void tlb_set_dirty(CPUState *cpu, vaddr addr) { - CPUArchState *env = cpu_env(cpu); int mmu_idx; assert_cpu_is_self(cpu); addr &= TARGET_PAGE_MASK; - qemu_spin_lock(&env_tlb(env)->c.lock); + qemu_spin_lock(&cpu->neg.tlb.c.lock); for (mmu_idx = 0; mmu_idx < NB_MMU_MODES; mmu_idx++) { - tlb_set_dirty1_locked(tlb_entry(env, mmu_idx, addr), addr); + tlb_set_dirty1_locked(tlb_entry(cpu, mmu_idx, addr), addr); } for (mmu_idx = 0; mmu_idx < NB_MMU_MODES; mmu_idx++) { int k; for (k = 0; k < CPU_VTLB_SIZE; k++) { - tlb_set_dirty1_locked(&env_tlb(env)->d[mmu_idx].vtable[k], addr); + tlb_set_dirty1_locked(&cpu->neg.tlb.d[mmu_idx].vtable[k], addr); } } - qemu_spin_unlock(&env_tlb(env)->c.lock); + qemu_spin_unlock(&cpu->neg.tlb.c.lock); } /* Our TLB does not support large pages, so remember the area covered by large pages and trigger a full TLB flush if these are invalidated. */ -static void tlb_add_large_page(CPUArchState *env, int mmu_idx, +static void tlb_add_large_page(CPUState *cpu, int mmu_idx, vaddr addr, uint64_t size) { - vaddr lp_addr = env_tlb(env)->d[mmu_idx].large_page_addr; + vaddr lp_addr = cpu->neg.tlb.d[mmu_idx].large_page_addr; vaddr lp_mask = ~(size - 1); if (lp_addr == (vaddr)-1) { @@ -1099,13 +1088,13 @@ static void tlb_add_large_page(CPUArchState *env, int mmu_idx, /* Extend the existing region to include the new page. This is a compromise between unnecessary flushes and the cost of maintaining a full variable size TLB. */ - lp_mask &= env_tlb(env)->d[mmu_idx].large_page_mask; + lp_mask &= cpu->neg.tlb.d[mmu_idx].large_page_mask; while (((lp_addr ^ addr) & lp_mask) != 0) { lp_mask <<= 1; } } - env_tlb(env)->d[mmu_idx].large_page_addr = lp_addr & lp_mask; - env_tlb(env)->d[mmu_idx].large_page_mask = lp_mask; + cpu->neg.tlb.d[mmu_idx].large_page_addr = lp_addr & lp_mask; + cpu->neg.tlb.d[mmu_idx].large_page_mask = lp_mask; } static inline void tlb_set_compare(CPUTLBEntryFull *full, CPUTLBEntry *ent, @@ -1137,8 +1126,7 @@ static inline void tlb_set_compare(CPUTLBEntryFull *full, CPUTLBEntry *ent, void tlb_set_page_full(CPUState *cpu, int mmu_idx, vaddr addr, CPUTLBEntryFull *full) { - CPUArchState *env = cpu_env(cpu); - CPUTLB *tlb = env_tlb(env); + CPUTLB *tlb = &cpu->neg.tlb; CPUTLBDesc *desc = &tlb->d[mmu_idx]; MemoryRegionSection *section; unsigned int index, read_flags, write_flags; @@ -1155,7 +1143,7 @@ void tlb_set_page_full(CPUState *cpu, int mmu_idx, sz = TARGET_PAGE_SIZE; } else { sz = (hwaddr)1 << full->lg_page_size; - tlb_add_large_page(env, mmu_idx, addr, sz); + tlb_add_large_page(cpu, mmu_idx, addr, sz); } addr_page = addr & TARGET_PAGE_MASK; paddr_page = full->phys_addr & TARGET_PAGE_MASK; @@ -1222,8 +1210,8 @@ void tlb_set_page_full(CPUState *cpu, int mmu_idx, wp_flags = cpu_watchpoint_address_matches(cpu, addr_page, TARGET_PAGE_SIZE); - index = tlb_index(env, mmu_idx, addr_page); - te = tlb_entry(env, mmu_idx, addr_page); + index = tlb_index(cpu, mmu_idx, addr_page); + te = tlb_entry(cpu, mmu_idx, addr_page); /* * Hold the TLB lock for the rest of the function. We could acquire/release @@ -1238,7 +1226,7 @@ void tlb_set_page_full(CPUState *cpu, int mmu_idx, tlb->c.dirty |= 1 << mmu_idx; /* Make sure there's no cached translation for the new page. */ - tlb_flush_vtlb_page_locked(env, mmu_idx, addr_page); + tlb_flush_vtlb_page_locked(cpu, mmu_idx, addr_page); /* * Only evict the old entry to the victim tlb if it's for a @@ -1251,7 +1239,7 @@ void tlb_set_page_full(CPUState *cpu, int mmu_idx, /* Evict the old entry into the victim tlb. */ copy_tlb_helper_locked(tv, te); desc->vfulltlb[vidx] = desc->fulltlb[index]; - tlb_n_used_entries_dec(env, mmu_idx); + tlb_n_used_entries_dec(cpu, mmu_idx); } /* refill the tlb */ @@ -1296,7 +1284,7 @@ void tlb_set_page_full(CPUState *cpu, int mmu_idx, MMU_DATA_STORE, prot & PAGE_WRITE); copy_tlb_helper_locked(te, &tn); - tlb_n_used_entries_inc(env, mmu_idx); + tlb_n_used_entries_inc(cpu, mmu_idx); qemu_spin_unlock(&tlb->c.lock); } @@ -1390,28 +1378,28 @@ static void io_failed(CPUArchState *env, CPUTLBEntryFull *full, vaddr addr, /* Return true if ADDR is present in the victim tlb, and has been copied back to the main tlb. */ -static bool victim_tlb_hit(CPUArchState *env, size_t mmu_idx, size_t index, +static bool victim_tlb_hit(CPUState *cpu, size_t mmu_idx, size_t index, MMUAccessType access_type, vaddr page) { size_t vidx; - assert_cpu_is_self(env_cpu(env)); + assert_cpu_is_self(cpu); for (vidx = 0; vidx < CPU_VTLB_SIZE; ++vidx) { - CPUTLBEntry *vtlb = &env_tlb(env)->d[mmu_idx].vtable[vidx]; + CPUTLBEntry *vtlb = &cpu->neg.tlb.d[mmu_idx].vtable[vidx]; uint64_t cmp = tlb_read_idx(vtlb, access_type); if (cmp == page) { /* Found entry in victim tlb, swap tlb and iotlb. */ - CPUTLBEntry tmptlb, *tlb = &env_tlb(env)->f[mmu_idx].table[index]; + CPUTLBEntry tmptlb, *tlb = &cpu->neg.tlb.f[mmu_idx].table[index]; - qemu_spin_lock(&env_tlb(env)->c.lock); + qemu_spin_lock(&cpu->neg.tlb.c.lock); copy_tlb_helper_locked(&tmptlb, tlb); copy_tlb_helper_locked(tlb, vtlb); copy_tlb_helper_locked(vtlb, &tmptlb); - qemu_spin_unlock(&env_tlb(env)->c.lock); + qemu_spin_unlock(&cpu->neg.tlb.c.lock); - CPUTLBEntryFull *f1 = &env_tlb(env)->d[mmu_idx].fulltlb[index]; - CPUTLBEntryFull *f2 = &env_tlb(env)->d[mmu_idx].vfulltlb[vidx]; + CPUTLBEntryFull *f1 = &cpu->neg.tlb.d[mmu_idx].fulltlb[index]; + CPUTLBEntryFull *f2 = &cpu->neg.tlb.d[mmu_idx].vfulltlb[vidx]; CPUTLBEntryFull tmpf; tmpf = *f1; *f1 = *f2; *f2 = tmpf; return true; @@ -1450,8 +1438,8 @@ static int probe_access_internal(CPUArchState *env, vaddr addr, void **phost, CPUTLBEntryFull **pfull, uintptr_t retaddr, bool check_mem_cbs) { - uintptr_t index = tlb_index(env, mmu_idx, addr); - CPUTLBEntry *entry = tlb_entry(env, mmu_idx, addr); + uintptr_t index = tlb_index(env_cpu(env), mmu_idx, addr); + CPUTLBEntry *entry = tlb_entry(env_cpu(env), mmu_idx, addr); uint64_t tlb_addr = tlb_read_idx(entry, access_type); vaddr page_addr = addr & TARGET_PAGE_MASK; int flags = TLB_FLAGS_MASK & ~TLB_FORCE_SLOW; @@ -1459,7 +1447,8 @@ static int probe_access_internal(CPUArchState *env, vaddr addr, CPUTLBEntryFull *full; if (!tlb_hit_page(tlb_addr, page_addr)) { - if (!victim_tlb_hit(env, mmu_idx, index, access_type, page_addr)) { + if (!victim_tlb_hit(env_cpu(env), mmu_idx, index, + access_type, page_addr)) { CPUState *cs = env_cpu(env); if (!cs->cc->tcg_ops->tlb_fill(cs, addr, fault_size, access_type, @@ -1471,8 +1460,8 @@ static int probe_access_internal(CPUArchState *env, vaddr addr, } /* TLB resize via tlb_fill may have moved the entry. */ - index = tlb_index(env, mmu_idx, addr); - entry = tlb_entry(env, mmu_idx, addr); + index = tlb_index(env_cpu(env), mmu_idx, addr); + entry = tlb_entry(env_cpu(env), mmu_idx, addr); /* * With PAGE_WRITE_INV, we set TLB_INVALID_MASK immediately, @@ -1662,9 +1651,8 @@ tb_page_addr_t get_page_addr_code_hostp(CPUArchState *env, vaddr addr, bool tlb_plugin_lookup(CPUState *cpu, vaddr addr, int mmu_idx, bool is_store, struct qemu_plugin_hwaddr *data) { - CPUArchState *env = cpu_env(cpu); - CPUTLBEntry *tlbe = tlb_entry(env, mmu_idx, addr); - uintptr_t index = tlb_index(env, mmu_idx, addr); + CPUTLBEntry *tlbe = tlb_entry(cpu, mmu_idx, addr); + uintptr_t index = tlb_index(cpu, mmu_idx, addr); MMUAccessType access_type = is_store ? MMU_DATA_STORE : MMU_DATA_LOAD; uint64_t tlb_addr = tlb_read_idx(tlbe, access_type); CPUTLBEntryFull *full; @@ -1673,7 +1661,7 @@ bool tlb_plugin_lookup(CPUState *cpu, vaddr addr, int mmu_idx, return false; } - full = &env_tlb(env)->d[mmu_idx].fulltlb[index]; + full = &cpu->neg.tlb.d[mmu_idx].fulltlb[index]; data->phys_addr = full->phys_addr | (addr & ~TARGET_PAGE_MASK); /* We must have an iotlb entry for MMIO */ @@ -1727,8 +1715,8 @@ static bool mmu_lookup1(CPUArchState *env, MMULookupPageData *data, int mmu_idx, MMUAccessType access_type, uintptr_t ra) { vaddr addr = data->addr; - uintptr_t index = tlb_index(env, mmu_idx, addr); - CPUTLBEntry *entry = tlb_entry(env, mmu_idx, addr); + uintptr_t index = tlb_index(env_cpu(env), mmu_idx, addr); + CPUTLBEntry *entry = tlb_entry(env_cpu(env), mmu_idx, addr); uint64_t tlb_addr = tlb_read_idx(entry, access_type); bool maybe_resized = false; CPUTLBEntryFull *full; @@ -1736,12 +1724,12 @@ static bool mmu_lookup1(CPUArchState *env, MMULookupPageData *data, /* If the TLB entry is for a different page, reload and try again. */ if (!tlb_hit(tlb_addr, addr)) { - if (!victim_tlb_hit(env, mmu_idx, index, access_type, + if (!victim_tlb_hit(env_cpu(env), mmu_idx, index, access_type, addr & TARGET_PAGE_MASK)) { tlb_fill(env_cpu(env), addr, data->size, access_type, mmu_idx, ra); maybe_resized = true; - index = tlb_index(env, mmu_idx, addr); - entry = tlb_entry(env, mmu_idx, addr); + index = tlb_index(env_cpu(env), mmu_idx, addr); + entry = tlb_entry(env_cpu(env), mmu_idx, addr); } tlb_addr = tlb_read_idx(entry, access_type) & ~TLB_INVALID_MASK; } @@ -1849,7 +1837,7 @@ static bool mmu_lookup(CPUArchState *env, vaddr addr, MemOpIdx oi, */ mmu_lookup1(env, &l->page[0], l->mmu_idx, type, ra); if (mmu_lookup1(env, &l->page[1], l->mmu_idx, type, ra)) { - uintptr_t index = tlb_index(env, l->mmu_idx, addr); + uintptr_t index = tlb_index(env_cpu(env), l->mmu_idx, addr); l->page[0].full = &env_tlb(env)->d[l->mmu_idx].fulltlb[index]; } @@ -1907,18 +1895,18 @@ static void *atomic_mmu_lookup(CPUArchState *env, vaddr addr, MemOpIdx oi, goto stop_the_world; } - index = tlb_index(env, mmu_idx, addr); - tlbe = tlb_entry(env, mmu_idx, addr); + index = tlb_index(env_cpu(env), mmu_idx, addr); + tlbe = tlb_entry(env_cpu(env), mmu_idx, addr); /* Check TLB entry and enforce page permissions. */ tlb_addr = tlb_addr_write(tlbe); if (!tlb_hit(tlb_addr, addr)) { - if (!victim_tlb_hit(env, mmu_idx, index, MMU_DATA_STORE, + if (!victim_tlb_hit(env_cpu(env), mmu_idx, index, MMU_DATA_STORE, addr & TARGET_PAGE_MASK)) { tlb_fill(env_cpu(env), addr, size, MMU_DATA_STORE, mmu_idx, retaddr); - index = tlb_index(env, mmu_idx, addr); - tlbe = tlb_entry(env, mmu_idx, addr); + index = tlb_index(env_cpu(env), mmu_idx, addr); + tlbe = tlb_entry(env_cpu(env), mmu_idx, addr); } tlb_addr = tlb_addr_write(tlbe) & ~TLB_INVALID_MASK; } diff --git a/include/exec/cpu_ldst.h b/include/exec/cpu_ldst.h index da10ba1433..6061e33ac9 100644 --- a/include/exec/cpu_ldst.h +++ b/include/exec/cpu_ldst.h @@ -361,19 +361,19 @@ static inline uint64_t tlb_addr_write(const CPUTLBEntry *entry) } /* Find the TLB index corresponding to the mmu_idx + address pair. */ -static inline uintptr_t tlb_index(CPUArchState *env, uintptr_t mmu_idx, +static inline uintptr_t tlb_index(CPUState *cpu, uintptr_t mmu_idx, vaddr addr) { - uintptr_t size_mask = env_tlb(env)->f[mmu_idx].mask >> CPU_TLB_ENTRY_BITS; + uintptr_t size_mask = cpu->neg.tlb.f[mmu_idx].mask >> CPU_TLB_ENTRY_BITS; return (addr >> TARGET_PAGE_BITS) & size_mask; } /* Find the TLB entry corresponding to the mmu_idx + address pair. */ -static inline CPUTLBEntry *tlb_entry(CPUArchState *env, uintptr_t mmu_idx, +static inline CPUTLBEntry *tlb_entry(CPUState *cpu, uintptr_t mmu_idx, vaddr addr) { - return &env_tlb(env)->f[mmu_idx].table[tlb_index(env, mmu_idx, addr)]; + return &cpu->neg.tlb.f[mmu_idx].table[tlb_index(cpu, mmu_idx, addr)]; } #endif /* defined(CONFIG_USER_ONLY) */ From 5afec1c63bcc6e23bec6fa8a1895f61d1f7f3cbe Mon Sep 17 00:00:00 2001 From: Anton Johansson Date: Tue, 12 Sep 2023 17:34:21 +0200 Subject: [PATCH 0253/1077] accel/tcg: Modify probe_access_internal() to use CPUState MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit probe_access_internal() is changed to instead take the generic CPUState over CPUArchState, in order to lessen the target-specific coupling of cputlb.c. Note: probe_access*() also don't need the full CPUArchState, but aren't touched in this patch as they are target-facing. Signed-off-by: Anton Johansson Message-Id: <20230912153428.17816-5-anjo@rev.ng> Reviewed-by: Richard Henderson Reviewed-by: Philippe Mathieu-Daudé [rth: Use cpu->neg.tlb instead of cpu_tlb()] Signed-off-by: Richard Henderson --- accel/tcg/cputlb.c | 46 +++++++++++++++++++++++----------------------- 1 file changed, 23 insertions(+), 23 deletions(-) diff --git a/accel/tcg/cputlb.c b/accel/tcg/cputlb.c index f88c394594..ab52afb3f3 100644 --- a/accel/tcg/cputlb.c +++ b/accel/tcg/cputlb.c @@ -1432,27 +1432,24 @@ static void notdirty_write(CPUState *cpu, vaddr mem_vaddr, unsigned size, } } -static int probe_access_internal(CPUArchState *env, vaddr addr, +static int probe_access_internal(CPUState *cpu, vaddr addr, int fault_size, MMUAccessType access_type, int mmu_idx, bool nonfault, void **phost, CPUTLBEntryFull **pfull, uintptr_t retaddr, bool check_mem_cbs) { - uintptr_t index = tlb_index(env_cpu(env), mmu_idx, addr); - CPUTLBEntry *entry = tlb_entry(env_cpu(env), mmu_idx, addr); + uintptr_t index = tlb_index(cpu, mmu_idx, addr); + CPUTLBEntry *entry = tlb_entry(cpu, mmu_idx, addr); uint64_t tlb_addr = tlb_read_idx(entry, access_type); vaddr page_addr = addr & TARGET_PAGE_MASK; int flags = TLB_FLAGS_MASK & ~TLB_FORCE_SLOW; - bool force_mmio = check_mem_cbs && cpu_plugin_mem_cbs_enabled(env_cpu(env)); + bool force_mmio = check_mem_cbs && cpu_plugin_mem_cbs_enabled(cpu); CPUTLBEntryFull *full; if (!tlb_hit_page(tlb_addr, page_addr)) { - if (!victim_tlb_hit(env_cpu(env), mmu_idx, index, - access_type, page_addr)) { - CPUState *cs = env_cpu(env); - - if (!cs->cc->tcg_ops->tlb_fill(cs, addr, fault_size, access_type, - mmu_idx, nonfault, retaddr)) { + if (!victim_tlb_hit(cpu, mmu_idx, index, access_type, page_addr)) { + if (!cpu->cc->tcg_ops->tlb_fill(cpu, addr, fault_size, access_type, + mmu_idx, nonfault, retaddr)) { /* Non-faulting page table read failed. */ *phost = NULL; *pfull = NULL; @@ -1460,8 +1457,8 @@ static int probe_access_internal(CPUArchState *env, vaddr addr, } /* TLB resize via tlb_fill may have moved the entry. */ - index = tlb_index(env_cpu(env), mmu_idx, addr); - entry = tlb_entry(env_cpu(env), mmu_idx, addr); + index = tlb_index(cpu, mmu_idx, addr); + entry = tlb_entry(cpu, mmu_idx, addr); /* * With PAGE_WRITE_INV, we set TLB_INVALID_MASK immediately, @@ -1474,7 +1471,7 @@ static int probe_access_internal(CPUArchState *env, vaddr addr, } flags &= tlb_addr; - *pfull = full = &env_tlb(env)->d[mmu_idx].fulltlb[index]; + *pfull = full = &cpu->neg.tlb.d[mmu_idx].fulltlb[index]; flags |= full->slow_flags[access_type]; /* Fold all "mmio-like" bits into TLB_MMIO. This is not RAM. */ @@ -1495,8 +1492,9 @@ int probe_access_full(CPUArchState *env, vaddr addr, int size, bool nonfault, void **phost, CPUTLBEntryFull **pfull, uintptr_t retaddr) { - int flags = probe_access_internal(env, addr, size, access_type, mmu_idx, - nonfault, phost, pfull, retaddr, true); + int flags = probe_access_internal(env_cpu(env), addr, size, access_type, + mmu_idx, nonfault, phost, pfull, retaddr, + true); /* Handle clean RAM pages. */ if (unlikely(flags & TLB_NOTDIRTY)) { @@ -1518,8 +1516,8 @@ int probe_access_full_mmu(CPUArchState *env, vaddr addr, int size, phost = phost ? phost : &discard_phost; pfull = pfull ? pfull : &discard_tlb; - int flags = probe_access_internal(env, addr, size, access_type, mmu_idx, - true, phost, pfull, 0, false); + int flags = probe_access_internal(env_cpu(env), addr, size, access_type, + mmu_idx, true, phost, pfull, 0, false); /* Handle clean RAM pages. */ if (unlikely(flags & TLB_NOTDIRTY)) { @@ -1539,8 +1537,9 @@ int probe_access_flags(CPUArchState *env, vaddr addr, int size, g_assert(-(addr | TARGET_PAGE_MASK) >= size); - flags = probe_access_internal(env, addr, size, access_type, mmu_idx, - nonfault, phost, &full, retaddr, true); + flags = probe_access_internal(env_cpu(env), addr, size, access_type, + mmu_idx, nonfault, phost, &full, retaddr, + true); /* Handle clean RAM pages. */ if (unlikely(flags & TLB_NOTDIRTY)) { @@ -1560,8 +1559,9 @@ void *probe_access(CPUArchState *env, vaddr addr, int size, g_assert(-(addr | TARGET_PAGE_MASK) >= size); - flags = probe_access_internal(env, addr, size, access_type, mmu_idx, - false, &host, &full, retaddr, true); + flags = probe_access_internal(env_cpu(env), addr, size, access_type, + mmu_idx, false, &host, &full, retaddr, + true); /* Per the interface, size == 0 merely faults the access. */ if (size == 0) { @@ -1593,7 +1593,7 @@ void *tlb_vaddr_to_host(CPUArchState *env, abi_ptr addr, void *host; int flags; - flags = probe_access_internal(env, addr, 0, access_type, + flags = probe_access_internal(env_cpu(env), addr, 0, access_type, mmu_idx, true, &host, &full, 0, false); /* No combination of flags are expected by the caller. */ @@ -1616,7 +1616,7 @@ tb_page_addr_t get_page_addr_code_hostp(CPUArchState *env, vaddr addr, CPUTLBEntryFull *full; void *p; - (void)probe_access_internal(env, addr, 1, MMU_INST_FETCH, + (void)probe_access_internal(env_cpu(env), addr, 1, MMU_INST_FETCH, cpu_mmu_index(env, true), false, &p, &full, 0, false); if (p == NULL) { From d50ef4467c4c0a35b6b57c532da5814a8327275c Mon Sep 17 00:00:00 2001 From: Anton Johansson Date: Tue, 12 Sep 2023 17:34:22 +0200 Subject: [PATCH 0254/1077] accel/tcg: Modify memory access functions to use CPUState MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit do_[ld|st]*() and mmu_lookup*() are changed to use CPUState over CPUArchState, moving the target-dependence to the target-facing facing cpu_[ld|st] functions. Signed-off-by: Anton Johansson Message-Id: <20230912153428.17816-6-anjo@rev.ng> Reviewed-by: Richard Henderson Reviewed-by: Philippe Mathieu-Daudé [rth: Use cpu->neg.tlb instead of cpu_tlb; cpu_env instead of env_ptr.] Signed-off-by: Richard Henderson --- accel/tcg/cputlb.c | 348 ++++++++++++++++++++++----------------------- 1 file changed, 171 insertions(+), 177 deletions(-) diff --git a/accel/tcg/cputlb.c b/accel/tcg/cputlb.c index ab52afb3f3..0e4bc82294 100644 --- a/accel/tcg/cputlb.c +++ b/accel/tcg/cputlb.c @@ -1339,10 +1339,9 @@ static inline void cpu_unaligned_access(CPUState *cpu, vaddr addr, } static MemoryRegionSection * -io_prepare(hwaddr *out_offset, CPUArchState *env, hwaddr xlat, +io_prepare(hwaddr *out_offset, CPUState *cpu, hwaddr xlat, MemTxAttrs attrs, vaddr addr, uintptr_t retaddr) { - CPUState *cpu = env_cpu(env); MemoryRegionSection *section; hwaddr mr_offset; @@ -1357,22 +1356,17 @@ io_prepare(hwaddr *out_offset, CPUArchState *env, hwaddr xlat, return section; } -static void io_failed(CPUArchState *env, CPUTLBEntryFull *full, vaddr addr, +static void io_failed(CPUState *cpu, CPUTLBEntryFull *full, vaddr addr, unsigned size, MMUAccessType access_type, int mmu_idx, MemTxResult response, uintptr_t retaddr) { - CPUState *cpu = env_cpu(env); + if (!cpu->ignore_memory_transaction_failures + && cpu->cc->tcg_ops->do_transaction_failed) { + hwaddr physaddr = full->phys_addr | (addr & ~TARGET_PAGE_MASK); - if (!cpu->ignore_memory_transaction_failures) { - CPUClass *cc = CPU_GET_CLASS(cpu); - - if (cc->tcg_ops->do_transaction_failed) { - hwaddr physaddr = full->phys_addr | (addr & ~TARGET_PAGE_MASK); - - cc->tcg_ops->do_transaction_failed(cpu, physaddr, addr, size, - access_type, mmu_idx, - full->attrs, response, retaddr); - } + cpu->cc->tcg_ops->do_transaction_failed(cpu, physaddr, addr, size, + access_type, mmu_idx, + full->attrs, response, retaddr); } } @@ -1700,7 +1694,7 @@ typedef struct MMULookupLocals { /** * mmu_lookup1: translate one page - * @env: cpu context + * @cpu: generic cpu state * @data: lookup parameters * @mmu_idx: virtual address context * @access_type: load/store/code @@ -1711,12 +1705,12 @@ typedef struct MMULookupLocals { * tlb_fill will longjmp out. Return true if the softmmu tlb for * @mmu_idx may have resized. */ -static bool mmu_lookup1(CPUArchState *env, MMULookupPageData *data, +static bool mmu_lookup1(CPUState *cpu, MMULookupPageData *data, int mmu_idx, MMUAccessType access_type, uintptr_t ra) { vaddr addr = data->addr; - uintptr_t index = tlb_index(env_cpu(env), mmu_idx, addr); - CPUTLBEntry *entry = tlb_entry(env_cpu(env), mmu_idx, addr); + uintptr_t index = tlb_index(cpu, mmu_idx, addr); + CPUTLBEntry *entry = tlb_entry(cpu, mmu_idx, addr); uint64_t tlb_addr = tlb_read_idx(entry, access_type); bool maybe_resized = false; CPUTLBEntryFull *full; @@ -1724,17 +1718,17 @@ static bool mmu_lookup1(CPUArchState *env, MMULookupPageData *data, /* If the TLB entry is for a different page, reload and try again. */ if (!tlb_hit(tlb_addr, addr)) { - if (!victim_tlb_hit(env_cpu(env), mmu_idx, index, access_type, + if (!victim_tlb_hit(cpu, mmu_idx, index, access_type, addr & TARGET_PAGE_MASK)) { - tlb_fill(env_cpu(env), addr, data->size, access_type, mmu_idx, ra); + tlb_fill(cpu, addr, data->size, access_type, mmu_idx, ra); maybe_resized = true; - index = tlb_index(env_cpu(env), mmu_idx, addr); - entry = tlb_entry(env_cpu(env), mmu_idx, addr); + index = tlb_index(cpu, mmu_idx, addr); + entry = tlb_entry(cpu, mmu_idx, addr); } tlb_addr = tlb_read_idx(entry, access_type) & ~TLB_INVALID_MASK; } - full = &env_tlb(env)->d[mmu_idx].fulltlb[index]; + full = &cpu->neg.tlb.d[mmu_idx].fulltlb[index]; flags = tlb_addr & (TLB_FLAGS_MASK & ~TLB_FORCE_SLOW); flags |= full->slow_flags[access_type]; @@ -1748,7 +1742,7 @@ static bool mmu_lookup1(CPUArchState *env, MMULookupPageData *data, /** * mmu_watch_or_dirty - * @env: cpu context + * @cpu: generic cpu state * @data: lookup parameters * @access_type: load/store/code * @ra: return address into tcg generated code, or 0 @@ -1756,7 +1750,7 @@ static bool mmu_lookup1(CPUArchState *env, MMULookupPageData *data, * Trigger watchpoints for @data.addr:@data.size; * record writes to protected clean pages. */ -static void mmu_watch_or_dirty(CPUArchState *env, MMULookupPageData *data, +static void mmu_watch_or_dirty(CPUState *cpu, MMULookupPageData *data, MMUAccessType access_type, uintptr_t ra) { CPUTLBEntryFull *full = data->full; @@ -1767,13 +1761,13 @@ static void mmu_watch_or_dirty(CPUArchState *env, MMULookupPageData *data, /* On watchpoint hit, this will longjmp out. */ if (flags & TLB_WATCHPOINT) { int wp = access_type == MMU_DATA_STORE ? BP_MEM_WRITE : BP_MEM_READ; - cpu_check_watchpoint(env_cpu(env), addr, size, full->attrs, wp, ra); + cpu_check_watchpoint(cpu, addr, size, full->attrs, wp, ra); flags &= ~TLB_WATCHPOINT; } /* Note that notdirty is only set for writes. */ if (flags & TLB_NOTDIRTY) { - notdirty_write(env_cpu(env), addr, size, full, ra); + notdirty_write(cpu, addr, size, full, ra); flags &= ~TLB_NOTDIRTY; } data->flags = flags; @@ -1781,7 +1775,7 @@ static void mmu_watch_or_dirty(CPUArchState *env, MMULookupPageData *data, /** * mmu_lookup: translate page(s) - * @env: cpu context + * @cpu: generic cpu state * @addr: virtual address * @oi: combined mmu_idx and MemOp * @ra: return address into tcg generated code, or 0 @@ -1791,7 +1785,7 @@ static void mmu_watch_or_dirty(CPUArchState *env, MMULookupPageData *data, * Resolve the translation for the page(s) beginning at @addr, for MemOp.size * bytes. Return true if the lookup crosses a page boundary. */ -static bool mmu_lookup(CPUArchState *env, vaddr addr, MemOpIdx oi, +static bool mmu_lookup(CPUState *cpu, vaddr addr, MemOpIdx oi, uintptr_t ra, MMUAccessType type, MMULookupLocals *l) { unsigned a_bits; @@ -1806,7 +1800,7 @@ static bool mmu_lookup(CPUArchState *env, vaddr addr, MemOpIdx oi, /* Handle CPU specific unaligned behaviour */ a_bits = get_alignment_bits(l->memop); if (addr & ((1 << a_bits) - 1)) { - cpu_unaligned_access(env_cpu(env), addr, type, l->mmu_idx, ra); + cpu_unaligned_access(cpu, addr, type, l->mmu_idx, ra); } l->page[0].addr = addr; @@ -1816,11 +1810,11 @@ static bool mmu_lookup(CPUArchState *env, vaddr addr, MemOpIdx oi, crosspage = (addr ^ l->page[1].addr) & TARGET_PAGE_MASK; if (likely(!crosspage)) { - mmu_lookup1(env, &l->page[0], l->mmu_idx, type, ra); + mmu_lookup1(cpu, &l->page[0], l->mmu_idx, type, ra); flags = l->page[0].flags; if (unlikely(flags & (TLB_WATCHPOINT | TLB_NOTDIRTY))) { - mmu_watch_or_dirty(env, &l->page[0], type, ra); + mmu_watch_or_dirty(cpu, &l->page[0], type, ra); } if (unlikely(flags & TLB_BSWAP)) { l->memop ^= MO_BSWAP; @@ -1835,16 +1829,16 @@ static bool mmu_lookup(CPUArchState *env, vaddr addr, MemOpIdx oi, * Lookup both pages, recognizing exceptions from either. If the * second lookup potentially resized, refresh first CPUTLBEntryFull. */ - mmu_lookup1(env, &l->page[0], l->mmu_idx, type, ra); - if (mmu_lookup1(env, &l->page[1], l->mmu_idx, type, ra)) { - uintptr_t index = tlb_index(env_cpu(env), l->mmu_idx, addr); - l->page[0].full = &env_tlb(env)->d[l->mmu_idx].fulltlb[index]; + mmu_lookup1(cpu, &l->page[0], l->mmu_idx, type, ra); + if (mmu_lookup1(cpu, &l->page[1], l->mmu_idx, type, ra)) { + uintptr_t index = tlb_index(cpu, l->mmu_idx, addr); + l->page[0].full = &cpu->neg.tlb.d[l->mmu_idx].fulltlb[index]; } flags = l->page[0].flags | l->page[1].flags; if (unlikely(flags & (TLB_WATCHPOINT | TLB_NOTDIRTY))) { - mmu_watch_or_dirty(env, &l->page[0], type, ra); - mmu_watch_or_dirty(env, &l->page[1], type, ra); + mmu_watch_or_dirty(cpu, &l->page[0], type, ra); + mmu_watch_or_dirty(cpu, &l->page[1], type, ra); } /* @@ -1984,7 +1978,7 @@ static void *atomic_mmu_lookup(CPUArchState *env, vaddr addr, MemOpIdx oi, /** * do_ld_mmio_beN: - * @env: cpu context + * @cpu: generic cpu state * @full: page parameters * @ret_be: accumulated data * @addr: virtual address @@ -1996,7 +1990,7 @@ static void *atomic_mmu_lookup(CPUArchState *env, vaddr addr, MemOpIdx oi, * Load @size bytes from @addr, which is memory-mapped i/o. * The bytes are concatenated in big-endian order with @ret_be. */ -static uint64_t int_ld_mmio_beN(CPUArchState *env, CPUTLBEntryFull *full, +static uint64_t int_ld_mmio_beN(CPUState *cpu, CPUTLBEntryFull *full, uint64_t ret_be, vaddr addr, int size, int mmu_idx, MMUAccessType type, uintptr_t ra, MemoryRegion *mr, hwaddr mr_offset) @@ -2015,7 +2009,7 @@ static uint64_t int_ld_mmio_beN(CPUArchState *env, CPUTLBEntryFull *full, r = memory_region_dispatch_read(mr, mr_offset, &val, this_mop, full->attrs); if (unlikely(r != MEMTX_OK)) { - io_failed(env, full, addr, this_size, type, mmu_idx, r, ra); + io_failed(cpu, full, addr, this_size, type, mmu_idx, r, ra); } if (this_size == 8) { return val; @@ -2030,7 +2024,7 @@ static uint64_t int_ld_mmio_beN(CPUArchState *env, CPUTLBEntryFull *full, return ret_be; } -static uint64_t do_ld_mmio_beN(CPUArchState *env, CPUTLBEntryFull *full, +static uint64_t do_ld_mmio_beN(CPUState *cpu, CPUTLBEntryFull *full, uint64_t ret_be, vaddr addr, int size, int mmu_idx, MMUAccessType type, uintptr_t ra) { @@ -2043,18 +2037,18 @@ static uint64_t do_ld_mmio_beN(CPUArchState *env, CPUTLBEntryFull *full, tcg_debug_assert(size > 0 && size <= 8); attrs = full->attrs; - section = io_prepare(&mr_offset, env, full->xlat_section, attrs, addr, ra); + section = io_prepare(&mr_offset, cpu, full->xlat_section, attrs, addr, ra); mr = section->mr; qemu_mutex_lock_iothread(); - ret = int_ld_mmio_beN(env, full, ret_be, addr, size, mmu_idx, + ret = int_ld_mmio_beN(cpu, full, ret_be, addr, size, mmu_idx, type, ra, mr, mr_offset); qemu_mutex_unlock_iothread(); return ret; } -static Int128 do_ld16_mmio_beN(CPUArchState *env, CPUTLBEntryFull *full, +static Int128 do_ld16_mmio_beN(CPUState *cpu, CPUTLBEntryFull *full, uint64_t ret_be, vaddr addr, int size, int mmu_idx, uintptr_t ra) { @@ -2067,13 +2061,13 @@ static Int128 do_ld16_mmio_beN(CPUArchState *env, CPUTLBEntryFull *full, tcg_debug_assert(size > 8 && size <= 16); attrs = full->attrs; - section = io_prepare(&mr_offset, env, full->xlat_section, attrs, addr, ra); + section = io_prepare(&mr_offset, cpu, full->xlat_section, attrs, addr, ra); mr = section->mr; qemu_mutex_lock_iothread(); - a = int_ld_mmio_beN(env, full, ret_be, addr, size - 8, mmu_idx, + a = int_ld_mmio_beN(cpu, full, ret_be, addr, size - 8, mmu_idx, MMU_DATA_LOAD, ra, mr, mr_offset); - b = int_ld_mmio_beN(env, full, ret_be, addr + size - 8, 8, mmu_idx, + b = int_ld_mmio_beN(cpu, full, ret_be, addr + size - 8, 8, mmu_idx, MMU_DATA_LOAD, ra, mr, mr_offset + size - 8); qemu_mutex_unlock_iothread(); @@ -2174,11 +2168,11 @@ static uint64_t do_ld_whole_be4(MMULookupPageData *p, uint64_t ret_be) * As do_ld_bytes_beN, but with one atomic load. * Eight aligned bytes are guaranteed to cover the load. */ -static uint64_t do_ld_whole_be8(CPUArchState *env, uintptr_t ra, +static uint64_t do_ld_whole_be8(CPUState *cpu, uintptr_t ra, MMULookupPageData *p, uint64_t ret_be) { int o = p->addr & 7; - uint64_t x = load_atomic8_or_exit(env, ra, p->haddr - o); + uint64_t x = load_atomic8_or_exit(cpu_env(cpu), ra, p->haddr - o); x = cpu_to_be64(x); x <<= o * 8; @@ -2194,11 +2188,11 @@ static uint64_t do_ld_whole_be8(CPUArchState *env, uintptr_t ra, * As do_ld_bytes_beN, but with one atomic load. * 16 aligned bytes are guaranteed to cover the load. */ -static Int128 do_ld_whole_be16(CPUArchState *env, uintptr_t ra, +static Int128 do_ld_whole_be16(CPUState *cpu, uintptr_t ra, MMULookupPageData *p, uint64_t ret_be) { int o = p->addr & 15; - Int128 x, y = load_atomic16_or_exit(env, ra, p->haddr - o); + Int128 x, y = load_atomic16_or_exit(cpu_env(cpu), ra, p->haddr - o); int size = p->size; if (!HOST_BIG_ENDIAN) { @@ -2214,7 +2208,7 @@ static Int128 do_ld_whole_be16(CPUArchState *env, uintptr_t ra, /* * Wrapper for the above. */ -static uint64_t do_ld_beN(CPUArchState *env, MMULookupPageData *p, +static uint64_t do_ld_beN(CPUState *cpu, MMULookupPageData *p, uint64_t ret_be, int mmu_idx, MMUAccessType type, MemOp mop, uintptr_t ra) { @@ -2222,7 +2216,7 @@ static uint64_t do_ld_beN(CPUArchState *env, MMULookupPageData *p, unsigned tmp, half_size; if (unlikely(p->flags & TLB_MMIO)) { - return do_ld_mmio_beN(env, p->full, ret_be, p->addr, p->size, + return do_ld_mmio_beN(cpu, p->full, ret_be, p->addr, p->size, mmu_idx, type, ra); } @@ -2246,7 +2240,7 @@ static uint64_t do_ld_beN(CPUArchState *env, MMULookupPageData *p, if (!HAVE_al8_fast && p->size < 4) { return do_ld_whole_be4(p, ret_be); } else { - return do_ld_whole_be8(env, ra, p, ret_be); + return do_ld_whole_be8(cpu, ra, p, ret_be); } } /* fall through */ @@ -2264,7 +2258,7 @@ static uint64_t do_ld_beN(CPUArchState *env, MMULookupPageData *p, /* * Wrapper for the above, for 8 < size < 16. */ -static Int128 do_ld16_beN(CPUArchState *env, MMULookupPageData *p, +static Int128 do_ld16_beN(CPUState *cpu, MMULookupPageData *p, uint64_t a, int mmu_idx, MemOp mop, uintptr_t ra) { int size = p->size; @@ -2272,7 +2266,7 @@ static Int128 do_ld16_beN(CPUArchState *env, MMULookupPageData *p, MemOp atom; if (unlikely(p->flags & TLB_MMIO)) { - return do_ld16_mmio_beN(env, p->full, a, p->addr, size, mmu_idx, ra); + return do_ld16_mmio_beN(cpu, p->full, a, p->addr, size, mmu_idx, ra); } /* @@ -2291,7 +2285,7 @@ static Int128 do_ld16_beN(CPUArchState *env, MMULookupPageData *p, case MO_ATOM_WITHIN16_PAIR: /* Since size > 8, this is the half that must be atomic. */ - return do_ld_whole_be16(env, ra, p, a); + return do_ld_whole_be16(cpu, ra, p, a); case MO_ATOM_IFALIGN_PAIR: /* @@ -2313,29 +2307,29 @@ static Int128 do_ld16_beN(CPUArchState *env, MMULookupPageData *p, return int128_make128(b, a); } -static uint8_t do_ld_1(CPUArchState *env, MMULookupPageData *p, int mmu_idx, +static uint8_t do_ld_1(CPUState *cpu, MMULookupPageData *p, int mmu_idx, MMUAccessType type, uintptr_t ra) { if (unlikely(p->flags & TLB_MMIO)) { - return do_ld_mmio_beN(env, p->full, 0, p->addr, 1, mmu_idx, type, ra); + return do_ld_mmio_beN(cpu, p->full, 0, p->addr, 1, mmu_idx, type, ra); } else { return *(uint8_t *)p->haddr; } } -static uint16_t do_ld_2(CPUArchState *env, MMULookupPageData *p, int mmu_idx, +static uint16_t do_ld_2(CPUState *cpu, MMULookupPageData *p, int mmu_idx, MMUAccessType type, MemOp memop, uintptr_t ra) { uint16_t ret; if (unlikely(p->flags & TLB_MMIO)) { - ret = do_ld_mmio_beN(env, p->full, 0, p->addr, 2, mmu_idx, type, ra); + ret = do_ld_mmio_beN(cpu, p->full, 0, p->addr, 2, mmu_idx, type, ra); if ((memop & MO_BSWAP) == MO_LE) { ret = bswap16(ret); } } else { /* Perform the load host endian, then swap if necessary. */ - ret = load_atom_2(env, ra, p->haddr, memop); + ret = load_atom_2(cpu_env(cpu), ra, p->haddr, memop); if (memop & MO_BSWAP) { ret = bswap16(ret); } @@ -2343,19 +2337,19 @@ static uint16_t do_ld_2(CPUArchState *env, MMULookupPageData *p, int mmu_idx, return ret; } -static uint32_t do_ld_4(CPUArchState *env, MMULookupPageData *p, int mmu_idx, +static uint32_t do_ld_4(CPUState *cpu, MMULookupPageData *p, int mmu_idx, MMUAccessType type, MemOp memop, uintptr_t ra) { uint32_t ret; if (unlikely(p->flags & TLB_MMIO)) { - ret = do_ld_mmio_beN(env, p->full, 0, p->addr, 4, mmu_idx, type, ra); + ret = do_ld_mmio_beN(cpu, p->full, 0, p->addr, 4, mmu_idx, type, ra); if ((memop & MO_BSWAP) == MO_LE) { ret = bswap32(ret); } } else { /* Perform the load host endian. */ - ret = load_atom_4(env, ra, p->haddr, memop); + ret = load_atom_4(cpu_env(cpu), ra, p->haddr, memop); if (memop & MO_BSWAP) { ret = bswap32(ret); } @@ -2363,19 +2357,19 @@ static uint32_t do_ld_4(CPUArchState *env, MMULookupPageData *p, int mmu_idx, return ret; } -static uint64_t do_ld_8(CPUArchState *env, MMULookupPageData *p, int mmu_idx, +static uint64_t do_ld_8(CPUState *cpu, MMULookupPageData *p, int mmu_idx, MMUAccessType type, MemOp memop, uintptr_t ra) { uint64_t ret; if (unlikely(p->flags & TLB_MMIO)) { - ret = do_ld_mmio_beN(env, p->full, 0, p->addr, 8, mmu_idx, type, ra); + ret = do_ld_mmio_beN(cpu, p->full, 0, p->addr, 8, mmu_idx, type, ra); if ((memop & MO_BSWAP) == MO_LE) { ret = bswap64(ret); } } else { /* Perform the load host endian. */ - ret = load_atom_8(env, ra, p->haddr, memop); + ret = load_atom_8(cpu_env(cpu), ra, p->haddr, memop); if (memop & MO_BSWAP) { ret = bswap64(ret); } @@ -2383,27 +2377,27 @@ static uint64_t do_ld_8(CPUArchState *env, MMULookupPageData *p, int mmu_idx, return ret; } -static uint8_t do_ld1_mmu(CPUArchState *env, vaddr addr, MemOpIdx oi, +static uint8_t do_ld1_mmu(CPUState *cpu, vaddr addr, MemOpIdx oi, uintptr_t ra, MMUAccessType access_type) { MMULookupLocals l; bool crosspage; cpu_req_mo(TCG_MO_LD_LD | TCG_MO_ST_LD); - crosspage = mmu_lookup(env, addr, oi, ra, access_type, &l); + crosspage = mmu_lookup(cpu, addr, oi, ra, access_type, &l); tcg_debug_assert(!crosspage); - return do_ld_1(env, &l.page[0], l.mmu_idx, access_type, ra); + return do_ld_1(cpu, &l.page[0], l.mmu_idx, access_type, ra); } tcg_target_ulong helper_ldub_mmu(CPUArchState *env, uint64_t addr, MemOpIdx oi, uintptr_t retaddr) { tcg_debug_assert((get_memop(oi) & MO_SIZE) == MO_8); - return do_ld1_mmu(env, addr, oi, retaddr, MMU_DATA_LOAD); + return do_ld1_mmu(env_cpu(env), addr, oi, retaddr, MMU_DATA_LOAD); } -static uint16_t do_ld2_mmu(CPUArchState *env, vaddr addr, MemOpIdx oi, +static uint16_t do_ld2_mmu(CPUState *cpu, vaddr addr, MemOpIdx oi, uintptr_t ra, MMUAccessType access_type) { MMULookupLocals l; @@ -2412,13 +2406,13 @@ static uint16_t do_ld2_mmu(CPUArchState *env, vaddr addr, MemOpIdx oi, uint8_t a, b; cpu_req_mo(TCG_MO_LD_LD | TCG_MO_ST_LD); - crosspage = mmu_lookup(env, addr, oi, ra, access_type, &l); + crosspage = mmu_lookup(cpu, addr, oi, ra, access_type, &l); if (likely(!crosspage)) { - return do_ld_2(env, &l.page[0], l.mmu_idx, access_type, l.memop, ra); + return do_ld_2(cpu, &l.page[0], l.mmu_idx, access_type, l.memop, ra); } - a = do_ld_1(env, &l.page[0], l.mmu_idx, access_type, ra); - b = do_ld_1(env, &l.page[1], l.mmu_idx, access_type, ra); + a = do_ld_1(cpu, &l.page[0], l.mmu_idx, access_type, ra); + b = do_ld_1(cpu, &l.page[1], l.mmu_idx, access_type, ra); if ((l.memop & MO_BSWAP) == MO_LE) { ret = a | (b << 8); @@ -2432,10 +2426,10 @@ tcg_target_ulong helper_lduw_mmu(CPUArchState *env, uint64_t addr, MemOpIdx oi, uintptr_t retaddr) { tcg_debug_assert((get_memop(oi) & MO_SIZE) == MO_16); - return do_ld2_mmu(env, addr, oi, retaddr, MMU_DATA_LOAD); + return do_ld2_mmu(env_cpu(env), addr, oi, retaddr, MMU_DATA_LOAD); } -static uint32_t do_ld4_mmu(CPUArchState *env, vaddr addr, MemOpIdx oi, +static uint32_t do_ld4_mmu(CPUState *cpu, vaddr addr, MemOpIdx oi, uintptr_t ra, MMUAccessType access_type) { MMULookupLocals l; @@ -2443,13 +2437,13 @@ static uint32_t do_ld4_mmu(CPUArchState *env, vaddr addr, MemOpIdx oi, uint32_t ret; cpu_req_mo(TCG_MO_LD_LD | TCG_MO_ST_LD); - crosspage = mmu_lookup(env, addr, oi, ra, access_type, &l); + crosspage = mmu_lookup(cpu, addr, oi, ra, access_type, &l); if (likely(!crosspage)) { - return do_ld_4(env, &l.page[0], l.mmu_idx, access_type, l.memop, ra); + return do_ld_4(cpu, &l.page[0], l.mmu_idx, access_type, l.memop, ra); } - ret = do_ld_beN(env, &l.page[0], 0, l.mmu_idx, access_type, l.memop, ra); - ret = do_ld_beN(env, &l.page[1], ret, l.mmu_idx, access_type, l.memop, ra); + ret = do_ld_beN(cpu, &l.page[0], 0, l.mmu_idx, access_type, l.memop, ra); + ret = do_ld_beN(cpu, &l.page[1], ret, l.mmu_idx, access_type, l.memop, ra); if ((l.memop & MO_BSWAP) == MO_LE) { ret = bswap32(ret); } @@ -2460,10 +2454,10 @@ tcg_target_ulong helper_ldul_mmu(CPUArchState *env, uint64_t addr, MemOpIdx oi, uintptr_t retaddr) { tcg_debug_assert((get_memop(oi) & MO_SIZE) == MO_32); - return do_ld4_mmu(env, addr, oi, retaddr, MMU_DATA_LOAD); + return do_ld4_mmu(env_cpu(env), addr, oi, retaddr, MMU_DATA_LOAD); } -static uint64_t do_ld8_mmu(CPUArchState *env, vaddr addr, MemOpIdx oi, +static uint64_t do_ld8_mmu(CPUState *cpu, vaddr addr, MemOpIdx oi, uintptr_t ra, MMUAccessType access_type) { MMULookupLocals l; @@ -2471,13 +2465,13 @@ static uint64_t do_ld8_mmu(CPUArchState *env, vaddr addr, MemOpIdx oi, uint64_t ret; cpu_req_mo(TCG_MO_LD_LD | TCG_MO_ST_LD); - crosspage = mmu_lookup(env, addr, oi, ra, access_type, &l); + crosspage = mmu_lookup(cpu, addr, oi, ra, access_type, &l); if (likely(!crosspage)) { - return do_ld_8(env, &l.page[0], l.mmu_idx, access_type, l.memop, ra); + return do_ld_8(cpu, &l.page[0], l.mmu_idx, access_type, l.memop, ra); } - ret = do_ld_beN(env, &l.page[0], 0, l.mmu_idx, access_type, l.memop, ra); - ret = do_ld_beN(env, &l.page[1], ret, l.mmu_idx, access_type, l.memop, ra); + ret = do_ld_beN(cpu, &l.page[0], 0, l.mmu_idx, access_type, l.memop, ra); + ret = do_ld_beN(cpu, &l.page[1], ret, l.mmu_idx, access_type, l.memop, ra); if ((l.memop & MO_BSWAP) == MO_LE) { ret = bswap64(ret); } @@ -2488,7 +2482,7 @@ uint64_t helper_ldq_mmu(CPUArchState *env, uint64_t addr, MemOpIdx oi, uintptr_t retaddr) { tcg_debug_assert((get_memop(oi) & MO_SIZE) == MO_64); - return do_ld8_mmu(env, addr, oi, retaddr, MMU_DATA_LOAD); + return do_ld8_mmu(env_cpu(env), addr, oi, retaddr, MMU_DATA_LOAD); } /* @@ -2514,7 +2508,7 @@ tcg_target_ulong helper_ldsl_mmu(CPUArchState *env, uint64_t addr, return (int32_t)helper_ldul_mmu(env, addr, oi, retaddr); } -static Int128 do_ld16_mmu(CPUArchState *env, vaddr addr, +static Int128 do_ld16_mmu(CPUState *cpu, vaddr addr, MemOpIdx oi, uintptr_t ra) { MMULookupLocals l; @@ -2524,17 +2518,17 @@ static Int128 do_ld16_mmu(CPUArchState *env, vaddr addr, int first; cpu_req_mo(TCG_MO_LD_LD | TCG_MO_ST_LD); - crosspage = mmu_lookup(env, addr, oi, ra, MMU_DATA_LOAD, &l); + crosspage = mmu_lookup(cpu, addr, oi, ra, MMU_DATA_LOAD, &l); if (likely(!crosspage)) { if (unlikely(l.page[0].flags & TLB_MMIO)) { - ret = do_ld16_mmio_beN(env, l.page[0].full, 0, addr, 16, + ret = do_ld16_mmio_beN(cpu, l.page[0].full, 0, addr, 16, l.mmu_idx, ra); if ((l.memop & MO_BSWAP) == MO_LE) { ret = bswap128(ret); } } else { /* Perform the load host endian. */ - ret = load_atom_16(env, ra, l.page[0].haddr, l.memop); + ret = load_atom_16(cpu_env(cpu), ra, l.page[0].haddr, l.memop); if (l.memop & MO_BSWAP) { ret = bswap128(ret); } @@ -2546,8 +2540,8 @@ static Int128 do_ld16_mmu(CPUArchState *env, vaddr addr, if (first == 8) { MemOp mop8 = (l.memop & ~MO_SIZE) | MO_64; - a = do_ld_8(env, &l.page[0], l.mmu_idx, MMU_DATA_LOAD, mop8, ra); - b = do_ld_8(env, &l.page[1], l.mmu_idx, MMU_DATA_LOAD, mop8, ra); + a = do_ld_8(cpu, &l.page[0], l.mmu_idx, MMU_DATA_LOAD, mop8, ra); + b = do_ld_8(cpu, &l.page[1], l.mmu_idx, MMU_DATA_LOAD, mop8, ra); if ((mop8 & MO_BSWAP) == MO_LE) { ret = int128_make128(a, b); } else { @@ -2557,15 +2551,15 @@ static Int128 do_ld16_mmu(CPUArchState *env, vaddr addr, } if (first < 8) { - a = do_ld_beN(env, &l.page[0], 0, l.mmu_idx, + a = do_ld_beN(cpu, &l.page[0], 0, l.mmu_idx, MMU_DATA_LOAD, l.memop, ra); - ret = do_ld16_beN(env, &l.page[1], a, l.mmu_idx, l.memop, ra); + ret = do_ld16_beN(cpu, &l.page[1], a, l.mmu_idx, l.memop, ra); } else { - ret = do_ld16_beN(env, &l.page[0], 0, l.mmu_idx, l.memop, ra); + ret = do_ld16_beN(cpu, &l.page[0], 0, l.mmu_idx, l.memop, ra); b = int128_getlo(ret); ret = int128_lshift(ret, l.page[1].size * 8); a = int128_gethi(ret); - b = do_ld_beN(env, &l.page[1], b, l.mmu_idx, + b = do_ld_beN(cpu, &l.page[1], b, l.mmu_idx, MMU_DATA_LOAD, l.memop, ra); ret = int128_make128(b, a); } @@ -2579,7 +2573,7 @@ Int128 helper_ld16_mmu(CPUArchState *env, uint64_t addr, uint32_t oi, uintptr_t retaddr) { tcg_debug_assert((get_memop(oi) & MO_SIZE) == MO_128); - return do_ld16_mmu(env, addr, oi, retaddr); + return do_ld16_mmu(env_cpu(env), addr, oi, retaddr); } Int128 helper_ld_i128(CPUArchState *env, uint64_t addr, uint32_t oi) @@ -2601,7 +2595,7 @@ uint8_t cpu_ldb_mmu(CPUArchState *env, abi_ptr addr, MemOpIdx oi, uintptr_t ra) uint8_t ret; tcg_debug_assert((get_memop(oi) & MO_SIZE) == MO_UB); - ret = do_ld1_mmu(env, addr, oi, ra, MMU_DATA_LOAD); + ret = do_ld1_mmu(env_cpu(env), addr, oi, ra, MMU_DATA_LOAD); plugin_load_cb(env, addr, oi); return ret; } @@ -2612,7 +2606,7 @@ uint16_t cpu_ldw_mmu(CPUArchState *env, abi_ptr addr, uint16_t ret; tcg_debug_assert((get_memop(oi) & MO_SIZE) == MO_16); - ret = do_ld2_mmu(env, addr, oi, ra, MMU_DATA_LOAD); + ret = do_ld2_mmu(env_cpu(env), addr, oi, ra, MMU_DATA_LOAD); plugin_load_cb(env, addr, oi); return ret; } @@ -2623,7 +2617,7 @@ uint32_t cpu_ldl_mmu(CPUArchState *env, abi_ptr addr, uint32_t ret; tcg_debug_assert((get_memop(oi) & MO_SIZE) == MO_32); - ret = do_ld4_mmu(env, addr, oi, ra, MMU_DATA_LOAD); + ret = do_ld4_mmu(env_cpu(env), addr, oi, ra, MMU_DATA_LOAD); plugin_load_cb(env, addr, oi); return ret; } @@ -2634,7 +2628,7 @@ uint64_t cpu_ldq_mmu(CPUArchState *env, abi_ptr addr, uint64_t ret; tcg_debug_assert((get_memop(oi) & MO_SIZE) == MO_64); - ret = do_ld8_mmu(env, addr, oi, ra, MMU_DATA_LOAD); + ret = do_ld8_mmu(env_cpu(env), addr, oi, ra, MMU_DATA_LOAD); plugin_load_cb(env, addr, oi); return ret; } @@ -2645,7 +2639,7 @@ Int128 cpu_ld16_mmu(CPUArchState *env, abi_ptr addr, Int128 ret; tcg_debug_assert((get_memop(oi) & MO_SIZE) == MO_128); - ret = do_ld16_mmu(env, addr, oi, ra); + ret = do_ld16_mmu(env_cpu(env), addr, oi, ra); plugin_load_cb(env, addr, oi); return ret; } @@ -2656,7 +2650,7 @@ Int128 cpu_ld16_mmu(CPUArchState *env, abi_ptr addr, /** * do_st_mmio_leN: - * @env: cpu context + * @cpu: generic cpu state * @full: page parameters * @val_le: data to store * @addr: virtual address @@ -2669,7 +2663,7 @@ Int128 cpu_ld16_mmu(CPUArchState *env, abi_ptr addr, * The bytes to store are extracted in little-endian order from @val_le; * return the bytes of @val_le beyond @p->size that have not been stored. */ -static uint64_t int_st_mmio_leN(CPUArchState *env, CPUTLBEntryFull *full, +static uint64_t int_st_mmio_leN(CPUState *cpu, CPUTLBEntryFull *full, uint64_t val_le, vaddr addr, int size, int mmu_idx, uintptr_t ra, MemoryRegion *mr, hwaddr mr_offset) @@ -2687,7 +2681,7 @@ static uint64_t int_st_mmio_leN(CPUArchState *env, CPUTLBEntryFull *full, r = memory_region_dispatch_write(mr, mr_offset, val_le, this_mop, full->attrs); if (unlikely(r != MEMTX_OK)) { - io_failed(env, full, addr, this_size, MMU_DATA_STORE, + io_failed(cpu, full, addr, this_size, MMU_DATA_STORE, mmu_idx, r, ra); } if (this_size == 8) { @@ -2703,7 +2697,7 @@ static uint64_t int_st_mmio_leN(CPUArchState *env, CPUTLBEntryFull *full, return val_le; } -static uint64_t do_st_mmio_leN(CPUArchState *env, CPUTLBEntryFull *full, +static uint64_t do_st_mmio_leN(CPUState *cpu, CPUTLBEntryFull *full, uint64_t val_le, vaddr addr, int size, int mmu_idx, uintptr_t ra) { @@ -2716,18 +2710,18 @@ static uint64_t do_st_mmio_leN(CPUArchState *env, CPUTLBEntryFull *full, tcg_debug_assert(size > 0 && size <= 8); attrs = full->attrs; - section = io_prepare(&mr_offset, env, full->xlat_section, attrs, addr, ra); + section = io_prepare(&mr_offset, cpu, full->xlat_section, attrs, addr, ra); mr = section->mr; qemu_mutex_lock_iothread(); - ret = int_st_mmio_leN(env, full, val_le, addr, size, mmu_idx, + ret = int_st_mmio_leN(cpu, full, val_le, addr, size, mmu_idx, ra, mr, mr_offset); qemu_mutex_unlock_iothread(); return ret; } -static uint64_t do_st16_mmio_leN(CPUArchState *env, CPUTLBEntryFull *full, +static uint64_t do_st16_mmio_leN(CPUState *cpu, CPUTLBEntryFull *full, Int128 val_le, vaddr addr, int size, int mmu_idx, uintptr_t ra) { @@ -2740,13 +2734,13 @@ static uint64_t do_st16_mmio_leN(CPUArchState *env, CPUTLBEntryFull *full, tcg_debug_assert(size > 8 && size <= 16); attrs = full->attrs; - section = io_prepare(&mr_offset, env, full->xlat_section, attrs, addr, ra); + section = io_prepare(&mr_offset, cpu, full->xlat_section, attrs, addr, ra); mr = section->mr; qemu_mutex_lock_iothread(); - int_st_mmio_leN(env, full, int128_getlo(val_le), addr, 8, + int_st_mmio_leN(cpu, full, int128_getlo(val_le), addr, 8, mmu_idx, ra, mr, mr_offset); - ret = int_st_mmio_leN(env, full, int128_gethi(val_le), addr + 8, + ret = int_st_mmio_leN(cpu, full, int128_gethi(val_le), addr + 8, size - 8, mmu_idx, ra, mr, mr_offset + 8); qemu_mutex_unlock_iothread(); @@ -2756,7 +2750,7 @@ static uint64_t do_st16_mmio_leN(CPUArchState *env, CPUTLBEntryFull *full, /* * Wrapper for the above. */ -static uint64_t do_st_leN(CPUArchState *env, MMULookupPageData *p, +static uint64_t do_st_leN(CPUState *cpu, MMULookupPageData *p, uint64_t val_le, int mmu_idx, MemOp mop, uintptr_t ra) { @@ -2764,7 +2758,7 @@ static uint64_t do_st_leN(CPUArchState *env, MMULookupPageData *p, unsigned tmp, half_size; if (unlikely(p->flags & TLB_MMIO)) { - return do_st_mmio_leN(env, p->full, val_le, p->addr, + return do_st_mmio_leN(cpu, p->full, val_le, p->addr, p->size, mmu_idx, ra); } else if (unlikely(p->flags & TLB_DISCARD_WRITE)) { return val_le >> (p->size * 8); @@ -2792,7 +2786,7 @@ static uint64_t do_st_leN(CPUArchState *env, MMULookupPageData *p, } else if (HAVE_al8) { return store_whole_le8(p->haddr, p->size, val_le); } else { - cpu_loop_exit_atomic(env_cpu(env), ra); + cpu_loop_exit_atomic(cpu, ra); } } /* fall through */ @@ -2810,7 +2804,7 @@ static uint64_t do_st_leN(CPUArchState *env, MMULookupPageData *p, /* * Wrapper for the above, for 8 < size < 16. */ -static uint64_t do_st16_leN(CPUArchState *env, MMULookupPageData *p, +static uint64_t do_st16_leN(CPUState *cpu, MMULookupPageData *p, Int128 val_le, int mmu_idx, MemOp mop, uintptr_t ra) { @@ -2818,7 +2812,7 @@ static uint64_t do_st16_leN(CPUArchState *env, MMULookupPageData *p, MemOp atom; if (unlikely(p->flags & TLB_MMIO)) { - return do_st16_mmio_leN(env, p->full, val_le, p->addr, + return do_st16_mmio_leN(cpu, p->full, val_le, p->addr, size, mmu_idx, ra); } else if (unlikely(p->flags & TLB_DISCARD_WRITE)) { return int128_gethi(val_le) >> ((size - 8) * 8); @@ -2838,7 +2832,7 @@ static uint64_t do_st16_leN(CPUArchState *env, MMULookupPageData *p, case MO_ATOM_WITHIN16_PAIR: /* Since size > 8, this is the half that must be atomic. */ if (!HAVE_ATOMIC128_RW) { - cpu_loop_exit_atomic(env_cpu(env), ra); + cpu_loop_exit_atomic(cpu, ra); } return store_whole_le16(p->haddr, p->size, val_le); @@ -2859,11 +2853,11 @@ static uint64_t do_st16_leN(CPUArchState *env, MMULookupPageData *p, } } -static void do_st_1(CPUArchState *env, MMULookupPageData *p, uint8_t val, +static void do_st_1(CPUState *cpu, MMULookupPageData *p, uint8_t val, int mmu_idx, uintptr_t ra) { if (unlikely(p->flags & TLB_MMIO)) { - do_st_mmio_leN(env, p->full, val, p->addr, 1, mmu_idx, ra); + do_st_mmio_leN(cpu, p->full, val, p->addr, 1, mmu_idx, ra); } else if (unlikely(p->flags & TLB_DISCARD_WRITE)) { /* nothing */ } else { @@ -2871,14 +2865,14 @@ static void do_st_1(CPUArchState *env, MMULookupPageData *p, uint8_t val, } } -static void do_st_2(CPUArchState *env, MMULookupPageData *p, uint16_t val, +static void do_st_2(CPUState *cpu, MMULookupPageData *p, uint16_t val, int mmu_idx, MemOp memop, uintptr_t ra) { if (unlikely(p->flags & TLB_MMIO)) { if ((memop & MO_BSWAP) != MO_LE) { val = bswap16(val); } - do_st_mmio_leN(env, p->full, val, p->addr, 2, mmu_idx, ra); + do_st_mmio_leN(cpu, p->full, val, p->addr, 2, mmu_idx, ra); } else if (unlikely(p->flags & TLB_DISCARD_WRITE)) { /* nothing */ } else { @@ -2886,18 +2880,18 @@ static void do_st_2(CPUArchState *env, MMULookupPageData *p, uint16_t val, if (memop & MO_BSWAP) { val = bswap16(val); } - store_atom_2(env, ra, p->haddr, memop, val); + store_atom_2(cpu_env(cpu), ra, p->haddr, memop, val); } } -static void do_st_4(CPUArchState *env, MMULookupPageData *p, uint32_t val, +static void do_st_4(CPUState *cpu, MMULookupPageData *p, uint32_t val, int mmu_idx, MemOp memop, uintptr_t ra) { if (unlikely(p->flags & TLB_MMIO)) { if ((memop & MO_BSWAP) != MO_LE) { val = bswap32(val); } - do_st_mmio_leN(env, p->full, val, p->addr, 4, mmu_idx, ra); + do_st_mmio_leN(cpu, p->full, val, p->addr, 4, mmu_idx, ra); } else if (unlikely(p->flags & TLB_DISCARD_WRITE)) { /* nothing */ } else { @@ -2905,18 +2899,18 @@ static void do_st_4(CPUArchState *env, MMULookupPageData *p, uint32_t val, if (memop & MO_BSWAP) { val = bswap32(val); } - store_atom_4(env, ra, p->haddr, memop, val); + store_atom_4(cpu_env(cpu), ra, p->haddr, memop, val); } } -static void do_st_8(CPUArchState *env, MMULookupPageData *p, uint64_t val, +static void do_st_8(CPUState *cpu, MMULookupPageData *p, uint64_t val, int mmu_idx, MemOp memop, uintptr_t ra) { if (unlikely(p->flags & TLB_MMIO)) { if ((memop & MO_BSWAP) != MO_LE) { val = bswap64(val); } - do_st_mmio_leN(env, p->full, val, p->addr, 8, mmu_idx, ra); + do_st_mmio_leN(cpu, p->full, val, p->addr, 8, mmu_idx, ra); } else if (unlikely(p->flags & TLB_DISCARD_WRITE)) { /* nothing */ } else { @@ -2924,7 +2918,7 @@ static void do_st_8(CPUArchState *env, MMULookupPageData *p, uint64_t val, if (memop & MO_BSWAP) { val = bswap64(val); } - store_atom_8(env, ra, p->haddr, memop, val); + store_atom_8(cpu_env(cpu), ra, p->haddr, memop, val); } } @@ -2936,13 +2930,13 @@ void helper_stb_mmu(CPUArchState *env, uint64_t addr, uint32_t val, tcg_debug_assert((get_memop(oi) & MO_SIZE) == MO_8); cpu_req_mo(TCG_MO_LD_ST | TCG_MO_ST_ST); - crosspage = mmu_lookup(env, addr, oi, ra, MMU_DATA_STORE, &l); + crosspage = mmu_lookup(env_cpu(env), addr, oi, ra, MMU_DATA_STORE, &l); tcg_debug_assert(!crosspage); - do_st_1(env, &l.page[0], val, l.mmu_idx, ra); + do_st_1(env_cpu(env), &l.page[0], val, l.mmu_idx, ra); } -static void do_st2_mmu(CPUArchState *env, vaddr addr, uint16_t val, +static void do_st2_mmu(CPUState *cpu, vaddr addr, uint16_t val, MemOpIdx oi, uintptr_t ra) { MMULookupLocals l; @@ -2950,9 +2944,9 @@ static void do_st2_mmu(CPUArchState *env, vaddr addr, uint16_t val, uint8_t a, b; cpu_req_mo(TCG_MO_LD_ST | TCG_MO_ST_ST); - crosspage = mmu_lookup(env, addr, oi, ra, MMU_DATA_STORE, &l); + crosspage = mmu_lookup(cpu, addr, oi, ra, MMU_DATA_STORE, &l); if (likely(!crosspage)) { - do_st_2(env, &l.page[0], val, l.mmu_idx, l.memop, ra); + do_st_2(cpu, &l.page[0], val, l.mmu_idx, l.memop, ra); return; } @@ -2961,27 +2955,27 @@ static void do_st2_mmu(CPUArchState *env, vaddr addr, uint16_t val, } else { b = val, a = val >> 8; } - do_st_1(env, &l.page[0], a, l.mmu_idx, ra); - do_st_1(env, &l.page[1], b, l.mmu_idx, ra); + do_st_1(cpu, &l.page[0], a, l.mmu_idx, ra); + do_st_1(cpu, &l.page[1], b, l.mmu_idx, ra); } void helper_stw_mmu(CPUArchState *env, uint64_t addr, uint32_t val, MemOpIdx oi, uintptr_t retaddr) { tcg_debug_assert((get_memop(oi) & MO_SIZE) == MO_16); - do_st2_mmu(env, addr, val, oi, retaddr); + do_st2_mmu(env_cpu(env), addr, val, oi, retaddr); } -static void do_st4_mmu(CPUArchState *env, vaddr addr, uint32_t val, +static void do_st4_mmu(CPUState *cpu, vaddr addr, uint32_t val, MemOpIdx oi, uintptr_t ra) { MMULookupLocals l; bool crosspage; cpu_req_mo(TCG_MO_LD_ST | TCG_MO_ST_ST); - crosspage = mmu_lookup(env, addr, oi, ra, MMU_DATA_STORE, &l); + crosspage = mmu_lookup(cpu, addr, oi, ra, MMU_DATA_STORE, &l); if (likely(!crosspage)) { - do_st_4(env, &l.page[0], val, l.mmu_idx, l.memop, ra); + do_st_4(cpu, &l.page[0], val, l.mmu_idx, l.memop, ra); return; } @@ -2989,27 +2983,27 @@ static void do_st4_mmu(CPUArchState *env, vaddr addr, uint32_t val, if ((l.memop & MO_BSWAP) != MO_LE) { val = bswap32(val); } - val = do_st_leN(env, &l.page[0], val, l.mmu_idx, l.memop, ra); - (void) do_st_leN(env, &l.page[1], val, l.mmu_idx, l.memop, ra); + val = do_st_leN(cpu, &l.page[0], val, l.mmu_idx, l.memop, ra); + (void) do_st_leN(cpu, &l.page[1], val, l.mmu_idx, l.memop, ra); } void helper_stl_mmu(CPUArchState *env, uint64_t addr, uint32_t val, MemOpIdx oi, uintptr_t retaddr) { tcg_debug_assert((get_memop(oi) & MO_SIZE) == MO_32); - do_st4_mmu(env, addr, val, oi, retaddr); + do_st4_mmu(env_cpu(env), addr, val, oi, retaddr); } -static void do_st8_mmu(CPUArchState *env, vaddr addr, uint64_t val, +static void do_st8_mmu(CPUState *cpu, vaddr addr, uint64_t val, MemOpIdx oi, uintptr_t ra) { MMULookupLocals l; bool crosspage; cpu_req_mo(TCG_MO_LD_ST | TCG_MO_ST_ST); - crosspage = mmu_lookup(env, addr, oi, ra, MMU_DATA_STORE, &l); + crosspage = mmu_lookup(cpu, addr, oi, ra, MMU_DATA_STORE, &l); if (likely(!crosspage)) { - do_st_8(env, &l.page[0], val, l.mmu_idx, l.memop, ra); + do_st_8(cpu, &l.page[0], val, l.mmu_idx, l.memop, ra); return; } @@ -3017,18 +3011,18 @@ static void do_st8_mmu(CPUArchState *env, vaddr addr, uint64_t val, if ((l.memop & MO_BSWAP) != MO_LE) { val = bswap64(val); } - val = do_st_leN(env, &l.page[0], val, l.mmu_idx, l.memop, ra); - (void) do_st_leN(env, &l.page[1], val, l.mmu_idx, l.memop, ra); + val = do_st_leN(cpu, &l.page[0], val, l.mmu_idx, l.memop, ra); + (void) do_st_leN(cpu, &l.page[1], val, l.mmu_idx, l.memop, ra); } void helper_stq_mmu(CPUArchState *env, uint64_t addr, uint64_t val, MemOpIdx oi, uintptr_t retaddr) { tcg_debug_assert((get_memop(oi) & MO_SIZE) == MO_64); - do_st8_mmu(env, addr, val, oi, retaddr); + do_st8_mmu(env_cpu(env), addr, val, oi, retaddr); } -static void do_st16_mmu(CPUArchState *env, vaddr addr, Int128 val, +static void do_st16_mmu(CPUState *cpu, vaddr addr, Int128 val, MemOpIdx oi, uintptr_t ra) { MMULookupLocals l; @@ -3037,13 +3031,13 @@ static void do_st16_mmu(CPUArchState *env, vaddr addr, Int128 val, int first; cpu_req_mo(TCG_MO_LD_ST | TCG_MO_ST_ST); - crosspage = mmu_lookup(env, addr, oi, ra, MMU_DATA_STORE, &l); + crosspage = mmu_lookup(cpu, addr, oi, ra, MMU_DATA_STORE, &l); if (likely(!crosspage)) { if (unlikely(l.page[0].flags & TLB_MMIO)) { if ((l.memop & MO_BSWAP) != MO_LE) { val = bswap128(val); } - do_st16_mmio_leN(env, l.page[0].full, val, addr, 16, l.mmu_idx, ra); + do_st16_mmio_leN(cpu, l.page[0].full, val, addr, 16, l.mmu_idx, ra); } else if (unlikely(l.page[0].flags & TLB_DISCARD_WRITE)) { /* nothing */ } else { @@ -3051,7 +3045,7 @@ static void do_st16_mmu(CPUArchState *env, vaddr addr, Int128 val, if (l.memop & MO_BSWAP) { val = bswap128(val); } - store_atom_16(env, ra, l.page[0].haddr, l.memop, val); + store_atom_16(cpu_env(cpu), ra, l.page[0].haddr, l.memop, val); } return; } @@ -3068,8 +3062,8 @@ static void do_st16_mmu(CPUArchState *env, vaddr addr, Int128 val, } else { a = int128_getlo(val), b = int128_gethi(val); } - do_st_8(env, &l.page[0], a, l.mmu_idx, mop8, ra); - do_st_8(env, &l.page[1], b, l.mmu_idx, mop8, ra); + do_st_8(cpu, &l.page[0], a, l.mmu_idx, mop8, ra); + do_st_8(cpu, &l.page[1], b, l.mmu_idx, mop8, ra); return; } @@ -3077,12 +3071,12 @@ static void do_st16_mmu(CPUArchState *env, vaddr addr, Int128 val, val = bswap128(val); } if (first < 8) { - do_st_leN(env, &l.page[0], int128_getlo(val), l.mmu_idx, l.memop, ra); + do_st_leN(cpu, &l.page[0], int128_getlo(val), l.mmu_idx, l.memop, ra); val = int128_urshift(val, first * 8); - do_st16_leN(env, &l.page[1], val, l.mmu_idx, l.memop, ra); + do_st16_leN(cpu, &l.page[1], val, l.mmu_idx, l.memop, ra); } else { - b = do_st16_leN(env, &l.page[0], val, l.mmu_idx, l.memop, ra); - do_st_leN(env, &l.page[1], b, l.mmu_idx, l.memop, ra); + b = do_st16_leN(cpu, &l.page[0], val, l.mmu_idx, l.memop, ra); + do_st_leN(cpu, &l.page[1], b, l.mmu_idx, l.memop, ra); } } @@ -3090,7 +3084,7 @@ void helper_st16_mmu(CPUArchState *env, uint64_t addr, Int128 val, MemOpIdx oi, uintptr_t retaddr) { tcg_debug_assert((get_memop(oi) & MO_SIZE) == MO_128); - do_st16_mmu(env, addr, val, oi, retaddr); + do_st16_mmu(env_cpu(env), addr, val, oi, retaddr); } void helper_st_i128(CPUArchState *env, uint64_t addr, Int128 val, MemOpIdx oi) @@ -3118,7 +3112,7 @@ void cpu_stw_mmu(CPUArchState *env, abi_ptr addr, uint16_t val, MemOpIdx oi, uintptr_t retaddr) { tcg_debug_assert((get_memop(oi) & MO_SIZE) == MO_16); - do_st2_mmu(env, addr, val, oi, retaddr); + do_st2_mmu(env_cpu(env), addr, val, oi, retaddr); plugin_store_cb(env, addr, oi); } @@ -3126,7 +3120,7 @@ void cpu_stl_mmu(CPUArchState *env, abi_ptr addr, uint32_t val, MemOpIdx oi, uintptr_t retaddr) { tcg_debug_assert((get_memop(oi) & MO_SIZE) == MO_32); - do_st4_mmu(env, addr, val, oi, retaddr); + do_st4_mmu(env_cpu(env), addr, val, oi, retaddr); plugin_store_cb(env, addr, oi); } @@ -3134,7 +3128,7 @@ void cpu_stq_mmu(CPUArchState *env, abi_ptr addr, uint64_t val, MemOpIdx oi, uintptr_t retaddr) { tcg_debug_assert((get_memop(oi) & MO_SIZE) == MO_64); - do_st8_mmu(env, addr, val, oi, retaddr); + do_st8_mmu(env_cpu(env), addr, val, oi, retaddr); plugin_store_cb(env, addr, oi); } @@ -3142,7 +3136,7 @@ void cpu_st16_mmu(CPUArchState *env, abi_ptr addr, Int128 val, MemOpIdx oi, uintptr_t retaddr) { tcg_debug_assert((get_memop(oi) & MO_SIZE) == MO_128); - do_st16_mmu(env, addr, val, oi, retaddr); + do_st16_mmu(env_cpu(env), addr, val, oi, retaddr); plugin_store_cb(env, addr, oi); } @@ -3184,47 +3178,47 @@ void cpu_st16_mmu(CPUArchState *env, abi_ptr addr, Int128 val, uint32_t cpu_ldub_code(CPUArchState *env, abi_ptr addr) { MemOpIdx oi = make_memop_idx(MO_UB, cpu_mmu_index(env, true)); - return do_ld1_mmu(env, addr, oi, 0, MMU_INST_FETCH); + return do_ld1_mmu(env_cpu(env), addr, oi, 0, MMU_INST_FETCH); } uint32_t cpu_lduw_code(CPUArchState *env, abi_ptr addr) { MemOpIdx oi = make_memop_idx(MO_TEUW, cpu_mmu_index(env, true)); - return do_ld2_mmu(env, addr, oi, 0, MMU_INST_FETCH); + return do_ld2_mmu(env_cpu(env), addr, oi, 0, MMU_INST_FETCH); } uint32_t cpu_ldl_code(CPUArchState *env, abi_ptr addr) { MemOpIdx oi = make_memop_idx(MO_TEUL, cpu_mmu_index(env, true)); - return do_ld4_mmu(env, addr, oi, 0, MMU_INST_FETCH); + return do_ld4_mmu(env_cpu(env), addr, oi, 0, MMU_INST_FETCH); } uint64_t cpu_ldq_code(CPUArchState *env, abi_ptr addr) { MemOpIdx oi = make_memop_idx(MO_TEUQ, cpu_mmu_index(env, true)); - return do_ld8_mmu(env, addr, oi, 0, MMU_INST_FETCH); + return do_ld8_mmu(env_cpu(env), addr, oi, 0, MMU_INST_FETCH); } uint8_t cpu_ldb_code_mmu(CPUArchState *env, abi_ptr addr, MemOpIdx oi, uintptr_t retaddr) { - return do_ld1_mmu(env, addr, oi, retaddr, MMU_INST_FETCH); + return do_ld1_mmu(env_cpu(env), addr, oi, retaddr, MMU_INST_FETCH); } uint16_t cpu_ldw_code_mmu(CPUArchState *env, abi_ptr addr, MemOpIdx oi, uintptr_t retaddr) { - return do_ld2_mmu(env, addr, oi, retaddr, MMU_INST_FETCH); + return do_ld2_mmu(env_cpu(env), addr, oi, retaddr, MMU_INST_FETCH); } uint32_t cpu_ldl_code_mmu(CPUArchState *env, abi_ptr addr, MemOpIdx oi, uintptr_t retaddr) { - return do_ld4_mmu(env, addr, oi, retaddr, MMU_INST_FETCH); + return do_ld4_mmu(env_cpu(env), addr, oi, retaddr, MMU_INST_FETCH); } uint64_t cpu_ldq_code_mmu(CPUArchState *env, abi_ptr addr, MemOpIdx oi, uintptr_t retaddr) { - return do_ld8_mmu(env, addr, oi, retaddr, MMU_INST_FETCH); + return do_ld8_mmu(env_cpu(env), addr, oi, retaddr, MMU_INST_FETCH); } From d560225fc4c3b75e65665df503c0641e3030bd08 Mon Sep 17 00:00:00 2001 From: Anton Johansson Date: Tue, 12 Sep 2023 17:34:23 +0200 Subject: [PATCH 0255/1077] accel/tcg: Modify atomic_mmu_lookup() to use CPUState MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The goal is to (in the future) allow for per-target compilation of functions in atomic_template.h whilst atomic_mmu_lookup() and cputlb.c are compiled once-per user- or system mode. Signed-off-by: Anton Johansson Message-Id: <20230912153428.17816-7-anjo@rev.ng> Reviewed-by: Richard Henderson Reviewed-by: Philippe Mathieu-Daudé [rth: Use cpu->neg.tlb instead of cpu_tlb()] Signed-off-by: Richard Henderson --- accel/tcg/atomic_template.h | 20 ++++++++++++-------- accel/tcg/cputlb.c | 26 +++++++++++++------------- accel/tcg/user-exec.c | 8 ++++---- 3 files changed, 29 insertions(+), 25 deletions(-) diff --git a/accel/tcg/atomic_template.h b/accel/tcg/atomic_template.h index 84c08b1425..1dc2151daf 100644 --- a/accel/tcg/atomic_template.h +++ b/accel/tcg/atomic_template.h @@ -73,7 +73,8 @@ ABI_TYPE ATOMIC_NAME(cmpxchg)(CPUArchState *env, abi_ptr addr, ABI_TYPE cmpv, ABI_TYPE newv, MemOpIdx oi, uintptr_t retaddr) { - DATA_TYPE *haddr = atomic_mmu_lookup(env, addr, oi, DATA_SIZE, retaddr); + DATA_TYPE *haddr = atomic_mmu_lookup(env_cpu(env), addr, oi, + DATA_SIZE, retaddr); DATA_TYPE ret; #if DATA_SIZE == 16 @@ -90,7 +91,8 @@ ABI_TYPE ATOMIC_NAME(cmpxchg)(CPUArchState *env, abi_ptr addr, ABI_TYPE ATOMIC_NAME(xchg)(CPUArchState *env, abi_ptr addr, ABI_TYPE val, MemOpIdx oi, uintptr_t retaddr) { - DATA_TYPE *haddr = atomic_mmu_lookup(env, addr, oi, DATA_SIZE, retaddr); + DATA_TYPE *haddr = atomic_mmu_lookup(env_cpu(env), addr, oi, + DATA_SIZE, retaddr); DATA_TYPE ret; ret = qatomic_xchg__nocheck(haddr, val); @@ -104,7 +106,7 @@ ABI_TYPE ATOMIC_NAME(X)(CPUArchState *env, abi_ptr addr, \ ABI_TYPE val, MemOpIdx oi, uintptr_t retaddr) \ { \ DATA_TYPE *haddr, ret; \ - haddr = atomic_mmu_lookup(env, addr, oi, DATA_SIZE, retaddr); \ + haddr = atomic_mmu_lookup(env_cpu(env), addr, oi, DATA_SIZE, retaddr); \ ret = qatomic_##X(haddr, val); \ ATOMIC_MMU_CLEANUP; \ atomic_trace_rmw_post(env, addr, oi); \ @@ -135,7 +137,7 @@ ABI_TYPE ATOMIC_NAME(X)(CPUArchState *env, abi_ptr addr, \ ABI_TYPE xval, MemOpIdx oi, uintptr_t retaddr) \ { \ XDATA_TYPE *haddr, cmp, old, new, val = xval; \ - haddr = atomic_mmu_lookup(env, addr, oi, DATA_SIZE, retaddr); \ + haddr = atomic_mmu_lookup(env_cpu(env), addr, oi, DATA_SIZE, retaddr); \ smp_mb(); \ cmp = qatomic_read__nocheck(haddr); \ do { \ @@ -176,7 +178,8 @@ ABI_TYPE ATOMIC_NAME(cmpxchg)(CPUArchState *env, abi_ptr addr, ABI_TYPE cmpv, ABI_TYPE newv, MemOpIdx oi, uintptr_t retaddr) { - DATA_TYPE *haddr = atomic_mmu_lookup(env, addr, oi, DATA_SIZE, retaddr); + DATA_TYPE *haddr = atomic_mmu_lookup(env_cpu(env), addr, oi, + DATA_SIZE, retaddr); DATA_TYPE ret; #if DATA_SIZE == 16 @@ -193,7 +196,8 @@ ABI_TYPE ATOMIC_NAME(cmpxchg)(CPUArchState *env, abi_ptr addr, ABI_TYPE ATOMIC_NAME(xchg)(CPUArchState *env, abi_ptr addr, ABI_TYPE val, MemOpIdx oi, uintptr_t retaddr) { - DATA_TYPE *haddr = atomic_mmu_lookup(env, addr, oi, DATA_SIZE, retaddr); + DATA_TYPE *haddr = atomic_mmu_lookup(env_cpu(env), addr, oi, + DATA_SIZE, retaddr); ABI_TYPE ret; ret = qatomic_xchg__nocheck(haddr, BSWAP(val)); @@ -207,7 +211,7 @@ ABI_TYPE ATOMIC_NAME(X)(CPUArchState *env, abi_ptr addr, \ ABI_TYPE val, MemOpIdx oi, uintptr_t retaddr) \ { \ DATA_TYPE *haddr, ret; \ - haddr = atomic_mmu_lookup(env, addr, oi, DATA_SIZE, retaddr); \ + haddr = atomic_mmu_lookup(env_cpu(env), addr, oi, DATA_SIZE, retaddr); \ ret = qatomic_##X(haddr, BSWAP(val)); \ ATOMIC_MMU_CLEANUP; \ atomic_trace_rmw_post(env, addr, oi); \ @@ -235,7 +239,7 @@ ABI_TYPE ATOMIC_NAME(X)(CPUArchState *env, abi_ptr addr, \ ABI_TYPE xval, MemOpIdx oi, uintptr_t retaddr) \ { \ XDATA_TYPE *haddr, ldo, ldn, old, new, val = xval; \ - haddr = atomic_mmu_lookup(env, addr, oi, DATA_SIZE, retaddr); \ + haddr = atomic_mmu_lookup(env_cpu(env), addr, oi, DATA_SIZE, retaddr); \ smp_mb(); \ ldn = qatomic_read__nocheck(haddr); \ do { \ diff --git a/accel/tcg/cputlb.c b/accel/tcg/cputlb.c index 0e4bc82294..3703443b5c 100644 --- a/accel/tcg/cputlb.c +++ b/accel/tcg/cputlb.c @@ -1856,7 +1856,7 @@ static bool mmu_lookup(CPUState *cpu, vaddr addr, MemOpIdx oi, * Probe for an atomic operation. Do not allow unaligned operations, * or io operations to proceed. Return the host address. */ -static void *atomic_mmu_lookup(CPUArchState *env, vaddr addr, MemOpIdx oi, +static void *atomic_mmu_lookup(CPUState *cpu, vaddr addr, MemOpIdx oi, int size, uintptr_t retaddr) { uintptr_t mmu_idx = get_mmuidx(oi); @@ -1876,7 +1876,7 @@ static void *atomic_mmu_lookup(CPUArchState *env, vaddr addr, MemOpIdx oi, /* Enforce guest required alignment. */ if (unlikely(a_bits > 0 && (addr & ((1 << a_bits) - 1)))) { /* ??? Maybe indicate atomic op to cpu_unaligned_access */ - cpu_unaligned_access(env_cpu(env), addr, MMU_DATA_STORE, + cpu_unaligned_access(cpu, addr, MMU_DATA_STORE, mmu_idx, retaddr); } @@ -1889,18 +1889,18 @@ static void *atomic_mmu_lookup(CPUArchState *env, vaddr addr, MemOpIdx oi, goto stop_the_world; } - index = tlb_index(env_cpu(env), mmu_idx, addr); - tlbe = tlb_entry(env_cpu(env), mmu_idx, addr); + index = tlb_index(cpu, mmu_idx, addr); + tlbe = tlb_entry(cpu, mmu_idx, addr); /* Check TLB entry and enforce page permissions. */ tlb_addr = tlb_addr_write(tlbe); if (!tlb_hit(tlb_addr, addr)) { - if (!victim_tlb_hit(env_cpu(env), mmu_idx, index, MMU_DATA_STORE, + if (!victim_tlb_hit(cpu, mmu_idx, index, MMU_DATA_STORE, addr & TARGET_PAGE_MASK)) { - tlb_fill(env_cpu(env), addr, size, + tlb_fill(cpu, addr, size, MMU_DATA_STORE, mmu_idx, retaddr); - index = tlb_index(env_cpu(env), mmu_idx, addr); - tlbe = tlb_entry(env_cpu(env), mmu_idx, addr); + index = tlb_index(cpu, mmu_idx, addr); + tlbe = tlb_entry(cpu, mmu_idx, addr); } tlb_addr = tlb_addr_write(tlbe) & ~TLB_INVALID_MASK; } @@ -1912,7 +1912,7 @@ static void *atomic_mmu_lookup(CPUArchState *env, vaddr addr, MemOpIdx oi, * but addr_read will only be -1 if PAGE_READ was unset. */ if (unlikely(tlbe->addr_read == -1)) { - tlb_fill(env_cpu(env), addr, size, MMU_DATA_LOAD, mmu_idx, retaddr); + tlb_fill(cpu, addr, size, MMU_DATA_LOAD, mmu_idx, retaddr); /* * Since we don't support reads and writes to different * addresses, and we do have the proper page loaded for @@ -1932,10 +1932,10 @@ static void *atomic_mmu_lookup(CPUArchState *env, vaddr addr, MemOpIdx oi, } hostaddr = (void *)((uintptr_t)addr + tlbe->addend); - full = &env_tlb(env)->d[mmu_idx].fulltlb[index]; + full = &cpu->neg.tlb.d[mmu_idx].fulltlb[index]; if (unlikely(tlb_addr & TLB_NOTDIRTY)) { - notdirty_write(env_cpu(env), addr, size, full, retaddr); + notdirty_write(cpu, addr, size, full, retaddr); } if (unlikely(tlb_addr & TLB_FORCE_SLOW)) { @@ -1948,7 +1948,7 @@ static void *atomic_mmu_lookup(CPUArchState *env, vaddr addr, MemOpIdx oi, wp_flags |= BP_MEM_READ; } if (wp_flags) { - cpu_check_watchpoint(env_cpu(env), addr, size, + cpu_check_watchpoint(cpu, addr, size, full->attrs, wp_flags, retaddr); } } @@ -1956,7 +1956,7 @@ static void *atomic_mmu_lookup(CPUArchState *env, vaddr addr, MemOpIdx oi, return hostaddr; stop_the_world: - cpu_loop_exit_atomic(env_cpu(env), retaddr); + cpu_loop_exit_atomic(cpu, retaddr); } /* diff --git a/accel/tcg/user-exec.c b/accel/tcg/user-exec.c index ab48cb41e4..d2daeafbab 100644 --- a/accel/tcg/user-exec.c +++ b/accel/tcg/user-exec.c @@ -1386,7 +1386,7 @@ uint64_t cpu_ldq_code_mmu(CPUArchState *env, abi_ptr addr, /* * Do not allow unaligned operations to proceed. Return the host address. */ -static void *atomic_mmu_lookup(CPUArchState *env, vaddr addr, MemOpIdx oi, +static void *atomic_mmu_lookup(CPUState *cpu, vaddr addr, MemOpIdx oi, int size, uintptr_t retaddr) { MemOp mop = get_memop(oi); @@ -1395,15 +1395,15 @@ static void *atomic_mmu_lookup(CPUArchState *env, vaddr addr, MemOpIdx oi, /* Enforce guest required alignment. */ if (unlikely(addr & ((1 << a_bits) - 1))) { - cpu_loop_exit_sigbus(env_cpu(env), addr, MMU_DATA_STORE, retaddr); + cpu_loop_exit_sigbus(cpu, addr, MMU_DATA_STORE, retaddr); } /* Enforce qemu required alignment. */ if (unlikely(addr & (size - 1))) { - cpu_loop_exit_atomic(env_cpu(env), retaddr); + cpu_loop_exit_atomic(cpu, retaddr); } - ret = g2h(env_cpu(env), addr); + ret = g2h(cpu, addr); set_helper_retaddr(retaddr); return ret; } From 73fda56f33151331b86bba5f6d1fbd001902776b Mon Sep 17 00:00:00 2001 From: Anton Johansson Date: Tue, 12 Sep 2023 17:34:24 +0200 Subject: [PATCH 0256/1077] accel/tcg: Use CPUState in atomicity helpers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Makes ldst_atomicity.c.inc almost target-independent, with the exception of TARGET_PAGE_MASK, which will be addressed in a future patch. Signed-off-by: Anton Johansson Message-Id: <20230912153428.17816-8-anjo@rev.ng> Reviewed-by: Richard Henderson Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Richard Henderson --- accel/tcg/cputlb.c | 20 ++++---- accel/tcg/ldst_atomicity.c.inc | 88 +++++++++++++++++----------------- accel/tcg/user-exec.c | 16 +++---- 3 files changed, 62 insertions(+), 62 deletions(-) diff --git a/accel/tcg/cputlb.c b/accel/tcg/cputlb.c index 3703443b5c..17fa7a514c 100644 --- a/accel/tcg/cputlb.c +++ b/accel/tcg/cputlb.c @@ -2172,7 +2172,7 @@ static uint64_t do_ld_whole_be8(CPUState *cpu, uintptr_t ra, MMULookupPageData *p, uint64_t ret_be) { int o = p->addr & 7; - uint64_t x = load_atomic8_or_exit(cpu_env(cpu), ra, p->haddr - o); + uint64_t x = load_atomic8_or_exit(cpu, ra, p->haddr - o); x = cpu_to_be64(x); x <<= o * 8; @@ -2192,7 +2192,7 @@ static Int128 do_ld_whole_be16(CPUState *cpu, uintptr_t ra, MMULookupPageData *p, uint64_t ret_be) { int o = p->addr & 15; - Int128 x, y = load_atomic16_or_exit(cpu_env(cpu), ra, p->haddr - o); + Int128 x, y = load_atomic16_or_exit(cpu, ra, p->haddr - o); int size = p->size; if (!HOST_BIG_ENDIAN) { @@ -2329,7 +2329,7 @@ static uint16_t do_ld_2(CPUState *cpu, MMULookupPageData *p, int mmu_idx, } } else { /* Perform the load host endian, then swap if necessary. */ - ret = load_atom_2(cpu_env(cpu), ra, p->haddr, memop); + ret = load_atom_2(cpu, ra, p->haddr, memop); if (memop & MO_BSWAP) { ret = bswap16(ret); } @@ -2349,7 +2349,7 @@ static uint32_t do_ld_4(CPUState *cpu, MMULookupPageData *p, int mmu_idx, } } else { /* Perform the load host endian. */ - ret = load_atom_4(cpu_env(cpu), ra, p->haddr, memop); + ret = load_atom_4(cpu, ra, p->haddr, memop); if (memop & MO_BSWAP) { ret = bswap32(ret); } @@ -2369,7 +2369,7 @@ static uint64_t do_ld_8(CPUState *cpu, MMULookupPageData *p, int mmu_idx, } } else { /* Perform the load host endian. */ - ret = load_atom_8(cpu_env(cpu), ra, p->haddr, memop); + ret = load_atom_8(cpu, ra, p->haddr, memop); if (memop & MO_BSWAP) { ret = bswap64(ret); } @@ -2528,7 +2528,7 @@ static Int128 do_ld16_mmu(CPUState *cpu, vaddr addr, } } else { /* Perform the load host endian. */ - ret = load_atom_16(cpu_env(cpu), ra, l.page[0].haddr, l.memop); + ret = load_atom_16(cpu, ra, l.page[0].haddr, l.memop); if (l.memop & MO_BSWAP) { ret = bswap128(ret); } @@ -2880,7 +2880,7 @@ static void do_st_2(CPUState *cpu, MMULookupPageData *p, uint16_t val, if (memop & MO_BSWAP) { val = bswap16(val); } - store_atom_2(cpu_env(cpu), ra, p->haddr, memop, val); + store_atom_2(cpu, ra, p->haddr, memop, val); } } @@ -2899,7 +2899,7 @@ static void do_st_4(CPUState *cpu, MMULookupPageData *p, uint32_t val, if (memop & MO_BSWAP) { val = bswap32(val); } - store_atom_4(cpu_env(cpu), ra, p->haddr, memop, val); + store_atom_4(cpu, ra, p->haddr, memop, val); } } @@ -2918,7 +2918,7 @@ static void do_st_8(CPUState *cpu, MMULookupPageData *p, uint64_t val, if (memop & MO_BSWAP) { val = bswap64(val); } - store_atom_8(cpu_env(cpu), ra, p->haddr, memop, val); + store_atom_8(cpu, ra, p->haddr, memop, val); } } @@ -3045,7 +3045,7 @@ static void do_st16_mmu(CPUState *cpu, vaddr addr, Int128 val, if (l.memop & MO_BSWAP) { val = bswap128(val); } - store_atom_16(cpu_env(cpu), ra, l.page[0].haddr, l.memop, val); + store_atom_16(cpu, ra, l.page[0].haddr, l.memop, val); } return; } diff --git a/accel/tcg/ldst_atomicity.c.inc b/accel/tcg/ldst_atomicity.c.inc index 1b793e6935..1cf5b92166 100644 --- a/accel/tcg/ldst_atomicity.c.inc +++ b/accel/tcg/ldst_atomicity.c.inc @@ -26,7 +26,7 @@ * If the operation must be split into two operations to be * examined separately for atomicity, return -lg2. */ -static int required_atomicity(CPUArchState *env, uintptr_t p, MemOp memop) +static int required_atomicity(CPUState *cpu, uintptr_t p, MemOp memop) { MemOp atom = memop & MO_ATOM_MASK; MemOp size = memop & MO_SIZE; @@ -93,7 +93,7 @@ static int required_atomicity(CPUArchState *env, uintptr_t p, MemOp memop) * host atomicity in order to avoid racing. This reduction * avoids looping with cpu_loop_exit_atomic. */ - if (cpu_in_serial_context(env_cpu(env))) { + if (cpu_in_serial_context(cpu)) { return MO_8; } return atmax; @@ -139,14 +139,14 @@ static inline uint64_t load_atomic8(void *pv) /** * load_atomic8_or_exit: - * @env: cpu context + * @cpu: generic cpu state * @ra: host unwind address * @pv: host address * * Atomically load 8 aligned bytes from @pv. * If this is not possible, longjmp out to restart serially. */ -static uint64_t load_atomic8_or_exit(CPUArchState *env, uintptr_t ra, void *pv) +static uint64_t load_atomic8_or_exit(CPUState *cpu, uintptr_t ra, void *pv) { if (HAVE_al8) { return load_atomic8(pv); @@ -168,19 +168,19 @@ static uint64_t load_atomic8_or_exit(CPUArchState *env, uintptr_t ra, void *pv) #endif /* Ultimate fallback: re-execute in serial context. */ - cpu_loop_exit_atomic(env_cpu(env), ra); + cpu_loop_exit_atomic(cpu, ra); } /** * load_atomic16_or_exit: - * @env: cpu context + * @cpu: generic cpu state * @ra: host unwind address * @pv: host address * * Atomically load 16 aligned bytes from @pv. * If this is not possible, longjmp out to restart serially. */ -static Int128 load_atomic16_or_exit(CPUArchState *env, uintptr_t ra, void *pv) +static Int128 load_atomic16_or_exit(CPUState *cpu, uintptr_t ra, void *pv) { Int128 *p = __builtin_assume_aligned(pv, 16); @@ -212,7 +212,7 @@ static Int128 load_atomic16_or_exit(CPUArchState *env, uintptr_t ra, void *pv) } /* Ultimate fallback: re-execute in serial context. */ - cpu_loop_exit_atomic(env_cpu(env), ra); + cpu_loop_exit_atomic(cpu, ra); } /** @@ -263,7 +263,7 @@ static uint64_t load_atom_extract_al8x2(void *pv) /** * load_atom_extract_al8_or_exit: - * @env: cpu context + * @cpu: generic cpu state * @ra: host unwind address * @pv: host address * @s: object size in bytes, @s <= 4. @@ -273,7 +273,7 @@ static uint64_t load_atom_extract_al8x2(void *pv) * 8-byte load and extract. * The value is returned in the low bits of a uint32_t. */ -static uint32_t load_atom_extract_al8_or_exit(CPUArchState *env, uintptr_t ra, +static uint32_t load_atom_extract_al8_or_exit(CPUState *cpu, uintptr_t ra, void *pv, int s) { uintptr_t pi = (uintptr_t)pv; @@ -281,12 +281,12 @@ static uint32_t load_atom_extract_al8_or_exit(CPUArchState *env, uintptr_t ra, int shr = (HOST_BIG_ENDIAN ? 8 - s - o : o) * 8; pv = (void *)(pi & ~7); - return load_atomic8_or_exit(env, ra, pv) >> shr; + return load_atomic8_or_exit(cpu, ra, pv) >> shr; } /** * load_atom_extract_al16_or_exit: - * @env: cpu context + * @cpu: generic cpu state * @ra: host unwind address * @p: host address * @s: object size in bytes, @s <= 8. @@ -299,7 +299,7 @@ static uint32_t load_atom_extract_al8_or_exit(CPUArchState *env, uintptr_t ra, * * If this is not possible, longjmp out to restart serially. */ -static uint64_t load_atom_extract_al16_or_exit(CPUArchState *env, uintptr_t ra, +static uint64_t load_atom_extract_al16_or_exit(CPUState *cpu, uintptr_t ra, void *pv, int s) { uintptr_t pi = (uintptr_t)pv; @@ -312,7 +312,7 @@ static uint64_t load_atom_extract_al16_or_exit(CPUArchState *env, uintptr_t ra, * Provoke SIGBUS if possible otherwise. */ pv = (void *)(pi & ~7); - r = load_atomic16_or_exit(env, ra, pv); + r = load_atomic16_or_exit(cpu, ra, pv); r = int128_urshift(r, shr); return int128_getlo(r); @@ -394,7 +394,7 @@ static inline uint64_t load_atom_8_by_8_or_4(void *pv) * * Load 2 bytes from @p, honoring the atomicity of @memop. */ -static uint16_t load_atom_2(CPUArchState *env, uintptr_t ra, +static uint16_t load_atom_2(CPUState *cpu, uintptr_t ra, void *pv, MemOp memop) { uintptr_t pi = (uintptr_t)pv; @@ -410,7 +410,7 @@ static uint16_t load_atom_2(CPUArchState *env, uintptr_t ra, } } - atmax = required_atomicity(env, pi, memop); + atmax = required_atomicity(cpu, pi, memop); switch (atmax) { case MO_8: return lduw_he_p(pv); @@ -421,9 +421,9 @@ static uint16_t load_atom_2(CPUArchState *env, uintptr_t ra, return load_atomic4(pv - 1) >> 8; } if ((pi & 15) != 7) { - return load_atom_extract_al8_or_exit(env, ra, pv, 2); + return load_atom_extract_al8_or_exit(cpu, ra, pv, 2); } - return load_atom_extract_al16_or_exit(env, ra, pv, 2); + return load_atom_extract_al16_or_exit(cpu, ra, pv, 2); default: g_assert_not_reached(); } @@ -436,7 +436,7 @@ static uint16_t load_atom_2(CPUArchState *env, uintptr_t ra, * * Load 4 bytes from @p, honoring the atomicity of @memop. */ -static uint32_t load_atom_4(CPUArchState *env, uintptr_t ra, +static uint32_t load_atom_4(CPUState *cpu, uintptr_t ra, void *pv, MemOp memop) { uintptr_t pi = (uintptr_t)pv; @@ -452,7 +452,7 @@ static uint32_t load_atom_4(CPUArchState *env, uintptr_t ra, } } - atmax = required_atomicity(env, pi, memop); + atmax = required_atomicity(cpu, pi, memop); switch (atmax) { case MO_8: case MO_16: @@ -466,9 +466,9 @@ static uint32_t load_atom_4(CPUArchState *env, uintptr_t ra, return load_atom_extract_al4x2(pv); case MO_32: if (!(pi & 4)) { - return load_atom_extract_al8_or_exit(env, ra, pv, 4); + return load_atom_extract_al8_or_exit(cpu, ra, pv, 4); } - return load_atom_extract_al16_or_exit(env, ra, pv, 4); + return load_atom_extract_al16_or_exit(cpu, ra, pv, 4); default: g_assert_not_reached(); } @@ -481,7 +481,7 @@ static uint32_t load_atom_4(CPUArchState *env, uintptr_t ra, * * Load 8 bytes from @p, honoring the atomicity of @memop. */ -static uint64_t load_atom_8(CPUArchState *env, uintptr_t ra, +static uint64_t load_atom_8(CPUState *cpu, uintptr_t ra, void *pv, MemOp memop) { uintptr_t pi = (uintptr_t)pv; @@ -498,12 +498,12 @@ static uint64_t load_atom_8(CPUArchState *env, uintptr_t ra, return load_atom_extract_al16_or_al8(pv, 8); } - atmax = required_atomicity(env, pi, memop); + atmax = required_atomicity(cpu, pi, memop); if (atmax == MO_64) { if (!HAVE_al8 && (pi & 7) == 0) { - load_atomic8_or_exit(env, ra, pv); + load_atomic8_or_exit(cpu, ra, pv); } - return load_atom_extract_al16_or_exit(env, ra, pv, 8); + return load_atom_extract_al16_or_exit(cpu, ra, pv, 8); } if (HAVE_al8_fast) { return load_atom_extract_al8x2(pv); @@ -519,7 +519,7 @@ static uint64_t load_atom_8(CPUArchState *env, uintptr_t ra, if (HAVE_al8) { return load_atom_extract_al8x2(pv); } - cpu_loop_exit_atomic(env_cpu(env), ra); + cpu_loop_exit_atomic(cpu, ra); default: g_assert_not_reached(); } @@ -532,7 +532,7 @@ static uint64_t load_atom_8(CPUArchState *env, uintptr_t ra, * * Load 16 bytes from @p, honoring the atomicity of @memop. */ -static Int128 load_atom_16(CPUArchState *env, uintptr_t ra, +static Int128 load_atom_16(CPUState *cpu, uintptr_t ra, void *pv, MemOp memop) { uintptr_t pi = (uintptr_t)pv; @@ -548,7 +548,7 @@ static Int128 load_atom_16(CPUArchState *env, uintptr_t ra, return atomic16_read_ro(pv); } - atmax = required_atomicity(env, pi, memop); + atmax = required_atomicity(cpu, pi, memop); switch (atmax) { case MO_8: memcpy(&r, pv, 16); @@ -563,20 +563,20 @@ static Int128 load_atom_16(CPUArchState *env, uintptr_t ra, break; case MO_64: if (!HAVE_al8) { - cpu_loop_exit_atomic(env_cpu(env), ra); + cpu_loop_exit_atomic(cpu, ra); } a = load_atomic8(pv); b = load_atomic8(pv + 8); break; case -MO_64: if (!HAVE_al8) { - cpu_loop_exit_atomic(env_cpu(env), ra); + cpu_loop_exit_atomic(cpu, ra); } a = load_atom_extract_al8x2(pv); b = load_atom_extract_al8x2(pv + 8); break; case MO_128: - return load_atomic16_or_exit(env, ra, pv); + return load_atomic16_or_exit(cpu, ra, pv); default: g_assert_not_reached(); } @@ -857,7 +857,7 @@ static uint64_t store_whole_le16(void *pv, int size, Int128 val_le) * * Store 2 bytes to @p, honoring the atomicity of @memop. */ -static void store_atom_2(CPUArchState *env, uintptr_t ra, +static void store_atom_2(CPUState *cpu, uintptr_t ra, void *pv, MemOp memop, uint16_t val) { uintptr_t pi = (uintptr_t)pv; @@ -868,7 +868,7 @@ static void store_atom_2(CPUArchState *env, uintptr_t ra, return; } - atmax = required_atomicity(env, pi, memop); + atmax = required_atomicity(cpu, pi, memop); if (atmax == MO_8) { stw_he_p(pv, val); return; @@ -897,7 +897,7 @@ static void store_atom_2(CPUArchState *env, uintptr_t ra, g_assert_not_reached(); } - cpu_loop_exit_atomic(env_cpu(env), ra); + cpu_loop_exit_atomic(cpu, ra); } /** @@ -908,7 +908,7 @@ static void store_atom_2(CPUArchState *env, uintptr_t ra, * * Store 4 bytes to @p, honoring the atomicity of @memop. */ -static void store_atom_4(CPUArchState *env, uintptr_t ra, +static void store_atom_4(CPUState *cpu, uintptr_t ra, void *pv, MemOp memop, uint32_t val) { uintptr_t pi = (uintptr_t)pv; @@ -919,7 +919,7 @@ static void store_atom_4(CPUArchState *env, uintptr_t ra, return; } - atmax = required_atomicity(env, pi, memop); + atmax = required_atomicity(cpu, pi, memop); switch (atmax) { case MO_8: stl_he_p(pv, val); @@ -961,7 +961,7 @@ static void store_atom_4(CPUArchState *env, uintptr_t ra, return; } } - cpu_loop_exit_atomic(env_cpu(env), ra); + cpu_loop_exit_atomic(cpu, ra); default: g_assert_not_reached(); } @@ -975,7 +975,7 @@ static void store_atom_4(CPUArchState *env, uintptr_t ra, * * Store 8 bytes to @p, honoring the atomicity of @memop. */ -static void store_atom_8(CPUArchState *env, uintptr_t ra, +static void store_atom_8(CPUState *cpu, uintptr_t ra, void *pv, MemOp memop, uint64_t val) { uintptr_t pi = (uintptr_t)pv; @@ -986,7 +986,7 @@ static void store_atom_8(CPUArchState *env, uintptr_t ra, return; } - atmax = required_atomicity(env, pi, memop); + atmax = required_atomicity(cpu, pi, memop); switch (atmax) { case MO_8: stq_he_p(pv, val); @@ -1029,7 +1029,7 @@ static void store_atom_8(CPUArchState *env, uintptr_t ra, default: g_assert_not_reached(); } - cpu_loop_exit_atomic(env_cpu(env), ra); + cpu_loop_exit_atomic(cpu, ra); } /** @@ -1040,7 +1040,7 @@ static void store_atom_8(CPUArchState *env, uintptr_t ra, * * Store 16 bytes to @p, honoring the atomicity of @memop. */ -static void store_atom_16(CPUArchState *env, uintptr_t ra, +static void store_atom_16(CPUState *cpu, uintptr_t ra, void *pv, MemOp memop, Int128 val) { uintptr_t pi = (uintptr_t)pv; @@ -1052,7 +1052,7 @@ static void store_atom_16(CPUArchState *env, uintptr_t ra, return; } - atmax = required_atomicity(env, pi, memop); + atmax = required_atomicity(cpu, pi, memop); a = HOST_BIG_ENDIAN ? int128_gethi(val) : int128_getlo(val); b = HOST_BIG_ENDIAN ? int128_getlo(val) : int128_gethi(val); @@ -1111,5 +1111,5 @@ static void store_atom_16(CPUArchState *env, uintptr_t ra, default: g_assert_not_reached(); } - cpu_loop_exit_atomic(env_cpu(env), ra); + cpu_loop_exit_atomic(cpu, ra); } diff --git a/accel/tcg/user-exec.c b/accel/tcg/user-exec.c index d2daeafbab..f9f5cd1770 100644 --- a/accel/tcg/user-exec.c +++ b/accel/tcg/user-exec.c @@ -1002,7 +1002,7 @@ static uint16_t do_ld2_mmu(CPUArchState *env, abi_ptr addr, tcg_debug_assert((mop & MO_SIZE) == MO_16); cpu_req_mo(TCG_MO_LD_LD | TCG_MO_ST_LD); haddr = cpu_mmu_lookup(env, addr, mop, ra, MMU_DATA_LOAD); - ret = load_atom_2(env, ra, haddr, mop); + ret = load_atom_2(env_cpu(env), ra, haddr, mop); clear_helper_retaddr(); if (mop & MO_BSWAP) { @@ -1040,7 +1040,7 @@ static uint32_t do_ld4_mmu(CPUArchState *env, abi_ptr addr, tcg_debug_assert((mop & MO_SIZE) == MO_32); cpu_req_mo(TCG_MO_LD_LD | TCG_MO_ST_LD); haddr = cpu_mmu_lookup(env, addr, mop, ra, MMU_DATA_LOAD); - ret = load_atom_4(env, ra, haddr, mop); + ret = load_atom_4(env_cpu(env), ra, haddr, mop); clear_helper_retaddr(); if (mop & MO_BSWAP) { @@ -1078,7 +1078,7 @@ static uint64_t do_ld8_mmu(CPUArchState *env, abi_ptr addr, tcg_debug_assert((mop & MO_SIZE) == MO_64); cpu_req_mo(TCG_MO_LD_LD | TCG_MO_ST_LD); haddr = cpu_mmu_lookup(env, addr, mop, ra, MMU_DATA_LOAD); - ret = load_atom_8(env, ra, haddr, mop); + ret = load_atom_8(env_cpu(env), ra, haddr, mop); clear_helper_retaddr(); if (mop & MO_BSWAP) { @@ -1110,7 +1110,7 @@ static Int128 do_ld16_mmu(CPUArchState *env, abi_ptr addr, tcg_debug_assert((mop & MO_SIZE) == MO_128); cpu_req_mo(TCG_MO_LD_LD | TCG_MO_ST_LD); haddr = cpu_mmu_lookup(env, addr, mop, ra, MMU_DATA_LOAD); - ret = load_atom_16(env, ra, haddr, mop); + ret = load_atom_16(env_cpu(env), ra, haddr, mop); clear_helper_retaddr(); if (mop & MO_BSWAP) { @@ -1175,7 +1175,7 @@ static void do_st2_mmu(CPUArchState *env, abi_ptr addr, uint16_t val, if (mop & MO_BSWAP) { val = bswap16(val); } - store_atom_2(env, ra, haddr, mop, val); + store_atom_2(env_cpu(env), ra, haddr, mop, val); clear_helper_retaddr(); } @@ -1204,7 +1204,7 @@ static void do_st4_mmu(CPUArchState *env, abi_ptr addr, uint32_t val, if (mop & MO_BSWAP) { val = bswap32(val); } - store_atom_4(env, ra, haddr, mop, val); + store_atom_4(env_cpu(env), ra, haddr, mop, val); clear_helper_retaddr(); } @@ -1233,7 +1233,7 @@ static void do_st8_mmu(CPUArchState *env, abi_ptr addr, uint64_t val, if (mop & MO_BSWAP) { val = bswap64(val); } - store_atom_8(env, ra, haddr, mop, val); + store_atom_8(env_cpu(env), ra, haddr, mop, val); clear_helper_retaddr(); } @@ -1262,7 +1262,7 @@ static void do_st16_mmu(CPUArchState *env, abi_ptr addr, Int128 val, if (mop & MO_BSWAP) { val = bswap128(val); } - store_atom_16(env, ra, haddr, mop, val); + store_atom_16(env_cpu(env), ra, haddr, mop, val); clear_helper_retaddr(); } From 623912cc140c8778edb1e8f1e29853b1256866cb Mon Sep 17 00:00:00 2001 From: Anton Johansson Date: Wed, 13 Sep 2023 18:57:20 -0700 Subject: [PATCH 0257/1077] accel/tcg: Remove env_tlb() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The function is no longer used to access the TLB, and has been replaced by cpu->neg.tlb. Signed-off-by: Anton Johansson Message-Id: <20230912153428.17816-9-anjo@rev.ng> Reviewed-by: Richard Henderson Reviewed-by: Philippe Mathieu-Daudé [rth: Merge comment update patch] Signed-off-by: Richard Henderson --- include/exec/cpu-all.h | 11 ----------- tcg/aarch64/tcg-target.c.inc | 2 +- tcg/arm/tcg-target.c.inc | 2 +- 3 files changed, 2 insertions(+), 13 deletions(-) diff --git a/include/exec/cpu-all.h b/include/exec/cpu-all.h index 46e494eeba..17c7420543 100644 --- a/include/exec/cpu-all.h +++ b/include/exec/cpu-all.h @@ -449,15 +449,4 @@ static inline CPUState *env_cpu(CPUArchState *env) return (void *)env - sizeof(CPUState); } -/** - * env_tlb(env) - * @env: The architecture environment - * - * Return the CPUTLB state associated with the environment. - */ -static inline CPUTLB *env_tlb(CPUArchState *env) -{ - return &env_cpu(env)->neg.tlb; -} - #endif /* CPU_ALL_H */ diff --git a/tcg/aarch64/tcg-target.c.inc b/tcg/aarch64/tcg-target.c.inc index 06ea3c7652..69f2daf2c2 100644 --- a/tcg/aarch64/tcg-target.c.inc +++ b/tcg/aarch64/tcg-target.c.inc @@ -1679,7 +1679,7 @@ static TCGLabelQemuLdst *prepare_host_addr(TCGContext *s, HostAddress *h, mask_type = (s->page_bits + s->tlb_dyn_max_bits > 32 ? TCG_TYPE_I64 : TCG_TYPE_I32); - /* Load env_tlb(env)->f[mmu_idx].{mask,table} into {tmp0,tmp1}. */ + /* Load cpu->neg.tlb.f[mmu_idx].{mask,table} into {tmp0,tmp1}. */ QEMU_BUILD_BUG_ON(offsetof(CPUTLBDescFast, mask) != 0); QEMU_BUILD_BUG_ON(offsetof(CPUTLBDescFast, table) != 8); tcg_out_insn(s, 3314, LDP, TCG_REG_TMP0, TCG_REG_TMP1, TCG_AREG0, diff --git a/tcg/arm/tcg-target.c.inc b/tcg/arm/tcg-target.c.inc index b1d56362a7..a2f60106af 100644 --- a/tcg/arm/tcg-target.c.inc +++ b/tcg/arm/tcg-target.c.inc @@ -1420,7 +1420,7 @@ static TCGLabelQemuLdst *prepare_host_addr(TCGContext *s, HostAddress *h, ldst->addrlo_reg = addrlo; ldst->addrhi_reg = addrhi; - /* Load env_tlb(env)->f[mmu_idx].{mask,table} into {r0,r1}. */ + /* Load cpu->neg.tlb.f[mmu_idx].{mask,table} into {r0,r1}. */ QEMU_BUILD_BUG_ON(offsetof(CPUTLBDescFast, mask) != 0); QEMU_BUILD_BUG_ON(offsetof(CPUTLBDescFast, table) != 4); tcg_out_ldrd_8(s, COND_AL, TCG_REG_R0, TCG_AREG0, fast_off); From e20f73fba5240dce86f0b49c01b2c824a0ce9f1f Mon Sep 17 00:00:00 2001 From: Anton Johansson Date: Tue, 12 Sep 2023 17:34:27 +0200 Subject: [PATCH 0258/1077] accel/tcg: Unify user and softmmu do_[st|ld]*_mmu() The prototype of do_[st|ld]*_mmu() is unified between system- and user-mode allowing a large chunk of helper_[st|ld]*() and cpu_[st|ld]*() functions to be expressed in same manner between both modes. These functions will be moved to ldst_common.c.inc in a following commit. Signed-off-by: Anton Johansson Message-Id: <20230912153428.17816-11-anjo@rev.ng> Reviewed-by: Richard Henderson Signed-off-by: Richard Henderson --- accel/tcg/cputlb.c | 16 ++-- accel/tcg/user-exec.c | 183 ++++++++++++++++++++++++------------------ 2 files changed, 117 insertions(+), 82 deletions(-) diff --git a/accel/tcg/cputlb.c b/accel/tcg/cputlb.c index 17fa7a514c..dc43839f87 100644 --- a/accel/tcg/cputlb.c +++ b/accel/tcg/cputlb.c @@ -2922,18 +2922,24 @@ static void do_st_8(CPUState *cpu, MMULookupPageData *p, uint64_t val, } } -void helper_stb_mmu(CPUArchState *env, uint64_t addr, uint32_t val, - MemOpIdx oi, uintptr_t ra) +static void do_st1_mmu(CPUState *cpu, vaddr addr, uint8_t val, + MemOpIdx oi, uintptr_t ra) { MMULookupLocals l; bool crosspage; - tcg_debug_assert((get_memop(oi) & MO_SIZE) == MO_8); cpu_req_mo(TCG_MO_LD_ST | TCG_MO_ST_ST); - crosspage = mmu_lookup(env_cpu(env), addr, oi, ra, MMU_DATA_STORE, &l); + crosspage = mmu_lookup(cpu, addr, oi, ra, MMU_DATA_STORE, &l); tcg_debug_assert(!crosspage); - do_st_1(env_cpu(env), &l.page[0], val, l.mmu_idx, ra); + do_st_1(cpu, &l.page[0], val, l.mmu_idx, ra); +} + +void helper_stb_mmu(CPUArchState *env, uint64_t addr, uint32_t val, + MemOpIdx oi, uintptr_t ra) +{ + tcg_debug_assert((get_memop(oi) & MO_SIZE) == MO_8); + do_st1_mmu(env_cpu(env), addr, val, oi, ra); } static void do_st2_mmu(CPUState *cpu, vaddr addr, uint16_t val, diff --git a/accel/tcg/user-exec.c b/accel/tcg/user-exec.c index f9f5cd1770..a6593d0e0f 100644 --- a/accel/tcg/user-exec.c +++ b/accel/tcg/user-exec.c @@ -941,7 +941,7 @@ void page_reset_target_data(target_ulong start, target_ulong last) { } /* The softmmu versions of these helpers are in cputlb.c. */ -static void *cpu_mmu_lookup(CPUArchState *env, vaddr addr, +static void *cpu_mmu_lookup(CPUState *cpu, vaddr addr, MemOp mop, uintptr_t ra, MMUAccessType type) { int a_bits = get_alignment_bits(mop); @@ -949,25 +949,24 @@ static void *cpu_mmu_lookup(CPUArchState *env, vaddr addr, /* Enforce guest required alignment. */ if (unlikely(addr & ((1 << a_bits) - 1))) { - cpu_loop_exit_sigbus(env_cpu(env), addr, type, ra); + cpu_loop_exit_sigbus(cpu, addr, type, ra); } - ret = g2h(env_cpu(env), addr); + ret = g2h(cpu, addr); set_helper_retaddr(ra); return ret; } #include "ldst_atomicity.c.inc" -static uint8_t do_ld1_mmu(CPUArchState *env, abi_ptr addr, - MemOp mop, uintptr_t ra) +static uint8_t do_ld1_mmu(CPUState *cpu, vaddr addr, MemOpIdx oi, + uintptr_t ra, MMUAccessType access_type) { void *haddr; uint8_t ret; - tcg_debug_assert((mop & MO_SIZE) == MO_8); cpu_req_mo(TCG_MO_LD_LD | TCG_MO_ST_LD); - haddr = cpu_mmu_lookup(env, addr, mop, ra, MMU_DATA_LOAD); + haddr = cpu_mmu_lookup(cpu, addr, get_memop(oi), ra, access_type); ret = ldub_p(haddr); clear_helper_retaddr(); return ret; @@ -976,33 +975,38 @@ static uint8_t do_ld1_mmu(CPUArchState *env, abi_ptr addr, tcg_target_ulong helper_ldub_mmu(CPUArchState *env, uint64_t addr, MemOpIdx oi, uintptr_t ra) { - return do_ld1_mmu(env, addr, get_memop(oi), ra); + tcg_debug_assert((get_memop(oi) & MO_SIZE) == MO_8); + return do_ld1_mmu(env_cpu(env), addr, oi, ra, MMU_DATA_LOAD); } tcg_target_ulong helper_ldsb_mmu(CPUArchState *env, uint64_t addr, MemOpIdx oi, uintptr_t ra) { - return (int8_t)do_ld1_mmu(env, addr, get_memop(oi), ra); + tcg_debug_assert((get_memop(oi) & MO_SIZE) == MO_8); + return (int8_t)do_ld1_mmu(env_cpu(env), addr, oi, ra, MMU_DATA_LOAD); } uint8_t cpu_ldb_mmu(CPUArchState *env, abi_ptr addr, MemOpIdx oi, uintptr_t ra) { - uint8_t ret = do_ld1_mmu(env, addr, get_memop(oi), ra); + uint8_t ret; + + tcg_debug_assert((get_memop(oi) & MO_SIZE) == MO_8); + ret = do_ld1_mmu(env_cpu(env), addr, oi, ra, MMU_DATA_LOAD); qemu_plugin_vcpu_mem_cb(env_cpu(env), addr, oi, QEMU_PLUGIN_MEM_R); return ret; } -static uint16_t do_ld2_mmu(CPUArchState *env, abi_ptr addr, - MemOp mop, uintptr_t ra) +static uint16_t do_ld2_mmu(CPUState *cpu, vaddr addr, MemOpIdx oi, + uintptr_t ra, MMUAccessType access_type) { void *haddr; uint16_t ret; + MemOp mop = get_memop(oi); - tcg_debug_assert((mop & MO_SIZE) == MO_16); cpu_req_mo(TCG_MO_LD_LD | TCG_MO_ST_LD); - haddr = cpu_mmu_lookup(env, addr, mop, ra, MMU_DATA_LOAD); - ret = load_atom_2(env_cpu(env), ra, haddr, mop); + haddr = cpu_mmu_lookup(cpu, addr, mop, ra, access_type); + ret = load_atom_2(cpu, ra, haddr, mop); clear_helper_retaddr(); if (mop & MO_BSWAP) { @@ -1014,33 +1018,38 @@ static uint16_t do_ld2_mmu(CPUArchState *env, abi_ptr addr, tcg_target_ulong helper_lduw_mmu(CPUArchState *env, uint64_t addr, MemOpIdx oi, uintptr_t ra) { - return do_ld2_mmu(env, addr, get_memop(oi), ra); + tcg_debug_assert((get_memop(oi) & MO_SIZE) == MO_16); + return do_ld2_mmu(env_cpu(env), addr, oi, ra, MMU_DATA_LOAD); } tcg_target_ulong helper_ldsw_mmu(CPUArchState *env, uint64_t addr, MemOpIdx oi, uintptr_t ra) { - return (int16_t)do_ld2_mmu(env, addr, get_memop(oi), ra); + tcg_debug_assert((get_memop(oi) & MO_SIZE) == MO_16); + return (int16_t)do_ld2_mmu(env_cpu(env), addr, oi, ra, MMU_DATA_LOAD); } uint16_t cpu_ldw_mmu(CPUArchState *env, abi_ptr addr, MemOpIdx oi, uintptr_t ra) { - uint16_t ret = do_ld2_mmu(env, addr, get_memop(oi), ra); + uint16_t ret; + + tcg_debug_assert((get_memop(oi) & MO_SIZE) == MO_16); + ret = do_ld2_mmu(env_cpu(env), addr, oi, ra, MMU_DATA_LOAD); qemu_plugin_vcpu_mem_cb(env_cpu(env), addr, oi, QEMU_PLUGIN_MEM_R); return ret; } -static uint32_t do_ld4_mmu(CPUArchState *env, abi_ptr addr, - MemOp mop, uintptr_t ra) +static uint32_t do_ld4_mmu(CPUState *cpu, vaddr addr, MemOpIdx oi, + uintptr_t ra, MMUAccessType access_type) { void *haddr; uint32_t ret; + MemOp mop = get_memop(oi); - tcg_debug_assert((mop & MO_SIZE) == MO_32); cpu_req_mo(TCG_MO_LD_LD | TCG_MO_ST_LD); - haddr = cpu_mmu_lookup(env, addr, mop, ra, MMU_DATA_LOAD); - ret = load_atom_4(env_cpu(env), ra, haddr, mop); + haddr = cpu_mmu_lookup(cpu, addr, mop, ra, access_type); + ret = load_atom_4(cpu, ra, haddr, mop); clear_helper_retaddr(); if (mop & MO_BSWAP) { @@ -1052,33 +1061,38 @@ static uint32_t do_ld4_mmu(CPUArchState *env, abi_ptr addr, tcg_target_ulong helper_ldul_mmu(CPUArchState *env, uint64_t addr, MemOpIdx oi, uintptr_t ra) { - return do_ld4_mmu(env, addr, get_memop(oi), ra); + tcg_debug_assert((get_memop(oi) & MO_SIZE) == MO_32); + return do_ld4_mmu(env_cpu(env), addr, oi, ra, MMU_DATA_LOAD); } tcg_target_ulong helper_ldsl_mmu(CPUArchState *env, uint64_t addr, MemOpIdx oi, uintptr_t ra) { - return (int32_t)do_ld4_mmu(env, addr, get_memop(oi), ra); + tcg_debug_assert((get_memop(oi) & MO_SIZE) == MO_32); + return (int32_t)do_ld4_mmu(env_cpu(env), addr, oi, ra, MMU_DATA_LOAD); } uint32_t cpu_ldl_mmu(CPUArchState *env, abi_ptr addr, MemOpIdx oi, uintptr_t ra) { - uint32_t ret = do_ld4_mmu(env, addr, get_memop(oi), ra); + uint32_t ret; + + tcg_debug_assert((get_memop(oi) & MO_SIZE) == MO_32); + ret = do_ld4_mmu(env_cpu(env), addr, oi, ra, MMU_DATA_LOAD); qemu_plugin_vcpu_mem_cb(env_cpu(env), addr, oi, QEMU_PLUGIN_MEM_R); return ret; } -static uint64_t do_ld8_mmu(CPUArchState *env, abi_ptr addr, - MemOp mop, uintptr_t ra) +static uint64_t do_ld8_mmu(CPUState *cpu, vaddr addr, MemOpIdx oi, + uintptr_t ra, MMUAccessType access_type) { void *haddr; uint64_t ret; + MemOp mop = get_memop(oi); - tcg_debug_assert((mop & MO_SIZE) == MO_64); cpu_req_mo(TCG_MO_LD_LD | TCG_MO_ST_LD); - haddr = cpu_mmu_lookup(env, addr, mop, ra, MMU_DATA_LOAD); - ret = load_atom_8(env_cpu(env), ra, haddr, mop); + haddr = cpu_mmu_lookup(cpu, addr, mop, ra, access_type); + ret = load_atom_8(cpu, ra, haddr, mop); clear_helper_retaddr(); if (mop & MO_BSWAP) { @@ -1090,27 +1104,32 @@ static uint64_t do_ld8_mmu(CPUArchState *env, abi_ptr addr, uint64_t helper_ldq_mmu(CPUArchState *env, uint64_t addr, MemOpIdx oi, uintptr_t ra) { - return do_ld8_mmu(env, addr, get_memop(oi), ra); + tcg_debug_assert((get_memop(oi) & MO_SIZE) == MO_64); + return do_ld8_mmu(env_cpu(env), addr, oi, ra, MMU_DATA_LOAD); } uint64_t cpu_ldq_mmu(CPUArchState *env, abi_ptr addr, MemOpIdx oi, uintptr_t ra) { - uint64_t ret = do_ld8_mmu(env, addr, get_memop(oi), ra); + uint64_t ret; + + tcg_debug_assert((get_memop(oi) & MO_SIZE) == MO_64); + ret = do_ld8_mmu(env_cpu(env), addr, oi, ra, MMU_DATA_LOAD); qemu_plugin_vcpu_mem_cb(env_cpu(env), addr, oi, QEMU_PLUGIN_MEM_R); return ret; } -static Int128 do_ld16_mmu(CPUArchState *env, abi_ptr addr, - MemOp mop, uintptr_t ra) +static Int128 do_ld16_mmu(CPUState *cpu, abi_ptr addr, + MemOpIdx oi, uintptr_t ra) { void *haddr; Int128 ret; + MemOp mop = get_memop(oi); tcg_debug_assert((mop & MO_SIZE) == MO_128); cpu_req_mo(TCG_MO_LD_LD | TCG_MO_ST_LD); - haddr = cpu_mmu_lookup(env, addr, mop, ra, MMU_DATA_LOAD); - ret = load_atom_16(env_cpu(env), ra, haddr, mop); + haddr = cpu_mmu_lookup(cpu, addr, mop, ra, MMU_DATA_LOAD); + ret = load_atom_16(cpu, ra, haddr, mop); clear_helper_retaddr(); if (mop & MO_BSWAP) { @@ -1122,7 +1141,7 @@ static Int128 do_ld16_mmu(CPUArchState *env, abi_ptr addr, Int128 helper_ld16_mmu(CPUArchState *env, uint64_t addr, MemOpIdx oi, uintptr_t ra) { - return do_ld16_mmu(env, addr, get_memop(oi), ra); + return do_ld16_mmu(env_cpu(env), addr, get_memop(oi), ra); } Int128 helper_ld_i128(CPUArchState *env, uint64_t addr, MemOpIdx oi) @@ -1133,19 +1152,18 @@ Int128 helper_ld_i128(CPUArchState *env, uint64_t addr, MemOpIdx oi) Int128 cpu_ld16_mmu(CPUArchState *env, abi_ptr addr, MemOpIdx oi, uintptr_t ra) { - Int128 ret = do_ld16_mmu(env, addr, get_memop(oi), ra); + Int128 ret = do_ld16_mmu(env_cpu(env), addr, get_memop(oi), ra); qemu_plugin_vcpu_mem_cb(env_cpu(env), addr, oi, QEMU_PLUGIN_MEM_R); return ret; } -static void do_st1_mmu(CPUArchState *env, abi_ptr addr, uint8_t val, - MemOp mop, uintptr_t ra) +static void do_st1_mmu(CPUState *cpu, vaddr addr, uint8_t val, + MemOpIdx oi, uintptr_t ra) { void *haddr; - tcg_debug_assert((mop & MO_SIZE) == MO_8); cpu_req_mo(TCG_MO_LD_ST | TCG_MO_ST_ST); - haddr = cpu_mmu_lookup(env, addr, mop, ra, MMU_DATA_STORE); + haddr = cpu_mmu_lookup(cpu, addr, get_memop(oi), ra, MMU_DATA_STORE); stb_p(haddr, val); clear_helper_retaddr(); } @@ -1153,134 +1171,145 @@ static void do_st1_mmu(CPUArchState *env, abi_ptr addr, uint8_t val, void helper_stb_mmu(CPUArchState *env, uint64_t addr, uint32_t val, MemOpIdx oi, uintptr_t ra) { - do_st1_mmu(env, addr, val, get_memop(oi), ra); + tcg_debug_assert((get_memop(oi) & MO_SIZE) == MO_8); + do_st1_mmu(env_cpu(env), addr, val, oi, ra); } void cpu_stb_mmu(CPUArchState *env, abi_ptr addr, uint8_t val, MemOpIdx oi, uintptr_t ra) { - do_st1_mmu(env, addr, val, get_memop(oi), ra); + tcg_debug_assert((get_memop(oi) & MO_SIZE) == MO_8); + do_st1_mmu(env_cpu(env), addr, val, oi, ra); qemu_plugin_vcpu_mem_cb(env_cpu(env), addr, oi, QEMU_PLUGIN_MEM_W); } -static void do_st2_mmu(CPUArchState *env, abi_ptr addr, uint16_t val, - MemOp mop, uintptr_t ra) +static void do_st2_mmu(CPUState *cpu, vaddr addr, uint16_t val, + MemOpIdx oi, uintptr_t ra) { void *haddr; + MemOp mop = get_memop(oi); - tcg_debug_assert((mop & MO_SIZE) == MO_16); cpu_req_mo(TCG_MO_LD_ST | TCG_MO_ST_ST); - haddr = cpu_mmu_lookup(env, addr, mop, ra, MMU_DATA_STORE); + haddr = cpu_mmu_lookup(cpu, addr, mop, ra, MMU_DATA_STORE); if (mop & MO_BSWAP) { val = bswap16(val); } - store_atom_2(env_cpu(env), ra, haddr, mop, val); + store_atom_2(cpu, ra, haddr, mop, val); clear_helper_retaddr(); } void helper_stw_mmu(CPUArchState *env, uint64_t addr, uint32_t val, MemOpIdx oi, uintptr_t ra) { - do_st2_mmu(env, addr, val, get_memop(oi), ra); + tcg_debug_assert((get_memop(oi) & MO_SIZE) == MO_16); + do_st2_mmu(env_cpu(env), addr, val, oi, ra); } void cpu_stw_mmu(CPUArchState *env, abi_ptr addr, uint16_t val, MemOpIdx oi, uintptr_t ra) { - do_st2_mmu(env, addr, val, get_memop(oi), ra); + tcg_debug_assert((get_memop(oi) & MO_SIZE) == MO_16); + do_st2_mmu(env_cpu(env), addr, val, oi, ra); qemu_plugin_vcpu_mem_cb(env_cpu(env), addr, oi, QEMU_PLUGIN_MEM_W); } -static void do_st4_mmu(CPUArchState *env, abi_ptr addr, uint32_t val, - MemOp mop, uintptr_t ra) +static void do_st4_mmu(CPUState *cpu, vaddr addr, uint32_t val, + MemOpIdx oi, uintptr_t ra) { void *haddr; + MemOp mop = get_memop(oi); - tcg_debug_assert((mop & MO_SIZE) == MO_32); cpu_req_mo(TCG_MO_LD_ST | TCG_MO_ST_ST); - haddr = cpu_mmu_lookup(env, addr, mop, ra, MMU_DATA_STORE); + haddr = cpu_mmu_lookup(cpu, addr, mop, ra, MMU_DATA_STORE); if (mop & MO_BSWAP) { val = bswap32(val); } - store_atom_4(env_cpu(env), ra, haddr, mop, val); + store_atom_4(cpu, ra, haddr, mop, val); clear_helper_retaddr(); } void helper_stl_mmu(CPUArchState *env, uint64_t addr, uint32_t val, MemOpIdx oi, uintptr_t ra) { - do_st4_mmu(env, addr, val, get_memop(oi), ra); + tcg_debug_assert((get_memop(oi) & MO_SIZE) == MO_32); + do_st4_mmu(env_cpu(env), addr, val, oi, ra); } void cpu_stl_mmu(CPUArchState *env, abi_ptr addr, uint32_t val, MemOpIdx oi, uintptr_t ra) { - do_st4_mmu(env, addr, val, get_memop(oi), ra); + tcg_debug_assert((get_memop(oi) & MO_SIZE) == MO_32); + do_st4_mmu(env_cpu(env), addr, val, oi, ra); qemu_plugin_vcpu_mem_cb(env_cpu(env), addr, oi, QEMU_PLUGIN_MEM_W); } -static void do_st8_mmu(CPUArchState *env, abi_ptr addr, uint64_t val, - MemOp mop, uintptr_t ra) +static void do_st8_mmu(CPUState *cpu, vaddr addr, uint64_t val, + MemOpIdx oi, uintptr_t ra) { void *haddr; + MemOp mop = get_memop(oi); - tcg_debug_assert((mop & MO_SIZE) == MO_64); cpu_req_mo(TCG_MO_LD_ST | TCG_MO_ST_ST); - haddr = cpu_mmu_lookup(env, addr, mop, ra, MMU_DATA_STORE); + haddr = cpu_mmu_lookup(cpu, addr, mop, ra, MMU_DATA_STORE); if (mop & MO_BSWAP) { val = bswap64(val); } - store_atom_8(env_cpu(env), ra, haddr, mop, val); + store_atom_8(cpu, ra, haddr, mop, val); clear_helper_retaddr(); } void helper_stq_mmu(CPUArchState *env, uint64_t addr, uint64_t val, MemOpIdx oi, uintptr_t ra) { - do_st8_mmu(env, addr, val, get_memop(oi), ra); + tcg_debug_assert((get_memop(oi) & MO_SIZE) == MO_64); + do_st8_mmu(env_cpu(env), addr, val, oi, ra); } void cpu_stq_mmu(CPUArchState *env, abi_ptr addr, uint64_t val, MemOpIdx oi, uintptr_t ra) { - do_st8_mmu(env, addr, val, get_memop(oi), ra); + tcg_debug_assert((get_memop(oi) & MO_SIZE) == MO_64); + do_st8_mmu(env_cpu(env), addr, val, oi, ra); qemu_plugin_vcpu_mem_cb(env_cpu(env), addr, oi, QEMU_PLUGIN_MEM_W); } -static void do_st16_mmu(CPUArchState *env, abi_ptr addr, Int128 val, - MemOp mop, uintptr_t ra) +static void do_st16_mmu(CPUState *cpu, vaddr addr, Int128 val, + MemOpIdx oi, uintptr_t ra) { void *haddr; + MemOpIdx mop = get_memop(oi); - tcg_debug_assert((mop & MO_SIZE) == MO_128); cpu_req_mo(TCG_MO_LD_ST | TCG_MO_ST_ST); - haddr = cpu_mmu_lookup(env, addr, mop, ra, MMU_DATA_STORE); + haddr = cpu_mmu_lookup(cpu, addr, mop, ra, MMU_DATA_STORE); if (mop & MO_BSWAP) { val = bswap128(val); } - store_atom_16(env_cpu(env), ra, haddr, mop, val); + store_atom_16(cpu, ra, haddr, mop, val); clear_helper_retaddr(); } void helper_st16_mmu(CPUArchState *env, uint64_t addr, Int128 val, MemOpIdx oi, uintptr_t ra) { - do_st16_mmu(env, addr, val, get_memop(oi), ra); + tcg_debug_assert((get_memop(oi) & MO_SIZE) == MO_128); + do_st16_mmu(env_cpu(env), addr, val, oi, ra); } void helper_st_i128(CPUArchState *env, uint64_t addr, Int128 val, MemOpIdx oi) { + tcg_debug_assert((get_memop(oi) & MO_SIZE) == MO_128); helper_st16_mmu(env, addr, val, oi, GETPC()); } void cpu_st16_mmu(CPUArchState *env, abi_ptr addr, Int128 val, MemOpIdx oi, uintptr_t ra) { - do_st16_mmu(env, addr, val, get_memop(oi), ra); + tcg_debug_assert((get_memop(oi) & MO_SIZE) == MO_128); + do_st16_mmu(env_cpu(env), addr, val, oi, ra); qemu_plugin_vcpu_mem_cb(env_cpu(env), addr, oi, QEMU_PLUGIN_MEM_W); } @@ -1330,7 +1359,7 @@ uint8_t cpu_ldb_code_mmu(CPUArchState *env, abi_ptr addr, void *haddr; uint8_t ret; - haddr = cpu_mmu_lookup(env, addr, oi, ra, MMU_INST_FETCH); + haddr = cpu_mmu_lookup(env_cpu(env), addr, oi, ra, MMU_INST_FETCH); ret = ldub_p(haddr); clear_helper_retaddr(); return ret; @@ -1342,7 +1371,7 @@ uint16_t cpu_ldw_code_mmu(CPUArchState *env, abi_ptr addr, void *haddr; uint16_t ret; - haddr = cpu_mmu_lookup(env, addr, oi, ra, MMU_INST_FETCH); + haddr = cpu_mmu_lookup(env_cpu(env), addr, oi, ra, MMU_INST_FETCH); ret = lduw_p(haddr); clear_helper_retaddr(); if (get_memop(oi) & MO_BSWAP) { @@ -1357,7 +1386,7 @@ uint32_t cpu_ldl_code_mmu(CPUArchState *env, abi_ptr addr, void *haddr; uint32_t ret; - haddr = cpu_mmu_lookup(env, addr, oi, ra, MMU_INST_FETCH); + haddr = cpu_mmu_lookup(env_cpu(env), addr, oi, ra, MMU_INST_FETCH); ret = ldl_p(haddr); clear_helper_retaddr(); if (get_memop(oi) & MO_BSWAP) { @@ -1372,7 +1401,7 @@ uint64_t cpu_ldq_code_mmu(CPUArchState *env, abi_ptr addr, void *haddr; uint64_t ret; - haddr = cpu_mmu_lookup(env, addr, oi, ra, MMU_DATA_LOAD); + haddr = cpu_mmu_lookup(env_cpu(env), addr, oi, ra, MMU_DATA_LOAD); ret = ldq_p(haddr); clear_helper_retaddr(); if (get_memop(oi) & MO_BSWAP) { From 27c46fadf6724b68dcbe275479f86992f33d7c24 Mon Sep 17 00:00:00 2001 From: Anton Johansson Date: Tue, 12 Sep 2023 17:34:28 +0200 Subject: [PATCH 0259/1077] accel/tcg: move ld/st helpers to ldst_common.c.inc A large chunk of ld/st functions are moved from cputlb.c and user-exec.c to ldst_common.c.inc as their implementation is the same between both modes. Eventually, ldst_common.c.inc could be compiled into a separate target-specific compilation unit, and be linked in with the targets. Keeping CPUArchState usage out of cputlb.c (CPUArchState is primarily used to access the mmu index in these functions). Signed-off-by: Anton Johansson Message-Id: <20230912153428.17816-12-anjo@rev.ng> Reviewed-by: Richard Henderson Signed-off-by: Richard Henderson --- accel/tcg/cputlb.c | 214 ---------------------------------- accel/tcg/ldst_common.c.inc | 225 ++++++++++++++++++++++++++++++++++++ accel/tcg/user-exec.c | 193 ------------------------------- 3 files changed, 225 insertions(+), 407 deletions(-) diff --git a/accel/tcg/cputlb.c b/accel/tcg/cputlb.c index dc43839f87..c53f434c88 100644 --- a/accel/tcg/cputlb.c +++ b/accel/tcg/cputlb.c @@ -2390,13 +2390,6 @@ static uint8_t do_ld1_mmu(CPUState *cpu, vaddr addr, MemOpIdx oi, return do_ld_1(cpu, &l.page[0], l.mmu_idx, access_type, ra); } -tcg_target_ulong helper_ldub_mmu(CPUArchState *env, uint64_t addr, - MemOpIdx oi, uintptr_t retaddr) -{ - tcg_debug_assert((get_memop(oi) & MO_SIZE) == MO_8); - return do_ld1_mmu(env_cpu(env), addr, oi, retaddr, MMU_DATA_LOAD); -} - static uint16_t do_ld2_mmu(CPUState *cpu, vaddr addr, MemOpIdx oi, uintptr_t ra, MMUAccessType access_type) { @@ -2422,13 +2415,6 @@ static uint16_t do_ld2_mmu(CPUState *cpu, vaddr addr, MemOpIdx oi, return ret; } -tcg_target_ulong helper_lduw_mmu(CPUArchState *env, uint64_t addr, - MemOpIdx oi, uintptr_t retaddr) -{ - tcg_debug_assert((get_memop(oi) & MO_SIZE) == MO_16); - return do_ld2_mmu(env_cpu(env), addr, oi, retaddr, MMU_DATA_LOAD); -} - static uint32_t do_ld4_mmu(CPUState *cpu, vaddr addr, MemOpIdx oi, uintptr_t ra, MMUAccessType access_type) { @@ -2450,13 +2436,6 @@ static uint32_t do_ld4_mmu(CPUState *cpu, vaddr addr, MemOpIdx oi, return ret; } -tcg_target_ulong helper_ldul_mmu(CPUArchState *env, uint64_t addr, - MemOpIdx oi, uintptr_t retaddr) -{ - tcg_debug_assert((get_memop(oi) & MO_SIZE) == MO_32); - return do_ld4_mmu(env_cpu(env), addr, oi, retaddr, MMU_DATA_LOAD); -} - static uint64_t do_ld8_mmu(CPUState *cpu, vaddr addr, MemOpIdx oi, uintptr_t ra, MMUAccessType access_type) { @@ -2478,36 +2457,6 @@ static uint64_t do_ld8_mmu(CPUState *cpu, vaddr addr, MemOpIdx oi, return ret; } -uint64_t helper_ldq_mmu(CPUArchState *env, uint64_t addr, - MemOpIdx oi, uintptr_t retaddr) -{ - tcg_debug_assert((get_memop(oi) & MO_SIZE) == MO_64); - return do_ld8_mmu(env_cpu(env), addr, oi, retaddr, MMU_DATA_LOAD); -} - -/* - * Provide signed versions of the load routines as well. We can of course - * avoid this for 64-bit data, or for 32-bit data on 32-bit host. - */ - -tcg_target_ulong helper_ldsb_mmu(CPUArchState *env, uint64_t addr, - MemOpIdx oi, uintptr_t retaddr) -{ - return (int8_t)helper_ldub_mmu(env, addr, oi, retaddr); -} - -tcg_target_ulong helper_ldsw_mmu(CPUArchState *env, uint64_t addr, - MemOpIdx oi, uintptr_t retaddr) -{ - return (int16_t)helper_lduw_mmu(env, addr, oi, retaddr); -} - -tcg_target_ulong helper_ldsl_mmu(CPUArchState *env, uint64_t addr, - MemOpIdx oi, uintptr_t retaddr) -{ - return (int32_t)helper_ldul_mmu(env, addr, oi, retaddr); -} - static Int128 do_ld16_mmu(CPUState *cpu, vaddr addr, MemOpIdx oi, uintptr_t ra) { @@ -2569,81 +2518,6 @@ static Int128 do_ld16_mmu(CPUState *cpu, vaddr addr, return ret; } -Int128 helper_ld16_mmu(CPUArchState *env, uint64_t addr, - uint32_t oi, uintptr_t retaddr) -{ - tcg_debug_assert((get_memop(oi) & MO_SIZE) == MO_128); - return do_ld16_mmu(env_cpu(env), addr, oi, retaddr); -} - -Int128 helper_ld_i128(CPUArchState *env, uint64_t addr, uint32_t oi) -{ - return helper_ld16_mmu(env, addr, oi, GETPC()); -} - -/* - * Load helpers for cpu_ldst.h. - */ - -static void plugin_load_cb(CPUArchState *env, abi_ptr addr, MemOpIdx oi) -{ - qemu_plugin_vcpu_mem_cb(env_cpu(env), addr, oi, QEMU_PLUGIN_MEM_R); -} - -uint8_t cpu_ldb_mmu(CPUArchState *env, abi_ptr addr, MemOpIdx oi, uintptr_t ra) -{ - uint8_t ret; - - tcg_debug_assert((get_memop(oi) & MO_SIZE) == MO_UB); - ret = do_ld1_mmu(env_cpu(env), addr, oi, ra, MMU_DATA_LOAD); - plugin_load_cb(env, addr, oi); - return ret; -} - -uint16_t cpu_ldw_mmu(CPUArchState *env, abi_ptr addr, - MemOpIdx oi, uintptr_t ra) -{ - uint16_t ret; - - tcg_debug_assert((get_memop(oi) & MO_SIZE) == MO_16); - ret = do_ld2_mmu(env_cpu(env), addr, oi, ra, MMU_DATA_LOAD); - plugin_load_cb(env, addr, oi); - return ret; -} - -uint32_t cpu_ldl_mmu(CPUArchState *env, abi_ptr addr, - MemOpIdx oi, uintptr_t ra) -{ - uint32_t ret; - - tcg_debug_assert((get_memop(oi) & MO_SIZE) == MO_32); - ret = do_ld4_mmu(env_cpu(env), addr, oi, ra, MMU_DATA_LOAD); - plugin_load_cb(env, addr, oi); - return ret; -} - -uint64_t cpu_ldq_mmu(CPUArchState *env, abi_ptr addr, - MemOpIdx oi, uintptr_t ra) -{ - uint64_t ret; - - tcg_debug_assert((get_memop(oi) & MO_SIZE) == MO_64); - ret = do_ld8_mmu(env_cpu(env), addr, oi, ra, MMU_DATA_LOAD); - plugin_load_cb(env, addr, oi); - return ret; -} - -Int128 cpu_ld16_mmu(CPUArchState *env, abi_ptr addr, - MemOpIdx oi, uintptr_t ra) -{ - Int128 ret; - - tcg_debug_assert((get_memop(oi) & MO_SIZE) == MO_128); - ret = do_ld16_mmu(env_cpu(env), addr, oi, ra); - plugin_load_cb(env, addr, oi); - return ret; -} - /* * Store Helpers */ @@ -2935,13 +2809,6 @@ static void do_st1_mmu(CPUState *cpu, vaddr addr, uint8_t val, do_st_1(cpu, &l.page[0], val, l.mmu_idx, ra); } -void helper_stb_mmu(CPUArchState *env, uint64_t addr, uint32_t val, - MemOpIdx oi, uintptr_t ra) -{ - tcg_debug_assert((get_memop(oi) & MO_SIZE) == MO_8); - do_st1_mmu(env_cpu(env), addr, val, oi, ra); -} - static void do_st2_mmu(CPUState *cpu, vaddr addr, uint16_t val, MemOpIdx oi, uintptr_t ra) { @@ -2965,13 +2832,6 @@ static void do_st2_mmu(CPUState *cpu, vaddr addr, uint16_t val, do_st_1(cpu, &l.page[1], b, l.mmu_idx, ra); } -void helper_stw_mmu(CPUArchState *env, uint64_t addr, uint32_t val, - MemOpIdx oi, uintptr_t retaddr) -{ - tcg_debug_assert((get_memop(oi) & MO_SIZE) == MO_16); - do_st2_mmu(env_cpu(env), addr, val, oi, retaddr); -} - static void do_st4_mmu(CPUState *cpu, vaddr addr, uint32_t val, MemOpIdx oi, uintptr_t ra) { @@ -2993,13 +2853,6 @@ static void do_st4_mmu(CPUState *cpu, vaddr addr, uint32_t val, (void) do_st_leN(cpu, &l.page[1], val, l.mmu_idx, l.memop, ra); } -void helper_stl_mmu(CPUArchState *env, uint64_t addr, uint32_t val, - MemOpIdx oi, uintptr_t retaddr) -{ - tcg_debug_assert((get_memop(oi) & MO_SIZE) == MO_32); - do_st4_mmu(env_cpu(env), addr, val, oi, retaddr); -} - static void do_st8_mmu(CPUState *cpu, vaddr addr, uint64_t val, MemOpIdx oi, uintptr_t ra) { @@ -3021,13 +2874,6 @@ static void do_st8_mmu(CPUState *cpu, vaddr addr, uint64_t val, (void) do_st_leN(cpu, &l.page[1], val, l.mmu_idx, l.memop, ra); } -void helper_stq_mmu(CPUArchState *env, uint64_t addr, uint64_t val, - MemOpIdx oi, uintptr_t retaddr) -{ - tcg_debug_assert((get_memop(oi) & MO_SIZE) == MO_64); - do_st8_mmu(env_cpu(env), addr, val, oi, retaddr); -} - static void do_st16_mmu(CPUState *cpu, vaddr addr, Int128 val, MemOpIdx oi, uintptr_t ra) { @@ -3086,66 +2932,6 @@ static void do_st16_mmu(CPUState *cpu, vaddr addr, Int128 val, } } -void helper_st16_mmu(CPUArchState *env, uint64_t addr, Int128 val, - MemOpIdx oi, uintptr_t retaddr) -{ - tcg_debug_assert((get_memop(oi) & MO_SIZE) == MO_128); - do_st16_mmu(env_cpu(env), addr, val, oi, retaddr); -} - -void helper_st_i128(CPUArchState *env, uint64_t addr, Int128 val, MemOpIdx oi) -{ - helper_st16_mmu(env, addr, val, oi, GETPC()); -} - -/* - * Store Helpers for cpu_ldst.h - */ - -static void plugin_store_cb(CPUArchState *env, abi_ptr addr, MemOpIdx oi) -{ - qemu_plugin_vcpu_mem_cb(env_cpu(env), addr, oi, QEMU_PLUGIN_MEM_W); -} - -void cpu_stb_mmu(CPUArchState *env, abi_ptr addr, uint8_t val, - MemOpIdx oi, uintptr_t retaddr) -{ - helper_stb_mmu(env, addr, val, oi, retaddr); - plugin_store_cb(env, addr, oi); -} - -void cpu_stw_mmu(CPUArchState *env, abi_ptr addr, uint16_t val, - MemOpIdx oi, uintptr_t retaddr) -{ - tcg_debug_assert((get_memop(oi) & MO_SIZE) == MO_16); - do_st2_mmu(env_cpu(env), addr, val, oi, retaddr); - plugin_store_cb(env, addr, oi); -} - -void cpu_stl_mmu(CPUArchState *env, abi_ptr addr, uint32_t val, - MemOpIdx oi, uintptr_t retaddr) -{ - tcg_debug_assert((get_memop(oi) & MO_SIZE) == MO_32); - do_st4_mmu(env_cpu(env), addr, val, oi, retaddr); - plugin_store_cb(env, addr, oi); -} - -void cpu_stq_mmu(CPUArchState *env, abi_ptr addr, uint64_t val, - MemOpIdx oi, uintptr_t retaddr) -{ - tcg_debug_assert((get_memop(oi) & MO_SIZE) == MO_64); - do_st8_mmu(env_cpu(env), addr, val, oi, retaddr); - plugin_store_cb(env, addr, oi); -} - -void cpu_st16_mmu(CPUArchState *env, abi_ptr addr, Int128 val, - MemOpIdx oi, uintptr_t retaddr) -{ - tcg_debug_assert((get_memop(oi) & MO_SIZE) == MO_128); - do_st16_mmu(env_cpu(env), addr, val, oi, retaddr); - plugin_store_cb(env, addr, oi); -} - #include "ldst_common.c.inc" /* diff --git a/accel/tcg/ldst_common.c.inc b/accel/tcg/ldst_common.c.inc index 5f8144b33a..44833513fb 100644 --- a/accel/tcg/ldst_common.c.inc +++ b/accel/tcg/ldst_common.c.inc @@ -8,6 +8,231 @@ * This work is licensed under the terms of the GNU GPL, version 2 or later. * See the COPYING file in the top-level directory. */ +/* + * Load helpers for tcg-ldst.h + */ + +tcg_target_ulong helper_ldub_mmu(CPUArchState *env, uint64_t addr, + MemOpIdx oi, uintptr_t retaddr) +{ + tcg_debug_assert((get_memop(oi) & MO_SIZE) == MO_8); + return do_ld1_mmu(env_cpu(env), addr, oi, retaddr, MMU_DATA_LOAD); +} + +tcg_target_ulong helper_lduw_mmu(CPUArchState *env, uint64_t addr, + MemOpIdx oi, uintptr_t retaddr) +{ + tcg_debug_assert((get_memop(oi) & MO_SIZE) == MO_16); + return do_ld2_mmu(env_cpu(env), addr, oi, retaddr, MMU_DATA_LOAD); +} + +tcg_target_ulong helper_ldul_mmu(CPUArchState *env, uint64_t addr, + MemOpIdx oi, uintptr_t retaddr) +{ + tcg_debug_assert((get_memop(oi) & MO_SIZE) == MO_32); + return do_ld4_mmu(env_cpu(env), addr, oi, retaddr, MMU_DATA_LOAD); +} + +uint64_t helper_ldq_mmu(CPUArchState *env, uint64_t addr, + MemOpIdx oi, uintptr_t retaddr) +{ + tcg_debug_assert((get_memop(oi) & MO_SIZE) == MO_64); + return do_ld8_mmu(env_cpu(env), addr, oi, retaddr, MMU_DATA_LOAD); +} + +/* + * Provide signed versions of the load routines as well. We can of course + * avoid this for 64-bit data, or for 32-bit data on 32-bit host. + */ + +tcg_target_ulong helper_ldsb_mmu(CPUArchState *env, uint64_t addr, + MemOpIdx oi, uintptr_t retaddr) +{ + return (int8_t)helper_ldub_mmu(env, addr, oi, retaddr); +} + +tcg_target_ulong helper_ldsw_mmu(CPUArchState *env, uint64_t addr, + MemOpIdx oi, uintptr_t retaddr) +{ + return (int16_t)helper_lduw_mmu(env, addr, oi, retaddr); +} + +tcg_target_ulong helper_ldsl_mmu(CPUArchState *env, uint64_t addr, + MemOpIdx oi, uintptr_t retaddr) +{ + return (int32_t)helper_ldul_mmu(env, addr, oi, retaddr); +} + +Int128 helper_ld16_mmu(CPUArchState *env, uint64_t addr, + MemOpIdx oi, uintptr_t retaddr) +{ + tcg_debug_assert((get_memop(oi) & MO_SIZE) == MO_128); + return do_ld16_mmu(env_cpu(env), addr, oi, retaddr); +} + +Int128 helper_ld_i128(CPUArchState *env, uint64_t addr, uint32_t oi) +{ + return helper_ld16_mmu(env, addr, oi, GETPC()); +} + +/* + * Store helpers for tcg-ldst.h + */ + +void helper_stb_mmu(CPUArchState *env, uint64_t addr, uint32_t val, + MemOpIdx oi, uintptr_t ra) +{ + tcg_debug_assert((get_memop(oi) & MO_SIZE) == MO_8); + do_st1_mmu(env_cpu(env), addr, val, oi, ra); +} + +void helper_stw_mmu(CPUArchState *env, uint64_t addr, uint32_t val, + MemOpIdx oi, uintptr_t retaddr) +{ + tcg_debug_assert((get_memop(oi) & MO_SIZE) == MO_16); + do_st2_mmu(env_cpu(env), addr, val, oi, retaddr); +} + +void helper_stl_mmu(CPUArchState *env, uint64_t addr, uint32_t val, + MemOpIdx oi, uintptr_t retaddr) +{ + tcg_debug_assert((get_memop(oi) & MO_SIZE) == MO_32); + do_st4_mmu(env_cpu(env), addr, val, oi, retaddr); +} + +void helper_stq_mmu(CPUArchState *env, uint64_t addr, uint64_t val, + MemOpIdx oi, uintptr_t retaddr) +{ + tcg_debug_assert((get_memop(oi) & MO_SIZE) == MO_64); + do_st8_mmu(env_cpu(env), addr, val, oi, retaddr); +} + +void helper_st16_mmu(CPUArchState *env, uint64_t addr, Int128 val, + MemOpIdx oi, uintptr_t retaddr) +{ + tcg_debug_assert((get_memop(oi) & MO_SIZE) == MO_128); + do_st16_mmu(env_cpu(env), addr, val, oi, retaddr); +} + +void helper_st_i128(CPUArchState *env, uint64_t addr, Int128 val, MemOpIdx oi) +{ + helper_st16_mmu(env, addr, val, oi, GETPC()); +} + +/* + * Load helpers for cpu_ldst.h + */ + +static void plugin_load_cb(CPUArchState *env, abi_ptr addr, MemOpIdx oi) +{ + qemu_plugin_vcpu_mem_cb(env_cpu(env), addr, oi, QEMU_PLUGIN_MEM_R); +} + +uint8_t cpu_ldb_mmu(CPUArchState *env, abi_ptr addr, MemOpIdx oi, uintptr_t ra) +{ + uint8_t ret; + + tcg_debug_assert((get_memop(oi) & MO_SIZE) == MO_UB); + ret = do_ld1_mmu(env_cpu(env), addr, oi, ra, MMU_DATA_LOAD); + plugin_load_cb(env, addr, oi); + return ret; +} + +uint16_t cpu_ldw_mmu(CPUArchState *env, abi_ptr addr, + MemOpIdx oi, uintptr_t ra) +{ + uint16_t ret; + + tcg_debug_assert((get_memop(oi) & MO_SIZE) == MO_16); + ret = do_ld2_mmu(env_cpu(env), addr, oi, ra, MMU_DATA_LOAD); + plugin_load_cb(env, addr, oi); + return ret; +} + +uint32_t cpu_ldl_mmu(CPUArchState *env, abi_ptr addr, + MemOpIdx oi, uintptr_t ra) +{ + uint32_t ret; + + tcg_debug_assert((get_memop(oi) & MO_SIZE) == MO_32); + ret = do_ld4_mmu(env_cpu(env), addr, oi, ra, MMU_DATA_LOAD); + plugin_load_cb(env, addr, oi); + return ret; +} + +uint64_t cpu_ldq_mmu(CPUArchState *env, abi_ptr addr, + MemOpIdx oi, uintptr_t ra) +{ + uint64_t ret; + + tcg_debug_assert((get_memop(oi) & MO_SIZE) == MO_64); + ret = do_ld8_mmu(env_cpu(env), addr, oi, ra, MMU_DATA_LOAD); + plugin_load_cb(env, addr, oi); + return ret; +} + +Int128 cpu_ld16_mmu(CPUArchState *env, abi_ptr addr, + MemOpIdx oi, uintptr_t ra) +{ + Int128 ret; + + tcg_debug_assert((get_memop(oi) & MO_SIZE) == MO_128); + ret = do_ld16_mmu(env_cpu(env), addr, oi, ra); + plugin_load_cb(env, addr, oi); + return ret; +} + +/* + * Store helpers for cpu_ldst.h + */ + +static void plugin_store_cb(CPUArchState *env, abi_ptr addr, MemOpIdx oi) +{ + qemu_plugin_vcpu_mem_cb(env_cpu(env), addr, oi, QEMU_PLUGIN_MEM_W); +} + +void cpu_stb_mmu(CPUArchState *env, abi_ptr addr, uint8_t val, + MemOpIdx oi, uintptr_t retaddr) +{ + helper_stb_mmu(env, addr, val, oi, retaddr); + plugin_store_cb(env, addr, oi); +} + +void cpu_stw_mmu(CPUArchState *env, abi_ptr addr, uint16_t val, + MemOpIdx oi, uintptr_t retaddr) +{ + tcg_debug_assert((get_memop(oi) & MO_SIZE) == MO_16); + do_st2_mmu(env_cpu(env), addr, val, oi, retaddr); + plugin_store_cb(env, addr, oi); +} + +void cpu_stl_mmu(CPUArchState *env, abi_ptr addr, uint32_t val, + MemOpIdx oi, uintptr_t retaddr) +{ + tcg_debug_assert((get_memop(oi) & MO_SIZE) == MO_32); + do_st4_mmu(env_cpu(env), addr, val, oi, retaddr); + plugin_store_cb(env, addr, oi); +} + +void cpu_stq_mmu(CPUArchState *env, abi_ptr addr, uint64_t val, + MemOpIdx oi, uintptr_t retaddr) +{ + tcg_debug_assert((get_memop(oi) & MO_SIZE) == MO_64); + do_st8_mmu(env_cpu(env), addr, val, oi, retaddr); + plugin_store_cb(env, addr, oi); +} + +void cpu_st16_mmu(CPUArchState *env, abi_ptr addr, Int128 val, + MemOpIdx oi, uintptr_t retaddr) +{ + tcg_debug_assert((get_memop(oi) & MO_SIZE) == MO_128); + do_st16_mmu(env_cpu(env), addr, val, oi, retaddr); + plugin_store_cb(env, addr, oi); +} + +/* + * Wrappers of the above + */ uint32_t cpu_ldub_mmuidx_ra(CPUArchState *env, abi_ptr addr, int mmu_idx, uintptr_t ra) diff --git a/accel/tcg/user-exec.c b/accel/tcg/user-exec.c index a6593d0e0f..17f9aff0cf 100644 --- a/accel/tcg/user-exec.c +++ b/accel/tcg/user-exec.c @@ -972,31 +972,6 @@ static uint8_t do_ld1_mmu(CPUState *cpu, vaddr addr, MemOpIdx oi, return ret; } -tcg_target_ulong helper_ldub_mmu(CPUArchState *env, uint64_t addr, - MemOpIdx oi, uintptr_t ra) -{ - tcg_debug_assert((get_memop(oi) & MO_SIZE) == MO_8); - return do_ld1_mmu(env_cpu(env), addr, oi, ra, MMU_DATA_LOAD); -} - -tcg_target_ulong helper_ldsb_mmu(CPUArchState *env, uint64_t addr, - MemOpIdx oi, uintptr_t ra) -{ - tcg_debug_assert((get_memop(oi) & MO_SIZE) == MO_8); - return (int8_t)do_ld1_mmu(env_cpu(env), addr, oi, ra, MMU_DATA_LOAD); -} - -uint8_t cpu_ldb_mmu(CPUArchState *env, abi_ptr addr, - MemOpIdx oi, uintptr_t ra) -{ - uint8_t ret; - - tcg_debug_assert((get_memop(oi) & MO_SIZE) == MO_8); - ret = do_ld1_mmu(env_cpu(env), addr, oi, ra, MMU_DATA_LOAD); - qemu_plugin_vcpu_mem_cb(env_cpu(env), addr, oi, QEMU_PLUGIN_MEM_R); - return ret; -} - static uint16_t do_ld2_mmu(CPUState *cpu, vaddr addr, MemOpIdx oi, uintptr_t ra, MMUAccessType access_type) { @@ -1015,31 +990,6 @@ static uint16_t do_ld2_mmu(CPUState *cpu, vaddr addr, MemOpIdx oi, return ret; } -tcg_target_ulong helper_lduw_mmu(CPUArchState *env, uint64_t addr, - MemOpIdx oi, uintptr_t ra) -{ - tcg_debug_assert((get_memop(oi) & MO_SIZE) == MO_16); - return do_ld2_mmu(env_cpu(env), addr, oi, ra, MMU_DATA_LOAD); -} - -tcg_target_ulong helper_ldsw_mmu(CPUArchState *env, uint64_t addr, - MemOpIdx oi, uintptr_t ra) -{ - tcg_debug_assert((get_memop(oi) & MO_SIZE) == MO_16); - return (int16_t)do_ld2_mmu(env_cpu(env), addr, oi, ra, MMU_DATA_LOAD); -} - -uint16_t cpu_ldw_mmu(CPUArchState *env, abi_ptr addr, - MemOpIdx oi, uintptr_t ra) -{ - uint16_t ret; - - tcg_debug_assert((get_memop(oi) & MO_SIZE) == MO_16); - ret = do_ld2_mmu(env_cpu(env), addr, oi, ra, MMU_DATA_LOAD); - qemu_plugin_vcpu_mem_cb(env_cpu(env), addr, oi, QEMU_PLUGIN_MEM_R); - return ret; -} - static uint32_t do_ld4_mmu(CPUState *cpu, vaddr addr, MemOpIdx oi, uintptr_t ra, MMUAccessType access_type) { @@ -1058,31 +1008,6 @@ static uint32_t do_ld4_mmu(CPUState *cpu, vaddr addr, MemOpIdx oi, return ret; } -tcg_target_ulong helper_ldul_mmu(CPUArchState *env, uint64_t addr, - MemOpIdx oi, uintptr_t ra) -{ - tcg_debug_assert((get_memop(oi) & MO_SIZE) == MO_32); - return do_ld4_mmu(env_cpu(env), addr, oi, ra, MMU_DATA_LOAD); -} - -tcg_target_ulong helper_ldsl_mmu(CPUArchState *env, uint64_t addr, - MemOpIdx oi, uintptr_t ra) -{ - tcg_debug_assert((get_memop(oi) & MO_SIZE) == MO_32); - return (int32_t)do_ld4_mmu(env_cpu(env), addr, oi, ra, MMU_DATA_LOAD); -} - -uint32_t cpu_ldl_mmu(CPUArchState *env, abi_ptr addr, - MemOpIdx oi, uintptr_t ra) -{ - uint32_t ret; - - tcg_debug_assert((get_memop(oi) & MO_SIZE) == MO_32); - ret = do_ld4_mmu(env_cpu(env), addr, oi, ra, MMU_DATA_LOAD); - qemu_plugin_vcpu_mem_cb(env_cpu(env), addr, oi, QEMU_PLUGIN_MEM_R); - return ret; -} - static uint64_t do_ld8_mmu(CPUState *cpu, vaddr addr, MemOpIdx oi, uintptr_t ra, MMUAccessType access_type) { @@ -1101,24 +1026,6 @@ static uint64_t do_ld8_mmu(CPUState *cpu, vaddr addr, MemOpIdx oi, return ret; } -uint64_t helper_ldq_mmu(CPUArchState *env, uint64_t addr, - MemOpIdx oi, uintptr_t ra) -{ - tcg_debug_assert((get_memop(oi) & MO_SIZE) == MO_64); - return do_ld8_mmu(env_cpu(env), addr, oi, ra, MMU_DATA_LOAD); -} - -uint64_t cpu_ldq_mmu(CPUArchState *env, abi_ptr addr, - MemOpIdx oi, uintptr_t ra) -{ - uint64_t ret; - - tcg_debug_assert((get_memop(oi) & MO_SIZE) == MO_64); - ret = do_ld8_mmu(env_cpu(env), addr, oi, ra, MMU_DATA_LOAD); - qemu_plugin_vcpu_mem_cb(env_cpu(env), addr, oi, QEMU_PLUGIN_MEM_R); - return ret; -} - static Int128 do_ld16_mmu(CPUState *cpu, abi_ptr addr, MemOpIdx oi, uintptr_t ra) { @@ -1138,25 +1045,6 @@ static Int128 do_ld16_mmu(CPUState *cpu, abi_ptr addr, return ret; } -Int128 helper_ld16_mmu(CPUArchState *env, uint64_t addr, - MemOpIdx oi, uintptr_t ra) -{ - return do_ld16_mmu(env_cpu(env), addr, get_memop(oi), ra); -} - -Int128 helper_ld_i128(CPUArchState *env, uint64_t addr, MemOpIdx oi) -{ - return helper_ld16_mmu(env, addr, oi, GETPC()); -} - -Int128 cpu_ld16_mmu(CPUArchState *env, abi_ptr addr, - MemOpIdx oi, uintptr_t ra) -{ - Int128 ret = do_ld16_mmu(env_cpu(env), addr, get_memop(oi), ra); - qemu_plugin_vcpu_mem_cb(env_cpu(env), addr, oi, QEMU_PLUGIN_MEM_R); - return ret; -} - static void do_st1_mmu(CPUState *cpu, vaddr addr, uint8_t val, MemOpIdx oi, uintptr_t ra) { @@ -1168,21 +1056,6 @@ static void do_st1_mmu(CPUState *cpu, vaddr addr, uint8_t val, clear_helper_retaddr(); } -void helper_stb_mmu(CPUArchState *env, uint64_t addr, uint32_t val, - MemOpIdx oi, uintptr_t ra) -{ - tcg_debug_assert((get_memop(oi) & MO_SIZE) == MO_8); - do_st1_mmu(env_cpu(env), addr, val, oi, ra); -} - -void cpu_stb_mmu(CPUArchState *env, abi_ptr addr, uint8_t val, - MemOpIdx oi, uintptr_t ra) -{ - tcg_debug_assert((get_memop(oi) & MO_SIZE) == MO_8); - do_st1_mmu(env_cpu(env), addr, val, oi, ra); - qemu_plugin_vcpu_mem_cb(env_cpu(env), addr, oi, QEMU_PLUGIN_MEM_W); -} - static void do_st2_mmu(CPUState *cpu, vaddr addr, uint16_t val, MemOpIdx oi, uintptr_t ra) { @@ -1199,21 +1072,6 @@ static void do_st2_mmu(CPUState *cpu, vaddr addr, uint16_t val, clear_helper_retaddr(); } -void helper_stw_mmu(CPUArchState *env, uint64_t addr, uint32_t val, - MemOpIdx oi, uintptr_t ra) -{ - tcg_debug_assert((get_memop(oi) & MO_SIZE) == MO_16); - do_st2_mmu(env_cpu(env), addr, val, oi, ra); -} - -void cpu_stw_mmu(CPUArchState *env, abi_ptr addr, uint16_t val, - MemOpIdx oi, uintptr_t ra) -{ - tcg_debug_assert((get_memop(oi) & MO_SIZE) == MO_16); - do_st2_mmu(env_cpu(env), addr, val, oi, ra); - qemu_plugin_vcpu_mem_cb(env_cpu(env), addr, oi, QEMU_PLUGIN_MEM_W); -} - static void do_st4_mmu(CPUState *cpu, vaddr addr, uint32_t val, MemOpIdx oi, uintptr_t ra) { @@ -1230,21 +1088,6 @@ static void do_st4_mmu(CPUState *cpu, vaddr addr, uint32_t val, clear_helper_retaddr(); } -void helper_stl_mmu(CPUArchState *env, uint64_t addr, uint32_t val, - MemOpIdx oi, uintptr_t ra) -{ - tcg_debug_assert((get_memop(oi) & MO_SIZE) == MO_32); - do_st4_mmu(env_cpu(env), addr, val, oi, ra); -} - -void cpu_stl_mmu(CPUArchState *env, abi_ptr addr, uint32_t val, - MemOpIdx oi, uintptr_t ra) -{ - tcg_debug_assert((get_memop(oi) & MO_SIZE) == MO_32); - do_st4_mmu(env_cpu(env), addr, val, oi, ra); - qemu_plugin_vcpu_mem_cb(env_cpu(env), addr, oi, QEMU_PLUGIN_MEM_W); -} - static void do_st8_mmu(CPUState *cpu, vaddr addr, uint64_t val, MemOpIdx oi, uintptr_t ra) { @@ -1261,21 +1104,6 @@ static void do_st8_mmu(CPUState *cpu, vaddr addr, uint64_t val, clear_helper_retaddr(); } -void helper_stq_mmu(CPUArchState *env, uint64_t addr, uint64_t val, - MemOpIdx oi, uintptr_t ra) -{ - tcg_debug_assert((get_memop(oi) & MO_SIZE) == MO_64); - do_st8_mmu(env_cpu(env), addr, val, oi, ra); -} - -void cpu_stq_mmu(CPUArchState *env, abi_ptr addr, uint64_t val, - MemOpIdx oi, uintptr_t ra) -{ - tcg_debug_assert((get_memop(oi) & MO_SIZE) == MO_64); - do_st8_mmu(env_cpu(env), addr, val, oi, ra); - qemu_plugin_vcpu_mem_cb(env_cpu(env), addr, oi, QEMU_PLUGIN_MEM_W); -} - static void do_st16_mmu(CPUState *cpu, vaddr addr, Int128 val, MemOpIdx oi, uintptr_t ra) { @@ -1292,27 +1120,6 @@ static void do_st16_mmu(CPUState *cpu, vaddr addr, Int128 val, clear_helper_retaddr(); } -void helper_st16_mmu(CPUArchState *env, uint64_t addr, Int128 val, - MemOpIdx oi, uintptr_t ra) -{ - tcg_debug_assert((get_memop(oi) & MO_SIZE) == MO_128); - do_st16_mmu(env_cpu(env), addr, val, oi, ra); -} - -void helper_st_i128(CPUArchState *env, uint64_t addr, Int128 val, MemOpIdx oi) -{ - tcg_debug_assert((get_memop(oi) & MO_SIZE) == MO_128); - helper_st16_mmu(env, addr, val, oi, GETPC()); -} - -void cpu_st16_mmu(CPUArchState *env, abi_ptr addr, - Int128 val, MemOpIdx oi, uintptr_t ra) -{ - tcg_debug_assert((get_memop(oi) & MO_SIZE) == MO_128); - do_st16_mmu(env_cpu(env), addr, val, oi, ra); - qemu_plugin_vcpu_mem_cb(env_cpu(env), addr, oi, QEMU_PLUGIN_MEM_W); -} - uint32_t cpu_ldub_code(CPUArchState *env, abi_ptr ptr) { uint32_t ret; From 65b074daa03cded3cc2c36e4eba7afc5b406b962 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Thu, 14 Sep 2023 20:57:07 +0200 Subject: [PATCH 0260/1077] exec: Make EXCP_FOO definitions target agnostic MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The EXCP_* definitions don't need to be target specific, move them to "exec/cpu-common.h". Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Anton Johansson Message-Id: <20230914185718.76241-2-philmd@linaro.org> Signed-off-by: Richard Henderson --- include/exec/cpu-all.h | 7 ------- include/exec/cpu-common.h | 7 +++++++ 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/include/exec/cpu-all.h b/include/exec/cpu-all.h index 17c7420543..b14255923b 100644 --- a/include/exec/cpu-all.h +++ b/include/exec/cpu-all.h @@ -26,13 +26,6 @@ #include "hw/core/cpu.h" #include "qemu/rcu.h" -#define EXCP_INTERRUPT 0x10000 /* async interruption */ -#define EXCP_HLT 0x10001 /* hlt instruction reached */ -#define EXCP_DEBUG 0x10002 /* cpu stopped after a breakpoint or singlestep */ -#define EXCP_HALTED 0x10003 /* cpu is halted (waiting for external event) */ -#define EXCP_YIELD 0x10004 /* cpu wants to yield timeslice to another */ -#define EXCP_ATOMIC 0x10005 /* stop-the-world and emulate atomic */ - /* some important defines: * * HOST_BIG_ENDIAN : whether the host cpu is big endian and diff --git a/include/exec/cpu-common.h b/include/exec/cpu-common.h index 41788c0bdd..360b8298a4 100644 --- a/include/exec/cpu-common.h +++ b/include/exec/cpu-common.h @@ -7,6 +7,13 @@ #include "exec/hwaddr.h" #endif +#define EXCP_INTERRUPT 0x10000 /* async interruption */ +#define EXCP_HLT 0x10001 /* hlt instruction reached */ +#define EXCP_DEBUG 0x10002 /* cpu stopped after a breakpoint or singlestep */ +#define EXCP_HALTED 0x10003 /* cpu is halted (waiting for external event) */ +#define EXCP_YIELD 0x10004 /* cpu wants to yield timeslice to another */ +#define EXCP_ATOMIC 0x10005 /* stop-the-world and emulate atomic */ + /** * vaddr: * Type wide enough to contain any #target_ulong virtual address. From 3549118b498873c84b442bc280a5edafbb61e0a4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Thu, 14 Sep 2023 20:57:08 +0200 Subject: [PATCH 0261/1077] exec: Move cpu_loop_foo() target agnostic functions to 'cpu-common.h' MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit While these functions are not TCG specific, they are not target specific. Move them to "exec/cpu-common.h" so their callers don't have to be tainted as target specific. Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Anton Johansson Message-Id: <20230914185718.76241-3-philmd@linaro.org> Signed-off-by: Richard Henderson --- include/exec/cpu-common.h | 32 ++++++++++++++++++++++++++++++++ include/exec/exec-all.h | 30 ------------------------------ 2 files changed, 32 insertions(+), 30 deletions(-) diff --git a/include/exec/cpu-common.h b/include/exec/cpu-common.h index 360b8298a4..605b160a7e 100644 --- a/include/exec/cpu-common.h +++ b/include/exec/cpu-common.h @@ -173,4 +173,36 @@ int cpu_memory_rw_debug(CPUState *cpu, vaddr addr, /* vl.c */ void list_cpus(void); +#ifdef CONFIG_TCG +/** + * cpu_unwind_state_data: + * @cpu: the cpu context + * @host_pc: the host pc within the translation + * @data: output data + * + * Attempt to load the the unwind state for a host pc occurring in + * translated code. If @host_pc is not in translated code, the + * function returns false; otherwise @data is loaded. + * This is the same unwind info as given to restore_state_to_opc. + */ +bool cpu_unwind_state_data(CPUState *cpu, uintptr_t host_pc, uint64_t *data); + +/** + * cpu_restore_state: + * @cpu: the cpu context + * @host_pc: the host pc within the translation + * @return: true if state was restored, false otherwise + * + * Attempt to restore the state for a fault occurring in translated + * code. If @host_pc is not in translated code no state is + * restored and the function returns false. + */ +bool cpu_restore_state(CPUState *cpu, uintptr_t host_pc); + +G_NORETURN void cpu_loop_exit_noexc(CPUState *cpu); +G_NORETURN void cpu_loop_exit_atomic(CPUState *cpu, uintptr_t pc); +#endif /* CONFIG_TCG */ +G_NORETURN void cpu_loop_exit(CPUState *cpu); +G_NORETURN void cpu_loop_exit_restore(CPUState *cpu, uintptr_t pc); + #endif /* CPU_COMMON_H */ diff --git a/include/exec/exec-all.h b/include/exec/exec-all.h index 2e4d337805..ee90ef122b 100644 --- a/include/exec/exec-all.h +++ b/include/exec/exec-all.h @@ -27,36 +27,6 @@ #include "exec/translation-block.h" #include "qemu/clang-tsa.h" -/** - * cpu_unwind_state_data: - * @cpu: the cpu context - * @host_pc: the host pc within the translation - * @data: output data - * - * Attempt to load the the unwind state for a host pc occurring in - * translated code. If @host_pc is not in translated code, the - * function returns false; otherwise @data is loaded. - * This is the same unwind info as given to restore_state_to_opc. - */ -bool cpu_unwind_state_data(CPUState *cpu, uintptr_t host_pc, uint64_t *data); - -/** - * cpu_restore_state: - * @cpu: the cpu context - * @host_pc: the host pc within the translation - * @return: true if state was restored, false otherwise - * - * Attempt to restore the state for a fault occurring in translated - * code. If @host_pc is not in translated code no state is - * restored and the function returns false. - */ -bool cpu_restore_state(CPUState *cpu, uintptr_t host_pc); - -G_NORETURN void cpu_loop_exit_noexc(CPUState *cpu); -G_NORETURN void cpu_loop_exit(CPUState *cpu); -G_NORETURN void cpu_loop_exit_restore(CPUState *cpu, uintptr_t pc); -G_NORETURN void cpu_loop_exit_atomic(CPUState *cpu, uintptr_t pc); - /** * cpu_loop_exit_requested: * @cpu: The CPU state to be tested From 7ada976fee54c1b67dac2d9c0cb3bb02173084cc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Thu, 14 Sep 2023 20:57:09 +0200 Subject: [PATCH 0262/1077] accel/tcg: Restrict dump_exec_info() declaration MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In commit 00c9a5c2c3 ("accel/tcg: Restrict 'qapi-commands-machine.h' to system emulation") we moved the definition to accel/tcg/ which is where this function is called. No need to expose it outside. Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Anton Johansson Message-Id: <20230914185718.76241-4-philmd@linaro.org> Signed-off-by: Richard Henderson --- accel/tcg/internal.h | 2 ++ include/exec/cpu-all.h | 5 ----- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/accel/tcg/internal.h b/accel/tcg/internal.h index 57ab397df1..f2fa52029e 100644 --- a/accel/tcg/internal.h +++ b/accel/tcg/internal.h @@ -105,6 +105,8 @@ static inline bool cpu_in_serial_context(CPUState *cs) extern int64_t max_delay; extern int64_t max_advance; +void dump_exec_info(GString *buf); + extern bool one_insn_per_tb; /** diff --git a/include/exec/cpu-all.h b/include/exec/cpu-all.h index b14255923b..5340907cfd 100644 --- a/include/exec/cpu-all.h +++ b/include/exec/cpu-all.h @@ -406,11 +406,6 @@ static inline bool tlb_hit(uint64_t tlb_addr, vaddr addr) return tlb_hit_page(tlb_addr, addr & TARGET_PAGE_MASK); } -#ifdef CONFIG_TCG -/* accel/tcg/translate-all.c */ -void dump_exec_info(GString *buf); -#endif /* CONFIG_TCG */ - #endif /* !CONFIG_USER_ONLY */ /* accel/tcg/cpu-exec.c */ From c9955713e9d275980ca2177cf7fbc94b49bc89e5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Thu, 14 Sep 2023 20:57:10 +0200 Subject: [PATCH 0263/1077] accel: Make accel-blocker.o target agnostic MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit accel-blocker.c is not target specific, move it to system_ss[]. Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Anton Johansson Message-Id: <20230914185718.76241-5-philmd@linaro.org> Signed-off-by: Richard Henderson --- accel/meson.build | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/accel/meson.build b/accel/meson.build index 638a9a03ba..76f3cbc530 100644 --- a/accel/meson.build +++ b/accel/meson.build @@ -1,5 +1,5 @@ -specific_ss.add(files('accel-common.c', 'accel-blocker.c')) -system_ss.add(files('accel-softmmu.c')) +specific_ss.add(files('accel-common.c')) +system_ss.add(files('accel-softmmu.c', 'accel-blocker.c')) user_ss.add(files('accel-user.c')) subdir('tcg') From e8b845b9b1a172c367bb77e16498664290736ad6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Thu, 14 Sep 2023 20:57:11 +0200 Subject: [PATCH 0264/1077] accel: Rename accel-common.c -> accel-target.c MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We use the '-common.c' suffix for target agnostic units. This file is target specific, rename it using the '-target' suffix. Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Anton Johansson Message-Id: <20230914185718.76241-6-philmd@linaro.org> Signed-off-by: Richard Henderson --- accel/{accel-common.c => accel-target.c} | 0 accel/meson.build | 2 +- 2 files changed, 1 insertion(+), 1 deletion(-) rename accel/{accel-common.c => accel-target.c} (100%) diff --git a/accel/accel-common.c b/accel/accel-target.c similarity index 100% rename from accel/accel-common.c rename to accel/accel-target.c diff --git a/accel/meson.build b/accel/meson.build index 76f3cbc530..fda3157a6e 100644 --- a/accel/meson.build +++ b/accel/meson.build @@ -1,4 +1,4 @@ -specific_ss.add(files('accel-common.c')) +specific_ss.add(files('accel-target.c')) system_ss.add(files('accel-softmmu.c', 'accel-blocker.c')) user_ss.add(files('accel-user.c')) From fe0007f3c1d7254ef738c36997ef7dbd4e5e36b3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Thu, 14 Sep 2023 20:57:12 +0200 Subject: [PATCH 0265/1077] exec: Rename cpu.c -> cpu-target.c MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We have exec/cpu code split in 2 files for target agnostic ("common") and specific. Rename 'cpu.c' which is target specific using the '-target' suffix. Update MAINTAINERS. Remove the 's from 'cpus-common.c' to match the API cpu_foo() functions. Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Anton Johansson Message-Id: <20230914185718.76241-7-philmd@linaro.org> Signed-off-by: Richard Henderson --- MAINTAINERS | 4 ++-- cpus-common.c => cpu-common.c | 0 cpu.c => cpu-target.c | 0 meson.build | 4 ++-- 4 files changed, 4 insertions(+), 4 deletions(-) rename cpus-common.c => cpu-common.c (100%) rename cpu.c => cpu-target.c (100%) diff --git a/MAINTAINERS b/MAINTAINERS index 81625f036b..f82b78afa8 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -139,7 +139,8 @@ R: Paolo Bonzini S: Maintained F: softmmu/cpus.c F: softmmu/watchpoint.c -F: cpus-common.c +F: cpu-common.c +F: cpu-target.c F: page-vary.c F: page-vary-common.c F: accel/tcg/ @@ -1766,7 +1767,6 @@ M: Marcel Apfelbaum R: Philippe Mathieu-Daudé R: Yanan Wang S: Supported -F: cpu.c F: hw/core/cpu.c F: hw/core/machine-qmp-cmds.c F: hw/core/machine.c diff --git a/cpus-common.c b/cpu-common.c similarity index 100% rename from cpus-common.c rename to cpu-common.c diff --git a/cpu.c b/cpu-target.c similarity index 100% rename from cpu.c rename to cpu-target.c diff --git a/meson.build b/meson.build index 21a1bc03f8..0760c29857 100644 --- a/meson.build +++ b/meson.build @@ -3431,8 +3431,8 @@ if have_block system_ss.add(when: 'CONFIG_WIN32', if_true: [files('os-win32.c')]) endif -common_ss.add(files('cpus-common.c')) -specific_ss.add(files('cpu.c')) +common_ss.add(files('cpu-common.c')) +specific_ss.add(files('cpu-target.c')) subdir('softmmu') From 8c7907a1807b681b2ccf1ca339e7f841b2ecf877 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Thu, 14 Sep 2023 20:57:13 +0200 Subject: [PATCH 0266/1077] exec: Rename target specific page-vary.c -> page-vary-target.c MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This matches the target agnostic 'page-vary-common.c' counterpart. Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Anton Johansson Message-Id: <20230914185718.76241-8-philmd@linaro.org> Signed-off-by: Richard Henderson --- MAINTAINERS | 2 +- meson.build | 2 +- page-vary.c => page-vary-target.c | 0 3 files changed, 2 insertions(+), 2 deletions(-) rename page-vary.c => page-vary-target.c (100%) diff --git a/MAINTAINERS b/MAINTAINERS index f82b78afa8..cb2dbd967e 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -141,7 +141,7 @@ F: softmmu/cpus.c F: softmmu/watchpoint.c F: cpu-common.c F: cpu-target.c -F: page-vary.c +F: page-vary-target.c F: page-vary-common.c F: accel/tcg/ F: accel/stubs/tcg-stub.c diff --git a/meson.build b/meson.build index 0760c29857..12df8fe0de 100644 --- a/meson.build +++ b/meson.build @@ -3454,7 +3454,7 @@ if get_option('b_lto') pagevary = declare_dependency(link_with: pagevary) endif common_ss.add(pagevary) -specific_ss.add(files('page-vary.c')) +specific_ss.add(files('page-vary-target.c')) subdir('backends') subdir('disas') diff --git a/page-vary.c b/page-vary-target.c similarity index 100% rename from page-vary.c rename to page-vary-target.c From 4c268d6d03d297b83f2aa0af2de2e867af2389fc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Thu, 14 Sep 2023 20:57:14 +0200 Subject: [PATCH 0267/1077] accel/tcg: Rename target-specific 'internal.h' -> 'internal-target.h' MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit accel/tcg/internal.h contains target specific declarations. Unit files including it become "target tainted": they can not be compiled as target agnostic. Rename using the '-target' suffix to make this explicit. Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Anton Johansson Message-Id: <20230914185718.76241-9-philmd@linaro.org> Signed-off-by: Richard Henderson --- accel/tcg/cpu-exec-common.c | 2 +- accel/tcg/cpu-exec.c | 2 +- accel/tcg/cputlb.c | 2 +- accel/tcg/{internal.h => internal-target.h} | 6 +++--- accel/tcg/monitor.c | 2 +- accel/tcg/tb-maint.c | 2 +- accel/tcg/tcg-all.c | 2 +- accel/tcg/translate-all.c | 2 +- accel/tcg/translator.c | 2 +- accel/tcg/user-exec.c | 2 +- 10 files changed, 12 insertions(+), 12 deletions(-) rename accel/tcg/{internal.h => internal-target.h} (96%) diff --git a/accel/tcg/cpu-exec-common.c b/accel/tcg/cpu-exec-common.c index 82ae837e39..a9f9dc2c56 100644 --- a/accel/tcg/cpu-exec-common.c +++ b/accel/tcg/cpu-exec-common.c @@ -22,7 +22,7 @@ #include "sysemu/tcg.h" #include "exec/exec-all.h" #include "qemu/plugin.h" -#include "internal.h" +#include "internal-target.h" bool tcg_allowed; diff --git a/accel/tcg/cpu-exec.c b/accel/tcg/cpu-exec.c index fe01d937d9..a4aa9ec9ca 100644 --- a/accel/tcg/cpu-exec.c +++ b/accel/tcg/cpu-exec.c @@ -42,7 +42,7 @@ #include "tb-jmp-cache.h" #include "tb-hash.h" #include "tb-context.h" -#include "internal.h" +#include "internal-target.h" /* -icount align implementation. */ diff --git a/accel/tcg/cputlb.c b/accel/tcg/cputlb.c index c53f434c88..df20bf4034 100644 --- a/accel/tcg/cputlb.c +++ b/accel/tcg/cputlb.c @@ -35,7 +35,7 @@ #include "exec/translate-all.h" #include "trace.h" #include "tb-hash.h" -#include "internal.h" +#include "internal-target.h" #ifdef CONFIG_PLUGIN #include "qemu/plugin-memory.h" #endif diff --git a/accel/tcg/internal.h b/accel/tcg/internal-target.h similarity index 96% rename from accel/tcg/internal.h rename to accel/tcg/internal-target.h index f2fa52029e..ed583e0efd 100644 --- a/accel/tcg/internal.h +++ b/accel/tcg/internal-target.h @@ -1,13 +1,13 @@ /* - * Internal execution defines for qemu + * Internal execution defines for qemu (target specific) * * Copyright (c) 2003 Fabrice Bellard * * SPDX-License-Identifier: LGPL-2.1-or-later */ -#ifndef ACCEL_TCG_INTERNAL_H -#define ACCEL_TCG_INTERNAL_H +#ifndef ACCEL_TCG_INTERNAL_TARGET_H +#define ACCEL_TCG_INTERNAL_TARGET_H #include "exec/exec-all.h" #include "exec/translate-all.h" diff --git a/accel/tcg/monitor.c b/accel/tcg/monitor.c index d48de23999..30724fdb98 100644 --- a/accel/tcg/monitor.c +++ b/accel/tcg/monitor.c @@ -16,7 +16,7 @@ #include "sysemu/cpu-timers.h" #include "sysemu/tcg.h" #include "tcg/tcg.h" -#include "internal.h" +#include "internal-target.h" static void dump_drift_info(GString *buf) diff --git a/accel/tcg/tb-maint.c b/accel/tcg/tb-maint.c index 835ce75443..290d94e8c2 100644 --- a/accel/tcg/tb-maint.c +++ b/accel/tcg/tb-maint.c @@ -29,7 +29,7 @@ #include "tcg/tcg.h" #include "tb-hash.h" #include "tb-context.h" -#include "internal.h" +#include "internal-target.h" /* List iterators for lists of tagged pointers in TranslationBlock. */ diff --git a/accel/tcg/tcg-all.c b/accel/tcg/tcg-all.c index 8ab873a5ab..7ea7dead16 100644 --- a/accel/tcg/tcg-all.c +++ b/accel/tcg/tcg-all.c @@ -38,7 +38,7 @@ #if !defined(CONFIG_USER_ONLY) #include "hw/boards.h" #endif -#include "internal.h" +#include "internal-target.h" struct TCGState { AccelState parent_obj; diff --git a/accel/tcg/translate-all.c b/accel/tcg/translate-all.c index 83e07b830f..6c09b7f50d 100644 --- a/accel/tcg/translate-all.c +++ b/accel/tcg/translate-all.c @@ -61,7 +61,7 @@ #include "tb-jmp-cache.h" #include "tb-hash.h" #include "tb-context.h" -#include "internal.h" +#include "internal-target.h" #include "perf.h" #include "tcg/insn-start-words.h" diff --git a/accel/tcg/translator.c b/accel/tcg/translator.c index 563262e5a9..e7abcd86c1 100644 --- a/accel/tcg/translator.c +++ b/accel/tcg/translator.c @@ -14,7 +14,7 @@ #include "exec/translator.h" #include "exec/plugin-gen.h" #include "tcg/tcg-op-common.h" -#include "internal.h" +#include "internal-target.h" static void set_can_do_io(DisasContextBase *db, bool val) { diff --git a/accel/tcg/user-exec.c b/accel/tcg/user-exec.c index 17f9aff0cf..f925dd0305 100644 --- a/accel/tcg/user-exec.c +++ b/accel/tcg/user-exec.c @@ -29,7 +29,7 @@ #include "qemu/atomic128.h" #include "trace/trace-root.h" #include "tcg/tcg-ldst.h" -#include "internal.h" +#include "internal-target.h" __thread uintptr_t helper_retaddr; From 5934660fa2aabaf76e650dcd1fccc2b676122137 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Thu, 14 Sep 2023 20:57:15 +0200 Subject: [PATCH 0268/1077] accel/tcg: Make monitor.c a target-agnostic unit MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Move target-agnostic declarations from "internal-target.h" to a new "internal-common.h" header. monitor.c now don't include target specific headers and can be compiled once in system_ss[]. Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Anton Johansson Message-Id: <20230914185718.76241-10-philmd@linaro.org> Signed-off-by: Richard Henderson --- accel/tcg/cpu-exec.c | 1 + accel/tcg/internal-common.h | 17 +++++++++++++++++ accel/tcg/internal-target.h | 5 ----- accel/tcg/meson.build | 3 +++ accel/tcg/monitor.c | 2 +- accel/tcg/translate-all.c | 1 + 6 files changed, 23 insertions(+), 6 deletions(-) create mode 100644 accel/tcg/internal-common.h diff --git a/accel/tcg/cpu-exec.c b/accel/tcg/cpu-exec.c index a4aa9ec9ca..1a5bc90220 100644 --- a/accel/tcg/cpu-exec.c +++ b/accel/tcg/cpu-exec.c @@ -42,6 +42,7 @@ #include "tb-jmp-cache.h" #include "tb-hash.h" #include "tb-context.h" +#include "internal-common.h" #include "internal-target.h" /* -icount align implementation. */ diff --git a/accel/tcg/internal-common.h b/accel/tcg/internal-common.h new file mode 100644 index 0000000000..5d5247442e --- /dev/null +++ b/accel/tcg/internal-common.h @@ -0,0 +1,17 @@ +/* + * Internal execution defines for qemu (target agnostic) + * + * Copyright (c) 2003 Fabrice Bellard + * + * SPDX-License-Identifier: LGPL-2.1-or-later + */ + +#ifndef ACCEL_TCG_INTERNAL_COMMON_H +#define ACCEL_TCG_INTERNAL_COMMON_H + +extern int64_t max_delay; +extern int64_t max_advance; + +void dump_exec_info(GString *buf); + +#endif diff --git a/accel/tcg/internal-target.h b/accel/tcg/internal-target.h index ed583e0efd..17e3ad7054 100644 --- a/accel/tcg/internal-target.h +++ b/accel/tcg/internal-target.h @@ -102,11 +102,6 @@ static inline bool cpu_in_serial_context(CPUState *cs) return !(cs->tcg_cflags & CF_PARALLEL) || cpu_in_exclusive_context(cs); } -extern int64_t max_delay; -extern int64_t max_advance; - -void dump_exec_info(GString *buf); - extern bool one_insn_per_tb; /** diff --git a/accel/tcg/meson.build b/accel/tcg/meson.build index 8ace783707..0fb03bd7d3 100644 --- a/accel/tcg/meson.build +++ b/accel/tcg/meson.build @@ -20,6 +20,9 @@ specific_ss.add_all(when: 'CONFIG_TCG', if_true: tcg_ss) specific_ss.add(when: ['CONFIG_SYSTEM_ONLY', 'CONFIG_TCG'], if_true: files( 'cputlb.c', +)) + +system_ss.add(when: ['CONFIG_TCG'], if_true: files( 'monitor.c', )) diff --git a/accel/tcg/monitor.c b/accel/tcg/monitor.c index 30724fdb98..caf1189e0b 100644 --- a/accel/tcg/monitor.c +++ b/accel/tcg/monitor.c @@ -16,7 +16,7 @@ #include "sysemu/cpu-timers.h" #include "sysemu/tcg.h" #include "tcg/tcg.h" -#include "internal-target.h" +#include "internal-common.h" static void dump_drift_info(GString *buf) diff --git a/accel/tcg/translate-all.c b/accel/tcg/translate-all.c index 6c09b7f50d..8cb6ad3511 100644 --- a/accel/tcg/translate-all.c +++ b/accel/tcg/translate-all.c @@ -61,6 +61,7 @@ #include "tb-jmp-cache.h" #include "tb-hash.h" #include "tb-context.h" +#include "internal-common.h" #include "internal-target.h" #include "perf.h" #include "tcg/insn-start-words.h" From 467bf3fc09d08937061c86eefef185341e4c2cf8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Thu, 14 Sep 2023 20:57:16 +0200 Subject: [PATCH 0269/1077] accel/tcg: Make icount.o a target agnostic unit MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Remove the unused "exec/exec-all.h" header. There is no more target specific code in it: make it target agnostic (rename using the '-common' suffix). Since it is TCG specific, move it to accel/tcg, updating MAINTAINERS. Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Anton Johansson Message-Id: <20230914185718.76241-11-philmd@linaro.org> Signed-off-by: Richard Henderson --- MAINTAINERS | 1 - softmmu/icount.c => accel/tcg/icount-common.c | 3 +-- accel/tcg/meson.build | 1 + softmmu/meson.build | 4 ---- 4 files changed, 2 insertions(+), 7 deletions(-) rename softmmu/icount.c => accel/tcg/icount-common.c (99%) diff --git a/MAINTAINERS b/MAINTAINERS index cb2dbd967e..78199101aa 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -2906,7 +2906,6 @@ F: softmmu/main.c F: softmmu/cpus.c F: softmmu/cpu-throttle.c F: softmmu/cpu-timers.c -F: softmmu/icount.c F: softmmu/runstate* F: qapi/run-state.json diff --git a/softmmu/icount.c b/accel/tcg/icount-common.c similarity index 99% rename from softmmu/icount.c rename to accel/tcg/icount-common.c index 4527bfbd6e..0bf5bb5e21 100644 --- a/softmmu/icount.c +++ b/accel/tcg/icount-common.c @@ -27,7 +27,6 @@ #include "migration/vmstate.h" #include "qapi/error.h" #include "qemu/error-report.h" -#include "exec/exec-all.h" #include "sysemu/cpus.h" #include "sysemu/qtest.h" #include "qemu/main-loop.h" @@ -38,7 +37,7 @@ #include "hw/core/cpu.h" #include "sysemu/cpu-timers.h" #include "sysemu/cpu-throttle.h" -#include "timers-state.h" +#include "softmmu/timers-state.h" /* * ICOUNT: Instruction Counter diff --git a/accel/tcg/meson.build b/accel/tcg/meson.build index 0fb03bd7d3..4633a34d28 100644 --- a/accel/tcg/meson.build +++ b/accel/tcg/meson.build @@ -23,6 +23,7 @@ specific_ss.add(when: ['CONFIG_SYSTEM_ONLY', 'CONFIG_TCG'], if_true: files( )) system_ss.add(when: ['CONFIG_TCG'], if_true: files( + 'icount-common.c', 'monitor.c', )) diff --git a/softmmu/meson.build b/softmmu/meson.build index c18b7ad738..3a64dd89de 100644 --- a/softmmu/meson.build +++ b/softmmu/meson.build @@ -6,10 +6,6 @@ specific_ss.add(when: 'CONFIG_SYSTEM_ONLY', if_true: [files( 'watchpoint.c', )]) -specific_ss.add(when: ['CONFIG_SYSTEM_ONLY', 'CONFIG_TCG'], if_true: [files( - 'icount.c', -)]) - system_ss.add(files( 'balloon.c', 'bootdevice.c', From 43e7a2d3f9d2c09c22f494f282dc8a421d3e649f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Thu, 14 Sep 2023 20:57:17 +0200 Subject: [PATCH 0270/1077] accel/tcg: Make cpu-exec-common.c a target agnostic unit MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit cpu_in_serial_context() is not target specific, move it declaration to "internal-common.h" (which we include in the 4 source files modified). Remove the unused "exec/exec-all.h" header from cpu-exec-common.c. There is no more target specific code in this file: make it target agnostic. Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Anton Johansson Message-Id: <20230914185718.76241-12-philmd@linaro.org> Signed-off-by: Richard Henderson --- accel/tcg/cpu-exec-common.c | 3 +-- accel/tcg/cputlb.c | 1 + accel/tcg/internal-common.h | 11 +++++++++++ accel/tcg/internal-target.h | 9 --------- accel/tcg/meson.build | 4 +++- accel/tcg/tb-maint.c | 1 + accel/tcg/user-exec.c | 1 + 7 files changed, 18 insertions(+), 12 deletions(-) diff --git a/accel/tcg/cpu-exec-common.c b/accel/tcg/cpu-exec-common.c index a9f9dc2c56..bc9b1a260e 100644 --- a/accel/tcg/cpu-exec-common.c +++ b/accel/tcg/cpu-exec-common.c @@ -20,9 +20,8 @@ #include "qemu/osdep.h" #include "sysemu/cpus.h" #include "sysemu/tcg.h" -#include "exec/exec-all.h" #include "qemu/plugin.h" -#include "internal-target.h" +#include "internal-common.h" bool tcg_allowed; diff --git a/accel/tcg/cputlb.c b/accel/tcg/cputlb.c index df20bf4034..b8c5e345b8 100644 --- a/accel/tcg/cputlb.c +++ b/accel/tcg/cputlb.c @@ -35,6 +35,7 @@ #include "exec/translate-all.h" #include "trace.h" #include "tb-hash.h" +#include "internal-common.h" #include "internal-target.h" #ifdef CONFIG_PLUGIN #include "qemu/plugin-memory.h" diff --git a/accel/tcg/internal-common.h b/accel/tcg/internal-common.h index 5d5247442e..3b2277e6e9 100644 --- a/accel/tcg/internal-common.h +++ b/accel/tcg/internal-common.h @@ -9,9 +9,20 @@ #ifndef ACCEL_TCG_INTERNAL_COMMON_H #define ACCEL_TCG_INTERNAL_COMMON_H +#include "exec/translation-block.h" + extern int64_t max_delay; extern int64_t max_advance; void dump_exec_info(GString *buf); +/* + * Return true if CS is not running in parallel with other cpus, either + * because there are no other cpus or we are within an exclusive context. + */ +static inline bool cpu_in_serial_context(CPUState *cs) +{ + return !(cs->tcg_cflags & CF_PARALLEL) || cpu_in_exclusive_context(cs); +} + #endif diff --git a/accel/tcg/internal-target.h b/accel/tcg/internal-target.h index 17e3ad7054..4e36cf858e 100644 --- a/accel/tcg/internal-target.h +++ b/accel/tcg/internal-target.h @@ -93,15 +93,6 @@ static inline vaddr log_pc(CPUState *cpu, const TranslationBlock *tb) } } -/* - * Return true if CS is not running in parallel with other cpus, either - * because there are no other cpus or we are within an exclusive context. - */ -static inline bool cpu_in_serial_context(CPUState *cs) -{ - return !(cs->tcg_cflags & CF_PARALLEL) || cpu_in_exclusive_context(cs); -} - extern bool one_insn_per_tb; /** diff --git a/accel/tcg/meson.build b/accel/tcg/meson.build index 4633a34d28..8783edd06e 100644 --- a/accel/tcg/meson.build +++ b/accel/tcg/meson.build @@ -1,7 +1,9 @@ tcg_ss = ss.source_set() +common_ss.add(when: 'CONFIG_TCG', if_true: files( + 'cpu-exec-common.c', +)) tcg_ss.add(files( 'tcg-all.c', - 'cpu-exec-common.c', 'cpu-exec.c', 'tb-maint.c', 'tcg-runtime-gvec.c', diff --git a/accel/tcg/tb-maint.c b/accel/tcg/tb-maint.c index 290d94e8c2..e678d20dc2 100644 --- a/accel/tcg/tb-maint.c +++ b/accel/tcg/tb-maint.c @@ -29,6 +29,7 @@ #include "tcg/tcg.h" #include "tb-hash.h" #include "tb-context.h" +#include "internal-common.h" #include "internal-target.h" diff --git a/accel/tcg/user-exec.c b/accel/tcg/user-exec.c index f925dd0305..5bf2761bf4 100644 --- a/accel/tcg/user-exec.c +++ b/accel/tcg/user-exec.c @@ -29,6 +29,7 @@ #include "qemu/atomic128.h" #include "trace/trace-root.h" #include "tcg/tcg-ldst.h" +#include "internal-common.h" #include "internal-target.h" __thread uintptr_t helper_retaddr; From 935f75ae639bab5e443aeea7c79a78b949c55fe8 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 29 Sep 2023 19:35:26 -0700 Subject: [PATCH 0271/1077] tcg: Remove argument to tcg_prologue_init MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We can load tcg_ctx just as easily within the callee. Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Richard Henderson --- accel/tcg/tcg-all.c | 2 +- bsd-user/main.c | 2 +- include/tcg/tcg.h | 2 +- linux-user/main.c | 2 +- tcg/tcg.c | 3 ++- 5 files changed, 6 insertions(+), 5 deletions(-) diff --git a/accel/tcg/tcg-all.c b/accel/tcg/tcg-all.c index 7ea7dead16..a81400d3ee 100644 --- a/accel/tcg/tcg-all.c +++ b/accel/tcg/tcg-all.c @@ -121,7 +121,7 @@ static int tcg_init_machine(MachineState *ms) * There's no guest base to take into account, so go ahead and * initialize the prologue now. */ - tcg_prologue_init(tcg_ctx); + tcg_prologue_init(); #endif return 0; diff --git a/bsd-user/main.c b/bsd-user/main.c index 6c9addb75a..7ad406903a 100644 --- a/bsd-user/main.c +++ b/bsd-user/main.c @@ -586,7 +586,7 @@ int main(int argc, char **argv) * generating the prologue until now so that the prologue can take * the real value of GUEST_BASE into account. */ - tcg_prologue_init(tcg_ctx); + tcg_prologue_init(); target_cpu_init(env, regs); diff --git a/include/tcg/tcg.h b/include/tcg/tcg.h index 7743868dc9..2e2d12d421 100644 --- a/include/tcg/tcg.h +++ b/include/tcg/tcg.h @@ -784,7 +784,7 @@ static inline void *tcg_malloc(int size) void tcg_init(size_t tb_size, int splitwx, unsigned max_cpus); void tcg_register_thread(void); -void tcg_prologue_init(TCGContext *s); +void tcg_prologue_init(void); void tcg_func_start(TCGContext *s); int tcg_gen_code(TCGContext *s, TranslationBlock *tb, uint64_t pc_start); diff --git a/linux-user/main.c b/linux-user/main.c index 0a62e2be47..eb66ddec11 100644 --- a/linux-user/main.c +++ b/linux-user/main.c @@ -994,7 +994,7 @@ int main(int argc, char **argv, char **envp) /* Now that we've loaded the binary, GUEST_BASE is fixed. Delay generating the prologue until now so that the prologue can take the real value of GUEST_BASE into account. */ - tcg_prologue_init(tcg_ctx); + tcg_prologue_init(); target_cpu_copy_regs(env, regs); diff --git a/tcg/tcg.c b/tcg/tcg.c index 9256217b8f..e37e5a3b5d 100644 --- a/tcg/tcg.c +++ b/tcg/tcg.c @@ -1395,8 +1395,9 @@ TranslationBlock *tcg_tb_alloc(TCGContext *s) return tb; } -void tcg_prologue_init(TCGContext *s) +void tcg_prologue_init(void) { + TCGContext *s = tcg_ctx; size_t prologue_size; s->code_ptr = s->code_gen_ptr; From d7ec12f83cbb63343dd6e76392241e16a58f41e8 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 29 Sep 2023 19:54:54 -0700 Subject: [PATCH 0272/1077] tcg: Split out tcg init functions to tcg/startup.h MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The tcg/tcg.h header is a big bucket, containing stuff related to the translators and the JIT backend. The places that initialize tcg or create new threads do not need all of that, so split out these three functions to a new header. Suggested-by: Peter Maydell Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Richard Henderson --- accel/tcg/tcg-accel-ops-mttcg.c | 2 +- accel/tcg/tcg-accel-ops-rr.c | 2 +- accel/tcg/tcg-all.c | 2 +- bsd-user/main.c | 2 +- include/tcg/startup.h | 58 +++++++++++++++++++++++++++++++++ include/tcg/tcg.h | 3 -- linux-user/main.c | 2 +- linux-user/syscall.c | 2 +- tcg/tcg.c | 1 + 9 files changed, 65 insertions(+), 9 deletions(-) create mode 100644 include/tcg/startup.h diff --git a/accel/tcg/tcg-accel-ops-mttcg.c b/accel/tcg/tcg-accel-ops-mttcg.c index ae95ba419e..fac80095bb 100644 --- a/accel/tcg/tcg-accel-ops-mttcg.c +++ b/accel/tcg/tcg-accel-ops-mttcg.c @@ -32,7 +32,7 @@ #include "qemu/guest-random.h" #include "exec/exec-all.h" #include "hw/boards.h" -#include "tcg/tcg.h" +#include "tcg/startup.h" #include "tcg-accel-ops.h" #include "tcg-accel-ops-mttcg.h" diff --git a/accel/tcg/tcg-accel-ops-rr.c b/accel/tcg/tcg-accel-ops-rr.c index 671a3c4ca0..611932f3c3 100644 --- a/accel/tcg/tcg-accel-ops-rr.c +++ b/accel/tcg/tcg-accel-ops-rr.c @@ -32,7 +32,7 @@ #include "qemu/notify.h" #include "qemu/guest-random.h" #include "exec/exec-all.h" -#include "tcg/tcg.h" +#include "tcg/startup.h" #include "tcg-accel-ops.h" #include "tcg-accel-ops-rr.h" #include "tcg-accel-ops-icount.h" diff --git a/accel/tcg/tcg-all.c b/accel/tcg/tcg-all.c index a81400d3ee..c6619f5b98 100644 --- a/accel/tcg/tcg-all.c +++ b/accel/tcg/tcg-all.c @@ -27,7 +27,7 @@ #include "sysemu/tcg.h" #include "exec/replay-core.h" #include "sysemu/cpu-timers.h" -#include "tcg/tcg.h" +#include "tcg/startup.h" #include "tcg/oversized-guest.h" #include "qapi/error.h" #include "qemu/error-report.h" diff --git a/bsd-user/main.c b/bsd-user/main.c index 7ad406903a..703f3e2c41 100644 --- a/bsd-user/main.c +++ b/bsd-user/main.c @@ -36,7 +36,7 @@ #include "qemu/help_option.h" #include "qemu/module.h" #include "exec/exec-all.h" -#include "tcg/tcg.h" +#include "tcg/startup.h" #include "qemu/timer.h" #include "qemu/envlist.h" #include "qemu/cutils.h" diff --git a/include/tcg/startup.h b/include/tcg/startup.h new file mode 100644 index 0000000000..f71305765c --- /dev/null +++ b/include/tcg/startup.h @@ -0,0 +1,58 @@ +/* + * Tiny Code Generator for QEMU: definitions used by runtime startup + * + * Copyright (c) 2008 Fabrice Bellard + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#ifndef TCG_STARTUP_H +#define TCG_STARTUP_H + +/** + * tcg_init: Initialize the TCG runtime + * @tb_size: translation buffer size + * @splitwx: use separate rw and rx mappings + * @max_cpus: number of vcpus in system mode + * + * Allocate and initialize TCG resources, especially the JIT buffer. + * In user-only mode, @max_cpus is unused. + */ +void tcg_init(size_t tb_size, int splitwx, unsigned max_cpus); + +/** + * tcg_register_thread: Register this thread with the TCG runtime + * + * All TCG threads except the parent (i.e. the one that called the TCG + * accelerator's init_machine() method) must register with this + * function before initiating translation. + */ +void tcg_register_thread(void); + +/** + * tcg_prologue_init(): Generate the code for the TCG prologue + * + * In softmmu this is done automatically as part of the TCG + * accelerator's init_machine() method, but for user-mode, the + * user-mode code must call this function after it has loaded + * the guest binary and the value of guest_base is known. + */ +void tcg_prologue_init(void); + +#endif diff --git a/include/tcg/tcg.h b/include/tcg/tcg.h index 2e2d12d421..680ff00722 100644 --- a/include/tcg/tcg.h +++ b/include/tcg/tcg.h @@ -782,9 +782,6 @@ static inline void *tcg_malloc(int size) } } -void tcg_init(size_t tb_size, int splitwx, unsigned max_cpus); -void tcg_register_thread(void); -void tcg_prologue_init(void); void tcg_func_start(TCGContext *s); int tcg_gen_code(TCGContext *s, TranslationBlock *tb, uint64_t pc_start); diff --git a/linux-user/main.c b/linux-user/main.c index eb66ddec11..0c23584a96 100644 --- a/linux-user/main.c +++ b/linux-user/main.c @@ -41,7 +41,7 @@ #include "exec/exec-all.h" #include "exec/gdbstub.h" #include "gdbstub/user.h" -#include "tcg/tcg.h" +#include "tcg/startup.h" #include "qemu/timer.h" #include "qemu/envlist.h" #include "qemu/guest-random.h" diff --git a/linux-user/syscall.c b/linux-user/syscall.c index 3521a2d70b..c6ffadd082 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -23,6 +23,7 @@ #include "qemu/memfd.h" #include "qemu/queue.h" #include "qemu/plugin.h" +#include "tcg/startup.h" #include "target_mman.h" #include #include @@ -141,7 +142,6 @@ #include "special-errno.h" #include "qapi/error.h" #include "fd-trans.h" -#include "tcg/tcg.h" #include "cpu_loop-common.h" #ifndef CLONE_IO diff --git a/tcg/tcg.c b/tcg/tcg.c index e37e5a3b5d..f664cf1484 100644 --- a/tcg/tcg.c +++ b/tcg/tcg.c @@ -36,6 +36,7 @@ #include "qemu/timer.h" #include "exec/translation-block.h" #include "exec/tlb-common.h" +#include "tcg/startup.h" #include "tcg/tcg-op-common.h" #if UINTPTR_MAX == UINT32_MAX From 33bc4fa78b06fc4e5fe22e5576811a97707e0cc6 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Sat, 30 Sep 2023 13:45:54 -0700 Subject: [PATCH 0273/1077] linux-user/hppa: Fix struct target_sigcontext layout MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use abi_ullong not uint64_t so that the alignment of the field and therefore the layout of the struct is correct. Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Richard Henderson --- linux-user/hppa/signal.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/linux-user/hppa/signal.c b/linux-user/hppa/signal.c index bda6e54655..ec5f5412d1 100644 --- a/linux-user/hppa/signal.c +++ b/linux-user/hppa/signal.c @@ -25,7 +25,7 @@ struct target_sigcontext { abi_ulong sc_flags; abi_ulong sc_gr[32]; - uint64_t sc_fr[32]; + abi_ullong sc_fr[32]; abi_ulong sc_iasq[2]; abi_ulong sc_iaoq[2]; abi_ulong sc_sar; From a0bc59972664194cc208e28ae714b134a26ba045 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Sat, 30 Sep 2023 11:15:23 -0700 Subject: [PATCH 0274/1077] build: Remove --enable-gprof MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This build option has been deprecated since 8.0. Remove all CONFIG_GPROF code that depends on that, including one errant check using TARGET_GPROF. Acked-by: Alex Bennée Reviewed-by: Philippe Mathieu-Daudé Acked-by: Paolo Bonzini Signed-off-by: Richard Henderson --- bsd-user/bsd-proc.h | 3 --- bsd-user/signal.c | 5 ----- docs/about/deprecated.rst | 14 -------------- linux-user/exit.c | 6 ------ linux-user/signal.c | 5 ----- meson.build | 12 ------------ meson_options.txt | 3 --- scripts/meson-buildoptions.sh | 3 --- tests/qemu-iotests/meson.build | 2 +- 9 files changed, 1 insertion(+), 52 deletions(-) diff --git a/bsd-user/bsd-proc.h b/bsd-user/bsd-proc.h index a1061bffb8..0e1d461c4c 100644 --- a/bsd-user/bsd-proc.h +++ b/bsd-user/bsd-proc.h @@ -25,9 +25,6 @@ /* exit(2) */ static inline abi_long do_bsd_exit(void *cpu_env, abi_long arg1) { -#ifdef TARGET_GPROF - _mcleanup(); -#endif gdb_exit(arg1); qemu_plugin_user_exit(); _exit(arg1); diff --git a/bsd-user/signal.c b/bsd-user/signal.c index 4109aa5043..f82df50af7 100644 --- a/bsd-user/signal.c +++ b/bsd-user/signal.c @@ -847,11 +847,6 @@ void signal_init(void) act.sa_flags = SA_SIGINFO; for (i = 1; i <= TARGET_NSIG; i++) { -#ifdef CONFIG_GPROF - if (i == TARGET_SIGPROF) { - continue; - } -#endif host_sig = target_to_host_signal(i); sigaction(host_sig, NULL, &oact); if (oact.sa_sigaction == (void *)SIG_IGN) { diff --git a/docs/about/deprecated.rst b/docs/about/deprecated.rst index 2f51cf770a..3b074b9ed4 100644 --- a/docs/about/deprecated.rst +++ b/docs/about/deprecated.rst @@ -20,20 +20,6 @@ they were first deprecated in the 2.10.0 release. What follows is a list of all features currently marked as deprecated. -Build options -------------- - -``gprof`` builds (since 8.0) -'''''''''''''''''''''''''''' - -The ``--enable-gprof`` configure setting relies on compiler -instrumentation to gather its data which can distort the generated -profile. As other non-instrumenting tools are available that give a -more holistic view of the system with non-instrumented binaries we are -deprecating the build option and no longer defend it in CI. The -``--enable-gcov`` build option remains for analysis test case -coverage. - System emulator command line arguments -------------------------------------- diff --git a/linux-user/exit.c b/linux-user/exit.c index 3017d28a3c..50266314e0 100644 --- a/linux-user/exit.c +++ b/linux-user/exit.c @@ -22,9 +22,6 @@ #include "qemu.h" #include "user-internals.h" #include "qemu/plugin.h" -#ifdef CONFIG_GPROF -#include -#endif #ifdef CONFIG_GCOV extern void __gcov_dump(void); @@ -32,9 +29,6 @@ extern void __gcov_dump(void); void preexit_cleanup(CPUArchState *env, int code) { -#ifdef CONFIG_GPROF - _mcleanup(); -#endif #ifdef CONFIG_GCOV __gcov_dump(); #endif diff --git a/linux-user/signal.c b/linux-user/signal.c index a7ba2ccaf4..a67ab47d30 100644 --- a/linux-user/signal.c +++ b/linux-user/signal.c @@ -588,11 +588,6 @@ void signal_init(void) act.sa_flags = SA_SIGINFO; act.sa_sigaction = host_signal_handler; for(i = 1; i <= TARGET_NSIG; i++) { -#ifdef CONFIG_GPROF - if (i == TARGET_SIGPROF) { - continue; - } -#endif host_sig = target_to_host_signal(i); sigaction(host_sig, NULL, &oact); if (oact.sa_sigaction == (void *)SIG_IGN) { diff --git a/meson.build b/meson.build index 12df8fe0de..b8bb69f9ea 100644 --- a/meson.build +++ b/meson.build @@ -254,11 +254,6 @@ if host_arch == 'i386' and not cc.links(''' qemu_common_flags = ['-march=i486'] + qemu_common_flags endif -if get_option('gprof') - qemu_common_flags += ['-p'] - qemu_ldflags += ['-p'] -endif - if get_option('prefer_static') qemu_ldflags += get_option('b_pie') ? '-static-pie' : '-static' endif @@ -2214,7 +2209,6 @@ config_host_data.set('CONFIG_DEBUG_GRAPH_LOCK', get_option('debug_graph_lock')) config_host_data.set('CONFIG_DEBUG_MUTEX', get_option('debug_mutex')) config_host_data.set('CONFIG_DEBUG_STACK_USAGE', get_option('debug_stack_usage')) config_host_data.set('CONFIG_DEBUG_TCG', get_option('debug_tcg')) -config_host_data.set('CONFIG_GPROF', get_option('gprof')) config_host_data.set('CONFIG_LIVE_BLOCK_MIGRATION', get_option('live_block_migration').allowed()) config_host_data.set('CONFIG_QOM_CAST_DEBUG', get_option('qom_cast_debug')) config_host_data.set('CONFIG_REPLICATION', get_option('replication').allowed()) @@ -4128,12 +4122,6 @@ summary_info += {'memory allocator': get_option('malloc')} summary_info += {'avx2 optimization': config_host_data.get('CONFIG_AVX2_OPT')} summary_info += {'avx512bw optimization': config_host_data.get('CONFIG_AVX512BW_OPT')} summary_info += {'avx512f optimization': config_host_data.get('CONFIG_AVX512F_OPT')} -if get_option('gprof') - gprof_info = 'YES (deprecated)' -else - gprof_info = get_option('gprof') -endif -summary_info += {'gprof': gprof_info} summary_info += {'gcov': get_option('b_coverage')} summary_info += {'thread sanitizer': get_option('tsan')} summary_info += {'CFI support': get_option('cfi')} diff --git a/meson_options.txt b/meson_options.txt index 57e265c871..6a17b90968 100644 --- a/meson_options.txt +++ b/meson_options.txt @@ -348,9 +348,6 @@ option('debug_stack_usage', type: 'boolean', value: false, description: 'measure coroutine stack usage') option('qom_cast_debug', type: 'boolean', value: true, description: 'cast debugging support') -option('gprof', type: 'boolean', value: false, - description: 'QEMU profiling with gprof', - deprecated: true) option('slirp_smbd', type : 'feature', value : 'auto', description: 'use smbd (at path --smbd=*) in slirp networking') diff --git a/scripts/meson-buildoptions.sh b/scripts/meson-buildoptions.sh index e4b46d5715..2a74b0275b 100644 --- a/scripts/meson-buildoptions.sh +++ b/scripts/meson-buildoptions.sh @@ -34,7 +34,6 @@ meson_options_help() { printf "%s\n" ' (choices: auto/disabled/enabled/internal/system)' printf "%s\n" ' --enable-fuzzing build fuzzing targets' printf "%s\n" ' --enable-gcov Enable coverage tracking.' - printf "%s\n" ' --enable-gprof QEMU profiling with gprof' printf "%s\n" ' --enable-lto Use link time optimization' printf "%s\n" ' --enable-malloc=CHOICE choose memory allocator to use [system] (choices:' printf "%s\n" ' jemalloc/system/tcmalloc)' @@ -309,8 +308,6 @@ _meson_option_parse() { --disable-glusterfs) printf "%s" -Dglusterfs=disabled ;; --enable-gnutls) printf "%s" -Dgnutls=enabled ;; --disable-gnutls) printf "%s" -Dgnutls=disabled ;; - --enable-gprof) printf "%s" -Dgprof=true ;; - --disable-gprof) printf "%s" -Dgprof=false ;; --enable-gtk) printf "%s" -Dgtk=enabled ;; --disable-gtk) printf "%s" -Dgtk=disabled ;; --enable-gtk-clipboard) printf "%s" -Dgtk_clipboard=enabled ;; diff --git a/tests/qemu-iotests/meson.build b/tests/qemu-iotests/meson.build index 44761e1e4d..53847cb98f 100644 --- a/tests/qemu-iotests/meson.build +++ b/tests/qemu-iotests/meson.build @@ -1,4 +1,4 @@ -if not have_tools or targetos == 'windows' or get_option('gprof') +if not have_tools or targetos == 'windows' subdir_done() endif From 432f936ae17a7f5b13bf294eaf96275ec3da46c1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Tue, 3 Oct 2023 08:38:08 +0200 Subject: [PATCH 0275/1077] tests/avocado: Re-enable MIPS Malta tests (GitLab issue #1884 fixed) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Commit 18a536f1f8 ("accel/tcg: Always require can_do_io") fixed the GitLab issue #1884: we can now re-enable those tests. This reverts commit f959c3d87ccfa585b105de6964a6261e368cc1da. Signed-off-by: Philippe Mathieu-Daudé Acked-by: Alex Bennée Message-Id: <20231003063808.66564-1-philmd@linaro.org> Signed-off-by: Richard Henderson --- tests/avocado/boot_linux_console.py | 7 ------- tests/avocado/machine_mips_malta.py | 6 ------ tests/avocado/replay_kernel.py | 7 ------- tests/avocado/tuxrun_baselines.py | 4 ---- 4 files changed, 24 deletions(-) diff --git a/tests/avocado/boot_linux_console.py b/tests/avocado/boot_linux_console.py index 01ee149812..6eab515718 100644 --- a/tests/avocado/boot_linux_console.py +++ b/tests/avocado/boot_linux_console.py @@ -116,7 +116,6 @@ class BootLinuxConsole(LinuxKernelTest): console_pattern = 'Kernel command line: %s' % kernel_command_line self.wait_for_console_pattern(console_pattern) - @skip('https://gitlab.com/qemu-project/qemu/-/issues/1884') def test_mips_malta(self): """ :avocado: tags=arch:mips @@ -139,7 +138,6 @@ class BootLinuxConsole(LinuxKernelTest): console_pattern = 'Kernel command line: %s' % kernel_command_line self.wait_for_console_pattern(console_pattern) - @skip('https://gitlab.com/qemu-project/qemu/-/issues/1884') def test_mips64el_malta(self): """ This test requires the ar tool to extract "data.tar.gz" from @@ -193,7 +191,6 @@ class BootLinuxConsole(LinuxKernelTest): console_pattern = 'Kernel command line: %s' % kernel_command_line self.wait_for_console_pattern(console_pattern) - @skip('https://gitlab.com/qemu-project/qemu/-/issues/1884') def test_mips_malta_cpio(self): """ :avocado: tags=arch:mips @@ -235,7 +232,6 @@ class BootLinuxConsole(LinuxKernelTest): # Wait for VM to shut down gracefully self.vm.wait() - @skip('https://gitlab.com/qemu-project/qemu/-/issues/1884') @skipUnless(os.getenv('AVOCADO_ALLOW_UNTRUSTED_CODE'), 'untrusted code') def test_mips64el_malta_5KEc_cpio(self): """ @@ -296,7 +292,6 @@ class BootLinuxConsole(LinuxKernelTest): console_pattern = 'Kernel command line: %s' % kernel_command_line self.wait_for_console_pattern(console_pattern) - @skip('https://gitlab.com/qemu-project/qemu/-/issues/1884') def test_mips_malta32el_nanomips_4k(self): """ :avocado: tags=arch:mipsel @@ -310,7 +305,6 @@ class BootLinuxConsole(LinuxKernelTest): kernel_hash = '477456aafd2a0f1ddc9482727f20fe9575565dd6' self.do_test_mips_malta32el_nanomips(kernel_url, kernel_hash) - @skip('https://gitlab.com/qemu-project/qemu/-/issues/1884') def test_mips_malta32el_nanomips_16k_up(self): """ :avocado: tags=arch:mipsel @@ -324,7 +318,6 @@ class BootLinuxConsole(LinuxKernelTest): kernel_hash = 'e882868f944c71c816e832e2303b7874d044a7bc' self.do_test_mips_malta32el_nanomips(kernel_url, kernel_hash) - @skip('https://gitlab.com/qemu-project/qemu/-/issues/1884') def test_mips_malta32el_nanomips_64k_dbg(self): """ :avocado: tags=arch:mipsel diff --git a/tests/avocado/machine_mips_malta.py b/tests/avocado/machine_mips_malta.py index 3620266589..92233451c5 100644 --- a/tests/avocado/machine_mips_malta.py +++ b/tests/avocado/machine_mips_malta.py @@ -11,7 +11,6 @@ import os import gzip import logging -from avocado import skip from avocado import skipIf from avocado import skipUnless from avocado.utils import archive @@ -94,7 +93,6 @@ class MaltaMachineFramebuffer(QemuSystemTest): cv2.imwrite(debug_png, screendump_bgr) self.assertGreaterEqual(tuxlogo_count, cpu_cores_count) - @skip('https://gitlab.com/qemu-project/qemu/-/issues/1884') def test_mips_malta_i6400_framebuffer_logo_1core(self): """ :avocado: tags=arch:mips64el @@ -103,7 +101,6 @@ class MaltaMachineFramebuffer(QemuSystemTest): """ self.do_test_i6400_framebuffer_logo(1) - @skip('https://gitlab.com/qemu-project/qemu/-/issues/1884') @skipIf(os.getenv('GITLAB_CI'), 'Running on GitLab') def test_mips_malta_i6400_framebuffer_logo_7cores(self): """ @@ -114,7 +111,6 @@ class MaltaMachineFramebuffer(QemuSystemTest): """ self.do_test_i6400_framebuffer_logo(7) - @skip('https://gitlab.com/qemu-project/qemu/-/issues/1884') @skipIf(os.getenv('GITLAB_CI'), 'Running on GitLab') def test_mips_malta_i6400_framebuffer_logo_8cores(self): """ @@ -146,7 +142,6 @@ class MaltaMachine(QemuSystemTest): wait_for_console_pattern(self, prompt) self.vm.shutdown() - @skip('https://gitlab.com/qemu-project/qemu/-/issues/1884') def test_mipsel_malta_yamon(self): """ :avocado: tags=arch:mipsel @@ -155,7 +150,6 @@ class MaltaMachine(QemuSystemTest): """ self.do_test_yamon() - @skip('https://gitlab.com/qemu-project/qemu/-/issues/1884') def test_mips64el_malta_yamon(self): """ :avocado: tags=arch:mips64el diff --git a/tests/avocado/replay_kernel.py b/tests/avocado/replay_kernel.py index f7ccfd2462..a18610542e 100644 --- a/tests/avocado/replay_kernel.py +++ b/tests/avocado/replay_kernel.py @@ -98,7 +98,6 @@ class ReplayKernelNormal(ReplayKernelBase): self.run_rr(kernel_path, kernel_command_line, console_pattern, shift=5) - @skip('https://gitlab.com/qemu-project/qemu/-/issues/1884') def test_mips_malta(self): """ :avocado: tags=arch:mips @@ -117,7 +116,6 @@ class ReplayKernelNormal(ReplayKernelBase): self.run_rr(kernel_path, kernel_command_line, console_pattern, shift=5) - @skip('https://gitlab.com/qemu-project/qemu/-/issues/1884') def test_mips64el_malta(self): """ This test requires the ar tool to extract "data.tar.gz" from @@ -433,7 +431,6 @@ class ReplayKernelSlow(ReplayKernelBase): # making it very slow. timeout = 180 - @skip('https://gitlab.com/qemu-project/qemu/-/issues/1884') def test_mips_malta_cpio(self): """ :avocado: tags=arch:mips @@ -463,7 +460,6 @@ class ReplayKernelSlow(ReplayKernelBase): self.run_rr(kernel_path, kernel_command_line, console_pattern, shift=5, args=('-initrd', initrd_path)) - @skip('https://gitlab.com/qemu-project/qemu/-/issues/1884') @skipUnless(os.getenv('AVOCADO_ALLOW_UNTRUSTED_CODE'), 'untrusted code') def test_mips64el_malta_5KEc_cpio(self): """ @@ -506,7 +502,6 @@ class ReplayKernelSlow(ReplayKernelBase): console_pattern = 'Kernel command line: %s' % kernel_command_line self.run_rr(kernel_path, kernel_command_line, console_pattern, shift=5) - @skip('https://gitlab.com/qemu-project/qemu/-/issues/1884') def test_mips_malta32el_nanomips_4k(self): """ :avocado: tags=arch:mipsel @@ -521,7 +516,6 @@ class ReplayKernelSlow(ReplayKernelBase): kernel_path_xz = self.fetch_asset(kernel_url, asset_hash=kernel_hash) self.do_test_mips_malta32el_nanomips(kernel_path_xz) - @skip('https://gitlab.com/qemu-project/qemu/-/issues/1884') def test_mips_malta32el_nanomips_16k_up(self): """ :avocado: tags=arch:mipsel @@ -536,7 +530,6 @@ class ReplayKernelSlow(ReplayKernelBase): kernel_path_xz = self.fetch_asset(kernel_url, asset_hash=kernel_hash) self.do_test_mips_malta32el_nanomips(kernel_path_xz) - @skip('https://gitlab.com/qemu-project/qemu/-/issues/1884') def test_mips_malta32el_nanomips_64k_dbg(self): """ :avocado: tags=arch:mipsel diff --git a/tests/avocado/tuxrun_baselines.py b/tests/avocado/tuxrun_baselines.py index 610b7e2bfa..e12250eabb 100644 --- a/tests/avocado/tuxrun_baselines.py +++ b/tests/avocado/tuxrun_baselines.py @@ -352,7 +352,6 @@ class TuxRunBaselineTest(QemuSystemTest): self.common_tuxrun(csums=sums, drive="virtio-blk-pci") - @skip('https://gitlab.com/qemu-project/qemu/-/issues/1884') def test_mips32(self): """ :avocado: tags=arch:mips @@ -371,7 +370,6 @@ class TuxRunBaselineTest(QemuSystemTest): self.common_tuxrun(csums=sums, drive="driver=ide-hd,bus=ide.0,unit=0") - @skip('https://gitlab.com/qemu-project/qemu/-/issues/1884') def test_mips32el(self): """ :avocado: tags=arch:mipsel @@ -389,7 +387,6 @@ class TuxRunBaselineTest(QemuSystemTest): self.common_tuxrun(csums=sums, drive="driver=ide-hd,bus=ide.0,unit=0") - @skip('https://gitlab.com/qemu-project/qemu/-/issues/1884') def test_mips64(self): """ :avocado: tags=arch:mips64 @@ -407,7 +404,6 @@ class TuxRunBaselineTest(QemuSystemTest): self.common_tuxrun(csums=sums, drive="driver=ide-hd,bus=ide.0,unit=0") - @skip('https://gitlab.com/qemu-project/qemu/-/issues/1884') def test_mips64el(self): """ :avocado: tags=arch:mips64el From 79de3960ae1e322835112755d99187ee9b63a270 Mon Sep 17 00:00:00 2001 From: gaosong Date: Tue, 26 Sep 2023 15:58:19 +0800 Subject: [PATCH 0276/1077] tcg/loongarch64: Fix buid error MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fix: In file included from ../tcg/tcg.c:735: /home1/gaosong/bugfix/qemu/tcg/loongarch64/tcg-target.c.inc: In function ‘tcg_out_vec_op’: /home1/gaosong/bugfix/qemu/tcg/loongarch64/tcg-target.c.inc:1855:9: error: a label can only be part of a statement and a declaration is not a statement TCGCond cond = args[3]; ^~~~~~~ Signed-off-by: gaosong Message-Id: <20230926075819.3602537-1-gaosong@loongson.cn> Reviewed-by: Richard Henderson Signed-off-by: Richard Henderson --- tcg/loongarch64/tcg-target.c.inc | 68 ++++++++++++++++---------------- 1 file changed, 35 insertions(+), 33 deletions(-) diff --git a/tcg/loongarch64/tcg-target.c.inc b/tcg/loongarch64/tcg-target.c.inc index b701df50db..8f7091002b 100644 --- a/tcg/loongarch64/tcg-target.c.inc +++ b/tcg/loongarch64/tcg-target.c.inc @@ -1852,43 +1852,45 @@ static void tcg_out_vec_op(TCGContext *s, TCGOpcode opc, tcg_out_opc_vnor_v(s, a0, a1, a1); break; case INDEX_op_cmp_vec: - TCGCond cond = args[3]; - if (const_args[2]) { - /* - * cmp_vec dest, src, value - * Try vseqi/vslei/vslti - */ - int64_t value = sextract64(a2, 0, 8 << vece); - if ((cond == TCG_COND_EQ || cond == TCG_COND_LE || \ - cond == TCG_COND_LT) && (-0x10 <= value && value <= 0x0f)) { - tcg_out32(s, encode_vdvjsk5_insn(cmp_vec_imm_insn[cond][vece], \ - a0, a1, value)); - break; - } else if ((cond == TCG_COND_LEU || cond == TCG_COND_LTU) && - (0x00 <= value && value <= 0x1f)) { - tcg_out32(s, encode_vdvjuk5_insn(cmp_vec_imm_insn[cond][vece], \ - a0, a1, value)); - break; + { + TCGCond cond = args[3]; + if (const_args[2]) { + /* + * cmp_vec dest, src, value + * Try vseqi/vslei/vslti + */ + int64_t value = sextract64(a2, 0, 8 << vece); + if ((cond == TCG_COND_EQ || cond == TCG_COND_LE || \ + cond == TCG_COND_LT) && (-0x10 <= value && value <= 0x0f)) { + tcg_out32(s, encode_vdvjsk5_insn(cmp_vec_imm_insn[cond][vece], \ + a0, a1, value)); + break; + } else if ((cond == TCG_COND_LEU || cond == TCG_COND_LTU) && + (0x00 <= value && value <= 0x1f)) { + tcg_out32(s, encode_vdvjuk5_insn(cmp_vec_imm_insn[cond][vece], \ + a0, a1, value)); + break; + } + + /* + * Fallback to: + * dupi_vec temp, a2 + * cmp_vec a0, a1, temp, cond + */ + tcg_out_dupi_vec(s, type, vece, temp_vec, a2); + a2 = temp_vec; } - /* - * Fallback to: - * dupi_vec temp, a2 - * cmp_vec a0, a1, temp, cond - */ - tcg_out_dupi_vec(s, type, vece, temp_vec, a2); - a2 = temp_vec; - } - - insn = cmp_vec_insn[cond][vece]; - if (insn == 0) { - TCGArg t; - t = a1, a1 = a2, a2 = t; - cond = tcg_swap_cond(cond); insn = cmp_vec_insn[cond][vece]; - tcg_debug_assert(insn != 0); + if (insn == 0) { + TCGArg t; + t = a1, a1 = a2, a2 = t; + cond = tcg_swap_cond(cond); + insn = cmp_vec_insn[cond][vece]; + tcg_debug_assert(insn != 0); + } + tcg_out32(s, encode_vdvjvk_insn(insn, a0, a1, a2)); } - tcg_out32(s, encode_vdvjvk_insn(insn, a0, a1, a2)); break; case INDEX_op_add_vec: tcg_out_addsub_vec(s, vece, a0, a1, a2, const_args[2], true); From f4a06e5921ec93bbb8baeca59f662672077535c3 Mon Sep 17 00:00:00 2001 From: Bernhard Beschow Date: Fri, 8 Sep 2023 10:42:27 +0200 Subject: [PATCH 0277/1077] hw/i386/acpi-build: Use pc_madt_cpu_entry() directly MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This is x86-specific code, so there is no advantage in using pc_madt_cpu_entry() behind an architecture-agnostic interface. Signed-off-by: Bernhard Beschow Reviewed-by: Philippe Mathieu-Daudé Message-Id: <20230908084234.17642-2-shentey@gmail.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/i386/acpi-build.c | 3 +-- hw/i386/acpi-common.c | 5 ++--- hw/i386/acpi-common.h | 3 +-- hw/i386/acpi-microvm.c | 3 +-- 4 files changed, 5 insertions(+), 9 deletions(-) diff --git a/hw/i386/acpi-build.c b/hw/i386/acpi-build.c index 4d2d40bab5..2879e0d555 100644 --- a/hw/i386/acpi-build.c +++ b/hw/i386/acpi-build.c @@ -2547,8 +2547,7 @@ void acpi_build(AcpiBuildTables *tables, MachineState *machine) acpi_add_table(table_offsets, tables_blob); acpi_build_madt(tables_blob, tables->linker, x86ms, - ACPI_DEVICE_IF(x86ms->acpi_dev), x86ms->oem_id, - x86ms->oem_table_id); + x86ms->oem_id, x86ms->oem_table_id); #ifdef CONFIG_ACPI_ERST { diff --git a/hw/i386/acpi-common.c b/hw/i386/acpi-common.c index 8a0932fe84..43dc23f7e0 100644 --- a/hw/i386/acpi-common.c +++ b/hw/i386/acpi-common.c @@ -94,14 +94,13 @@ build_xrupt_override(GArray *entry, uint8_t src, uint32_t gsi, uint16_t flags) * 5.2.8 Multiple APIC Description Table */ void acpi_build_madt(GArray *table_data, BIOSLinker *linker, - X86MachineState *x86ms, AcpiDeviceIf *adev, + X86MachineState *x86ms, const char *oem_id, const char *oem_table_id) { int i; bool x2apic_mode = false; MachineClass *mc = MACHINE_GET_CLASS(x86ms); const CPUArchIdList *apic_ids = mc->possible_cpu_arch_ids(MACHINE(x86ms)); - AcpiDeviceIfClass *adevc = ACPI_DEVICE_IF_GET_CLASS(adev); AcpiTable table = { .sig = "APIC", .rev = 3, .oem_id = oem_id, .oem_table_id = oem_table_id }; @@ -111,7 +110,7 @@ void acpi_build_madt(GArray *table_data, BIOSLinker *linker, build_append_int_noprefix(table_data, 1 /* PCAT_COMPAT */, 4); /* Flags */ for (i = 0; i < apic_ids->len; i++) { - adevc->madt_cpu(i, apic_ids, table_data, false); + pc_madt_cpu_entry(i, apic_ids, table_data, false); if (apic_ids->cpus[i].arch_id > 254) { x2apic_mode = true; } diff --git a/hw/i386/acpi-common.h b/hw/i386/acpi-common.h index a68825acf5..b3c56ee014 100644 --- a/hw/i386/acpi-common.h +++ b/hw/i386/acpi-common.h @@ -1,7 +1,6 @@ #ifndef HW_I386_ACPI_COMMON_H #define HW_I386_ACPI_COMMON_H -#include "hw/acpi/acpi_dev_interface.h" #include "hw/acpi/bios-linker-loader.h" #include "hw/i386/x86.h" @@ -9,7 +8,7 @@ #define ACPI_BUILD_IOAPIC_ID 0x0 void acpi_build_madt(GArray *table_data, BIOSLinker *linker, - X86MachineState *x86ms, AcpiDeviceIf *adev, + X86MachineState *x86ms, const char *oem_id, const char *oem_table_id); #endif diff --git a/hw/i386/acpi-microvm.c b/hw/i386/acpi-microvm.c index a075360d85..fec22d85c1 100644 --- a/hw/i386/acpi-microvm.c +++ b/hw/i386/acpi-microvm.c @@ -214,8 +214,7 @@ static void acpi_build_microvm(AcpiBuildTables *tables, acpi_add_table(table_offsets, tables_blob); acpi_build_madt(tables_blob, tables->linker, X86_MACHINE(machine), - ACPI_DEVICE_IF(x86ms->acpi_dev), x86ms->oem_id, - x86ms->oem_table_id); + x86ms->oem_id, x86ms->oem_table_id); #ifdef CONFIG_ACPI_ERST { From 9a4fedcf12ae388722fa5430df92d0f41e3ba9be Mon Sep 17 00:00:00 2001 From: Bernhard Beschow Date: Fri, 8 Sep 2023 10:42:28 +0200 Subject: [PATCH 0278/1077] hw/acpi/cpu: Have build_cpus_aml() take a build_madt_cpu_fn callback MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit build_cpus_aml() is architecture independent but needs to create architecture- specific CPU AML. So far this was achieved by using a virtual method from TYPE_ACPI_DEVICE_IF. However, build_cpus_aml() would resolve this interface from global (!) state. This makes it quite incomprehensible where this interface comes from (TYPE_PIIX4_PM?, TYPE_ICH9_LPC_DEVICE?, TYPE_ACPI_GED_X86?) an can lead to crashes when the generic code is ported to new architectures. So far, build_cpus_aml() is only called in architecture-specific code -- and only in x86. We can therefore simply pass pc_madt_cpu_entry() as callback to build_cpus_aml(). This is the same callback that would be used through TYPE_ACPI_DEVICE_IF. Signed-off-by: Bernhard Beschow Reviewed-by: Philippe Mathieu-Daudé Message-Id: <20230908084234.17642-3-shentey@gmail.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/acpi/cpu.c | 8 ++------ hw/i386/acpi-build.c | 4 ++-- include/hw/acpi/cpu.h | 6 +++++- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/hw/acpi/cpu.c b/hw/acpi/cpu.c index 19c154d78f..65a3202d3f 100644 --- a/hw/acpi/cpu.c +++ b/hw/acpi/cpu.c @@ -338,7 +338,7 @@ const VMStateDescription vmstate_cpu_hotplug = { #define CPU_FW_EJECT_EVENT "CEJF" void build_cpus_aml(Aml *table, MachineState *machine, CPUHotplugFeatures opts, - hwaddr io_base, + build_madt_cpu_fn build_madt_cpu, hwaddr io_base, const char *res_root, const char *event_handler_method) { @@ -353,8 +353,6 @@ void build_cpus_aml(Aml *table, MachineState *machine, CPUHotplugFeatures opts, MachineClass *mc = MACHINE_GET_CLASS(machine); const CPUArchIdList *arch_ids = mc->possible_cpu_arch_ids(machine); char *cphp_res_path = g_strdup_printf("%s." CPUHP_RES_DEVICE, res_root); - Object *obj = object_resolve_path_type("", TYPE_ACPI_DEVICE_IF, NULL); - AcpiDeviceIfClass *adevc = ACPI_DEVICE_IF_GET_CLASS(obj); cpu_ctrl_dev = aml_device("%s", cphp_res_path); { @@ -664,9 +662,7 @@ void build_cpus_aml(Aml *table, MachineState *machine, CPUHotplugFeatures opts, aml_append(dev, method); /* build _MAT object */ - assert(adevc && adevc->madt_cpu); - adevc->madt_cpu(i, arch_ids, madt_buf, - true); /* set enabled flag */ + build_madt_cpu(i, arch_ids, madt_buf, true); /* set enabled flag */ aml_append(dev, aml_name_decl("_MAT", aml_buffer(madt_buf->len, (uint8_t *)madt_buf->data))); g_array_free(madt_buf, true); diff --git a/hw/i386/acpi-build.c b/hw/i386/acpi-build.c index 2879e0d555..76581d51aa 100644 --- a/hw/i386/acpi-build.c +++ b/hw/i386/acpi-build.c @@ -1549,8 +1549,8 @@ build_dsdt(GArray *table_data, BIOSLinker *linker, .smi_path = pm->smi_on_cpuhp ? "\\_SB.PCI0.SMI0.SMIC" : NULL, .fw_unplugs_cpu = pm->smi_on_cpu_unplug, }; - build_cpus_aml(dsdt, machine, opts, pm->cpu_hp_io_base, - "\\_SB.PCI0", "\\_GPE._E02"); + build_cpus_aml(dsdt, machine, opts, pc_madt_cpu_entry, + pm->cpu_hp_io_base, "\\_SB.PCI0", "\\_GPE._E02"); } if (pcms->memhp_io_base && nr_mem) { diff --git a/include/hw/acpi/cpu.h b/include/hw/acpi/cpu.h index 999caaf510..bc901660fb 100644 --- a/include/hw/acpi/cpu.h +++ b/include/hw/acpi/cpu.h @@ -15,6 +15,7 @@ #include "hw/qdev-core.h" #include "hw/acpi/acpi.h" #include "hw/acpi/aml-build.h" +#include "hw/boards.h" #include "hw/hotplug.h" typedef struct AcpiCpuStatus { @@ -55,8 +56,11 @@ typedef struct CPUHotplugFeatures { const char *smi_path; } CPUHotplugFeatures; +typedef void (*build_madt_cpu_fn)(int uid, const CPUArchIdList *apic_ids, + GArray *entry, bool force_enabled); + void build_cpus_aml(Aml *table, MachineState *machine, CPUHotplugFeatures opts, - hwaddr io_base, + build_madt_cpu_fn build_madt_cpu, hwaddr io_base, const char *res_root, const char *event_handler_method); From c461f3e3820f2a033e7eed08689060328b31dcbf Mon Sep 17 00:00:00 2001 From: Bernhard Beschow Date: Fri, 8 Sep 2023 10:42:29 +0200 Subject: [PATCH 0279/1077] hw/acpi/acpi_dev_interface: Remove now unused madt_cpu virtual method MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This virtual method was always set to the x86-specific pc_madt_cpu_entry(), even in piix4 which is also used in MIPS. The previous changes use pc_madt_cpu_entry() otherwise, so madt_cpu can be dropped. Since pc_madt_cpu_entry() is now only used in x86-specific code, the stub in hw/acpi/acpi-x86-stub can be removed as well. Signed-off-by: Bernhard Beschow Reviewed-by: Philippe Mathieu-Daudé Message-Id: <20230908084234.17642-4-shentey@gmail.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/acpi/acpi-x86-stub.c | 6 ------ hw/acpi/piix4.c | 2 -- hw/i386/generic_event_device_x86.c | 9 --------- hw/isa/lpc_ich9.c | 1 - include/hw/acpi/acpi_dev_interface.h | 2 -- 5 files changed, 20 deletions(-) diff --git a/hw/acpi/acpi-x86-stub.c b/hw/acpi/acpi-x86-stub.c index d0d399d26b..9662a594ad 100644 --- a/hw/acpi/acpi-x86-stub.c +++ b/hw/acpi/acpi-x86-stub.c @@ -1,12 +1,6 @@ #include "qemu/osdep.h" -#include "hw/i386/pc.h" #include "hw/i386/acpi-build.h" -void pc_madt_cpu_entry(int uid, const CPUArchIdList *apic_ids, - GArray *entry, bool force_enabled) -{ -} - Object *acpi_get_i386_pci_host(void) { return NULL; diff --git a/hw/acpi/piix4.c b/hw/acpi/piix4.c index 63d2113b86..a7892c444c 100644 --- a/hw/acpi/piix4.c +++ b/hw/acpi/piix4.c @@ -20,7 +20,6 @@ */ #include "qemu/osdep.h" -#include "hw/i386/pc.h" #include "hw/irq.h" #include "hw/isa/apm.h" #include "hw/i2c/pm_smbus.h" @@ -654,7 +653,6 @@ static void piix4_pm_class_init(ObjectClass *klass, void *data) hc->is_hotpluggable_bus = piix4_is_hotpluggable_bus; adevc->ospm_status = piix4_ospm_status; adevc->send_event = piix4_send_gpe; - adevc->madt_cpu = pc_madt_cpu_entry; } static const TypeInfo piix4_pm_info = { diff --git a/hw/i386/generic_event_device_x86.c b/hw/i386/generic_event_device_x86.c index e26fb02a2e..8fc233e1f1 100644 --- a/hw/i386/generic_event_device_x86.c +++ b/hw/i386/generic_event_device_x86.c @@ -8,19 +8,10 @@ #include "qemu/osdep.h" #include "hw/acpi/generic_event_device.h" -#include "hw/i386/pc.h" - -static void acpi_ged_x86_class_init(ObjectClass *class, void *data) -{ - AcpiDeviceIfClass *adevc = ACPI_DEVICE_IF_CLASS(class); - - adevc->madt_cpu = pc_madt_cpu_entry; -} static const TypeInfo acpi_ged_x86_info = { .name = TYPE_ACPI_GED_X86, .parent = TYPE_ACPI_GED, - .class_init = acpi_ged_x86_class_init, .interfaces = (InterfaceInfo[]) { { TYPE_HOTPLUG_HANDLER }, { TYPE_ACPI_DEVICE_IF }, diff --git a/hw/isa/lpc_ich9.c b/hw/isa/lpc_ich9.c index bce487ac4e..3f59980aa0 100644 --- a/hw/isa/lpc_ich9.c +++ b/hw/isa/lpc_ich9.c @@ -891,7 +891,6 @@ static void ich9_lpc_class_init(ObjectClass *klass, void *data) hc->is_hotpluggable_bus = ich9_pm_is_hotpluggable_bus; adevc->ospm_status = ich9_pm_ospm_status; adevc->send_event = ich9_send_gpe; - adevc->madt_cpu = pc_madt_cpu_entry; amldevc->build_dev_aml = build_ich9_isa_aml; } diff --git a/include/hw/acpi/acpi_dev_interface.h b/include/hw/acpi/acpi_dev_interface.h index a1648220ff..ca92928124 100644 --- a/include/hw/acpi/acpi_dev_interface.h +++ b/include/hw/acpi/acpi_dev_interface.h @@ -52,7 +52,5 @@ struct AcpiDeviceIfClass { /* */ void (*ospm_status)(AcpiDeviceIf *adev, ACPIOSTInfoList ***list); void (*send_event)(AcpiDeviceIf *adev, AcpiEventStatusBits ev); - void (*madt_cpu)(int uid, const CPUArchIdList *apic_ids, GArray *entry, - bool force_enabled); }; #endif From 4f70dd5f6366ac04b0f67d026ee2e17eb35daa45 Mon Sep 17 00:00:00 2001 From: Bernhard Beschow Date: Fri, 8 Sep 2023 10:42:30 +0200 Subject: [PATCH 0280/1077] hw/acpi/acpi_dev_interface: Remove now unused #include "hw/boards.h" MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The "hw/boards.h" is unused since the previous commit. Since its removal requires include fixes in various unrelated files to keep the code compiling it has been split in a dedicated commit. Signed-off-by: Bernhard Beschow Reviewed-by: Philippe Mathieu-Daudé Message-Id: <20230908084234.17642-5-shentey@gmail.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/acpi/cpu.c | 1 + hw/acpi/hmat.c | 1 + hw/acpi/hmat.h | 3 ++- hw/acpi/memory_hotplug.c | 1 + include/hw/acpi/acpi_dev_interface.h | 1 - 5 files changed, 5 insertions(+), 2 deletions(-) diff --git a/hw/acpi/cpu.c b/hw/acpi/cpu.c index 65a3202d3f..011d2c6c2d 100644 --- a/hw/acpi/cpu.c +++ b/hw/acpi/cpu.c @@ -1,6 +1,7 @@ #include "qemu/osdep.h" #include "migration/vmstate.h" #include "hw/acpi/cpu.h" +#include "hw/core/cpu.h" #include "qapi/error.h" #include "qapi/qapi-events-acpi.h" #include "trace.h" diff --git a/hw/acpi/hmat.c b/hw/acpi/hmat.c index 2d5e199ba9..3042d223c8 100644 --- a/hw/acpi/hmat.c +++ b/hw/acpi/hmat.c @@ -27,6 +27,7 @@ #include "qemu/osdep.h" #include "qemu/units.h" #include "sysemu/numa.h" +#include "hw/acpi/aml-build.h" #include "hw/acpi/hmat.h" /* diff --git a/hw/acpi/hmat.h b/hw/acpi/hmat.h index b57f0e7e80..fd989cb661 100644 --- a/hw/acpi/hmat.h +++ b/hw/acpi/hmat.h @@ -27,7 +27,8 @@ #ifndef HMAT_H #define HMAT_H -#include "hw/acpi/aml-build.h" +#include "hw/acpi/bios-linker-loader.h" +#include "sysemu/numa.h" /* * ACPI 6.3: 5.2.27.3 Memory Proximity Domain Attributes Structure, diff --git a/hw/acpi/memory_hotplug.c b/hw/acpi/memory_hotplug.c index d926f4f77d..0b883df813 100644 --- a/hw/acpi/memory_hotplug.c +++ b/hw/acpi/memory_hotplug.c @@ -1,6 +1,7 @@ #include "qemu/osdep.h" #include "hw/acpi/memory_hotplug.h" #include "hw/mem/pc-dimm.h" +#include "hw/boards.h" #include "hw/qdev-core.h" #include "migration/vmstate.h" #include "trace.h" diff --git a/include/hw/acpi/acpi_dev_interface.h b/include/hw/acpi/acpi_dev_interface.h index ca92928124..68d9d15f50 100644 --- a/include/hw/acpi/acpi_dev_interface.h +++ b/include/hw/acpi/acpi_dev_interface.h @@ -3,7 +3,6 @@ #include "qapi/qapi-types-acpi.h" #include "qom/object.h" -#include "hw/boards.h" #include "hw/qdev-core.h" /* These values are part of guest ABI, and can not be changed */ From c9c8ba69d5dbe5c1c6370e1f09ebd7531509d075 Mon Sep 17 00:00:00 2001 From: Bernhard Beschow Date: Fri, 8 Sep 2023 10:42:31 +0200 Subject: [PATCH 0281/1077] hw/i386: Remove now redundant TYPE_ACPI_GED_X86 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Now that TYPE_ACPI_GED_X86 doesn't assign AcpiDeviceIfClass::madt_cpu any more it is the same as TYPE_ACPI_GED. Signed-off-by: Bernhard Beschow Reviewed-by: Philippe Mathieu-Daudé Message-Id: <20230908084234.17642-6-shentey@gmail.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/i386/generic_event_device_x86.c | 27 -------------------------- hw/i386/meson.build | 1 - hw/i386/microvm.c | 2 +- include/hw/acpi/generic_event_device.h | 2 -- 4 files changed, 1 insertion(+), 31 deletions(-) delete mode 100644 hw/i386/generic_event_device_x86.c diff --git a/hw/i386/generic_event_device_x86.c b/hw/i386/generic_event_device_x86.c deleted file mode 100644 index 8fc233e1f1..0000000000 --- a/hw/i386/generic_event_device_x86.c +++ /dev/null @@ -1,27 +0,0 @@ -/* - * x86 variant of the generic event device for hw reduced acpi - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2 or later, as published by the Free Software Foundation. - */ - -#include "qemu/osdep.h" -#include "hw/acpi/generic_event_device.h" - -static const TypeInfo acpi_ged_x86_info = { - .name = TYPE_ACPI_GED_X86, - .parent = TYPE_ACPI_GED, - .interfaces = (InterfaceInfo[]) { - { TYPE_HOTPLUG_HANDLER }, - { TYPE_ACPI_DEVICE_IF }, - { } - } -}; - -static void acpi_ged_x86_register_types(void) -{ - type_register_static(&acpi_ged_x86_info); -} - -type_init(acpi_ged_x86_register_types) diff --git a/hw/i386/meson.build b/hw/i386/meson.build index cfdbfdcbcb..ff879069c9 100644 --- a/hw/i386/meson.build +++ b/hw/i386/meson.build @@ -20,7 +20,6 @@ i386_ss.add(when: 'CONFIG_SGX', if_true: files('sgx-epc.c','sgx.c'), if_false: files('sgx-stub.c')) i386_ss.add(when: 'CONFIG_ACPI', if_true: files('acpi-common.c')) -i386_ss.add(when: 'CONFIG_ACPI_HW_REDUCED', if_true: files('generic_event_device_x86.c')) i386_ss.add(when: 'CONFIG_PC', if_true: files( 'pc.c', 'pc_sysfw.c', diff --git a/hw/i386/microvm.c b/hw/i386/microvm.c index 8deeb62774..b9c93039e2 100644 --- a/hw/i386/microvm.c +++ b/hw/i386/microvm.c @@ -204,7 +204,7 @@ static void microvm_devices_init(MicrovmMachineState *mms) /* Optional and legacy devices */ if (x86_machine_is_acpi_enabled(x86ms)) { - DeviceState *dev = qdev_new(TYPE_ACPI_GED_X86); + DeviceState *dev = qdev_new(TYPE_ACPI_GED); qdev_prop_set_uint32(dev, "ged-event", ACPI_GED_PWR_DOWN_EVT); sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, GED_MMIO_BASE); /* sysbus_mmio_map(SYS_BUS_DEVICE(dev), 1, GED_MMIO_BASE_MEMHP); */ diff --git a/include/hw/acpi/generic_event_device.h b/include/hw/acpi/generic_event_device.h index d831bbd889..ba84ce0214 100644 --- a/include/hw/acpi/generic_event_device.h +++ b/include/hw/acpi/generic_event_device.h @@ -69,8 +69,6 @@ #define TYPE_ACPI_GED "acpi-ged" OBJECT_DECLARE_SIMPLE_TYPE(AcpiGedState, ACPI_GED) -#define TYPE_ACPI_GED_X86 "acpi-ged-x86" - #define ACPI_GED_EVT_SEL_OFFSET 0x0 #define ACPI_GED_EVT_SEL_LEN 0x4 From 5cdb639d25f9951a90b6b7ba31d376d8ab132a61 Mon Sep 17 00:00:00 2001 From: Bernhard Beschow Date: Fri, 8 Sep 2023 10:42:32 +0200 Subject: [PATCH 0282/1077] hw/i386/acpi-build: Determine SMI command port just once MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The SMI command port is currently hardcoded by means of the ACPI_PORT_SMI_CMD macro. This hardcoding is Intel specific and doesn't match VIA, for example. There is already the AcpiFadtData::smi_cmd attribute which is used when building the FADT. Let's also use it when building the DSDT which confines SMI command port determination to just one place. This allows it to become a property later, thus resolving the Intel assumption. Signed-off-by: Bernhard Beschow Reviewed-by: Philippe Mathieu-Daudé Message-Id: <20230908084234.17642-7-shentey@gmail.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/i386/acpi-build.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/hw/i386/acpi-build.c b/hw/i386/acpi-build.c index 76581d51aa..863a939210 100644 --- a/hw/i386/acpi-build.c +++ b/hw/i386/acpi-build.c @@ -1495,14 +1495,14 @@ build_dsdt(GArray *table_data, BIOSLinker *linker, aml_append(crs, aml_io( AML_DECODE16, - ACPI_PORT_SMI_CMD, - ACPI_PORT_SMI_CMD, + pm->fadt.smi_cmd, + pm->fadt.smi_cmd, 1, 2) ); aml_append(dev, aml_name_decl("_CRS", crs)); aml_append(dev, aml_operation_region("SMIR", AML_SYSTEM_IO, - aml_int(ACPI_PORT_SMI_CMD), 2)); + aml_int(pm->fadt.smi_cmd), 2)); field = aml_field("SMIR", AML_BYTE_ACC, AML_NOLOCK, AML_WRITE_AS_ZEROS); aml_append(field, aml_named_field("SMIC", 8)); From 7f558ea58bb60257b111abac0424dc601ff54875 Mon Sep 17 00:00:00 2001 From: Bernhard Beschow Date: Fri, 8 Sep 2023 10:42:33 +0200 Subject: [PATCH 0283/1077] hw/acpi: Trace GPE access in all device models, not just PIIX4 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Bernhard Beschow Reviewed-by: Igor Mammedov Reviewed-by: Philippe Mathieu-Daudé Message-Id: <20230908084234.17642-8-shentey@gmail.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/acpi/core.c | 5 +++++ hw/acpi/piix4.c | 3 --- hw/acpi/trace-events | 8 ++++---- 3 files changed, 9 insertions(+), 7 deletions(-) diff --git a/hw/acpi/core.c b/hw/acpi/core.c index 00b1e79a30..c561845a4a 100644 --- a/hw/acpi/core.c +++ b/hw/acpi/core.c @@ -32,6 +32,7 @@ #include "qemu/module.h" #include "qemu/option.h" #include "sysemu/runstate.h" +#include "trace.h" struct acpi_table_header { uint16_t _length; /* our length, not actual part of the hdr */ @@ -686,6 +687,8 @@ void acpi_gpe_ioport_writeb(ACPIREGS *ar, uint32_t addr, uint32_t val) { uint8_t *cur; + trace_acpi_gpe_ioport_writeb(addr, val); + cur = acpi_gpe_ioport_get_ptr(ar, addr); if (addr < ar->gpe.len / 2) { /* GPE_STS */ @@ -709,6 +712,8 @@ uint32_t acpi_gpe_ioport_readb(ACPIREGS *ar, uint32_t addr) val = *cur; } + trace_acpi_gpe_ioport_readb(addr, val); + return val; } diff --git a/hw/acpi/piix4.c b/hw/acpi/piix4.c index a7892c444c..dd523d2e4c 100644 --- a/hw/acpi/piix4.c +++ b/hw/acpi/piix4.c @@ -42,7 +42,6 @@ #include "hw/acpi/acpi_dev_interface.h" #include "migration/vmstate.h" #include "hw/core/cpu.h" -#include "trace.h" #include "qom/object.h" #define GPE_BASE 0xafe0 @@ -517,7 +516,6 @@ static uint64_t gpe_readb(void *opaque, hwaddr addr, unsigned width) PIIX4PMState *s = opaque; uint32_t val = acpi_gpe_ioport_readb(&s->ar, addr); - trace_piix4_gpe_readb(addr, width, val); return val; } @@ -526,7 +524,6 @@ static void gpe_writeb(void *opaque, hwaddr addr, uint64_t val, { PIIX4PMState *s = opaque; - trace_piix4_gpe_writeb(addr, width, val); acpi_gpe_ioport_writeb(&s->ar, addr, val); acpi_update_sci(&s->ar, s->irq); } diff --git a/hw/acpi/trace-events b/hw/acpi/trace-events index 78e0a8670e..159937ddb9 100644 --- a/hw/acpi/trace-events +++ b/hw/acpi/trace-events @@ -17,6 +17,10 @@ mhp_acpi_clear_remove_evt(uint32_t slot) "slot[0x%"PRIx32"] clear remove event" mhp_acpi_pc_dimm_deleted(uint32_t slot) "slot[0x%"PRIx32"] pc-dimm deleted" mhp_acpi_pc_dimm_delete_failed(uint32_t slot) "slot[0x%"PRIx32"] pc-dimm delete failed" +# core.c +acpi_gpe_ioport_readb(uint32_t addr, uint8_t val) "addr: 0x%" PRIx32 " ==> 0x%" PRIx8 +acpi_gpe_ioport_writeb(uint32_t addr, uint8_t val) "addr: 0x%" PRIx32 " <== 0x%" PRIx8 + # cpu.c cpuhp_acpi_invalid_idx_selected(uint32_t idx) "0x%"PRIx32 cpuhp_acpi_read_flags(uint32_t idx, uint8_t flags) "idx[0x%"PRIx32"] flags: 0x%"PRIx8 @@ -48,10 +52,6 @@ acpi_pci_sel_read(uint32_t val) "%" PRIu32 acpi_pci_ej_write(uint64_t addr, uint64_t data) "0x%" PRIx64 " <== %" PRIu64 acpi_pci_sel_write(uint64_t addr, uint64_t data) "0x%" PRIx64 " <== %" PRIu64 -# piix4.c -piix4_gpe_readb(uint64_t addr, unsigned width, uint64_t val) "addr: 0x%" PRIx64 " width: %d ==> 0x%" PRIx64 -piix4_gpe_writeb(uint64_t addr, unsigned width, uint64_t val) "addr: 0x%" PRIx64 " width: %d <== 0x%" PRIx64 - # tco.c tco_timer_reload(int ticks, int msec) "ticks=%d (%d ms)" tco_timer_expired(int timeouts_no, bool strap, bool no_reboot) "timeouts_no=%d no_reboot=%d/%d" From 40a6b8935d5862840c602f977564d2ebbea60ed6 Mon Sep 17 00:00:00 2001 From: Bernhard Beschow Date: Fri, 8 Sep 2023 10:42:34 +0200 Subject: [PATCH 0284/1077] hw/acpi/core: Trace enable and status registers of GPE separately MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The bit positions of both registers are related. Tracing the registers independently results in the same offsets across these registers which eases debugging. Signed-off-by: Bernhard Beschow Acked-by: Igor Mammedov Reviewed-by: Philippe Mathieu-Daudé Message-Id: <20230908084234.17642-9-shentey@gmail.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/acpi/core.c | 10 +++++++--- hw/acpi/trace-events | 6 ++++-- 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/hw/acpi/core.c b/hw/acpi/core.c index c561845a4a..ec5e127d17 100644 --- a/hw/acpi/core.c +++ b/hw/acpi/core.c @@ -687,13 +687,13 @@ void acpi_gpe_ioport_writeb(ACPIREGS *ar, uint32_t addr, uint32_t val) { uint8_t *cur; - trace_acpi_gpe_ioport_writeb(addr, val); - cur = acpi_gpe_ioport_get_ptr(ar, addr); if (addr < ar->gpe.len / 2) { + trace_acpi_gpe_sts_ioport_writeb(addr, val); /* GPE_STS */ *cur = (*cur) & ~val; } else if (addr < ar->gpe.len) { + trace_acpi_gpe_en_ioport_writeb(addr - (ar->gpe.len / 2), val); /* GPE_EN */ *cur = val; } else { @@ -712,7 +712,11 @@ uint32_t acpi_gpe_ioport_readb(ACPIREGS *ar, uint32_t addr) val = *cur; } - trace_acpi_gpe_ioport_readb(addr, val); + if (addr < ar->gpe.len / 2) { + trace_acpi_gpe_sts_ioport_readb(addr, val); + } else { + trace_acpi_gpe_en_ioport_readb(addr - (ar->gpe.len / 2), val); + } return val; } diff --git a/hw/acpi/trace-events b/hw/acpi/trace-events index 159937ddb9..edc93e703c 100644 --- a/hw/acpi/trace-events +++ b/hw/acpi/trace-events @@ -18,8 +18,10 @@ mhp_acpi_pc_dimm_deleted(uint32_t slot) "slot[0x%"PRIx32"] pc-dimm deleted" mhp_acpi_pc_dimm_delete_failed(uint32_t slot) "slot[0x%"PRIx32"] pc-dimm delete failed" # core.c -acpi_gpe_ioport_readb(uint32_t addr, uint8_t val) "addr: 0x%" PRIx32 " ==> 0x%" PRIx8 -acpi_gpe_ioport_writeb(uint32_t addr, uint8_t val) "addr: 0x%" PRIx32 " <== 0x%" PRIx8 +acpi_gpe_en_ioport_readb(uint32_t addr, uint8_t val) "addr: 0x%" PRIx32 " ==> 0x%02" PRIx8 +acpi_gpe_en_ioport_writeb(uint32_t addr, uint8_t val) "addr: 0x%" PRIx32 " <== 0x%02" PRIx8 +acpi_gpe_sts_ioport_readb(uint32_t addr, uint8_t val) "addr: 0x%" PRIx32 " ==> 0x%02" PRIx8 +acpi_gpe_sts_ioport_writeb(uint32_t addr, uint8_t val) "addr: 0x%" PRIx32 " <== 0x%02" PRIx8 # cpu.c cpuhp_acpi_invalid_idx_selected(uint32_t idx) "0x%"PRIx32 From e77db790d1bdef9370d23a0a9350c084ce45d91d Mon Sep 17 00:00:00 2001 From: Stefan Hajnoczi Date: Mon, 11 Sep 2023 17:54:35 -0400 Subject: [PATCH 0285/1077] vdpa: fix gcc cvq_isolated uninitialized variable warning MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit gcc 13.2.1 emits the following warning: net/vhost-vdpa.c: In function ‘net_vhost_vdpa_init.constprop’: net/vhost-vdpa.c:1394:25: error: ‘cvq_isolated’ may be used uninitialized [-Werror=maybe-uninitialized] 1394 | s->cvq_isolated = cvq_isolated; | ~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~ net/vhost-vdpa.c:1355:9: note: ‘cvq_isolated’ was declared here 1355 | int cvq_isolated; | ^~~~~~~~~~~~ cc1: all warnings being treated as errors Cc: Eugenio Pérez Cc: Michael S. Tsirkin Cc: Jason Wang Signed-off-by: Stefan Hajnoczi Message-Id: <20230911215435.4156314-1-stefanha@redhat.com> Acked-by: Eugenio Pérez Acked-by: Jason Wang Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- net/vhost-vdpa.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/vhost-vdpa.c b/net/vhost-vdpa.c index 5808d1b60c..94635fcbee 100644 --- a/net/vhost-vdpa.c +++ b/net/vhost-vdpa.c @@ -1425,7 +1425,7 @@ static NetClientState *net_vhost_vdpa_init(NetClientState *peer, VhostVDPAState *s; int ret = 0; assert(name); - int cvq_isolated; + int cvq_isolated = 0; if (is_datapath) { nc = qemu_new_net_client(&net_vhost_vdpa_info, peer, device, From 0a7a164bc37b4ecbf74466e1e5243d72a768ad06 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Eugenio=20P=C3=A9rez?= Date: Wed, 13 Sep 2023 14:34:08 +0200 Subject: [PATCH 0286/1077] vdpa net: zero vhost_vdpa iova_tree pointer at cleanup MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Not zeroing it causes a SIGSEGV if the live migration is cancelled, at net device restart. This is caused because CVQ tries to reuse the iova_tree that is present in the first vhost_vdpa device at the end of vhost_vdpa_net_cvq_start. As a consequence, it tries to access an iova_tree that has been already free. Fixes: 00ef422e9fbf ("vdpa net: move iova tree creation from init to start") Reported-by: Yanhui Ma Signed-off-by: Eugenio Pérez Message-Id: <20230913123408.2819185-1-eperezma@redhat.com> Acked-by: Jason Wang Tested-by: Lei Yang Reviewed-by: Si-Wei Liu Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- net/vhost-vdpa.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/net/vhost-vdpa.c b/net/vhost-vdpa.c index 94635fcbee..fe519d908d 100644 --- a/net/vhost-vdpa.c +++ b/net/vhost-vdpa.c @@ -405,6 +405,8 @@ static void vhost_vdpa_net_client_stop(NetClientState *nc) dev = s->vhost_vdpa.dev; if (dev->vq_index + dev->nvqs == dev->vq_index_end) { g_clear_pointer(&s->vhost_vdpa.iova_tree, vhost_iova_tree_delete); + } else { + s->vhost_vdpa.iova_tree = NULL; } } From f5a4e1a697e98c7bd0a663d53a378d8c6918ed72 Mon Sep 17 00:00:00 2001 From: Jonathan Cameron Date: Wed, 13 Sep 2023 14:25:20 +0100 Subject: [PATCH 0287/1077] hw/cxl: Push cxl_decoder_count_enc() and cxl_decode_ig() into .c MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit There is no strong justification for keeping these in the header so push them down into the associated cxl-component-utils.c file. Suggested-by: Philippe Mathieu-Daudé Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Fan Ni Signed-off-by: Jonathan Cameron Message-Id: <20230913132523.29780-2-Jonathan.Cameron@huawei.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/cxl/cxl-component-utils.c | 18 ++++++++++++++++++ include/hw/cxl/cxl_component.h | 18 ++---------------- 2 files changed, 20 insertions(+), 16 deletions(-) diff --git a/hw/cxl/cxl-component-utils.c b/hw/cxl/cxl-component-utils.c index 378f1082ce..ea2d4770ec 100644 --- a/hw/cxl/cxl-component-utils.c +++ b/hw/cxl/cxl-component-utils.c @@ -13,6 +13,24 @@ #include "hw/pci/pci.h" #include "hw/cxl/cxl.h" +int cxl_decoder_count_enc(int count) +{ + switch (count) { + case 1: return 0; + case 2: return 1; + case 4: return 2; + case 6: return 3; + case 8: return 4; + case 10: return 5; + } + return 0; +} + +hwaddr cxl_decode_ig(int ig) +{ + return 1ULL << (ig + 8); +} + static uint64_t cxl_cache_mem_read_reg(void *opaque, hwaddr offset, unsigned size) { diff --git a/include/hw/cxl/cxl_component.h b/include/hw/cxl/cxl_component.h index 42c7e581a7..bdb3881a6b 100644 --- a/include/hw/cxl/cxl_component.h +++ b/include/hw/cxl/cxl_component.h @@ -225,26 +225,12 @@ void cxl_component_create_dvsec(CXLComponentState *cxl_cstate, enum reg_type cxl_dev_type, uint16_t length, uint16_t type, uint8_t rev, uint8_t *body); -static inline int cxl_decoder_count_enc(int count) -{ - switch (count) { - case 1: return 0; - case 2: return 1; - case 4: return 2; - case 6: return 3; - case 8: return 4; - case 10: return 5; - } - return 0; -} +int cxl_decoder_count_enc(int count); uint8_t cxl_interleave_ways_enc(int iw, Error **errp); uint8_t cxl_interleave_granularity_enc(uint64_t gran, Error **errp); -static inline hwaddr cxl_decode_ig(int ig) -{ - return 1ULL << (ig + 8); -} +hwaddr cxl_decode_ig(int ig); CXLComponentState *cxl_get_hb_cstate(PCIHostState *hb); bool cxl_get_hb_passthrough(PCIHostState *hb); From 87de174ac49acaa37264e38129596c9819e4a2c5 Mon Sep 17 00:00:00 2001 From: Jonathan Cameron Date: Wed, 13 Sep 2023 14:25:21 +0100 Subject: [PATCH 0288/1077] hw/cxl: Add utility functions decoder interleave ways and target count. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit As an encoded version of these key configuration parameters is available in a register, provide functions to extract it again so as to avoid the need for duplicating the storage. Whilst here update the _enc() function to include additional values as defined in the CXL 3.0 specification. Whilst they are not currently used in the emulation, they may be in future and it is easier to compare with the specification if all values are covered. Add a spec reference for cxl_interleave_ways_enc() for consistency with the target count equivalent (and because it's nice to know where the magic numbers come from). Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Fan Ni Signed-off-by: Jonathan Cameron Message-Id: <20230913132523.29780-3-Jonathan.Cameron@huawei.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/cxl/cxl-component-utils.c | 60 ++++++++++++++++++++++++++++++---- include/hw/cxl/cxl_component.h | 2 ++ 2 files changed, 56 insertions(+), 6 deletions(-) diff --git a/hw/cxl/cxl-component-utils.c b/hw/cxl/cxl-component-utils.c index ea2d4770ec..5f38f2016f 100644 --- a/hw/cxl/cxl-component-utils.c +++ b/hw/cxl/cxl-component-utils.c @@ -13,15 +13,45 @@ #include "hw/pci/pci.h" #include "hw/cxl/cxl.h" +/* CXL r3.0 Section 8.2.4.19.1 CXL HDM Decoder Capability Register */ int cxl_decoder_count_enc(int count) { switch (count) { - case 1: return 0; - case 2: return 1; - case 4: return 2; - case 6: return 3; - case 8: return 4; - case 10: return 5; + case 1: return 0x0; + case 2: return 0x1; + case 4: return 0x2; + case 6: return 0x3; + case 8: return 0x4; + case 10: return 0x5; + /* Switches and Host Bridges may have more than 10 decoders */ + case 12: return 0x6; + case 14: return 0x7; + case 16: return 0x8; + case 20: return 0x9; + case 24: return 0xa; + case 28: return 0xb; + case 32: return 0xc; + } + return 0; +} + +int cxl_decoder_count_dec(int enc_cnt) +{ + switch (enc_cnt) { + case 0x0: return 1; + case 0x1: return 2; + case 0x2: return 4; + case 0x3: return 6; + case 0x4: return 8; + case 0x5: return 10; + /* Switches and Host Bridges may have more than 10 decoders */ + case 0x6: return 12; + case 0x7: return 14; + case 0x8: return 16; + case 0x9: return 20; + case 0xa: return 24; + case 0xb: return 28; + case 0xc: return 32; } return 0; } @@ -393,6 +423,7 @@ void cxl_component_create_dvsec(CXLComponentState *cxl, cxl->dvsec_offset += length; } +/* CXL r3.0 Section 8.2.4.19.7 CXL HDM Decoder n Control Register */ uint8_t cxl_interleave_ways_enc(int iw, Error **errp) { switch (iw) { @@ -410,6 +441,23 @@ uint8_t cxl_interleave_ways_enc(int iw, Error **errp) } } +int cxl_interleave_ways_dec(uint8_t iw_enc, Error **errp) +{ + switch (iw_enc) { + case 0x0: return 1; + case 0x1: return 2; + case 0x2: return 4; + case 0x3: return 8; + case 0x4: return 16; + case 0x8: return 3; + case 0x9: return 6; + case 0xa: return 12; + default: + error_setg(errp, "Encoded interleave ways: %d not supported", iw_enc); + return 0; + } +} + uint8_t cxl_interleave_granularity_enc(uint64_t gran, Error **errp) { switch (gran) { diff --git a/include/hw/cxl/cxl_component.h b/include/hw/cxl/cxl_component.h index bdb3881a6b..ef9e033919 100644 --- a/include/hw/cxl/cxl_component.h +++ b/include/hw/cxl/cxl_component.h @@ -226,8 +226,10 @@ void cxl_component_create_dvsec(CXLComponentState *cxl_cstate, uint16_t type, uint8_t rev, uint8_t *body); int cxl_decoder_count_enc(int count); +int cxl_decoder_count_dec(int enc_cnt); uint8_t cxl_interleave_ways_enc(int iw, Error **errp); +int cxl_interleave_ways_dec(uint8_t iw_enc, Error **errp); uint8_t cxl_interleave_granularity_enc(uint64_t gran, Error **errp); hwaddr cxl_decode_ig(int ig); From 61c44bcf510f4db51c28d0288e528cfdf0ebabc3 Mon Sep 17 00:00:00 2001 From: Jonathan Cameron Date: Wed, 13 Sep 2023 14:25:22 +0100 Subject: [PATCH 0289/1077] hw/cxl: Fix and use same calculation for HDM decoder block size everywhere MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In order to avoid having the size of the per HDM decoder register block repeated in lots of places, create the register definitions for HDM decoder 1 and use the offset between the first registers in HDM decoder 0 and HDM decoder 1 to establish the offset. Calculate in each function as this is more obvious and leads to shorter line lengths than a single #define which would need a long name to be specific enough. Note that the code currently only supports one decoder, so the bugs this fixes don't actually affect anything. Signed-off-by: Jonathan Cameron Reviewed-by: Fan Ni Reviewed-by: Philippe Mathieu-Daudé Message-Id: <20230913132523.29780-4-Jonathan.Cameron@huawei.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/cxl/cxl-component-utils.c | 19 +++++++++++-------- hw/cxl/cxl-host.c | 4 +++- hw/mem/cxl_type3.c | 24 +++++++++++++++--------- include/hw/cxl/cxl_component.h | 2 ++ 4 files changed, 31 insertions(+), 18 deletions(-) diff --git a/hw/cxl/cxl-component-utils.c b/hw/cxl/cxl-component-utils.c index 5f38f2016f..c0630ba5c1 100644 --- a/hw/cxl/cxl-component-utils.c +++ b/hw/cxl/cxl-component-utils.c @@ -210,6 +210,7 @@ static void hdm_init_common(uint32_t *reg_state, uint32_t *write_msk, enum reg_type type) { int decoder_count = 1; + int hdm_inc = R_CXL_HDM_DECODER1_BASE_LO - R_CXL_HDM_DECODER0_BASE_LO; int i; ARRAY_FIELD_DP32(reg_state, CXL_HDM_DECODER_CAPABILITY, DECODER_COUNT, @@ -222,19 +223,21 @@ static void hdm_init_common(uint32_t *reg_state, uint32_t *write_msk, HDM_DECODER_ENABLE, 0); write_msk[R_CXL_HDM_DECODER_GLOBAL_CONTROL] = 0x3; for (i = 0; i < decoder_count; i++) { - write_msk[R_CXL_HDM_DECODER0_BASE_LO + i * 0x20] = 0xf0000000; - write_msk[R_CXL_HDM_DECODER0_BASE_HI + i * 0x20] = 0xffffffff; - write_msk[R_CXL_HDM_DECODER0_SIZE_LO + i * 0x20] = 0xf0000000; - write_msk[R_CXL_HDM_DECODER0_SIZE_HI + i * 0x20] = 0xffffffff; - write_msk[R_CXL_HDM_DECODER0_CTRL + i * 0x20] = 0x13ff; + write_msk[R_CXL_HDM_DECODER0_BASE_LO + i * hdm_inc] = 0xf0000000; + write_msk[R_CXL_HDM_DECODER0_BASE_HI + i * hdm_inc] = 0xffffffff; + write_msk[R_CXL_HDM_DECODER0_SIZE_LO + i * hdm_inc] = 0xf0000000; + write_msk[R_CXL_HDM_DECODER0_SIZE_HI + i * hdm_inc] = 0xffffffff; + write_msk[R_CXL_HDM_DECODER0_CTRL + i * hdm_inc] = 0x13ff; if (type == CXL2_DEVICE || type == CXL2_TYPE3_DEVICE || type == CXL2_LOGICAL_DEVICE) { - write_msk[R_CXL_HDM_DECODER0_TARGET_LIST_LO + i * 0x20] = 0xf0000000; + write_msk[R_CXL_HDM_DECODER0_TARGET_LIST_LO + i * hdm_inc] = + 0xf0000000; } else { - write_msk[R_CXL_HDM_DECODER0_TARGET_LIST_LO + i * 0x20] = 0xffffffff; + write_msk[R_CXL_HDM_DECODER0_TARGET_LIST_LO + i * hdm_inc] = + 0xffffffff; } - write_msk[R_CXL_HDM_DECODER0_TARGET_LIST_HI + i * 0x20] = 0xffffffff; + write_msk[R_CXL_HDM_DECODER0_TARGET_LIST_HI + i * hdm_inc] = 0xffffffff; } } diff --git a/hw/cxl/cxl-host.c b/hw/cxl/cxl-host.c index f0920da956..73c5426476 100644 --- a/hw/cxl/cxl-host.c +++ b/hw/cxl/cxl-host.c @@ -101,12 +101,14 @@ void cxl_fmws_link_targets(CXLState *cxl_state, Error **errp) static bool cxl_hdm_find_target(uint32_t *cache_mem, hwaddr addr, uint8_t *target) { + int hdm_inc = R_CXL_HDM_DECODER1_BASE_LO - R_CXL_HDM_DECODER0_BASE_LO; uint32_t ctrl; uint32_t ig_enc; uint32_t iw_enc; uint32_t target_idx; + int i = 0; - ctrl = cache_mem[R_CXL_HDM_DECODER0_CTRL]; + ctrl = cache_mem[R_CXL_HDM_DECODER0_CTRL + i * hdm_inc]; if (!FIELD_EX32(ctrl, CXL_HDM_DECODER0_CTRL, COMMITTED)) { return false; } diff --git a/hw/mem/cxl_type3.c b/hw/mem/cxl_type3.c index 4cdcb3f7e7..9f3022189b 100644 --- a/hw/mem/cxl_type3.c +++ b/hw/mem/cxl_type3.c @@ -388,34 +388,36 @@ static void build_dvsecs(CXLType3Dev *ct3d) static void hdm_decoder_commit(CXLType3Dev *ct3d, int which) { + int hdm_inc = R_CXL_HDM_DECODER1_BASE_LO - R_CXL_HDM_DECODER0_BASE_LO; ComponentRegisters *cregs = &ct3d->cxl_cstate.crb; uint32_t *cache_mem = cregs->cache_mem_registers; uint32_t ctrl; assert(which == 0); - ctrl = ldl_le_p(cache_mem + R_CXL_HDM_DECODER0_CTRL); + ctrl = ldl_le_p(cache_mem + R_CXL_HDM_DECODER0_CTRL + which * hdm_inc); /* TODO: Sanity checks that the decoder is possible */ ctrl = FIELD_DP32(ctrl, CXL_HDM_DECODER0_CTRL, ERR, 0); ctrl = FIELD_DP32(ctrl, CXL_HDM_DECODER0_CTRL, COMMITTED, 1); - stl_le_p(cache_mem + R_CXL_HDM_DECODER0_CTRL, ctrl); + stl_le_p(cache_mem + R_CXL_HDM_DECODER0_CTRL + which * hdm_inc, ctrl); } static void hdm_decoder_uncommit(CXLType3Dev *ct3d, int which) { + int hdm_inc = R_CXL_HDM_DECODER1_BASE_LO - R_CXL_HDM_DECODER0_BASE_LO; ComponentRegisters *cregs = &ct3d->cxl_cstate.crb; uint32_t *cache_mem = cregs->cache_mem_registers; uint32_t ctrl; assert(which == 0); - ctrl = ldl_le_p(cache_mem + R_CXL_HDM_DECODER0_CTRL); + ctrl = ldl_le_p(cache_mem + R_CXL_HDM_DECODER0_CTRL + which * hdm_inc); ctrl = FIELD_DP32(ctrl, CXL_HDM_DECODER0_CTRL, ERR, 0); ctrl = FIELD_DP32(ctrl, CXL_HDM_DECODER0_CTRL, COMMITTED, 0); - stl_le_p(cache_mem + R_CXL_HDM_DECODER0_CTRL, ctrl); + stl_le_p(cache_mem + R_CXL_HDM_DECODER0_CTRL + which * hdm_inc, ctrl); } static int ct3d_qmp_uncor_err_to_cxl(CxlUncorErrorType qmp_err) @@ -772,26 +774,30 @@ static void ct3_exit(PCIDevice *pci_dev) /* TODO: Support multiple HDM decoders and DPA skip */ static bool cxl_type3_dpa(CXLType3Dev *ct3d, hwaddr host_addr, uint64_t *dpa) { + int hdm_inc = R_CXL_HDM_DECODER1_BASE_LO - R_CXL_HDM_DECODER0_BASE_LO; uint32_t *cache_mem = ct3d->cxl_cstate.crb.cache_mem_registers; uint64_t decoder_base, decoder_size, hpa_offset; uint32_t hdm0_ctrl; int ig, iw; + int i = 0; - decoder_base = (((uint64_t)cache_mem[R_CXL_HDM_DECODER0_BASE_HI] << 32) | - cache_mem[R_CXL_HDM_DECODER0_BASE_LO]); + decoder_base = + (((uint64_t)cache_mem[R_CXL_HDM_DECODER0_BASE_HI + i * hdm_inc] << 32) | + cache_mem[R_CXL_HDM_DECODER0_BASE_LO + i * hdm_inc]); if ((uint64_t)host_addr < decoder_base) { return false; } hpa_offset = (uint64_t)host_addr - decoder_base; - decoder_size = ((uint64_t)cache_mem[R_CXL_HDM_DECODER0_SIZE_HI] << 32) | - cache_mem[R_CXL_HDM_DECODER0_SIZE_LO]; + decoder_size = + ((uint64_t)cache_mem[R_CXL_HDM_DECODER0_SIZE_HI + i * hdm_inc] << 32) | + cache_mem[R_CXL_HDM_DECODER0_SIZE_LO + i * hdm_inc]; if (hpa_offset >= decoder_size) { return false; } - hdm0_ctrl = cache_mem[R_CXL_HDM_DECODER0_CTRL]; + hdm0_ctrl = cache_mem[R_CXL_HDM_DECODER0_CTRL + i * hdm_inc]; iw = FIELD_EX32(hdm0_ctrl, CXL_HDM_DECODER0_CTRL, IW); ig = FIELD_EX32(hdm0_ctrl, CXL_HDM_DECODER0_CTRL, IG); diff --git a/include/hw/cxl/cxl_component.h b/include/hw/cxl/cxl_component.h index ef9e033919..7c864d2044 100644 --- a/include/hw/cxl/cxl_component.h +++ b/include/hw/cxl/cxl_component.h @@ -148,6 +148,8 @@ REG32(CXL_HDM_DECODER_GLOBAL_CONTROL, CXL_HDM_REGISTERS_OFFSET + 4) FIELD(CXL_HDM_DECODER_GLOBAL_CONTROL, HDM_DECODER_ENABLE, 1, 1) HDM_DECODER_INIT(0); +/* Only used for HDM decoder registers block address increment */ +HDM_DECODER_INIT(1); /* 8.2.5.13 - CXL Extended Security Capability Structure (Root complex only) */ #define EXTSEC_ENTRY_MAX 256 From e967413fe0f2f3fe022658bb279aef95d24210ec Mon Sep 17 00:00:00 2001 From: Jonathan Cameron Date: Wed, 13 Sep 2023 14:25:23 +0100 Subject: [PATCH 0290/1077] hw/cxl: Support 4 HDM decoders at all levels of topology Support these decoders in CXL host bridges (pxb-cxl), CXL Switch USP and CXL Type 3 end points. Signed-off-by: Jonathan Cameron Message-Id: <20230913132523.29780-5-Jonathan.Cameron@huawei.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/cxl/cxl-component-utils.c | 7 ++- hw/cxl/cxl-host.c | 67 +++++++++++++++-------- hw/mem/cxl_type3.c | 98 +++++++++++++++++++++++----------- include/hw/cxl/cxl_component.h | 10 +++- 4 files changed, 125 insertions(+), 57 deletions(-) diff --git a/hw/cxl/cxl-component-utils.c b/hw/cxl/cxl-component-utils.c index c0630ba5c1..f3bbf0fd13 100644 --- a/hw/cxl/cxl-component-utils.c +++ b/hw/cxl/cxl-component-utils.c @@ -90,6 +90,9 @@ static void dumb_hdm_handler(CXLComponentState *cxl_cstate, hwaddr offset, switch (offset) { case A_CXL_HDM_DECODER0_CTRL: + case A_CXL_HDM_DECODER1_CTRL: + case A_CXL_HDM_DECODER2_CTRL: + case A_CXL_HDM_DECODER3_CTRL: should_commit = FIELD_EX32(value, CXL_HDM_DECODER0_CTRL, COMMIT); should_uncommit = !should_commit; break; @@ -129,7 +132,7 @@ static void cxl_cache_mem_write_reg(void *opaque, hwaddr offset, uint64_t value, } if (offset >= A_CXL_HDM_DECODER_CAPABILITY && - offset <= A_CXL_HDM_DECODER0_TARGET_LIST_HI) { + offset <= A_CXL_HDM_DECODER3_TARGET_LIST_HI) { dumb_hdm_handler(cxl_cstate, offset, value); } else { cregs->cache_mem_registers[offset / sizeof(*cregs->cache_mem_registers)] = value; @@ -209,7 +212,7 @@ static void ras_init_common(uint32_t *reg_state, uint32_t *write_msk) static void hdm_init_common(uint32_t *reg_state, uint32_t *write_msk, enum reg_type type) { - int decoder_count = 1; + int decoder_count = CXL_HDM_DECODER_COUNT; int hdm_inc = R_CXL_HDM_DECODER1_BASE_LO - R_CXL_HDM_DECODER0_BASE_LO; int i; diff --git a/hw/cxl/cxl-host.c b/hw/cxl/cxl-host.c index 73c5426476..2aa776c79c 100644 --- a/hw/cxl/cxl-host.c +++ b/hw/cxl/cxl-host.c @@ -97,35 +97,58 @@ void cxl_fmws_link_targets(CXLState *cxl_state, Error **errp) } } -/* TODO: support, multiple hdm decoders */ static bool cxl_hdm_find_target(uint32_t *cache_mem, hwaddr addr, uint8_t *target) { int hdm_inc = R_CXL_HDM_DECODER1_BASE_LO - R_CXL_HDM_DECODER0_BASE_LO; - uint32_t ctrl; - uint32_t ig_enc; - uint32_t iw_enc; - uint32_t target_idx; - int i = 0; + unsigned int hdm_count; + bool found = false; + int i; + uint32_t cap; - ctrl = cache_mem[R_CXL_HDM_DECODER0_CTRL + i * hdm_inc]; - if (!FIELD_EX32(ctrl, CXL_HDM_DECODER0_CTRL, COMMITTED)) { - return false; + cap = ldl_le_p(cache_mem + R_CXL_HDM_DECODER_CAPABILITY); + hdm_count = cxl_decoder_count_dec(FIELD_EX32(cap, + CXL_HDM_DECODER_CAPABILITY, + DECODER_COUNT)); + for (i = 0; i < hdm_count; i++) { + uint32_t ctrl, ig_enc, iw_enc, target_idx; + uint32_t low, high; + uint64_t base, size; + + low = ldl_le_p(cache_mem + R_CXL_HDM_DECODER0_BASE_LO + i * hdm_inc); + high = ldl_le_p(cache_mem + R_CXL_HDM_DECODER0_BASE_HI + i * hdm_inc); + base = (low & 0xf0000000) | ((uint64_t)high << 32); + low = ldl_le_p(cache_mem + R_CXL_HDM_DECODER0_SIZE_LO + i * hdm_inc); + high = ldl_le_p(cache_mem + R_CXL_HDM_DECODER0_SIZE_HI + i * hdm_inc); + size = (low & 0xf0000000) | ((uint64_t)high << 32); + if (addr < base || addr >= base + size) { + continue; + } + + ctrl = ldl_le_p(cache_mem + R_CXL_HDM_DECODER0_CTRL + i * hdm_inc); + if (!FIELD_EX32(ctrl, CXL_HDM_DECODER0_CTRL, COMMITTED)) { + return false; + } + found = true; + ig_enc = FIELD_EX32(ctrl, CXL_HDM_DECODER0_CTRL, IG); + iw_enc = FIELD_EX32(ctrl, CXL_HDM_DECODER0_CTRL, IW); + target_idx = (addr / cxl_decode_ig(ig_enc)) % (1 << iw_enc); + + if (target_idx < 4) { + uint32_t val = ldl_le_p(cache_mem + + R_CXL_HDM_DECODER0_TARGET_LIST_LO + + i * hdm_inc); + *target = extract32(val, target_idx * 8, 8); + } else { + uint32_t val = ldl_le_p(cache_mem + + R_CXL_HDM_DECODER0_TARGET_LIST_HI + + i * hdm_inc); + *target = extract32(val, (target_idx - 4) * 8, 8); + } + break; } - ig_enc = FIELD_EX32(ctrl, CXL_HDM_DECODER0_CTRL, IG); - iw_enc = FIELD_EX32(ctrl, CXL_HDM_DECODER0_CTRL, IW); - target_idx = (addr / cxl_decode_ig(ig_enc)) % (1 << iw_enc); - - if (target_idx < 4) { - *target = extract32(cache_mem[R_CXL_HDM_DECODER0_TARGET_LIST_LO], - target_idx * 8, 8); - } else { - *target = extract32(cache_mem[R_CXL_HDM_DECODER0_TARGET_LIST_HI], - (target_idx - 4) * 8, 8); - } - - return true; + return found; } static PCIDevice *cxl_cfmws_find_device(CXLFixedWindow *fw, hwaddr addr) diff --git a/hw/mem/cxl_type3.c b/hw/mem/cxl_type3.c index 9f3022189b..c02be4ce45 100644 --- a/hw/mem/cxl_type3.c +++ b/hw/mem/cxl_type3.c @@ -393,8 +393,6 @@ static void hdm_decoder_commit(CXLType3Dev *ct3d, int which) uint32_t *cache_mem = cregs->cache_mem_registers; uint32_t ctrl; - assert(which == 0); - ctrl = ldl_le_p(cache_mem + R_CXL_HDM_DECODER0_CTRL + which * hdm_inc); /* TODO: Sanity checks that the decoder is possible */ ctrl = FIELD_DP32(ctrl, CXL_HDM_DECODER0_CTRL, ERR, 0); @@ -410,8 +408,6 @@ static void hdm_decoder_uncommit(CXLType3Dev *ct3d, int which) uint32_t *cache_mem = cregs->cache_mem_registers; uint32_t ctrl; - assert(which == 0); - ctrl = ldl_le_p(cache_mem + R_CXL_HDM_DECODER0_CTRL + which * hdm_inc); ctrl = FIELD_DP32(ctrl, CXL_HDM_DECODER0_CTRL, ERR, 0); @@ -500,6 +496,21 @@ static void ct3d_reg_write(void *opaque, hwaddr offset, uint64_t value, should_uncommit = !should_commit; which_hdm = 0; break; + case A_CXL_HDM_DECODER1_CTRL: + should_commit = FIELD_EX32(value, CXL_HDM_DECODER0_CTRL, COMMIT); + should_uncommit = !should_commit; + which_hdm = 1; + break; + case A_CXL_HDM_DECODER2_CTRL: + should_commit = FIELD_EX32(value, CXL_HDM_DECODER0_CTRL, COMMIT); + should_uncommit = !should_commit; + which_hdm = 2; + break; + case A_CXL_HDM_DECODER3_CTRL: + should_commit = FIELD_EX32(value, CXL_HDM_DECODER0_CTRL, COMMIT); + should_uncommit = !should_commit; + which_hdm = 3; + break; case A_CXL_RAS_UNC_ERR_STATUS: { uint32_t capctrl = ldl_le_p(cache_mem + R_CXL_RAS_ERR_CAP_CTRL); @@ -771,40 +782,63 @@ static void ct3_exit(PCIDevice *pci_dev) } } -/* TODO: Support multiple HDM decoders and DPA skip */ static bool cxl_type3_dpa(CXLType3Dev *ct3d, hwaddr host_addr, uint64_t *dpa) { int hdm_inc = R_CXL_HDM_DECODER1_BASE_LO - R_CXL_HDM_DECODER0_BASE_LO; uint32_t *cache_mem = ct3d->cxl_cstate.crb.cache_mem_registers; - uint64_t decoder_base, decoder_size, hpa_offset; - uint32_t hdm0_ctrl; - int ig, iw; - int i = 0; + unsigned int hdm_count; + uint32_t cap; + uint64_t dpa_base = 0; + int i; - decoder_base = - (((uint64_t)cache_mem[R_CXL_HDM_DECODER0_BASE_HI + i * hdm_inc] << 32) | - cache_mem[R_CXL_HDM_DECODER0_BASE_LO + i * hdm_inc]); - if ((uint64_t)host_addr < decoder_base) { - return false; + cap = ldl_le_p(cache_mem + R_CXL_HDM_DECODER_CAPABILITY); + hdm_count = cxl_decoder_count_dec(FIELD_EX32(cap, + CXL_HDM_DECODER_CAPABILITY, + DECODER_COUNT)); + + for (i = 0; i < hdm_count; i++) { + uint64_t decoder_base, decoder_size, hpa_offset, skip; + uint32_t hdm_ctrl, low, high; + int ig, iw; + + low = ldl_le_p(cache_mem + R_CXL_HDM_DECODER0_BASE_LO + i * hdm_inc); + high = ldl_le_p(cache_mem + R_CXL_HDM_DECODER0_BASE_HI + i * hdm_inc); + decoder_base = ((uint64_t)high << 32) | (low & 0xf0000000); + + low = ldl_le_p(cache_mem + R_CXL_HDM_DECODER0_SIZE_LO + i * hdm_inc); + high = ldl_le_p(cache_mem + R_CXL_HDM_DECODER0_SIZE_HI + i * hdm_inc); + decoder_size = ((uint64_t)high << 32) | (low & 0xf0000000); + + low = ldl_le_p(cache_mem + R_CXL_HDM_DECODER0_DPA_SKIP_LO + + i * hdm_inc); + high = ldl_le_p(cache_mem + R_CXL_HDM_DECODER0_DPA_SKIP_HI + + i * hdm_inc); + skip = ((uint64_t)high << 32) | (low & 0xf0000000); + dpa_base += skip; + + hpa_offset = (uint64_t)host_addr - decoder_base; + + hdm_ctrl = ldl_le_p(cache_mem + R_CXL_HDM_DECODER0_CTRL + i * hdm_inc); + iw = FIELD_EX32(hdm_ctrl, CXL_HDM_DECODER0_CTRL, IW); + ig = FIELD_EX32(hdm_ctrl, CXL_HDM_DECODER0_CTRL, IG); + if (!FIELD_EX32(hdm_ctrl, CXL_HDM_DECODER0_CTRL, COMMITTED)) { + return false; + } + if (((uint64_t)host_addr < decoder_base) || + (hpa_offset >= decoder_size)) { + dpa_base += decoder_size / + cxl_interleave_ways_dec(iw, &error_fatal); + continue; + } + + *dpa = dpa_base + + ((MAKE_64BIT_MASK(0, 8 + ig) & hpa_offset) | + ((MAKE_64BIT_MASK(8 + ig + iw, 64 - 8 - ig - iw) & hpa_offset) + >> iw)); + + return true; } - - hpa_offset = (uint64_t)host_addr - decoder_base; - - decoder_size = - ((uint64_t)cache_mem[R_CXL_HDM_DECODER0_SIZE_HI + i * hdm_inc] << 32) | - cache_mem[R_CXL_HDM_DECODER0_SIZE_LO + i * hdm_inc]; - if (hpa_offset >= decoder_size) { - return false; - } - - hdm0_ctrl = cache_mem[R_CXL_HDM_DECODER0_CTRL + i * hdm_inc]; - iw = FIELD_EX32(hdm0_ctrl, CXL_HDM_DECODER0_CTRL, IW); - ig = FIELD_EX32(hdm0_ctrl, CXL_HDM_DECODER0_CTRL, IG); - - *dpa = (MAKE_64BIT_MASK(0, 8 + ig) & hpa_offset) | - ((MAKE_64BIT_MASK(8 + ig + iw, 64 - 8 - ig - iw) & hpa_offset) >> iw); - - return true; + return false; } static int cxl_type3_hpa_to_as_and_dpa(CXLType3Dev *ct3d, diff --git a/include/hw/cxl/cxl_component.h b/include/hw/cxl/cxl_component.h index 7c864d2044..3c795a6278 100644 --- a/include/hw/cxl/cxl_component.h +++ b/include/hw/cxl/cxl_component.h @@ -135,6 +135,10 @@ REG32(CXL_RAS_ERR_HEADER0, CXL_RAS_REGISTERS_OFFSET + 0x18) REG32(CXL_HDM_DECODER##n##_TARGET_LIST_LO, \ CXL_HDM_REGISTERS_OFFSET + (0x20 * n) + 0x24) \ REG32(CXL_HDM_DECODER##n##_TARGET_LIST_HI, \ + CXL_HDM_REGISTERS_OFFSET + (0x20 * n) + 0x28) \ + REG32(CXL_HDM_DECODER##n##_DPA_SKIP_LO, \ + CXL_HDM_REGISTERS_OFFSET + (0x20 * n) + 0x24) \ + REG32(CXL_HDM_DECODER##n##_DPA_SKIP_HI, \ CXL_HDM_REGISTERS_OFFSET + (0x20 * n) + 0x28) REG32(CXL_HDM_DECODER_CAPABILITY, CXL_HDM_REGISTERS_OFFSET) @@ -147,9 +151,13 @@ REG32(CXL_HDM_DECODER_GLOBAL_CONTROL, CXL_HDM_REGISTERS_OFFSET + 4) FIELD(CXL_HDM_DECODER_GLOBAL_CONTROL, POISON_ON_ERR_EN, 0, 1) FIELD(CXL_HDM_DECODER_GLOBAL_CONTROL, HDM_DECODER_ENABLE, 1, 1) +/* Support 4 decoders at all levels of topology */ +#define CXL_HDM_DECODER_COUNT 4 + HDM_DECODER_INIT(0); -/* Only used for HDM decoder registers block address increment */ HDM_DECODER_INIT(1); +HDM_DECODER_INIT(2); +HDM_DECODER_INIT(3); /* 8.2.5.13 - CXL Extended Security Capability Structure (Root complex only) */ #define EXTSEC_ENTRY_MAX 256 From 2c9ec2a827f5d36e9cf3c55d931cc0dca2f12092 Mon Sep 17 00:00:00 2001 From: Jonathan Cameron Date: Wed, 13 Sep 2023 14:36:15 +0100 Subject: [PATCH 0291/1077] hw/pci-bridge/cxl-upstream: Add serial number extended capability support Will be needed so there is a defined serial number for information queries via the Switch CCI. Signed-off-by: Jonathan Cameron Message-Id: <20230913133615.29876-1-Jonathan.Cameron@huawei.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/pci-bridge/cxl_upstream.c | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/hw/pci-bridge/cxl_upstream.c b/hw/pci-bridge/cxl_upstream.c index 2b9cf0cc97..a57806fb31 100644 --- a/hw/pci-bridge/cxl_upstream.c +++ b/hw/pci-bridge/cxl_upstream.c @@ -14,14 +14,21 @@ #include "hw/pci/msi.h" #include "hw/pci/pcie.h" #include "hw/pci/pcie_port.h" +/* + * Null value of all Fs suggested by IEEE RA guidelines for use of + * EU, OUI and CID + */ +#define UI64_NULL (~0ULL) #define CXL_UPSTREAM_PORT_MSI_NR_VECTOR 2 #define CXL_UPSTREAM_PORT_MSI_OFFSET 0x70 #define CXL_UPSTREAM_PORT_PCIE_CAP_OFFSET 0x90 #define CXL_UPSTREAM_PORT_AER_OFFSET 0x100 -#define CXL_UPSTREAM_PORT_DVSEC_OFFSET \ +#define CXL_UPSTREAM_PORT_SN_OFFSET \ (CXL_UPSTREAM_PORT_AER_OFFSET + PCI_ERR_SIZEOF) +#define CXL_UPSTREAM_PORT_DVSEC_OFFSET \ + (CXL_UPSTREAM_PORT_SN_OFFSET + PCI_EXT_CAP_DSN_SIZEOF) typedef struct CXLUpstreamPort { /*< private >*/ @@ -30,6 +37,7 @@ typedef struct CXLUpstreamPort { /*< public >*/ CXLComponentState cxl_cstate; DOECap doe_cdat; + uint64_t sn; } CXLUpstreamPort; CXLComponentState *cxl_usp_to_cstate(CXLUpstreamPort *usp) @@ -326,7 +334,9 @@ static void cxl_usp_realize(PCIDevice *d, Error **errp) if (rc) { goto err_cap; } - + if (usp->sn != UI64_NULL) { + pcie_dev_ser_num_init(d, CXL_UPSTREAM_PORT_SN_OFFSET, usp->sn); + } cxl_cstate->dvsec_offset = CXL_UPSTREAM_PORT_DVSEC_OFFSET; cxl_cstate->pdev = d; build_dvsecs(cxl_cstate); @@ -366,6 +376,7 @@ static void cxl_usp_exitfn(PCIDevice *d) } static Property cxl_upstream_props[] = { + DEFINE_PROP_UINT64("sn", CXLUpstreamPort, sn, UI64_NULL), DEFINE_PROP_STRING("cdat", CXLUpstreamPort, cxl_cstate.cdat.filename), DEFINE_PROP_END_OF_LIST() }; From cbc9ae87b5f6f81c52a249e0b64100d5011fca53 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Eugenio=20P=C3=A9rez?= Date: Fri, 15 Sep 2023 19:08:34 +0200 Subject: [PATCH 0292/1077] vdpa net: fix error message setting virtio status MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit It incorrectly prints "error setting features", probably because a copy paste miss. Fixes: 152128d646 ("vdpa: move CVQ isolation check to net_init_vhost_vdpa") Reported-by: Peter Maydell Signed-off-by: Eugenio Pérez Message-Id: <20230915170836.3078172-2-eperezma@redhat.com> Tested-by: Lei Yang Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin Reviewed-by: Philippe Mathieu-Daudé --- net/vhost-vdpa.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/vhost-vdpa.c b/net/vhost-vdpa.c index fe519d908d..650125bb0f 100644 --- a/net/vhost-vdpa.c +++ b/net/vhost-vdpa.c @@ -1368,7 +1368,7 @@ static int vhost_vdpa_probe_cvq_isolation(int device_fd, uint64_t features, r = ioctl(device_fd, VHOST_VDPA_SET_STATUS, &status); if (unlikely(r)) { - error_setg_errno(errp, -r, "Cannot set device features"); + error_setg_errno(errp, -r, "Cannot set status"); goto out; } From f1085882d028e5a1b227443cd6e96bbb63d66f43 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Eugenio=20P=C3=A9rez?= Date: Fri, 15 Sep 2023 19:08:35 +0200 Subject: [PATCH 0293/1077] vdpa net: stop probing if cannot set features MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Otherwise it continues the CVQ isolation probing. Fixes: 152128d646 ("vdpa: move CVQ isolation check to net_init_vhost_vdpa") Reported-by: Peter Maydell Signed-off-by: Eugenio Pérez Message-Id: <20230915170836.3078172-3-eperezma@redhat.com> Tested-by: Lei Yang Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin Reviewed-by: Philippe Mathieu-Daudé --- net/vhost-vdpa.c | 1 + 1 file changed, 1 insertion(+) diff --git a/net/vhost-vdpa.c b/net/vhost-vdpa.c index 650125bb0f..b688877f90 100644 --- a/net/vhost-vdpa.c +++ b/net/vhost-vdpa.c @@ -1364,6 +1364,7 @@ static int vhost_vdpa_probe_cvq_isolation(int device_fd, uint64_t features, r = ioctl(device_fd, VHOST_SET_FEATURES, &features); if (unlikely(r)) { error_setg_errno(errp, errno, "Cannot set features"); + goto out; } r = ioctl(device_fd, VHOST_VDPA_SET_STATUS, &status); From 845ec38ae1578dd2d42ff15c9979f1bf44b23418 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Eugenio=20P=C3=A9rez?= Date: Fri, 15 Sep 2023 19:08:36 +0200 Subject: [PATCH 0294/1077] vdpa net: follow VirtIO initialization properly at cvq isolation probing MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This patch solves a few issues. The most obvious is that the feature set was done previous to ACKNOWLEDGE | DRIVER status bit set. Current vdpa devices are permissive with this, but it is better to follow the standard. Fixes: 152128d646 ("vdpa: move CVQ isolation check to net_init_vhost_vdpa") Signed-off-by: Eugenio Pérez Message-Id: <20230915170836.3078172-4-eperezma@redhat.com> Tested-by: Lei Yang Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- net/vhost-vdpa.c | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/net/vhost-vdpa.c b/net/vhost-vdpa.c index b688877f90..939c984d5b 100644 --- a/net/vhost-vdpa.c +++ b/net/vhost-vdpa.c @@ -1345,8 +1345,7 @@ static int vhost_vdpa_probe_cvq_isolation(int device_fd, uint64_t features, uint64_t backend_features; int64_t cvq_group; uint8_t status = VIRTIO_CONFIG_S_ACKNOWLEDGE | - VIRTIO_CONFIG_S_DRIVER | - VIRTIO_CONFIG_S_FEATURES_OK; + VIRTIO_CONFIG_S_DRIVER; int r; ERRP_GUARD(); @@ -1361,15 +1360,22 @@ static int vhost_vdpa_probe_cvq_isolation(int device_fd, uint64_t features, return 0; } - r = ioctl(device_fd, VHOST_SET_FEATURES, &features); + r = ioctl(device_fd, VHOST_VDPA_SET_STATUS, &status); if (unlikely(r)) { - error_setg_errno(errp, errno, "Cannot set features"); + error_setg_errno(errp, -r, "Cannot set device status"); goto out; } + r = ioctl(device_fd, VHOST_SET_FEATURES, &features); + if (unlikely(r)) { + error_setg_errno(errp, -r, "Cannot set features"); + goto out; + } + + status |= VIRTIO_CONFIG_S_FEATURES_OK; r = ioctl(device_fd, VHOST_VDPA_SET_STATUS, &status); if (unlikely(r)) { - error_setg_errno(errp, -r, "Cannot set status"); + error_setg_errno(errp, -r, "Cannot set device status"); goto out; } From 0114c4513095598cdf1cd8d7dacdfff757628121 Mon Sep 17 00:00:00 2001 From: Akihiko Odaki Date: Thu, 21 Sep 2023 20:46:11 +0900 Subject: [PATCH 0295/1077] amd_iommu: Fix APIC address check An MSI from I/O APIC may not exactly equal to APIC_DEFAULT_ADDRESS. In fact, Windows 17763.3650 configures I/O APIC to set the dest_mode bit. Cover the range assigned to APIC. Fixes: 577c470f43 ("x86_iommu/amd: Prepare for interrupt remap support") Signed-off-by: Akihiko Odaki Message-Id: <20230921114612.40671-1-akihiko.odaki@daynix.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/i386/amd_iommu.c | 9 ++------- hw/i386/amd_iommu.h | 2 -- 2 files changed, 2 insertions(+), 9 deletions(-) diff --git a/hw/i386/amd_iommu.c b/hw/i386/amd_iommu.c index c98a3c6e11..8d0f2f99dd 100644 --- a/hw/i386/amd_iommu.c +++ b/hw/i386/amd_iommu.c @@ -1246,13 +1246,8 @@ static int amdvi_int_remap_msi(AMDVIState *iommu, return -AMDVI_IR_ERR; } - if (origin->address & AMDVI_MSI_ADDR_HI_MASK) { - trace_amdvi_err("MSI address high 32 bits non-zero when " - "Interrupt Remapping enabled."); - return -AMDVI_IR_ERR; - } - - if ((origin->address & AMDVI_MSI_ADDR_LO_MASK) != APIC_DEFAULT_ADDRESS) { + if (origin->address < AMDVI_INT_ADDR_FIRST || + origin->address + sizeof(origin->data) > AMDVI_INT_ADDR_LAST + 1) { trace_amdvi_err("MSI is not from IOAPIC."); return -AMDVI_IR_ERR; } diff --git a/hw/i386/amd_iommu.h b/hw/i386/amd_iommu.h index 6da893ee57..c5065a3e27 100644 --- a/hw/i386/amd_iommu.h +++ b/hw/i386/amd_iommu.h @@ -210,8 +210,6 @@ #define AMDVI_INT_ADDR_FIRST 0xfee00000 #define AMDVI_INT_ADDR_LAST 0xfeefffff #define AMDVI_INT_ADDR_SIZE (AMDVI_INT_ADDR_LAST - AMDVI_INT_ADDR_FIRST + 1) -#define AMDVI_MSI_ADDR_HI_MASK (0xffffffff00000000ULL) -#define AMDVI_MSI_ADDR_LO_MASK (0x00000000ffffffffULL) /* SB IOAPIC is always on this device in AMD systems */ #define AMDVI_IOAPIC_SB_DEVID PCI_BUILD_BDF(0, PCI_DEVFN(0x14, 0)) From cf0386509ece089213226855ae685e2228315ffe Mon Sep 17 00:00:00 2001 From: Ani Sinha Date: Fri, 22 Sep 2023 21:34:13 +0530 Subject: [PATCH 0296/1077] hw/i386/pc: improve physical address space bound check for 32-bit x86 systems 32-bit x86 systems do not have a reserved memory for hole64. On those 32-bit systems without PSE36 or PAE CPU features, hotplugging memory devices are not supported by QEMU as QEMU always places hotplugged memory above 4 GiB boundary which is beyond the physical address space of the processor. Linux guests also does not support memory hotplug on those systems. Please see Linux kernel commit b59d02ed08690 ("mm/memory_hotplug: disable the functionality for 32b") for more details. Therefore, the maximum limit of the guest physical address in the absence of additional memory devices effectively coincides with the end of "above 4G memory space" region for 32-bit x86 without PAE/PSE36. When users configure additional memory devices, after properly accounting for the additional device memory region to find the maximum value of the guest physical address, the address will be outside the range of the processor's physical address space. This change adds improvements to take above into consideration. For example, previously this was allowed: $ ./qemu-system-x86_64 -cpu pentium -m size=10G With this change now it is no longer allowed: $ ./qemu-system-x86_64 -cpu pentium -m size=10G qemu-system-x86_64: Address space limit 0xffffffff < 0x2bfffffff phys-bits too low (32) However, the following are allowed since on both cases physical address space of the processor is 36 bits: $ ./qemu-system-x86_64 -cpu pentium2 -m size=10G $ ./qemu-system-x86_64 -cpu pentium,pse36=on -m size=10G For 32-bit, without PAE/PSE36, hotplugging additional memory is no longer allowed. $ ./qemu-system-i386 -m size=1G,maxmem=3G,slots=2 qemu-system-i386: Address space limit 0xffffffff < 0x1ffffffff phys-bits too low (32) $ ./qemu-system-i386 -machine q35 -m size=1G,maxmem=3G,slots=2 qemu-system-i386: Address space limit 0xffffffff < 0x1ffffffff phys-bits too low (32) A new compatibility flag is introduced to make sure pc_max_used_gpa() keeps returning the old value for machines 8.1 and older. Therefore, the above is still allowed for older machine types in order to support compatibility. Hence, the following still works: $ ./qemu-system-i386 -machine pc-i440fx-8.1 -m size=1G,maxmem=3G,slots=2 $ ./qemu-system-i386 -machine pc-q35-8.1 -m size=1G,maxmem=3G,slots=2 Further, following is also allowed as with PSE36, the processor has 36-bit address space: $ ./qemu-system-i386 -cpu 486,pse36=on -m size=1G,maxmem=3G,slots=2 After calling CPUID with EAX=0x80000001, all AMD64 compliant processors have the longmode-capable-bit turned on in the extended feature flags (bit 29) in EDX. The absence of CPUID longmode can be used to differentiate between 32-bit and 64-bit processors and is the recommended approach. QEMU takes this approach elsewhere (for example, please see x86_cpu_realizefn()), With this change, pc_max_used_gpa() also uses the same method to detect 32-bit processors. Unit tests are modified to not run 32-bit x86 tests that use memory hotplug. Suggested-by: David Hildenbrand Signed-off-by: Ani Sinha Reviewed-by: David Hildenbrand Message-Id: <20230922160413.165702-1-anisinha@redhat.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/i386/pc.c | 32 +++++++++++++++++++++++++++++--- hw/i386/pc_piix.c | 4 ++++ hw/i386/pc_q35.c | 2 ++ include/hw/i386/pc.h | 6 ++++++ tests/qtest/bios-tables-test.c | 26 ++++++++++++++++++-------- tests/qtest/numa-test.c | 7 ++++++- 6 files changed, 65 insertions(+), 12 deletions(-) diff --git a/hw/i386/pc.c b/hw/i386/pc.c index 3db0743f31..a532d42cf4 100644 --- a/hw/i386/pc.c +++ b/hw/i386/pc.c @@ -907,13 +907,39 @@ static uint64_t pc_get_cxl_range_end(PCMachineState *pcms) static hwaddr pc_max_used_gpa(PCMachineState *pcms, uint64_t pci_hole64_size) { X86CPU *cpu = X86_CPU(first_cpu); + PCMachineClass *pcmc = PC_MACHINE_GET_CLASS(pcms); + MachineState *ms = MACHINE(pcms); - /* 32-bit systems don't have hole64 thus return max CPU address */ - if (cpu->phys_bits <= 32) { + if (cpu->env.features[FEAT_8000_0001_EDX] & CPUID_EXT2_LM) { + /* 64-bit systems */ + return pc_pci_hole64_start() + pci_hole64_size - 1; + } + + /* 32-bit systems */ + if (pcmc->broken_32bit_mem_addr_check) { + /* old value for compatibility reasons */ return ((hwaddr)1 << cpu->phys_bits) - 1; } - return pc_pci_hole64_start() + pci_hole64_size - 1; + /* + * 32-bit systems don't have hole64 but they might have a region for + * memory devices. Even if additional hotplugged memory devices might + * not be usable by most guest OSes, we need to still consider them for + * calculating the highest possible GPA so that we can properly report + * if someone configures them on a CPU that cannot possibly address them. + */ + if (pcmc->has_reserved_memory && + (ms->ram_size < ms->maxram_size)) { + hwaddr devmem_start; + ram_addr_t devmem_size; + + pc_get_device_memory_range(pcms, &devmem_start, &devmem_size); + devmem_start += devmem_size; + return devmem_start - 1; + } + + /* configuration without any memory hotplug */ + return pc_above_4g_end(pcms) - 1; } /* diff --git a/hw/i386/pc_piix.c b/hw/i386/pc_piix.c index 8321f36f97..71003759bb 100644 --- a/hw/i386/pc_piix.c +++ b/hw/i386/pc_piix.c @@ -517,9 +517,13 @@ DEFINE_I440FX_MACHINE(v8_2, "pc-i440fx-8.2", NULL, static void pc_i440fx_8_1_machine_options(MachineClass *m) { + PCMachineClass *pcmc = PC_MACHINE_CLASS(m); + pc_i440fx_8_2_machine_options(m); m->alias = NULL; m->is_default = false; + pcmc->broken_32bit_mem_addr_check = true; + compat_props_add(m->compat_props, hw_compat_8_1, hw_compat_8_1_len); compat_props_add(m->compat_props, pc_compat_8_1, pc_compat_8_1_len); } diff --git a/hw/i386/pc_q35.c b/hw/i386/pc_q35.c index 2dd1158b70..a7386f2ca2 100644 --- a/hw/i386/pc_q35.c +++ b/hw/i386/pc_q35.c @@ -394,8 +394,10 @@ DEFINE_Q35_MACHINE(v8_2, "pc-q35-8.2", NULL, static void pc_q35_8_1_machine_options(MachineClass *m) { + PCMachineClass *pcmc = PC_MACHINE_CLASS(m); pc_q35_8_2_machine_options(m); m->alias = NULL; + pcmc->broken_32bit_mem_addr_check = true; compat_props_add(m->compat_props, hw_compat_8_1, hw_compat_8_1_len); compat_props_add(m->compat_props, pc_compat_8_1, pc_compat_8_1_len); } diff --git a/include/hw/i386/pc.h b/include/hw/i386/pc.h index 0fabece236..bec38cb92c 100644 --- a/include/hw/i386/pc.h +++ b/include/hw/i386/pc.h @@ -129,6 +129,12 @@ struct PCMachineClass { /* resizable acpi blob compat */ bool resizable_acpi_blob; + + /* + * whether the machine type implements broken 32-bit address space bound + * check for memory. + */ + bool broken_32bit_mem_addr_check; }; #define TYPE_PC_MACHINE "generic-pc-machine" diff --git a/tests/qtest/bios-tables-test.c b/tests/qtest/bios-tables-test.c index d1b80149f2..f8e03dfd46 100644 --- a/tests/qtest/bios-tables-test.c +++ b/tests/qtest/bios-tables-test.c @@ -2080,7 +2080,6 @@ int main(int argc, char *argv[]) test_acpi_piix4_no_acpi_pci_hotplug); qtest_add_func("acpi/piix4/ipmi", test_acpi_piix4_tcg_ipmi); qtest_add_func("acpi/piix4/cpuhp", test_acpi_piix4_tcg_cphp); - qtest_add_func("acpi/piix4/memhp", test_acpi_piix4_tcg_memhp); qtest_add_func("acpi/piix4/numamem", test_acpi_piix4_tcg_numamem); qtest_add_func("acpi/piix4/nosmm", test_acpi_piix4_tcg_nosmm); qtest_add_func("acpi/piix4/smm-compat", @@ -2088,9 +2087,15 @@ int main(int argc, char *argv[]) qtest_add_func("acpi/piix4/smm-compat-nosmm", test_acpi_piix4_tcg_smm_compat_nosmm); qtest_add_func("acpi/piix4/nohpet", test_acpi_piix4_tcg_nohpet); - qtest_add_func("acpi/piix4/dimmpxm", test_acpi_piix4_tcg_dimm_pxm); - qtest_add_func("acpi/piix4/acpihmat", - test_acpi_piix4_tcg_acpi_hmat); + + /* i386 does not support memory hotplug */ + if (strcmp(arch, "i386")) { + qtest_add_func("acpi/piix4/memhp", test_acpi_piix4_tcg_memhp); + qtest_add_func("acpi/piix4/dimmpxm", + test_acpi_piix4_tcg_dimm_pxm); + qtest_add_func("acpi/piix4/acpihmat", + test_acpi_piix4_tcg_acpi_hmat); + } #ifdef CONFIG_POSIX qtest_add_func("acpi/piix4/acpierst", test_acpi_piix4_acpi_erst); #endif @@ -2108,11 +2113,9 @@ int main(int argc, char *argv[]) test_acpi_q35_tcg_no_acpi_hotplug); qtest_add_func("acpi/q35/multif-bridge", test_acpi_q35_multif_bridge); - qtest_add_func("acpi/q35/mmio64", test_acpi_q35_tcg_mmio64); qtest_add_func("acpi/q35/ipmi", test_acpi_q35_tcg_ipmi); qtest_add_func("acpi/q35/smbus/ipmi", test_acpi_q35_tcg_smbus_ipmi); qtest_add_func("acpi/q35/cpuhp", test_acpi_q35_tcg_cphp); - qtest_add_func("acpi/q35/memhp", test_acpi_q35_tcg_memhp); qtest_add_func("acpi/q35/numamem", test_acpi_q35_tcg_numamem); qtest_add_func("acpi/q35/nosmm", test_acpi_q35_tcg_nosmm); qtest_add_func("acpi/q35/smm-compat", @@ -2120,10 +2123,17 @@ int main(int argc, char *argv[]) qtest_add_func("acpi/q35/smm-compat-nosmm", test_acpi_q35_tcg_smm_compat_nosmm); qtest_add_func("acpi/q35/nohpet", test_acpi_q35_tcg_nohpet); - qtest_add_func("acpi/q35/dimmpxm", test_acpi_q35_tcg_dimm_pxm); - qtest_add_func("acpi/q35/acpihmat", test_acpi_q35_tcg_acpi_hmat); qtest_add_func("acpi/q35/acpihmat-noinitiator", test_acpi_q35_tcg_acpi_hmat_noinitiator); + + /* i386 does not support memory hotplug */ + if (strcmp(arch, "i386")) { + qtest_add_func("acpi/q35/memhp", test_acpi_q35_tcg_memhp); + qtest_add_func("acpi/q35/dimmpxm", test_acpi_q35_tcg_dimm_pxm); + qtest_add_func("acpi/q35/acpihmat", + test_acpi_q35_tcg_acpi_hmat); + qtest_add_func("acpi/q35/mmio64", test_acpi_q35_tcg_mmio64); + } #ifdef CONFIG_POSIX qtest_add_func("acpi/q35/acpierst", test_acpi_q35_acpi_erst); #endif diff --git a/tests/qtest/numa-test.c b/tests/qtest/numa-test.c index c5eb13f349..4f4404a4b1 100644 --- a/tests/qtest/numa-test.c +++ b/tests/qtest/numa-test.c @@ -568,7 +568,7 @@ int main(int argc, char **argv) qtest_add_data_func("/numa/mon/cpus/partial", args, test_mon_partial); qtest_add_data_func("/numa/qmp/cpus/query-cpus", args, test_query_cpus); - if (!strcmp(arch, "i386") || !strcmp(arch, "x86_64")) { + if (!strcmp(arch, "x86_64")) { qtest_add_data_func("/numa/pc/cpu/explicit", args, pc_numa_cpu); qtest_add_data_func("/numa/pc/dynamic/cpu", args, pc_dynamic_cpu_cfg); qtest_add_data_func("/numa/pc/hmat/build", args, pc_hmat_build_cfg); @@ -576,6 +576,11 @@ int main(int argc, char **argv) qtest_add_data_func("/numa/pc/hmat/erange", args, pc_hmat_erange_cfg); } + if (!strcmp(arch, "i386")) { + qtest_add_data_func("/numa/pc/cpu/explicit", args, pc_numa_cpu); + qtest_add_data_func("/numa/pc/dynamic/cpu", args, pc_dynamic_cpu_cfg); + } + if (!strcmp(arch, "ppc64")) { qtest_add_data_func("/numa/spapr/cpu/explicit", args, spapr_numa_cpu); } From f1a153857abc1ba8835b12a01520df9f1b64e15b Mon Sep 17 00:00:00 2001 From: Vladimir Sementsov-Ogievskiy Date: Mon, 25 Sep 2023 22:40:35 +0300 Subject: [PATCH 0297/1077] pcie_sriov: unregister_vfs(): fix error path local_err must be NULL before calling object_property_set_bool(), so we must clear it on each iteration. Let's also use more convenient error_reportf_err(). Signed-off-by: Vladimir Sementsov-Ogievskiy Message-Id: <20230925194040.68592-8-vsementsov@yandex-team.ru> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/pci/pcie_sriov.c | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/hw/pci/pcie_sriov.c b/hw/pci/pcie_sriov.c index 76a3b6917e..5ef8950940 100644 --- a/hw/pci/pcie_sriov.c +++ b/hw/pci/pcie_sriov.c @@ -196,19 +196,16 @@ static void register_vfs(PCIDevice *dev) static void unregister_vfs(PCIDevice *dev) { - Error *local_err = NULL; uint16_t num_vfs = dev->exp.sriov_pf.num_vfs; uint16_t i; trace_sriov_unregister_vfs(dev->name, PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn), num_vfs); for (i = 0; i < num_vfs; i++) { + Error *err = NULL; PCIDevice *vf = dev->exp.sriov_pf.vf[i]; - object_property_set_bool(OBJECT(vf), "realized", false, &local_err); - if (local_err) { - fprintf(stderr, "Failed to unplug: %s\n", - error_get_pretty(local_err)); - error_free(local_err); + if (!object_property_set_bool(OBJECT(vf), "realized", false, &err)) { + error_reportf_err(err, "Failed to unplug: "); } object_unparent(OBJECT(vf)); object_unref(OBJECT(vf)); From a6f4d2ec42f3feb6c399f5760a2567ca78897bd7 Mon Sep 17 00:00:00 2001 From: Vladimir Sementsov-Ogievskiy Date: Mon, 25 Sep 2023 22:40:32 +0300 Subject: [PATCH 0298/1077] libvhost-user.c: add assertion to vu_message_read_default Explain Coverity that we are not going to overflow vmsg->fds. Signed-off-by: Vladimir Sementsov-Ogievskiy Message-Id: <20230925194040.68592-5-vsementsov@yandex-team.ru> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- subprojects/libvhost-user/libvhost-user.c | 1 + 1 file changed, 1 insertion(+) diff --git a/subprojects/libvhost-user/libvhost-user.c b/subprojects/libvhost-user/libvhost-user.c index 0469a50101..49b57c7ef4 100644 --- a/subprojects/libvhost-user/libvhost-user.c +++ b/subprojects/libvhost-user/libvhost-user.c @@ -322,6 +322,7 @@ vu_message_read_default(VuDev *dev, int conn_fd, VhostUserMsg *vmsg) if (cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SCM_RIGHTS) { fd_size = cmsg->cmsg_len - CMSG_LEN(0); vmsg->fd_num = fd_size / sizeof(int); + assert(fd_size < VHOST_MEMORY_BASELINE_NREGIONS); memcpy(vmsg->fds, CMSG_DATA(cmsg), fd_size); break; } From 850cd20b072cd330cb24aa1c92732b9722998d40 Mon Sep 17 00:00:00 2001 From: Ilya Maximets Date: Wed, 27 Sep 2023 15:50:33 +0200 Subject: [PATCH 0299/1077] virtio: use shadow_avail_idx while checking number of heads We do not need the most up to date number of heads, we only want to know if there is at least one. Use shadow variable as long as it is not equal to the last available index checked. This avoids expensive qatomic dereference of the RCU-protected memory region cache as well as the memory access itself. The change improves performance of the af-xdp network backend by 2-3%. Signed-off-by: Ilya Maximets Message-Id: <20230927135157.2316982-1-i.maximets@ovn.org> Reviewed-by: Stefan Hajnoczi Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/virtio/virtio.c | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/hw/virtio/virtio.c b/hw/virtio/virtio.c index c727e9201b..2058b838e9 100644 --- a/hw/virtio/virtio.c +++ b/hw/virtio/virtio.c @@ -997,7 +997,12 @@ void virtqueue_push(VirtQueue *vq, const VirtQueueElement *elem, /* Called within rcu_read_lock(). */ static int virtqueue_num_heads(VirtQueue *vq, unsigned int idx) { - uint16_t num_heads = vring_avail_idx(vq) - idx; + uint16_t avail_idx, num_heads; + + /* Use shadow index whenever possible. */ + avail_idx = (vq->shadow_avail_idx != idx) ? vq->shadow_avail_idx + : vring_avail_idx(vq); + num_heads = avail_idx - idx; /* Check it isn't doing very strange things with descriptor numbers. */ if (num_heads > vq->vring.num) { @@ -1005,8 +1010,15 @@ static int virtqueue_num_heads(VirtQueue *vq, unsigned int idx) idx, vq->shadow_avail_idx); return -EINVAL; } - /* On success, callers read a descriptor at vq->last_avail_idx. - * Make sure descriptor read does not bypass avail index read. */ + /* + * On success, callers read a descriptor at vq->last_avail_idx. + * Make sure descriptor read does not bypass avail index read. + * + * This is necessary even if we are using a shadow index, since + * the shadow index could have been initialized by calling + * vring_avail_idx() outside of this function, i.e., by a guest + * memory read not accompanied by a barrier. + */ if (num_heads) { smp_rmb(); } From d501f97d9607eff1750549e0270c034102786d33 Mon Sep 17 00:00:00 2001 From: Ilya Maximets Date: Wed, 27 Sep 2023 15:59:41 +0200 Subject: [PATCH 0300/1077] virtio: remove unnecessary thread fence while reading next descriptor It was supposed to be a compiler barrier and it was a compiler barrier initially called 'wmb' when virtio core support was introduced. Later all the instances of 'wmb' were switched to smp_wmb to fix memory ordering issues on non-x86 platforms. However, this one doesn't need to be an actual barrier, as its only purpose was to ensure that the value is not read twice. And since commit aa570d6fb6bd ("virtio: combine the read of a descriptor") there is no need for a barrier at all, since we're no longer reading guest memory here, but accessing a local structure. Signed-off-by: Ilya Maximets Message-Id: <20230927140016.2317404-2-i.maximets@ovn.org> Reviewed-by: Stefan Hajnoczi Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/virtio/virtio.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/hw/virtio/virtio.c b/hw/virtio/virtio.c index 2058b838e9..87e8f990c5 100644 --- a/hw/virtio/virtio.c +++ b/hw/virtio/virtio.c @@ -1060,8 +1060,6 @@ static int virtqueue_split_read_next_desc(VirtIODevice *vdev, VRingDesc *desc, /* Check they're not leading us off end of descriptors. */ *next = desc->next; - /* Make sure compiler knows to grab that: we don't want it changing! */ - smp_wmb(); if (*next >= max) { virtio_error(vdev, "Desc next is %u", *next); From 70f88436aa5a8aeddd33e4d06270146af5d5bb52 Mon Sep 17 00:00:00 2001 From: Ilya Maximets Date: Wed, 27 Sep 2023 15:59:42 +0200 Subject: [PATCH 0301/1077] virtio: remove unused next argument from virtqueue_split_read_next_desc() The 'next' was converted from a local variable to an output parameter in commit: 412e0e81b174 ("virtio: handle virtqueue_read_next_desc() errors") But all the actual uses of the 'i/next' as an output were removed a few months prior in commit: aa570d6fb6bd ("virtio: combine the read of a descriptor") Remove the unused argument to simplify the code. Also, adding a comment to the function to describe what it is actually doing, as it is not obvious that the 'desc' is both an input and an output argument. Signed-off-by: Ilya Maximets Message-Id: <20230927140016.2317404-3-i.maximets@ovn.org> Reviewed-by: Stefan Hajnoczi Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/virtio/virtio.c | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/hw/virtio/virtio.c b/hw/virtio/virtio.c index 87e8f990c5..6facd64fbc 100644 --- a/hw/virtio/virtio.c +++ b/hw/virtio/virtio.c @@ -1049,9 +1049,10 @@ enum { VIRTQUEUE_READ_DESC_MORE = 1, /* more buffers in chain */ }; +/* Reads the 'desc->next' descriptor into '*desc'. */ static int virtqueue_split_read_next_desc(VirtIODevice *vdev, VRingDesc *desc, MemoryRegionCache *desc_cache, - unsigned int max, unsigned int *next) + unsigned int max) { /* If this descriptor says it doesn't chain, we're done. */ if (!(desc->flags & VRING_DESC_F_NEXT)) { @@ -1059,14 +1060,12 @@ static int virtqueue_split_read_next_desc(VirtIODevice *vdev, VRingDesc *desc, } /* Check they're not leading us off end of descriptors. */ - *next = desc->next; - - if (*next >= max) { - virtio_error(vdev, "Desc next is %u", *next); + if (desc->next >= max) { + virtio_error(vdev, "Desc next is %u", desc->next); return VIRTQUEUE_READ_DESC_ERROR; } - vring_split_desc_read(vdev, desc, desc_cache, *next); + vring_split_desc_read(vdev, desc, desc_cache, desc->next); return VIRTQUEUE_READ_DESC_MORE; } @@ -1146,7 +1145,7 @@ static void virtqueue_split_get_avail_bytes(VirtQueue *vq, goto done; } - rc = virtqueue_split_read_next_desc(vdev, &desc, desc_cache, max, &i); + rc = virtqueue_split_read_next_desc(vdev, &desc, desc_cache, max); } while (rc == VIRTQUEUE_READ_DESC_MORE); if (rc == VIRTQUEUE_READ_DESC_ERROR) { @@ -1601,7 +1600,7 @@ static void *virtqueue_split_pop(VirtQueue *vq, size_t sz) goto err_undo_map; } - rc = virtqueue_split_read_next_desc(vdev, &desc, desc_cache, max, &i); + rc = virtqueue_split_read_next_desc(vdev, &desc, desc_cache, max); } while (rc == VIRTQUEUE_READ_DESC_MORE); if (rc == VIRTQUEUE_READ_DESC_ERROR) { @@ -4055,8 +4054,7 @@ VirtioQueueElement *qmp_x_query_virtio_queue_element(const char *path, list = node; ndescs++; - rc = virtqueue_split_read_next_desc(vdev, &desc, desc_cache, - max, &i); + rc = virtqueue_split_read_next_desc(vdev, &desc, desc_cache, max); } while (rc == VIRTQUEUE_READ_DESC_MORE); element->descs = list; done: From a6ceee591acdb9c9c772bf59544a57891308222e Mon Sep 17 00:00:00 2001 From: Albert Esteve Date: Mon, 2 Oct 2023 08:57:03 +0200 Subject: [PATCH 0302/1077] util/uuid: add a hash function MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add hash function to uuid module using the djb2 hash algorithm. Add a couple simple unit tests for the hash function, checking collisions for similar UUIDs. Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Albert Esteve Message-Id: <20231002065706.94707-2-aesteve@redhat.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- include/qemu/uuid.h | 2 ++ tests/unit/test-uuid.c | 27 +++++++++++++++++++++++++++ util/uuid.c | 14 ++++++++++++++ 3 files changed, 43 insertions(+) diff --git a/include/qemu/uuid.h b/include/qemu/uuid.h index dc40ee1fc9..e24a1099e4 100644 --- a/include/qemu/uuid.h +++ b/include/qemu/uuid.h @@ -96,4 +96,6 @@ int qemu_uuid_parse(const char *str, QemuUUID *uuid); QemuUUID qemu_uuid_bswap(QemuUUID uuid); +uint32_t qemu_uuid_hash(const void *uuid); + #endif diff --git a/tests/unit/test-uuid.c b/tests/unit/test-uuid.c index c111de5fc1..aedc125ae9 100644 --- a/tests/unit/test-uuid.c +++ b/tests/unit/test-uuid.c @@ -171,6 +171,32 @@ static void test_uuid_unparse_strdup(void) } } +static void test_uuid_hash(void) +{ + QemuUUID uuid; + int i; + + for (i = 0; i < 100; i++) { + qemu_uuid_generate(&uuid); + /* Obtain the UUID hash */ + uint32_t hash_a = qemu_uuid_hash(&uuid); + int data_idx = g_random_int_range(0, 15); + /* Change a single random byte of the UUID */ + if (uuid.data[data_idx] < 0xFF) { + uuid.data[data_idx]++; + } else { + uuid.data[data_idx]--; + } + /* Obtain the UUID hash again */ + uint32_t hash_b = qemu_uuid_hash(&uuid); + /* + * Both hashes shall be different (avoid collision) + * for any change in the UUID fields + */ + g_assert_cmpint(hash_a, !=, hash_b); + } +} + int main(int argc, char **argv) { g_test_init(&argc, &argv, NULL); @@ -179,6 +205,7 @@ int main(int argc, char **argv) g_test_add_func("/uuid/parse", test_uuid_parse); g_test_add_func("/uuid/unparse", test_uuid_unparse); g_test_add_func("/uuid/unparse_strdup", test_uuid_unparse_strdup); + g_test_add_func("/uuid/hash", test_uuid_hash); return g_test_run(); } diff --git a/util/uuid.c b/util/uuid.c index b1108dde78..d71aa79e5e 100644 --- a/util/uuid.c +++ b/util/uuid.c @@ -116,3 +116,17 @@ QemuUUID qemu_uuid_bswap(QemuUUID uuid) bswap16s(&uuid.fields.time_high_and_version); return uuid; } + +/* djb2 hash algorithm */ +uint32_t qemu_uuid_hash(const void *uuid) +{ + QemuUUID *qid = (QemuUUID *) uuid; + uint32_t h = 5381; + int i; + + for (i = 0; i < ARRAY_SIZE(qid->data); i++) { + h = (h << 5) + h + qid->data[i]; + } + + return h; +} From faefdba8474fbc30427a64caa4dcd6df611f5b60 Mon Sep 17 00:00:00 2001 From: Albert Esteve Date: Mon, 2 Oct 2023 08:57:04 +0200 Subject: [PATCH 0303/1077] hw/display: introduce virtio-dmabuf MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This API manages objects (in this iteration, dmabuf fds) that can be shared along different virtio devices, associated to a UUID. The API allows the different devices to add, remove and/or retrieve the objects by simply invoking the public functions that reside in the virtio-dmabuf file. For vhost backends, the API stores the pointer to the backend holding the object. Suggested-by: Gerd Hoffmann Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Albert Esteve Message-Id: <20231002065706.94707-3-aesteve@redhat.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- MAINTAINERS | 7 ++ hw/display/meson.build | 1 + hw/display/virtio-dmabuf.c | 138 ++++++++++++++++++++++++++++++ include/hw/virtio/virtio-dmabuf.h | 100 ++++++++++++++++++++++ tests/unit/meson.build | 1 + tests/unit/test-virtio-dmabuf.c | 137 +++++++++++++++++++++++++++++ 6 files changed, 384 insertions(+) create mode 100644 hw/display/virtio-dmabuf.c create mode 100644 include/hw/virtio/virtio-dmabuf.h create mode 100644 tests/unit/test-virtio-dmabuf.c diff --git a/MAINTAINERS b/MAINTAINERS index 355b1960ce..5e27ce3ceb 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -2154,6 +2154,13 @@ T: git https://gitlab.com/cohuck/qemu.git s390-next T: git https://github.com/borntraeger/qemu.git s390-next L: qemu-s390x@nongnu.org +virtio-dmabuf +M: Albert Esteve +S: Supported +F: hw/display/virtio-dmabuf.c +F: include/hw/virtio/virtio-dmabuf.h +F: tests/unit/test-virtio-dmabuf.c + virtiofs M: Stefan Hajnoczi S: Supported diff --git a/hw/display/meson.build b/hw/display/meson.build index 413ba4ab24..05619c6968 100644 --- a/hw/display/meson.build +++ b/hw/display/meson.build @@ -37,6 +37,7 @@ system_ss.add(when: 'CONFIG_MACFB', if_true: files('macfb.c')) system_ss.add(when: 'CONFIG_NEXTCUBE', if_true: files('next-fb.c')) system_ss.add(when: 'CONFIG_VGA', if_true: files('vga.c')) +system_ss.add(when: 'CONFIG_VIRTIO', if_true: files('virtio-dmabuf.c')) if (config_all_devices.has_key('CONFIG_VGA_CIRRUS') or config_all_devices.has_key('CONFIG_VGA_PCI') or diff --git a/hw/display/virtio-dmabuf.c b/hw/display/virtio-dmabuf.c new file mode 100644 index 0000000000..4a8e430f3d --- /dev/null +++ b/hw/display/virtio-dmabuf.c @@ -0,0 +1,138 @@ +/* + * Virtio Shared dma-buf + * + * Copyright Red Hat, Inc. 2023 + * + * Authors: + * Albert Esteve + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + */ + +#include "qemu/osdep.h" + +#include "hw/virtio/virtio-dmabuf.h" + + +static GMutex lock; +static GHashTable *resource_uuids; + +/* + * uuid_equal_func: wrapper for UUID is_equal function to + * satisfy g_hash_table_new expected parameters signatures. + */ +static int uuid_equal_func(const void *lhv, const void *rhv) +{ + return qemu_uuid_is_equal(lhv, rhv); +} + +static bool virtio_add_resource(QemuUUID *uuid, VirtioSharedObject *value) +{ + bool result = false; + + g_mutex_lock(&lock); + if (resource_uuids == NULL) { + resource_uuids = g_hash_table_new_full(qemu_uuid_hash, + uuid_equal_func, + NULL, + g_free); + } + if (g_hash_table_lookup(resource_uuids, uuid) == NULL) { + result = g_hash_table_insert(resource_uuids, uuid, value); + } + g_mutex_unlock(&lock); + + return result; +} + +bool virtio_add_dmabuf(QemuUUID *uuid, int udmabuf_fd) +{ + bool result; + VirtioSharedObject *vso; + if (udmabuf_fd < 0) { + return false; + } + vso = g_new(VirtioSharedObject, 1); + vso->type = TYPE_DMABUF; + vso->value = GINT_TO_POINTER(udmabuf_fd); + result = virtio_add_resource(uuid, vso); + + return result; +} + +bool virtio_add_vhost_device(QemuUUID *uuid, struct vhost_dev *dev) +{ + bool result; + VirtioSharedObject *vso; + if (dev == NULL) { + return false; + } + vso = g_new(VirtioSharedObject, 1); + vso->type = TYPE_VHOST_DEV; + vso->value = dev; + result = virtio_add_resource(uuid, vso); + + return result; +} + +bool virtio_remove_resource(const QemuUUID *uuid) +{ + bool result; + g_mutex_lock(&lock); + result = g_hash_table_remove(resource_uuids, uuid); + g_mutex_unlock(&lock); + + return result; +} + +static VirtioSharedObject *get_shared_object(const QemuUUID *uuid) +{ + gpointer lookup_res = NULL; + + g_mutex_lock(&lock); + if (resource_uuids != NULL) { + lookup_res = g_hash_table_lookup(resource_uuids, uuid); + } + g_mutex_unlock(&lock); + + return (VirtioSharedObject *) lookup_res; +} + +int virtio_lookup_dmabuf(const QemuUUID *uuid) +{ + VirtioSharedObject *vso = get_shared_object(uuid); + if (vso == NULL) { + return -1; + } + assert(vso->type == TYPE_DMABUF); + return GPOINTER_TO_INT(vso->value); +} + +struct vhost_dev *virtio_lookup_vhost_device(const QemuUUID *uuid) +{ + VirtioSharedObject *vso = get_shared_object(uuid); + if (vso == NULL) { + return NULL; + } + assert(vso->type == TYPE_VHOST_DEV); + return (struct vhost_dev *) vso->value; +} + +SharedObjectType virtio_object_type(const QemuUUID *uuid) +{ + VirtioSharedObject *vso = get_shared_object(uuid); + if (vso == NULL) { + return TYPE_INVALID; + } + return vso->type; +} + +void virtio_free_resources(void) +{ + g_mutex_lock(&lock); + g_hash_table_destroy(resource_uuids); + /* Reference count shall be 0 after the implicit unref on destroy */ + resource_uuids = NULL; + g_mutex_unlock(&lock); +} diff --git a/include/hw/virtio/virtio-dmabuf.h b/include/hw/virtio/virtio-dmabuf.h new file mode 100644 index 0000000000..627c3b6db7 --- /dev/null +++ b/include/hw/virtio/virtio-dmabuf.h @@ -0,0 +1,100 @@ +/* + * Virtio Shared dma-buf + * + * Copyright Red Hat, Inc. 2023 + * + * Authors: + * Albert Esteve + * + * This work is licensed under the terms of the GNU GPL, version 2. + * See the COPYING file in the top-level directory. + */ + +#ifndef VIRTIO_DMABUF_H +#define VIRTIO_DMABUF_H + +#include "qemu/uuid.h" +#include "vhost.h" + +typedef enum SharedObjectType { + TYPE_INVALID = 0, + TYPE_DMABUF, + TYPE_VHOST_DEV, +} SharedObjectType; + +typedef struct VirtioSharedObject { + SharedObjectType type; + gpointer value; +} VirtioSharedObject; + +/** + * virtio_add_dmabuf() - Add a new dma-buf resource to the lookup table + * @uuid: new resource's UUID + * @dmabuf_fd: the dma-buf descriptor that will be stored and shared with + * other virtio devices. The caller retains ownership over the + * descriptor and its lifecycle. + * + * Note: @dmabuf_fd must be a valid (non-negative) file descriptor. + * + * Return: true if the UUID did not exist and the resource has been added, + * false if another resource with the same UUID already existed. + * Note that if it finds a repeated UUID, the resource is not inserted in + * the lookup table. + */ +bool virtio_add_dmabuf(QemuUUID *uuid, int dmabuf_fd); + +/** + * virtio_add_vhost_device() - Add a new exporter vhost device that holds the + * resource with the associated UUID + * @uuid: new resource's UUID + * @dev: the pointer to the vhost device that holds the resource. The caller + * retains ownership over the device struct and its lifecycle. + * + * Return: true if the UUID did not exist and the device has been tracked, + * false if another resource with the same UUID already existed. + * Note that if it finds a repeated UUID, the resource is not inserted in + * the lookup table. + */ +bool virtio_add_vhost_device(QemuUUID *uuid, struct vhost_dev *dev); + +/** + * virtio_remove_resource() - Removes a resource from the lookup table + * @uuid: resource's UUID + * + * Return: true if the UUID has been found and removed from the lookup table. + */ +bool virtio_remove_resource(const QemuUUID *uuid); + +/** + * virtio_lookup_dmabuf() - Looks for a dma-buf resource in the lookup table + * @uuid: resource's UUID + * + * Return: the dma-buf file descriptor integer, or -1 if the key is not found. + */ +int virtio_lookup_dmabuf(const QemuUUID *uuid); + +/** + * virtio_lookup_vhost_device() - Looks for an exporter vhost device in the + * lookup table + * @uuid: resource's UUID + * + * Return: pointer to the vhost_dev struct, or NULL if the key is not found. + */ +struct vhost_dev *virtio_lookup_vhost_device(const QemuUUID *uuid); + +/** + * virtio_object_type() - Looks for the type of resource in the lookup table + * @uuid: resource's UUID + * + * Return: the type of resource associated with the UUID, or TYPE_INVALID if + * the key is not found. + */ +SharedObjectType virtio_object_type(const QemuUUID *uuid); + +/** + * virtio_free_resources() - Destroys all keys and values of the shared + * resources lookup table, and frees them + */ +void virtio_free_resources(void); + +#endif /* VIRTIO_DMABUF_H */ diff --git a/tests/unit/meson.build b/tests/unit/meson.build index 0299ef6906..1977b302e2 100644 --- a/tests/unit/meson.build +++ b/tests/unit/meson.build @@ -50,6 +50,7 @@ tests = { 'test-qapi-util': [], 'test-interval-tree': [], 'test-xs-node': [qom], + 'test-virtio-dmabuf': [meson.project_source_root() / 'hw/display/virtio-dmabuf.c'], } if have_system or have_tools diff --git a/tests/unit/test-virtio-dmabuf.c b/tests/unit/test-virtio-dmabuf.c new file mode 100644 index 0000000000..a45ec52f42 --- /dev/null +++ b/tests/unit/test-virtio-dmabuf.c @@ -0,0 +1,137 @@ +/* + * QEMU tests for shared dma-buf API + * + * Copyright (c) 2023 Red Hat, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see . + * + */ + +#include "qemu/osdep.h" +#include "hw/virtio/virtio-dmabuf.h" + + +static void test_add_remove_resources(void) +{ + QemuUUID uuid; + int i, dmabuf_fd; + + for (i = 0; i < 100; ++i) { + qemu_uuid_generate(&uuid); + dmabuf_fd = g_random_int_range(3, 500); + /* Add a new resource */ + g_assert(virtio_add_dmabuf(&uuid, dmabuf_fd)); + g_assert_cmpint(virtio_lookup_dmabuf(&uuid), ==, dmabuf_fd); + /* Remove the resource */ + g_assert(virtio_remove_resource(&uuid)); + /* Resource is not found anymore */ + g_assert_cmpint(virtio_lookup_dmabuf(&uuid), ==, -1); + } +} + +static void test_add_remove_dev(void) +{ + QemuUUID uuid; + struct vhost_dev *dev = g_new0(struct vhost_dev, 1); + int i; + + for (i = 0; i < 100; ++i) { + qemu_uuid_generate(&uuid); + virtio_add_vhost_device(&uuid, dev); + /* vhost device is found */ + g_assert(virtio_lookup_vhost_device(&uuid) != NULL); + /* Remove the vhost device */ + g_assert(virtio_remove_resource(&uuid)); + /* vhost device is not found anymore */ + g_assert(virtio_lookup_vhost_device(&uuid) == NULL); + } + g_free(dev); +} + +static void test_remove_invalid_resource(void) +{ + QemuUUID uuid; + int i; + + for (i = 0; i < 20; ++i) { + qemu_uuid_generate(&uuid); + g_assert_cmpint(virtio_lookup_dmabuf(&uuid), ==, -1); + /* Removing a resource that does not exist returns false */ + g_assert_false(virtio_remove_resource(&uuid)); + } +} + +static void test_add_invalid_resource(void) +{ + QemuUUID uuid; + struct vhost_dev *dev = NULL; + int i, dmabuf_fd = -2, alt_dmabuf = 2; + + for (i = 0; i < 20; ++i) { + qemu_uuid_generate(&uuid); + /* Add a new resource with invalid (negative) resource fd */ + g_assert_false(virtio_add_dmabuf(&uuid, dmabuf_fd)); + /* Resource is not found */ + g_assert_cmpint(virtio_lookup_dmabuf(&uuid), ==, -1); + /* Add a new vhost device with invalid (NULL) pointer */ + g_assert_false(virtio_add_vhost_device(&uuid, dev)); + /* vhost device is not found */ + g_assert(virtio_lookup_vhost_device(&uuid) == NULL); + } + + for (i = 0; i < 20; ++i) { + /* Add a valid resource */ + qemu_uuid_generate(&uuid); + dmabuf_fd = g_random_int_range(3, 500); + g_assert(virtio_add_dmabuf(&uuid, dmabuf_fd)); + g_assert_cmpint(virtio_lookup_dmabuf(&uuid), ==, dmabuf_fd); + /* Add a new resource with repeated uuid returns false */ + g_assert_false(virtio_add_dmabuf(&uuid, alt_dmabuf)); + /* The value for the uuid key is not replaced */ + g_assert_cmpint(virtio_lookup_dmabuf(&uuid), ==, dmabuf_fd); + } +} + +static void test_free_resources(void) +{ + QemuUUID uuids[20]; + int i, dmabuf_fd; + + for (i = 0; i < ARRAY_SIZE(uuids); ++i) { + qemu_uuid_generate(&uuids[i]); + dmabuf_fd = g_random_int_range(3, 500); + g_assert(virtio_add_dmabuf(&uuids[i], dmabuf_fd)); + g_assert_cmpint(virtio_lookup_dmabuf(&uuids[i]), ==, dmabuf_fd); + } + virtio_free_resources(); + for (i = 0; i < ARRAY_SIZE(uuids); ++i) { + /* None of the resources is found after free'd */ + g_assert_cmpint(virtio_lookup_dmabuf(&uuids[i]), ==, -1); + } + +} + +int main(int argc, char **argv) +{ + g_test_init(&argc, &argv, NULL); + g_test_add_func("/virtio-dmabuf/add_rm_res", test_add_remove_resources); + g_test_add_func("/virtio-dmabuf/add_rm_dev", test_add_remove_dev); + g_test_add_func("/virtio-dmabuf/rm_invalid_res", + test_remove_invalid_resource); + g_test_add_func("/virtio-dmabuf/add_invalid_res", + test_add_invalid_resource); + g_test_add_func("/virtio-dmabuf/free_res", test_free_resources); + + return g_test_run(); +} From 160947666276c5b7f6bca4d746bcac2966635d79 Mon Sep 17 00:00:00 2001 From: Albert Esteve Date: Mon, 2 Oct 2023 08:57:05 +0200 Subject: [PATCH 0304/1077] vhost-user: add shared_object msg Add three new vhost-user protocol `VHOST_USER_BACKEND_SHARED_OBJECT_* messages`. These new messages are sent from vhost-user back-ends to interact with the virtio-dmabuf table in order to add or remove themselves as virtio exporters, or lookup for virtio dma-buf shared objects. The action taken in the front-end depends on the type stored in the virtio shared object hash table. When the table holds a pointer to a vhost backend for a given UUID, the front-end sends a VHOST_USER_GET_SHARED_OBJECT to the backend holding the shared object. The messages can only be sent after successfully negotiating a new VHOST_USER_PROTOCOL_F_SHARED_OBJECT vhost-user protocol feature bit. Finally, refactor code to send response message so that all common parts both for the common REPLY_ACK case, and other data responses, can call it and avoid code repetition. Signed-off-by: Albert Esteve Message-Id: <20231002065706.94707-4-aesteve@redhat.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- docs/interop/vhost-user.rst | 57 ++++++++++ hw/virtio/vhost-user.c | 167 +++++++++++++++++++++++++++--- include/hw/virtio/vhost-backend.h | 3 + include/hw/virtio/vhost-user.h | 1 + 4 files changed, 216 insertions(+), 12 deletions(-) diff --git a/docs/interop/vhost-user.rst b/docs/interop/vhost-user.rst index 5a070adbc1..415bb47a19 100644 --- a/docs/interop/vhost-user.rst +++ b/docs/interop/vhost-user.rst @@ -1440,6 +1440,18 @@ Front-end message types query the back-end for its device status as defined in the Virtio specification. +``VHOST_USER_GET_SHARED_OBJECT`` + :id: 41 + :equivalent ioctl: N/A + :request payload: ``struct VhostUserShared`` + :reply payload: dmabuf fd + + When the ``VHOST_USER_PROTOCOL_F_SHARED_OBJECT`` protocol + feature has been successfully negotiated, and the UUID is found + in the exporters cache, this message is submitted by the front-end + to retrieve a given dma-buf fd from a given back-end, determined by + the requested UUID. Back-end will reply passing the fd when the operation + is successful, or no fd otherwise. Back-end message types ---------------------- @@ -1528,6 +1540,51 @@ is sent by the front-end. The state.num field is currently reserved and must be set to 0. +``VHOST_USER_BACKEND_SHARED_OBJECT_ADD`` + :id: 6 + :equivalent ioctl: N/A + :request payload: ``struct VhostUserShared`` + :reply payload: N/A + + When the ``VHOST_USER_PROTOCOL_F_SHARED_OBJECT`` protocol + feature has been successfully negotiated, this message can be submitted + by the backends to add themselves as exporters to the virtio shared lookup + table. The back-end device gets associated with a UUID in the shared table. + The back-end is responsible of keeping its own table with exported dma-buf fds. + When another back-end tries to import the resource associated with the UUID, + it will send a message to the front-end, which will act as a proxy to the + exporter back-end. If ``VHOST_USER_PROTOCOL_F_REPLY_ACK`` is negotiated, and + the back-end sets the ``VHOST_USER_NEED_REPLY`` flag, the front-end must + respond with zero when operation is successfully completed, or non-zero + otherwise. + +``VHOST_USER_BACKEND_SHARED_OBJECT_REMOVE`` + :id: 7 + :equivalent ioctl: N/A + :request payload: ``struct VhostUserShared`` + :reply payload: N/A + + When the ``VHOST_USER_PROTOCOL_F_SHARED_OBJECT`` protocol + feature has been successfully negotiated, this message can be submitted + by the backend to remove themselves from to the virtio-dmabuf shared + table API. The shared table will remove the back-end device associated with + the UUID. If ``VHOST_USER_PROTOCOL_F_REPLY_ACK`` is negotiated, and the + back-end sets the ``VHOST_USER_NEED_REPLY`` flag, the front-end must respond + with zero when operation is successfully completed, or non-zero otherwise. + +``VHOST_USER_BACKEND_SHARED_OBJECT_LOOKUP`` + :id: 8 + :equivalent ioctl: N/A + :request payload: ``struct VhostUserShared`` + :reply payload: dmabuf fd and ``u64`` + + When the ``VHOST_USER_PROTOCOL_F_SHARED_OBJECT`` protocol + feature has been successfully negotiated, this message can be submitted + by the backends to retrieve a given dma-buf fd from the virtio-dmabuf + shared table given a UUID. Frontend will reply passing the fd and a zero + when the operation is successful, or non-zero otherwise. Note that if the + operation fails, no fd is sent to the backend. + .. _reply_ack: VHOST_USER_PROTOCOL_F_REPLY_ACK diff --git a/hw/virtio/vhost-user.c b/hw/virtio/vhost-user.c index a096335921..3766b415f8 100644 --- a/hw/virtio/vhost-user.c +++ b/hw/virtio/vhost-user.c @@ -10,6 +10,7 @@ #include "qemu/osdep.h" #include "qapi/error.h" +#include "hw/virtio/virtio-dmabuf.h" #include "hw/virtio/vhost.h" #include "hw/virtio/virtio-crypto.h" #include "hw/virtio/vhost-user.h" @@ -21,6 +22,7 @@ #include "sysemu/kvm.h" #include "qemu/error-report.h" #include "qemu/main-loop.h" +#include "qemu/uuid.h" #include "qemu/sockets.h" #include "sysemu/runstate.h" #include "sysemu/cryptodev.h" @@ -100,6 +102,7 @@ typedef enum VhostUserRequest { VHOST_USER_REM_MEM_REG = 38, VHOST_USER_SET_STATUS = 39, VHOST_USER_GET_STATUS = 40, + VHOST_USER_GET_SHARED_OBJECT = 41, VHOST_USER_MAX } VhostUserRequest; @@ -108,6 +111,9 @@ typedef enum VhostUserBackendRequest { VHOST_USER_BACKEND_IOTLB_MSG = 1, VHOST_USER_BACKEND_CONFIG_CHANGE_MSG = 2, VHOST_USER_BACKEND_VRING_HOST_NOTIFIER_MSG = 3, + VHOST_USER_BACKEND_SHARED_OBJECT_ADD = 6, + VHOST_USER_BACKEND_SHARED_OBJECT_REMOVE = 7, + VHOST_USER_BACKEND_SHARED_OBJECT_LOOKUP = 8, VHOST_USER_BACKEND_MAX } VhostUserBackendRequest; @@ -181,6 +187,10 @@ typedef struct VhostUserInflight { uint16_t queue_size; } VhostUserInflight; +typedef struct VhostUserShared { + unsigned char uuid[16]; +} VhostUserShared; + typedef struct { VhostUserRequest request; @@ -205,6 +215,7 @@ typedef union { VhostUserCryptoSession session; VhostUserVringArea area; VhostUserInflight inflight; + VhostUserShared object; } VhostUserPayload; typedef struct VhostUserMsg { @@ -1580,6 +1591,139 @@ static int vhost_user_backend_handle_vring_host_notifier(struct vhost_dev *dev, return 0; } +static int +vhost_user_backend_handle_shared_object_add(struct vhost_dev *dev, + VhostUserShared *object) +{ + QemuUUID uuid; + + memcpy(uuid.data, object->uuid, sizeof(object->uuid)); + return virtio_add_vhost_device(&uuid, dev); +} + +static int +vhost_user_backend_handle_shared_object_remove(VhostUserShared *object) +{ + QemuUUID uuid; + + memcpy(uuid.data, object->uuid, sizeof(object->uuid)); + return virtio_remove_resource(&uuid); +} + +static bool vhost_user_send_resp(QIOChannel *ioc, VhostUserHeader *hdr, + VhostUserPayload *payload, Error **errp) +{ + struct iovec iov[] = { + { .iov_base = hdr, .iov_len = VHOST_USER_HDR_SIZE }, + { .iov_base = payload, .iov_len = hdr->size }, + }; + + hdr->flags &= ~VHOST_USER_NEED_REPLY_MASK; + hdr->flags |= VHOST_USER_REPLY_MASK; + + return !qio_channel_writev_all(ioc, iov, ARRAY_SIZE(iov), errp); +} + +static bool +vhost_user_backend_send_dmabuf_fd(QIOChannel *ioc, VhostUserHeader *hdr, + VhostUserPayload *payload, Error **errp) +{ + hdr->size = sizeof(payload->u64); + return vhost_user_send_resp(ioc, hdr, payload, errp); +} + +int vhost_user_get_shared_object(struct vhost_dev *dev, unsigned char *uuid, + int *dmabuf_fd) +{ + struct vhost_user *u = dev->opaque; + CharBackend *chr = u->user->chr; + int ret; + VhostUserMsg msg = { + .hdr.request = VHOST_USER_GET_SHARED_OBJECT, + .hdr.flags = VHOST_USER_VERSION, + }; + memcpy(msg.payload.object.uuid, uuid, sizeof(msg.payload.object.uuid)); + + ret = vhost_user_write(dev, &msg, NULL, 0); + if (ret < 0) { + return ret; + } + + ret = vhost_user_read(dev, &msg); + if (ret < 0) { + return ret; + } + + if (msg.hdr.request != VHOST_USER_GET_SHARED_OBJECT) { + error_report("Received unexpected msg type. " + "Expected %d received %d", + VHOST_USER_GET_SHARED_OBJECT, msg.hdr.request); + return -EPROTO; + } + + *dmabuf_fd = qemu_chr_fe_get_msgfd(chr); + if (*dmabuf_fd < 0) { + error_report("Failed to get dmabuf fd"); + return -EIO; + } + + return 0; +} + +static int +vhost_user_backend_handle_shared_object_lookup(struct vhost_user *u, + QIOChannel *ioc, + VhostUserHeader *hdr, + VhostUserPayload *payload) +{ + QemuUUID uuid; + CharBackend *chr = u->user->chr; + Error *local_err = NULL; + int dmabuf_fd = -1; + int fd_num = 0; + + memcpy(uuid.data, payload->object.uuid, sizeof(payload->object.uuid)); + + payload->u64 = 0; + switch (virtio_object_type(&uuid)) { + case TYPE_DMABUF: + dmabuf_fd = virtio_lookup_dmabuf(&uuid); + break; + case TYPE_VHOST_DEV: + { + struct vhost_dev *dev = virtio_lookup_vhost_device(&uuid); + if (dev == NULL) { + payload->u64 = -EINVAL; + break; + } + int ret = vhost_user_get_shared_object(dev, uuid.data, &dmabuf_fd); + if (ret < 0) { + payload->u64 = ret; + } + break; + } + case TYPE_INVALID: + payload->u64 = -EINVAL; + break; + } + + if (dmabuf_fd != -1) { + fd_num++; + } + + if (qemu_chr_fe_set_msgfds(chr, &dmabuf_fd, fd_num) < 0) { + error_report("Failed to set msg fds."); + payload->u64 = -EINVAL; + } + + if (!vhost_user_backend_send_dmabuf_fd(ioc, hdr, payload, &local_err)) { + error_report_err(local_err); + return -EINVAL; + } + + return 0; +} + static void close_backend_channel(struct vhost_user *u) { g_source_destroy(u->backend_src); @@ -1637,6 +1781,16 @@ static gboolean backend_read(QIOChannel *ioc, GIOCondition condition, ret = vhost_user_backend_handle_vring_host_notifier(dev, &payload.area, fd ? fd[0] : -1); break; + case VHOST_USER_BACKEND_SHARED_OBJECT_ADD: + ret = vhost_user_backend_handle_shared_object_add(dev, &payload.object); + break; + case VHOST_USER_BACKEND_SHARED_OBJECT_REMOVE: + ret = vhost_user_backend_handle_shared_object_remove(&payload.object); + break; + case VHOST_USER_BACKEND_SHARED_OBJECT_LOOKUP: + ret = vhost_user_backend_handle_shared_object_lookup(dev->opaque, ioc, + &hdr, &payload); + break; default: error_report("Received unexpected msg type: %d.", hdr.request); ret = -EINVAL; @@ -1647,21 +1801,10 @@ static gboolean backend_read(QIOChannel *ioc, GIOCondition condition, * directly in their request handlers. */ if (hdr.flags & VHOST_USER_NEED_REPLY_MASK) { - struct iovec iovec[2]; - - - hdr.flags &= ~VHOST_USER_NEED_REPLY_MASK; - hdr.flags |= VHOST_USER_REPLY_MASK; - payload.u64 = !!ret; hdr.size = sizeof(payload.u64); - iovec[0].iov_base = &hdr; - iovec[0].iov_len = VHOST_USER_HDR_SIZE; - iovec[1].iov_base = &payload; - iovec[1].iov_len = hdr.size; - - if (qio_channel_writev_all(ioc, iovec, ARRAY_SIZE(iovec), &local_err)) { + if (!vhost_user_send_resp(ioc, &hdr, &payload, &local_err)) { error_report_err(local_err); goto err; } diff --git a/include/hw/virtio/vhost-backend.h b/include/hw/virtio/vhost-backend.h index 31a251a9f5..1860b541d8 100644 --- a/include/hw/virtio/vhost-backend.h +++ b/include/hw/virtio/vhost-backend.h @@ -196,4 +196,7 @@ int vhost_backend_handle_iotlb_msg(struct vhost_dev *dev, int vhost_user_gpu_set_socket(struct vhost_dev *dev, int fd); +int vhost_user_get_shared_object(struct vhost_dev *dev, unsigned char *uuid, + int *dmabuf_fd); + #endif /* VHOST_BACKEND_H */ diff --git a/include/hw/virtio/vhost-user.h b/include/hw/virtio/vhost-user.h index 80e2b4a463..9f9ddf878d 100644 --- a/include/hw/virtio/vhost-user.h +++ b/include/hw/virtio/vhost-user.h @@ -29,6 +29,7 @@ enum VhostUserProtocolFeature { VHOST_USER_PROTOCOL_F_INBAND_NOTIFICATIONS = 14, VHOST_USER_PROTOCOL_F_CONFIGURE_MEM_SLOTS = 15, VHOST_USER_PROTOCOL_F_STATUS = 16, + VHOST_USER_PROTOCOL_F_SHARED_OBJECT = 17, VHOST_USER_PROTOCOL_F_MAX }; From ce0f3b032a960726c0dddfb4f81f223215179f26 Mon Sep 17 00:00:00 2001 From: Albert Esteve Date: Mon, 2 Oct 2023 08:57:06 +0200 Subject: [PATCH 0305/1077] libvhost-user: handle shared_object msg In the libvhost-user library we need to handle VHOST_USER_GET_SHARED_OBJECT requests, and add helper functions to allow sending messages to interact with the virtio shared objects hash table. Signed-off-by: Albert Esteve Message-Id: <20231002065706.94707-5-aesteve@redhat.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- subprojects/libvhost-user/libvhost-user.c | 120 ++++++++++++++++++++++ subprojects/libvhost-user/libvhost-user.h | 55 +++++++++- 2 files changed, 174 insertions(+), 1 deletion(-) diff --git a/subprojects/libvhost-user/libvhost-user.c b/subprojects/libvhost-user/libvhost-user.c index 49b57c7ef4..051a611da3 100644 --- a/subprojects/libvhost-user/libvhost-user.c +++ b/subprojects/libvhost-user/libvhost-user.c @@ -161,6 +161,7 @@ vu_request_to_string(unsigned int req) REQ(VHOST_USER_GET_MAX_MEM_SLOTS), REQ(VHOST_USER_ADD_MEM_REG), REQ(VHOST_USER_REM_MEM_REG), + REQ(VHOST_USER_GET_SHARED_OBJECT), REQ(VHOST_USER_MAX), }; #undef REQ @@ -901,6 +902,24 @@ vu_rem_mem_reg(VuDev *dev, VhostUserMsg *vmsg) { return false; } +static bool +vu_get_shared_object(VuDev *dev, VhostUserMsg *vmsg) +{ + int fd_num = 0; + int dmabuf_fd = -1; + if (dev->iface->get_shared_object) { + dmabuf_fd = dev->iface->get_shared_object( + dev, &vmsg->payload.object.uuid[0]); + } + if (dmabuf_fd != -1) { + DPRINT("dmabuf_fd found for requested UUID\n"); + vmsg->fds[fd_num++] = dmabuf_fd; + } + vmsg->fd_num = fd_num; + + return true; +} + static bool vu_set_mem_table_exec_postcopy(VuDev *dev, VhostUserMsg *vmsg) { @@ -1404,6 +1423,105 @@ bool vu_set_queue_host_notifier(VuDev *dev, VuVirtq *vq, int fd, return vu_process_message_reply(dev, &vmsg); } +bool +vu_lookup_shared_object(VuDev *dev, unsigned char uuid[UUID_LEN], + int *dmabuf_fd) +{ + bool result = false; + VhostUserMsg msg_reply; + VhostUserMsg msg = { + .request = VHOST_USER_BACKEND_SHARED_OBJECT_LOOKUP, + .size = sizeof(msg.payload.object), + .flags = VHOST_USER_VERSION | VHOST_USER_NEED_REPLY_MASK, + }; + + memcpy(msg.payload.object.uuid, uuid, sizeof(uuid[0]) * UUID_LEN); + + if (!vu_has_protocol_feature(dev, VHOST_USER_PROTOCOL_F_SHARED_OBJECT)) { + return false; + } + + pthread_mutex_lock(&dev->backend_mutex); + if (!vu_message_write(dev, dev->backend_fd, &msg)) { + goto out; + } + + if (!vu_message_read_default(dev, dev->backend_fd, &msg_reply)) { + goto out; + } + + if (msg_reply.request != msg.request) { + DPRINT("Received unexpected msg type. Expected %d, received %d", + msg.request, msg_reply.request); + goto out; + } + + if (msg_reply.fd_num != 1) { + DPRINT("Received unexpected number of fds. Expected 1, received %d", + msg_reply.fd_num); + goto out; + } + + *dmabuf_fd = msg_reply.fds[0]; + result = *dmabuf_fd > 0 && msg_reply.payload.u64 == 0; +out: + pthread_mutex_unlock(&dev->backend_mutex); + + return result; +} + +static bool +vu_send_message(VuDev *dev, VhostUserMsg *vmsg) +{ + bool result = false; + pthread_mutex_lock(&dev->backend_mutex); + if (!vu_message_write(dev, dev->backend_fd, vmsg)) { + goto out; + } + + result = true; +out: + pthread_mutex_unlock(&dev->backend_mutex); + + return result; +} + +bool +vu_add_shared_object(VuDev *dev, unsigned char uuid[UUID_LEN]) +{ + VhostUserMsg msg = { + .request = VHOST_USER_BACKEND_SHARED_OBJECT_ADD, + .size = sizeof(msg.payload.object), + .flags = VHOST_USER_VERSION, + }; + + memcpy(msg.payload.object.uuid, uuid, sizeof(uuid[0]) * UUID_LEN); + + if (!vu_has_protocol_feature(dev, VHOST_USER_PROTOCOL_F_SHARED_OBJECT)) { + return false; + } + + return vu_send_message(dev, &msg); +} + +bool +vu_rm_shared_object(VuDev *dev, unsigned char uuid[UUID_LEN]) +{ + VhostUserMsg msg = { + .request = VHOST_USER_BACKEND_SHARED_OBJECT_REMOVE, + .size = sizeof(msg.payload.object), + .flags = VHOST_USER_VERSION, + }; + + memcpy(msg.payload.object.uuid, uuid, sizeof(uuid[0]) * UUID_LEN); + + if (!vu_has_protocol_feature(dev, VHOST_USER_PROTOCOL_F_SHARED_OBJECT)) { + return false; + } + + return vu_send_message(dev, &msg); +} + static bool vu_set_vring_call_exec(VuDev *dev, VhostUserMsg *vmsg) { @@ -1944,6 +2062,8 @@ vu_process_message(VuDev *dev, VhostUserMsg *vmsg) return vu_add_mem_reg(dev, vmsg); case VHOST_USER_REM_MEM_REG: return vu_rem_mem_reg(dev, vmsg); + case VHOST_USER_GET_SHARED_OBJECT: + return vu_get_shared_object(dev, vmsg); default: vmsg_close_fds(vmsg); vu_panic(dev, "Unhandled request: %d", vmsg->request); diff --git a/subprojects/libvhost-user/libvhost-user.h b/subprojects/libvhost-user/libvhost-user.h index 708370c5f5..b36a42a7ca 100644 --- a/subprojects/libvhost-user/libvhost-user.h +++ b/subprojects/libvhost-user/libvhost-user.h @@ -64,7 +64,8 @@ enum VhostUserProtocolFeature { VHOST_USER_PROTOCOL_F_INFLIGHT_SHMFD = 12, VHOST_USER_PROTOCOL_F_INBAND_NOTIFICATIONS = 14, VHOST_USER_PROTOCOL_F_CONFIGURE_MEM_SLOTS = 15, - + /* Feature 16 is reserved for VHOST_USER_PROTOCOL_F_STATUS. */ + VHOST_USER_PROTOCOL_F_SHARED_OBJECT = 17, VHOST_USER_PROTOCOL_F_MAX }; @@ -109,6 +110,7 @@ typedef enum VhostUserRequest { VHOST_USER_GET_MAX_MEM_SLOTS = 36, VHOST_USER_ADD_MEM_REG = 37, VHOST_USER_REM_MEM_REG = 38, + VHOST_USER_GET_SHARED_OBJECT = 41, VHOST_USER_MAX } VhostUserRequest; @@ -119,6 +121,9 @@ typedef enum VhostUserBackendRequest { VHOST_USER_BACKEND_VRING_HOST_NOTIFIER_MSG = 3, VHOST_USER_BACKEND_VRING_CALL = 4, VHOST_USER_BACKEND_VRING_ERR = 5, + VHOST_USER_BACKEND_SHARED_OBJECT_ADD = 6, + VHOST_USER_BACKEND_SHARED_OBJECT_REMOVE = 7, + VHOST_USER_BACKEND_SHARED_OBJECT_LOOKUP = 8, VHOST_USER_BACKEND_MAX } VhostUserBackendRequest; @@ -172,6 +177,12 @@ typedef struct VhostUserInflight { uint16_t queue_size; } VhostUserInflight; +#define UUID_LEN 16 + +typedef struct VhostUserShared { + unsigned char uuid[UUID_LEN]; +} VhostUserShared; + #if defined(_WIN32) && (defined(__x86_64__) || defined(__i386__)) # define VU_PACKED __attribute__((gcc_struct, packed)) #else @@ -199,6 +210,7 @@ typedef struct VhostUserMsg { VhostUserConfig config; VhostUserVringArea area; VhostUserInflight inflight; + VhostUserShared object; } payload; int fds[VHOST_MEMORY_BASELINE_NREGIONS]; @@ -232,6 +244,7 @@ typedef int (*vu_get_config_cb) (VuDev *dev, uint8_t *config, uint32_t len); typedef int (*vu_set_config_cb) (VuDev *dev, const uint8_t *data, uint32_t offset, uint32_t size, uint32_t flags); +typedef int (*vu_get_shared_object_cb) (VuDev *dev, const unsigned char *uuid); typedef struct VuDevIface { /* called by VHOST_USER_GET_FEATURES to get the features bitmask */ @@ -258,6 +271,8 @@ typedef struct VuDevIface { vu_get_config_cb get_config; /* set the config space of the device */ vu_set_config_cb set_config; + /* get virtio shared object from the underlying vhost implementation. */ + vu_get_shared_object_cb get_shared_object; } VuDevIface; typedef void (*vu_queue_handler_cb) (VuDev *dev, int qidx); @@ -541,6 +556,44 @@ void vu_set_queue_handler(VuDev *dev, VuVirtq *vq, bool vu_set_queue_host_notifier(VuDev *dev, VuVirtq *vq, int fd, int size, int offset); +/** + * vu_lookup_shared_object: + * @dev: a VuDev context + * @uuid: UUID of the shared object + * @dmabuf_fd: output dma-buf file descriptor + * + * Lookup for a virtio shared object (i.e., dma-buf fd) associated with the + * received UUID. Result, if found, is stored in the dmabuf_fd argument. + * + * Returns: whether the virtio object was found. + */ +bool vu_lookup_shared_object(VuDev *dev, unsigned char uuid[UUID_LEN], + int *dmabuf_fd); + +/** + * vu_add_shared_object: + * @dev: a VuDev context + * @uuid: UUID of the shared object + * + * Registers this back-end as the exporter for the object associated with + * the received UUID. + * + * Returns: TRUE on success, FALSE on failure. + */ +bool vu_add_shared_object(VuDev *dev, unsigned char uuid[UUID_LEN]); + +/** + * vu_rm_shared_object: + * @dev: a VuDev context + * @uuid: UUID of the shared object + * + * Removes a shared object entry (i.e., back-end entry) associated with the + * received UUID key from the hash table. + * + * Returns: TRUE on success, FALSE on failure. + */ +bool vu_rm_shared_object(VuDev *dev, unsigned char uuid[UUID_LEN]); + /** * vu_queue_set_notification: * @dev: a VuDev context From 994679b98abc320149b30209cfa93dfe66160c50 Mon Sep 17 00:00:00 2001 From: Andrey Drobyshev Date: Wed, 27 Sep 2023 09:38:17 -0500 Subject: [PATCH 0306/1077] mailmap: Fix Andrey Drobyshev author email MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This fixes authorship of commits 2848289168, 52b10c9c0c as the mailing list rewrote the "From:" field in the corresponding patches. See commit 3bd2608db7 ("maint: Add .mailmap entries for patches claiming list authorship") for explanation. Signed-off-by: Andrey Drobyshev Message-ID: <20230926102801.512107-1-andrey.drobyshev@virtuozzo.com> Reviewed-by: Eric Blake Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Eric Blake --- .mailmap | 1 + 1 file changed, 1 insertion(+) diff --git a/.mailmap b/.mailmap index 64ef9f4de6..04a7feb005 100644 --- a/.mailmap +++ b/.mailmap @@ -46,6 +46,7 @@ Ian McKellar Ian McKellar via Qemu-devel Julia Suvorova via Qemu-devel Justin Terry (VM) Justin Terry (VM) via Qemu-devel Stefan Weil Stefan Weil via +Andrey Drobyshev Andrey Drobyshev via # Next, replace old addresses by a more recent one. Aleksandar Markovic From 8a18f28c00ba6bdb5a6f18d6cc6560adfa1e4d0f Mon Sep 17 00:00:00 2001 From: Eric Blake Date: Wed, 27 Sep 2023 09:38:18 -0500 Subject: [PATCH 0307/1077] maint: Tweak comments in mailmap regarding SPF Documenting that we should not add new lines to work around SPF rewrites sounds foreboding; the intent is instead that new lines here are okay, but indicate a second problem elsewhere in our build process that we should also consider fixing at the same time, to keep the section from growing without bounds. While we have been doing that for qemu-devel for a while, we jut recently fixed that for qemu-block: https://git.linaro.org/people/pmaydell/misc-scripts.git/commit/?id=f9a317392 Mentioning DMARC alongside SPF may also help people grep for this scenario, as well as documenting the 'git config' workaround that can be used by submitters to avoid the munging issue in the first place. Note the subtlety: 'git commit' sets authorship information based on user.name and user.email (where name is usually unquoted); while 'git send-email' includes a body 'From:' line only when sendemail.from is present but differs from authorship information. Hence the use of quotes in sendemail.from (not a semantic change to email, but enough of a difference to add the body 'From:'). Fixes: 3bd2608d ("maint: Add .mailmap entries for patches claiming list authorship") CC: Andrey Drobyshev Cc: Peter Maydell Signed-off-by: Eric Blake Message-ID: <20230927143815.3397386-7-eblake@redhat.com> Reviewed-by: Peter Maydell --- .mailmap | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/.mailmap b/.mailmap index 04a7feb005..fadf6e7450 100644 --- a/.mailmap +++ b/.mailmap @@ -40,7 +40,19 @@ Nick Hudson hnick@vmware.com # for the cvs2svn initialization commit e63c3dc74bf. # Next, translate a few commits where mailman rewrote the From: line due -# to strict SPF, although we prefer to avoid adding more entries like that. +# to strict SPF and DMARC. Usually, our build process should be flagging +# commits like these before maintainer merges; if you find the need to add +# a line here, please also report a bug against the part of the build +# process that let the mis-attribution slip through in the first place. +# +# If the mailing list munges your emails, use: +# git config sendemail.from '"Your Name" ' +# the use of "" in that line will differ from the typically unquoted +# 'git config user.name', which in turn is sufficient for 'git send-email' +# to add an extra From: line in the body of your email that takes +# precedence over any munged From: in the mail's headers. +# See https://lists.openembedded.org/g/openembedded-core/message/166515 +# and https://lists.gnu.org/archive/html/qemu-devel/2023-09/msg06784.html Ed Swierk Ed Swierk via Qemu-devel Ian McKellar Ian McKellar via Qemu-devel Julia Suvorova Julia Suvorova via Qemu-devel From a960a27ed093dabf891e3f727ec4494479e359fa Mon Sep 17 00:00:00 2001 From: Eric Blake Date: Wed, 27 Sep 2023 09:38:19 -0500 Subject: [PATCH 0308/1077] mailmap: Fix BALATON Zoltan author email This fixes authorship of commits 5cbd51a5 and friends, where the qemu-ppc mailing list rewrote the "From:" field in the corresponding patches. See commit 3bd2608db7 ("maint: Add .mailmap entries for patches claiming list authorship") for explanation. Signed-off-by: Eric Blake Message-ID: <20230927143815.3397386-8-eblake@redhat.com> --- .mailmap | 1 + 1 file changed, 1 insertion(+) diff --git a/.mailmap b/.mailmap index fadf6e7450..d214959288 100644 --- a/.mailmap +++ b/.mailmap @@ -59,6 +59,7 @@ Julia Suvorova Julia Suvorova via Qemu-devel Justin Terry (VM) via Qemu-devel Stefan Weil Stefan Weil via Andrey Drobyshev Andrey Drobyshev via +BALATON Zoltan BALATON Zoltan via # Next, replace old addresses by a more recent one. Aleksandar Markovic From 009cd8665095a04115940704d680a52dcc49d489 Mon Sep 17 00:00:00 2001 From: Eric Blake Date: Mon, 25 Sep 2023 14:22:31 -0500 Subject: [PATCH 0309/1077] nbd/server: Support a request payload Upcoming additions to support NBD 64-bit effect lengths allow for the possibility to distinguish between payload length (capped at 32M) and effect length (64 bits, although we generally assume 63 bits because of off_t limitations). Without that extension, only the NBD_CMD_WRITE request has a payload; but with the extension, it makes sense to allow at least NBD_CMD_BLOCK_STATUS to have both a payload and effect length in a future patch (where the payload is a limited-size struct that in turn gives the real effect length as well as a subset of known ids for which status is requested). Other future NBD commands may also have a request payload, so the 64-bit extension introduces a new NBD_CMD_FLAG_PAYLOAD_LEN that distinguishes between whether the header length is a payload length or an effect length, rather than hard-coding the decision based on the command. According to the spec, a client should never send a command with a payload without the negotiation phase proving such extension is available. So in the unlikely event the bit is set or cleared incorrectly, the client is already at fault; if the client then provides the payload, we can gracefully consume it off the wire and fail the command with NBD_EINVAL (subsequent checks for magic numbers ensure we are still in sync), while if the client fails to send payload we block waiting for it (basically deadlocking our connection to the bad client, but not negatively impacting our ability to service other clients, so not a security risk). Note that we do not support the payload version of BLOCK_STATUS yet. This patch also fixes a latent bug introduced in b2578459: once request->len can be 64 bits, assigning it to a 32-bit payload_len can cause wraparound to 0 which then sets req->complete prematurely; thankfully, the bug was not possible back then (it takes this and later patches to even allow request->len larger than 32 bits; and since previously the only 'payload_len = request->len' assignment was in NBD_CMD_WRITE which also sets check_length, which in turn rejects lengths larger than 32M before relying on any possibly-truncated value stored in payload_len). Signed-off-by: Eric Blake Message-ID: <20230925192229.3186470-15-eblake@redhat.com> Reviewed-by: Vladimir Sementsov-Ogievskiy [eblake: enhance comment on handling client error, fix type bug] Signed-off-by: Eric Blake --- nbd/server.c | 42 +++++++++++++++++++++++++++++++++++++----- nbd/trace-events | 1 + 2 files changed, 38 insertions(+), 5 deletions(-) diff --git a/nbd/server.c b/nbd/server.c index 7a6f95071f..56e9b41828 100644 --- a/nbd/server.c +++ b/nbd/server.c @@ -2322,10 +2322,12 @@ static int coroutine_fn nbd_co_receive_request(NBDRequestData *req, Error **errp) { NBDClient *client = req->client; + bool extended_with_payload; bool check_length = false; bool check_rofs = false; bool allocate_buffer = false; - unsigned payload_len = 0; + bool payload_okay = false; + uint64_t payload_len = 0; int valid_flags = NBD_CMD_FLAG_FUA; int ret; @@ -2338,6 +2340,13 @@ static int coroutine_fn nbd_co_receive_request(NBDRequestData *req, trace_nbd_co_receive_request_decode_type(request->cookie, request->type, nbd_cmd_lookup(request->type)); + extended_with_payload = client->mode >= NBD_MODE_EXTENDED && + request->flags & NBD_CMD_FLAG_PAYLOAD_LEN; + if (extended_with_payload) { + payload_len = request->len; + check_length = true; + } + switch (request->type) { case NBD_CMD_DISC: /* Special case: we're going to disconnect without a reply, @@ -2354,6 +2363,15 @@ static int coroutine_fn nbd_co_receive_request(NBDRequestData *req, break; case NBD_CMD_WRITE: + if (client->mode >= NBD_MODE_EXTENDED) { + if (!extended_with_payload) { + /* The client is noncompliant. Trace it, but proceed. */ + trace_nbd_co_receive_ext_payload_compliance(request->from, + request->len); + } + valid_flags |= NBD_CMD_FLAG_PAYLOAD_LEN; + } + payload_okay = true; payload_len = request->len; check_length = true; allocate_buffer = true; @@ -2395,6 +2413,16 @@ static int coroutine_fn nbd_co_receive_request(NBDRequestData *req, request->len, NBD_MAX_BUFFER_SIZE); return -EINVAL; } + if (payload_len && !payload_okay) { + /* + * For now, we don't support payloads on other commands; but + * we can keep the connection alive by ignoring the payload. + * We will fail the command later with NBD_EINVAL for the use + * of an unsupported flag (and not for access beyond bounds). + */ + assert(request->type != NBD_CMD_WRITE); + request->len = 0; + } if (allocate_buffer) { /* READ, WRITE */ req->data = blk_try_blockalign(client->exp->common.blk, @@ -2405,10 +2433,14 @@ static int coroutine_fn nbd_co_receive_request(NBDRequestData *req, } } if (payload_len) { - /* WRITE */ - assert(req->data); - ret = nbd_read(client->ioc, req->data, payload_len, - "CMD_WRITE data", errp); + if (payload_okay) { + /* WRITE */ + assert(req->data); + ret = nbd_read(client->ioc, req->data, payload_len, + "CMD_WRITE data", errp); + } else { + ret = nbd_drop(client->ioc, payload_len, errp); + } if (ret < 0) { return -EIO; } diff --git a/nbd/trace-events b/nbd/trace-events index f9dccfcfb4..c1a3227613 100644 --- a/nbd/trace-events +++ b/nbd/trace-events @@ -71,6 +71,7 @@ nbd_co_send_extents(uint64_t cookie, unsigned int extents, uint32_t id, uint64_t nbd_co_send_chunk_error(uint64_t cookie, int err, const char *errname, const char *msg) "Send structured error reply: cookie = %" PRIu64 ", error = %d (%s), msg = '%s'" nbd_co_receive_request_decode_type(uint64_t cookie, uint16_t type, const char *name) "Decoding type: cookie = %" PRIu64 ", type = %" PRIu16 " (%s)" nbd_co_receive_request_payload_received(uint64_t cookie, uint64_t len) "Payload received: cookie = %" PRIu64 ", len = %" PRIu64 +nbd_co_receive_ext_payload_compliance(uint64_t from, uint64_t len) "client sent non-compliant write without payload flag: from=0x%" PRIx64 ", len=0x%" PRIx64 nbd_co_receive_align_compliance(const char *op, uint64_t from, uint64_t len, uint32_t align) "client sent non-compliant unaligned %s request: from=0x%" PRIx64 ", len=0x%" PRIx64 ", align=0x%" PRIx32 nbd_trip(void) "Reading request" From c8720ca03e01cf68f23a2017586db57abe12de0f Mon Sep 17 00:00:00 2001 From: Eric Blake Date: Mon, 25 Sep 2023 14:22:32 -0500 Subject: [PATCH 0310/1077] nbd/server: Prepare to receive extended header requests Although extended mode is not yet enabled, once we do turn it on, we need to accept extended requests for all messages. Previous patches have already taken care of supporting 64-bit lengths, now we just need to read it off the wire. Note that this implementation will block indefinitely on a buggy client that sends a non-extended payload (that is, we try to read a full packet before we ever check the magic number, but a client that mistakenly sends a simple request after negotiating extended headers doesn't send us enough bytes), but it's no different from any other client that stops talking to us partway through a packet and thus not worth coding around. Signed-off-by: Eric Blake Reviewed-by: Vladimir Sementsov-Ogievskiy Message-ID: <20230925192229.3186470-16-eblake@redhat.com> --- nbd/nbd-internal.h | 5 ++++- nbd/server.c | 43 ++++++++++++++++++++++++++++++------------- 2 files changed, 34 insertions(+), 14 deletions(-) diff --git a/nbd/nbd-internal.h b/nbd/nbd-internal.h index 133b1d94b5..dfa02f77ee 100644 --- a/nbd/nbd-internal.h +++ b/nbd/nbd-internal.h @@ -34,8 +34,11 @@ * https://github.com/yoe/nbd/blob/master/doc/proto.md */ -/* Size of all NBD_OPT_*, without payload */ +/* Size of all compact NBD_CMD_*, without payload */ #define NBD_REQUEST_SIZE (4 + 2 + 2 + 8 + 8 + 4) +/* Size of all extended NBD_CMD_*, without payload */ +#define NBD_EXTENDED_REQUEST_SIZE (4 + 2 + 2 + 8 + 8 + 8) + /* Size of all NBD_REP_* sent in answer to most NBD_OPT_*, without payload */ #define NBD_REPLY_SIZE (4 + 4 + 8) /* Size of reply to NBD_OPT_EXPORT_NAME */ diff --git a/nbd/server.c b/nbd/server.c index 56e9b41828..501749d62b 100644 --- a/nbd/server.c +++ b/nbd/server.c @@ -1411,11 +1411,13 @@ nbd_read_eof(NBDClient *client, void *buffer, size_t size, Error **errp) static int coroutine_fn nbd_receive_request(NBDClient *client, NBDRequest *request, Error **errp) { - uint8_t buf[NBD_REQUEST_SIZE]; - uint32_t magic; + uint8_t buf[NBD_EXTENDED_REQUEST_SIZE]; + uint32_t magic, expect; int ret; + size_t size = client->mode >= NBD_MODE_EXTENDED ? + NBD_EXTENDED_REQUEST_SIZE : NBD_REQUEST_SIZE; - ret = nbd_read_eof(client, buf, sizeof(buf), errp); + ret = nbd_read_eof(client, buf, size, errp); if (ret < 0) { return ret; } @@ -1423,13 +1425,21 @@ static int coroutine_fn nbd_receive_request(NBDClient *client, NBDRequest *reque return -EIO; } - /* Request - [ 0 .. 3] magic (NBD_REQUEST_MAGIC) - [ 4 .. 5] flags (NBD_CMD_FLAG_FUA, ...) - [ 6 .. 7] type (NBD_CMD_READ, ...) - [ 8 .. 15] cookie - [16 .. 23] from - [24 .. 27] len + /* + * Compact request + * [ 0 .. 3] magic (NBD_REQUEST_MAGIC) + * [ 4 .. 5] flags (NBD_CMD_FLAG_FUA, ...) + * [ 6 .. 7] type (NBD_CMD_READ, ...) + * [ 8 .. 15] cookie + * [16 .. 23] from + * [24 .. 27] len + * Extended request + * [ 0 .. 3] magic (NBD_EXTENDED_REQUEST_MAGIC) + * [ 4 .. 5] flags (NBD_CMD_FLAG_FUA, NBD_CMD_FLAG_PAYLOAD_LEN, ...) + * [ 6 .. 7] type (NBD_CMD_READ, ...) + * [ 8 .. 15] cookie + * [16 .. 23] from + * [24 .. 31] len */ magic = ldl_be_p(buf); @@ -1437,13 +1447,20 @@ static int coroutine_fn nbd_receive_request(NBDClient *client, NBDRequest *reque request->type = lduw_be_p(buf + 6); request->cookie = ldq_be_p(buf + 8); request->from = ldq_be_p(buf + 16); - request->len = (uint32_t)ldl_be_p(buf + 24); /* widen 32 to 64 bits */ + if (client->mode >= NBD_MODE_EXTENDED) { + request->len = ldq_be_p(buf + 24); + expect = NBD_EXTENDED_REQUEST_MAGIC; + } else { + request->len = (uint32_t)ldl_be_p(buf + 24); /* widen 32 to 64 bits */ + expect = NBD_REQUEST_MAGIC; + } trace_nbd_receive_request(magic, request->flags, request->type, request->from, request->len); - if (magic != NBD_REQUEST_MAGIC) { - error_setg(errp, "invalid magic (got 0x%" PRIx32 ")", magic); + if (magic != expect) { + error_setg(errp, "invalid magic (got 0x%" PRIx32 ", expected 0x%" + PRIx32 ")", magic, expect); return -EINVAL; } return 0; From 11d3355fc83f48b317f0d1f70d69c0085da7dce6 Mon Sep 17 00:00:00 2001 From: Eric Blake Date: Mon, 25 Sep 2023 14:22:33 -0500 Subject: [PATCH 0311/1077] nbd/server: Prepare to send extended header replies Although extended mode is not yet enabled, once we do turn it on, we need to reply with extended headers to all messages. Update the low level entry points necessary so that all other callers automatically get the right header based on the current mode. Signed-off-by: Eric Blake Reviewed-by: Vladimir Sementsov-Ogievskiy Message-ID: <20230925192229.3186470-17-eblake@redhat.com> --- nbd/server.c | 30 ++++++++++++++++++++++-------- 1 file changed, 22 insertions(+), 8 deletions(-) diff --git a/nbd/server.c b/nbd/server.c index 501749d62b..910c48c646 100644 --- a/nbd/server.c +++ b/nbd/server.c @@ -1938,8 +1938,6 @@ static inline void set_be_chunk(NBDClient *client, struct iovec *iov, size_t niov, uint16_t flags, uint16_t type, NBDRequest *request) { - /* TODO - handle structured vs. extended replies */ - NBDStructuredReplyChunk *chunk = iov->iov_base; size_t i, length = 0; for (i = 1; i < niov; i++) { @@ -1947,12 +1945,26 @@ static inline void set_be_chunk(NBDClient *client, struct iovec *iov, } assert(length <= NBD_MAX_BUFFER_SIZE + sizeof(NBDStructuredReadData)); - iov[0].iov_len = sizeof(*chunk); - stl_be_p(&chunk->magic, NBD_STRUCTURED_REPLY_MAGIC); - stw_be_p(&chunk->flags, flags); - stw_be_p(&chunk->type, type); - stq_be_p(&chunk->cookie, request->cookie); - stl_be_p(&chunk->length, length); + if (client->mode >= NBD_MODE_EXTENDED) { + NBDExtendedReplyChunk *chunk = iov->iov_base; + + iov[0].iov_len = sizeof(*chunk); + stl_be_p(&chunk->magic, NBD_EXTENDED_REPLY_MAGIC); + stw_be_p(&chunk->flags, flags); + stw_be_p(&chunk->type, type); + stq_be_p(&chunk->cookie, request->cookie); + stq_be_p(&chunk->offset, request->from); + stq_be_p(&chunk->length, length); + } else { + NBDStructuredReplyChunk *chunk = iov->iov_base; + + iov[0].iov_len = sizeof(*chunk); + stl_be_p(&chunk->magic, NBD_STRUCTURED_REPLY_MAGIC); + stw_be_p(&chunk->flags, flags); + stw_be_p(&chunk->type, type); + stq_be_p(&chunk->cookie, request->cookie); + stl_be_p(&chunk->length, length); + } } static int coroutine_fn nbd_co_send_chunk_done(NBDClient *client, @@ -2512,6 +2524,8 @@ static coroutine_fn int nbd_send_generic_reply(NBDClient *client, { if (client->mode >= NBD_MODE_STRUCTURED && ret < 0) { return nbd_co_send_chunk_error(client, request, -ret, error_msg, errp); + } else if (client->mode >= NBD_MODE_EXTENDED) { + return nbd_co_send_chunk_done(client, request, errp); } else { return nbd_co_send_simple_reply(client, request, ret < 0 ? -ret : 0, NULL, 0, errp); From bcc16cc19eb87889c92b71a8cde77f502e7e19be Mon Sep 17 00:00:00 2001 From: Eric Blake Date: Mon, 25 Sep 2023 14:22:34 -0500 Subject: [PATCH 0312/1077] nbd/server: Support 64-bit block status The NBD spec states that if the client negotiates extended headers, the server must avoid NBD_REPLY_TYPE_BLOCK_STATUS and instead use NBD_REPLY_TYPE_BLOCK_STATUS_EXT which supports 64-bit lengths, even if the reply does not need more than 32 bits. As of this patch, client->mode is still never NBD_MODE_EXTENDED, so the code added here does not take effect until the next patch enables negotiation. For now, all metacontexts that we know how to export never populate more than 32 bits of information, so we don't have to worry about NBD_REP_ERR_EXT_HEADER_REQD or filtering during handshake, and we always send all zeroes for the upper 32 bits of status during NBD_CMD_BLOCK_STATUS. Note that we previously had some interesting size-juggling on call chains, such as: nbd_co_send_block_status(uint32_t length) -> blockstatus_to_extents(uint32_t bytes) -> bdrv_block_status_above(bytes, &uint64_t num) -> nbd_extent_array_add(uint64_t num) -> store num in 32-bit length But we were lucky that it never overflowed: bdrv_block_status_above never sets num larger than bytes, and we had previously been capping 'bytes' at 32 bits (since the protocol does not allow sending a larger request without extended headers). This patch adds some assertions that ensure we continue to avoid overflowing 32 bits for a narrow client, while fully utilizing 64-bits all the way through when the client understands that. Even in 64-bit math, overflow is not an issue, because all lengths are coming from the block layer, and we know that the block layer does not support images larger than off_t (if lengths were coming from the network, the story would be different). Signed-off-by: Eric Blake Reviewed-by: Vladimir Sementsov-Ogievskiy Message-ID: <20230925192229.3186470-18-eblake@redhat.com> --- nbd/server.c | 106 +++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 81 insertions(+), 25 deletions(-) diff --git a/nbd/server.c b/nbd/server.c index 910c48c646..183efe27bf 100644 --- a/nbd/server.c +++ b/nbd/server.c @@ -2103,20 +2103,24 @@ static int coroutine_fn nbd_co_send_sparse_read(NBDClient *client, } typedef struct NBDExtentArray { - NBDExtent32 *extents; + NBDExtent64 *extents; unsigned int nb_alloc; unsigned int count; uint64_t total_length; + bool extended; bool can_add; bool converted_to_be; } NBDExtentArray; -static NBDExtentArray *nbd_extent_array_new(unsigned int nb_alloc) +static NBDExtentArray *nbd_extent_array_new(unsigned int nb_alloc, + NBDMode mode) { NBDExtentArray *ea = g_new0(NBDExtentArray, 1); + assert(mode >= NBD_MODE_STRUCTURED); ea->nb_alloc = nb_alloc; - ea->extents = g_new(NBDExtent32, nb_alloc); + ea->extents = g_new(NBDExtent64, nb_alloc); + ea->extended = mode >= NBD_MODE_EXTENDED; ea->can_add = true; return ea; @@ -2135,15 +2139,36 @@ static void nbd_extent_array_convert_to_be(NBDExtentArray *ea) int i; assert(!ea->converted_to_be); + assert(ea->extended); ea->can_add = false; ea->converted_to_be = true; for (i = 0; i < ea->count; i++) { - ea->extents[i].flags = cpu_to_be32(ea->extents[i].flags); - ea->extents[i].length = cpu_to_be32(ea->extents[i].length); + ea->extents[i].length = cpu_to_be64(ea->extents[i].length); + ea->extents[i].flags = cpu_to_be64(ea->extents[i].flags); } } +/* Further modifications of the array after conversion are abandoned */ +static NBDExtent32 *nbd_extent_array_convert_to_narrow(NBDExtentArray *ea) +{ + int i; + NBDExtent32 *extents = g_new(NBDExtent32, ea->count); + + assert(!ea->converted_to_be); + assert(!ea->extended); + ea->can_add = false; + ea->converted_to_be = true; + + for (i = 0; i < ea->count; i++) { + assert((ea->extents[i].length | ea->extents[i].flags) <= UINT32_MAX); + extents[i].length = cpu_to_be32(ea->extents[i].length); + extents[i].flags = cpu_to_be32(ea->extents[i].flags); + } + + return extents; +} + /* * Add extent to NBDExtentArray. If extent can't be added (no available space), * return -1. @@ -2154,19 +2179,27 @@ static void nbd_extent_array_convert_to_be(NBDExtentArray *ea) * would result in an incorrect range reported to the client) */ static int nbd_extent_array_add(NBDExtentArray *ea, - uint32_t length, uint32_t flags) + uint64_t length, uint32_t flags) { assert(ea->can_add); if (!length) { return 0; } + if (!ea->extended) { + assert(length <= UINT32_MAX); + } /* Extend previous extent if flags are the same */ if (ea->count > 0 && flags == ea->extents[ea->count - 1].flags) { - uint64_t sum = (uint64_t)length + ea->extents[ea->count - 1].length; + uint64_t sum = length + ea->extents[ea->count - 1].length; - if (sum <= UINT32_MAX) { + /* + * sum cannot overflow: the block layer bounds image size at + * 2^63, and ea->extents[].length comes from the block layer. + */ + assert(sum >= length); + if (sum <= UINT32_MAX || ea->extended) { ea->extents[ea->count - 1].length = sum; ea->total_length += length; return 0; @@ -2179,7 +2212,7 @@ static int nbd_extent_array_add(NBDExtentArray *ea, } ea->total_length += length; - ea->extents[ea->count] = (NBDExtent32) {.length = length, .flags = flags}; + ea->extents[ea->count] = (NBDExtent64) {.length = length, .flags = flags}; ea->count++; return 0; @@ -2248,20 +2281,39 @@ nbd_co_send_extents(NBDClient *client, NBDRequest *request, NBDExtentArray *ea, bool last, uint32_t context_id, Error **errp) { NBDReply hdr; - NBDStructuredMeta chunk; - struct iovec iov[] = { - {.iov_base = &hdr}, - {.iov_base = &chunk, .iov_len = sizeof(chunk)}, - {.iov_base = ea->extents, .iov_len = ea->count * sizeof(ea->extents[0])} - }; + NBDStructuredMeta meta; + NBDExtendedMeta meta_ext; + g_autofree NBDExtent32 *extents = NULL; + uint16_t type; + struct iovec iov[] = { {.iov_base = &hdr}, {0}, {0} }; - nbd_extent_array_convert_to_be(ea); + if (client->mode >= NBD_MODE_EXTENDED) { + type = NBD_REPLY_TYPE_BLOCK_STATUS_EXT; + + iov[1].iov_base = &meta_ext; + iov[1].iov_len = sizeof(meta_ext); + stl_be_p(&meta_ext.context_id, context_id); + stl_be_p(&meta_ext.count, ea->count); + + nbd_extent_array_convert_to_be(ea); + iov[2].iov_base = ea->extents; + iov[2].iov_len = ea->count * sizeof(ea->extents[0]); + } else { + type = NBD_REPLY_TYPE_BLOCK_STATUS; + + iov[1].iov_base = &meta; + iov[1].iov_len = sizeof(meta); + stl_be_p(&meta.context_id, context_id); + + extents = nbd_extent_array_convert_to_narrow(ea); + iov[2].iov_base = extents; + iov[2].iov_len = ea->count * sizeof(extents[0]); + } trace_nbd_co_send_extents(request->cookie, ea->count, context_id, ea->total_length, last); - set_be_chunk(client, iov, 3, last ? NBD_REPLY_FLAG_DONE : 0, - NBD_REPLY_TYPE_BLOCK_STATUS, request); - stl_be_p(&chunk.context_id, context_id); + set_be_chunk(client, iov, 3, last ? NBD_REPLY_FLAG_DONE : 0, type, + request); return nbd_co_send_iov(client, iov, 3, errp); } @@ -2270,13 +2322,14 @@ nbd_co_send_extents(NBDClient *client, NBDRequest *request, NBDExtentArray *ea, static int coroutine_fn nbd_co_send_block_status(NBDClient *client, NBDRequest *request, BlockBackend *blk, uint64_t offset, - uint32_t length, bool dont_fragment, + uint64_t length, bool dont_fragment, bool last, uint32_t context_id, Error **errp) { int ret; unsigned int nb_extents = dont_fragment ? 1 : NBD_MAX_BLOCK_STATUS_EXTENTS; - g_autoptr(NBDExtentArray) ea = nbd_extent_array_new(nb_extents); + g_autoptr(NBDExtentArray) ea = + nbd_extent_array_new(nb_extents, client->mode); if (context_id == NBD_META_ID_BASE_ALLOCATION) { ret = blockstatus_to_extents(blk, offset, length, ea); @@ -2299,11 +2352,12 @@ static void bitmap_to_extents(BdrvDirtyBitmap *bitmap, int64_t start, dirty_start, dirty_count; int64_t end = offset + length; bool full = false; + int64_t bound = es->extended ? INT64_MAX : INT32_MAX; bdrv_dirty_bitmap_lock(bitmap); for (start = offset; - bdrv_dirty_bitmap_next_dirty_area(bitmap, start, end, INT32_MAX, + bdrv_dirty_bitmap_next_dirty_area(bitmap, start, end, bound, &dirty_start, &dirty_count); start = dirty_start + dirty_count) { @@ -2327,12 +2381,13 @@ static int coroutine_fn nbd_co_send_bitmap(NBDClient *client, NBDRequest *request, BdrvDirtyBitmap *bitmap, uint64_t offset, - uint32_t length, bool dont_fragment, + uint64_t length, bool dont_fragment, bool last, uint32_t context_id, Error **errp) { unsigned int nb_extents = dont_fragment ? 1 : NBD_MAX_BLOCK_STATUS_EXTENTS; - g_autoptr(NBDExtentArray) ea = nbd_extent_array_new(nb_extents); + g_autoptr(NBDExtentArray) ea = + nbd_extent_array_new(nb_extents, client->mode); bitmap_to_extents(bitmap, offset, length, ea); @@ -2671,7 +2726,8 @@ static coroutine_fn int nbd_handle_request(NBDClient *client, return nbd_send_generic_reply(client, request, -EINVAL, "need non-zero length", errp); } - assert(request->len <= UINT32_MAX); + assert(client->mode >= NBD_MODE_EXTENDED || + request->len <= UINT32_MAX); if (client->export_meta.count) { bool dont_fragment = request->flags & NBD_CMD_FLAG_REQ_ONE; int contexts_remaining = client->export_meta.count; From 9c1d26143764dc53c19d872de4f8a9f820e05177 Mon Sep 17 00:00:00 2001 From: Eric Blake Date: Mon, 25 Sep 2023 14:22:35 -0500 Subject: [PATCH 0313/1077] nbd/server: Enable initial support for extended headers Time to start supporting clients that request extended headers. Now we can finally reach the code added across several previous patches. Even though the NBD spec has been altered to allow us to accept NBD_CMD_READ larger than the max payload size (provided our response is a hole or broken up over more than one data chunk), we are not planning to take advantage of that, and continue to cap NBD_CMD_READ to 32M regardless of header size. For NBD_CMD_WRITE_ZEROES and NBD_CMD_TRIM, the block layer already supports 64-bit operations without any effort on our part. For NBD_CMD_BLOCK_STATUS, the client's length is a hint, and the previous patch took care of implementing the required NBD_REPLY_TYPE_BLOCK_STATUS_EXT. We do not yet support clients that want to do request payload filtering of NBD_CMD_BLOCK_STATUS; that will be added in later patches, but is not essential for qemu as a client since qemu only requests the single context base:allocation. Signed-off-by: Eric Blake Reviewed-by: Vladimir Sementsov-Ogievskiy Message-ID: <20230925192229.3186470-19-eblake@redhat.com> --- docs/interop/nbd.txt | 1 + nbd/server.c | 21 +++++++++++++++++++++ 2 files changed, 22 insertions(+) diff --git a/docs/interop/nbd.txt b/docs/interop/nbd.txt index f5ca25174a..9aae5e1f29 100644 --- a/docs/interop/nbd.txt +++ b/docs/interop/nbd.txt @@ -69,3 +69,4 @@ NBD_CMD_BLOCK_STATUS for "qemu:dirty-bitmap:", NBD_CMD_CACHE NBD_CMD_FLAG_FAST_ZERO * 5.2: NBD_CMD_BLOCK_STATUS for "qemu:allocation-depth" * 7.1: NBD_FLAG_CAN_MULTI_CONN for shareable writable exports +* 8.2: NBD_OPT_EXTENDED_HEADERS diff --git a/nbd/server.c b/nbd/server.c index 183efe27bf..d3eed6535b 100644 --- a/nbd/server.c +++ b/nbd/server.c @@ -482,6 +482,10 @@ static int nbd_negotiate_handle_export_name(NBDClient *client, bool no_zeroes, [10 .. 133] reserved (0) [unless no_zeroes] */ trace_nbd_negotiate_handle_export_name(); + if (client->mode >= NBD_MODE_EXTENDED) { + error_setg(errp, "Extended headers already negotiated"); + return -EINVAL; + } if (client->optlen > NBD_MAX_STRING_SIZE) { error_setg(errp, "Bad length received"); return -EINVAL; @@ -1264,6 +1268,10 @@ static int nbd_negotiate_options(NBDClient *client, Error **errp) case NBD_OPT_STRUCTURED_REPLY: if (length) { ret = nbd_reject_length(client, false, errp); + } else if (client->mode >= NBD_MODE_EXTENDED) { + ret = nbd_negotiate_send_rep_err( + client, NBD_REP_ERR_EXT_HEADER_REQD, errp, + "extended headers already negotiated"); } else if (client->mode >= NBD_MODE_STRUCTURED) { ret = nbd_negotiate_send_rep_err( client, NBD_REP_ERR_INVALID, errp, @@ -1280,6 +1288,19 @@ static int nbd_negotiate_options(NBDClient *client, Error **errp) errp); break; + case NBD_OPT_EXTENDED_HEADERS: + if (length) { + ret = nbd_reject_length(client, false, errp); + } else if (client->mode >= NBD_MODE_EXTENDED) { + ret = nbd_negotiate_send_rep_err( + client, NBD_REP_ERR_INVALID, errp, + "extended headers already negotiated"); + } else { + ret = nbd_negotiate_send_rep(client, NBD_REP_ACK, errp); + client->mode = NBD_MODE_EXTENDED; + } + break; + default: ret = nbd_opt_drop(client, NBD_REP_ERR_UNSUP, errp, "Unsupported option %" PRIu32 " (%s)", From ed6c996c673e3d64be1f060abc3a6999e007dae2 Mon Sep 17 00:00:00 2001 From: Eric Blake Date: Mon, 25 Sep 2023 14:22:36 -0500 Subject: [PATCH 0314/1077] nbd/client: Plumb errp through nbd_receive_replies Instead of ignoring the low-level error just to refabricate our own message to pass to the caller, we can just plumb the caller's errp down to the low level. Signed-off-by: Eric Blake Message-ID: <20230925192229.3186470-20-eblake@redhat.com> Reviewed-by: Vladimir Sementsov-Ogievskiy --- block/nbd.c | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/block/nbd.c b/block/nbd.c index 4a7f37da1c..22d3cb11ac 100644 --- a/block/nbd.c +++ b/block/nbd.c @@ -416,7 +416,8 @@ static void coroutine_fn GRAPH_RDLOCK nbd_reconnect_attempt(BDRVNBDState *s) reconnect_delay_timer_del(s); } -static coroutine_fn int nbd_receive_replies(BDRVNBDState *s, uint64_t cookie) +static coroutine_fn int nbd_receive_replies(BDRVNBDState *s, uint64_t cookie, + Error **errp) { int ret; uint64_t ind = COOKIE_TO_INDEX(cookie), ind2; @@ -457,20 +458,25 @@ static coroutine_fn int nbd_receive_replies(BDRVNBDState *s, uint64_t cookie) /* We are under mutex and cookie is 0. We have to do the dirty work. */ assert(s->reply.cookie == 0); - ret = nbd_receive_reply(s->bs, s->ioc, &s->reply, NULL); - if (ret <= 0) { - ret = ret ? ret : -EIO; + ret = nbd_receive_reply(s->bs, s->ioc, &s->reply, errp); + if (ret == 0) { + ret = -EIO; + error_setg(errp, "server dropped connection"); + } + if (ret < 0) { nbd_channel_error(s, ret); return ret; } if (nbd_reply_is_structured(&s->reply) && s->info.mode < NBD_MODE_STRUCTURED) { nbd_channel_error(s, -EINVAL); + error_setg(errp, "unexpected structured reply"); return -EINVAL; } ind2 = COOKIE_TO_INDEX(s->reply.cookie); if (ind2 >= MAX_NBD_REQUESTS || !s->requests[ind2].coroutine) { nbd_channel_error(s, -EINVAL); + error_setg(errp, "unexpected cookie value"); return -EINVAL; } if (s->reply.cookie == cookie) { @@ -842,9 +848,9 @@ static coroutine_fn int nbd_co_do_receive_one_chunk( } *request_ret = 0; - ret = nbd_receive_replies(s, cookie); + ret = nbd_receive_replies(s, cookie, errp); if (ret < 0) { - error_setg(errp, "Connection closed"); + error_prepend(errp, "Connection closed: "); return -EIO; } assert(s->ioc); From 4fc55bf3b0608f15ce64d7b8cdaa95ac29e62d6c Mon Sep 17 00:00:00 2001 From: Eric Blake Date: Mon, 25 Sep 2023 14:22:37 -0500 Subject: [PATCH 0315/1077] nbd/client: Initial support for extended headers Update the client code to be able to send an extended request, and parse an extended header from the server. Note that since we reject any structured reply with a too-large payload, we can always normalize a valid header back into the compact form, so that the caller need not deal with two branches of a union. Still, until a later patch lets the client negotiate extended headers, the code added here should not be reached. Note that because of the different magic numbers, it is just as easy to trace and then tolerate a non-compliant server sending the wrong header reply as it would be to insist that the server is compliant. Signed-off-by: Eric Blake Message-ID: <20230925192229.3186470-21-eblake@redhat.com> [eblake: fix trace format] Reviewed-by: Vladimir Sementsov-Ogievskiy --- block/nbd.c | 2 +- include/block/nbd.h | 3 +- nbd/client.c | 104 +++++++++++++++++++++++++++++--------------- nbd/trace-events | 3 +- 4 files changed, 74 insertions(+), 38 deletions(-) diff --git a/block/nbd.c b/block/nbd.c index 22d3cb11ac..7646143041 100644 --- a/block/nbd.c +++ b/block/nbd.c @@ -458,7 +458,7 @@ static coroutine_fn int nbd_receive_replies(BDRVNBDState *s, uint64_t cookie, /* We are under mutex and cookie is 0. We have to do the dirty work. */ assert(s->reply.cookie == 0); - ret = nbd_receive_reply(s->bs, s->ioc, &s->reply, errp); + ret = nbd_receive_reply(s->bs, s->ioc, &s->reply, s->info.mode, errp); if (ret == 0) { ret = -EIO; error_setg(errp, "server dropped connection"); diff --git a/include/block/nbd.h b/include/block/nbd.h index 8a765e78df..ba8724f533 100644 --- a/include/block/nbd.h +++ b/include/block/nbd.h @@ -389,7 +389,8 @@ int nbd_init(int fd, QIOChannelSocket *sioc, NBDExportInfo *info, Error **errp); int nbd_send_request(QIOChannel *ioc, NBDRequest *request); int coroutine_fn nbd_receive_reply(BlockDriverState *bs, QIOChannel *ioc, - NBDReply *reply, Error **errp); + NBDReply *reply, NBDMode mode, + Error **errp); int nbd_client(int fd); int nbd_disconnect(int fd); int nbd_errno_to_system_errno(int err); diff --git a/nbd/client.c b/nbd/client.c index cecb0f0437..a2f253062a 100644 --- a/nbd/client.c +++ b/nbd/client.c @@ -1346,22 +1346,29 @@ int nbd_disconnect(int fd) int nbd_send_request(QIOChannel *ioc, NBDRequest *request) { - uint8_t buf[NBD_REQUEST_SIZE]; + uint8_t buf[NBD_EXTENDED_REQUEST_SIZE]; + size_t len; - assert(request->mode <= NBD_MODE_STRUCTURED); /* TODO handle extended */ - assert(request->len <= UINT32_MAX); trace_nbd_send_request(request->from, request->len, request->cookie, request->flags, request->type, nbd_cmd_lookup(request->type)); - stl_be_p(buf, NBD_REQUEST_MAGIC); stw_be_p(buf + 4, request->flags); stw_be_p(buf + 6, request->type); stq_be_p(buf + 8, request->cookie); stq_be_p(buf + 16, request->from); - stl_be_p(buf + 24, request->len); + if (request->mode >= NBD_MODE_EXTENDED) { + stl_be_p(buf, NBD_EXTENDED_REQUEST_MAGIC); + stq_be_p(buf + 24, request->len); + len = NBD_EXTENDED_REQUEST_SIZE; + } else { + assert(request->len <= UINT32_MAX); + stl_be_p(buf, NBD_REQUEST_MAGIC); + stl_be_p(buf + 24, request->len); + len = NBD_REQUEST_SIZE; + } - return nbd_write(ioc, buf, sizeof(buf), NULL); + return nbd_write(ioc, buf, len, NULL); } /* nbd_receive_simple_reply @@ -1388,30 +1395,36 @@ static int nbd_receive_simple_reply(QIOChannel *ioc, NBDSimpleReply *reply, return 0; } -/* nbd_receive_structured_reply_chunk +/* nbd_receive_reply_chunk_header * Read structured reply chunk except magic field (which should be already - * read). + * read). Normalize into the compact form. * Payload is not read. */ -static int nbd_receive_structured_reply_chunk(QIOChannel *ioc, - NBDStructuredReplyChunk *chunk, - Error **errp) +static int nbd_receive_reply_chunk_header(QIOChannel *ioc, NBDReply *chunk, + Error **errp) { int ret; + size_t len; + uint64_t payload_len; - assert(chunk->magic == NBD_STRUCTURED_REPLY_MAGIC); + if (chunk->magic == NBD_STRUCTURED_REPLY_MAGIC) { + len = sizeof(chunk->structured); + } else { + assert(chunk->magic == NBD_EXTENDED_REPLY_MAGIC); + len = sizeof(chunk->extended); + } ret = nbd_read(ioc, (uint8_t *)chunk + sizeof(chunk->magic), - sizeof(*chunk) - sizeof(chunk->magic), "structured chunk", + len - sizeof(chunk->magic), "structured chunk", errp); if (ret < 0) { return ret; } - chunk->flags = be16_to_cpu(chunk->flags); - chunk->type = be16_to_cpu(chunk->type); - chunk->cookie = be64_to_cpu(chunk->cookie); - chunk->length = be32_to_cpu(chunk->length); + /* flags, type, and cookie occupy same space between forms */ + chunk->structured.flags = be16_to_cpu(chunk->structured.flags); + chunk->structured.type = be16_to_cpu(chunk->structured.type); + chunk->structured.cookie = be64_to_cpu(chunk->structured.cookie); /* * Because we use BLOCK_STATUS with REQ_ONE, and cap READ requests @@ -1419,11 +1432,20 @@ static int nbd_receive_structured_reply_chunk(QIOChannel *ioc, * this. Even if we stopped using REQ_ONE, sane servers will cap * the number of extents they return for block status. */ - if (chunk->length > NBD_MAX_BUFFER_SIZE + sizeof(NBDStructuredReadData)) { + if (chunk->magic == NBD_STRUCTURED_REPLY_MAGIC) { + payload_len = be32_to_cpu(chunk->structured.length); + } else { + /* For now, we are ignoring the extended header offset. */ + payload_len = be64_to_cpu(chunk->extended.length); + chunk->magic = NBD_STRUCTURED_REPLY_MAGIC; + } + if (payload_len > NBD_MAX_BUFFER_SIZE + sizeof(NBDStructuredReadData)) { error_setg(errp, "server chunk %" PRIu32 " (%s) payload is too long", - chunk->type, nbd_rep_lookup(chunk->type)); + chunk->structured.type, + nbd_rep_lookup(chunk->structured.type)); return -EINVAL; } + chunk->structured.length = payload_len; return 0; } @@ -1470,19 +1492,21 @@ nbd_read_eof(BlockDriverState *bs, QIOChannel *ioc, void *buffer, size_t size, /* nbd_receive_reply * - * Decreases bs->in_flight while waiting for a new reply. This yield is where - * we wait indefinitely and the coroutine must be able to be safely reentered - * for nbd_client_attach_aio_context(). + * Wait for a new reply. If this yields, the coroutine must be able to be + * safely reentered for nbd_client_attach_aio_context(). @mode determines + * which reply magic we are expecting, although this normalizes the result + * so that the caller only has to work with compact headers. * * Returns 1 on success - * 0 on eof, when no data was read (errp is not set) - * negative errno on failure (errp is set) + * 0 on eof, when no data was read + * negative errno on failure */ int coroutine_fn nbd_receive_reply(BlockDriverState *bs, QIOChannel *ioc, - NBDReply *reply, Error **errp) + NBDReply *reply, NBDMode mode, Error **errp) { int ret; const char *type; + uint32_t expected; ret = nbd_read_eof(bs, ioc, &reply->magic, sizeof(reply->magic), errp); if (ret <= 0) { @@ -1491,34 +1515,44 @@ int coroutine_fn nbd_receive_reply(BlockDriverState *bs, QIOChannel *ioc, reply->magic = be32_to_cpu(reply->magic); + /* Diagnose but accept wrong-width header */ switch (reply->magic) { case NBD_SIMPLE_REPLY_MAGIC: + if (mode >= NBD_MODE_EXTENDED) { + trace_nbd_receive_wrong_header(reply->magic, + nbd_mode_lookup(mode)); + } ret = nbd_receive_simple_reply(ioc, &reply->simple, errp); if (ret < 0) { - break; + return ret; } trace_nbd_receive_simple_reply(reply->simple.error, nbd_err_lookup(reply->simple.error), reply->cookie); break; case NBD_STRUCTURED_REPLY_MAGIC: - ret = nbd_receive_structured_reply_chunk(ioc, &reply->structured, errp); + case NBD_EXTENDED_REPLY_MAGIC: + expected = mode >= NBD_MODE_EXTENDED ? NBD_EXTENDED_REPLY_MAGIC + : NBD_STRUCTURED_REPLY_MAGIC; + if (reply->magic != expected) { + trace_nbd_receive_wrong_header(reply->magic, + nbd_mode_lookup(mode)); + } + ret = nbd_receive_reply_chunk_header(ioc, reply, errp); if (ret < 0) { - break; + return ret; } type = nbd_reply_type_lookup(reply->structured.type); - trace_nbd_receive_structured_reply_chunk(reply->structured.flags, - reply->structured.type, type, - reply->structured.cookie, - reply->structured.length); + trace_nbd_receive_reply_chunk_header(reply->structured.flags, + reply->structured.type, type, + reply->structured.cookie, + reply->structured.length); break; default: + trace_nbd_receive_wrong_header(reply->magic, nbd_mode_lookup(mode)); error_setg(errp, "invalid magic (got 0x%" PRIx32 ")", reply->magic); return -EINVAL; } - if (ret < 0) { - return ret; - } return 1; } diff --git a/nbd/trace-events b/nbd/trace-events index c1a3227613..cb5d719ed6 100644 --- a/nbd/trace-events +++ b/nbd/trace-events @@ -33,7 +33,8 @@ nbd_client_clear_queue(void) "Clearing NBD queue" nbd_client_clear_socket(void) "Clearing NBD socket" nbd_send_request(uint64_t from, uint64_t len, uint64_t cookie, uint16_t flags, uint16_t type, const char *name) "Sending request to server: { .from = %" PRIu64", .len = %" PRIu64 ", .cookie = %" PRIu64 ", .flags = 0x%" PRIx16 ", .type = %" PRIu16 " (%s) }" nbd_receive_simple_reply(int32_t error, const char *errname, uint64_t cookie) "Got simple reply: { .error = %" PRId32 " (%s), cookie = %" PRIu64" }" -nbd_receive_structured_reply_chunk(uint16_t flags, uint16_t type, const char *name, uint64_t cookie, uint32_t length) "Got structured reply chunk: { flags = 0x%" PRIx16 ", type = %d (%s), cookie = %" PRIu64 ", length = %" PRIu32 " }" +nbd_receive_reply_chunk_header(uint16_t flags, uint16_t type, const char *name, uint64_t cookie, uint32_t length) "Got reply chunk header: { flags = 0x%" PRIx16 ", type = %" PRIu16 " (%s), cookie = %" PRIu64 ", length = %" PRIu32 " }" +nbd_receive_wrong_header(uint32_t magic, const char *mode) "Server sent unexpected magic 0x%" PRIx32 " for negotiated mode %s" # common.c nbd_unknown_error(int err) "Squashing unexpected error %d to EINVAL" From a7c18670b429cc5e9c5e6a25cc401dc93086f1a7 Mon Sep 17 00:00:00 2001 From: Eric Blake Date: Mon, 25 Sep 2023 14:22:38 -0500 Subject: [PATCH 0316/1077] nbd/client: Accept 64-bit block status chunks Once extended mode is enabled, we need to accept 64-bit status replies (even for replies that don't exceed a 32-bit length). It is easier to normalize narrow replies into wide format so that the rest of our code only has to handle one width. Although a server is non-compliant if it sends a 64-bit reply in compact mode, or a 32-bit reply in extended mode, it is still easy enough to tolerate these mismatches. In normal execution, we are only requesting "base:allocation" which never exceeds 32 bits for flag values. But during testing with x-dirty-bitmap, we can force qemu to connect to some other context that might have 64-bit status bit; however, we ignore those upper bits (other than mapping qemu:allocation-depth into something that 'qemu-img map --output=json' can expose), and since that only affects testing, we really don't bother with checking whether more than the two least-significant bits are set. Signed-off-by: Eric Blake Reviewed-by: Vladimir Sementsov-Ogievskiy Message-ID: <20230925192229.3186470-22-eblake@redhat.com> --- block/nbd.c | 49 ++++++++++++++++++++++++++++++++-------------- block/trace-events | 1 + 2 files changed, 35 insertions(+), 15 deletions(-) diff --git a/block/nbd.c b/block/nbd.c index 7646143041..52ebc8b2f5 100644 --- a/block/nbd.c +++ b/block/nbd.c @@ -615,13 +615,17 @@ static int nbd_parse_offset_hole_payload(BDRVNBDState *s, */ static int nbd_parse_blockstatus_payload(BDRVNBDState *s, NBDStructuredReplyChunk *chunk, - uint8_t *payload, uint64_t orig_length, - NBDExtent32 *extent, Error **errp) + uint8_t *payload, bool wide, + uint64_t orig_length, + NBDExtent64 *extent, Error **errp) { uint32_t context_id; + uint32_t count; + size_t ext_len = wide ? sizeof(*extent) : sizeof(NBDExtent32); + size_t pay_len = sizeof(context_id) + wide * sizeof(count) + ext_len; /* The server succeeded, so it must have sent [at least] one extent */ - if (chunk->length < sizeof(context_id) + sizeof(*extent)) { + if (chunk->length < pay_len) { error_setg(errp, "Protocol error: invalid payload for " "NBD_REPLY_TYPE_BLOCK_STATUS"); return -EINVAL; @@ -636,8 +640,15 @@ static int nbd_parse_blockstatus_payload(BDRVNBDState *s, return -EINVAL; } - extent->length = payload_advance32(&payload); - extent->flags = payload_advance32(&payload); + if (wide) { + count = payload_advance32(&payload); + extent->length = payload_advance64(&payload); + extent->flags = payload_advance64(&payload); + } else { + count = 0; + extent->length = payload_advance32(&payload); + extent->flags = payload_advance32(&payload); + } if (extent->length == 0) { error_setg(errp, "Protocol error: server sent status chunk with " @@ -658,7 +669,7 @@ static int nbd_parse_blockstatus_payload(BDRVNBDState *s, * (always a safe status, even if it loses information). */ if (s->info.min_block && !QEMU_IS_ALIGNED(extent->length, - s->info.min_block)) { + s->info.min_block)) { trace_nbd_parse_blockstatus_compliance("extent length is unaligned"); if (extent->length > s->info.min_block) { extent->length = QEMU_ALIGN_DOWN(extent->length, @@ -672,13 +683,15 @@ static int nbd_parse_blockstatus_payload(BDRVNBDState *s, /* * We used NBD_CMD_FLAG_REQ_ONE, so the server should not have * sent us any more than one extent, nor should it have included - * status beyond our request in that extent. However, it's easy - * enough to ignore the server's noncompliance without killing the + * status beyond our request in that extent. Furthermore, a wide + * server should have replied with an accurate count (we left + * count at 0 for a narrow server). However, it's easy enough to + * ignore the server's noncompliance without killing the * connection; just ignore trailing extents, and clamp things to * the length of our request. */ - if (chunk->length > sizeof(context_id) + sizeof(*extent)) { - trace_nbd_parse_blockstatus_compliance("more than one extent"); + if (count != wide || chunk->length > pay_len) { + trace_nbd_parse_blockstatus_compliance("unexpected extent count"); } if (extent->length > orig_length) { extent->length = orig_length; @@ -1124,7 +1137,7 @@ nbd_co_receive_cmdread_reply(BDRVNBDState *s, uint64_t cookie, static int coroutine_fn nbd_co_receive_blockstatus_reply(BDRVNBDState *s, uint64_t cookie, - uint64_t length, NBDExtent32 *extent, + uint64_t length, NBDExtent64 *extent, int *request_ret, Error **errp) { NBDReplyChunkIter iter; @@ -1137,11 +1150,17 @@ nbd_co_receive_blockstatus_reply(BDRVNBDState *s, uint64_t cookie, NBD_FOREACH_REPLY_CHUNK(s, iter, cookie, false, NULL, &reply, &payload) { int ret; NBDStructuredReplyChunk *chunk = &reply.structured; + bool wide; assert(nbd_reply_is_structured(&reply)); switch (chunk->type) { + case NBD_REPLY_TYPE_BLOCK_STATUS_EXT: case NBD_REPLY_TYPE_BLOCK_STATUS: + wide = chunk->type == NBD_REPLY_TYPE_BLOCK_STATUS_EXT; + if ((s->info.mode >= NBD_MODE_EXTENDED) != wide) { + trace_nbd_extended_headers_compliance("block_status"); + } if (received) { nbd_channel_error(s, -EINVAL); error_setg(&local_err, "Several BLOCK_STATUS chunks in reply"); @@ -1149,9 +1168,9 @@ nbd_co_receive_blockstatus_reply(BDRVNBDState *s, uint64_t cookie, } received = true; - ret = nbd_parse_blockstatus_payload(s, &reply.structured, - payload, length, extent, - &local_err); + ret = nbd_parse_blockstatus_payload( + s, &reply.structured, payload, wide, + length, extent, &local_err); if (ret < 0) { nbd_channel_error(s, ret); nbd_iter_channel_error(&iter, ret, &local_err); @@ -1381,7 +1400,7 @@ static int coroutine_fn GRAPH_RDLOCK nbd_client_co_block_status( int64_t *pnum, int64_t *map, BlockDriverState **file) { int ret, request_ret; - NBDExtent32 extent = { 0 }; + NBDExtent64 extent = { 0 }; BDRVNBDState *s = (BDRVNBDState *)bs->opaque; Error *local_err = NULL; diff --git a/block/trace-events b/block/trace-events index 925aa554bb..8e789e1f12 100644 --- a/block/trace-events +++ b/block/trace-events @@ -166,6 +166,7 @@ iscsi_xcopy(void *src_lun, uint64_t src_off, void *dst_lun, uint64_t dst_off, ui # nbd.c nbd_parse_blockstatus_compliance(const char *err) "ignoring extra data from non-compliant server: %s" nbd_structured_read_compliance(const char *type) "server sent non-compliant unaligned read %s chunk" +nbd_extended_headers_compliance(const char *type) "server sent non-compliant %s chunk not matching choice of extended headers" nbd_read_reply_entry_fail(int ret, const char *err) "ret = %d, err: %s" nbd_co_request_fail(uint64_t from, uint64_t len, uint64_t handle, uint16_t flags, uint16_t type, const char *name, int ret, const char *err) "Request failed { .from = %" PRIu64", .len = %" PRIu64 ", .handle = %" PRIu64 ", .flags = 0x%" PRIx16 ", .type = %" PRIu16 " (%s) } ret = %d, err: %s" nbd_client_handshake(const char *export_name) "export '%s'" From 56cf9d0471c6481adcada2b6afbaf6c7af9e76c7 Mon Sep 17 00:00:00 2001 From: Eric Blake Date: Mon, 25 Sep 2023 14:22:39 -0500 Subject: [PATCH 0317/1077] nbd/client: Request extended headers during negotiation All the pieces are in place for a client to finally request extended headers. Note that we must not request extended headers when qemu-nbd is used to connect to the kernel module (as nbd.ko does not expect them, but expects us to do the negotiation in userspace before handing the socket over to the kernel), but there is no harm in all other clients requesting them. Extended headers are not essential to the information collected during 'qemu-nbd --list', but probing for it gives us one more piece of information in that output. Update the iotests affected by the new line of output. Signed-off-by: Eric Blake Reviewed-by: Vladimir Sementsov-Ogievskiy Message-ID: <20230925192229.3186470-23-eblake@redhat.com> --- nbd/client-connection.c | 2 +- nbd/client.c | 20 ++++++++++++++----- qemu-nbd.c | 3 +++ tests/qemu-iotests/223.out | 6 ++++++ tests/qemu-iotests/233.out | 4 ++++ tests/qemu-iotests/241.out | 3 +++ tests/qemu-iotests/307.out | 5 +++++ .../tests/nbd-qemu-allocation.out | 1 + 8 files changed, 38 insertions(+), 6 deletions(-) diff --git a/nbd/client-connection.c b/nbd/client-connection.c index aa0201b710..f9da67c87e 100644 --- a/nbd/client-connection.c +++ b/nbd/client-connection.c @@ -93,7 +93,7 @@ NBDClientConnection *nbd_client_connection_new(const SocketAddress *saddr, .do_negotiation = do_negotiation, .initial_info.request_sizes = true, - .initial_info.mode = NBD_MODE_STRUCTURED, + .initial_info.mode = NBD_MODE_EXTENDED, .initial_info.base_allocation = true, .initial_info.x_dirty_bitmap = g_strdup(x_dirty_bitmap), .initial_info.name = g_strdup(export_name ?: "") diff --git a/nbd/client.c b/nbd/client.c index a2f253062a..29ffc609a4 100644 --- a/nbd/client.c +++ b/nbd/client.c @@ -953,15 +953,23 @@ static int nbd_start_negotiate(QIOChannel *ioc, QCryptoTLSCreds *tlscreds, if (fixedNewStyle) { int result = 0; + if (max_mode >= NBD_MODE_EXTENDED) { + result = nbd_request_simple_option(ioc, + NBD_OPT_EXTENDED_HEADERS, + false, errp); + if (result) { + return result < 0 ? -EINVAL : NBD_MODE_EXTENDED; + } + } if (max_mode >= NBD_MODE_STRUCTURED) { result = nbd_request_simple_option(ioc, NBD_OPT_STRUCTURED_REPLY, false, errp); - if (result < 0) { - return -EINVAL; + if (result) { + return result < 0 ? -EINVAL : NBD_MODE_STRUCTURED; } } - return result ? NBD_MODE_STRUCTURED : NBD_MODE_SIMPLE; + return NBD_MODE_SIMPLE; } else { return NBD_MODE_EXPORT_NAME; } @@ -1034,6 +1042,7 @@ int nbd_receive_negotiate(QIOChannel *ioc, QCryptoTLSCreds *tlscreds, } switch (info->mode) { + case NBD_MODE_EXTENDED: case NBD_MODE_STRUCTURED: if (base_allocation) { result = nbd_negotiate_simple_meta_context(ioc, info, errp); @@ -1144,7 +1153,7 @@ int nbd_receive_export_list(QIOChannel *ioc, QCryptoTLSCreds *tlscreds, *info = NULL; result = nbd_start_negotiate(ioc, tlscreds, hostname, &sioc, - NBD_MODE_STRUCTURED, NULL, errp); + NBD_MODE_EXTENDED, NULL, errp); if (tlscreds && sioc) { ioc = sioc; } @@ -1155,6 +1164,7 @@ int nbd_receive_export_list(QIOChannel *ioc, QCryptoTLSCreds *tlscreds, switch ((NBDMode)result) { case NBD_MODE_SIMPLE: case NBD_MODE_STRUCTURED: + case NBD_MODE_EXTENDED: /* newstyle - use NBD_OPT_LIST to populate array, then try * NBD_OPT_INFO on each array member. If structured replies * are enabled, also try NBD_OPT_LIST_META_CONTEXT. */ @@ -1191,7 +1201,7 @@ int nbd_receive_export_list(QIOChannel *ioc, QCryptoTLSCreds *tlscreds, break; } - if (result == NBD_MODE_STRUCTURED && + if (result >= NBD_MODE_STRUCTURED && nbd_list_meta_contexts(ioc, &array[i], errp) < 0) { goto out; } diff --git a/qemu-nbd.c b/qemu-nbd.c index 54faa87a0c..1a39bb8fac 100644 --- a/qemu-nbd.c +++ b/qemu-nbd.c @@ -235,6 +235,9 @@ static int qemu_nbd_client_list(SocketAddress *saddr, QCryptoTLSCreds *tls, printf(" opt block: %u\n", list[i].opt_block); printf(" max block: %u\n", list[i].max_block); } + printf(" transaction size: %s\n", + list[i].mode >= NBD_MODE_EXTENDED ? + "64-bit" : "32-bit"); if (list[i].n_contexts) { printf(" available meta contexts: %d\n", list[i].n_contexts); for (j = 0; j < list[i].n_contexts; j++) { diff --git a/tests/qemu-iotests/223.out b/tests/qemu-iotests/223.out index 86a37014d0..32f05f1c9a 100644 --- a/tests/qemu-iotests/223.out +++ b/tests/qemu-iotests/223.out @@ -87,6 +87,7 @@ exports available: 3 min block: 1 opt block: 4096 max block: 33554432 + transaction size: 64-bit available meta contexts: 2 base:allocation qemu:dirty-bitmap:b @@ -97,6 +98,7 @@ exports available: 3 min block: 1 opt block: 4096 max block: 33554432 + transaction size: 64-bit available meta contexts: 2 base:allocation qemu:dirty-bitmap:b2 @@ -106,6 +108,7 @@ exports available: 3 min block: 1 opt block: 4096 max block: 33554432 + transaction size: 64-bit available meta contexts: 2 base:allocation qemu:dirty-bitmap:b3 @@ -206,6 +209,7 @@ exports available: 3 min block: 1 opt block: 4096 max block: 33554432 + transaction size: 64-bit available meta contexts: 2 base:allocation qemu:dirty-bitmap:b @@ -216,6 +220,7 @@ exports available: 3 min block: 1 opt block: 4096 max block: 33554432 + transaction size: 64-bit available meta contexts: 2 base:allocation qemu:dirty-bitmap:b2 @@ -225,6 +230,7 @@ exports available: 3 min block: 1 opt block: 4096 max block: 33554432 + transaction size: 64-bit available meta contexts: 2 base:allocation qemu:dirty-bitmap:b3 diff --git a/tests/qemu-iotests/233.out b/tests/qemu-iotests/233.out index 237c82767e..1910f7df20 100644 --- a/tests/qemu-iotests/233.out +++ b/tests/qemu-iotests/233.out @@ -39,6 +39,7 @@ exports available: 1 export: '' size: 67108864 min block: 1 + transaction size: 64-bit == check TLS fail over TCP with mismatched hostname == qemu-img: Could not open 'driver=nbd,host=localhost,port=PORT,tls-creds=tls0': Certificate does not match the hostname localhost @@ -53,6 +54,7 @@ exports available: 1 export: '' size: 67108864 min block: 1 + transaction size: 64-bit == check TLS with different CA fails == qemu-img: Could not open 'driver=nbd,host=127.0.0.1,port=PORT,tls-creds=tls0': The certificate hasn't got a known issuer @@ -83,6 +85,7 @@ exports available: 1 export: '' size: 67108864 min block: 1 + transaction size: 64-bit == check TLS works over UNIX with PSK == image: nbd+unix://?socket=SOCK_DIR/qemu-nbd.sock @@ -93,6 +96,7 @@ exports available: 1 export: '' size: 67108864 min block: 1 + transaction size: 64-bit == check TLS fails over UNIX with mismatch PSK == qemu-img: Could not open 'driver=nbd,path=SOCK_DIR/qemu-nbd.sock,tls-creds=tls0': TLS handshake failed: The TLS connection was non-properly terminated. diff --git a/tests/qemu-iotests/241.out b/tests/qemu-iotests/241.out index 7946c286d5..7267cd2997 100644 --- a/tests/qemu-iotests/241.out +++ b/tests/qemu-iotests/241.out @@ -6,6 +6,7 @@ exports available: 1 export: '' size: 1024 min block: 1 + transaction size: 64-bit [{ "start": 0, "length": 1000, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, { "start": 1000, "length": 24, "depth": 0, "present": true, "zero": true, "data": false, "compressed": false, "offset": OFFSET}] 1 KiB (0x400) bytes allocated at offset 0 bytes (0x0) @@ -16,6 +17,7 @@ exports available: 1 export: '' size: 1024 min block: 512 + transaction size: 64-bit [{ "start": 0, "length": 1024, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}] 1 KiB (0x400) bytes allocated at offset 0 bytes (0x0) WARNING: Image format was not specified for 'TEST_DIR/t.raw' and probing guessed raw. @@ -28,6 +30,7 @@ exports available: 1 export: '' size: 1024 min block: 1 + transaction size: 64-bit [{ "start": 0, "length": 1000, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, { "start": 1000, "length": 24, "depth": 0, "present": true, "zero": true, "data": false, "compressed": false, "offset": OFFSET}] 1 KiB (0x400) bytes allocated at offset 0 bytes (0x0) diff --git a/tests/qemu-iotests/307.out b/tests/qemu-iotests/307.out index 390f05d1b7..2b9a6a67a1 100644 --- a/tests/qemu-iotests/307.out +++ b/tests/qemu-iotests/307.out @@ -19,6 +19,7 @@ exports available: 1 min block: XXX opt block: XXX max block: XXX + transaction size: 64-bit available meta contexts: 1 base:allocation @@ -47,6 +48,7 @@ exports available: 1 min block: XXX opt block: XXX max block: XXX + transaction size: 64-bit available meta contexts: 1 base:allocation @@ -78,6 +80,7 @@ exports available: 2 min block: XXX opt block: XXX max block: XXX + transaction size: 64-bit available meta contexts: 1 base:allocation export: 'export1' @@ -87,6 +90,7 @@ exports available: 2 min block: XXX opt block: XXX max block: XXX + transaction size: 64-bit available meta contexts: 1 base:allocation @@ -113,6 +117,7 @@ exports available: 1 min block: XXX opt block: XXX max block: XXX + transaction size: 64-bit available meta contexts: 1 base:allocation diff --git a/tests/qemu-iotests/tests/nbd-qemu-allocation.out b/tests/qemu-iotests/tests/nbd-qemu-allocation.out index 138eb09c6d..1db16926ed 100644 --- a/tests/qemu-iotests/tests/nbd-qemu-allocation.out +++ b/tests/qemu-iotests/tests/nbd-qemu-allocation.out @@ -21,6 +21,7 @@ exports available: 1 min block: 1 opt block: 4096 max block: 33554432 + transaction size: 64-bit available meta contexts: 2 base:allocation qemu:allocation-depth From fd358d83901d7ccf51a389bd2d0718b28ca77c1f Mon Sep 17 00:00:00 2001 From: Eric Blake Date: Mon, 25 Sep 2023 14:22:40 -0500 Subject: [PATCH 0318/1077] nbd/server: Refactor list of negotiated meta contexts Peform several minor refactorings of how the list of negotiated meta contexts is managed, to make upcoming patches easier: Promote the internal type NBDExportMetaContexts to the public opaque type NBDMetaContexts, and mark exp const. Use a shorter member name in NBDClient. Hoist calls to nbd_check_meta_context() earlier in their callers, as the number of negotiated contexts may impact the flags exposed in regards to an export, which in turn requires a new parameter. Drop a redundant parameter to nbd_negotiate_meta_queries. No semantic change intended on the success path; on the failure path, dropping context in nbd_check_meta_export even when reporting an error is safer. Signed-off-by: Eric Blake Reviewed-by: Vladimir Sementsov-Ogievskiy Message-ID: <20230925192229.3186470-24-eblake@redhat.com> --- include/block/nbd.h | 1 + nbd/server.c | 55 ++++++++++++++++++++++++--------------------- 2 files changed, 31 insertions(+), 25 deletions(-) diff --git a/include/block/nbd.h b/include/block/nbd.h index ba8724f533..2006497f98 100644 --- a/include/block/nbd.h +++ b/include/block/nbd.h @@ -29,6 +29,7 @@ typedef struct NBDExport NBDExport; typedef struct NBDClient NBDClient; typedef struct NBDClientConnection NBDClientConnection; +typedef struct NBDMetaContexts NBDMetaContexts; extern const BlockExportDriver blk_exp_nbd; diff --git a/nbd/server.c b/nbd/server.c index d3eed6535b..2719992db7 100644 --- a/nbd/server.c +++ b/nbd/server.c @@ -105,11 +105,13 @@ struct NBDExport { static QTAILQ_HEAD(, NBDExport) exports = QTAILQ_HEAD_INITIALIZER(exports); -/* NBDExportMetaContexts represents a list of contexts to be exported, +/* + * NBDMetaContexts represents a list of meta contexts in use, * as selected by NBD_OPT_SET_META_CONTEXT. Also used for - * NBD_OPT_LIST_META_CONTEXT. */ -typedef struct NBDExportMetaContexts { - NBDExport *exp; + * NBD_OPT_LIST_META_CONTEXT. + */ +struct NBDMetaContexts { + const NBDExport *exp; /* associated export */ size_t count; /* number of negotiated contexts */ bool base_allocation; /* export base:allocation context (block status) */ bool allocation_depth; /* export qemu:allocation-depth */ @@ -117,7 +119,7 @@ typedef struct NBDExportMetaContexts { * export qemu:dirty-bitmap:, * sized by exp->nr_export_bitmaps */ -} NBDExportMetaContexts; +}; struct NBDClient { int refcount; @@ -144,7 +146,7 @@ struct NBDClient { uint32_t check_align; /* If non-zero, check for aligned client requests */ NBDMode mode; - NBDExportMetaContexts export_meta; + NBDMetaContexts contexts; /* Negotiated meta contexts */ uint32_t opt; /* Current option being negotiated */ uint32_t optlen; /* remaining length of data in ioc for the option being @@ -455,10 +457,10 @@ static int nbd_negotiate_handle_list(NBDClient *client, Error **errp) return nbd_negotiate_send_rep(client, NBD_REP_ACK, errp); } -static void nbd_check_meta_export(NBDClient *client) +static void nbd_check_meta_export(NBDClient *client, NBDExport *exp) { - if (client->exp != client->export_meta.exp) { - client->export_meta.count = 0; + if (exp != client->contexts.exp) { + client->contexts.count = 0; } } @@ -504,6 +506,7 @@ static int nbd_negotiate_handle_export_name(NBDClient *client, bool no_zeroes, error_setg(errp, "export not found"); return -EINVAL; } + nbd_check_meta_export(client, client->exp); myflags = client->exp->nbdflags; if (client->mode >= NBD_MODE_STRUCTURED) { @@ -521,7 +524,6 @@ static int nbd_negotiate_handle_export_name(NBDClient *client, bool no_zeroes, QTAILQ_INSERT_TAIL(&client->exp->clients, client, next); blk_exp_ref(&client->exp->common); - nbd_check_meta_export(client); return 0; } @@ -641,6 +643,9 @@ static int nbd_negotiate_handle_info(NBDClient *client, Error **errp) errp, "export '%s' not present", sane_name); } + if (client->opt == NBD_OPT_GO) { + nbd_check_meta_export(client, exp); + } /* Don't bother sending NBD_INFO_NAME unless client requested it */ if (sendname) { @@ -729,7 +734,6 @@ static int nbd_negotiate_handle_info(NBDClient *client, Error **errp) client->check_align = check_align; QTAILQ_INSERT_TAIL(&client->exp->clients, client, next); blk_exp_ref(&client->exp->common); - nbd_check_meta_export(client); rc = 1; } return rc; @@ -852,7 +856,7 @@ static bool nbd_strshift(const char **str, const char *prefix) * Handle queries to 'base' namespace. For now, only the base:allocation * context is available. Return true if @query has been handled. */ -static bool nbd_meta_base_query(NBDClient *client, NBDExportMetaContexts *meta, +static bool nbd_meta_base_query(NBDClient *client, NBDMetaContexts *meta, const char *query) { if (!nbd_strshift(&query, "base:")) { @@ -872,7 +876,7 @@ static bool nbd_meta_base_query(NBDClient *client, NBDExportMetaContexts *meta, * and qemu:allocation-depth contexts are available. Return true if @query * has been handled. */ -static bool nbd_meta_qemu_query(NBDClient *client, NBDExportMetaContexts *meta, +static bool nbd_meta_qemu_query(NBDClient *client, NBDMetaContexts *meta, const char *query) { size_t i; @@ -938,7 +942,7 @@ static bool nbd_meta_qemu_query(NBDClient *client, NBDExportMetaContexts *meta, * Return -errno on I/O error, 0 if option was completely handled by * sending a reply about inconsistent lengths, or 1 on success. */ static int nbd_negotiate_meta_query(NBDClient *client, - NBDExportMetaContexts *meta, Error **errp) + NBDMetaContexts *meta, Error **errp) { int ret; g_autofree char *query = NULL; @@ -977,14 +981,14 @@ static int nbd_negotiate_meta_query(NBDClient *client, * Handle NBD_OPT_LIST_META_CONTEXT and NBD_OPT_SET_META_CONTEXT * * Return -errno on I/O error, or 0 if option was completely handled. */ -static int nbd_negotiate_meta_queries(NBDClient *client, - NBDExportMetaContexts *meta, Error **errp) +static int nbd_negotiate_meta_queries(NBDClient *client, Error **errp) { int ret; g_autofree char *export_name = NULL; /* Mark unused to work around https://bugs.llvm.org/show_bug.cgi?id=3888 */ g_autofree G_GNUC_UNUSED bool *bitmaps = NULL; - NBDExportMetaContexts local_meta = {0}; + NBDMetaContexts local_meta = {0}; + NBDMetaContexts *meta; uint32_t nb_queries; size_t i; size_t count = 0; @@ -1000,6 +1004,8 @@ static int nbd_negotiate_meta_queries(NBDClient *client, if (client->opt == NBD_OPT_LIST_META_CONTEXT) { /* Only change the caller's meta on SET. */ meta = &local_meta; + } else { + meta = &client->contexts; } g_free(meta->bitmaps); @@ -1284,8 +1290,7 @@ static int nbd_negotiate_options(NBDClient *client, Error **errp) case NBD_OPT_LIST_META_CONTEXT: case NBD_OPT_SET_META_CONTEXT: - ret = nbd_negotiate_meta_queries(client, &client->export_meta, - errp); + ret = nbd_negotiate_meta_queries(client, errp); break; case NBD_OPT_EXTENDED_HEADERS: @@ -1512,7 +1517,7 @@ void nbd_client_put(NBDClient *client) QTAILQ_REMOVE(&client->exp->clients, client, next); blk_exp_unref(&client->exp->common); } - g_free(client->export_meta.bitmaps); + g_free(client->contexts.bitmaps); g_free(client); } } @@ -2749,11 +2754,11 @@ static coroutine_fn int nbd_handle_request(NBDClient *client, } assert(client->mode >= NBD_MODE_EXTENDED || request->len <= UINT32_MAX); - if (client->export_meta.count) { + if (client->contexts.count) { bool dont_fragment = request->flags & NBD_CMD_FLAG_REQ_ONE; - int contexts_remaining = client->export_meta.count; + int contexts_remaining = client->contexts.count; - if (client->export_meta.base_allocation) { + if (client->contexts.base_allocation) { ret = nbd_co_send_block_status(client, request, exp->common.blk, request->from, @@ -2766,7 +2771,7 @@ static coroutine_fn int nbd_handle_request(NBDClient *client, } } - if (client->export_meta.allocation_depth) { + if (client->contexts.allocation_depth) { ret = nbd_co_send_block_status(client, request, exp->common.blk, request->from, request->len, @@ -2780,7 +2785,7 @@ static coroutine_fn int nbd_handle_request(NBDClient *client, } for (i = 0; i < client->exp->nr_export_bitmaps; i++) { - if (!client->export_meta.bitmaps[i]) { + if (!client->contexts.bitmaps[i]) { continue; } ret = nbd_co_send_bitmap(client, request, From 1dec4643d13cb3ba8315e07ce89c7fd4faaff2de Mon Sep 17 00:00:00 2001 From: Eric Blake Date: Mon, 25 Sep 2023 14:22:41 -0500 Subject: [PATCH 0319/1077] nbd/server: Prepare for per-request filtering of BLOCK_STATUS The next commit will add support for the optional extension NBD_CMD_FLAG_PAYLOAD during NBD_CMD_BLOCK_STATUS, where the client can request that the server only return a subset of negotiated contexts, rather than all contexts. To make that task easier, this patch populates the list of contexts to return on a per-command basis (for now, identical to the full set of negotiated contexts). Signed-off-by: Eric Blake Message-ID: <20230925192229.3186470-25-eblake@redhat.com> Reviewed-by: Vladimir Sementsov-Ogievskiy --- include/block/nbd.h | 1 + nbd/server.c | 22 +++++++++++++++++----- 2 files changed, 18 insertions(+), 5 deletions(-) diff --git a/include/block/nbd.h b/include/block/nbd.h index 2006497f98..4e7bd6342f 100644 --- a/include/block/nbd.h +++ b/include/block/nbd.h @@ -77,6 +77,7 @@ typedef struct NBDRequest { uint16_t flags; /* NBD_CMD_FLAG_* */ uint16_t type; /* NBD_CMD_* */ NBDMode mode; /* Determines which network representation to use */ + NBDMetaContexts *contexts; /* Used by NBD_CMD_BLOCK_STATUS */ } NBDRequest; typedef struct NBDSimpleReply { diff --git a/nbd/server.c b/nbd/server.c index 2719992db7..2dce9c3ad6 100644 --- a/nbd/server.c +++ b/nbd/server.c @@ -2505,6 +2505,7 @@ static int coroutine_fn nbd_co_receive_request(NBDRequestData *req, break; case NBD_CMD_BLOCK_STATUS: + request->contexts = &client->contexts; valid_flags |= NBD_CMD_FLAG_REQ_ONE; break; @@ -2748,17 +2749,18 @@ static coroutine_fn int nbd_handle_request(NBDClient *client, "discard failed", errp); case NBD_CMD_BLOCK_STATUS: + assert(request->contexts); if (!request->len) { return nbd_send_generic_reply(client, request, -EINVAL, "need non-zero length", errp); } assert(client->mode >= NBD_MODE_EXTENDED || request->len <= UINT32_MAX); - if (client->contexts.count) { + if (request->contexts->count) { bool dont_fragment = request->flags & NBD_CMD_FLAG_REQ_ONE; - int contexts_remaining = client->contexts.count; + int contexts_remaining = request->contexts->count; - if (client->contexts.base_allocation) { + if (request->contexts->base_allocation) { ret = nbd_co_send_block_status(client, request, exp->common.blk, request->from, @@ -2771,7 +2773,7 @@ static coroutine_fn int nbd_handle_request(NBDClient *client, } } - if (client->contexts.allocation_depth) { + if (request->contexts->allocation_depth) { ret = nbd_co_send_block_status(client, request, exp->common.blk, request->from, request->len, @@ -2784,8 +2786,9 @@ static coroutine_fn int nbd_handle_request(NBDClient *client, } } + assert(request->contexts->exp == client->exp); for (i = 0; i < client->exp->nr_export_bitmaps; i++) { - if (!client->contexts.bitmaps[i]) { + if (!request->contexts->bitmaps[i]) { continue; } ret = nbd_co_send_bitmap(client, request, @@ -2801,6 +2804,10 @@ static coroutine_fn int nbd_handle_request(NBDClient *client, assert(!contexts_remaining); return 0; + } else if (client->contexts.count) { + return nbd_send_generic_reply(client, request, -EINVAL, + "CMD_BLOCK_STATUS payload not valid", + errp); } else { return nbd_send_generic_reply(client, request, -EINVAL, "CMD_BLOCK_STATUS not negotiated", @@ -2879,6 +2886,11 @@ static coroutine_fn void nbd_trip(void *opaque) } else { ret = nbd_handle_request(client, &request, req->data, &local_err); } + if (request.contexts && request.contexts != &client->contexts) { + assert(request.type == NBD_CMD_BLOCK_STATUS); + g_free(request.contexts->bitmaps); + g_free(request.contexts); + } if (ret < 0) { error_prepend(&local_err, "Failed to send reply: "); goto disconnect; From 2dcbb11b399ada51f734229b612e4f561a2aae0a Mon Sep 17 00:00:00 2001 From: Eric Blake Date: Mon, 25 Sep 2023 14:22:42 -0500 Subject: [PATCH 0320/1077] nbd/server: Add FLAG_PAYLOAD support to CMD_BLOCK_STATUS Allow a client to request a subset of negotiated meta contexts. For example, a client may ask to use a single connection to learn about both block status and dirty bitmaps, but where the dirty bitmap queries only need to be performed on a subset of the disk; forcing the server to compute that information on block status queries in the rest of the disk is wasted effort (both at the server, and on the amount of traffic sent over the wire to be parsed and ignored by the client). Qemu as an NBD client never requests to use more than one meta context, so it has no need to use block status payloads. Testing this instead requires support from libnbd, which CAN access multiple meta contexts in parallel from a single NBD connection; an interop test submitted to the libnbd project at the same time as this patch demonstrates the feature working, as well as testing some corner cases (for example, when the payload length is longer than the export length), although other corner cases (like passing the same id duplicated) requires a protocol fuzzer because libnbd is not wired up to break the protocol that badly. This also includes tweaks to 'qemu-nbd --list' to show when a server is advertising the capability, and to the testsuite to reflect the addition to that output. Of note: qemu will always advertise the new feature bit during NBD_OPT_INFO if extended headers have alreay been negotiated (regardless of whether any NBD_OPT_SET_META_CONTEXT negotiation has occurred); but for NBD_OPT_GO, qemu only advertises the feature if block status is also enabled (that is, if the client does not negotiate any contexts, then NBD_CMD_BLOCK_STATUS cannot be used, so the feature is not advertised). Signed-off-by: Eric Blake Message-ID: <20230925192229.3186470-26-eblake@redhat.com> [eblake: fix logic to reject unnegotiated contexts] Signed-off-by: Eric Blake --- docs/interop/nbd.txt | 2 +- nbd/server.c | 117 ++++++++++++++++-- nbd/trace-events | 1 + qemu-nbd.c | 1 + tests/qemu-iotests/223.out | 12 +- tests/qemu-iotests/307.out | 10 +- .../tests/nbd-qemu-allocation.out | 2 +- 7 files changed, 125 insertions(+), 20 deletions(-) diff --git a/docs/interop/nbd.txt b/docs/interop/nbd.txt index 9aae5e1f29..18efb251de 100644 --- a/docs/interop/nbd.txt +++ b/docs/interop/nbd.txt @@ -69,4 +69,4 @@ NBD_CMD_BLOCK_STATUS for "qemu:dirty-bitmap:", NBD_CMD_CACHE NBD_CMD_FLAG_FAST_ZERO * 5.2: NBD_CMD_BLOCK_STATUS for "qemu:allocation-depth" * 7.1: NBD_FLAG_CAN_MULTI_CONN for shareable writable exports -* 8.2: NBD_OPT_EXTENDED_HEADERS +* 8.2: NBD_OPT_EXTENDED_HEADERS, NBD_FLAG_BLOCK_STATUS_PAYLOAD diff --git a/nbd/server.c b/nbd/server.c index 2dce9c3ad6..859c163d19 100644 --- a/nbd/server.c +++ b/nbd/server.c @@ -512,6 +512,9 @@ static int nbd_negotiate_handle_export_name(NBDClient *client, bool no_zeroes, if (client->mode >= NBD_MODE_STRUCTURED) { myflags |= NBD_FLAG_SEND_DF; } + if (client->mode >= NBD_MODE_EXTENDED && client->contexts.count) { + myflags |= NBD_FLAG_BLOCK_STAT_PAYLOAD; + } trace_nbd_negotiate_new_style_size_flags(client->exp->size, myflags); stq_be_p(buf, client->exp->size); stw_be_p(buf + 8, myflags); @@ -699,6 +702,10 @@ static int nbd_negotiate_handle_info(NBDClient *client, Error **errp) if (client->mode >= NBD_MODE_STRUCTURED) { myflags |= NBD_FLAG_SEND_DF; } + if (client->mode >= NBD_MODE_EXTENDED && + (client->contexts.count || client->opt == NBD_OPT_INFO)) { + myflags |= NBD_FLAG_BLOCK_STAT_PAYLOAD; + } trace_nbd_negotiate_new_style_size_flags(exp->size, myflags); stq_be_p(buf, exp->size); stw_be_p(buf + 8, myflags); @@ -2420,6 +2427,90 @@ static int coroutine_fn nbd_co_send_bitmap(NBDClient *client, return nbd_co_send_extents(client, request, ea, last, context_id, errp); } +/* + * nbd_co_block_status_payload_read + * Called when a client wants a subset of negotiated contexts via a + * BLOCK_STATUS payload. Check the payload for valid length and + * contents. On success, return 0 with request updated to effective + * length. If request was invalid but all payload consumed, return 0 + * with request->len and request->contexts->count set to 0 (which will + * trigger an appropriate NBD_EINVAL response later on). Return + * negative errno if the payload was not fully consumed. + */ +static int +nbd_co_block_status_payload_read(NBDClient *client, NBDRequest *request, + Error **errp) +{ + uint64_t payload_len = request->len; + g_autofree char *buf = NULL; + size_t count, i, nr_bitmaps; + uint32_t id; + + if (payload_len > NBD_MAX_BUFFER_SIZE) { + error_setg(errp, "len (%" PRIu64 ") is larger than max len (%u)", + request->len, NBD_MAX_BUFFER_SIZE); + return -EINVAL; + } + + assert(client->contexts.exp == client->exp); + nr_bitmaps = client->exp->nr_export_bitmaps; + request->contexts = g_new0(NBDMetaContexts, 1); + request->contexts->exp = client->exp; + + if (payload_len % sizeof(uint32_t) || + payload_len < sizeof(NBDBlockStatusPayload) || + payload_len > (sizeof(NBDBlockStatusPayload) + + sizeof(id) * client->contexts.count)) { + goto skip; + } + + buf = g_malloc(payload_len); + if (nbd_read(client->ioc, buf, payload_len, + "CMD_BLOCK_STATUS data", errp) < 0) { + return -EIO; + } + trace_nbd_co_receive_request_payload_received(request->cookie, + payload_len); + request->contexts->bitmaps = g_new0(bool, nr_bitmaps); + count = (payload_len - sizeof(NBDBlockStatusPayload)) / sizeof(id); + payload_len = 0; + + for (i = 0; i < count; i++) { + id = ldl_be_p(buf + sizeof(NBDBlockStatusPayload) + sizeof(id) * i); + if (id == NBD_META_ID_BASE_ALLOCATION) { + if (!client->contexts.base_allocation || + request->contexts->base_allocation) { + goto skip; + } + request->contexts->base_allocation = true; + } else if (id == NBD_META_ID_ALLOCATION_DEPTH) { + if (!client->contexts.allocation_depth || + request->contexts->allocation_depth) { + goto skip; + } + request->contexts->allocation_depth = true; + } else { + unsigned idx = id - NBD_META_ID_DIRTY_BITMAP; + + if (idx >= nr_bitmaps || !client->contexts.bitmaps[idx] || + request->contexts->bitmaps[idx]) { + goto skip; + } + request->contexts->bitmaps[idx] = true; + } + } + + request->len = ldq_be_p(buf); + request->contexts->count = count; + return 0; + + skip: + trace_nbd_co_receive_block_status_payload_compliance(request->from, + request->len); + request->len = request->contexts->count = 0; + return nbd_drop(client->ioc, payload_len, errp); +} + /* nbd_co_receive_request * Collect a client request. Return 0 if request looks valid, -EIO to drop * connection right away, -EAGAIN to indicate we were interrupted and the @@ -2505,7 +2596,18 @@ static int coroutine_fn nbd_co_receive_request(NBDRequestData *req, break; case NBD_CMD_BLOCK_STATUS: - request->contexts = &client->contexts; + if (extended_with_payload) { + ret = nbd_co_block_status_payload_read(client, request, errp); + if (ret < 0) { + return ret; + } + /* payload now consumed */ + check_length = false; + payload_len = 0; + valid_flags |= NBD_CMD_FLAG_PAYLOAD_LEN; + } else { + request->contexts = &client->contexts; + } valid_flags |= NBD_CMD_FLAG_REQ_ONE; break; @@ -2750,16 +2852,16 @@ static coroutine_fn int nbd_handle_request(NBDClient *client, case NBD_CMD_BLOCK_STATUS: assert(request->contexts); - if (!request->len) { - return nbd_send_generic_reply(client, request, -EINVAL, - "need non-zero length", errp); - } assert(client->mode >= NBD_MODE_EXTENDED || request->len <= UINT32_MAX); if (request->contexts->count) { bool dont_fragment = request->flags & NBD_CMD_FLAG_REQ_ONE; int contexts_remaining = request->contexts->count; + if (!request->len) { + return nbd_send_generic_reply(client, request, -EINVAL, + "need non-zero length", errp); + } if (request->contexts->base_allocation) { ret = nbd_co_send_block_status(client, request, exp->common.blk, @@ -2896,8 +2998,9 @@ static coroutine_fn void nbd_trip(void *opaque) goto disconnect; } - /* We must disconnect after NBD_CMD_WRITE if we did not - * read the payload. + /* + * We must disconnect after NBD_CMD_WRITE or BLOCK_STATUS with + * payload if we did not read the payload. */ if (!req->complete) { error_setg(&local_err, "Request handling failed in intermediate state"); diff --git a/nbd/trace-events b/nbd/trace-events index cb5d719ed6..00ae3216a1 100644 --- a/nbd/trace-events +++ b/nbd/trace-events @@ -70,6 +70,7 @@ nbd_co_send_chunk_read(uint64_t cookie, uint64_t offset, void *data, uint64_t si nbd_co_send_chunk_read_hole(uint64_t cookie, uint64_t offset, uint64_t size) "Send structured read hole reply: cookie = %" PRIu64 ", offset = %" PRIu64 ", len = %" PRIu64 nbd_co_send_extents(uint64_t cookie, unsigned int extents, uint32_t id, uint64_t length, int last) "Send block status reply: cookie = %" PRIu64 ", extents = %u, context = %d (extents cover %" PRIu64 " bytes, last chunk = %d)" nbd_co_send_chunk_error(uint64_t cookie, int err, const char *errname, const char *msg) "Send structured error reply: cookie = %" PRIu64 ", error = %d (%s), msg = '%s'" +nbd_co_receive_block_status_payload_compliance(uint64_t from, uint64_t len) "client sent unusable block status payload: from=0x%" PRIx64 ", len=0x%" PRIx64 nbd_co_receive_request_decode_type(uint64_t cookie, uint16_t type, const char *name) "Decoding type: cookie = %" PRIu64 ", type = %" PRIu16 " (%s)" nbd_co_receive_request_payload_received(uint64_t cookie, uint64_t len) "Payload received: cookie = %" PRIu64 ", len = %" PRIu64 nbd_co_receive_ext_payload_compliance(uint64_t from, uint64_t len) "client sent non-compliant write without payload flag: from=0x%" PRIx64 ", len=0x%" PRIx64 diff --git a/qemu-nbd.c b/qemu-nbd.c index 1a39bb8fac..186e6468b1 100644 --- a/qemu-nbd.c +++ b/qemu-nbd.c @@ -219,6 +219,7 @@ static int qemu_nbd_client_list(SocketAddress *saddr, QCryptoTLSCreds *tls, [NBD_FLAG_SEND_RESIZE_BIT] = "resize", [NBD_FLAG_SEND_CACHE_BIT] = "cache", [NBD_FLAG_SEND_FAST_ZERO_BIT] = "fast-zero", + [NBD_FLAG_BLOCK_STAT_PAYLOAD_BIT] = "block-status-payload", }; printf(" size: %" PRIu64 "\n", list[i].size); diff --git a/tests/qemu-iotests/223.out b/tests/qemu-iotests/223.out index 32f05f1c9a..e5e7f42caa 100644 --- a/tests/qemu-iotests/223.out +++ b/tests/qemu-iotests/223.out @@ -83,7 +83,7 @@ exports available: 0 exports available: 3 export: 'n' size: 4194304 - flags: 0x58f ( readonly flush fua df multi cache ) + flags: 0x158f ( readonly flush fua df multi cache block-status-payload ) min block: 1 opt block: 4096 max block: 33554432 @@ -94,7 +94,7 @@ exports available: 3 export: 'n2' description: some text size: 4194304 - flags: 0xded ( flush fua trim zeroes df multi cache fast-zero ) + flags: 0x1ded ( flush fua trim zeroes df multi cache fast-zero block-status-payload ) min block: 1 opt block: 4096 max block: 33554432 @@ -104,7 +104,7 @@ exports available: 3 qemu:dirty-bitmap:b2 export: 'n3' size: 4194304 - flags: 0x58f ( readonly flush fua df multi cache ) + flags: 0x158f ( readonly flush fua df multi cache block-status-payload ) min block: 1 opt block: 4096 max block: 33554432 @@ -205,7 +205,7 @@ exports available: 0 exports available: 3 export: 'n' size: 4194304 - flags: 0x58f ( readonly flush fua df multi cache ) + flags: 0x158f ( readonly flush fua df multi cache block-status-payload ) min block: 1 opt block: 4096 max block: 33554432 @@ -216,7 +216,7 @@ exports available: 3 export: 'n2' description: some text size: 4194304 - flags: 0xded ( flush fua trim zeroes df multi cache fast-zero ) + flags: 0x1ded ( flush fua trim zeroes df multi cache fast-zero block-status-payload ) min block: 1 opt block: 4096 max block: 33554432 @@ -226,7 +226,7 @@ exports available: 3 qemu:dirty-bitmap:b2 export: 'n3' size: 4194304 - flags: 0x58f ( readonly flush fua df multi cache ) + flags: 0x158f ( readonly flush fua df multi cache block-status-payload ) min block: 1 opt block: 4096 max block: 33554432 diff --git a/tests/qemu-iotests/307.out b/tests/qemu-iotests/307.out index 2b9a6a67a1..f645f3315f 100644 --- a/tests/qemu-iotests/307.out +++ b/tests/qemu-iotests/307.out @@ -15,7 +15,7 @@ wrote 4096/4096 bytes at offset 0 exports available: 1 export: 'fmt' size: 67108864 - flags: 0x58f ( readonly flush fua df multi cache ) + flags: 0x158f ( readonly flush fua df multi cache block-status-payload ) min block: XXX opt block: XXX max block: XXX @@ -44,7 +44,7 @@ exports available: 1 exports available: 1 export: 'fmt' size: 67108864 - flags: 0x58f ( readonly flush fua df multi cache ) + flags: 0x158f ( readonly flush fua df multi cache block-status-payload ) min block: XXX opt block: XXX max block: XXX @@ -76,7 +76,7 @@ exports available: 1 exports available: 2 export: 'fmt' size: 67108864 - flags: 0x58f ( readonly flush fua df multi cache ) + flags: 0x158f ( readonly flush fua df multi cache block-status-payload ) min block: XXX opt block: XXX max block: XXX @@ -86,7 +86,7 @@ exports available: 2 export: 'export1' description: This is the writable second export size: 67108864 - flags: 0xded ( flush fua trim zeroes df multi cache fast-zero ) + flags: 0x1ded ( flush fua trim zeroes df multi cache fast-zero block-status-payload ) min block: XXX opt block: XXX max block: XXX @@ -113,7 +113,7 @@ exports available: 1 export: 'export1' description: This is the writable second export size: 67108864 - flags: 0xded ( flush fua trim zeroes df multi cache fast-zero ) + flags: 0x1ded ( flush fua trim zeroes df multi cache fast-zero block-status-payload ) min block: XXX opt block: XXX max block: XXX diff --git a/tests/qemu-iotests/tests/nbd-qemu-allocation.out b/tests/qemu-iotests/tests/nbd-qemu-allocation.out index 1db16926ed..56b57c69ed 100644 --- a/tests/qemu-iotests/tests/nbd-qemu-allocation.out +++ b/tests/qemu-iotests/tests/nbd-qemu-allocation.out @@ -17,7 +17,7 @@ wrote 2097152/2097152 bytes at offset 1048576 exports available: 1 export: '' size: 4194304 - flags: 0x48f ( readonly flush fua df cache ) + flags: 0x148f ( readonly flush fua df cache block-status-payload ) min block: 1 opt block: 4096 max block: 33554432 From 931150e56b056b120c868f94751722710df0b6a7 Mon Sep 17 00:00:00 2001 From: Alex Williamson Date: Wed, 16 Aug 2023 15:55:49 -0600 Subject: [PATCH 0321/1077] vfio/display: Fix missing update to set backing fields MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The below referenced commit renames scanout_width/height to backing_width/height, but also promotes these fields in various portions of the egl interface. Meanwhile vfio dmabuf support has never used the previous scanout fields and is therefore missed in the update. This results in a black screen when transitioning from ramfb to dmabuf display when using Intel vGPU with these features. Resolves: https://gitlab.com/qemu-project/qemu/-/issues/1891 Link: https://lists.gnu.org/archive/html/qemu-devel/2023-08/msg02726.html Fixes: 9ac06df8b684 ("virtio-gpu-udmabuf: correct naming of QemuDmaBuf size properties") Signed-off-by: Alex Williamson Tested-by: Cédric Le Goater Signed-off-by: Cédric Le Goater --- hw/vfio/display.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/hw/vfio/display.c b/hw/vfio/display.c index bec864f482..837d9e6a30 100644 --- a/hw/vfio/display.c +++ b/hw/vfio/display.c @@ -243,6 +243,8 @@ static VFIODMABuf *vfio_display_get_dmabuf(VFIOPCIDevice *vdev, dmabuf->dmabuf_id = plane.dmabuf_id; dmabuf->buf.width = plane.width; dmabuf->buf.height = plane.height; + dmabuf->buf.backing_width = plane.width; + dmabuf->buf.backing_height = plane.height; dmabuf->buf.stride = plane.stride; dmabuf->buf.fourcc = plane.drm_format; dmabuf->buf.modifier = plane.drm_format_mod; From c06327c9db960158edc8756dbc0eb25fab920656 Mon Sep 17 00:00:00 2001 From: Zhenzhong Duan Date: Fri, 22 Sep 2023 10:52:23 +0800 Subject: [PATCH 0322/1077] vfio/pci: rename vfio_put_device to vfio_pci_put_device MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit vfio_put_device() is a VFIO PCI specific function, rename it with 'vfio_pci' prefix to avoid confusing. No functional change. Suggested-by: Cédric Le Goater Signed-off-by: Zhenzhong Duan Signed-off-by: Cédric Le Goater --- hw/vfio/pci.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/hw/vfio/pci.c b/hw/vfio/pci.c index 3b2ca3c24c..b2d5010b9f 100644 --- a/hw/vfio/pci.c +++ b/hw/vfio/pci.c @@ -2826,7 +2826,7 @@ static void vfio_populate_device(VFIOPCIDevice *vdev, Error **errp) } } -static void vfio_put_device(VFIOPCIDevice *vdev) +static void vfio_pci_put_device(VFIOPCIDevice *vdev) { g_free(vdev->vbasedev.name); g_free(vdev->msix); @@ -3317,7 +3317,7 @@ static void vfio_instance_finalize(Object *obj) * * g_free(vdev->igd_opregion); */ - vfio_put_device(vdev); + vfio_pci_put_device(vdev); vfio_put_group(group); } From 45d85f6228117dbe01d3680f1ad834389f69012f Mon Sep 17 00:00:00 2001 From: Jing Liu Date: Mon, 25 Sep 2023 22:14:04 -0400 Subject: [PATCH 0323/1077] vfio/pci: detect the support of dynamic MSI-X allocation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Kernel provides the guidance of dynamic MSI-X allocation support of passthrough device, by clearing the VFIO_IRQ_INFO_NORESIZE flag to guide user space. Fetch the flags from host to determine if dynamic MSI-X allocation is supported. Originally-by: Reinette Chatre Signed-off-by: Jing Liu Reviewed-by: Cédric Le Goater Reviewed-by: Alex Williamson Signed-off-by: Cédric Le Goater --- hw/vfio/pci.c | 16 ++++++++++++++-- hw/vfio/pci.h | 1 + hw/vfio/trace-events | 2 +- 3 files changed, 16 insertions(+), 3 deletions(-) diff --git a/hw/vfio/pci.c b/hw/vfio/pci.c index b2d5010b9f..86c92c51a4 100644 --- a/hw/vfio/pci.c +++ b/hw/vfio/pci.c @@ -1493,7 +1493,9 @@ static void vfio_msix_early_setup(VFIOPCIDevice *vdev, Error **errp) uint8_t pos; uint16_t ctrl; uint32_t table, pba; - int fd = vdev->vbasedev.fd; + int ret, fd = vdev->vbasedev.fd; + struct vfio_irq_info irq_info = { .argsz = sizeof(irq_info), + .index = VFIO_PCI_MSIX_IRQ_INDEX }; VFIOMSIXInfo *msix; pos = pci_find_capability(&vdev->pdev, PCI_CAP_ID_MSIX); @@ -1530,6 +1532,15 @@ static void vfio_msix_early_setup(VFIOPCIDevice *vdev, Error **errp) msix->pba_offset = pba & ~PCI_MSIX_FLAGS_BIRMASK; msix->entries = (ctrl & PCI_MSIX_FLAGS_QSIZE) + 1; + ret = ioctl(vdev->vbasedev.fd, VFIO_DEVICE_GET_IRQ_INFO, &irq_info); + if (ret < 0) { + error_setg_errno(errp, -ret, "failed to get MSI-X irq info"); + g_free(msix); + return; + } + + msix->noresize = !!(irq_info.flags & VFIO_IRQ_INFO_NORESIZE); + /* * Test the size of the pba_offset variable and catch if it extends outside * of the specified BAR. If it is the case, we need to apply a hardware @@ -1562,7 +1573,8 @@ static void vfio_msix_early_setup(VFIOPCIDevice *vdev, Error **errp) } trace_vfio_msix_early_setup(vdev->vbasedev.name, pos, msix->table_bar, - msix->table_offset, msix->entries); + msix->table_offset, msix->entries, + msix->noresize); vdev->msix = msix; vfio_pci_fixup_msix_region(vdev); diff --git a/hw/vfio/pci.h b/hw/vfio/pci.h index 2d836093a8..0d89eb761e 100644 --- a/hw/vfio/pci.h +++ b/hw/vfio/pci.h @@ -113,6 +113,7 @@ typedef struct VFIOMSIXInfo { uint32_t table_offset; uint32_t pba_offset; unsigned long *pending; + bool noresize; } VFIOMSIXInfo; #define TYPE_VFIO_PCI "vfio-pci" diff --git a/hw/vfio/trace-events b/hw/vfio/trace-events index e64ca4a019..0ba3c5a0e2 100644 --- a/hw/vfio/trace-events +++ b/hw/vfio/trace-events @@ -27,7 +27,7 @@ vfio_vga_read(uint64_t addr, int size, uint64_t data) " (0x%"PRIx64", %d) = 0x%" vfio_pci_read_config(const char *name, int addr, int len, int val) " (%s, @0x%x, len=0x%x) 0x%x" vfio_pci_write_config(const char *name, int addr, int val, int len) " (%s, @0x%x, 0x%x, len=0x%x)" vfio_msi_setup(const char *name, int pos) "%s PCI MSI CAP @0x%x" -vfio_msix_early_setup(const char *name, int pos, int table_bar, int offset, int entries) "%s PCI MSI-X CAP @0x%x, BAR %d, offset 0x%x, entries %d" +vfio_msix_early_setup(const char *name, int pos, int table_bar, int offset, int entries, bool noresize) "%s PCI MSI-X CAP @0x%x, BAR %d, offset 0x%x, entries %d, noresize %d" vfio_check_pcie_flr(const char *name) "%s Supports FLR via PCIe cap" vfio_check_pm_reset(const char *name) "%s Supports PM reset" vfio_check_af_flr(const char *name) "%s Supports FLR via AF cap" From d9e6710d7d59c1f774bfb49f3b1c2b5ee06ed33e Mon Sep 17 00:00:00 2001 From: Jing Liu Date: Mon, 25 Sep 2023 22:14:05 -0400 Subject: [PATCH 0324/1077] vfio/pci: enable vector on dynamic MSI-X allocation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The vector_use callback is used to enable vector that is unmasked in guest. The kernel used to only support static MSI-X allocation. When allocating a new interrupt using "static MSI-X allocation" kernels, QEMU first disables all previously allocated vectors and then re-allocates all including the new one. The nr_vectors of VFIOPCIDevice indicates that all vectors from 0 to nr_vectors are allocated (and may be enabled), which is used to loop all the possibly used vectors when e.g., disabling MSI-X interrupts. Extend the vector_use function to support dynamic MSI-X allocation when host supports the capability. QEMU therefore can individually allocate and enable a new interrupt without affecting others or causing interrupts lost during runtime. Utilize nr_vectors to calculate the upper bound of enabled vectors in dynamic MSI-X allocation mode since looping all msix_entries_nr is not efficient and unnecessary. Signed-off-by: Jing Liu Tested-by: Reinette Chatre Reviewed-by: Alex Williamson Signed-off-by: Cédric Le Goater --- hw/vfio/pci.c | 46 ++++++++++++++++++++++++++++------------------ 1 file changed, 28 insertions(+), 18 deletions(-) diff --git a/hw/vfio/pci.c b/hw/vfio/pci.c index 86c92c51a4..eb7627c5f9 100644 --- a/hw/vfio/pci.c +++ b/hw/vfio/pci.c @@ -470,6 +470,7 @@ static int vfio_msix_vector_do_use(PCIDevice *pdev, unsigned int nr, VFIOPCIDevice *vdev = VFIO_PCI(pdev); VFIOMSIVector *vector; int ret; + bool resizing = !!(vdev->nr_vectors < nr + 1); trace_vfio_msix_vector_do_use(vdev->vbasedev.name, nr); @@ -512,33 +513,42 @@ static int vfio_msix_vector_do_use(PCIDevice *pdev, unsigned int nr, } /* - * We don't want to have the host allocate all possible MSI vectors - * for a device if they're not in use, so we shutdown and incrementally - * increase them as needed. + * When dynamic allocation is not supported, we don't want to have the + * host allocate all possible MSI vectors for a device if they're not + * in use, so we shutdown and incrementally increase them as needed. + * nr_vectors represents the total number of vectors allocated. + * + * When dynamic allocation is supported, let the host only allocate + * and enable a vector when it is in use in guest. nr_vectors represents + * the upper bound of vectors being enabled (but not all of the ranges + * is allocated or enabled). */ - if (vdev->nr_vectors < nr + 1) { + if (resizing) { vdev->nr_vectors = nr + 1; - if (!vdev->defer_kvm_irq_routing) { + } + + if (!vdev->defer_kvm_irq_routing) { + if (vdev->msix->noresize && resizing) { vfio_disable_irqindex(&vdev->vbasedev, VFIO_PCI_MSIX_IRQ_INDEX); ret = vfio_enable_vectors(vdev, true); if (ret) { error_report("vfio: failed to enable vectors, %d", ret); } - } - } else { - Error *err = NULL; - int32_t fd; - - if (vector->virq >= 0) { - fd = event_notifier_get_fd(&vector->kvm_interrupt); } else { - fd = event_notifier_get_fd(&vector->interrupt); - } + Error *err = NULL; + int32_t fd; - if (vfio_set_irq_signaling(&vdev->vbasedev, - VFIO_PCI_MSIX_IRQ_INDEX, nr, - VFIO_IRQ_SET_ACTION_TRIGGER, fd, &err)) { - error_reportf_err(err, VFIO_MSG_PREFIX, vdev->vbasedev.name); + if (vector->virq >= 0) { + fd = event_notifier_get_fd(&vector->kvm_interrupt); + } else { + fd = event_notifier_get_fd(&vector->interrupt); + } + + if (vfio_set_irq_signaling(&vdev->vbasedev, + VFIO_PCI_MSIX_IRQ_INDEX, nr, + VFIO_IRQ_SET_ACTION_TRIGGER, fd, &err)) { + error_reportf_err(err, VFIO_MSG_PREFIX, vdev->vbasedev.name); + } } } From 5ebffa4e87e7a3127650ef2c0fc12e8624337ee4 Mon Sep 17 00:00:00 2001 From: Jing Liu Date: Mon, 25 Sep 2023 22:14:06 -0400 Subject: [PATCH 0325/1077] vfio/pci: use an invalid fd to enable MSI-X MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Guests typically enable MSI-X with all of the vectors masked in the MSI-X vector table. To match the guest state of device, QEMU enables MSI-X by enabling vector 0 with userspace triggering and immediately release. However the release function actually does not release it due to already using userspace mode. It is no need to enable triggering on host and rely on the mask bit to avoid spurious interrupts. Use an invalid fd (i.e. fd = -1) is enough to get MSI-X enabled. After dynamic MSI-X allocation is supported, the interrupt restoring also need use such way to enable MSI-X, therefore, create a function for that. Suggested-by: Alex Williamson Signed-off-by: Jing Liu Reviewed-by: Cédric Le Goater Reviewed-by: Alex Williamson Signed-off-by: Cédric Le Goater --- hw/vfio/pci.c | 44 ++++++++++++++++++++++++++++++++++++-------- 1 file changed, 36 insertions(+), 8 deletions(-) diff --git a/hw/vfio/pci.c b/hw/vfio/pci.c index eb7627c5f9..ad508abd6f 100644 --- a/hw/vfio/pci.c +++ b/hw/vfio/pci.c @@ -369,6 +369,33 @@ static void vfio_msi_interrupt(void *opaque) notify(&vdev->pdev, nr); } +/* + * Get MSI-X enabled, but no vector enabled, by setting vector 0 with an invalid + * fd to kernel. + */ +static int vfio_enable_msix_no_vec(VFIOPCIDevice *vdev) +{ + g_autofree struct vfio_irq_set *irq_set = NULL; + int ret = 0, argsz; + int32_t *fd; + + argsz = sizeof(*irq_set) + sizeof(*fd); + + irq_set = g_malloc0(argsz); + irq_set->argsz = argsz; + irq_set->flags = VFIO_IRQ_SET_DATA_EVENTFD | + VFIO_IRQ_SET_ACTION_TRIGGER; + irq_set->index = VFIO_PCI_MSIX_IRQ_INDEX; + irq_set->start = 0; + irq_set->count = 1; + fd = (int32_t *)&irq_set->data; + *fd = -1; + + ret = ioctl(vdev->vbasedev.fd, VFIO_DEVICE_SET_IRQS, irq_set); + + return ret; +} + static int vfio_enable_vectors(VFIOPCIDevice *vdev, bool msix) { struct vfio_irq_set *irq_set; @@ -618,6 +645,8 @@ static void vfio_commit_kvm_msi_virq_batch(VFIOPCIDevice *vdev) static void vfio_msix_enable(VFIOPCIDevice *vdev) { + int ret; + vfio_disable_interrupts(vdev); vdev->msi_vectors = g_new0(VFIOMSIVector, vdev->msix->entries); @@ -640,8 +669,6 @@ static void vfio_msix_enable(VFIOPCIDevice *vdev) vfio_commit_kvm_msi_virq_batch(vdev); if (vdev->nr_vectors) { - int ret; - ret = vfio_enable_vectors(vdev, true); if (ret) { error_report("vfio: failed to enable vectors, %d", ret); @@ -655,13 +682,14 @@ static void vfio_msix_enable(VFIOPCIDevice *vdev) * MSI-X capability, but leaves the vector table masked. We therefore * can't rely on a vector_use callback (from request_irq() in the guest) * to switch the physical device into MSI-X mode because that may come a - * long time after pci_enable_msix(). This code enables vector 0 with - * triggering to userspace, then immediately release the vector, leaving - * the physical device with no vectors enabled, but MSI-X enabled, just - * like the guest view. + * long time after pci_enable_msix(). This code sets vector 0 with an + * invalid fd to make the physical device MSI-X enabled, but with no + * vectors enabled, just like the guest view. */ - vfio_msix_vector_do_use(&vdev->pdev, 0, NULL, NULL); - vfio_msix_vector_release(&vdev->pdev, 0); + ret = vfio_enable_msix_no_vec(vdev); + if (ret) { + error_report("vfio: failed to enable MSI-X, %d", ret); + } } trace_vfio_msix_enable(vdev->vbasedev.name); From eaadba6f9b14823e52ee154d0052d69907deee8a Mon Sep 17 00:00:00 2001 From: Jing Liu Date: Mon, 25 Sep 2023 22:14:07 -0400 Subject: [PATCH 0326/1077] vfio/pci: enable MSI-X in interrupt restoring on dynamic allocation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit During migration restoring, vfio_enable_vectors() is called to restore enabling MSI-X interrupts for assigned devices. It sets the range from 0 to nr_vectors to kernel to enable MSI-X and the vectors unmasked in guest. During the MSI-X enabling, all the vectors within the range are allocated according to the VFIO_DEVICE_SET_IRQS ioctl. When dynamic MSI-X allocation is supported, we only want the guest unmasked vectors being allocated and enabled. Use vector 0 with an invalid fd to get MSI-X enabled, after that, all the vectors can be allocated in need. Signed-off-by: Jing Liu Reviewed-by: Cédric Le Goater Reviewed-by: Alex Williamson Signed-off-by: Cédric Le Goater --- hw/vfio/pci.c | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/hw/vfio/pci.c b/hw/vfio/pci.c index ad508abd6f..898296fd54 100644 --- a/hw/vfio/pci.c +++ b/hw/vfio/pci.c @@ -402,6 +402,23 @@ static int vfio_enable_vectors(VFIOPCIDevice *vdev, bool msix) int ret = 0, i, argsz; int32_t *fds; + /* + * If dynamic MSI-X allocation is supported, the vectors to be allocated + * and enabled can be scattered. Before kernel enabling MSI-X, setting + * nr_vectors causes all these vectors to be allocated on host. + * + * To keep allocation as needed, use vector 0 with an invalid fd to get + * MSI-X enabled first, then set vectors with a potentially sparse set of + * eventfds to enable interrupts only when enabled in guest. + */ + if (msix && !vdev->msix->noresize) { + ret = vfio_enable_msix_no_vec(vdev); + + if (ret) { + return ret; + } + } + argsz = sizeof(*irq_set) + (vdev->nr_vectors * sizeof(*fds)); irq_set = g_malloc0(argsz); From d43e967f692ab5389da9a8fa3064ffc6586a3d13 Mon Sep 17 00:00:00 2001 From: Mark Cave-Ayland Date: Wed, 4 Oct 2023 09:37:47 +0100 Subject: [PATCH 0327/1077] q800-glue.c: convert to Resettable interface MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Convert the GLUE device to 3-phase reset. The legacy method doesn't do anything that's invalid in the hold phase, so the conversion is simple and not a behaviour change. Signed-off-by: Mark Cave-Ayland Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Laurent Vivier Message-ID: <20231004083806.757242-2-mark.cave-ayland@ilande.co.uk> Signed-off-by: Laurent Vivier --- hw/m68k/q800-glue.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/hw/m68k/q800-glue.c b/hw/m68k/q800-glue.c index 34c4f0e987..710a5c331e 100644 --- a/hw/m68k/q800-glue.c +++ b/hw/m68k/q800-glue.c @@ -166,9 +166,9 @@ static void glue_nmi_release(void *opaque) GLUE_set_irq(s, GLUE_IRQ_IN_NMI, 0); } -static void glue_reset(DeviceState *dev) +static void glue_reset_hold(Object *obj) { - GLUEState *s = GLUE(dev); + GLUEState *s = GLUE(obj); s->ipr = 0; s->auxmode = 0; @@ -223,11 +223,12 @@ static void glue_init(Object *obj) static void glue_class_init(ObjectClass *klass, void *data) { DeviceClass *dc = DEVICE_CLASS(klass); + ResettableClass *rc = RESETTABLE_CLASS(klass); NMIClass *nc = NMI_CLASS(klass); dc->vmsd = &vmstate_glue; - dc->reset = glue_reset; device_class_set_props(dc, glue_properties); + rc->phases.hold = glue_reset_hold; nc->nmi_monitor_handler = glue_nmi; } From e2fd695e9daf4d31386e26695dcc61fef5363fed Mon Sep 17 00:00:00 2001 From: Mark Cave-Ayland Date: Wed, 4 Oct 2023 09:37:48 +0100 Subject: [PATCH 0328/1077] q800: add djMEMC memory controller MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The djMEMC controller is used to store information related to the physical memory configuration. Co-developed-by: Laurent Vivier Signed-off-by: Mark Cave-Ayland Reviewed-by: Philippe Mathieu-Daudé Message-ID: <20231004083806.757242-3-mark.cave-ayland@ilande.co.uk> Signed-off-by: Laurent Vivier --- MAINTAINERS | 2 + hw/m68k/Kconfig | 1 + hw/m68k/q800.c | 10 +++ hw/misc/Kconfig | 3 + hw/misc/djmemc.c | 135 +++++++++++++++++++++++++++++++++++++++ hw/misc/meson.build | 1 + hw/misc/trace-events | 4 ++ include/hw/m68k/q800.h | 2 + include/hw/misc/djmemc.h | 30 +++++++++ 9 files changed, 188 insertions(+) create mode 100644 hw/misc/djmemc.c create mode 100644 include/hw/misc/djmemc.h diff --git a/MAINTAINERS b/MAINTAINERS index ea91f9e804..dead0d4a47 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1229,6 +1229,7 @@ F: hw/misc/mac_via.c F: hw/nubus/* F: hw/display/macfb.c F: hw/block/swim.c +F: hw/misc/djmemc.c F: hw/m68k/bootinfo.h F: include/standard-headers/asm-m68k/bootinfo.h F: include/standard-headers/asm-m68k/bootinfo-mac.h @@ -1238,6 +1239,7 @@ F: include/hw/display/macfb.h F: include/hw/block/swim.h F: include/hw/m68k/q800.h F: include/hw/m68k/q800-glue.h +F: include/hw/misc/djmemc.h virt M: Laurent Vivier diff --git a/hw/m68k/Kconfig b/hw/m68k/Kconfig index f839f8a030..330cfdfa2d 100644 --- a/hw/m68k/Kconfig +++ b/hw/m68k/Kconfig @@ -23,6 +23,7 @@ config Q800 select ESP select DP8393X select OR_IRQ + select DJMEMC config M68K_VIRT bool diff --git a/hw/m68k/q800.c b/hw/m68k/q800.c index b770b71d54..f9ecc1fbb0 100644 --- a/hw/m68k/q800.c +++ b/hw/m68k/q800.c @@ -40,6 +40,7 @@ #include "hw/m68k/q800.h" #include "hw/m68k/q800-glue.h" #include "hw/misc/mac_via.h" +#include "hw/misc/djmemc.h" #include "hw/input/adb.h" #include "hw/nubus/mac-nubus-bridge.h" #include "hw/display/macfb.h" @@ -66,6 +67,7 @@ #define SONIC_PROM_BASE (IO_BASE + 0x08000) #define SONIC_BASE (IO_BASE + 0x0a000) #define SCC_BASE (IO_BASE + 0x0c020) +#define DJMEMC_BASE (IO_BASE + 0x0e000) #define ESP_BASE (IO_BASE + 0x10000) #define ESP_PDMA (IO_BASE + 0x10100) #define ASC_BASE (IO_BASE + 0x14000) @@ -257,6 +259,14 @@ static void q800_machine_init(MachineState *machine) &error_abort); sysbus_realize(SYS_BUS_DEVICE(&m->glue), &error_fatal); + /* djMEMC memory controller */ + object_initialize_child(OBJECT(machine), "djmemc", &m->djmemc, + TYPE_DJMEMC); + sysbus = SYS_BUS_DEVICE(&m->djmemc); + sysbus_realize_and_unref(sysbus, &error_fatal); + memory_region_add_subregion(&m->macio, DJMEMC_BASE - IO_BASE, + sysbus_mmio_get_region(sysbus, 0)); + /* VIA 1 */ object_initialize_child(OBJECT(machine), "via1", &m->via1, TYPE_MOS6522_Q800_VIA1); diff --git a/hw/misc/Kconfig b/hw/misc/Kconfig index 6996d265e4..cb7857e3ed 100644 --- a/hw/misc/Kconfig +++ b/hw/misc/Kconfig @@ -186,4 +186,7 @@ config AXP2XX_PMU bool depends on I2C +config DJMEMC + bool + source macio/Kconfig diff --git a/hw/misc/djmemc.c b/hw/misc/djmemc.c new file mode 100644 index 0000000000..fd02640838 --- /dev/null +++ b/hw/misc/djmemc.c @@ -0,0 +1,135 @@ +/* + * djMEMC, macintosh memory and interrupt controller + * (Quadra 610/650/800 & Centris 610/650) + * + * https://mac68k.info/wiki/display/mac68k/djMEMC+Information + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +#include "qemu/osdep.h" +#include "qemu/log.h" +#include "migration/vmstate.h" +#include "hw/misc/djmemc.h" +#include "hw/qdev-properties.h" +#include "trace.h" + + +#define DJMEMC_INTERLEAVECONF 0x0 +#define DJMEMC_BANK0CONF 0x4 +#define DJMEMC_BANK1CONF 0x8 +#define DJMEMC_BANK2CONF 0xc +#define DJMEMC_BANK3CONF 0x10 +#define DJMEMC_BANK4CONF 0x14 +#define DJMEMC_BANK5CONF 0x18 +#define DJMEMC_BANK6CONF 0x1c +#define DJMEMC_BANK7CONF 0x20 +#define DJMEMC_BANK8CONF 0x24 +#define DJMEMC_BANK9CONF 0x28 +#define DJMEMC_MEMTOP 0x2c +#define DJMEMC_CONFIG 0x30 +#define DJMEMC_REFRESH 0x34 + + +static uint64_t djmemc_read(void *opaque, hwaddr addr, unsigned size) +{ + DJMEMCState *s = opaque; + uint64_t val = 0; + + switch (addr) { + case DJMEMC_INTERLEAVECONF: + case DJMEMC_BANK0CONF ... DJMEMC_BANK9CONF: + case DJMEMC_MEMTOP: + case DJMEMC_CONFIG: + case DJMEMC_REFRESH: + val = s->regs[addr >> 2]; + break; + default: + qemu_log_mask(LOG_UNIMP, "djMEMC: unimplemented read addr=0x%"PRIx64 + " val=0x%"PRIx64 " size=%d\n", + addr, val, size); + } + + trace_djmemc_read(addr, val, size); + return val; +} + +static void djmemc_write(void *opaque, hwaddr addr, uint64_t val, + unsigned size) +{ + DJMEMCState *s = opaque; + + trace_djmemc_write(addr, val, size); + + switch (addr) { + case DJMEMC_INTERLEAVECONF: + case DJMEMC_BANK0CONF ... DJMEMC_BANK9CONF: + case DJMEMC_MEMTOP: + case DJMEMC_CONFIG: + case DJMEMC_REFRESH: + s->regs[addr >> 2] = val; + break; + default: + qemu_log_mask(LOG_UNIMP, "djMEMC: unimplemented write addr=0x%"PRIx64 + " val=0x%"PRIx64 " size=%d\n", + addr, val, size); + } +} + +static const MemoryRegionOps djmemc_mmio_ops = { + .read = djmemc_read, + .write = djmemc_write, + .impl = { + .min_access_size = 4, + .max_access_size = 4, + }, + .endianness = DEVICE_BIG_ENDIAN, +}; + +static void djmemc_init(Object *obj) +{ + DJMEMCState *s = DJMEMC(obj); + SysBusDevice *sbd = SYS_BUS_DEVICE(obj); + + memory_region_init_io(&s->mem_regs, obj, &djmemc_mmio_ops, s, "djMEMC", + DJMEMC_SIZE); + sysbus_init_mmio(sbd, &s->mem_regs); +} + +static void djmemc_reset_hold(Object *obj) +{ + DJMEMCState *s = DJMEMC(obj); + + memset(s->regs, 0, sizeof(s->regs)); +} + +static const VMStateDescription vmstate_djmemc = { + .name = "djMEMC", + .version_id = 1, + .minimum_version_id = 1, + .fields = (VMStateField[]) { + VMSTATE_UINT32_ARRAY(regs, DJMEMCState, DJMEMC_NUM_REGS), + VMSTATE_END_OF_LIST() + } +}; + +static void djmemc_class_init(ObjectClass *oc, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(oc); + ResettableClass *rc = RESETTABLE_CLASS(oc); + + dc->vmsd = &vmstate_djmemc; + rc->phases.hold = djmemc_reset_hold; +} + +static const TypeInfo djmemc_info_types[] = { + { + .name = TYPE_DJMEMC, + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(DJMEMCState), + .instance_init = djmemc_init, + .class_init = djmemc_class_init, + }, +}; + +DEFINE_TYPES(djmemc_info_types) diff --git a/hw/misc/meson.build b/hw/misc/meson.build index 88ecab8392..ee5ee37648 100644 --- a/hw/misc/meson.build +++ b/hw/misc/meson.build @@ -20,6 +20,7 @@ system_ss.add(when: 'CONFIG_ARM_V7M', if_true: files('armv7m_ras.c')) # Mac devices system_ss.add(when: 'CONFIG_MOS6522', if_true: files('mos6522.c')) +system_ss.add(when: 'CONFIG_DJMEMC', if_true: files('djmemc.c')) # virt devices system_ss.add(when: 'CONFIG_VIRT_CTRL', if_true: files('virt_ctrl.c')) diff --git a/hw/misc/trace-events b/hw/misc/trace-events index bc87cd3670..c71a47d288 100644 --- a/hw/misc/trace-events +++ b/hw/misc/trace-events @@ -301,3 +301,7 @@ virt_ctrl_instance_init(void *dev) "ctrl: %p" lasi_chip_mem_valid(uint64_t addr, uint32_t val) "access to addr 0x%"PRIx64" is %d" lasi_chip_read(uint64_t addr, uint32_t val) "addr 0x%"PRIx64" val 0x%08x" lasi_chip_write(uint64_t addr, uint32_t val) "addr 0x%"PRIx64" val 0x%08x" + +# djmemc.c +djmemc_read(int reg, uint64_t value, unsigned int size) "reg=0x%x value=0x%"PRIx64" size=%u" +djmemc_write(int reg, uint64_t value, unsigned int size) "reg=0x%x value=0x%"PRIx64" size=%u" diff --git a/include/hw/m68k/q800.h b/include/hw/m68k/q800.h index b3d77f1cba..f6ae4c1c4f 100644 --- a/include/hw/m68k/q800.h +++ b/include/hw/m68k/q800.h @@ -36,6 +36,7 @@ #include "hw/block/swim.h" #include "hw/nubus/mac-nubus-bridge.h" #include "hw/display/macfb.h" +#include "hw/misc/djmemc.h" /* * The main Q800 machine @@ -56,6 +57,7 @@ struct Q800MachineState { Swim swim; MacNubusBridge mac_nubus_bridge; MacfbNubusState macfb; + DJMEMCState djmemc; MemoryRegion macio; MemoryRegion macio_alias; }; diff --git a/include/hw/misc/djmemc.h b/include/hw/misc/djmemc.h new file mode 100644 index 0000000000..82d4e4a2fe --- /dev/null +++ b/include/hw/misc/djmemc.h @@ -0,0 +1,30 @@ +/* + * djMEMC, macintosh memory and interrupt controller + * (Quadra 610/650/800 & Centris 610/650) + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +#ifndef HW_MISC_DJMEMC_H +#define HW_MISC_DJMEMC_H + +#include "hw/sysbus.h" + +#define DJMEMC_SIZE 0x2000 +#define DJMEMC_NUM_REGS (0x38 / sizeof(uint32_t)) + +#define DJMEMC_MAXBANKS 10 + +struct DJMEMCState { + SysBusDevice parent_obj; + + MemoryRegion mem_regs; + + /* Memory controller */ + uint32_t regs[DJMEMC_NUM_REGS]; +}; + +#define TYPE_DJMEMC "djMEMC" +OBJECT_DECLARE_SIMPLE_TYPE(DJMEMCState, DJMEMC); + +#endif From e993af36a7bf2d1299f932098c9b19766626d7d8 Mon Sep 17 00:00:00 2001 From: Mark Cave-Ayland Date: Wed, 4 Oct 2023 09:37:49 +0100 Subject: [PATCH 0329/1077] q800: add machine id register MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit MacOS reads this address to identify the hardware. This is a basic implementation returning the ID of Quadra 800. Details: http://mess.redump.net/mess/driver_info/mac_technical_notes "There are 3 ID schemes [...] The third and most scalable is a machine ID register at 0x5ffffffc. The top word must be 0xa55a to be valid. Then bits 15-11 are 0 for consumer Macs, 1 for portables, 2 for high-end 68k, and 3 for high-end PowerPC. Bit 10 is 1 if additional ID bits appear elsewhere (e.g. in VIA1). The rest of the bits are a per-model identifier. Model Lower 16 bits of ID ... Quadra/Centris 610/650/800 0x2BAD" Co-developed-by: Laurent Vivier Signed-off-by: Mark Cave-Ayland Reviewed-by: Philippe Mathieu-Daudé Message-ID: <20231004083806.757242-4-mark.cave-ayland@ilande.co.uk> Signed-off-by: Laurent Vivier --- hw/m68k/q800.c | 29 +++++++++++++++++++++++++++++ include/hw/m68k/q800.h | 1 + 2 files changed, 30 insertions(+) diff --git a/hw/m68k/q800.c b/hw/m68k/q800.c index f9ecc1fbb0..ac8509ba6f 100644 --- a/hw/m68k/q800.c +++ b/hw/m68k/q800.c @@ -91,6 +91,9 @@ #define Q800_NUBUS_SLOTS_AVAILABLE (BIT(0x9) | BIT(0xc) | BIT(0xd) | \ BIT(0xe)) +/* Quadra 800 machine ID */ +#define Q800_MACHINE_ID 0xa55a2bad + static void main_cpu_reset(void *opaque) { @@ -192,6 +195,27 @@ static const MemoryRegionOps macio_alias_ops = { }, }; +static uint64_t machine_id_read(void *opaque, hwaddr addr, unsigned size) +{ + return Q800_MACHINE_ID; +} + +static void machine_id_write(void *opaque, hwaddr addr, uint64_t val, + unsigned size) +{ + return; +} + +static const MemoryRegionOps machine_id_ops = { + .read = machine_id_read, + .write = machine_id_write, + .endianness = DEVICE_BIG_ENDIAN, + .valid = { + .min_access_size = 4, + .max_access_size = 4, + }, +}; + static void q800_machine_init(MachineState *machine) { Q800MachineState *m = Q800_MACHINE(machine); @@ -253,6 +277,11 @@ static void q800_machine_init(MachineState *machine) memory_region_add_subregion(get_system_memory(), IO_BASE + IO_SLICE, &m->macio_alias); + memory_region_init_io(&m->machine_id, NULL, &machine_id_ops, NULL, + "Machine ID", 4); + memory_region_add_subregion(get_system_memory(), 0x5ffffffc, + &m->machine_id); + /* IRQ Glue */ object_initialize_child(OBJECT(machine), "glue", &m->glue, TYPE_GLUE); object_property_set_link(OBJECT(&m->glue), "cpu", OBJECT(&m->cpu), diff --git a/include/hw/m68k/q800.h b/include/hw/m68k/q800.h index f6ae4c1c4f..dd7d7a6f2c 100644 --- a/include/hw/m68k/q800.h +++ b/include/hw/m68k/q800.h @@ -60,6 +60,7 @@ struct Q800MachineState { DJMEMCState djmemc; MemoryRegion macio; MemoryRegion macio_alias; + MemoryRegion machine_id; }; #define TYPE_Q800_MACHINE MACHINE_TYPE_NAME("q800") From 0f03047c1b09fcccf16bcf1c2d8d9e375155adfd Mon Sep 17 00:00:00 2001 From: Mark Cave-Ayland Date: Wed, 4 Oct 2023 09:37:50 +0100 Subject: [PATCH 0330/1077] q800: implement additional machine id bits on VIA1 port A MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-developed-by: Laurent Vivier Signed-off-by: Mark Cave-Ayland Reviewed-by: Philippe Mathieu-Daudé Message-ID: <20231004083806.757242-5-mark.cave-ayland@ilande.co.uk> Signed-off-by: Laurent Vivier --- hw/misc/mac_via.c | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/hw/misc/mac_via.c b/hw/misc/mac_via.c index f84cc68849..e87a1b82d8 100644 --- a/hw/misc/mac_via.c +++ b/hw/misc/mac_via.c @@ -114,6 +114,9 @@ #define VIA1A_CPUID1 0x04 /* CPU id bit 0 on RBV, others */ #define VIA1A_CPUID2 0x10 /* CPU id bit 0 on RBV, others */ #define VIA1A_CPUID3 0x40 /* CPU id bit 0 on RBV, others */ +#define VIA1A_CPUID_MASK (VIA1A_CPUID0 | VIA1A_CPUID1 | \ + VIA1A_CPUID2 | VIA1A_CPUID3) +#define VIA1A_CPUID_Q800 (VIA1A_CPUID0 | VIA1A_CPUID2) /* * Info on VIA1B is from Macintosh Family Hardware & MkLinux. @@ -872,9 +875,18 @@ static uint64_t mos6522_q800_via1_read(void *opaque, hwaddr addr, unsigned size) { MOS6522Q800VIA1State *s = MOS6522_Q800_VIA1(opaque); MOS6522State *ms = MOS6522(s); + uint64_t ret; addr = (addr >> 9) & 0xf; - return mos6522_read(ms, addr, size); + ret = mos6522_read(ms, addr, size); + switch (addr) { + case VIA_REG_A: + case VIA_REG_ANH: + /* Quadra 800 Id */ + ret = (ret & ~VIA1A_CPUID_MASK) | VIA1A_CPUID_Q800; + break; + } + return ret; } static void mos6522_q800_via1_write(void *opaque, hwaddr addr, uint64_t val, From bdc2c77d2922d8274608b8dbc70b956494853f1b Mon Sep 17 00:00:00 2001 From: Mark Cave-Ayland Date: Wed, 4 Oct 2023 09:37:51 +0100 Subject: [PATCH 0331/1077] q800: add IOSB subsystem It is needed because it defines the BIOSConfig area. Co-developed-by: Laurent Vivier Signed-off-by: Mark Cave-Ayland Reviewed-by: BALATON Zoltan Message-ID: <20231004083806.757242-6-mark.cave-ayland@ilande.co.uk> Signed-off-by: Laurent Vivier --- MAINTAINERS | 2 + hw/m68k/Kconfig | 1 + hw/m68k/q800.c | 9 +++ hw/misc/Kconfig | 3 + hw/misc/iosb.c | 133 +++++++++++++++++++++++++++++++++++++++++ hw/misc/meson.build | 1 + hw/misc/trace-events | 4 ++ include/hw/m68k/q800.h | 2 + include/hw/misc/iosb.h | 25 ++++++++ 9 files changed, 180 insertions(+) create mode 100644 hw/misc/iosb.c create mode 100644 include/hw/misc/iosb.h diff --git a/MAINTAINERS b/MAINTAINERS index dead0d4a47..38fc8e0a22 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1230,6 +1230,7 @@ F: hw/nubus/* F: hw/display/macfb.c F: hw/block/swim.c F: hw/misc/djmemc.c +F: hw/misc/iosb.c F: hw/m68k/bootinfo.h F: include/standard-headers/asm-m68k/bootinfo.h F: include/standard-headers/asm-m68k/bootinfo-mac.h @@ -1240,6 +1241,7 @@ F: include/hw/block/swim.h F: include/hw/m68k/q800.h F: include/hw/m68k/q800-glue.h F: include/hw/misc/djmemc.h +F: include/hw/misc/iosb.h virt M: Laurent Vivier diff --git a/hw/m68k/Kconfig b/hw/m68k/Kconfig index 330cfdfa2d..64fa70a0db 100644 --- a/hw/m68k/Kconfig +++ b/hw/m68k/Kconfig @@ -24,6 +24,7 @@ config Q800 select DP8393X select OR_IRQ select DJMEMC + select IOSB config M68K_VIRT bool diff --git a/hw/m68k/q800.c b/hw/m68k/q800.c index ac8509ba6f..081b95e9cf 100644 --- a/hw/m68k/q800.c +++ b/hw/m68k/q800.c @@ -41,6 +41,7 @@ #include "hw/m68k/q800-glue.h" #include "hw/misc/mac_via.h" #include "hw/misc/djmemc.h" +#include "hw/misc/iosb.h" #include "hw/input/adb.h" #include "hw/nubus/mac-nubus-bridge.h" #include "hw/display/macfb.h" @@ -71,6 +72,7 @@ #define ESP_BASE (IO_BASE + 0x10000) #define ESP_PDMA (IO_BASE + 0x10100) #define ASC_BASE (IO_BASE + 0x14000) +#define IOSB_BASE (IO_BASE + 0x18000) #define SWIM_BASE (IO_BASE + 0x1E000) #define SONIC_PROM_SIZE 0x1000 @@ -296,6 +298,13 @@ static void q800_machine_init(MachineState *machine) memory_region_add_subregion(&m->macio, DJMEMC_BASE - IO_BASE, sysbus_mmio_get_region(sysbus, 0)); + /* IOSB subsystem */ + object_initialize_child(OBJECT(machine), "iosb", &m->iosb, TYPE_IOSB); + sysbus = SYS_BUS_DEVICE(&m->iosb); + sysbus_realize_and_unref(sysbus, &error_fatal); + memory_region_add_subregion(&m->macio, IOSB_BASE - IO_BASE, + sysbus_mmio_get_region(sysbus, 0)); + /* VIA 1 */ object_initialize_child(OBJECT(machine), "via1", &m->via1, TYPE_MOS6522_Q800_VIA1); diff --git a/hw/misc/Kconfig b/hw/misc/Kconfig index cb7857e3ed..858277bb60 100644 --- a/hw/misc/Kconfig +++ b/hw/misc/Kconfig @@ -189,4 +189,7 @@ config AXP2XX_PMU config DJMEMC bool +config IOSB + bool + source macio/Kconfig diff --git a/hw/misc/iosb.c b/hw/misc/iosb.c new file mode 100644 index 0000000000..e7e9dcca47 --- /dev/null +++ b/hw/misc/iosb.c @@ -0,0 +1,133 @@ +/* + * QEMU IOSB emulation + * + * Copyright (c) 2019 Laurent Vivier + * Copyright (c) 2022 Mark Cave-Ayland + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +#include "qemu/osdep.h" +#include "qemu/log.h" +#include "migration/vmstate.h" +#include "hw/sysbus.h" +#include "hw/misc/iosb.h" +#include "trace.h" + +#define IOSB_SIZE 0x2000 + +#define IOSB_CONFIG 0x0 +#define IOSB_CONFIG2 0x100 +#define IOSB_SONIC_SCSI 0x200 +#define IOSB_REVISION 0x300 +#define IOSB_SCSI_RESID 0x400 +#define IOSB_BRIGHTNESS 0x500 +#define IOSB_TIMEOUT 0x600 + + +static uint64_t iosb_read(void *opaque, hwaddr addr, + unsigned size) +{ + IOSBState *s = IOSB(opaque); + uint64_t val = 0; + + switch (addr) { + case IOSB_CONFIG: + case IOSB_CONFIG2: + case IOSB_SONIC_SCSI: + case IOSB_REVISION: + case IOSB_SCSI_RESID: + case IOSB_BRIGHTNESS: + case IOSB_TIMEOUT: + val = s->regs[addr >> 8]; + break; + default: + qemu_log_mask(LOG_UNIMP, "IOSB: unimplemented read addr=0x%"PRIx64 + " val=0x%"PRIx64 " size=%d\n", + addr, val, size); + } + + trace_iosb_read(addr, val, size); + return val; +} + +static void iosb_write(void *opaque, hwaddr addr, uint64_t val, + unsigned size) +{ + IOSBState *s = IOSB(opaque); + + switch (addr) { + case IOSB_CONFIG: + case IOSB_CONFIG2: + case IOSB_SONIC_SCSI: + case IOSB_REVISION: + case IOSB_SCSI_RESID: + case IOSB_BRIGHTNESS: + case IOSB_TIMEOUT: + s->regs[addr >> 8] = val; + break; + default: + qemu_log_mask(LOG_UNIMP, "IOSB: unimplemented write addr=0x%"PRIx64 + " val=0x%"PRIx64 " size=%d\n", + addr, val, size); + } + + trace_iosb_write(addr, val, size); +} + +static const MemoryRegionOps iosb_mmio_ops = { + .read = iosb_read, + .write = iosb_write, + .endianness = DEVICE_BIG_ENDIAN, +}; + +static void iosb_reset_hold(Object *obj) +{ + IOSBState *s = IOSB(obj); + + memset(s->regs, 0, sizeof(s->regs)); + + /* BCLK 33 MHz */ + s->regs[IOSB_CONFIG >> 8] = 1; +} + +static void iosb_init(Object *obj) +{ + IOSBState *s = IOSB(obj); + SysBusDevice *sbd = SYS_BUS_DEVICE(obj); + + memory_region_init_io(&s->mem_regs, obj, &iosb_mmio_ops, s, "IOSB", + IOSB_SIZE); + sysbus_init_mmio(sbd, &s->mem_regs); +} + +static const VMStateDescription vmstate_iosb = { + .name = "IOSB", + .version_id = 1, + .minimum_version_id = 1, + .fields = (VMStateField[]) { + VMSTATE_UINT32_ARRAY(regs, IOSBState, IOSB_REGS), + VMSTATE_END_OF_LIST() + } +}; + +static void iosb_class_init(ObjectClass *oc, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(oc); + ResettableClass *rc = RESETTABLE_CLASS(oc); + + dc->vmsd = &vmstate_iosb; + rc->phases.hold = iosb_reset_hold; +} + +static const TypeInfo iosb_info_types[] = { + { + .name = TYPE_IOSB, + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(IOSBState), + .instance_init = iosb_init, + .class_init = iosb_class_init, + }, +}; + +DEFINE_TYPES(iosb_info_types) diff --git a/hw/misc/meson.build b/hw/misc/meson.build index ee5ee37648..33659313b4 100644 --- a/hw/misc/meson.build +++ b/hw/misc/meson.build @@ -21,6 +21,7 @@ system_ss.add(when: 'CONFIG_ARM_V7M', if_true: files('armv7m_ras.c')) # Mac devices system_ss.add(when: 'CONFIG_MOS6522', if_true: files('mos6522.c')) system_ss.add(when: 'CONFIG_DJMEMC', if_true: files('djmemc.c')) +system_ss.add(when: 'CONFIG_IOSB', if_true: files('iosb.c')) # virt devices system_ss.add(when: 'CONFIG_VIRT_CTRL', if_true: files('virt_ctrl.c')) diff --git a/hw/misc/trace-events b/hw/misc/trace-events index c71a47d288..29bc531d4d 100644 --- a/hw/misc/trace-events +++ b/hw/misc/trace-events @@ -305,3 +305,7 @@ lasi_chip_write(uint64_t addr, uint32_t val) "addr 0x%"PRIx64" val 0x%08x" # djmemc.c djmemc_read(int reg, uint64_t value, unsigned int size) "reg=0x%x value=0x%"PRIx64" size=%u" djmemc_write(int reg, uint64_t value, unsigned int size) "reg=0x%x value=0x%"PRIx64" size=%u" + +# iosb.c +iosb_read(int reg, uint64_t value, unsigned int size) "reg=0x%x value=0x%"PRIx64" size=%u" +iosb_write(int reg, uint64_t value, unsigned int size) "reg=0x%x value=0x%"PRIx64" size=%u" diff --git a/include/hw/m68k/q800.h b/include/hw/m68k/q800.h index dd7d7a6f2c..98097165d9 100644 --- a/include/hw/m68k/q800.h +++ b/include/hw/m68k/q800.h @@ -37,6 +37,7 @@ #include "hw/nubus/mac-nubus-bridge.h" #include "hw/display/macfb.h" #include "hw/misc/djmemc.h" +#include "hw/misc/iosb.h" /* * The main Q800 machine @@ -58,6 +59,7 @@ struct Q800MachineState { MacNubusBridge mac_nubus_bridge; MacfbNubusState macfb; DJMEMCState djmemc; + IOSBState iosb; MemoryRegion macio; MemoryRegion macio_alias; MemoryRegion machine_id; diff --git a/include/hw/misc/iosb.h b/include/hw/misc/iosb.h new file mode 100644 index 0000000000..377f8ca7e2 --- /dev/null +++ b/include/hw/misc/iosb.h @@ -0,0 +1,25 @@ +/* + * QEMU IOSB emulation + * + * Copyright (c) 2019 Laurent Vivier + * Copyright (c) 2022 Mark Cave-Ayland + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +#ifndef HW_MEM_IOSB_H +#define HW_MEM_IOSB_H + +#define IOSB_REGS 7 + +struct IOSBState { + SysBusDevice parent_obj; + + MemoryRegion mem_regs; + uint32_t regs[IOSB_REGS]; +}; + +#define TYPE_IOSB "IOSB" +OBJECT_DECLARE_SIMPLE_TYPE(IOSBState, IOSB); + +#endif From 6997f26d0dfd11f27a42caa04c3a20287452f364 Mon Sep 17 00:00:00 2001 From: Mark Cave-Ayland Date: Wed, 4 Oct 2023 09:37:52 +0100 Subject: [PATCH 0332/1077] q800: allow accesses to RAM area even if less memory is available MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit MacOS attempts a series of writes and reads over the entire RAM area in order to determine the amount of RAM within the machine. Allow accesses to the entire RAM area ignoring writes and always reading zero for areas where there is no physical RAM installed to allow MacOS to detect the memory size without faulting. Signed-off-by: Mark Cave-Ayland Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Laurent Vivier Message-ID: <20231004083806.757242-7-mark.cave-ayland@ilande.co.uk> Signed-off-by: Laurent Vivier --- hw/m68k/q800.c | 30 +++++++++++++++++++++++++++++- include/hw/m68k/q800.h | 1 + 2 files changed, 30 insertions(+), 1 deletion(-) diff --git a/hw/m68k/q800.c b/hw/m68k/q800.c index 081b95e9cf..3209309173 100644 --- a/hw/m68k/q800.c +++ b/hw/m68k/q800.c @@ -86,6 +86,9 @@ #define MAC_CLOCK 3686418 +/* Size of whole RAM area */ +#define RAM_SIZE 0x40000000 + /* * Slot 0x9 is reserved for use by the in-built framebuffer whilst only * slots 0xc, 0xd and 0xe physically exist on the Quadra 800 @@ -218,6 +221,27 @@ static const MemoryRegionOps machine_id_ops = { }, }; +static uint64_t ramio_read(void *opaque, hwaddr addr, unsigned size) +{ + return 0x0; +} + +static void ramio_write(void *opaque, hwaddr addr, uint64_t val, + unsigned size) +{ + return; +} + +static const MemoryRegionOps ramio_ops = { + .read = ramio_read, + .write = ramio_write, + .endianness = DEVICE_BIG_ENDIAN, + .valid = { + .min_access_size = 1, + .max_access_size = 4, + }, +}; + static void q800_machine_init(MachineState *machine) { Q800MachineState *m = Q800_MACHINE(machine); @@ -262,7 +286,11 @@ static void q800_machine_init(MachineState *machine) qemu_register_reset(main_cpu_reset, &m->cpu); /* RAM */ - memory_region_add_subregion(get_system_memory(), 0, machine->ram); + memory_region_init_io(&m->ramio, OBJECT(machine), &ramio_ops, &m->ramio, + "ram", RAM_SIZE); + memory_region_add_subregion(get_system_memory(), 0x0, &m->ramio); + + memory_region_add_subregion(&m->ramio, 0, machine->ram); /* * Create container for all IO devices diff --git a/include/hw/m68k/q800.h b/include/hw/m68k/q800.h index 98097165d9..04e4e0bce3 100644 --- a/include/hw/m68k/q800.h +++ b/include/hw/m68k/q800.h @@ -60,6 +60,7 @@ struct Q800MachineState { MacfbNubusState macfb; DJMEMCState djmemc; IOSBState iosb; + MemoryRegion ramio; MemoryRegion macio; MemoryRegion macio_alias; MemoryRegion machine_id; From ac13a6b3fd7421606822bd20c7d847c0756fd32d Mon Sep 17 00:00:00 2001 From: Mark Cave-Ayland Date: Wed, 4 Oct 2023 09:37:53 +0100 Subject: [PATCH 0333/1077] audio: add Apple Sound Chip (ASC) emulation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The Apple Sound Chip was primarily used by the Macintosh II to generate sound in hardware which was previously handled by the toolbox ROM with software interrupts. Implement both the standard ASC and also the enhanced ASC (EASC) functionality which is used in the Quadra 800. Note that whilst real ASC hardware uses AUDIO_FORMAT_S8, this implementation uses AUDIO_FORMAT_U8 instead because AUDIO_FORMAT_S8 is rarely used and not supported by some audio backends like PulseAudio and DirectSound when played directly with -audiodev out.mixing-engine=off. Co-developed-by: Laurent Vivier Co-developed-by: Volker Rümelin Signed-off-by: Mark Cave-Ayland Message-ID: <20231004083806.757242-8-mark.cave-ayland@ilande.co.uk> Signed-off-by: Laurent Vivier --- MAINTAINERS | 2 + hw/audio/Kconfig | 3 + hw/audio/asc.c | 708 +++++++++++++++++++++++++++++++++++++++++ hw/audio/meson.build | 1 + hw/audio/trace-events | 10 + hw/m68k/Kconfig | 1 + include/hw/audio/asc.h | 84 +++++ 7 files changed, 809 insertions(+) create mode 100644 hw/audio/asc.c create mode 100644 include/hw/audio/asc.h diff --git a/MAINTAINERS b/MAINTAINERS index 38fc8e0a22..ac865c4e59 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1231,6 +1231,7 @@ F: hw/display/macfb.c F: hw/block/swim.c F: hw/misc/djmemc.c F: hw/misc/iosb.c +F: hw/audio/asc.c F: hw/m68k/bootinfo.h F: include/standard-headers/asm-m68k/bootinfo.h F: include/standard-headers/asm-m68k/bootinfo-mac.h @@ -1242,6 +1243,7 @@ F: include/hw/m68k/q800.h F: include/hw/m68k/q800-glue.h F: include/hw/misc/djmemc.h F: include/hw/misc/iosb.h +F: include/hw/audio/asc.h virt M: Laurent Vivier diff --git a/hw/audio/Kconfig b/hw/audio/Kconfig index e76c69ca7e..d0993514a1 100644 --- a/hw/audio/Kconfig +++ b/hw/audio/Kconfig @@ -47,3 +47,6 @@ config PL041 config CS4231 bool + +config ASC + bool diff --git a/hw/audio/asc.c b/hw/audio/asc.c new file mode 100644 index 0000000000..9084708eaf --- /dev/null +++ b/hw/audio/asc.c @@ -0,0 +1,708 @@ +/* + * QEMU Apple Sound Chip emulation + * + * Apple Sound Chip (ASC) 344S0063 + * Enhanced Apple Sound Chip (EASC) 343S1063 + * + * Copyright (c) 2012-2018 Laurent Vivier + * Copyright (c) 2022 Mark Cave-Ayland + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +#include "qemu/osdep.h" +#include "qemu/timer.h" +#include "hw/sysbus.h" +#include "hw/irq.h" +#include "audio/audio.h" +#include "hw/audio/asc.h" +#include "hw/qdev-properties.h" +#include "migration/vmstate.h" +#include "trace.h" + +/* + * Linux doesn't provide information about ASC, see arch/m68k/mac/macboing.c + * and arch/m68k/include/asm/mac_asc.h + * + * best information is coming from MAME: + * https://github.com/mamedev/mame/blob/master/src/devices/sound/asc.h + * https://github.com/mamedev/mame/blob/master/src/devices/sound/asc.cpp + * Emulation by R. Belmont + * or MESS: + * http://mess.redump.net/mess/driver_info/easc + * + * 0x800: VERSION + * 0x801: MODE + * 1=FIFO mode, + * 2=wavetable mode + * 0x802: CONTROL + * bit 0=analog or PWM output, + * 1=stereo/mono, + * 7=processing time exceeded + * 0x803: FIFO MODE + * bit 7=clear FIFO, + * bit 1="non-ROM companding", + * bit 0="ROM companding") + * 0x804: FIFO IRQ STATUS + * bit 0=ch A 1/2 full, + * 1=ch A full, + * 2=ch B 1/2 full, + * 3=ch B full) + * 0x805: WAVETABLE CONTROL + * bits 0-3 wavetables 0-3 start + * 0x806: VOLUME + * bits 2-4 = 3 bit internal ASC volume, + * bits 5-7 = volume control sent to Sony sound chip + * 0x807: CLOCK RATE + * 0 = Mac 22257 Hz, + * 1 = undefined, + * 2 = 22050 Hz, + * 3 = 44100 Hz + * 0x80a: PLAY REC A + * 0x80f: TEST + * bits 6-7 = digital test, + * bits 4-5 = analog test + * 0x810: WAVETABLE 0 PHASE + * big-endian 9.15 fixed-point, only 24 bits valid + * 0x814: WAVETABLE 0 INCREMENT + * big-endian 9.15 fixed-point, only 24 bits valid + * 0x818: WAVETABLE 1 PHASE + * 0x81C: WAVETABLE 1 INCREMENT + * 0x820: WAVETABLE 2 PHASE + * 0x824: WAVETABLE 2 INCREMENT + * 0x828: WAVETABLE 3 PHASE + * 0x82C: WAVETABLE 3 INCREMENT + * 0x830: UNKNOWN START + * NetBSD writes Wavetable data here (are there more + * wavetables/channels than we know about?) + * 0x857: UNKNOWN END + */ + +#define ASC_SIZE 0x2000 + +enum { + ASC_VERSION = 0x00, + ASC_MODE = 0x01, + ASC_CONTROL = 0x02, + ASC_FIFOMODE = 0x03, + ASC_FIFOIRQ = 0x04, + ASC_WAVECTRL = 0x05, + ASC_VOLUME = 0x06, + ASC_CLOCK = 0x07, + ASC_PLAYRECA = 0x0a, + ASC_TEST = 0x0f, + ASC_WAVETABLE = 0x10 +}; + +#define ASC_FIFO_STATUS_HALF_FULL 1 +#define ASC_FIFO_STATUS_FULL_EMPTY 2 + +#define ASC_EXTREGS_FIFOCTRL 0x8 +#define ASC_EXTREGS_INTCTRL 0x9 +#define ASC_EXTREGS_CDXA_DECOMP_FILT 0x10 + +#define ASC_FIFO_CYCLE_TIME ((NANOSECONDS_PER_SECOND / ASC_FREQ) * \ + 0x400) + +static void asc_raise_irq(ASCState *s) +{ + qemu_set_irq(s->irq, 1); +} + +static void asc_lower_irq(ASCState *s) +{ + qemu_set_irq(s->irq, 0); +} + +static uint8_t asc_fifo_get(ASCFIFOState *fs) +{ + ASCState *s = container_of(fs, ASCState, fifos[fs->index]); + bool fifo_half_irq_enabled = fs->extregs[ASC_EXTREGS_INTCTRL] & 1; + uint8_t val; + + assert(fs->cnt); + + val = fs->fifo[fs->rptr]; + trace_asc_fifo_get('A' + fs->index, fs->rptr, fs->cnt, val); + + fs->rptr++; + fs->rptr &= 0x3ff; + fs->cnt--; + + if (fs->cnt <= 0x1ff) { + /* FIFO less than half full */ + fs->int_status |= ASC_FIFO_STATUS_HALF_FULL; + } else { + /* FIFO more than half full */ + fs->int_status &= ~ASC_FIFO_STATUS_HALF_FULL; + } + + if (fs->cnt == 0x1ff && fifo_half_irq_enabled) { + /* Raise FIFO half full IRQ */ + asc_raise_irq(s); + } + + if (fs->cnt == 0) { + /* Raise FIFO empty IRQ */ + fs->int_status |= ASC_FIFO_STATUS_FULL_EMPTY; + asc_raise_irq(s); + } + + return val; +} + +static int generate_fifo(ASCState *s, int maxsamples) +{ + int64_t now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); + uint8_t *buf = s->mixbuf; + int i, wcount = 0; + + while (wcount < maxsamples) { + uint8_t val; + int16_t d, f0, f1; + int32_t t; + int shift, filter; + bool hasdata = false; + + for (i = 0; i < 2; i++) { + ASCFIFOState *fs = &s->fifos[i]; + + switch (fs->extregs[ASC_EXTREGS_FIFOCTRL] & 0x83) { + case 0x82: + /* + * CD-XA BRR mode: decompress 15 bytes into 28 16-bit + * samples + */ + if (!fs->cnt) { + val = 0x80; + break; + } + + if (fs->xa_cnt == -1) { + /* Start of packet, get flags */ + fs->xa_flags = asc_fifo_get(fs); + fs->xa_cnt = 0; + } + + shift = fs->xa_flags & 0xf; + filter = fs->xa_flags >> 4; + f0 = (int8_t)fs->extregs[ASC_EXTREGS_CDXA_DECOMP_FILT + + (filter << 1) + 1]; + f1 = (int8_t)fs->extregs[ASC_EXTREGS_CDXA_DECOMP_FILT + + (filter << 1)]; + + if ((fs->xa_cnt & 1) == 0) { + if (!fs->cnt) { + val = 0x80; + break; + } + + fs->xa_val = asc_fifo_get(fs); + d = (fs->xa_val & 0xf) << 12; + } else { + d = (fs->xa_val & 0xf0) << 8; + } + t = (d >> shift) + (((fs->xa_last[0] * f0) + + (fs->xa_last[1] * f1) + 32) >> 6); + if (t < -32768) { + t = -32768; + } else if (t > 32767) { + t = 32767; + } + + /* + * CD-XA BRR generates 16-bit signed output, so convert to + * 8-bit before writing to buffer. Does real hardware do the + * same? + */ + val = (uint8_t)(t / 256) ^ 0x80; + hasdata = true; + fs->xa_cnt++; + + fs->xa_last[1] = fs->xa_last[0]; + fs->xa_last[0] = (int16_t)t; + + if (fs->xa_cnt == 28) { + /* End of packet */ + fs->xa_cnt = -1; + } + break; + + default: + /* fallthrough */ + case 0x80: + /* Raw mode */ + if (fs->cnt) { + val = asc_fifo_get(fs); + hasdata = true; + } else { + val = 0x80; + } + break; + } + + buf[wcount * 2 + i] = val; + } + + if (!hasdata) { + break; + } + + wcount++; + } + + /* + * MacOS (un)helpfully leaves the FIFO engine running even when it has + * finished writing out samples, but still expects the FIFO empty + * interrupts to be generated for each FIFO cycle (without these interrupts + * MacOS will freeze) + */ + if (s->fifos[0].cnt == 0 && s->fifos[1].cnt == 0) { + if (!s->fifo_empty_ns) { + /* FIFO has completed first empty cycle */ + s->fifo_empty_ns = now; + } else if (now > (s->fifo_empty_ns + ASC_FIFO_CYCLE_TIME)) { + /* FIFO has completed entire cycle with no data */ + s->fifos[0].int_status |= ASC_FIFO_STATUS_HALF_FULL | + ASC_FIFO_STATUS_FULL_EMPTY; + s->fifos[1].int_status |= ASC_FIFO_STATUS_HALF_FULL | + ASC_FIFO_STATUS_FULL_EMPTY; + s->fifo_empty_ns = now; + asc_raise_irq(s); + } + } else { + /* FIFO contains data, reset empty time */ + s->fifo_empty_ns = 0; + } + + return wcount; +} + +static int generate_wavetable(ASCState *s, int maxsamples) +{ + uint8_t *buf = s->mixbuf; + int channel, count = 0; + + while (count < maxsamples) { + uint32_t left = 0, right = 0; + uint8_t sample; + + for (channel = 0; channel < 4; channel++) { + ASCFIFOState *fs = &s->fifos[channel >> 1]; + int chanreg = ASC_WAVETABLE + (channel << 3); + uint32_t phase, incr, offset; + + phase = ldl_be_p(&s->regs[chanreg]); + incr = ldl_be_p(&s->regs[chanreg + sizeof(uint32_t)]); + + phase += incr; + offset = (phase >> 15) & 0x1ff; + sample = fs->fifo[0x200 * (channel >> 1) + offset]; + + stl_be_p(&s->regs[chanreg], phase); + + left += sample; + right += sample; + } + + buf[count * 2] = left >> 2; + buf[count * 2 + 1] = right >> 2; + + count++; + } + + return count; +} + +static void asc_out_cb(void *opaque, int free_b) +{ + ASCState *s = opaque; + int samples, generated; + + if (free_b == 0) { + return; + } + + samples = MIN(s->samples, free_b >> s->shift); + + switch (s->regs[ASC_MODE] & 3) { + default: + /* Off */ + generated = 0; + break; + case 1: + /* FIFO mode */ + generated = generate_fifo(s, samples); + break; + case 2: + /* Wave table mode */ + generated = generate_wavetable(s, samples); + break; + } + + if (!generated) { + return; + } + + AUD_write(s->voice, s->mixbuf, generated << s->shift); +} + +static uint64_t asc_fifo_read(void *opaque, hwaddr addr, + unsigned size) +{ + ASCFIFOState *fs = opaque; + + trace_asc_read_fifo('A' + fs->index, addr, size, fs->fifo[addr]); + return fs->fifo[addr]; +} + +static void asc_fifo_write(void *opaque, hwaddr addr, uint64_t value, + unsigned size) +{ + ASCFIFOState *fs = opaque; + ASCState *s = container_of(fs, ASCState, fifos[fs->index]); + bool fifo_half_irq_enabled = fs->extregs[ASC_EXTREGS_INTCTRL] & 1; + + trace_asc_write_fifo('A' + fs->index, addr, size, fs->wptr, fs->cnt, value); + + if (s->regs[ASC_MODE] == 1) { + fs->fifo[fs->wptr++] = value; + fs->wptr &= 0x3ff; + fs->cnt++; + + if (fs->cnt <= 0x1ff) { + /* FIFO less than half full */ + fs->int_status |= ASC_FIFO_STATUS_HALF_FULL; + } else { + /* FIFO at least half full */ + fs->int_status &= ~ASC_FIFO_STATUS_HALF_FULL; + } + + if (fs->cnt == 0x200 && fifo_half_irq_enabled) { + /* Raise FIFO half full interrupt */ + asc_raise_irq(s); + } + + if (fs->cnt == 0x3ff) { + /* Raise FIFO full interrupt */ + fs->int_status |= ASC_FIFO_STATUS_FULL_EMPTY; + asc_raise_irq(s); + } + } else { + fs->fifo[addr] = value; + } + return; +} + +static const MemoryRegionOps asc_fifo_ops = { + .read = asc_fifo_read, + .write = asc_fifo_write, + .impl = { + .min_access_size = 1, + .max_access_size = 1, + }, + .endianness = DEVICE_BIG_ENDIAN, +}; + +static void asc_fifo_reset(ASCFIFOState *fs); + +static uint64_t asc_read(void *opaque, hwaddr addr, + unsigned size) +{ + ASCState *s = opaque; + uint64_t prev, value; + + switch (addr) { + case ASC_VERSION: + switch (s->type) { + default: + case ASC_TYPE_ASC: + value = 0; + break; + case ASC_TYPE_EASC: + value = 0xb0; + break; + } + break; + case ASC_FIFOIRQ: + prev = (s->fifos[0].int_status & 0x3) | + (s->fifos[1].int_status & 0x3) << 2; + + s->fifos[0].int_status = 0; + s->fifos[1].int_status = 0; + asc_lower_irq(s); + value = prev; + break; + default: + value = s->regs[addr]; + break; + } + + trace_asc_read_reg(addr, size, value); + return value; +} + +static void asc_write(void *opaque, hwaddr addr, uint64_t value, + unsigned size) +{ + ASCState *s = opaque; + + switch (addr) { + case ASC_MODE: + value &= 3; + if (value != s->regs[ASC_MODE]) { + asc_fifo_reset(&s->fifos[0]); + asc_fifo_reset(&s->fifos[1]); + asc_lower_irq(s); + if (value != 0) { + AUD_set_active_out(s->voice, 1); + } else { + AUD_set_active_out(s->voice, 0); + } + } + break; + case ASC_FIFOMODE: + if (value & 0x80) { + asc_fifo_reset(&s->fifos[0]); + asc_fifo_reset(&s->fifos[1]); + asc_lower_irq(s); + } + break; + case ASC_WAVECTRL: + break; + case ASC_VOLUME: + { + int vol = (value & 0xe0); + + AUD_set_volume_out(s->voice, 0, vol, vol); + break; + } + } + + trace_asc_write_reg(addr, size, value); + s->regs[addr] = value; +} + +static const MemoryRegionOps asc_regs_ops = { + .read = asc_read, + .write = asc_write, + .endianness = DEVICE_BIG_ENDIAN, + .impl = { + .min_access_size = 1, + .max_access_size = 1, + } +}; + +static uint64_t asc_ext_read(void *opaque, hwaddr addr, + unsigned size) +{ + ASCFIFOState *fs = opaque; + uint64_t value; + + value = fs->extregs[addr]; + + trace_asc_read_extreg('A' + fs->index, addr, size, value); + return value; +} + +static void asc_ext_write(void *opaque, hwaddr addr, uint64_t value, + unsigned size) +{ + ASCFIFOState *fs = opaque; + + trace_asc_write_extreg('A' + fs->index, addr, size, value); + + fs->extregs[addr] = value; +} + +static const MemoryRegionOps asc_extregs_ops = { + .read = asc_ext_read, + .write = asc_ext_write, + .impl = { + .min_access_size = 1, + .max_access_size = 1, + }, + .endianness = DEVICE_BIG_ENDIAN, +}; + +static int asc_post_load(void *opaque, int version) +{ + ASCState *s = ASC(opaque); + + if (s->regs[ASC_MODE] != 0) { + AUD_set_active_out(s->voice, 1); + } + + return 0; +} + +static const VMStateDescription vmstate_asc_fifo = { + .name = "apple-sound-chip.fifo", + .version_id = 0, + .minimum_version_id = 0, + .fields = (VMStateField[]) { + VMSTATE_UINT8_ARRAY(fifo, ASCFIFOState, ASC_FIFO_SIZE), + VMSTATE_UINT8(int_status, ASCFIFOState), + VMSTATE_INT32(cnt, ASCFIFOState), + VMSTATE_INT32(wptr, ASCFIFOState), + VMSTATE_INT32(rptr, ASCFIFOState), + VMSTATE_UINT8_ARRAY(extregs, ASCFIFOState, ASC_EXTREG_SIZE), + VMSTATE_INT32(xa_cnt, ASCFIFOState), + VMSTATE_UINT8(xa_val, ASCFIFOState), + VMSTATE_UINT8(xa_flags, ASCFIFOState), + VMSTATE_INT16_ARRAY(xa_last, ASCFIFOState, 2), + VMSTATE_END_OF_LIST() + } +}; + +static const VMStateDescription vmstate_asc = { + .name = "apple-sound-chip", + .version_id = 0, + .minimum_version_id = 0, + .post_load = asc_post_load, + .fields = (VMStateField[]) { + VMSTATE_STRUCT_ARRAY(fifos, ASCState, 2, 0, vmstate_asc_fifo, + ASCFIFOState), + VMSTATE_UINT8_ARRAY(regs, ASCState, ASC_REG_SIZE), + VMSTATE_INT64(fifo_empty_ns, ASCState), + VMSTATE_END_OF_LIST() + } +}; + +static void asc_fifo_reset(ASCFIFOState *fs) +{ + fs->wptr = 0; + fs->rptr = 0; + fs->cnt = 0; + fs->xa_cnt = -1; + fs->int_status = 0; +} + +static void asc_fifo_init(ASCFIFOState *fs, int index) +{ + ASCState *s = container_of(fs, ASCState, fifos[index]); + char *name; + + fs->index = index; + name = g_strdup_printf("asc.fifo%c", 'A' + index); + memory_region_init_io(&fs->mem_fifo, OBJECT(s), &asc_fifo_ops, fs, + name, ASC_FIFO_SIZE); + g_free(name); + + name = g_strdup_printf("asc.extregs%c", 'A' + index); + memory_region_init_io(&fs->mem_extregs, OBJECT(s), &asc_extregs_ops, + fs, name, ASC_EXTREG_SIZE); + g_free(name); +} + +static void asc_reset_hold(Object *obj) +{ + ASCState *s = ASC(obj); + + AUD_set_active_out(s->voice, 0); + + memset(s->regs, 0, sizeof(s->regs)); + asc_fifo_reset(&s->fifos[0]); + asc_fifo_reset(&s->fifos[1]); + s->fifo_empty_ns = 0; + + if (s->type == ASC_TYPE_ASC) { + /* FIFO half full IRQs enabled by default */ + s->fifos[0].extregs[ASC_EXTREGS_INTCTRL] = 1; + s->fifos[1].extregs[ASC_EXTREGS_INTCTRL] = 1; + } +} + +static void asc_unrealize(DeviceState *dev) +{ + ASCState *s = ASC(dev); + + g_free(s->mixbuf); + + AUD_remove_card(&s->card); +} + +static void asc_realize(DeviceState *dev, Error **errp) +{ + ASCState *s = ASC(dev); + struct audsettings as; + + if (!AUD_register_card("Apple Sound Chip", &s->card, errp)) { + return; + } + + as.freq = ASC_FREQ; + as.nchannels = 2; + as.fmt = AUDIO_FORMAT_U8; + as.endianness = AUDIO_HOST_ENDIANNESS; + + s->voice = AUD_open_out(&s->card, s->voice, "asc.out", s, asc_out_cb, + &as); + s->shift = 1; + s->samples = AUD_get_buffer_size_out(s->voice) >> s->shift; + s->mixbuf = g_malloc0(s->samples << s->shift); + + /* Add easc registers if required */ + if (s->type == ASC_TYPE_EASC) { + memory_region_add_subregion(&s->asc, ASC_EXTREG_OFFSET, + &s->fifos[0].mem_extregs); + memory_region_add_subregion(&s->asc, + ASC_EXTREG_OFFSET + ASC_EXTREG_SIZE, + &s->fifos[1].mem_extregs); + } +} + +static void asc_init(Object *obj) +{ + ASCState *s = ASC(obj); + SysBusDevice *sbd = SYS_BUS_DEVICE(obj); + + memory_region_init(&s->asc, OBJECT(obj), "asc", ASC_SIZE); + + asc_fifo_init(&s->fifos[0], 0); + asc_fifo_init(&s->fifos[1], 1); + + memory_region_add_subregion(&s->asc, ASC_FIFO_OFFSET, + &s->fifos[0].mem_fifo); + memory_region_add_subregion(&s->asc, + ASC_FIFO_OFFSET + ASC_FIFO_SIZE, + &s->fifos[1].mem_fifo); + + memory_region_init_io(&s->mem_regs, OBJECT(obj), &asc_regs_ops, s, + "asc.regs", ASC_REG_SIZE); + memory_region_add_subregion(&s->asc, ASC_REG_OFFSET, &s->mem_regs); + + sysbus_init_irq(sbd, &s->irq); + sysbus_init_mmio(sbd, &s->asc); +} + +static Property asc_properties[] = { + DEFINE_AUDIO_PROPERTIES(ASCState, card), + DEFINE_PROP_UINT8("asctype", ASCState, type, ASC_TYPE_ASC), + DEFINE_PROP_END_OF_LIST(), +}; + +static void asc_class_init(ObjectClass *oc, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(oc); + ResettableClass *rc = RESETTABLE_CLASS(oc); + + dc->realize = asc_realize; + dc->unrealize = asc_unrealize; + set_bit(DEVICE_CATEGORY_SOUND, dc->categories); + dc->vmsd = &vmstate_asc; + device_class_set_props(dc, asc_properties); + rc->phases.hold = asc_reset_hold; +} + +static const TypeInfo asc_info_types[] = { + { + .name = TYPE_ASC, + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(ASCState), + .instance_init = asc_init, + .class_init = asc_class_init, + }, +}; + +DEFINE_TYPES(asc_info_types) diff --git a/hw/audio/meson.build b/hw/audio/meson.build index d0fda1009e..8805322f5c 100644 --- a/hw/audio/meson.build +++ b/hw/audio/meson.build @@ -1,6 +1,7 @@ system_ss.add(files('soundhw.c')) system_ss.add(when: 'CONFIG_AC97', if_true: files('ac97.c')) system_ss.add(when: 'CONFIG_ADLIB', if_true: files('fmopl.c', 'adlib.c')) +system_ss.add(when: 'CONFIG_ASC', if_true: files('asc.c')) system_ss.add(when: 'CONFIG_CS4231', if_true: files('cs4231.c')) system_ss.add(when: 'CONFIG_CS4231A', if_true: files('cs4231a.c')) system_ss.add(when: 'CONFIG_ES1370', if_true: files('es1370.c')) diff --git a/hw/audio/trace-events b/hw/audio/trace-events index 4dec48a4fd..89ef2996e5 100644 --- a/hw/audio/trace-events +++ b/hw/audio/trace-events @@ -17,3 +17,13 @@ via_ac97_codec_write(uint8_t addr, uint16_t val) "0x%x <- 0x%x" via_ac97_sgd_fetch(uint32_t curr, uint32_t addr, char stop, char eol, char flag, uint32_t len) "curr=0x%x addr=0x%x %c%c%c len=%d" via_ac97_sgd_read(uint64_t addr, unsigned size, uint64_t val) "0x%"PRIx64" %d -> 0x%"PRIx64 via_ac97_sgd_write(uint64_t addr, unsigned size, uint64_t val) "0x%"PRIx64" %d <- 0x%"PRIx64 + +# asc.c +asc_read_fifo(const char fifo, int reg, unsigned size, uint64_t value) "fifo %c reg=0x%03x size=%u value=0x%"PRIx64 +asc_read_reg(int reg, unsigned size, uint64_t value) "reg=0x%03x size=%u value=0x%"PRIx64 +asc_read_extreg(const char fifo, int reg, unsigned size, uint64_t value) "fifo %c reg=0x%03x size=%u value=0x%"PRIx64 +asc_fifo_get(const char fifo, int rptr, int cnt, uint64_t value) "fifo %c rptr=0x%x cnt=0x%x value=0x%"PRIx64 +asc_write_fifo(const char fifo, int reg, unsigned size, int wrptr, int cnt, uint64_t value) "fifo %c reg=0x%03x size=%u wptr=0x%x cnt=0x%x value=0x%"PRIx64 +asc_write_reg(int reg, unsigned size, uint64_t value) "reg=0x%03x size=%u value=0x%"PRIx64 +asc_write_extreg(const char fifo, int reg, unsigned size, uint64_t value) "fifo %c reg=0x%03x size=%u value=0x%"PRIx64 +asc_update_irq(int irq, int a, int b) "set IRQ to %d (A: 0x%x B: 0x%x)" diff --git a/hw/m68k/Kconfig b/hw/m68k/Kconfig index 64fa70a0db..d88741ec9d 100644 --- a/hw/m68k/Kconfig +++ b/hw/m68k/Kconfig @@ -25,6 +25,7 @@ config Q800 select OR_IRQ select DJMEMC select IOSB + select ASC config M68K_VIRT bool diff --git a/include/hw/audio/asc.h b/include/hw/audio/asc.h new file mode 100644 index 0000000000..d9412815c3 --- /dev/null +++ b/include/hw/audio/asc.h @@ -0,0 +1,84 @@ +/* + * QEMU Apple Sound Chip emulation + * + * Apple Sound Chip (ASC) 344S0063 + * Enhanced Apple Sound Chip (EASC) 343S1063 + * + * Copyright (c) 2012-2018 Laurent Vivier + * Copyright (c) 2022 Mark Cave-Ayland + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +#ifndef HW_AUDIO_ASC_H +#define HW_AUDIO_ASC_H + +#include "qemu/osdep.h" +#include "hw/sysbus.h" +#include "audio/audio.h" + +#define ASC_FREQ 22257 + +enum { + ASC_TYPE_ASC = 0, /* original discrete Apple Sound Chip */ + ASC_TYPE_EASC = 1 /* discrete Enhanced Apple Sound Chip */ +}; + +#define ASC_FIFO_OFFSET 0x0 +#define ASC_FIFO_SIZE 0x400 + +#define ASC_REG_OFFSET 0x800 +#define ASC_REG_SIZE 0x60 + +#define ASC_EXTREG_OFFSET 0xf00 +#define ASC_EXTREG_SIZE 0x20 + +typedef struct ASCFIFOState { + int index; + + MemoryRegion mem_fifo; + uint8_t fifo[ASC_FIFO_SIZE]; + uint8_t int_status; + + int cnt; + int wptr; + int rptr; + + MemoryRegion mem_extregs; + uint8_t extregs[ASC_EXTREG_SIZE]; + + int xa_cnt; + uint8_t xa_val; + uint8_t xa_flags; + int16_t xa_last[2]; +} ASCFIFOState; + +struct ASCState { + SysBusDevice parent_obj; + + uint8_t type; + MemoryRegion asc; + MemoryRegion mem_fifo; + MemoryRegion mem_regs; + MemoryRegion mem_extregs; + + QEMUSoundCard card; + SWVoiceOut *voice; + uint8_t *mixbuf; + int samples; + int shift; + + /* Time when we were last able to generate samples */ + int64_t fifo_empty_ns; + + qemu_irq irq; + + ASCFIFOState fifos[2]; + + uint8_t regs[ASC_REG_SIZE]; +}; + +#define TYPE_ASC "apple-sound-chip" +OBJECT_DECLARE_SIMPLE_TYPE(ASCState, ASC) + +#endif From 5243e5543e27410984d84a30aa7d7b7210d14daa Mon Sep 17 00:00:00 2001 From: Mark Cave-Ayland Date: Wed, 4 Oct 2023 09:37:54 +0100 Subject: [PATCH 0334/1077] asc: generate silence if FIFO empty but engine still running MacOS (un)helpfully leaves the FIFO engine running even when all the samples have been written to the hardware, and expects the FIFO status flags and IRQ to be updated continuously. There is an additional problem in that not all audio backends guarantee an all-zero output when there is no FIFO data available, in particular the Windows dsound backend which re-uses its internal circular buffer causing the last played sound to loop indefinitely. Whilst this is effectively a bug in the Windows dsound backend, work around it for now using a simple heuristic: if the FIFO remains empty for half a cycle (~23ms) then continuously fill the generated buffer with empty silence. Signed-off-by: Mark Cave-Ayland Reviewed-by: Laurent Vivier Message-ID: <20231004083806.757242-9-mark.cave-ayland@ilande.co.uk> Signed-off-by: Laurent Vivier --- hw/audio/asc.c | 19 +++++++++++++++++++ include/hw/audio/asc.h | 2 ++ 2 files changed, 21 insertions(+) diff --git a/hw/audio/asc.c b/hw/audio/asc.c index 9084708eaf..0f36b4ce9b 100644 --- a/hw/audio/asc.c +++ b/hw/audio/asc.c @@ -341,6 +341,21 @@ static void asc_out_cb(void *opaque, int free_b) } if (!generated) { + /* Workaround for audio underflow bug on Windows dsound backend */ + int64_t now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); + int silent_samples = muldiv64(now - s->fifo_empty_ns, + NANOSECONDS_PER_SECOND, ASC_FREQ); + + if (silent_samples > ASC_FIFO_CYCLE_TIME / 2) { + /* + * No new FIFO data within half a cycle time (~23ms) so fill the + * entire available buffer with silence. This prevents an issue + * with the Windows dsound backend whereby the sound appears to + * loop because the FIFO has run out of data, and the driver + * reuses the stale content in its circular audio buffer. + */ + AUD_write(s->voice, s->silentbuf, samples << s->shift); + } return; } @@ -618,6 +633,7 @@ static void asc_unrealize(DeviceState *dev) ASCState *s = ASC(dev); g_free(s->mixbuf); + g_free(s->silentbuf); AUD_remove_card(&s->card); } @@ -642,6 +658,9 @@ static void asc_realize(DeviceState *dev, Error **errp) s->samples = AUD_get_buffer_size_out(s->voice) >> s->shift; s->mixbuf = g_malloc0(s->samples << s->shift); + s->silentbuf = g_malloc0(s->samples << s->shift); + memset(s->silentbuf, 0x80, s->samples << s->shift); + /* Add easc registers if required */ if (s->type == ASC_TYPE_EASC) { memory_region_add_subregion(&s->asc, ASC_EXTREG_OFFSET, diff --git a/include/hw/audio/asc.h b/include/hw/audio/asc.h index d9412815c3..4741f92c46 100644 --- a/include/hw/audio/asc.h +++ b/include/hw/audio/asc.h @@ -68,6 +68,8 @@ struct ASCState { int samples; int shift; + uint8_t *silentbuf; + /* Time when we were last able to generate samples */ int64_t fifo_empty_ns; From 9983f6e12e11c6519c9626f4c63df53edefab5f2 Mon Sep 17 00:00:00 2001 From: Mark Cave-Ayland Date: Wed, 4 Oct 2023 09:37:55 +0100 Subject: [PATCH 0335/1077] q800: add Apple Sound Chip (ASC) audio to machine The Quadra 800 has the enhanced ASC (EASC) audio chip which supports both the legacy IRQ routing through VIA2 and also "A/UX" mode routing direct to the CPU. Co-developed-by: Laurent Vivier Signed-off-by: Mark Cave-Ayland Message-ID: <20231004083806.757242-10-mark.cave-ayland@ilande.co.uk> Signed-off-by: Laurent Vivier --- hw/m68k/q800-glue.c | 11 ++++++++++- hw/m68k/q800.c | 21 +++++++++++++++++++++ include/hw/m68k/q800-glue.h | 4 +++- include/hw/m68k/q800.h | 2 ++ 4 files changed, 36 insertions(+), 2 deletions(-) diff --git a/hw/m68k/q800-glue.c b/hw/m68k/q800-glue.c index 710a5c331e..f413b1599a 100644 --- a/hw/m68k/q800-glue.c +++ b/hw/m68k/q800-glue.c @@ -97,6 +97,11 @@ static void GLUE_set_irq(void *opaque, int irq, int level) irq = 6; break; + case GLUE_IRQ_IN_ASC: + /* Route to VIA2 instead, negative edge-triggered */ + qemu_set_irq(s->irqs[GLUE_IRQ_ASC], !level); + return; + default: g_assert_not_reached(); } @@ -123,6 +128,10 @@ static void GLUE_set_irq(void *opaque, int irq, int level) irq = 6; break; + case GLUE_IRQ_IN_ASC: + irq = 4; + break; + default: g_assert_not_reached(); } @@ -214,7 +223,7 @@ static void glue_init(Object *obj) qdev_init_gpio_in(dev, GLUE_set_irq, 8); qdev_init_gpio_in_named(dev, glue_auxmode_set_irq, "auxmode", 1); - qdev_init_gpio_out(dev, s->irqs, 1); + qdev_init_gpio_out(dev, s->irqs, 2); /* NMI release timer */ s->nmi_release = timer_new_ms(QEMU_CLOCK_VIRTUAL, glue_nmi_release, s); diff --git a/hw/m68k/q800.c b/hw/m68k/q800.c index 3209309173..249fedde7a 100644 --- a/hw/m68k/q800.c +++ b/hw/m68k/q800.c @@ -43,6 +43,7 @@ #include "hw/misc/djmemc.h" #include "hw/misc/iosb.h" #include "hw/input/adb.h" +#include "hw/audio/asc.h" #include "hw/nubus/mac-nubus-bridge.h" #include "hw/display/macfb.h" #include "hw/block/swim.h" @@ -480,6 +481,25 @@ static void q800_machine_init(MachineState *machine) scsi_bus_legacy_handle_cmdline(&esp->bus); + /* Apple Sound Chip */ + + object_initialize_child(OBJECT(machine), "asc", &m->asc, TYPE_ASC); + qdev_prop_set_uint8(DEVICE(&m->asc), "asctype", ASC_TYPE_EASC); + if (machine->audiodev) { + qdev_prop_set_string(DEVICE(&m->asc), "audiodev", machine->audiodev); + } + sysbus = SYS_BUS_DEVICE(&m->asc); + sysbus_realize_and_unref(sysbus, &error_fatal); + memory_region_add_subregion(&m->macio, ASC_BASE - IO_BASE, + sysbus_mmio_get_region(sysbus, 0)); + sysbus_connect_irq(sysbus, 0, qdev_get_gpio_in(DEVICE(&m->glue), + GLUE_IRQ_IN_ASC)); + + /* Wire ASC IRQ via GLUE for use in classic mode */ + qdev_connect_gpio_out(DEVICE(&m->glue), GLUE_IRQ_ASC, + qdev_get_gpio_in(DEVICE(&m->via2), + VIA2_IRQ_ASC_BIT)); + /* SWIM floppy controller */ object_initialize_child(OBJECT(machine), "swim", &m->swim, @@ -688,6 +708,7 @@ static void q800_machine_class_init(ObjectClass *oc, void *data) mc->max_cpus = 1; mc->block_default_type = IF_SCSI; mc->default_ram_id = "m68k_mac.ram"; + machine_add_audiodev_property(mc); compat_props_add(mc->compat_props, hw_compat_q800, hw_compat_q800_len); } diff --git a/include/hw/m68k/q800-glue.h b/include/hw/m68k/q800-glue.h index a35efc1c53..ceb916d16c 100644 --- a/include/hw/m68k/q800-glue.h +++ b/include/hw/m68k/q800-glue.h @@ -35,7 +35,7 @@ struct GLUEState { M68kCPU *cpu; uint8_t ipr; uint8_t auxmode; - qemu_irq irqs[1]; + qemu_irq irqs[2]; QEMUTimer *nmi_release; }; @@ -44,7 +44,9 @@ struct GLUEState { #define GLUE_IRQ_IN_SONIC 2 #define GLUE_IRQ_IN_ESCC 3 #define GLUE_IRQ_IN_NMI 4 +#define GLUE_IRQ_IN_ASC 5 #define GLUE_IRQ_NUBUS_9 0 +#define GLUE_IRQ_ASC 1 #endif diff --git a/include/hw/m68k/q800.h b/include/hw/m68k/q800.h index 04e4e0bce3..790cf433f3 100644 --- a/include/hw/m68k/q800.h +++ b/include/hw/m68k/q800.h @@ -38,6 +38,7 @@ #include "hw/display/macfb.h" #include "hw/misc/djmemc.h" #include "hw/misc/iosb.h" +#include "hw/audio/asc.h" /* * The main Q800 machine @@ -60,6 +61,7 @@ struct Q800MachineState { MacfbNubusState macfb; DJMEMCState djmemc; IOSBState iosb; + ASCState asc; MemoryRegion ramio; MemoryRegion macio; MemoryRegion macio_alias; From 7afc4356c39ffff7cade349808618878a1dbcf1e Mon Sep 17 00:00:00 2001 From: Mark Cave-Ayland Date: Wed, 4 Oct 2023 09:37:56 +0100 Subject: [PATCH 0336/1077] q800: add easc bool machine class property to switch between ASC and EASC MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This determines whether the Apple Sound Chip (ASC) is set to enhanced mode (default) or to original mode. The real Q800 hardware used an EASC chip however a lot of older software only works with the older ASC chip. Adding this as a machine parameter allows QEMU to be used as an developer aid for testing and migrating code from ASC to EASC. Signed-off-by: Mark Cave-Ayland Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Laurent Vivier Message-ID: <20231004083806.757242-11-mark.cave-ayland@ilande.co.uk> Signed-off-by: Laurent Vivier --- hw/m68k/q800.c | 30 +++++++++++++++++++++++++++++- include/hw/m68k/q800.h | 1 + 2 files changed, 30 insertions(+), 1 deletion(-) diff --git a/hw/m68k/q800.c b/hw/m68k/q800.c index 249fedde7a..ac3115d328 100644 --- a/hw/m68k/q800.c +++ b/hw/m68k/q800.c @@ -484,7 +484,8 @@ static void q800_machine_init(MachineState *machine) /* Apple Sound Chip */ object_initialize_child(OBJECT(machine), "asc", &m->asc, TYPE_ASC); - qdev_prop_set_uint8(DEVICE(&m->asc), "asctype", ASC_TYPE_EASC); + qdev_prop_set_uint8(DEVICE(&m->asc), "asctype", m->easc ? ASC_TYPE_EASC + : ASC_TYPE_ASC); if (machine->audiodev) { qdev_prop_set_string(DEVICE(&m->asc), "audiodev", machine->audiodev); } @@ -677,6 +678,28 @@ static void q800_machine_init(MachineState *machine) } } +static bool q800_get_easc(Object *obj, Error **errp) +{ + Q800MachineState *ms = Q800_MACHINE(obj); + + return ms->easc; +} + +static void q800_set_easc(Object *obj, bool value, Error **errp) +{ + Q800MachineState *ms = Q800_MACHINE(obj); + + ms->easc = value; +} + +static void q800_init(Object *obj) +{ + Q800MachineState *ms = Q800_MACHINE(obj); + + /* Default to EASC */ + ms->easc = true; +} + static GlobalProperty hw_compat_q800[] = { { "scsi-hd", "quirk_mode_page_vendor_specific_apple", "on" }, { "scsi-hd", "vendor", " SEAGATE" }, @@ -710,11 +733,16 @@ static void q800_machine_class_init(ObjectClass *oc, void *data) mc->default_ram_id = "m68k_mac.ram"; machine_add_audiodev_property(mc); compat_props_add(mc->compat_props, hw_compat_q800, hw_compat_q800_len); + + object_class_property_add_bool(oc, "easc", q800_get_easc, q800_set_easc); + object_class_property_set_description(oc, "easc", + "Set to off to use ASC rather than EASC"); } static const TypeInfo q800_machine_typeinfo = { .name = MACHINE_TYPE_NAME("q800"), .parent = TYPE_MACHINE, + .instance_init = q800_init, .instance_size = sizeof(Q800MachineState), .class_init = q800_machine_class_init, }; diff --git a/include/hw/m68k/q800.h b/include/hw/m68k/q800.h index 790cf433f3..fbaacd88bd 100644 --- a/include/hw/m68k/q800.h +++ b/include/hw/m68k/q800.h @@ -47,6 +47,7 @@ struct Q800MachineState { MachineState parent_obj; + bool easc; M68kCPU cpu; MemoryRegion rom; GLUEState glue; From d05cad2bf6daff56c46e7c42f56fe39bd7bcbc06 Mon Sep 17 00:00:00 2001 From: Mark Cave-Ayland Date: Wed, 4 Oct 2023 09:37:57 +0100 Subject: [PATCH 0337/1077] swim: add trace events for IWM and ISM registers Signed-off-by: Mark Cave-Ayland Reviewed-by: Laurent Vivier Message-ID: <20231004083806.757242-12-mark.cave-ayland@ilande.co.uk> Signed-off-by: Laurent Vivier --- hw/block/swim.c | 14 ++++++++++++++ hw/block/trace-events | 7 +++++++ 2 files changed, 21 insertions(+) diff --git a/hw/block/swim.c b/hw/block/swim.c index 333da08ce0..7df36ea139 100644 --- a/hw/block/swim.c +++ b/hw/block/swim.c @@ -19,6 +19,7 @@ #include "hw/block/block.h" #include "hw/block/swim.h" #include "hw/qdev-properties.h" +#include "trace.h" /* IWM registers */ @@ -125,6 +126,13 @@ #define SWIM_HEDSEL 0x20 #define SWIM_MOTON 0x80 +static const char *swim_reg_names[] = { + "WRITE_DATA", "WRITE_MARK", "WRITE_CRC", "WRITE_PARAMETER", + "WRITE_PHASE", "WRITE_SETUP", "WRITE_MODE0", "WRITE_MODE1", + "READ_DATA", "READ_MARK", "READ_ERROR", "READ_PARAMETER", + "READ_PHASE", "READ_SETUP", "READ_STATUS", "READ_HANDSHAKE" +}; + static void fd_recalibrate(FDrive *drive) { } @@ -267,6 +275,7 @@ static void iwmctrl_write(void *opaque, hwaddr reg, uint64_t value, reg >>= REG_SHIFT; swimctrl->regs[reg >> 1] = reg & 1; + trace_swim_iwmctrl_write((reg >> 1), size, (reg & 1)); if (swimctrl->regs[IWM_Q6] && swimctrl->regs[IWM_Q7]) { @@ -297,6 +306,7 @@ static void iwmctrl_write(void *opaque, hwaddr reg, uint64_t value, if (value == 0x57) { swimctrl->mode = SWIM_MODE_SWIM; swimctrl->iwm_switch = 0; + trace_swim_iwm_switch(); } break; } @@ -312,6 +322,7 @@ static uint64_t iwmctrl_read(void *opaque, hwaddr reg, unsigned size) swimctrl->regs[reg >> 1] = reg & 1; + trace_swim_iwmctrl_read((reg >> 1), size, (reg & 1)); return 0; } @@ -327,6 +338,8 @@ static void swimctrl_write(void *opaque, hwaddr reg, uint64_t value, reg >>= REG_SHIFT; + trace_swim_swimctrl_write(reg, swim_reg_names[reg], size, value); + switch (reg) { case SWIM_WRITE_PHASE: swimctrl->swim_phase = value; @@ -376,6 +389,7 @@ static uint64_t swimctrl_read(void *opaque, hwaddr reg, unsigned size) break; } + trace_swim_swimctrl_read(reg, swim_reg_names[reg], size, value); return value; } diff --git a/hw/block/trace-events b/hw/block/trace-events index 34be8b9135..c041ec45e3 100644 --- a/hw/block/trace-events +++ b/hw/block/trace-events @@ -90,3 +90,10 @@ m25p80_read_data(void *s, uint32_t pos, uint8_t v) "[%p] Read data 0x%"PRIx32"=0 m25p80_read_sfdp(void *s, uint32_t addr, uint8_t v) "[%p] Read SFDP 0x%"PRIx32"=0x%"PRIx8 m25p80_binding(void *s) "[%p] Binding to IF_MTD drive" m25p80_binding_no_bdrv(void *s) "[%p] No BDRV - binding to RAM" + +# swim.c +swim_swimctrl_read(int reg, const char *name, unsigned size, uint64_t value) "reg=%d [%s] size=%u value=0x%"PRIx64 +swim_swimctrl_write(int reg, const char *name, unsigned size, uint64_t value) "reg=%d [%s] size=%u value=0x%"PRIx64 +swim_iwmctrl_read(int reg, unsigned size, uint64_t value) "reg=%d size=%u value=0x%"PRIx64 +swim_iwmctrl_write(int reg, unsigned size, uint64_t value) "reg=%d size=%u value=0x%"PRIx64 +swim_iwm_switch(void) "switch from IWM to SWIM mode" From 57004204172b59de40bb8617a9082d882c60a2fd Mon Sep 17 00:00:00 2001 From: Mark Cave-Ayland Date: Wed, 4 Oct 2023 09:37:58 +0100 Subject: [PATCH 0338/1077] swim: split into separate IWM and ISM register blocks The swim chip provides an implementation of both Apple's IWM and ISM floppy disk controllers. Split the existing implementation into separate register banks for each controller, whilst also switching the IWM registers from 16-bit to 8-bit as implemented in real hardware. Signed-off-by: Mark Cave-Ayland Reviewed-by: Laurent Vivier Message-ID: <20231004083806.757242-13-mark.cave-ayland@ilande.co.uk> Signed-off-by: Laurent Vivier --- hw/block/swim.c | 85 ++++++++++++++++++++++++----------------- hw/block/trace-events | 4 +- include/hw/block/swim.h | 15 +++----- 3 files changed, 58 insertions(+), 46 deletions(-) diff --git a/hw/block/swim.c b/hw/block/swim.c index 7df36ea139..505718bdae 100644 --- a/hw/block/swim.c +++ b/hw/block/swim.c @@ -126,7 +126,14 @@ #define SWIM_HEDSEL 0x20 #define SWIM_MOTON 0x80 -static const char *swim_reg_names[] = { +static const char *iwm_reg_names[] = { + "PH0L", "PH0H", "PH1L", "PH1H", + "PH2L", "PH2H", "PH3L", "PH3H", + "MTROFF", "MTRON", "INTDRIVE", "EXTDRIVE", + "Q6L", "Q6H", "Q7L", "Q7H" +}; + +static const char *ism_reg_names[] = { "WRITE_DATA", "WRITE_MARK", "WRITE_CRC", "WRITE_PARAMETER", "WRITE_PHASE", "WRITE_SETUP", "WRITE_MODE0", "WRITE_MODE1", "READ_DATA", "READ_MARK", "READ_ERROR", "READ_PARAMETER", @@ -274,12 +281,11 @@ static void iwmctrl_write(void *opaque, hwaddr reg, uint64_t value, reg >>= REG_SHIFT; - swimctrl->regs[reg >> 1] = reg & 1; - trace_swim_iwmctrl_write((reg >> 1), size, (reg & 1)); + swimctrl->iwmregs[reg] = value; + trace_swim_iwmctrl_write(reg, iwm_reg_names[reg], size, value); - if (swimctrl->regs[IWM_Q6] && - swimctrl->regs[IWM_Q7]) { - if (swimctrl->regs[IWM_MTR]) { + if (swimctrl->iwmregs[IWM_Q7H]) { + if (swimctrl->iwmregs[IWM_MTRON]) { /* data register */ swimctrl->iwm_data = value; } else { @@ -307,6 +313,12 @@ static void iwmctrl_write(void *opaque, hwaddr reg, uint64_t value, swimctrl->mode = SWIM_MODE_SWIM; swimctrl->iwm_switch = 0; trace_swim_iwm_switch(); + + /* Switch to ISM registers */ + memory_region_del_subregion(&swimctrl->swim, + &swimctrl->iwm); + memory_region_add_subregion(&swimctrl->swim, 0x0, + &swimctrl->ism); } break; } @@ -317,28 +329,30 @@ static void iwmctrl_write(void *opaque, hwaddr reg, uint64_t value, static uint64_t iwmctrl_read(void *opaque, hwaddr reg, unsigned size) { SWIMCtrl *swimctrl = opaque; + uint8_t value; reg >>= REG_SHIFT; - swimctrl->regs[reg >> 1] = reg & 1; + value = swimctrl->iwmregs[reg]; + trace_swim_iwmctrl_read(reg, iwm_reg_names[reg], size, value); - trace_swim_iwmctrl_read((reg >> 1), size, (reg & 1)); - return 0; + return value; } -static void swimctrl_write(void *opaque, hwaddr reg, uint64_t value, - unsigned size) +static const MemoryRegionOps swimctrl_iwm_ops = { + .write = iwmctrl_write, + .read = iwmctrl_read, + .endianness = DEVICE_BIG_ENDIAN, +}; + +static void ismctrl_write(void *opaque, hwaddr reg, uint64_t value, + unsigned size) { SWIMCtrl *swimctrl = opaque; - if (swimctrl->mode == SWIM_MODE_IWM) { - iwmctrl_write(opaque, reg, value, size); - return; - } - reg >>= REG_SHIFT; - trace_swim_swimctrl_write(reg, swim_reg_names[reg], size, value); + trace_swim_swimctrl_write(reg, ism_reg_names[reg], size, value); switch (reg) { case SWIM_WRITE_PHASE: @@ -359,15 +373,11 @@ static void swimctrl_write(void *opaque, hwaddr reg, uint64_t value, } } -static uint64_t swimctrl_read(void *opaque, hwaddr reg, unsigned size) +static uint64_t ismctrl_read(void *opaque, hwaddr reg, unsigned size) { SWIMCtrl *swimctrl = opaque; uint32_t value = 0; - if (swimctrl->mode == SWIM_MODE_IWM) { - return iwmctrl_read(opaque, reg, size); - } - reg >>= REG_SHIFT; switch (reg) { @@ -389,14 +399,14 @@ static uint64_t swimctrl_read(void *opaque, hwaddr reg, unsigned size) break; } - trace_swim_swimctrl_read(reg, swim_reg_names[reg], size, value); + trace_swim_swimctrl_read(reg, ism_reg_names[reg], size, value); return value; } -static const MemoryRegionOps swimctrl_mem_ops = { - .write = swimctrl_write, - .read = swimctrl_read, - .endianness = DEVICE_NATIVE_ENDIAN, +static const MemoryRegionOps swimctrl_ism_ops = { + .write = ismctrl_write, + .read = ismctrl_read, + .endianness = DEVICE_BIG_ENDIAN, }; static void sysbus_swim_reset(DeviceState *d) @@ -407,13 +417,13 @@ static void sysbus_swim_reset(DeviceState *d) ctrl->mode = 0; ctrl->iwm_switch = 0; - for (i = 0; i < 8; i++) { - ctrl->regs[i] = 0; - } ctrl->iwm_data = 0; ctrl->iwm_mode = 0; + memset(ctrl->iwmregs, 0, 16); + ctrl->swim_phase = 0; ctrl->swim_mode = 0; + memset(ctrl->ismregs, 0, 16); for (i = 0; i < SWIM_MAX_FD; i++) { fd_recalibrate(&ctrl->drives[i]); } @@ -425,9 +435,12 @@ static void sysbus_swim_init(Object *obj) Swim *sbs = SWIM(obj); SWIMCtrl *swimctrl = &sbs->ctrl; - memory_region_init_io(&swimctrl->iomem, obj, &swimctrl_mem_ops, swimctrl, - "swim", 0x2000); - sysbus_init_mmio(sbd, &swimctrl->iomem); + memory_region_init(&swimctrl->swim, obj, "swim", 0x2000); + memory_region_init_io(&swimctrl->iwm, obj, &swimctrl_iwm_ops, swimctrl, + "iwm", 0x2000); + memory_region_init_io(&swimctrl->ism, obj, &swimctrl_ism_ops, swimctrl, + "ism", 0x2000); + sysbus_init_mmio(sbd, &swimctrl->swim); } static void sysbus_swim_realize(DeviceState *dev, Error **errp) @@ -437,6 +450,9 @@ static void sysbus_swim_realize(DeviceState *dev, Error **errp) qbus_init(&swimctrl->bus, sizeof(SWIMBus), TYPE_SWIM_BUS, dev, NULL); swimctrl->bus.ctrl = swimctrl; + + /* Default register set is IWM */ + memory_region_add_subregion(&swimctrl->swim, 0x0, &swimctrl->iwm); } static const VMStateDescription vmstate_fdrive = { @@ -456,10 +472,11 @@ static const VMStateDescription vmstate_swim = { VMSTATE_INT32(mode, SWIMCtrl), /* IWM mode */ VMSTATE_INT32(iwm_switch, SWIMCtrl), - VMSTATE_UINT16_ARRAY(regs, SWIMCtrl, 8), + VMSTATE_UINT8_ARRAY(iwmregs, SWIMCtrl, 16), VMSTATE_UINT8(iwm_data, SWIMCtrl), VMSTATE_UINT8(iwm_mode, SWIMCtrl), /* SWIM mode */ + VMSTATE_UINT8_ARRAY(ismregs, SWIMCtrl, 16), VMSTATE_UINT8(swim_phase, SWIMCtrl), VMSTATE_UINT8(swim_mode, SWIMCtrl), /* Drives */ diff --git a/hw/block/trace-events b/hw/block/trace-events index c041ec45e3..ea84ad6c77 100644 --- a/hw/block/trace-events +++ b/hw/block/trace-events @@ -94,6 +94,6 @@ m25p80_binding_no_bdrv(void *s) "[%p] No BDRV - binding to RAM" # swim.c swim_swimctrl_read(int reg, const char *name, unsigned size, uint64_t value) "reg=%d [%s] size=%u value=0x%"PRIx64 swim_swimctrl_write(int reg, const char *name, unsigned size, uint64_t value) "reg=%d [%s] size=%u value=0x%"PRIx64 -swim_iwmctrl_read(int reg, unsigned size, uint64_t value) "reg=%d size=%u value=0x%"PRIx64 -swim_iwmctrl_write(int reg, unsigned size, uint64_t value) "reg=%d size=%u value=0x%"PRIx64 +swim_iwmctrl_read(int reg, const char *name, unsigned size, uint64_t value) "reg=%d [%s] size=%u value=0x%"PRIx64 +swim_iwmctrl_write(int reg, const char *name, unsigned size, uint64_t value) "reg=%d [%s] size=%u value=0x%"PRIx64 swim_iwm_switch(void) "switch from IWM to SWIM mode" diff --git a/include/hw/block/swim.h b/include/hw/block/swim.h index 9b3dcb029d..1bc7635d02 100644 --- a/include/hw/block/swim.h +++ b/include/hw/block/swim.h @@ -43,23 +43,18 @@ typedef struct FDrive { } FDrive; struct SWIMCtrl { - MemoryRegion iomem; + MemoryRegion swim; + MemoryRegion iwm; + MemoryRegion ism; FDrive drives[SWIM_MAX_FD]; int mode; /* IWM mode */ int iwm_switch; - uint16_t regs[8]; -#define IWM_PH0 0 -#define IWM_PH1 1 -#define IWM_PH2 2 -#define IWM_PH3 3 -#define IWM_MTR 4 -#define IWM_DRIVE 5 -#define IWM_Q6 6 -#define IWM_Q7 7 + uint8_t iwmregs[16]; uint8_t iwm_data; uint8_t iwm_mode; /* SWIM mode */ + uint8_t ismregs[16]; uint8_t swim_phase; uint8_t swim_mode; SWIMBus bus; From 994af0b2e020a91729a39f8c4af4a522ccd3a556 Mon Sep 17 00:00:00 2001 From: Mark Cave-Ayland Date: Wed, 4 Oct 2023 09:37:59 +0100 Subject: [PATCH 0339/1077] swim: update IWM/ISM register block decoding Update the IWM/ISM register block decoding to match the description given in the "SWIM Chip Users Reference". This allows us to validate the device response to the guest OS which currently only does just enough to indicate that the floppy drive is unavailable. Signed-off-by: Mark Cave-Ayland Reviewed-by: Laurent Vivier Message-ID: <20231004083806.757242-14-mark.cave-ayland@ilande.co.uk> Signed-off-by: Laurent Vivier --- hw/block/swim.c | 210 +++++++++++++++++++++++++--------------- hw/block/trace-events | 7 +- include/hw/block/swim.h | 8 +- 3 files changed, 142 insertions(+), 83 deletions(-) diff --git a/hw/block/swim.c b/hw/block/swim.c index 505718bdae..fd65c59f8a 100644 --- a/hw/block/swim.c +++ b/hw/block/swim.c @@ -21,24 +21,28 @@ #include "hw/qdev-properties.h" #include "trace.h" + +/* IWM latch bits */ + +#define IWMLB_PHASE0 0 +#define IWMLB_PHASE1 1 +#define IWMLB_PHASE2 2 +#define IWMLB_PHASE3 3 +#define IWMLB_MOTORON 4 +#define IWMLB_DRIVESEL 5 +#define IWMLB_L6 6 +#define IWMLB_L7 7 + /* IWM registers */ -#define IWM_PH0L 0 -#define IWM_PH0H 1 -#define IWM_PH1L 2 -#define IWM_PH1H 3 -#define IWM_PH2L 4 -#define IWM_PH2H 5 -#define IWM_PH3L 6 -#define IWM_PH3H 7 -#define IWM_MTROFF 8 -#define IWM_MTRON 9 -#define IWM_INTDRIVE 10 -#define IWM_EXTDRIVE 11 -#define IWM_Q6L 12 -#define IWM_Q6H 13 -#define IWM_Q7L 14 -#define IWM_Q7H 15 +#define IWM_READALLONES 0 +#define IWM_READDATA 1 +#define IWM_READSTATUS0 2 +#define IWM_READSTATUS1 3 +#define IWM_READWHANDSHAKE0 4 +#define IWM_READWHANDSHAKE1 5 +#define IWM_WRITESETMODE 6 +#define IWM_WRITEDATA 7 /* SWIM registers */ @@ -62,8 +66,9 @@ #define REG_SHIFT 9 -#define SWIM_MODE_IWM 0 -#define SWIM_MODE_SWIM 1 +#define SWIM_MODE_STATUS_BIT 6 +#define SWIM_MODE_IWM 0 +#define SWIM_MODE_ISM 1 /* bits in phase register */ @@ -127,10 +132,8 @@ #define SWIM_MOTON 0x80 static const char *iwm_reg_names[] = { - "PH0L", "PH0H", "PH1L", "PH1H", - "PH2L", "PH2H", "PH3L", "PH3H", - "MTROFF", "MTRON", "INTDRIVE", "EXTDRIVE", - "Q6L", "Q6H", "Q7L", "Q7H" + "READALLONES", "READDATA", "READSTATUS0", "READSTATUS1", + "READWHANDSHAKE0", "READWHANDSHAKE1", "WRITESETMODE", "WRITEDATA" }; static const char *ism_reg_names[] = { @@ -274,68 +277,99 @@ static const TypeInfo swim_bus_info = { .instance_size = sizeof(SWIMBus), }; -static void iwmctrl_write(void *opaque, hwaddr reg, uint64_t value, +static void iwmctrl_write(void *opaque, hwaddr addr, uint64_t value, unsigned size) { SWIMCtrl *swimctrl = opaque; + uint8_t latch, reg, ism_bit; - reg >>= REG_SHIFT; + addr >>= REG_SHIFT; + + /* A3-A1 select a latch, A0 specifies the value */ + latch = (addr >> 1) & 7; + if (addr & 1) { + swimctrl->iwm_latches |= (1 << latch); + } else { + swimctrl->iwm_latches &= ~(1 << latch); + } + + reg = (swimctrl->iwm_latches & 0xc0) >> 5 | + (swimctrl->iwm_latches & 0x10) >> 4; swimctrl->iwmregs[reg] = value; trace_swim_iwmctrl_write(reg, iwm_reg_names[reg], size, value); - if (swimctrl->iwmregs[IWM_Q7H]) { - if (swimctrl->iwmregs[IWM_MTRON]) { - /* data register */ - swimctrl->iwm_data = value; - } else { - /* mode register */ - swimctrl->iwm_mode = value; - /* detect sequence to switch from IWM mode to SWIM mode */ - switch (swimctrl->iwm_switch) { - case 0: - if (value == 0x57) { - swimctrl->iwm_switch++; - } - break; - case 1: - if (value == 0x17) { - swimctrl->iwm_switch++; - } - break; - case 2: - if (value == 0x57) { - swimctrl->iwm_switch++; - } - break; - case 3: - if (value == 0x57) { - swimctrl->mode = SWIM_MODE_SWIM; - swimctrl->iwm_switch = 0; - trace_swim_iwm_switch(); + switch (reg) { + case IWM_WRITESETMODE: + /* detect sequence to switch from IWM mode to SWIM mode */ + ism_bit = (value & (1 << SWIM_MODE_STATUS_BIT)); - /* Switch to ISM registers */ - memory_region_del_subregion(&swimctrl->swim, - &swimctrl->iwm); - memory_region_add_subregion(&swimctrl->swim, 0x0, - &swimctrl->ism); - } - break; + switch (swimctrl->iwm_switch) { + case 0: + if (ism_bit) { /* 1 */ + swimctrl->iwm_switch++; } + break; + case 1: + if (!ism_bit) { /* 0 */ + swimctrl->iwm_switch++; + } + break; + case 2: + if (ism_bit) { /* 1 */ + swimctrl->iwm_switch++; + } + break; + case 3: + if (ism_bit) { /* 1 */ + swimctrl->iwm_switch++; + + swimctrl->mode = SWIM_MODE_ISM; + swimctrl->swim_mode |= (1 << SWIM_MODE_STATUS_BIT); + swimctrl->iwm_switch = 0; + trace_swim_switch_to_ism(); + + /* Switch to ISM registers */ + memory_region_del_subregion(&swimctrl->swim, &swimctrl->iwm); + memory_region_add_subregion(&swimctrl->swim, 0x0, + &swimctrl->ism); + } + break; } + break; + default: + break; } } -static uint64_t iwmctrl_read(void *opaque, hwaddr reg, unsigned size) +static uint64_t iwmctrl_read(void *opaque, hwaddr addr, unsigned size) { SWIMCtrl *swimctrl = opaque; - uint8_t value; + uint8_t latch, reg, value; - reg >>= REG_SHIFT; + addr >>= REG_SHIFT; + + /* A3-A1 select a latch, A0 specifies the value */ + latch = (addr >> 1) & 7; + if (addr & 1) { + swimctrl->iwm_latches |= (1 << latch); + } else { + swimctrl->iwm_latches &= ~(1 << latch); + } + + reg = (swimctrl->iwm_latches & 0xc0) >> 5 | + (swimctrl->iwm_latches & 0x10) >> 4; + + switch (reg) { + case IWM_READALLONES: + value = 0xff; + break; + default: + value = 0; + break; + } - value = swimctrl->iwmregs[reg]; trace_swim_iwmctrl_read(reg, iwm_reg_names[reg], size, value); - return value; } @@ -352,7 +386,7 @@ static void ismctrl_write(void *opaque, hwaddr reg, uint64_t value, reg >>= REG_SHIFT; - trace_swim_swimctrl_write(reg, ism_reg_names[reg], size, value); + trace_swim_ismctrl_write(reg, ism_reg_names[reg], size, value); switch (reg) { case SWIM_WRITE_PHASE: @@ -360,14 +394,31 @@ static void ismctrl_write(void *opaque, hwaddr reg, uint64_t value, break; case SWIM_WRITE_MODE0: swimctrl->swim_mode &= ~value; + /* Any access to MODE0 register resets PRAM index */ + swimctrl->pram_idx = 0; + + if (!(swimctrl->swim_mode & (1 << SWIM_MODE_STATUS_BIT))) { + /* Clearing the mode bit switches to IWM mode */ + swimctrl->mode = SWIM_MODE_IWM; + swimctrl->iwm_latches = 0; + trace_swim_switch_to_iwm(); + + /* Switch to IWM registers */ + memory_region_del_subregion(&swimctrl->swim, &swimctrl->ism); + memory_region_add_subregion(&swimctrl->swim, 0x0, + &swimctrl->iwm); + } break; case SWIM_WRITE_MODE1: swimctrl->swim_mode |= value; break; + case SWIM_WRITE_PARAMETER: + swimctrl->pram[swimctrl->pram_idx++] = value; + swimctrl->pram_idx &= 0xf; + break; case SWIM_WRITE_DATA: case SWIM_WRITE_MARK: case SWIM_WRITE_CRC: - case SWIM_WRITE_PARAMETER: case SWIM_WRITE_SETUP: break; } @@ -390,16 +441,24 @@ static uint64_t ismctrl_read(void *opaque, hwaddr reg, unsigned size) value = SWIM_SENSE; } break; + case SWIM_READ_PARAMETER: + value = swimctrl->pram[swimctrl->pram_idx++]; + swimctrl->pram_idx &= 0xf; + break; + case SWIM_READ_STATUS: + value = swimctrl->swim_status & ~(1 << SWIM_MODE_STATUS_BIT); + if (swimctrl->swim_mode == SWIM_MODE_ISM) { + value |= (1 << SWIM_MODE_STATUS_BIT); + } + break; case SWIM_READ_DATA: case SWIM_READ_MARK: case SWIM_READ_ERROR: - case SWIM_READ_PARAMETER: case SWIM_READ_SETUP: - case SWIM_READ_STATUS: break; } - trace_swim_swimctrl_read(reg, ism_reg_names[reg], size, value); + trace_swim_ismctrl_read(reg, ism_reg_names[reg], size, value); return value; } @@ -417,13 +476,11 @@ static void sysbus_swim_reset(DeviceState *d) ctrl->mode = 0; ctrl->iwm_switch = 0; - ctrl->iwm_data = 0; - ctrl->iwm_mode = 0; - memset(ctrl->iwmregs, 0, 16); + memset(ctrl->iwmregs, 0, sizeof(ctrl->iwmregs)); ctrl->swim_phase = 0; ctrl->swim_mode = 0; - memset(ctrl->ismregs, 0, 16); + memset(ctrl->ismregs, 0, sizeof(ctrl->ismregs)); for (i = 0; i < SWIM_MAX_FD; i++) { fd_recalibrate(&ctrl->drives[i]); } @@ -472,9 +529,8 @@ static const VMStateDescription vmstate_swim = { VMSTATE_INT32(mode, SWIMCtrl), /* IWM mode */ VMSTATE_INT32(iwm_switch, SWIMCtrl), - VMSTATE_UINT8_ARRAY(iwmregs, SWIMCtrl, 16), - VMSTATE_UINT8(iwm_data, SWIMCtrl), - VMSTATE_UINT8(iwm_mode, SWIMCtrl), + VMSTATE_UINT8(iwm_latches, SWIMCtrl), + VMSTATE_UINT8_ARRAY(iwmregs, SWIMCtrl, 8), /* SWIM mode */ VMSTATE_UINT8_ARRAY(ismregs, SWIMCtrl, 16), VMSTATE_UINT8(swim_phase, SWIMCtrl), diff --git a/hw/block/trace-events b/hw/block/trace-events index ea84ad6c77..bab21d3a1c 100644 --- a/hw/block/trace-events +++ b/hw/block/trace-events @@ -92,8 +92,9 @@ m25p80_binding(void *s) "[%p] Binding to IF_MTD drive" m25p80_binding_no_bdrv(void *s) "[%p] No BDRV - binding to RAM" # swim.c -swim_swimctrl_read(int reg, const char *name, unsigned size, uint64_t value) "reg=%d [%s] size=%u value=0x%"PRIx64 -swim_swimctrl_write(int reg, const char *name, unsigned size, uint64_t value) "reg=%d [%s] size=%u value=0x%"PRIx64 +swim_ismctrl_read(int reg, const char *name, unsigned size, uint64_t value) "reg=%d [%s] size=%u value=0x%"PRIx64 +swim_ismctrl_write(int reg, const char *name, unsigned size, uint64_t value) "reg=%d [%s] size=%u value=0x%"PRIx64 swim_iwmctrl_read(int reg, const char *name, unsigned size, uint64_t value) "reg=%d [%s] size=%u value=0x%"PRIx64 swim_iwmctrl_write(int reg, const char *name, unsigned size, uint64_t value) "reg=%d [%s] size=%u value=0x%"PRIx64 -swim_iwm_switch(void) "switch from IWM to SWIM mode" +swim_switch_to_ism(void) "switch from IWM to ISM mode" +swim_switch_to_iwm(void) "switch from ISM to IWM mode" diff --git a/include/hw/block/swim.h b/include/hw/block/swim.h index 1bc7635d02..5f567e8d59 100644 --- a/include/hw/block/swim.h +++ b/include/hw/block/swim.h @@ -50,13 +50,15 @@ struct SWIMCtrl { int mode; /* IWM mode */ int iwm_switch; - uint8_t iwmregs[16]; - uint8_t iwm_data; - uint8_t iwm_mode; + uint8_t iwm_latches; + uint8_t iwmregs[8]; /* SWIM mode */ uint8_t ismregs[16]; uint8_t swim_phase; uint8_t swim_mode; + uint8_t swim_status; + uint8_t pram[16]; + uint8_t pram_idx; SWIMBus bus; }; From 366d27796ca1d09d6b6a6ad69a89cb7644d92930 Mon Sep 17 00:00:00 2001 From: Mark Cave-Ayland Date: Wed, 4 Oct 2023 09:38:00 +0100 Subject: [PATCH 0340/1077] mac_via: work around underflow in TimeDBRA timing loop in SETUPTIMEK The MacOS toolbox ROM calculates the number of branches that can be executed per millisecond as part of its timer calibration. Since modern hosts are considerably quicker than original hardware, the negative counter reaches zero before the calibration completes leading to division by zero later in CALCULATESLOD. Instead of trying to fudge the timing loop (which won't work for TimeDBRA/TimeSCCDB anyhow), use the pattern of access to the VIA1 registers to detect when SETUPTIMEK has finished executing and write some well-known good timer values to TimeDBRA and TimeSCCDB taken from real hardware with a suitable scaling factor. Signed-off-by: Mark Cave-Ayland Reviewed-by: Laurent Vivier Message-ID: <20231004083806.757242-15-mark.cave-ayland@ilande.co.uk> Signed-off-by: Laurent Vivier --- hw/misc/mac_via.c | 115 ++++++++++++++++++++++++++++++++++++++ hw/misc/trace-events | 1 + include/hw/misc/mac_via.h | 3 + 3 files changed, 119 insertions(+) diff --git a/hw/misc/mac_via.c b/hw/misc/mac_via.c index e87a1b82d8..f2ccb12d64 100644 --- a/hw/misc/mac_via.c +++ b/hw/misc/mac_via.c @@ -16,6 +16,7 @@ */ #include "qemu/osdep.h" +#include "exec/address-spaces.h" #include "migration/vmstate.h" #include "hw/sysbus.h" #include "hw/irq.h" @@ -871,6 +872,112 @@ static void via1_auxmode_update(MOS6522Q800VIA1State *v1s) } } +/* + * Addresses and real values for TimeDBRA/TimeSCCB to allow timer calibration + * to succeed (NOTE: both values have been multiplied by 3 to cope with the + * speed of QEMU execution on a modern host + */ +#define MACOS_TIMEDBRA 0xd00 +#define MACOS_TIMESCCB 0xd02 + +#define MACOS_TIMEDBRA_VALUE (0x2a00 * 3) +#define MACOS_TIMESCCB_VALUE (0x079d * 3) + +static bool via1_is_toolbox_timer_calibrated(void) +{ + /* + * Indicate whether the MacOS toolbox has been calibrated by checking + * for the value of our magic constants + */ + uint16_t timedbra = lduw_be_phys(&address_space_memory, MACOS_TIMEDBRA); + uint16_t timesccdb = lduw_be_phys(&address_space_memory, MACOS_TIMESCCB); + + return (timedbra == MACOS_TIMEDBRA_VALUE && + timesccdb == MACOS_TIMESCCB_VALUE); +} + +static void via1_timer_calibration_hack(MOS6522Q800VIA1State *v1s, int addr, + uint64_t val, int size) +{ + /* + * Work around timer calibration to ensure we that we have non-zero and + * known good values for TIMEDRBA and TIMESCCDB. + * + * This works by attempting to detect the reset and calibration sequence + * of writes to VIA1 + */ + int old_timer_hack_state = v1s->timer_hack_state; + + switch (v1s->timer_hack_state) { + case 0: + if (addr == VIA_REG_PCR && val == 0x22) { + /* VIA_REG_PCR: configure VIA1 edge triggering */ + v1s->timer_hack_state = 1; + } + break; + case 1: + if (addr == VIA_REG_T2CL && val == 0xc) { + /* VIA_REG_T2CL: low byte of 1ms counter */ + if (!via1_is_toolbox_timer_calibrated()) { + v1s->timer_hack_state = 2; + } else { + v1s->timer_hack_state = 0; + } + } + break; + case 2: + if (addr == VIA_REG_T2CH && val == 0x3) { + /* + * VIA_REG_T2CH: high byte of 1ms counter (very likely at the + * start of SETUPTIMEK) + */ + if (!via1_is_toolbox_timer_calibrated()) { + v1s->timer_hack_state = 3; + } else { + v1s->timer_hack_state = 0; + } + } + break; + case 3: + if (addr == VIA_REG_IER && val == 0x20) { + /* + * VIA_REG_IER: update at end of SETUPTIMEK + * + * Timer calibration has finished: unfortunately the values in + * TIMEDBRA (0xd00) and TIMESCCDB (0xd02) are so far out they + * cause divide by zero errors. + * + * Update them with values obtained from a real Q800 but with + * a x3 scaling factor which seems to work well + */ + stw_be_phys(&address_space_memory, MACOS_TIMEDBRA, + MACOS_TIMEDBRA_VALUE); + stw_be_phys(&address_space_memory, MACOS_TIMESCCB, + MACOS_TIMESCCB_VALUE); + + v1s->timer_hack_state = 4; + } + break; + case 4: + /* + * This is the normal post-calibration timer state: we should + * generally remain here unless we detect the A/UX calibration + * loop, or a write to VIA_REG_PCR suggesting a reset + */ + if (addr == VIA_REG_PCR && val == 0x22) { + /* Looks like there has been a reset? */ + v1s->timer_hack_state = 1; + } + break; + default: + g_assert_not_reached(); + } + + if (old_timer_hack_state != v1s->timer_hack_state) { + trace_via1_timer_hack_state(v1s->timer_hack_state); + } +} + static uint64_t mos6522_q800_via1_read(void *opaque, hwaddr addr, unsigned size) { MOS6522Q800VIA1State *s = MOS6522_Q800_VIA1(opaque); @@ -896,6 +1003,9 @@ static void mos6522_q800_via1_write(void *opaque, hwaddr addr, uint64_t val, MOS6522State *ms = MOS6522(v1s); addr = (addr >> 9) & 0xf; + + via1_timer_calibration_hack(v1s, addr, val, size); + mos6522_write(ms, addr, val, size); switch (addr) { @@ -1008,6 +1118,9 @@ static void mos6522_q800_via1_reset_hold(Object *obj) adb_set_autopoll_enabled(adb_bus, true); v1s->cmd = REG_EMPTY; v1s->alt = REG_EMPTY; + + /* Timer calibration hack */ + v1s->timer_hack_state = 0; } static void mos6522_q800_via1_realize(DeviceState *dev, Error **errp) @@ -1100,6 +1213,8 @@ static const VMStateDescription vmstate_q800_via1 = { VMSTATE_INT64(next_second, MOS6522Q800VIA1State), VMSTATE_TIMER_PTR(sixty_hz_timer, MOS6522Q800VIA1State), VMSTATE_INT64(next_sixty_hz, MOS6522Q800VIA1State), + /* Timer hack */ + VMSTATE_INT32(timer_hack_state, MOS6522Q800VIA1State), VMSTATE_END_OF_LIST() } }; diff --git a/hw/misc/trace-events b/hw/misc/trace-events index 29bc531d4d..5a998f5e4e 100644 --- a/hw/misc/trace-events +++ b/hw/misc/trace-events @@ -272,6 +272,7 @@ via1_adb_send(const char *state, uint8_t data, const char *vadbint) "state %s da via1_adb_receive(const char *state, uint8_t data, const char *vadbint, int status, int index, int size) "state %s data=0x%02x vADBInt=%s status=0x%x index=%d size=%d" via1_adb_poll(uint8_t data, const char *vadbint, int status, int index, int size) "data=0x%02x vADBInt=%s status=0x%x index=%d size=%d" via1_auxmode(int mode) "setting auxmode to %d" +via1_timer_hack_state(int state) "setting timer_hack_state to %d" # grlib_ahb_apb_pnp.c grlib_ahb_pnp_read(uint64_t addr, unsigned size, uint32_t value) "AHB PnP read addr:0x%03"PRIx64" size:%u data:0x%08x" diff --git a/include/hw/misc/mac_via.h b/include/hw/misc/mac_via.h index 422da43bf9..63cdcf7c69 100644 --- a/include/hw/misc/mac_via.h +++ b/include/hw/misc/mac_via.h @@ -74,6 +74,9 @@ struct MOS6522Q800VIA1State { int64_t next_second; QEMUTimer *sixty_hz_timer; int64_t next_sixty_hz; + + /* SETUPTIMEK hack */ + int timer_hack_state; }; From 2006904938fbb85ef32eb79ab96cdcc8cbc6de1c Mon Sep 17 00:00:00 2001 From: Mark Cave-Ayland Date: Wed, 4 Oct 2023 09:38:01 +0100 Subject: [PATCH 0341/1077] mac_via: workaround NetBSD ADB bus enumeration issue NetBSD assumes it can send its first ADB command after sending the ADB_BUSRESET command in ADB_STATE_NEW without changing the state back to ADB_STATE_IDLE first as detailed in the ADB protocol. Add a workaround to detect this condition at the start of ADB enumeration and send the next command written to SR after a ADB_BUSRESET onto the bus regardless, even if we don't detect a state transition to ADB_STATE_NEW. Signed-off-by: Mark Cave-Ayland Reviewed-by: Laurent Vivier Message-ID: <20231004083806.757242-16-mark.cave-ayland@ilande.co.uk> Signed-off-by: Laurent Vivier --- hw/misc/mac_via.c | 34 ++++++++++++++++++++++++++++++++++ hw/misc/trace-events | 1 + 2 files changed, 35 insertions(+) diff --git a/hw/misc/mac_via.c b/hw/misc/mac_via.c index f2ccb12d64..9f9c2815d0 100644 --- a/hw/misc/mac_via.c +++ b/hw/misc/mac_via.c @@ -1001,6 +1001,8 @@ static void mos6522_q800_via1_write(void *opaque, hwaddr addr, uint64_t val, { MOS6522Q800VIA1State *v1s = MOS6522_Q800_VIA1(opaque); MOS6522State *ms = MOS6522(v1s); + int oldstate, state; + int oldsr = ms->sr; addr = (addr >> 9) & 0xf; @@ -1016,6 +1018,38 @@ static void mos6522_q800_via1_write(void *opaque, hwaddr addr, uint64_t val, v1s->last_b = ms->b; break; + + case VIA_REG_SR: + { + /* + * NetBSD assumes it can send its first ADB command after sending + * the ADB_BUSRESET command in ADB_STATE_NEW without changing the + * state back to ADB_STATE_IDLE first as detailed in the ADB + * protocol. + * + * Add a workaround to detect this condition at the start of ADB + * enumeration and send the next command written to SR after a + * ADB_BUSRESET onto the bus regardless, even if we don't detect a + * state transition to ADB_STATE_NEW. + * + * Note that in my tests the NetBSD state machine takes one ADB + * operation to recover which means the probe for an ADB device at + * address 1 always fails. However since the first device is at + * address 2 then this will work fine, without having to come up + * with a more complicated and invasive solution. + */ + oldstate = (v1s->last_b & VIA1B_vADB_StateMask) >> + VIA1B_vADB_StateShift; + state = (ms->b & VIA1B_vADB_StateMask) >> VIA1B_vADB_StateShift; + + if (oldstate == ADB_STATE_NEW && state == ADB_STATE_NEW && + (ms->acr & VIA1ACR_vShiftOut) && + oldsr == 0 /* ADB_BUSRESET */) { + trace_via1_adb_netbsd_enum_hack(); + adb_via_send(v1s, state, ms->sr); + } + } + break; } } diff --git a/hw/misc/trace-events b/hw/misc/trace-events index 5a998f5e4e..24ba7cc4d0 100644 --- a/hw/misc/trace-events +++ b/hw/misc/trace-events @@ -271,6 +271,7 @@ via1_rtc_cmd_pram_sect_write(int sector, int offset, int addr, int value) "secto via1_adb_send(const char *state, uint8_t data, const char *vadbint) "state %s data=0x%02x vADBInt=%s" via1_adb_receive(const char *state, uint8_t data, const char *vadbint, int status, int index, int size) "state %s data=0x%02x vADBInt=%s status=0x%x index=%d size=%d" via1_adb_poll(uint8_t data, const char *vadbint, int status, int index, int size) "data=0x%02x vADBInt=%s status=0x%x index=%d size=%d" +via1_adb_netbsd_enum_hack(void) "using NetBSD enum hack" via1_auxmode(int mode) "setting auxmode to %d" via1_timer_hack_state(int state) "setting timer_hack_state to %d" From 7ebfb91d8f07447dc6cd30fba0119dc07c9cd3ba Mon Sep 17 00:00:00 2001 From: Mark Cave-Ayland Date: Wed, 4 Oct 2023 09:38:02 +0100 Subject: [PATCH 0342/1077] mac_via: implement ADB_STATE_IDLE state if shift register in input mode NetBSD switches directly to IDLE state without switching the shift register to input mode. Duplicate the existing ADB_STATE_IDLE logic in input mode from when the shift register is in output mode which allows the ADB autopoll handler to handle the response. Signed-off-by: Mark Cave-Ayland Reviewed-by: Laurent Vivier Message-ID: <20231004083806.757242-17-mark.cave-ayland@ilande.co.uk> Signed-off-by: Laurent Vivier --- hw/misc/mac_via.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/hw/misc/mac_via.c b/hw/misc/mac_via.c index 9f9c2815d0..3c41d6263d 100644 --- a/hw/misc/mac_via.c +++ b/hw/misc/mac_via.c @@ -702,6 +702,12 @@ static void adb_via_send(MOS6522Q800VIA1State *v1s, int state, uint8_t data) break; case ADB_STATE_IDLE: + ms->b |= VIA1B_vADBInt; + adb_autopoll_unblock(adb_bus); + + trace_via1_adb_send("IDLE", data, + (ms->b & VIA1B_vADBInt) ? "+" : "-"); + return; } From c698b0c8edd63f8631efd935ac75c28418ae4c7d Mon Sep 17 00:00:00 2001 From: Mark Cave-Ayland Date: Wed, 4 Oct 2023 09:38:03 +0100 Subject: [PATCH 0343/1077] mac_via: always clear ADB interrupt when switching to A/UX mode When the NetBSD kernel initialises it can leave the ADB interrupt asserted depending upon where in the ADB poll cycle the MacOS ADB interrupt handler is when the NetBSD kernel disables interrupts. The NetBSD ADB driver uses the ADB interrupt state to determine if the ADB is busy and refuses to send ADB commands unless it is clear. To ensure that this doesn't happen, always clear the ADB interrupt when switching to A/UX mode to ensure that the bus enumeration always occurs. Signed-off-by: Mark Cave-Ayland Reviewed-by: Laurent Vivier Message-ID: <20231004083806.757242-18-mark.cave-ayland@ilande.co.uk> Signed-off-by: Laurent Vivier --- hw/misc/mac_via.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/hw/misc/mac_via.c b/hw/misc/mac_via.c index 3c41d6263d..500ece5872 100644 --- a/hw/misc/mac_via.c +++ b/hw/misc/mac_via.c @@ -875,6 +875,15 @@ static void via1_auxmode_update(MOS6522Q800VIA1State *v1s) if (irq != oldirq) { trace_via1_auxmode(irq); qemu_set_irq(v1s->auxmode_irq, irq); + + /* + * Clear the ADB interrupt. MacOS can leave VIA1B_vADBInt asserted + * (low) if a poll sequence doesn't complete before NetBSD disables + * interrupts upon boot. Fortunately NetBSD switches to the so-called + * "A/UX" interrupt mode after it initialises, so we can use this as + * a convenient place to clear the ADB interrupt for now. + */ + s->b |= VIA1B_vADBInt; } } From 7685fc2a18cad56ec67f54ff64f06d840dcb0b29 Mon Sep 17 00:00:00 2001 From: Mark Cave-Ayland Date: Wed, 4 Oct 2023 09:38:04 +0100 Subject: [PATCH 0344/1077] q800: add ESCC alias at 0xc000 Tests on real Q800 hardware show that the ESCC is addressable at multiple locations within the ESCC memory region - at least 0xc000, 0xc020 (as expected by the MacOS toolbox ROM) and 0xc040. All released NetBSD kernels before 10 use the 0xc000 address which causes a fatal error when running the MacOS booter. Add a single memory region alias at 0xc000 to enable NetBSD kernels to start booting under QEMU. Signed-off-by: Mark Cave-Ayland Reviewed-by: Laurent Vivier Message-ID: <20231004083806.757242-19-mark.cave-ayland@ilande.co.uk> Signed-off-by: Laurent Vivier --- hw/m68k/q800.c | 6 ++++++ include/hw/m68k/q800.h | 1 + 2 files changed, 7 insertions(+) diff --git a/hw/m68k/q800.c b/hw/m68k/q800.c index ac3115d328..27a0b3c08a 100644 --- a/hw/m68k/q800.c +++ b/hw/m68k/q800.c @@ -451,6 +451,12 @@ static void q800_machine_init(MachineState *machine) memory_region_add_subregion(&m->macio, SCC_BASE - IO_BASE, sysbus_mmio_get_region(sysbus, 0)); + /* Create alias for NetBSD */ + memory_region_init_alias(&m->escc_alias, OBJECT(machine), "escc-alias", + sysbus_mmio_get_region(sysbus, 0), 0, 0x8); + memory_region_add_subregion(&m->macio, SCC_BASE - IO_BASE - 0x20, + &m->escc_alias); + /* SCSI */ object_initialize_child(OBJECT(machine), "esp", &m->esp, diff --git a/include/hw/m68k/q800.h b/include/hw/m68k/q800.h index fbaacd88bd..348eaf4703 100644 --- a/include/hw/m68k/q800.h +++ b/include/hw/m68k/q800.h @@ -67,6 +67,7 @@ struct Q800MachineState { MemoryRegion macio; MemoryRegion macio_alias; MemoryRegion machine_id; + MemoryRegion escc_alias; }; #define TYPE_Q800_MACHINE MACHINE_TYPE_NAME("q800") From 9d35c6ade54c05754a1cac99df5c9a8ce6252bbe Mon Sep 17 00:00:00 2001 From: Mark Cave-Ayland Date: Wed, 4 Oct 2023 09:38:05 +0100 Subject: [PATCH 0345/1077] q800: add alias for MacOS toolbox ROM at 0x40000000 According to the Apple Quadra 800 Developer Note document, the Quadra 800 ROM consists of 2 ROM code sections based at offsets 0x0 and 0x800000. A/UX attempts to access the toolbox ROM at the lower offset during startup, so provide a memory alias to allow the access to succeed. Signed-off-by: Mark Cave-Ayland Reviewed-by: Laurent Vivier Message-ID: <20231004083806.757242-20-mark.cave-ayland@ilande.co.uk> Signed-off-by: Laurent Vivier --- hw/m68k/q800.c | 5 +++++ include/hw/m68k/q800.h | 1 + 2 files changed, 6 insertions(+) diff --git a/hw/m68k/q800.c b/hw/m68k/q800.c index 27a0b3c08a..1d7cd5ff1c 100644 --- a/hw/m68k/q800.c +++ b/hw/m68k/q800.c @@ -660,6 +660,11 @@ static void q800_machine_init(MachineState *machine) filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, bios_name); memory_region_add_subregion(get_system_memory(), MACROM_ADDR, &m->rom); + memory_region_init_alias(&m->rom_alias, NULL, "m68k_mac.rom-alias", + &m->rom, 0, MACROM_SIZE); + memory_region_add_subregion(get_system_memory(), 0x40000000, + &m->rom_alias); + /* Load MacROM binary */ if (filename) { bios_size = load_image_targphys(filename, MACROM_ADDR, MACROM_SIZE); diff --git a/include/hw/m68k/q800.h b/include/hw/m68k/q800.h index 348eaf4703..a9661f65f6 100644 --- a/include/hw/m68k/q800.h +++ b/include/hw/m68k/q800.h @@ -50,6 +50,7 @@ struct Q800MachineState { bool easc; M68kCPU cpu; MemoryRegion rom; + MemoryRegion rom_alias; GLUEState glue; MOS6522Q800VIA1State via1; MOS6522Q800VIA2State via2; From b4d3a83b89fba814613f7ead6b6ea92e0b2c3cd8 Mon Sep 17 00:00:00 2001 From: Mark Cave-Ayland Date: Wed, 4 Oct 2023 09:38:06 +0100 Subject: [PATCH 0346/1077] mac_via: extend timer calibration hack to work with A/UX The A/UX timer calibration loop runs continuously until 2 consecutive iterations differ by at least 0x492 timer ticks. Modern hosts execute the timer calibration loop so fast that this situation never occurs causing a hang on boot. Use a similar method to Shoebill which is to randomly add 0x500 to the T2 counter value during calibration to enable it to eventually succeed. Signed-off-by: Mark Cave-Ayland Reviewed-by: Laurent Vivier Message-ID: <20231004083806.757242-21-mark.cave-ayland@ilande.co.uk> Signed-off-by: Laurent Vivier --- hw/misc/mac_via.c | 56 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 56 insertions(+) diff --git a/hw/misc/mac_via.c b/hw/misc/mac_via.c index 500ece5872..b6206ef73c 100644 --- a/hw/misc/mac_via.c +++ b/hw/misc/mac_via.c @@ -983,6 +983,44 @@ static void via1_timer_calibration_hack(MOS6522Q800VIA1State *v1s, int addr, /* Looks like there has been a reset? */ v1s->timer_hack_state = 1; } + + if (addr == VIA_REG_T2CL && val == 0xf0) { + /* VIA_REG_T2CL: low byte of counter (A/UX) */ + v1s->timer_hack_state = 5; + } + break; + case 5: + if (addr == VIA_REG_T2CH && val == 0x3c) { + /* + * VIA_REG_T2CH: high byte of counter (A/UX). We are now extremely + * likely to be in the A/UX timer calibration routine, so move to + * the next state where we enable the calibration hack. + */ + v1s->timer_hack_state = 6; + } else if ((addr == VIA_REG_IER && val == 0x20) || + addr == VIA_REG_T2CH) { + /* We're doing something else with the timer, not calibration */ + v1s->timer_hack_state = 0; + } + break; + case 6: + if ((addr == VIA_REG_IER && val == 0x20) || addr == VIA_REG_T2CH) { + /* End of A/UX timer calibration routine, or another write */ + v1s->timer_hack_state = 7; + } else { + v1s->timer_hack_state = 0; + } + break; + case 7: + /* + * This is the normal post-calibration timer state once both the + * MacOS toolbox and A/UX have been calibrated, until we see a write + * to VIA_REG_PCR to suggest a reset + */ + if (addr == VIA_REG_PCR && val == 0x22) { + /* Looks like there has been a reset? */ + v1s->timer_hack_state = 1; + } break; default: g_assert_not_reached(); @@ -998,6 +1036,7 @@ static uint64_t mos6522_q800_via1_read(void *opaque, hwaddr addr, unsigned size) MOS6522Q800VIA1State *s = MOS6522_Q800_VIA1(opaque); MOS6522State *ms = MOS6522(s); uint64_t ret; + int64_t now; addr = (addr >> 9) & 0xf; ret = mos6522_read(ms, addr, size); @@ -1007,6 +1046,23 @@ static uint64_t mos6522_q800_via1_read(void *opaque, hwaddr addr, unsigned size) /* Quadra 800 Id */ ret = (ret & ~VIA1A_CPUID_MASK) | VIA1A_CPUID_Q800; break; + case VIA_REG_T2CH: + if (s->timer_hack_state == 6) { + /* + * The A/UX timer calibration loop runs continuously until 2 + * consecutive iterations differ by at least 0x492 timer ticks. + * Modern hosts execute the timer calibration loop so fast that + * this situation never occurs causing a hang on boot. Use a + * similar method to Shoebill which is to randomly add 0x500 to + * the T2 counter value during calibration to enable it to + * eventually succeed. + */ + now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); + if (now & 1) { + ret += 0x5; + } + } + break; } return ret; } From a97bcfea7e1e275d17bff06b7d2544d7ecbeb489 Mon Sep 17 00:00:00 2001 From: Jonathan Cameron Date: Mon, 25 Sep 2023 16:22:58 +0100 Subject: [PATCH 0347/1077] hw/cxl: Fix local variable shadowing of cap_hdrs Rename the version not burried in the macro to cap_h. Signed-off-by: Jonathan Cameron Message-ID: <20230925152258.5444-1-Jonathan.Cameron@huawei.com> Reviewed-by: Michael S. Tsirkin Reviewed-by: Fan Ni Signed-off-by: Markus Armbruster --- hw/cxl/cxl-device-utils.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/hw/cxl/cxl-device-utils.c b/hw/cxl/cxl-device-utils.c index 517f06d869..bd68328032 100644 --- a/hw/cxl/cxl-device-utils.c +++ b/hw/cxl/cxl-device-utils.c @@ -283,13 +283,13 @@ static void memdev_reg_init_common(CXLDeviceState *cxl_dstate) { } void cxl_device_register_init_common(CXLDeviceState *cxl_dstate) { - uint64_t *cap_hdrs = cxl_dstate->caps_reg_state64; + uint64_t *cap_h = cxl_dstate->caps_reg_state64; const int cap_count = 3; /* CXL Device Capabilities Array Register */ - ARRAY_FIELD_DP64(cap_hdrs, CXL_DEV_CAP_ARRAY, CAP_ID, 0); - ARRAY_FIELD_DP64(cap_hdrs, CXL_DEV_CAP_ARRAY, CAP_VERSION, 1); - ARRAY_FIELD_DP64(cap_hdrs, CXL_DEV_CAP_ARRAY, CAP_COUNT, cap_count); + ARRAY_FIELD_DP64(cap_h, CXL_DEV_CAP_ARRAY, CAP_ID, 0); + ARRAY_FIELD_DP64(cap_h, CXL_DEV_CAP_ARRAY, CAP_VERSION, 1); + ARRAY_FIELD_DP64(cap_h, CXL_DEV_CAP_ARRAY, CAP_COUNT, cap_count); cxl_device_cap_init(cxl_dstate, DEVICE_STATUS, 1, 2); device_reg_init_common(cxl_dstate); From 78bcc3cc7b16d9ca118e1f860751930cbb64e81c Mon Sep 17 00:00:00 2001 From: Song Gao Date: Tue, 26 Sep 2023 15:12:53 +0800 Subject: [PATCH 0348/1077] target/loongarch: Clean up local variable shadowing Fix: [1839/2601] Compiling C object libqemu-loongarch64-softmmu.fa.p/hw_loongarch_virt.c.o ../hw/loongarch/virt.c: In function 'loongarch_irq_init': ../hw/loongarch/virt.c:665:14: warning: declaration of 'i' shadows a previous local [-Wshadow=compatible-local] for (int i = 0; i < num; i++) { ^ ../hw/loongarch/virt.c:582:19: note: shadowed declaration is here int cpu, pin, i, start, num; Signed-off-by: Song Gao Message-ID: <20230926071253.3601021-1-gaosong@loongson.cn> Reviewed-by: Markus Armbruster Signed-off-by: Markus Armbruster --- hw/loongarch/virt.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/loongarch/virt.c b/hw/loongarch/virt.c index 2629128aed..b0a004f860 100644 --- a/hw/loongarch/virt.c +++ b/hw/loongarch/virt.c @@ -662,7 +662,7 @@ static void loongarch_irq_init(LoongArchMachineState *lams) sysbus_mmio_get_region(d, 2)); /* Connect pch_pic irqs to extioi */ - for (int i = 0; i < num; i++) { + for (i = 0; i < num; i++) { qdev_connect_gpio_out(DEVICE(d), i, qdev_get_gpio_in(extioi, i)); } From 668a63140a42cd61c79a956a6222ce25cc893f69 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Le=20Goater?= Date: Fri, 29 Sep 2023 10:31:43 +0200 Subject: [PATCH 0349/1077] target/ppc: Rename variables to avoid local variable shadowing in VUPKPX MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit and fix such warnings : ../target/ppc/int_helper.c: In function ‘helper_vupklpx’: ../target/ppc/int_helper.c:2025:21: warning: declaration of ‘r’ shadows a parameter [-Wshadow=local] 2025 | uint8_t r = (e >> 10) & 0x1f; \ | ^ ../target/ppc/int_helper.c:2033:1: note: in expansion of macro ‘VUPKPX’ 2033 | VUPKPX(lpx, UPKLO) | ^~~~~~ ../target/ppc/int_helper.c:2017:41: note: shadowed declaration is here 2017 | void helper_vupk##suffix(ppc_avr_t *r, ppc_avr_t *b) \ | ~~~~~~~~~~~^ ../target/ppc/int_helper.c:2033:1: note: in expansion of macro ‘VUPKPX’ 2033 | VUPKPX(lpx, UPKLO) | ^~~~~~ Signed-off-by: Cédric Le Goater Message-ID: <20230929083143.234553-1-clg@kaod.org> Reviewed-by: Michael Tokarev Signed-off-by: Markus Armbruster --- target/ppc/int_helper.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/target/ppc/int_helper.c b/target/ppc/int_helper.c index 6fd00684a5..0a5c3e78a4 100644 --- a/target/ppc/int_helper.c +++ b/target/ppc/int_helper.c @@ -2020,13 +2020,13 @@ void helper_vsum4ubs(CPUPPCState *env, ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) ppc_avr_t result; \ \ for (i = 0; i < ARRAY_SIZE(r->u32); i++) { \ - uint16_t e = b->u16[hi ? i : i + 4]; \ - uint8_t a = (e >> 15) ? 0xff : 0; \ - uint8_t r = (e >> 10) & 0x1f; \ - uint8_t g = (e >> 5) & 0x1f; \ - uint8_t b = e & 0x1f; \ + uint16_t _e = b->u16[hi ? i : i + 4]; \ + uint8_t _a = (_e >> 15) ? 0xff : 0; \ + uint8_t _r = (_e >> 10) & 0x1f; \ + uint8_t _g = (_e >> 5) & 0x1f; \ + uint8_t _b = _e & 0x1f; \ \ - result.u32[i] = (a << 24) | (r << 16) | (g << 8) | b; \ + result.u32[i] = (_a << 24) | (_r << 16) | (_g << 8) | _b; \ } \ *r = result; \ } From 363636787d49a46840d415c2dbc925d287ed0206 Mon Sep 17 00:00:00 2001 From: Ani Sinha Date: Tue, 3 Oct 2023 15:58:02 +0530 Subject: [PATCH 0350/1077] hw/i386: changes towards enabling -Wshadow=local for x86 machines MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Code changes that addresses all compiler complaints coming from enabling -Wshadow flags. Enabling -Wshadow catches cases of local variables shadowing other local variables or parameters. These makes the code confusing and/or adds bugs that are difficult to catch. See also Subject: Help wanted for enabling -Wshadow=local Message-Id: <87r0mqlf9x.fsf@pond.sub.org> https://lore.kernel.org/qemu-devel/87r0mqlf9x.fsf@pond.sub.org CC: Markus Armbruster CC: Philippe Mathieu-Daude CC: mst@redhat.com Signed-off-by: Ani Sinha Reviewed-by: Daniel P. Berrangé Reviewed-by: Peter Xu Message-ID: <20231003102803.6163-1-anisinha@redhat.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Markus Armbruster --- hw/i386/acpi-microvm.c | 4 ++-- hw/i386/pc.c | 1 - hw/i386/x86.c | 2 -- 3 files changed, 2 insertions(+), 5 deletions(-) diff --git a/hw/i386/acpi-microvm.c b/hw/i386/acpi-microvm.c index fec22d85c1..2909a73933 100644 --- a/hw/i386/acpi-microvm.c +++ b/hw/i386/acpi-microvm.c @@ -55,8 +55,8 @@ static void acpi_dsdt_add_virtio(Aml *scope, bus = sysbus_get_default(); QTAILQ_FOREACH(kid, &bus->children, sibling) { - DeviceState *dev = kid->child; - Object *obj = object_dynamic_cast(OBJECT(dev), TYPE_VIRTIO_MMIO); + Object *obj = object_dynamic_cast(OBJECT(kid->child), + TYPE_VIRTIO_MMIO); if (obj) { VirtIOMMIOProxy *mmio = VIRTIO_MMIO(obj); diff --git a/hw/i386/pc.c b/hw/i386/pc.c index aad7e8ccd1..bb3854d1d0 100644 --- a/hw/i386/pc.c +++ b/hw/i386/pc.c @@ -1049,7 +1049,6 @@ void pc_memory_init(PCMachineState *pcms, if (machine->device_memory) { uint64_t *val = g_malloc(sizeof(*val)); - PCMachineClass *pcmc = PC_MACHINE_GET_CLASS(pcms); uint64_t res_mem_end = machine->device_memory->base; if (!pcmc->broken_reserved_end) { diff --git a/hw/i386/x86.c b/hw/i386/x86.c index f034df8bf6..b3d054889b 100644 --- a/hw/i386/x86.c +++ b/hw/i386/x86.c @@ -365,8 +365,6 @@ void x86_cpu_pre_plug(HotplugHandler *hotplug_dev, cpu_slot = x86_find_cpu_slot(MACHINE(x86ms), cpu->apic_id, &idx); if (!cpu_slot) { - MachineState *ms = MACHINE(x86ms); - x86_topo_ids_from_apicid(cpu->apic_id, &topo_info, &topo_ids); error_setg(errp, "Invalid CPU [socket: %u, die: %u, core: %u, thread: %u] with" From 071add900ba33cee8976dc3ae5b0d4909b1955f2 Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Wed, 4 Oct 2023 10:39:00 +0200 Subject: [PATCH 0351/1077] audio/ossaudio: Fix compiler warning with -Wshadow MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The "err" variable is only used twice in this code, in a very local fashion of first assigning it and then checking it in the next line. So there is no need to declare this variable a second time in the innermost block, we can re-use the variable that is declared at the beginning of the function. This fixes the compiler warning that occurs with "-Wshadow". Signed-off-by: Thomas Huth Message-ID: <20231004083900.95856-1-thuth@redhat.com> Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Markus Armbruster --- audio/ossaudio.c | 1 - 1 file changed, 1 deletion(-) diff --git a/audio/ossaudio.c b/audio/ossaudio.c index 3f31852371..c5858284a1 100644 --- a/audio/ossaudio.c +++ b/audio/ossaudio.c @@ -549,7 +549,6 @@ static int oss_init_out(HWVoiceOut *hw, struct audsettings *as, hw->size_emul); hw->buf_emul = NULL; } else { - int err; int trig = 0; if (ioctl (fd, SNDCTL_DSP_SETTRIGGER, &trig) < 0) { oss_logerr (errno, "SNDCTL_DSP_SETTRIGGER 0 failed\n"); From 5d63cb15bf2667486117690de02bbb85c1a36942 Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Wed, 4 Oct 2023 10:49:39 +0200 Subject: [PATCH 0352/1077] hw/net/vhost_net: Silence compiler warning when compiling with -Wshadow Rename the innermost local variables to avoid compiler warnings with "-Wshadow". Signed-off-by: Thomas Huth Message-ID: <20231004084939.96349-1-thuth@redhat.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Markus Armbruster --- hw/net/vhost_net.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/hw/net/vhost_net.c b/hw/net/vhost_net.c index 57427a3997..e8e1661646 100644 --- a/hw/net/vhost_net.c +++ b/hw/net/vhost_net.c @@ -313,8 +313,8 @@ fail: /* Queue might not be ready for start */ continue; } - int r = vhost_net_set_backend(&net->dev, &file); - assert(r >= 0); + int ret = vhost_net_set_backend(&net->dev, &file); + assert(ret >= 0); } } if (net->nc->info->poll) { @@ -629,8 +629,8 @@ err_start: if (net->nc->info->type == NET_CLIENT_DRIVER_TAP) { file.fd = VHOST_FILE_UNBIND; file.index = idx; - int r = vhost_net_set_backend(&net->dev, &file); - assert(r >= 0); + int ret = vhost_net_set_backend(&net->dev, &file); + assert(ret >= 0); } vhost_dev_stop(&net->dev, vdev, false); From 5ae80e6297080b3592b4658d92acfdba5255fc8b Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Wed, 4 Oct 2023 11:53:02 +0200 Subject: [PATCH 0353/1077] hw/virtio/virtio-pci: Avoid compiler warning with -Wshadow MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit "len" is used as parameter of the functions virtio_write_config() and virtio_read_config(), and additionally as a local variable, so this causes a compiler warning when compiling with "-Wshadow" and can be confusing for the reader. Rename the local variables to "caplen" to avoid this problem. Signed-off-by: Thomas Huth Message-ID: <20231004095302.99037-1-thuth@redhat.com> Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Markus Armbruster --- hw/virtio/virtio-pci.c | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/hw/virtio/virtio-pci.c b/hw/virtio/virtio-pci.c index edbc0daa18..abebd0075a 100644 --- a/hw/virtio/virtio-pci.c +++ b/hw/virtio/virtio-pci.c @@ -780,15 +780,15 @@ static void virtio_write_config(PCIDevice *pci_dev, uint32_t address, pci_cfg_data), sizeof cfg->pci_cfg_data)) { uint32_t off; - uint32_t len; + uint32_t caplen; cfg = (void *)(proxy->pci_dev.config + proxy->config_cap); off = le32_to_cpu(cfg->cap.offset); - len = le32_to_cpu(cfg->cap.length); + caplen = le32_to_cpu(cfg->cap.length); - if (len == 1 || len == 2 || len == 4) { - assert(len <= sizeof cfg->pci_cfg_data); - virtio_address_space_write(proxy, off, cfg->pci_cfg_data, len); + if (caplen == 1 || caplen == 2 || caplen == 4) { + assert(caplen <= sizeof cfg->pci_cfg_data); + virtio_address_space_write(proxy, off, cfg->pci_cfg_data, caplen); } } } @@ -804,15 +804,15 @@ static uint32_t virtio_read_config(PCIDevice *pci_dev, pci_cfg_data), sizeof cfg->pci_cfg_data)) { uint32_t off; - uint32_t len; + uint32_t caplen; cfg = (void *)(proxy->pci_dev.config + proxy->config_cap); off = le32_to_cpu(cfg->cap.offset); - len = le32_to_cpu(cfg->cap.length); + caplen = le32_to_cpu(cfg->cap.length); - if (len == 1 || len == 2 || len == 4) { - assert(len <= sizeof cfg->pci_cfg_data); - virtio_address_space_read(proxy, off, cfg->pci_cfg_data, len); + if (caplen == 1 || caplen == 2 || caplen == 4) { + assert(caplen <= sizeof cfg->pci_cfg_data); + virtio_address_space_read(proxy, off, cfg->pci_cfg_data, caplen); } } From da3182887cd3d3d02c3406549818cf222a9f0ca1 Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Wed, 4 Oct 2023 13:48:09 +0200 Subject: [PATCH 0354/1077] hw/virtio/vhost: Silence compiler warnings in vhost code when using -Wshadow Rename a variable in vhost_dev_sync_region() and remove a superfluous declaration in vhost_commit() to make this code compilable with "-Wshadow". Signed-off-by: Thomas Huth Message-ID: <20231004114809.105672-1-thuth@redhat.com> Reviewed-by: Michael S. Tsirkin Reviewed-By: Michael Tokarev Signed-off-by: Markus Armbruster --- hw/virtio/vhost.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/hw/virtio/vhost.c b/hw/virtio/vhost.c index e2f6ffb446..9cfac40fde 100644 --- a/hw/virtio/vhost.c +++ b/hw/virtio/vhost.c @@ -66,12 +66,12 @@ static void vhost_dev_sync_region(struct vhost_dev *dev, uint64_t mfirst, uint64_t mlast, uint64_t rfirst, uint64_t rlast) { - vhost_log_chunk_t *log = dev->log->log; + vhost_log_chunk_t *dev_log = dev->log->log; uint64_t start = MAX(mfirst, rfirst); uint64_t end = MIN(mlast, rlast); - vhost_log_chunk_t *from = log + start / VHOST_LOG_CHUNK; - vhost_log_chunk_t *to = log + end / VHOST_LOG_CHUNK + 1; + vhost_log_chunk_t *from = dev_log + start / VHOST_LOG_CHUNK; + vhost_log_chunk_t *to = dev_log + end / VHOST_LOG_CHUNK + 1; uint64_t addr = QEMU_ALIGN_DOWN(start, VHOST_LOG_CHUNK); if (end < start) { @@ -549,7 +549,7 @@ static void vhost_commit(MemoryListener *listener) changed = true; } else { /* Same size, lets check the contents */ - for (int i = 0; i < n_old_sections; i++) { + for (i = 0; i < n_old_sections; i++) { if (!MemoryRegionSection_eq(&old_sections[i], &dev->mem_sections[i])) { changed = true; From 71efffbcfc4ee4fb68228e7bafcc35cc6b2d8af0 Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Wed, 4 Oct 2023 15:13:38 +0200 Subject: [PATCH 0355/1077] dump: Silence compiler warning in dump code when compiling with -Wshadow MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Rename a variable to make this code compilable with -Wshadow. Signed-off-by: Thomas Huth Message-ID: <20231004131338.215081-1-thuth@redhat.com> Reviewed-by: Philippe Mathieu-Daudé Reviewed-By: Michael Tokarev Signed-off-by: Markus Armbruster --- dump/dump.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/dump/dump.c b/dump/dump.c index d4ef713cd0..d3578ddc62 100644 --- a/dump/dump.c +++ b/dump/dump.c @@ -1872,20 +1872,20 @@ static void dump_init(DumpState *s, int fd, bool has_format, if (vmci) { uint64_t addr, note_head_size, name_size, desc_size; uint32_t size; - uint16_t format; + uint16_t guest_format; note_head_size = dump_is_64bit(s) ? sizeof(Elf64_Nhdr) : sizeof(Elf32_Nhdr); - format = le16_to_cpu(vmci->vmcoreinfo.guest_format); + guest_format = le16_to_cpu(vmci->vmcoreinfo.guest_format); size = le32_to_cpu(vmci->vmcoreinfo.size); addr = le64_to_cpu(vmci->vmcoreinfo.paddr); if (!vmci->has_vmcoreinfo) { warn_report("guest note is not present"); } else if (size < note_head_size || size > MAX_GUEST_NOTE_SIZE) { warn_report("guest note size is invalid: %" PRIu32, size); - } else if (format != FW_CFG_VMCOREINFO_FORMAT_ELF) { - warn_report("guest note format is unsupported: %" PRIu16, format); + } else if (guest_format != FW_CFG_VMCOREINFO_FORMAT_ELF) { + warn_report("guest note format is unsupported: %" PRIu16, guest_format); } else { s->guest_note = g_malloc(size + 1); /* +1 for adding \0 */ cpu_physical_memory_read(addr, s->guest_note, size); From badf708d698853ce572c7dd41de6d81de1dedcbe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Wed, 4 Oct 2023 14:00:04 +0200 Subject: [PATCH 0356/1077] hw/audio/soundhw: Clean up global variable shadowing MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fix: hw/audio/soundhw.c:86:33: error: declaration shadows a variable in the global scope [-Werror,-Wshadow] void select_soundhw(const char *optarg, const char *audiodev) ^ /Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/include/getopt.h:77:14: note: previous declaration is here extern char *optarg; /* getopt(3) external variables */ ^ Signed-off-by: Philippe Mathieu-Daudé Message-ID: <20231004120019.93101-2-philmd@linaro.org> Reviewed-by: Richard Henderson Reviewed-by: Thomas Huth Signed-off-by: Markus Armbruster --- hw/audio/soundhw.c | 6 +++--- include/hw/audio/soundhw.h | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/hw/audio/soundhw.c b/hw/audio/soundhw.c index 94d9463e42..b387b0ef7d 100644 --- a/hw/audio/soundhw.c +++ b/hw/audio/soundhw.c @@ -83,7 +83,7 @@ void show_valid_soundhw(void) static struct soundhw *selected = NULL; static const char *audiodev_id; -void select_soundhw(const char *optarg, const char *audiodev) +void select_soundhw(const char *name, const char *audiodev) { struct soundhw *c; @@ -92,7 +92,7 @@ void select_soundhw(const char *optarg, const char *audiodev) } for (c = soundhw; c->name; ++c) { - if (g_str_equal(c->name, optarg)) { + if (g_str_equal(c->name, name)) { selected = c; audiodev_id = audiodev; break; @@ -100,7 +100,7 @@ void select_soundhw(const char *optarg, const char *audiodev) } if (!c->name) { - error_report("Unknown sound card name `%s'", optarg); + error_report("Unknown sound card name `%s'", name); show_valid_soundhw(); exit(1); } diff --git a/include/hw/audio/soundhw.h b/include/hw/audio/soundhw.h index 270717a06a..474c5ff94e 100644 --- a/include/hw/audio/soundhw.h +++ b/include/hw/audio/soundhw.h @@ -8,6 +8,6 @@ void deprecated_register_soundhw(const char *name, const char *descr, void soundhw_init(void); void show_valid_soundhw(void); -void select_soundhw(const char *optarg, const char *audiodev); +void select_soundhw(const char *name, const char *audiodev); #endif From a5afeefb58707768b86673118bd996bcfc8ea91e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Wed, 4 Oct 2023 14:00:05 +0200 Subject: [PATCH 0357/1077] hw/ide/ahci: Clean up local variable shadowing MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fix: hw/ide/ahci.c:1577:23: error: declaration shadows a local variable [-Werror,-Wshadow] IDEState *s = &ad->port.ifs[j]; ^ hw/ide/ahci.c:1569:29: note: previous declaration is here void ahci_uninit(AHCIState *s) ^ Signed-off-by: Philippe Mathieu-Daudé Message-ID: <20231004120019.93101-3-philmd@linaro.org> Reviewed-by: Richard Henderson Reviewed-by: John Snow Signed-off-by: Markus Armbruster --- hw/ide/ahci.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/hw/ide/ahci.c b/hw/ide/ahci.c index d0a774bc17..fcc5476e9e 100644 --- a/hw/ide/ahci.c +++ b/hw/ide/ahci.c @@ -1622,9 +1622,7 @@ void ahci_uninit(AHCIState *s) AHCIDevice *ad = &s->dev[i]; for (j = 0; j < 2; j++) { - IDEState *s = &ad->port.ifs[j]; - - ide_exit(s); + ide_exit(&ad->port.ifs[j]); } object_unparent(OBJECT(&ad->port)); } From 73071f1923ec1f30ddb894cd535a294fa198e11c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Wed, 4 Oct 2023 14:00:06 +0200 Subject: [PATCH 0358/1077] net/net: Clean up global variable shadowing MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fix: net/net.c:1680:35: error: declaration shadows a variable in the global scope [-Werror,-Wshadow] bool netdev_is_modern(const char *optarg) ^ net/net.c:1714:38: error: declaration shadows a variable in the global scope [-Werror,-Wshadow] void netdev_parse_modern(const char *optarg) ^ net/net.c:1728:60: error: declaration shadows a variable in the global scope [-Werror,-Wshadow] void net_client_parse(QemuOptsList *opts_list, const char *optarg) ^ /Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/include/getopt.h:77:14: note: previous declaration is here extern char *optarg; /* getopt(3) external variables */ ^ Signed-off-by: Philippe Mathieu-Daudé Message-ID: <20231004120019.93101-4-philmd@linaro.org> Reviewed-by: Richard Henderson Reviewed-by: Thomas Huth Signed-off-by: Markus Armbruster --- include/net/net.h | 6 +++--- net/net.c | 14 +++++++------- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/include/net/net.h b/include/net/net.h index 330d285930..2fb1c9181c 100644 --- a/include/net/net.h +++ b/include/net/net.h @@ -247,9 +247,9 @@ extern const char *host_net_devices[]; /* from net.c */ extern NetClientStateList net_clients; -bool netdev_is_modern(const char *optarg); -void netdev_parse_modern(const char *optarg); -void net_client_parse(QemuOptsList *opts_list, const char *str); +bool netdev_is_modern(const char *optstr); +void netdev_parse_modern(const char *optstr); +void net_client_parse(QemuOptsList *opts_list, const char *optstr); void show_netdevs(void); void net_init_clients(void); void net_check_clients(void); diff --git a/net/net.c b/net/net.c index 1c0bfdaa6c..c0c0cbe99e 100644 --- a/net/net.c +++ b/net/net.c @@ -1677,7 +1677,7 @@ void net_init_clients(void) * Modern syntax is to be parsed with netdev_parse_modern(). * Traditional syntax is to be parsed with net_client_parse(). */ -bool netdev_is_modern(const char *optarg) +bool netdev_is_modern(const char *optstr) { QemuOpts *opts; bool is_modern; @@ -1689,13 +1689,13 @@ bool netdev_is_modern(const char *optarg) .desc = { { } }, }; - if (optarg[0] == '{') { + if (optstr[0] == '{') { /* This is JSON, which means it's modern syntax */ return true; } opts = qemu_opts_create(&dummy_opts, NULL, false, &error_abort); - qemu_opts_do_parse(opts, optarg, dummy_opts.implied_opt_name, + qemu_opts_do_parse(opts, optstr, dummy_opts.implied_opt_name, &error_abort); type = qemu_opt_get(opts, "type"); is_modern = !g_strcmp0(type, "stream") || !g_strcmp0(type, "dgram"); @@ -1711,12 +1711,12 @@ bool netdev_is_modern(const char *optarg) * netdev_parse_modern() appends to @nd_queue, whereas net_client_parse() * appends to @qemu_netdev_opts. */ -void netdev_parse_modern(const char *optarg) +void netdev_parse_modern(const char *optstr) { Visitor *v; NetdevQueueEntry *nd; - v = qobject_input_visitor_new_str(optarg, "type", &error_fatal); + v = qobject_input_visitor_new_str(optstr, "type", &error_fatal); nd = g_new(NetdevQueueEntry, 1); visit_type_Netdev(v, NULL, &nd->nd, &error_fatal); visit_free(v); @@ -1725,9 +1725,9 @@ void netdev_parse_modern(const char *optarg) QSIMPLEQ_INSERT_TAIL(&nd_queue, nd, entry); } -void net_client_parse(QemuOptsList *opts_list, const char *optarg) +void net_client_parse(QemuOptsList *opts_list, const char *optstr) { - if (!qemu_opts_parse_noisily(opts_list, optarg, true)) { + if (!qemu_opts_parse_noisily(opts_list, optstr, true)) { exit(1); } } From d2803376849806135d7a3c6bc1ad2026cdaeec22 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Wed, 4 Oct 2023 14:00:07 +0200 Subject: [PATCH 0359/1077] os-posix: Clean up global variable shadowing MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fix: os-posix.c:103:31: error: declaration shadows a variable in the global scope [-Werror,-Wshadow] bool os_set_runas(const char *optarg) ^ os-posix.c:176:32: error: declaration shadows a variable in the global scope [-Werror,-Wshadow] void os_set_chroot(const char *optarg) ^ /Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/include/getopt.h:77:14: note: previous declaration is here extern char *optarg; /* getopt(3) external variables */ ^ Signed-off-by: Philippe Mathieu-Daudé Message-ID: <20231004120019.93101-5-philmd@linaro.org> Reviewed-by: Eric Blake Reviewed-by: Richard Henderson Signed-off-by: Markus Armbruster --- include/sysemu/os-posix.h | 4 ++-- os-posix.c | 12 ++++++------ 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/include/sysemu/os-posix.h b/include/sysemu/os-posix.h index 6dfdcbb086..dff32ae185 100644 --- a/include/sysemu/os-posix.h +++ b/include/sysemu/os-posix.h @@ -49,8 +49,8 @@ void os_setup_signal_handling(void); int os_set_daemonize(bool d); bool is_daemonized(void); void os_daemonize(void); -bool os_set_runas(const char *optarg); -void os_set_chroot(const char *optarg); +bool os_set_runas(const char *user_id); +void os_set_chroot(const char *path); void os_setup_post(void); int os_mlock(void); diff --git a/os-posix.c b/os-posix.c index f90dfda9b0..52ef6990ff 100644 --- a/os-posix.c +++ b/os-posix.c @@ -94,13 +94,13 @@ static uid_t user_uid = (uid_t)-1; /* -1 -1 >=0 */ static gid_t user_gid = (gid_t)-1; /* -1 -1 >=0 */ /* - * Prepare to change user ID. optarg can be one of 3 forms: + * Prepare to change user ID. user_id can be one of 3 forms: * - a username, in which case user ID will be changed to its uid, * with primary and supplementary groups set up too; * - a numeric uid, in which case only the uid will be set; * - a pair of numeric uid:gid. */ -bool os_set_runas(const char *optarg) +bool os_set_runas(const char *user_id) { unsigned long lv; const char *ep; @@ -108,14 +108,14 @@ bool os_set_runas(const char *optarg) gid_t got_gid; int rc; - user_pwd = getpwnam(optarg); + user_pwd = getpwnam(user_id); if (user_pwd) { user_uid = -1; user_gid = -1; return true; } - rc = qemu_strtoul(optarg, &ep, 0, &lv); + rc = qemu_strtoul(user_id, &ep, 0, &lv); got_uid = lv; /* overflow here is ID in C99 */ if (rc || *ep != ':' || got_uid != lv || got_uid == (uid_t)-1) { return false; @@ -173,9 +173,9 @@ static void change_process_uid(void) static const char *chroot_dir; -void os_set_chroot(const char *optarg) +void os_set_chroot(const char *path) { - chroot_dir = optarg; + chroot_dir = path; } static void change_root(void) From 82f3346ff46e1bbbe768a3084e7052668d34c1fe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Wed, 4 Oct 2023 14:00:08 +0200 Subject: [PATCH 0360/1077] plugins/loader: Clean up global variable shadowing MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fix: include/qemu/plugin.h:245:54: error: declaration shadows a variable in the global scope [-Werror,-Wshadow] static inline void qemu_plugin_opt_parse(const char *optarg, ^ /Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/include/getopt.h:77:14: note: previous declaration is here extern char *optarg; /* getopt(3) external variables */ ^ Signed-off-by: Philippe Mathieu-Daudé Message-ID: <20231004120019.93101-6-philmd@linaro.org> Reviewed-by: Richard Henderson Signed-off-by: Markus Armbruster --- include/qemu/plugin.h | 4 ++-- plugins/loader.c | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/include/qemu/plugin.h b/include/qemu/plugin.h index bc0781cab8..7fdc3a4849 100644 --- a/include/qemu/plugin.h +++ b/include/qemu/plugin.h @@ -50,7 +50,7 @@ static inline void qemu_plugin_add_opts(void) qemu_add_opts(&qemu_plugin_opts); } -void qemu_plugin_opt_parse(const char *optarg, QemuPluginList *head); +void qemu_plugin_opt_parse(const char *optstr, QemuPluginList *head); int qemu_plugin_load_list(QemuPluginList *head, Error **errp); union qemu_plugin_cb_sig { @@ -242,7 +242,7 @@ void qemu_plugin_user_postfork(bool is_child); static inline void qemu_plugin_add_opts(void) { } -static inline void qemu_plugin_opt_parse(const char *optarg, +static inline void qemu_plugin_opt_parse(const char *optstr, QemuPluginList *head) { error_report("plugin interface not enabled in this build"); diff --git a/plugins/loader.c b/plugins/loader.c index 809f3f9b13..734c11cae0 100644 --- a/plugins/loader.c +++ b/plugins/loader.c @@ -140,12 +140,12 @@ static int plugin_add(void *opaque, const char *name, const char *value, return 0; } -void qemu_plugin_opt_parse(const char *optarg, QemuPluginList *head) +void qemu_plugin_opt_parse(const char *optstr, QemuPluginList *head) { struct qemu_plugin_parse_arg arg; QemuOpts *opts; - opts = qemu_opts_parse_noisily(qemu_find_opts("plugin"), optarg, true); + opts = qemu_opts_parse_noisily(qemu_find_opts("plugin"), optstr, true); if (opts == NULL) { exit(1); } From 46bb944efdfbcf8447784b2c4464c6f515460095 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Wed, 4 Oct 2023 14:00:09 +0200 Subject: [PATCH 0361/1077] qemu-img: Clean up global variable shadowing MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fix: qemu-img.c:247:46: error: declaration shadows a variable in the global scope [-Werror,-Wshadow] static bool is_valid_option_list(const char *optarg) ^ qemu-img.c:265:53: error: declaration shadows a variable in the global scope [-Werror,-Wshadow] static int accumulate_options(char **options, char *optarg) ^ /Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/include/getopt.h:77:14: note: previous declaration is here extern char *optarg; /* getopt(3) external variables */ ^ Signed-off-by: Philippe Mathieu-Daudé Message-ID: <20231004120019.93101-7-philmd@linaro.org> Reviewed-by: Eric Blake Reviewed-by: Richard Henderson Signed-off-by: Markus Armbruster --- qemu-img.c | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/qemu-img.c b/qemu-img.c index a48edb7101..6068ab0d27 100644 --- a/qemu-img.c +++ b/qemu-img.c @@ -235,25 +235,25 @@ void help(void) } /* - * Is @optarg safe for accumulate_options()? + * Is @list safe for accumulate_options()? * It is when multiple of them can be joined together separated by ','. - * To make that work, @optarg must not start with ',' (or else a + * To make that work, @list must not start with ',' (or else a * separating ',' preceding it gets escaped), and it must not end with * an odd number of ',' (or else a separating ',' following it gets * escaped), or be empty (or else a separating ',' preceding it can * escape a separating ',' following it). * */ -static bool is_valid_option_list(const char *optarg) +static bool is_valid_option_list(const char *list) { - size_t len = strlen(optarg); + size_t len = strlen(list); size_t i; - if (!optarg[0] || optarg[0] == ',') { + if (!list[0] || list[0] == ',') { return false; } - for (i = len; i > 0 && optarg[i - 1] == ','; i--) { + for (i = len; i > 0 && list[i - 1] == ','; i--) { } if ((len - i) % 2) { return false; @@ -262,19 +262,19 @@ static bool is_valid_option_list(const char *optarg) return true; } -static int accumulate_options(char **options, char *optarg) +static int accumulate_options(char **options, char *list) { char *new_options; - if (!is_valid_option_list(optarg)) { - error_report("Invalid option list: %s", optarg); + if (!is_valid_option_list(list)) { + error_report("Invalid option list: %s", list); return -1; } if (!*options) { - *options = g_strdup(optarg); + *options = g_strdup(list); } else { - new_options = g_strdup_printf("%s,%s", *options, optarg); + new_options = g_strdup_printf("%s,%s", *options, list); g_free(*options); *options = new_options; } From 21c029e65fe6245a64bbab8047903c4883476bd2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Wed, 4 Oct 2023 14:00:10 +0200 Subject: [PATCH 0362/1077] qemu-io: Clean up global variable shadowing MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fix: qemu-io.c:478:36: error: declaration shadows a variable in the global scope [-Werror,-Wshadow] static void add_user_command(char *optarg) ^ /Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/include/getopt.h:77:14: note: previous declaration is here extern char *optarg; /* getopt(3) external variables */ ^ Signed-off-by: Philippe Mathieu-Daudé Message-ID: <20231004120019.93101-8-philmd@linaro.org> Reviewed-by: Eric Blake Reviewed-by: Richard Henderson Signed-off-by: Markus Armbruster --- qemu-io.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/qemu-io.c b/qemu-io.c index 2bd7bfb650..050c70835f 100644 --- a/qemu-io.c +++ b/qemu-io.c @@ -475,10 +475,10 @@ static int command_loop(void) return last_error; } -static void add_user_command(char *optarg) +static void add_user_command(char *user_cmd) { cmdline = g_renew(char *, cmdline, ++ncmdline); - cmdline[ncmdline-1] = optarg; + cmdline[ncmdline - 1] = user_cmd; } static void reenable_tty_echo(void) From e0c7de8dc4a3c0b7a0d0fa21fa0561a4dc763716 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Wed, 4 Oct 2023 14:00:11 +0200 Subject: [PATCH 0363/1077] qom/object_interfaces: Clean up global variable shadowing MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fix: qom/object_interfaces.c:262:53: error: declaration shadows a variable in the global scope [-Werror,-Wshadow] ObjectOptions *user_creatable_parse_str(const char *optarg, Error **errp) ^ qom/object_interfaces.c:298:46: error: declaration shadows a variable in the global scope [-Werror,-Wshadow] bool user_creatable_add_from_str(const char *optarg, Error **errp) ^ qom/object_interfaces.c:313:49: error: declaration shadows a variable in the global scope [-Werror,-Wshadow] void user_creatable_process_cmdline(const char *optarg) ^ /Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/include/getopt.h:77:14: note: previous declaration is here extern char *optarg; /* getopt(3) external variables */ ^ Signed-off-by: Philippe Mathieu-Daudé Message-ID: <20231004120019.93101-9-philmd@linaro.org> Reviewed-by: Richard Henderson Signed-off-by: Markus Armbruster --- include/qom/object_interfaces.h | 16 ++++++++-------- qom/object_interfaces.c | 16 ++++++++-------- 2 files changed, 16 insertions(+), 16 deletions(-) diff --git a/include/qom/object_interfaces.h b/include/qom/object_interfaces.h index 81541e2080..02b11a7ef0 100644 --- a/include/qom/object_interfaces.h +++ b/include/qom/object_interfaces.h @@ -99,7 +99,7 @@ void user_creatable_add_qapi(ObjectOptions *options, Error **errp); /** * user_creatable_parse_str: - * @optarg: the object definition string as passed on the command line + * @str: the object definition string as passed on the command line * @errp: if an error occurs, a pointer to an area to store the error * * Parses the option for the user creatable object with a keyval parser and @@ -110,14 +110,14 @@ void user_creatable_add_qapi(ObjectOptions *options, Error **errp); * Returns: ObjectOptions on success, NULL when an error occurred (*errp is set * then) or help was printed (*errp is not set). */ -ObjectOptions *user_creatable_parse_str(const char *optarg, Error **errp); +ObjectOptions *user_creatable_parse_str(const char *str, Error **errp); /** * user_creatable_add_from_str: - * @optarg: the object definition string as passed on the command line + * @str: the object definition string as passed on the command line * @errp: if an error occurs, a pointer to an area to store the error * - * Create an instance of the user creatable object by parsing optarg + * Create an instance of the user creatable object by parsing @str * with a keyval parser and implicit key 'qom-type', converting the * result to ObjectOptions and calling into qmp_object_add(). * @@ -126,13 +126,13 @@ ObjectOptions *user_creatable_parse_str(const char *optarg, Error **errp); * Returns: true when an object was successfully created, false when an error * occurred (*errp is set then) or help was printed (*errp is not set). */ -bool user_creatable_add_from_str(const char *optarg, Error **errp); +bool user_creatable_add_from_str(const char *str, Error **errp); /** * user_creatable_process_cmdline: - * @optarg: the object definition string as passed on the command line + * @cmdline: the object definition string as passed on the command line * - * Create an instance of the user creatable object by parsing optarg + * Create an instance of the user creatable object by parsing @cmdline * with a keyval parser and implicit key 'qom-type', converting the * result to ObjectOptions and calling into qmp_object_add(). * @@ -141,7 +141,7 @@ bool user_creatable_add_from_str(const char *optarg, Error **errp); * This function is only meant to be called during command line parsing. * It exits the process on failure or after printing help. */ -void user_creatable_process_cmdline(const char *optarg); +void user_creatable_process_cmdline(const char *cmdline); /** * user_creatable_print_help: diff --git a/qom/object_interfaces.c b/qom/object_interfaces.c index 7d31589b04..e0833c8bfe 100644 --- a/qom/object_interfaces.c +++ b/qom/object_interfaces.c @@ -259,7 +259,7 @@ static void user_creatable_print_help_from_qdict(QDict *args) } } -ObjectOptions *user_creatable_parse_str(const char *optarg, Error **errp) +ObjectOptions *user_creatable_parse_str(const char *str, Error **errp) { ERRP_GUARD(); QObject *obj; @@ -267,14 +267,14 @@ ObjectOptions *user_creatable_parse_str(const char *optarg, Error **errp) Visitor *v; ObjectOptions *options; - if (optarg[0] == '{') { - obj = qobject_from_json(optarg, errp); + if (str[0] == '{') { + obj = qobject_from_json(str, errp); if (!obj) { return NULL; } v = qobject_input_visitor_new(obj); } else { - QDict *args = keyval_parse(optarg, "qom-type", &help, errp); + QDict *args = keyval_parse(str, "qom-type", &help, errp); if (*errp) { return NULL; } @@ -295,12 +295,12 @@ ObjectOptions *user_creatable_parse_str(const char *optarg, Error **errp) return options; } -bool user_creatable_add_from_str(const char *optarg, Error **errp) +bool user_creatable_add_from_str(const char *str, Error **errp) { ERRP_GUARD(); ObjectOptions *options; - options = user_creatable_parse_str(optarg, errp); + options = user_creatable_parse_str(str, errp); if (!options) { return false; } @@ -310,9 +310,9 @@ bool user_creatable_add_from_str(const char *optarg, Error **errp) return !*errp; } -void user_creatable_process_cmdline(const char *optarg) +void user_creatable_process_cmdline(const char *cmdline) { - if (!user_creatable_add_from_str(optarg, &error_fatal)) { + if (!user_creatable_add_from_str(cmdline, &error_fatal)) { /* Help was printed */ exit(EXIT_SUCCESS); } From afb81fe8542c0962b025c566476cdded3b8ec5e1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Wed, 4 Oct 2023 14:00:12 +0200 Subject: [PATCH 0364/1077] semihosting: Clean up global variable shadowing MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fix: semihosting/config.c:134:49: error: declaration shadows a variable in the global scope [-Werror,-Wshadow] int qemu_semihosting_config_options(const char *optarg) ^ /Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/include/getopt.h:77:14: note: previous declaration is here extern char *optarg; /* getopt(3) external variables */ ^ Signed-off-by: Philippe Mathieu-Daudé Message-ID: <20231004120019.93101-10-philmd@linaro.org> Reviewed-by: Alex Bennée Reviewed-by: Richard Henderson Signed-off-by: Markus Armbruster --- include/semihosting/semihost.h | 2 +- semihosting/config.c | 8 ++++---- stubs/semihost.c | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/include/semihosting/semihost.h b/include/semihosting/semihost.h index efd2efa25a..97d2a2ba99 100644 --- a/include/semihosting/semihost.h +++ b/include/semihosting/semihost.h @@ -66,7 +66,7 @@ const char *semihosting_get_cmdline(void); void semihosting_arg_fallback(const char *file, const char *cmd); /* for vl.c hooks */ void qemu_semihosting_enable(void); -int qemu_semihosting_config_options(const char *opt); +int qemu_semihosting_config_options(const char *optstr); void qemu_semihosting_chardev_init(void); void qemu_semihosting_console_init(Chardev *); #endif /* CONFIG_USER_ONLY */ diff --git a/semihosting/config.c b/semihosting/config.c index 8ca569735d..e826457733 100644 --- a/semihosting/config.c +++ b/semihosting/config.c @@ -131,10 +131,10 @@ void qemu_semihosting_enable(void) semihosting.target = SEMIHOSTING_TARGET_AUTO; } -int qemu_semihosting_config_options(const char *optarg) +int qemu_semihosting_config_options(const char *optstr) { QemuOptsList *opt_list = qemu_find_opts("semihosting-config"); - QemuOpts *opts = qemu_opts_parse_noisily(opt_list, optarg, false); + QemuOpts *opts = qemu_opts_parse_noisily(opt_list, optstr, false); semihosting.enabled = true; @@ -155,7 +155,7 @@ int qemu_semihosting_config_options(const char *optarg) semihosting.target = SEMIHOSTING_TARGET_AUTO; } else { error_report("unsupported semihosting-config %s", - optarg); + optstr); return 1; } } else { @@ -165,7 +165,7 @@ int qemu_semihosting_config_options(const char *optarg) qemu_opt_foreach(opts, add_semihosting_arg, &semihosting, NULL); } else { - error_report("unsupported semihosting-config %s", optarg); + error_report("unsupported semihosting-config %s", optstr); return 1; } diff --git a/stubs/semihost.c b/stubs/semihost.c index aad7a70353..b3c61935b3 100644 --- a/stubs/semihost.c +++ b/stubs/semihost.c @@ -36,7 +36,7 @@ void qemu_semihosting_enable(void) { } -int qemu_semihosting_config_options(const char *optarg) +int qemu_semihosting_config_options(const char *optstr) { return 1; } From 21eb752ff53bed33594766d1dccd66efcf4f54ab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Wed, 4 Oct 2023 14:00:13 +0200 Subject: [PATCH 0365/1077] ui/cocoa: Clean up global variable shadowing MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fix: ui/cocoa.m:346:20: error: declaration shadows a variable in the global scope [-Werror,-Wshadow] QemuCocoaView *cocoaView = userInfo; ^ ui/cocoa.m:342:16: note: previous declaration is here QemuCocoaView *cocoaView; ^ Signed-off-by: Philippe Mathieu-Daudé Message-ID: <20231004120019.93101-11-philmd@linaro.org> Reviewed-by: Richard Henderson Reviewed-by: Akihiko Odaki Signed-off-by: Markus Armbruster --- ui/cocoa.m | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ui/cocoa.m b/ui/cocoa.m index 145f42d190..d95276013c 100644 --- a/ui/cocoa.m +++ b/ui/cocoa.m @@ -343,9 +343,9 @@ QemuCocoaView *cocoaView; static CGEventRef handleTapEvent(CGEventTapProxy proxy, CGEventType type, CGEventRef cgEvent, void *userInfo) { - QemuCocoaView *cocoaView = userInfo; + QemuCocoaView *view = userInfo; NSEvent *event = [NSEvent eventWithCGEvent:cgEvent]; - if ([cocoaView isMouseGrabbed] && [cocoaView handleEvent:event]) { + if ([view isMouseGrabbed] && [view handleEvent:event]) { COCOA_DEBUG("Global events tap: qemu handled the event, capturing!\n"); return NULL; } From 5bebe03f51991ad92ae1220111eda5c7a0e70289 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Wed, 4 Oct 2023 14:00:14 +0200 Subject: [PATCH 0366/1077] util/cutils: Clean up global variable shadowing in get_relocated_path() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fix: util/cutils.c:1147:17: error: declaration shadows a variable in the global scope [-Werror,-Wshadow] const char *exec_dir = qemu_get_exec_dir(); ^ util/cutils.c:1035:20: note: previous declaration is here static const char *exec_dir; ^ Signed-off-by: Philippe Mathieu-Daudé Message-ID: <20231004120019.93101-12-philmd@linaro.org> Reviewed-by: Eric Blake Reviewed-by: Richard Henderson Signed-off-by: Markus Armbruster --- util/cutils.c | 1 - 1 file changed, 1 deletion(-) diff --git a/util/cutils.c b/util/cutils.c index 25373198ad..b44718a6a2 100644 --- a/util/cutils.c +++ b/util/cutils.c @@ -1144,7 +1144,6 @@ char *get_relocated_path(const char *dir) { size_t prefix_len = strlen(CONFIG_PREFIX); const char *bindir = CONFIG_BINDIR; - const char *exec_dir = qemu_get_exec_dir(); GString *result; int len_dir, len_bindir; From ca84e7b2250496748ac6ed8956aad8a0fb72acde Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Wed, 4 Oct 2023 14:00:15 +0200 Subject: [PATCH 0367/1077] util/guest-random: Clean up global variable shadowing MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fix: util/guest-random.c:90:45: error: declaration shadows a variable in the global scope [-Werror,-Wshadow] int qemu_guest_random_seed_main(const char *optarg, Error **errp) ^ /Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/include/getopt.h:77:14: note: previous declaration is here extern char *optarg; /* getopt(3) external variables */ ^ Signed-off-by: Philippe Mathieu-Daudé Message-ID: <20231004120019.93101-13-philmd@linaro.org> Reviewed-by: Richard Henderson Signed-off-by: Markus Armbruster --- include/qemu/guest-random.h | 8 ++++---- util/guest-random.c | 6 +++--- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/include/qemu/guest-random.h b/include/qemu/guest-random.h index 09ff9c2236..5060d49d60 100644 --- a/include/qemu/guest-random.h +++ b/include/qemu/guest-random.h @@ -13,16 +13,16 @@ #define QEMU_GUEST_RANDOM_H /** - * qemu_guest_random_seed_main(const char *optarg, Error **errp) - * @optarg: a non-NULL pointer to a C string + * qemu_guest_random_seed_main(const char *seedstr, Error **errp) + * @seedstr: a non-NULL pointer to a C string * @errp: an error indicator * - * The @optarg value is that which accompanies the -seed argument. + * The @seedstr value is that which accompanies the -seed argument. * This forces qemu_guest_getrandom into deterministic mode. * * Returns 0 on success, < 0 on failure while setting *errp. */ -int qemu_guest_random_seed_main(const char *optarg, Error **errp); +int qemu_guest_random_seed_main(const char *seedstr, Error **errp); /** * qemu_guest_random_seed_thread_part1(void) diff --git a/util/guest-random.c b/util/guest-random.c index 9465dda085..33607d5ff2 100644 --- a/util/guest-random.c +++ b/util/guest-random.c @@ -87,11 +87,11 @@ void qemu_guest_random_seed_thread_part2(uint64_t seed) } } -int qemu_guest_random_seed_main(const char *optarg, Error **errp) +int qemu_guest_random_seed_main(const char *seedstr, Error **errp) { uint64_t seed; - if (parse_uint_full(optarg, 0, &seed)) { - error_setg(errp, "Invalid seed number: %s", optarg); + if (parse_uint_full(seedstr, 0, &seed)) { + error_setg(errp, "Invalid seed number: %s", seedstr); return -1; } else { deterministic = true; From a60e5736eb8d8b624739dd4e94b9faf07fdbbbe0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Wed, 4 Oct 2023 14:00:16 +0200 Subject: [PATCH 0368/1077] semihosting/arm-compat: Clean up local variable shadowing MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fix: semihosting/arm-compat-semi.c: In function ‘do_common_semihosting’: semihosting/arm-compat-semi.c:379:13: warning: declaration of ‘ret’ shadows a previous local [-Wshadow=local] 379 | int ret, err = 0; | ^~~ semihosting/arm-compat-semi.c:370:14: note: shadowed declaration is here 370 | uint32_t ret; | ^~~ semihosting/arm-compat-semi.c:682:27: warning: declaration of ‘ret’ shadows a previous local [-Wshadow=local] 682 | abi_ulong ret; | ^~~ semihosting/arm-compat-semi.c:370:9: note: shadowed declaration is here 370 | int ret; | ^~~ Signed-off-by: Philippe Mathieu-Daudé Message-ID: <20231004120019.93101-14-philmd@linaro.org> Reviewed-by: Richard Henderson Signed-off-by: Markus Armbruster --- semihosting/arm-compat-semi.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/semihosting/arm-compat-semi.c b/semihosting/arm-compat-semi.c index 29c5670fdf..ec959b3e01 100644 --- a/semihosting/arm-compat-semi.c +++ b/semihosting/arm-compat-semi.c @@ -367,7 +367,6 @@ void do_common_semihosting(CPUState *cs) target_ulong ul_ret; char * s; int nr; - uint32_t ret; int64_t elapsed; nr = common_semi_arg(cs, 0) & 0xffffffffU; @@ -725,6 +724,9 @@ void do_common_semihosting(CPUState *cs) case TARGET_SYS_EXIT: case TARGET_SYS_EXIT_EXTENDED: + { + uint32_t ret; + if (common_semi_sys_exit_extended(cs, nr)) { /* * The A64 version of SYS_EXIT takes a parameter block, @@ -752,6 +754,7 @@ void do_common_semihosting(CPUState *cs) } gdb_exit(ret); exit(ret); + } case TARGET_SYS_ELAPSED: elapsed = get_clock() - clock_start; From 48176a1d287179ea4e85122e1bc803f329773141 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Wed, 4 Oct 2023 14:00:17 +0200 Subject: [PATCH 0369/1077] softmmu/vl: Clean up global variable shadowing MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fix: softmmu/vl.c:1069:44: error: declaration shadows a variable in the global scope [-Werror,-Wshadow] static void parse_display_qapi(const char *optarg) ^ softmmu/vl.c:1224:39: error: declaration shadows a variable in the global scope [-Werror,-Wshadow] static void monitor_parse(const char *optarg, const char *mode, bool pretty) ^ softmmu/vl.c:1634:17: error: declaration shadows a variable in the global scope [-Werror,-Wshadow] const char *optarg = qdict_get_try_str(qdict, "type"); ^ softmmu/vl.c:1784:45: error: declaration shadows a variable in the global scope [-Werror,-Wshadow] static void object_option_parse(const char *optarg) ^ /Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/include/getopt.h:77:14: note: previous declaration is here extern char *optarg; /* getopt(3) external variables */ ^ Signed-off-by: Philippe Mathieu-Daudé Message-ID: <20231004120019.93101-15-philmd@linaro.org> Reviewed-by: Richard Henderson Reviewed-by: Markus Armbruster [Tweak two parameter names] Signed-off-by: Markus Armbruster --- softmmu/vl.c | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/softmmu/vl.c b/softmmu/vl.c index 98e071e63b..13c1b24706 100644 --- a/softmmu/vl.c +++ b/softmmu/vl.c @@ -1066,12 +1066,12 @@ static void select_vgahw(const MachineClass *machine_class, const char *p) } } -static void parse_display_qapi(const char *optarg) +static void parse_display_qapi(const char *str) { DisplayOptions *opts; Visitor *v; - v = qobject_input_visitor_new_str(optarg, "type", &error_fatal); + v = qobject_input_visitor_new_str(str, "type", &error_fatal); visit_type_DisplayOptions(v, NULL, &opts, &error_fatal); QAPI_CLONE_MEMBERS(DisplayOptions, &dpy, opts); @@ -1221,21 +1221,21 @@ static int mon_init_func(void *opaque, QemuOpts *opts, Error **errp) return monitor_init_opts(opts, errp); } -static void monitor_parse(const char *optarg, const char *mode, bool pretty) +static void monitor_parse(const char *str, const char *mode, bool pretty) { static int monitor_device_index = 0; QemuOpts *opts; const char *p; char label[32]; - if (strstart(optarg, "chardev:", &p)) { + if (strstart(str, "chardev:", &p)) { snprintf(label, sizeof(label), "%s", p); } else { snprintf(label, sizeof(label), "compat_monitor%d", monitor_device_index); - opts = qemu_chr_parse_compat(label, optarg, true); + opts = qemu_chr_parse_compat(label, str, true); if (!opts) { - error_report("parse error: %s", optarg); + error_report("parse error: %s", str); exit(1); } } @@ -1631,13 +1631,13 @@ static const QEMUOption *lookup_opt(int argc, char **argv, static MachineClass *select_machine(QDict *qdict, Error **errp) { - const char *optarg = qdict_get_try_str(qdict, "type"); + const char *machine_type = qdict_get_try_str(qdict, "type"); GSList *machines = object_class_get_list(TYPE_MACHINE, false); MachineClass *machine_class; Error *local_err = NULL; - if (optarg) { - machine_class = find_machine(optarg, machines); + if (machine_type) { + machine_class = find_machine(machine_type, machines); qdict_del(qdict, "type"); if (!machine_class) { error_setg(&local_err, "unsupported machine type"); @@ -1781,20 +1781,20 @@ static void object_option_add_visitor(Visitor *v) QTAILQ_INSERT_TAIL(&object_opts, opt, next); } -static void object_option_parse(const char *optarg) +static void object_option_parse(const char *str) { QemuOpts *opts; const char *type; Visitor *v; - if (optarg[0] == '{') { - QObject *obj = qobject_from_json(optarg, &error_fatal); + if (str[0] == '{') { + QObject *obj = qobject_from_json(str, &error_fatal); v = qobject_input_visitor_new(obj); qobject_unref(obj); } else { opts = qemu_opts_parse_noisily(qemu_find_opts("object"), - optarg, true); + str, true); if (!opts) { exit(1); } From fcd9a353798d09a6fe39e720fb1a52ed32cad91d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Wed, 4 Oct 2023 14:00:18 +0200 Subject: [PATCH 0370/1077] sysemu/tpm: Clean up global variable shadowing MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fix: softmmu/tpm.c:178:59: error: declaration shadows a variable in the global scope [-Werror,-Wshadow] int tpm_config_parse(QemuOptsList *opts_list, const char *optarg) ^ /Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/include/getopt.h:77:14: note: previous declaration is here extern char *optarg; /* getopt(3) external variables */ ^ Signed-off-by: Philippe Mathieu-Daudé Message-ID: <20231004120019.93101-16-philmd@linaro.org> Reviewed-by: Stefan Berger Reviewed-by: Richard Henderson Signed-off-by: Markus Armbruster --- include/sysemu/tpm.h | 2 +- softmmu/tpm.c | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/include/sysemu/tpm.h b/include/sysemu/tpm.h index 66e3b45f30..1ee568b3b6 100644 --- a/include/sysemu/tpm.h +++ b/include/sysemu/tpm.h @@ -17,7 +17,7 @@ #ifdef CONFIG_TPM -int tpm_config_parse(QemuOptsList *opts_list, const char *optarg); +int tpm_config_parse(QemuOptsList *opts_list, const char *optstr); int tpm_init(void); void tpm_cleanup(void); diff --git a/softmmu/tpm.c b/softmmu/tpm.c index 578563f05a..7164ea7ff1 100644 --- a/softmmu/tpm.c +++ b/softmmu/tpm.c @@ -175,15 +175,15 @@ int tpm_init(void) * Parse the TPM configuration options. * To display all available TPM backends the user may use '-tpmdev help' */ -int tpm_config_parse(QemuOptsList *opts_list, const char *optarg) +int tpm_config_parse(QemuOptsList *opts_list, const char *optstr) { QemuOpts *opts; - if (!strcmp(optarg, "help")) { + if (!strcmp(optstr, "help")) { tpm_display_backend_drivers(); return -1; } - opts = qemu_opts_parse_noisily(opts_list, optarg, true); + opts = qemu_opts_parse_noisily(opts_list, optstr, true); if (!opts) { return -1; } From 8b7b9c5c88a8886312d3b9bc5e3615d21df143b6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Wed, 4 Oct 2023 14:00:19 +0200 Subject: [PATCH 0371/1077] trace/control: Clean up global variable shadowing MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fix: trace/control.c:288:34: error: declaration shadows a variable in the global scope [-Werror,-Wshadow] void trace_opt_parse(const char *optarg) ^ /Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/include/getopt.h:77:14: note: previous declaration is here extern char *optarg; /* getopt(3) external variables */ ^ Signed-off-by: Philippe Mathieu-Daudé Message-ID: <20231004120019.93101-17-philmd@linaro.org> Reviewed-by: Stefan Hajnoczi Reviewed-by: Richard Henderson Signed-off-by: Markus Armbruster --- trace/control.c | 4 ++-- trace/control.h | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/trace/control.c b/trace/control.c index 1a48a7e266..ef107829ac 100644 --- a/trace/control.c +++ b/trace/control.c @@ -285,10 +285,10 @@ bool trace_init_backends(void) return true; } -void trace_opt_parse(const char *optarg) +void trace_opt_parse(const char *optstr) { QemuOpts *opts = qemu_opts_parse_noisily(qemu_find_opts("trace"), - optarg, true); + optstr, true); if (!opts) { exit(1); } diff --git a/trace/control.h b/trace/control.h index dfd209edd8..6754bfe052 100644 --- a/trace/control.h +++ b/trace/control.h @@ -197,11 +197,11 @@ extern QemuOptsList qemu_trace_opts; /** * trace_opt_parse: - * @optarg: A string argument of --trace command line argument + * @optstr: A string argument of --trace command line argument * * Initialize tracing subsystem. */ -void trace_opt_parse(const char *optarg); +void trace_opt_parse(const char *optstr); /** * trace_get_vcpu_event_count: From 0edc9e45f3d6b0601f3628df2ca78b3ee78aa662 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Le=20Goater?= Date: Fri, 6 Oct 2023 07:35:26 +0200 Subject: [PATCH 0372/1077] target/ppc: Clean up local variable shadowing in kvm_arch_*_registers() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Remove extra 'i' variable to fix this warning : ../target/ppc/kvm.c: In function ‘kvm_arch_put_registers’: ../target/ppc/kvm.c:963:13: warning: declaration of ‘i’ shadows a previous local [-Wshadow=compatible-local] 963 | int i; | ^ ../target/ppc/kvm.c:906:9: note: shadowed declaration is here 906 | int i; | ^ ../target/ppc/kvm.c: In function ‘kvm_arch_get_registers’: ../target/ppc/kvm.c:1265:13: warning: declaration of ‘i’ shadows a previous local [-Wshadow=compatible-local] 1265 | int i; | ^ ../target/ppc/kvm.c:1212:9: note: shadowed declaration is here 1212 | int i, ret; | ^ Signed-off-by: Cédric Le Goater Message-ID: <20231006053526.1031252-1-clg@kaod.org> Reviewed-by: Thomas Huth Signed-off-by: Markus Armbruster --- target/ppc/kvm.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/target/ppc/kvm.c b/target/ppc/kvm.c index 51112bd367..d0e2dcdc77 100644 --- a/target/ppc/kvm.c +++ b/target/ppc/kvm.c @@ -960,8 +960,6 @@ int kvm_arch_put_registers(CPUState *cs, int level) } if (cap_one_reg) { - int i; - /* * We deliberately ignore errors here, for kernels which have * the ONE_REG calls, but don't support the specific @@ -1262,8 +1260,6 @@ int kvm_arch_get_registers(CPUState *cs) } if (cap_one_reg) { - int i; - /* * We deliberately ignore errors here, for kernels which have * the ONE_REG calls, but don't support the specific From e7121b15411d0a9220d82d293537b91841f47c82 Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Wed, 4 Oct 2023 15:08:22 +0200 Subject: [PATCH 0373/1077] hw/usb: Silence compiler warnings in USB code when compiling with -Wshadow Rename variables or remove nested definitions where it makes sense, so that we can finally compile the USB code with "-Wshadow", too. Signed-off-by: Thomas Huth Message-ID: <20231004130822.113343-1-thuth@redhat.com> Reviewed-by: Michael Tokarev Signed-off-by: Markus Armbruster --- hw/usb/desc.c | 2 +- hw/usb/dev-hub.c | 8 ++++---- hw/usb/dev-storage.c | 6 +++--- hw/usb/hcd-xhci.c | 10 +++++----- hw/usb/host-libusb.c | 2 +- 5 files changed, 14 insertions(+), 14 deletions(-) diff --git a/hw/usb/desc.c b/hw/usb/desc.c index 7f6cc2f99b..f2bdc05a95 100644 --- a/hw/usb/desc.c +++ b/hw/usb/desc.c @@ -227,7 +227,7 @@ int usb_desc_endpoint(const USBDescEndpoint *ep, int flags, } if (superlen) { - USBDescriptor *d = (void *)(dest + bLength); + d = (void *)(dest + bLength); d->bLength = 0x06; d->bDescriptorType = USB_DT_ENDPOINT_COMPANION; diff --git a/hw/usb/dev-hub.c b/hw/usb/dev-hub.c index a6b50dbc8d..5703e0e826 100644 --- a/hw/usb/dev-hub.c +++ b/hw/usb/dev-hub.c @@ -402,7 +402,7 @@ static void usb_hub_handle_control(USBDevice *dev, USBPacket *p, { unsigned int n = index - 1; USBHubPort *port; - USBDevice *dev; + USBDevice *pdev; trace_usb_hub_set_port_feature(s->dev.addr, index, feature_name(value)); @@ -411,7 +411,7 @@ static void usb_hub_handle_control(USBDevice *dev, USBPacket *p, goto fail; } port = &s->ports[n]; - dev = port->port.dev; + pdev = port->port.dev; switch(value) { case PORT_SUSPEND: port->wPortStatus |= PORT_STAT_SUSPEND; @@ -419,8 +419,8 @@ static void usb_hub_handle_control(USBDevice *dev, USBPacket *p, case PORT_RESET: usb_hub_port_set(port, PORT_STAT_RESET); usb_hub_port_clear(port, PORT_STAT_RESET); - if (dev && dev->attached) { - usb_device_reset(dev); + if (pdev && pdev->attached) { + usb_device_reset(pdev); usb_hub_port_set(port, PORT_STAT_ENABLE); } usb_wakeup(s->intr, 0); diff --git a/hw/usb/dev-storage.c b/hw/usb/dev-storage.c index e3bcffb3e0..a496c811a7 100644 --- a/hw/usb/dev-storage.c +++ b/hw/usb/dev-storage.c @@ -403,7 +403,7 @@ static void usb_msd_handle_data(USBDevice *dev, USBPacket *p) struct usb_msd_cbw cbw; uint8_t devep = p->ep->nr; SCSIDevice *scsi_dev; - uint32_t len; + int len; if (s->needs_reset) { p->status = USB_RET_STALL; @@ -465,7 +465,7 @@ static void usb_msd_handle_data(USBDevice *dev, USBPacket *p) usb_msd_copy_data(s, p); } if (le32_to_cpu(s->csw.residue)) { - int len = p->iov.size - p->actual_length; + len = p->iov.size - p->actual_length; if (len) { usb_packet_skip(p, len); if (len > s->data_len) { @@ -526,7 +526,7 @@ static void usb_msd_handle_data(USBDevice *dev, USBPacket *p) usb_msd_copy_data(s, p); } if (le32_to_cpu(s->csw.residue)) { - int len = p->iov.size - p->actual_length; + len = p->iov.size - p->actual_length; if (len) { usb_packet_skip(p, len); if (len > s->data_len) { diff --git a/hw/usb/hcd-xhci.c b/hw/usb/hcd-xhci.c index 324177ad5d..4b60114207 100644 --- a/hw/usb/hcd-xhci.c +++ b/hw/usb/hcd-xhci.c @@ -217,10 +217,10 @@ enum { (((data) >> field##_SHIFT) & field##_MASK) #define set_field(data, newval, field) do { \ - uint32_t val = *data; \ - val &= ~(field##_MASK << field##_SHIFT); \ - val |= ((newval) & field##_MASK) << field##_SHIFT; \ - *data = val; \ + uint32_t val_ = *data; \ + val_ &= ~(field##_MASK << field##_SHIFT); \ + val_ |= ((newval) & field##_MASK) << field##_SHIFT; \ + *data = val_; \ } while (0) typedef enum EPType { @@ -1894,7 +1894,7 @@ static void xhci_kick_epctx(XHCIEPContext *epctx, unsigned int streamid) } if (epctx->retry) { - XHCITransfer *xfer = epctx->retry; + xfer = epctx->retry; trace_usb_xhci_xfer_retry(xfer); assert(xfer->running_retry); diff --git a/hw/usb/host-libusb.c b/hw/usb/host-libusb.c index f500db85ab..d7060a42d5 100644 --- a/hw/usb/host-libusb.c +++ b/hw/usb/host-libusb.c @@ -1010,7 +1010,7 @@ static int usb_host_open(USBHostDevice *s, libusb_device *dev, int hostfd) * Speeds are defined in linux/usb/ch9.h, file not included * due to name conflicts. */ - int rc = ioctl(hostfd, USBDEVFS_GET_SPEED, NULL); + rc = ioctl(hostfd, USBDEVFS_GET_SPEED, NULL); switch (rc) { case 1: /* low */ libusb_speed = LIBUSB_SPEED_LOW; From d5308ea64c1a4608f98b80e83a126515045d0fac Mon Sep 17 00:00:00 2001 From: Laurent Vivier Date: Mon, 25 Sep 2023 17:10:25 +0200 Subject: [PATCH 0374/1077] linux-user/flatload: clean up local variable shadowing Fix following warnings: .../linux-user/flatload.c: In function 'load_flt_binary': .../linux-user/flatload.c:758:23: warning: declaration of 'p' shadows a previous local [-Wshadow=compatible-local] 758 | abi_ulong p; | ^ ../../../Projects/qemu/linux-user/flatload.c:722:15: note: shadowed declaration is here 722 | abi_ulong p; | ^ Signed-off-by: Laurent Vivier Message-ID: <20230925151029.461358-2-laurent@vivier.eu> Reviewed-by: Thomas Huth Signed-off-by: Markus Armbruster --- linux-user/flatload.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/linux-user/flatload.c b/linux-user/flatload.c index 4331a11bf0..fdcc4610fa 100644 --- a/linux-user/flatload.c +++ b/linux-user/flatload.c @@ -755,15 +755,15 @@ int load_flt_binary(struct linux_binprm *bprm, struct image_info *info) /* Update data segment pointers for all libraries */ for (i=0; i Date: Mon, 25 Sep 2023 17:10:26 +0200 Subject: [PATCH 0375/1077] linux-user/mmap.c: clean up local variable shadowing Fix following warnings: .../linux-user/mmap.c: In function 'target_mremap': .../linux-user/mmap.c:913:13: warning: declaration of 'prot' shadows a previous local [-Wshadow=compatible-local] 913 | int prot = 0; | ^~~~ ../../../Projects/qemu/linux-user/mmap.c:871:9: note: shadowed declaration is here 871 | int prot; | ^~~~ Signed-off-by: Laurent Vivier Message-ID: <20230925151029.461358-3-laurent@vivier.eu> Reviewed-by: Thomas Huth Signed-off-by: Markus Armbruster --- linux-user/mmap.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/linux-user/mmap.c b/linux-user/mmap.c index 8eaf57b208..8ccaab7859 100644 --- a/linux-user/mmap.c +++ b/linux-user/mmap.c @@ -910,16 +910,16 @@ abi_long target_mremap(abi_ulong old_addr, abi_ulong old_size, } } } else { - int prot = 0; + int page_flags = 0; if (reserved_va && old_size < new_size) { abi_ulong addr; for (addr = old_addr + old_size; addr < old_addr + new_size; addr++) { - prot |= page_get_flags(addr); + page_flags |= page_get_flags(addr); } } - if (prot == 0) { + if (page_flags == 0) { host_addr = mremap(g2h_untagged(old_addr), old_size, new_size, flags); From eb2929ca50e76b6e6a7152b45a9973472dd1c1aa Mon Sep 17 00:00:00 2001 From: Laurent Vivier Date: Mon, 25 Sep 2023 17:10:27 +0200 Subject: [PATCH 0376/1077] linux-user/syscall.c: clean up local variable shadowing in do_ioctl_dm() Fix following warnings: .../linux-user/syscall.c: In function 'do_ioctl_dm': .../linux-user/syscall.c:5053:23: warning: declaration of 'arg_type' shadows a previous local [-Wshadow=local] 5053 | const argtype arg_type[] = { MK_STRUCT(STRUCT_dm_target_spec) }; | ^~~~~~~~ .../linux-user/syscall.c:4991:20: note: shadowed declaration is here 4991 | const argtype *arg_type = ie->arg_type; | ^~~~~~~~ ...//linux-user/syscall.c:5102:27: warning: declaration of 'arg_type' shadows a previous local [-Wshadow=local] 5102 | const argtype arg_type[] = { MK_STRUCT(STRUCT_dm_name_list) }; | ^~~~~~~~ .../linux-user/syscall.c:4991:20: note: shadowed declaration is here 4991 | const argtype *arg_type = ie->arg_type; | ^~~~~~~~ .../linux-user/syscall.c:5130:27: warning: declaration of 'arg_type' shadows a previous local [-Wshadow=local] 5130 | const argtype arg_type[] = { MK_STRUCT(STRUCT_dm_target_spec) }; | ^~~~~~~~ .../linux-user/syscall.c:4991:20: note: shadowed declaration is here 4991 | const argtype *arg_type = ie->arg_type; | ^~~~~~~~ .../linux-user/syscall.c:5170:27: warning: declaration of 'arg_type' shadows a previous local [-Wshadow=local] 5170 | const argtype arg_type[] = { MK_STRUCT(STRUCT_dm_target_versions) }; | ^~~~~~~~ .../linux-user/syscall.c:4991:20: note: shadowed declaration is here 4991 | const argtype *arg_type = ie->arg_type; | ^~~~~~~~ Signed-off-by: Laurent Vivier Message-ID: <20230925151029.461358-4-laurent@vivier.eu> Reviewed-by: Thomas Huth Signed-off-by: Markus Armbruster --- linux-user/syscall.c | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/linux-user/syscall.c b/linux-user/syscall.c index c6ffadd082..0f1ecc1e0b 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -5050,8 +5050,8 @@ static abi_long do_ioctl_dm(const IOCTLEntry *ie, uint8_t *buf_temp, int fd, { void *gspec = argptr; void *cur_data = host_data; - const argtype arg_type[] = { MK_STRUCT(STRUCT_dm_target_spec) }; - int spec_size = thunk_type_size(arg_type, 0); + const argtype dm_arg_type[] = { MK_STRUCT(STRUCT_dm_target_spec) }; + int spec_size = thunk_type_size(dm_arg_type, 0); int i; for (i = 0; i < host_dm->target_count; i++) { @@ -5059,7 +5059,7 @@ static abi_long do_ioctl_dm(const IOCTLEntry *ie, uint8_t *buf_temp, int fd, uint32_t next; int slen; - thunk_convert(spec, gspec, arg_type, THUNK_HOST); + thunk_convert(spec, gspec, dm_arg_type, THUNK_HOST); slen = strlen((char*)gspec + spec_size) + 1; next = spec->next; spec->next = sizeof(*spec) + slen; @@ -5099,7 +5099,7 @@ static abi_long do_ioctl_dm(const IOCTLEntry *ie, uint8_t *buf_temp, int fd, struct dm_name_list *nl = (void*)host_dm + host_dm->data_start; uint32_t remaining_data = guest_data_size; void *cur_data = argptr; - const argtype arg_type[] = { MK_STRUCT(STRUCT_dm_name_list) }; + const argtype dm_arg_type[] = { MK_STRUCT(STRUCT_dm_name_list) }; int nl_size = 12; /* can't use thunk_size due to alignment */ while (1) { @@ -5111,7 +5111,7 @@ static abi_long do_ioctl_dm(const IOCTLEntry *ie, uint8_t *buf_temp, int fd, host_dm->flags |= DM_BUFFER_FULL_FLAG; break; } - thunk_convert(cur_data, nl, arg_type, THUNK_TARGET); + thunk_convert(cur_data, nl, dm_arg_type, THUNK_TARGET); strcpy(cur_data + nl_size, nl->name); cur_data += nl->next; remaining_data -= nl->next; @@ -5127,8 +5127,8 @@ static abi_long do_ioctl_dm(const IOCTLEntry *ie, uint8_t *buf_temp, int fd, { struct dm_target_spec *spec = (void*)host_dm + host_dm->data_start; void *cur_data = argptr; - const argtype arg_type[] = { MK_STRUCT(STRUCT_dm_target_spec) }; - int spec_size = thunk_type_size(arg_type, 0); + const argtype dm_arg_type[] = { MK_STRUCT(STRUCT_dm_target_spec) }; + int spec_size = thunk_type_size(dm_arg_type, 0); int i; for (i = 0; i < host_dm->target_count; i++) { @@ -5139,7 +5139,7 @@ static abi_long do_ioctl_dm(const IOCTLEntry *ie, uint8_t *buf_temp, int fd, host_dm->flags |= DM_BUFFER_FULL_FLAG; break; } - thunk_convert(cur_data, spec, arg_type, THUNK_TARGET); + thunk_convert(cur_data, spec, dm_arg_type, THUNK_TARGET); strcpy(cur_data + spec_size, (char*)&spec[1]); cur_data = argptr + spec->next; spec = (void*)host_dm + host_dm->data_start + next; @@ -5167,8 +5167,8 @@ static abi_long do_ioctl_dm(const IOCTLEntry *ie, uint8_t *buf_temp, int fd, struct dm_target_versions *vers = (void*)host_dm + host_dm->data_start; uint32_t remaining_data = guest_data_size; void *cur_data = argptr; - const argtype arg_type[] = { MK_STRUCT(STRUCT_dm_target_versions) }; - int vers_size = thunk_type_size(arg_type, 0); + const argtype dm_arg_type[] = { MK_STRUCT(STRUCT_dm_target_versions) }; + int vers_size = thunk_type_size(dm_arg_type, 0); while (1) { uint32_t next = vers->next; @@ -5179,7 +5179,7 @@ static abi_long do_ioctl_dm(const IOCTLEntry *ie, uint8_t *buf_temp, int fd, host_dm->flags |= DM_BUFFER_FULL_FLAG; break; } - thunk_convert(cur_data, vers, arg_type, THUNK_TARGET); + thunk_convert(cur_data, vers, dm_arg_type, THUNK_TARGET); strcpy(cur_data + vers_size, vers->name); cur_data += vers->next; remaining_data -= vers->next; From 9962b7c213e08cbf233eb405b781ecfbb89bfd5c Mon Sep 17 00:00:00 2001 From: Laurent Vivier Date: Mon, 25 Sep 2023 17:10:28 +0200 Subject: [PATCH 0377/1077] linux-user/syscall.c: clean up local variable shadowing in TARGET_NR_getcpu Fix following warnings: .../linux-user/syscall.c: In function 'do_syscall1': .../linux-user/syscall.c:11180:22: warning: declaration of 'cpu' shadows a previous local [-Wshadow=local] 11180 | unsigned cpu, node; | ^~~ .../linux-user/syscall.c:8963:15: note: shadowed declaration is here 8963 | CPUState *cpu = env_cpu(cpu_env); | ^~~ Signed-off-by: Laurent Vivier Message-ID: <20230925151029.461358-5-laurent@vivier.eu> Reviewed-by: Thomas Huth Signed-off-by: Markus Armbruster --- linux-user/syscall.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/linux-user/syscall.c b/linux-user/syscall.c index 0f1ecc1e0b..97a5e9ddf2 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -11177,14 +11177,14 @@ static abi_long do_syscall1(CPUArchState *cpu_env, int num, abi_long arg1, } case TARGET_NR_getcpu: { - unsigned cpu, node; - ret = get_errno(sys_getcpu(arg1 ? &cpu : NULL, + unsigned cpuid, node; + ret = get_errno(sys_getcpu(arg1 ? &cpuid : NULL, arg2 ? &node : NULL, NULL)); if (is_error(ret)) { return ret; } - if (arg1 && put_user_u32(cpu, arg1)) { + if (arg1 && put_user_u32(cpuid, arg1)) { return -TARGET_EFAULT; } if (arg2 && put_user_u32(node, arg2)) { From 77c9f177e02dccd8688eba9550a4fb961742a638 Mon Sep 17 00:00:00 2001 From: Laurent Vivier Date: Mon, 25 Sep 2023 17:10:29 +0200 Subject: [PATCH 0378/1077] linux-user/syscall.c: clean up local variable shadowing in xattr syscalls p is a generic variable in syscall() and can be used by any syscall case, so this patch removes the useless local variable declaration for the following syscalls: TARGET_NR_llistxattr, TARGET_NR_listxattr, TARGET_NR_setxattr, TARGET_NR_lsetxattr, TARGET_NR_getxattr, TARGET_NR_lgetxattr, TARGET_NR_removexattr, TARGET_NR_lremovexattr. Fix following warnings: .../linux-user/syscall.c:12342:15: warning: declaration of 'p' shadows a previous local [-Wshadow=compatible-local] 12342 | void *p, *b = 0; | ^ .../linux-user/syscall.c:8975:11: note: shadowed declaration is here 8975 | void *p; | ^ .../linux-user/syscall.c:12379:19: warning: declaration of 'p' shadows a previous local [-Wshadow=compatible-local] 12379 | void *p, *n, *v = 0; | ^ .../linux-user/syscall.c:8975:11: note: shadowed declaration is here 8975 | void *p; | ^ .../linux-user/syscall.c:12424:19: warning: declaration of 'p' shadows a previous local [-Wshadow=compatible-local] 12424 | void *p, *n, *v = 0; | ^ .../linux-user/syscall.c:8975:11: note: shadowed declaration is here 8975 | void *p; | ^ .../linux-user/syscall.c:12469:19: warning: declaration of 'p' shadows a previous local [-Wshadow=compatible-local] 12469 | void *p, *n; | ^ .../linux-user/syscall.c:8975:11: note: shadowed declaration is here 8975 | void *p; | ^ Signed-off-by: Laurent Vivier Message-ID: <20230925151029.461358-6-laurent@vivier.eu> Reviewed-by: Thomas Huth Signed-off-by: Markus Armbruster --- linux-user/syscall.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/linux-user/syscall.c b/linux-user/syscall.c index 97a5e9ddf2..d49cd314a2 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -12339,7 +12339,7 @@ static abi_long do_syscall1(CPUArchState *cpu_env, int num, abi_long arg1, case TARGET_NR_listxattr: case TARGET_NR_llistxattr: { - void *p, *b = 0; + void *b = 0; if (arg2) { b = lock_user(VERIFY_WRITE, arg2, arg3, 0); if (!b) { @@ -12376,7 +12376,7 @@ static abi_long do_syscall1(CPUArchState *cpu_env, int num, abi_long arg1, case TARGET_NR_setxattr: case TARGET_NR_lsetxattr: { - void *p, *n, *v = 0; + void *n, *v = 0; if (arg3) { v = lock_user(VERIFY_READ, arg3, arg4, 1); if (!v) { @@ -12421,7 +12421,7 @@ static abi_long do_syscall1(CPUArchState *cpu_env, int num, abi_long arg1, case TARGET_NR_getxattr: case TARGET_NR_lgetxattr: { - void *p, *n, *v = 0; + void *n, *v = 0; if (arg3) { v = lock_user(VERIFY_WRITE, arg3, arg4, 0); if (!v) { @@ -12466,7 +12466,7 @@ static abi_long do_syscall1(CPUArchState *cpu_env, int num, abi_long arg1, case TARGET_NR_removexattr: case TARGET_NR_lremovexattr: { - void *p, *n; + void *n; p = lock_user_string(arg1); n = lock_user_string(arg2); if (p && n) { From 6da9447929a88c05bc82a6ead0c967ce1e1e838c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Wed, 4 Oct 2023 11:25:08 +0200 Subject: [PATCH 0379/1077] target/i386/hvf: Remove unused includes in 'hvf-i386.h' MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The only non standard type -- CPUArchState -- is forward declared in "qemu/typedefs.h", so no particular header is required here. Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Roman Bolshakov Tested-by: Roman Bolshakov Message-ID: <20231004092510.39498-2-philmd@linaro.org> Signed-off-by: Paolo Bonzini --- target/i386/hvf/hvf-i386.h | 6 ------ 1 file changed, 6 deletions(-) diff --git a/target/i386/hvf/hvf-i386.h b/target/i386/hvf/hvf-i386.h index 95b47c1c2e..243bc111cc 100644 --- a/target/i386/hvf/hvf-i386.h +++ b/target/i386/hvf/hvf-i386.h @@ -16,12 +16,6 @@ #ifndef HVF_I386_H #define HVF_I386_H -#include "qemu/accel.h" -#include "sysemu/hvf.h" -#include "sysemu/hvf_int.h" -#include "cpu.h" -#include "x86.h" - void hvf_handle_io(CPUArchState *, uint16_t, void *, int, int, int); /* Host specific functions */ From 044431cfe7a9325cc5c22b5feb5a6116d0264e2f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Wed, 4 Oct 2023 11:25:09 +0200 Subject: [PATCH 0380/1077] sysemu/kvm: Restrict hvf_get_supported_cpuid() to x86 targets MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit hvf_get_supported_cpuid() is only defined for x86 targets (in target/i386/hvf/x86_cpuid.c). Its declaration is pointless on all other targets. All the calls to it in target/i386/cpu.c are guarded by a call on hvf_enabled(), so are elided when HVF is not built in. Therefore we can remove the unnecessary function stub. Signed-off-by: Philippe Mathieu-Daudé Message-ID: <20231004092510.39498-3-philmd@linaro.org> Signed-off-by: Paolo Bonzini --- include/sysemu/hvf.h | 3 --- target/i386/cpu.c | 1 + target/i386/hvf/hvf-cpu.c | 1 + target/i386/hvf/hvf-i386.h | 2 ++ target/i386/hvf/x86_cpuid.c | 1 + 5 files changed, 5 insertions(+), 3 deletions(-) diff --git a/include/sysemu/hvf.h b/include/sysemu/hvf.h index 4037cd6a73..4a7c6af3a5 100644 --- a/include/sysemu/hvf.h +++ b/include/sysemu/hvf.h @@ -20,13 +20,10 @@ #include "cpu.h" #ifdef CONFIG_HVF -uint32_t hvf_get_supported_cpuid(uint32_t func, uint32_t idx, - int reg); extern bool hvf_allowed; #define hvf_enabled() (hvf_allowed) #else /* !CONFIG_HVF */ #define hvf_enabled() 0 -#define hvf_get_supported_cpuid(func, idx, reg) 0 #endif /* !CONFIG_HVF */ #endif /* NEED_CPU_H */ diff --git a/target/i386/cpu.c b/target/i386/cpu.c index 9fad31b8db..ac0ae502f5 100644 --- a/target/i386/cpu.c +++ b/target/i386/cpu.c @@ -26,6 +26,7 @@ #include "tcg/helper-tcg.h" #include "sysemu/reset.h" #include "sysemu/hvf.h" +#include "hvf/hvf-i386.h" #include "kvm/kvm_i386.h" #include "sev.h" #include "qapi/error.h" diff --git a/target/i386/hvf/hvf-cpu.c b/target/i386/hvf/hvf-cpu.c index bb0da3947a..ac617f17e7 100644 --- a/target/i386/hvf/hvf-cpu.c +++ b/target/i386/hvf/hvf-cpu.c @@ -15,6 +15,7 @@ #include "hw/boards.h" #include "sysemu/hvf.h" #include "hw/core/accel-cpu.h" +#include "hvf-i386.h" static void hvf_cpu_max_instance_init(X86CPU *cpu) { diff --git a/target/i386/hvf/hvf-i386.h b/target/i386/hvf/hvf-i386.h index 243bc111cc..e99c02cd4b 100644 --- a/target/i386/hvf/hvf-i386.h +++ b/target/i386/hvf/hvf-i386.h @@ -16,6 +16,8 @@ #ifndef HVF_I386_H #define HVF_I386_H +uint32_t hvf_get_supported_cpuid(uint32_t func, uint32_t idx, int reg); + void hvf_handle_io(CPUArchState *, uint16_t, void *, int, int, int); /* Host specific functions */ diff --git a/target/i386/hvf/x86_cpuid.c b/target/i386/hvf/x86_cpuid.c index 7323a7a94b..9380b90496 100644 --- a/target/i386/hvf/x86_cpuid.c +++ b/target/i386/hvf/x86_cpuid.c @@ -25,6 +25,7 @@ #include "x86.h" #include "vmx.h" #include "sysemu/hvf.h" +#include "hvf-i386.h" static bool xgetbv(uint32_t cpuid_ecx, uint32_t idx, uint64_t *xcr) { From f05142d511e86d8e97967d21f205d990dfc634de Mon Sep 17 00:00:00 2001 From: Fiona Ebner Date: Wed, 4 Oct 2023 14:44:46 +0200 Subject: [PATCH 0381/1077] util/log: re-allow switching away from stderr log file Commit 59bde21374 ("util/log: do not close and reopen log files when flags are turned off") prevented switching away from stderr on a subsequent invocation of qemu_set_log_internal(). This prevented switching away from stderr with the 'logfile' monitor command as well as an invocation like > ./qemu-system-x86_64 -trace 'qemu_mutex_lock,file=log' from opening the specified log file. Fixes: 59bde21374 ("util/log: do not close and reopen log files when flags are turned off") Signed-off-by: Fiona Ebner Message-ID: <20231004124446.491481-1-f.ebner@proxmox.com> Signed-off-by: Paolo Bonzini --- util/log.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/util/log.c b/util/log.c index def88a9402..d36c98da0b 100644 --- a/util/log.c +++ b/util/log.c @@ -298,6 +298,8 @@ static bool qemu_set_log_internal(const char *filename, bool changed_name, r->fd = logfile; qatomic_rcu_set(&global_file, NULL); call_rcu(r, rcu_close_file, rcu); + } + if (changed_name) { logfile = NULL; } } From 1da389c5dba3efca5de6b983cf788054880de432 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Wed, 4 Oct 2023 10:22:39 +0200 Subject: [PATCH 0382/1077] target/i386: Check for USER_ONLY definition instead of SOFTMMU one MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Since we *might* have user emulation with softmmu, replace the system emulation check by !user emulation one. (target/ was cleaned from invalid CONFIG_SOFTMMU uses at commit cab35c73be, but these files were merged few days after, thus missed the cleanup.) Signed-off-by: Philippe Mathieu-Daudé Message-ID: <20231004082239.27251-1-philmd@linaro.org> Signed-off-by: Paolo Bonzini --- target/i386/cpu.c | 2 +- target/i386/tcg/misc_helper.c | 2 +- target/i386/tcg/translate.c | 6 +++--- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/target/i386/cpu.c b/target/i386/cpu.c index ac0ae502f5..cec5d2b7b6 100644 --- a/target/i386/cpu.c +++ b/target/i386/cpu.c @@ -719,7 +719,7 @@ void x86_cpu_vendor_words2str(char *dst, uint32_t vendor1, CPUID_7_0_EBX_HLE CPUID_7_0_EBX_INVPCID, CPUID_7_0_EBX_RTM */ -#if defined CONFIG_SOFTMMU || defined CONFIG_LINUX +#if !defined CONFIG_USER_ONLY || defined CONFIG_LINUX #define TCG_7_0_ECX_RDPID CPUID_7_0_ECX_RDPID #else #define TCG_7_0_ECX_RDPID 0 diff --git a/target/i386/tcg/misc_helper.c b/target/i386/tcg/misc_helper.c index 868f36ab7f..babff06186 100644 --- a/target/i386/tcg/misc_helper.c +++ b/target/i386/tcg/misc_helper.c @@ -134,7 +134,7 @@ void helper_wrpkru(CPUX86State *env, uint32_t ecx, uint64_t val) target_ulong HELPER(rdpid)(CPUX86State *env) { -#if defined CONFIG_SOFTMMU +#if !defined CONFIG_USER_ONLY return env->tsc_aux; #elif defined CONFIG_LINUX && defined CONFIG_GETCPU unsigned cpu, node; diff --git a/target/i386/tcg/translate.c b/target/i386/tcg/translate.c index 4f1287311d..d2061ec44a 100644 --- a/target/i386/tcg/translate.c +++ b/target/i386/tcg/translate.c @@ -178,10 +178,10 @@ typedef struct DisasContext { #else #define CODE64(S) (((S)->flags & HF_CS64_MASK) != 0) #endif -#if defined(CONFIG_SOFTMMU) && !defined(TARGET_X86_64) -#define LMA(S) false -#else +#if defined(CONFIG_USER_ONLY) || defined(TARGET_X86_64) #define LMA(S) (((S)->flags & HF_LMA_MASK) != 0) +#else +#define LMA(S) false #endif #ifdef TARGET_X86_64 From fc78f56e2546bcf354193d9a380618067c15264b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Wed, 4 Oct 2023 11:06:16 +0200 Subject: [PATCH 0383/1077] softmmu/trace-events: Fix a typo MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Commit 8af3f5c6d6 ("softmmu: add trace point when bdrv_flush_all fails") added calls to trace_vm_stop_flush_all() in 'cpus.c'. Signed-off-by: Philippe Mathieu-Daudé Message-ID: <20231004090629.37473-2-philmd@linaro.org> Signed-off-by: Paolo Bonzini --- softmmu/trace-events | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/softmmu/trace-events b/softmmu/trace-events index 22606dc27b..69c9044151 100644 --- a/softmmu/trace-events +++ b/softmmu/trace-events @@ -21,7 +21,7 @@ flatview_destroy(void *view, void *root) "%p (root %p)" flatview_destroy_rcu(void *view, void *root) "%p (root %p)" global_dirty_changed(unsigned int bitmask) "bitmask 0x%"PRIx32 -# softmmu.c +# cpus.c vm_stop_flush_all(int ret) "ret %d" # vl.c From 27703590316efc1be5ff1ad8f209d9c5e2f8304b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Wed, 4 Oct 2023 11:06:17 +0200 Subject: [PATCH 0384/1077] travis-ci: Correct invalid mentions of 'softmmu' by 'system' MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Philippe Mathieu-Daudé Message-ID: <20231004090629.37473-3-philmd@linaro.org> Signed-off-by: Paolo Bonzini --- .travis.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index b958eca5de..76859d48da 100644 --- a/.travis.yml +++ b/.travis.yml @@ -34,7 +34,7 @@ env: - BASE_CONFIG="--disable-docs --disable-tools" - TEST_BUILD_CMD="" - TEST_CMD="make check V=1" - # This is broadly a list of "mainline" softmmu targets which have support across the major distros + # This is broadly a list of "mainline" system targets which have support across the major distros - MAIN_SOFTMMU_TARGETS="aarch64-softmmu,mips64-softmmu,ppc64-softmmu,riscv64-softmmu,s390x-softmmu,x86_64-softmmu" - CCACHE_SLOPPINESS="include_file_ctime,include_file_mtime" - CCACHE_MAXSIZE=1G @@ -197,7 +197,7 @@ jobs: $(exit $BUILD_RC); fi - - name: "[s390x] GCC (other-softmmu)" + - name: "[s390x] GCC (other-system)" arch: s390x dist: focal addons: From 54b99122eb01eb78e2933da4c476d166e846d572 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Wed, 4 Oct 2023 11:06:18 +0200 Subject: [PATCH 0385/1077] cpu: Correct invalid mentions of 'softmmu' by 'system-mode' MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Philippe Mathieu-Daudé Message-ID: <20231004090629.37473-4-philmd@linaro.org> Signed-off-by: Paolo Bonzini --- cpu-target.c | 2 +- hw/core/cpu-common.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/cpu-target.c b/cpu-target.c index 658d179582..79363ae370 100644 --- a/cpu-target.c +++ b/cpu-target.c @@ -202,7 +202,7 @@ static Property cpu_common_props[] = { prctl_unalign_sigbus, false), #else /* - * Create a memory property for softmmu CPU object, so users can + * Create a memory property for system CPU object, so users can * wire up its memory. The default if no link is set up is to use * the system address space. */ diff --git a/hw/core/cpu-common.c b/hw/core/cpu-common.c index 4d406995ab..bab8942c30 100644 --- a/hw/core/cpu-common.c +++ b/hw/core/cpu-common.c @@ -228,8 +228,8 @@ static void cpu_common_initfn(Object *obj) cpu->cpu_index = UNASSIGNED_CPU_INDEX; cpu->cluster_index = UNASSIGNED_CLUSTER_INDEX; cpu->gdb_num_regs = cpu->gdb_num_g_regs = cc->gdb_num_core_regs; - /* *-user doesn't have configurable SMP topology */ - /* the default value is changed by qemu_init_vcpu() for softmmu */ + /* user-mode doesn't have configurable SMP topology */ + /* the default value is changed by qemu_init_vcpu() for system-mode */ cpu->nr_cores = 1; cpu->nr_threads = 1; cpu->cflags_next_tb = -1; From c2646d49588d834c2bcc050539053074ac43d4ba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Wed, 4 Oct 2023 11:06:19 +0200 Subject: [PATCH 0386/1077] fuzz: Correct invalid mentions of 'softmmu' by 'system' MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Alexander Bulekov Message-ID: <20231004090629.37473-5-philmd@linaro.org> Signed-off-by: Paolo Bonzini --- softmmu/memory.c | 2 +- tests/qtest/fuzz/fuzz.c | 2 +- tests/qtest/fuzz/fuzz.h | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/softmmu/memory.c b/softmmu/memory.c index 234bd7b116..fa1c99f9ba 100644 --- a/softmmu/memory.c +++ b/softmmu/memory.c @@ -3638,7 +3638,7 @@ void memory_region_init_rom_device(MemoryRegion *mr, } /* - * Support softmmu builds with CONFIG_FUZZ using a weak symbol and a stub for + * Support system builds with CONFIG_FUZZ using a weak symbol and a stub for * the fuzz_dma_read_cb callback */ #ifdef CONFIG_FUZZ diff --git a/tests/qtest/fuzz/fuzz.c b/tests/qtest/fuzz/fuzz.c index 3bedb81b32..9b9c9f9c36 100644 --- a/tests/qtest/fuzz/fuzz.c +++ b/tests/qtest/fuzz/fuzz.c @@ -207,7 +207,7 @@ int LLVMFuzzerInitialize(int *argc, char ***argv, char ***envp) fuzz_target->pre_vm_init(); } - /* Run QEMU's softmmu main with the fuzz-target dependent arguments */ + /* Run QEMU's system main with the fuzz-target dependent arguments */ cmd_line = fuzz_target->get_init_cmdline(fuzz_target); g_string_append_printf(cmd_line, " %s -qtest /dev/null ", getenv("QTEST_LOG") ? "" : "-qtest-log none"); diff --git a/tests/qtest/fuzz/fuzz.h b/tests/qtest/fuzz/fuzz.h index 21d1362d65..7da0bc3d7e 100644 --- a/tests/qtest/fuzz/fuzz.h +++ b/tests/qtest/fuzz/fuzz.h @@ -49,13 +49,13 @@ typedef struct FuzzTarget { /* - * Returns the arguments that are passed to qemu/softmmu init(). Freed by + * Returns the arguments that are passed to qemu/system init(). Freed by * the caller. */ GString *(*get_init_cmdline)(struct FuzzTarget *); /* - * will run once, prior to running qemu/softmmu init. + * will run once, prior to running qemu/system init. * eg: set up shared-memory for communication with the child-process * Can be NULL */ From 7893e42d5d9cafeeab30a114e8ec86517f8a1b36 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Wed, 4 Oct 2023 11:06:20 +0200 Subject: [PATCH 0387/1077] tcg: Correct invalid mentions of 'softmmu' by 'system-mode' MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Philippe Mathieu-Daudé Message-ID: <20231004090629.37473-6-philmd@linaro.org> Signed-off-by: Paolo Bonzini --- accel/tcg/user-exec.c | 2 +- docs/devel/testing.rst | 2 +- include/qemu/atomic128.h | 4 ++-- include/tcg/tcg-op-common.h | 2 +- target/riscv/vector_helper.c | 2 +- tcg/aarch64/tcg-target.c.inc | 4 ++-- tcg/arm/tcg-target.c.inc | 2 +- tcg/i386/tcg-target.c.inc | 2 +- tcg/loongarch64/tcg-target.c.inc | 4 ++-- tcg/meson.build | 6 +++--- tcg/mips/tcg-target.c.inc | 4 ++-- tcg/ppc/tcg-target.c.inc | 4 ++-- tcg/region.c | 4 ++-- tcg/riscv/tcg-target.c.inc | 4 ++-- tcg/s390x/tcg-target.c.inc | 4 ++-- tcg/sparc64/tcg-target.c.inc | 4 ++-- tcg/tcg.c | 11 ++++++----- tests/tcg/Makefile.target | 2 +- tests/tcg/multiarch/gdbstub/interrupt.py | 2 +- tests/tcg/multiarch/gdbstub/memory.py | 2 +- tests/tcg/multiarch/system/memory.c | 4 ++-- tests/tcg/s390x/pgm-specification-softmmu.S | 2 +- tests/tcg/s390x/pgm-specification.mak | 2 +- tests/tcg/s390x/softmmu.ld | 2 +- tests/tcg/xtensa/Makefile.softmmu-target | 2 +- tests/tcg/xtensaeb/Makefile.softmmu-target | 2 +- 26 files changed, 43 insertions(+), 42 deletions(-) diff --git a/accel/tcg/user-exec.c b/accel/tcg/user-exec.c index 5bf2761bf4..68b252cb8e 100644 --- a/accel/tcg/user-exec.c +++ b/accel/tcg/user-exec.c @@ -940,7 +940,7 @@ void *page_get_target_data(target_ulong address) void page_reset_target_data(target_ulong start, target_ulong last) { } #endif /* TARGET_PAGE_DATA_SIZE */ -/* The softmmu versions of these helpers are in cputlb.c. */ +/* The system-mode versions of these helpers are in cputlb.c. */ static void *cpu_mmu_lookup(CPUState *cpu, vaddr addr, MemOp mop, uintptr_t ra, MMUAccessType type) diff --git a/docs/devel/testing.rst b/docs/devel/testing.rst index 5d1fc0aa95..f3e2472189 100644 --- a/docs/devel/testing.rst +++ b/docs/devel/testing.rst @@ -1458,7 +1458,7 @@ TCG test dependencies ~~~~~~~~~~~~~~~~~~~~~ The TCG tests are deliberately very light on dependencies and are -either totally bare with minimal gcc lib support (for softmmu tests) +either totally bare with minimal gcc lib support (for system-mode tests) or just glibc (for linux-user tests). This is because getting a cross compiler to work with additional libraries can be challenging. diff --git a/include/qemu/atomic128.h b/include/qemu/atomic128.h index 34554bf0ac..88af6d4ea3 100644 --- a/include/qemu/atomic128.h +++ b/include/qemu/atomic128.h @@ -43,8 +43,8 @@ * See https://gcc.gnu.org/bugzilla/show_bug.cgi?id=80878 * * This interpretation is not especially helpful for QEMU. - * For softmmu, all RAM is always read/write from the hypervisor. - * For user-only, if the guest doesn't implement such an __atomic_read + * For system-mode, all RAM is always read/write from the hypervisor. + * For user-mode, if the guest doesn't implement such an __atomic_read * then the host need not worry about it either. * * Moreover, using libatomic is not an option, because its interface is diff --git a/include/tcg/tcg-op-common.h b/include/tcg/tcg-op-common.h index a53b15933b..2048f92b5e 100644 --- a/include/tcg/tcg-op-common.h +++ b/include/tcg/tcg-op-common.h @@ -265,7 +265,7 @@ void tcg_gen_exit_tb(const TranslationBlock *tb, unsigned idx); * * See tcg/README for more info about this TCG operation. * - * NOTE: In softmmu emulation, direct jumps with goto_tb are only safe within + * NOTE: In system emulation, direct jumps with goto_tb are only safe within * the pages this TB resides in because we don't take care of direct jumps when * address mapping changes, e.g. in tlb_flush(). In user mode, there's only a * static address translation, so the destination address is always valid, TBs diff --git a/target/riscv/vector_helper.c b/target/riscv/vector_helper.c index cba02c1320..c9b39fb67f 100644 --- a/target/riscv/vector_helper.c +++ b/target/riscv/vector_helper.c @@ -100,7 +100,7 @@ static inline target_ulong adjust_addr(CPURISCVState *env, target_ulong addr) /* * This function checks watchpoint before real load operation. * - * In softmmu mode, the TLB API probe_access is enough for watchpoint check. + * In system mode, the TLB API probe_access is enough for watchpoint check. * In user mode, there is no watchpoint support now. * * It will trigger an exception if there is no mapping in TLB diff --git a/tcg/aarch64/tcg-target.c.inc b/tcg/aarch64/tcg-target.c.inc index 69f2daf2c2..3afb896a3a 100644 --- a/tcg/aarch64/tcg-target.c.inc +++ b/tcg/aarch64/tcg-target.c.inc @@ -1643,8 +1643,8 @@ static bool tcg_out_qemu_st_slow_path(TCGContext *s, TCGLabelQemuLdst *lb) #define MIN_TLB_MASK_TABLE_OFS -512 /* - * For softmmu, perform the TLB load and compare. - * For useronly, perform any required alignment tests. + * For system-mode, perform the TLB load and compare. + * For user-mode, perform any required alignment tests. * In both cases, return a TCGLabelQemuLdst structure if the slow path * is required and fill in @h with the host address for the fast path. */ diff --git a/tcg/arm/tcg-target.c.inc b/tcg/arm/tcg-target.c.inc index a2f60106af..0d9c2d157b 100644 --- a/tcg/arm/tcg-target.c.inc +++ b/tcg/arm/tcg-target.c.inc @@ -353,7 +353,7 @@ static bool patch_reloc(tcg_insn_unit *code_ptr, int type, #define ALL_VECTOR_REGS 0xffff0000u /* - * r0-r3 will be overwritten when reading the tlb entry (softmmu only); + * r0-r3 will be overwritten when reading the tlb entry (system-mode only); * r14 will be overwritten by the BLNE branching to the slow path. */ #ifdef CONFIG_SOFTMMU diff --git a/tcg/i386/tcg-target.c.inc b/tcg/i386/tcg-target.c.inc index 4e47151241..788d608150 100644 --- a/tcg/i386/tcg-target.c.inc +++ b/tcg/i386/tcg-target.c.inc @@ -2276,7 +2276,7 @@ static void tcg_out_qemu_st_direct(TCGContext *s, TCGReg datalo, TCGReg datahi, int movop = OPC_MOVL_EvGv; /* - * Do big-endian stores with movbe or softmmu. + * Do big-endian stores with movbe or system-mode. * User-only without movbe will have its swapping done generically. */ if (memop & MO_BSWAP) { diff --git a/tcg/loongarch64/tcg-target.c.inc b/tcg/loongarch64/tcg-target.c.inc index 8f7091002b..801302d85d 100644 --- a/tcg/loongarch64/tcg-target.c.inc +++ b/tcg/loongarch64/tcg-target.c.inc @@ -891,8 +891,8 @@ bool tcg_target_has_memory_bswap(MemOp memop) #define MIN_TLB_MASK_TABLE_OFS -(1 << 11) /* - * For softmmu, perform the TLB load and compare. - * For useronly, perform any required alignment tests. + * For system-mode, perform the TLB load and compare. + * For user-mode, perform any required alignment tests. * In both cases, return a TCGLabelQemuLdst structure if the slow path * is required and fill in @h with the host address for the fast path. */ diff --git a/tcg/meson.build b/tcg/meson.build index 4be4a616ca..895a11d3fa 100644 --- a/tcg/meson.build +++ b/tcg/meson.build @@ -34,12 +34,12 @@ tcg_user = declare_dependency(link_with: libtcg_user, dependencies: tcg_ss.dependencies()) user_ss.add(tcg_user) -libtcg_softmmu = static_library('tcg_softmmu', +libtcg_system = static_library('tcg_system', tcg_ss.sources() + genh, name_suffix: 'fa', c_args: '-DCONFIG_SOFTMMU', build_by_default: false) -tcg_softmmu = declare_dependency(link_with: libtcg_softmmu, +tcg_system = declare_dependency(link_with: libtcg_system, dependencies: tcg_ss.dependencies()) -system_ss.add(tcg_softmmu) +system_ss.add(tcg_system) diff --git a/tcg/mips/tcg-target.c.inc b/tcg/mips/tcg-target.c.inc index f52bda4828..e2892edc6a 100644 --- a/tcg/mips/tcg-target.c.inc +++ b/tcg/mips/tcg-target.c.inc @@ -1258,8 +1258,8 @@ bool tcg_target_has_memory_bswap(MemOp memop) #define MIN_TLB_MASK_TABLE_OFS -32768 /* - * For softmmu, perform the TLB load and compare. - * For useronly, perform any required alignment tests. + * For system-mode, perform the TLB load and compare. + * For user-mode, perform any required alignment tests. * In both cases, return a TCGLabelQemuLdst structure if the slow path * is required and fill in @h with the host address for the fast path. */ diff --git a/tcg/ppc/tcg-target.c.inc b/tcg/ppc/tcg-target.c.inc index 90d76c2c2c..5c873b2161 100644 --- a/tcg/ppc/tcg-target.c.inc +++ b/tcg/ppc/tcg-target.c.inc @@ -2091,8 +2091,8 @@ bool tcg_target_has_memory_bswap(MemOp memop) #define MIN_TLB_MASK_TABLE_OFS -32768 /* - * For softmmu, perform the TLB load and compare. - * For useronly, perform any required alignment tests. + * For system-mode, perform the TLB load and compare. + * For user-mode, perform any required alignment tests. * In both cases, return a TCGLabelQemuLdst structure if the slow path * is required and fill in @h with the host address for the fast path. */ diff --git a/tcg/region.c b/tcg/region.c index a078899096..86692455c0 100644 --- a/tcg/region.c +++ b/tcg/region.c @@ -733,7 +733,7 @@ static int alloc_code_gen_buffer(size_t size, int splitwx, Error **errp) * and then assigning regions to TCG threads so that the threads can translate * code in parallel without synchronization. * - * In softmmu the number of TCG threads is bounded by max_cpus, so we use at + * In system-mode the number of TCG threads is bounded by max_cpus, so we use at * least max_cpus regions in MTTCG. In !MTTCG we use a single region. * Note that the TCG options from the command-line (i.e. -accel accel=tcg,[...]) * must have been parsed before calling this function, since it calls @@ -749,7 +749,7 @@ static int alloc_code_gen_buffer(size_t size, int splitwx, Error **errp) * * However, this user-mode limitation is unlikely to be a significant problem * in practice. Multi-threaded guests share most if not all of their translated - * code, which makes parallel code generation less appealing than in softmmu. + * code, which makes parallel code generation less appealing than in system-mode */ void tcg_region_init(size_t tb_size, int splitwx, unsigned max_cpus) { diff --git a/tcg/riscv/tcg-target.c.inc b/tcg/riscv/tcg-target.c.inc index c2bcdea33f..d6dbcaf3cb 100644 --- a/tcg/riscv/tcg-target.c.inc +++ b/tcg/riscv/tcg-target.c.inc @@ -1227,8 +1227,8 @@ static bool tcg_out_qemu_st_slow_path(TCGContext *s, TCGLabelQemuLdst *l) #define MIN_TLB_MASK_TABLE_OFS -(1 << 11) /* - * For softmmu, perform the TLB load and compare. - * For useronly, perform any required alignment tests. + * For system-mode, perform the TLB load and compare. + * For user-mode, perform any required alignment tests. * In both cases, return a TCGLabelQemuLdst structure if the slow path * is required and fill in @h with the host address for the fast path. */ diff --git a/tcg/s390x/tcg-target.c.inc b/tcg/s390x/tcg-target.c.inc index 7552f63a05..4ef9ac3d5b 100644 --- a/tcg/s390x/tcg-target.c.inc +++ b/tcg/s390x/tcg-target.c.inc @@ -1750,8 +1750,8 @@ static bool tcg_out_qemu_st_slow_path(TCGContext *s, TCGLabelQemuLdst *lb) #define MIN_TLB_MASK_TABLE_OFS -(1 << 19) /* - * For softmmu, perform the TLB load and compare. - * For useronly, perform any required alignment tests. + * For system-mode, perform the TLB load and compare. + * For user-mode, perform any required alignment tests. * In both cases, return a TCGLabelQemuLdst structure if the slow path * is required and fill in @h with the host address for the fast path. */ diff --git a/tcg/sparc64/tcg-target.c.inc b/tcg/sparc64/tcg-target.c.inc index 01ac26c192..19d9df4a09 100644 --- a/tcg/sparc64/tcg-target.c.inc +++ b/tcg/sparc64/tcg-target.c.inc @@ -1033,8 +1033,8 @@ bool tcg_target_has_memory_bswap(MemOp memop) #define MIN_TLB_MASK_TABLE_OFS -(1 << 12) /* - * For softmmu, perform the TLB load and compare. - * For useronly, perform any required alignment tests. + * For system-mode, perform the TLB load and compare. + * For user-mode, perform any required alignment tests. * In both cases, return a TCGLabelQemuLdst structure if the slow path * is required and fill in @h with the host address for the fast path. */ diff --git a/tcg/tcg.c b/tcg/tcg.c index f664cf1484..637b9e6870 100644 --- a/tcg/tcg.c +++ b/tcg/tcg.c @@ -760,12 +760,13 @@ static void alloc_tcg_plugin_context(TCGContext *s) * In user-mode we just point tcg_ctx to tcg_init_ctx. See the documentation * of tcg_region_init() for the reasoning behind this. * - * In softmmu each caller registers its context in tcg_ctxs[]. Note that in - * softmmu tcg_ctxs[] does not track tcg_ctx_init, since the initial context + * In system-mode each caller registers its context in tcg_ctxs[]. Note that in + * system-mode tcg_ctxs[] does not track tcg_ctx_init, since the initial context * is not used anymore for translation once this function is called. * - * Not tracking tcg_init_ctx in tcg_ctxs[] in softmmu keeps code that iterates - * over the array (e.g. tcg_code_size() the same for both softmmu and user-mode. + * Not tracking tcg_init_ctx in tcg_ctxs[] in system-mode keeps code that + * iterates over the array (e.g. tcg_code_size() the same for both system/user + * modes. */ #ifdef CONFIG_USER_ONLY void tcg_register_thread(void) @@ -1349,7 +1350,7 @@ static void tcg_context_init(unsigned max_cpus) * In user-mode we simply share the init context among threads, since we * use a single region. See the documentation tcg_region_init() for the * reasoning behind this. - * In softmmu we will have at most max_cpus TCG threads. + * In system-mode we will have at most max_cpus TCG threads. */ #ifdef CONFIG_USER_ONLY tcg_ctxs = &tcg_ctx; diff --git a/tests/tcg/Makefile.target b/tests/tcg/Makefile.target index 462289f47c..f3a189c9d4 100644 --- a/tests/tcg/Makefile.target +++ b/tests/tcg/Makefile.target @@ -120,7 +120,7 @@ endif %: %.S $(CC) $(CFLAGS) $(EXTRA_CFLAGS) $< -o $@ $(LDFLAGS) else -# For softmmu targets we include a different Makefile fragment as the +# For system targets we include a different Makefile fragment as the # build options for bare programs are usually pretty different. They # are expected to provide their own build recipes. EXTRA_CFLAGS += -ffreestanding diff --git a/tests/tcg/multiarch/gdbstub/interrupt.py b/tests/tcg/multiarch/gdbstub/interrupt.py index e222ac94c5..c016e7afbb 100644 --- a/tests/tcg/multiarch/gdbstub/interrupt.py +++ b/tests/tcg/multiarch/gdbstub/interrupt.py @@ -1,6 +1,6 @@ from __future__ import print_function # -# Test some of the softmmu debug features with the multiarch memory +# Test some of the system debug features with the multiarch memory # test. It is a port of the original vmlinux focused test case but # using the "memory" test instead. # diff --git a/tests/tcg/multiarch/gdbstub/memory.py b/tests/tcg/multiarch/gdbstub/memory.py index dd25e72281..fb1d06b7bb 100644 --- a/tests/tcg/multiarch/gdbstub/memory.py +++ b/tests/tcg/multiarch/gdbstub/memory.py @@ -1,6 +1,6 @@ from __future__ import print_function # -# Test some of the softmmu debug features with the multiarch memory +# Test some of the system debug features with the multiarch memory # test. It is a port of the original vmlinux focused test case but # using the "memory" test instead. # diff --git a/tests/tcg/multiarch/system/memory.c b/tests/tcg/multiarch/system/memory.c index e29786ae55..6eb2eb16f7 100644 --- a/tests/tcg/multiarch/system/memory.c +++ b/tests/tcg/multiarch/system/memory.c @@ -1,14 +1,14 @@ /* * Memory Test * - * This is intended to test the softmmu code and ensure we properly + * This is intended to test the system-mode code and ensure we properly * behave across normal and unaligned accesses across several pages. * We are not replicating memory tests for stuck bits and other * hardware level failures but looking for issues with different size * accesses when access is: * * - unaligned at various sizes (if -DCHECK_UNALIGNED set) - * - spanning a (softmmu) page + * - spanning a (system) page * - sign extension when loading */ diff --git a/tests/tcg/s390x/pgm-specification-softmmu.S b/tests/tcg/s390x/pgm-specification-softmmu.S index d534f4e505..86c340aeef 100644 --- a/tests/tcg/s390x/pgm-specification-softmmu.S +++ b/tests/tcg/s390x/pgm-specification-softmmu.S @@ -1,5 +1,5 @@ /* - * Common softmmu code for specification exception testing. + * Common system code for specification exception testing. * * SPDX-License-Identifier: GPL-2.0-or-later */ diff --git a/tests/tcg/s390x/pgm-specification.mak b/tests/tcg/s390x/pgm-specification.mak index 2999aee26e..73dc47af0d 100644 --- a/tests/tcg/s390x/pgm-specification.mak +++ b/tests/tcg/s390x/pgm-specification.mak @@ -1,6 +1,6 @@ # SPDX-License-Identifier: GPL-2.0-or-later # List of specification exception tests. -# Shared between the softmmu and the user makefiles. +# Shared between the system and the user makefiles. PGM_SPECIFICATION_TESTS = \ br-odd \ cgrl-unaligned \ diff --git a/tests/tcg/s390x/softmmu.ld b/tests/tcg/s390x/softmmu.ld index ea944eaa3c..c7a8864407 100644 --- a/tests/tcg/s390x/softmmu.ld +++ b/tests/tcg/s390x/softmmu.ld @@ -1,5 +1,5 @@ /* - * Linker script for the softmmu test kernels. + * Linker script for the system test kernels. * * SPDX-License-Identifier: GPL-2.0-or-later */ diff --git a/tests/tcg/xtensa/Makefile.softmmu-target b/tests/tcg/xtensa/Makefile.softmmu-target index 78bf72dfaa..a29571b367 100644 --- a/tests/tcg/xtensa/Makefile.softmmu-target +++ b/tests/tcg/xtensa/Makefile.softmmu-target @@ -1,5 +1,5 @@ # -# Xtensa softmmu tests +# Xtensa system tests # CORE=dc232b diff --git a/tests/tcg/xtensaeb/Makefile.softmmu-target b/tests/tcg/xtensaeb/Makefile.softmmu-target index 4204a96d53..95d0528c37 100644 --- a/tests/tcg/xtensaeb/Makefile.softmmu-target +++ b/tests/tcg/xtensaeb/Makefile.softmmu-target @@ -1,5 +1,5 @@ # -# Xtensa softmmu tests +# Xtensa system tests # include $(SRC_PATH)/tests/tcg/xtensa/Makefile.softmmu-target From 0017c64e1ce298796caee2d38bde9d7fc59a1510 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Wed, 4 Oct 2023 11:06:21 +0200 Subject: [PATCH 0388/1077] accel: Rename accel_softmmu* -> accel_system* MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Rename accel.softmmu -> accel.system in file paths and the register_types() method. Rename sysemu_stubs_ss -> system_stubs_ss in meson following the pattern used on other source set names. Signed-off-by: Philippe Mathieu-Daudé Message-ID: <20231004090629.37473-7-philmd@linaro.org> Signed-off-by: Paolo Bonzini --- accel/{accel-softmmu.c => accel-system.c} | 6 +++--- accel/{accel-softmmu.h => accel-system.h} | 6 +++--- accel/accel-target.c | 2 +- accel/meson.build | 2 +- accel/stubs/meson.build | 10 +++++----- 5 files changed, 13 insertions(+), 13 deletions(-) rename accel/{accel-softmmu.c => accel-system.c} (96%) rename accel/{accel-softmmu.h => accel-system.h} (77%) diff --git a/accel/accel-softmmu.c b/accel/accel-system.c similarity index 96% rename from accel/accel-softmmu.c rename to accel/accel-system.c index 9c804ba9e3..fa8f43757c 100644 --- a/accel/accel-softmmu.c +++ b/accel/accel-system.c @@ -28,7 +28,7 @@ #include "hw/boards.h" #include "sysemu/cpus.h" #include "qemu/error-report.h" -#include "accel-softmmu.h" +#include "accel-system.h" int accel_init_machine(AccelState *accel, MachineState *ms) { @@ -99,8 +99,8 @@ static const TypeInfo accel_ops_type_info = { .class_size = sizeof(AccelOpsClass), }; -static void accel_softmmu_register_types(void) +static void accel_system_register_types(void) { type_register_static(&accel_ops_type_info); } -type_init(accel_softmmu_register_types); +type_init(accel_system_register_types); diff --git a/accel/accel-softmmu.h b/accel/accel-system.h similarity index 77% rename from accel/accel-softmmu.h rename to accel/accel-system.h index 5e192f1882..d41c62f21b 100644 --- a/accel/accel-softmmu.h +++ b/accel/accel-system.h @@ -7,9 +7,9 @@ * See the COPYING file in the top-level directory. */ -#ifndef ACCEL_SOFTMMU_H -#define ACCEL_SOFTMMU_H +#ifndef ACCEL_SYSTEM_H +#define ACCEL_SYSTEM_H void accel_init_ops_interfaces(AccelClass *ac); -#endif /* ACCEL_SOFTMMU_H */ +#endif /* ACCEL_SYSTEM_H */ diff --git a/accel/accel-target.c b/accel/accel-target.c index 11d74b4ad7..7e3cbde5df 100644 --- a/accel/accel-target.c +++ b/accel/accel-target.c @@ -30,7 +30,7 @@ #include "hw/core/accel-cpu.h" #ifndef CONFIG_USER_ONLY -#include "accel-softmmu.h" +#include "accel-system.h" #endif /* !CONFIG_USER_ONLY */ static const TypeInfo accel_type = { diff --git a/accel/meson.build b/accel/meson.build index fda3157a6e..5eaeb68338 100644 --- a/accel/meson.build +++ b/accel/meson.build @@ -1,5 +1,5 @@ specific_ss.add(files('accel-target.c')) -system_ss.add(files('accel-softmmu.c', 'accel-blocker.c')) +system_ss.add(files('accel-system.c', 'accel-blocker.c')) user_ss.add(files('accel-user.c')) subdir('tcg') diff --git a/accel/stubs/meson.build b/accel/stubs/meson.build index 6b0f200efe..91a2d21925 100644 --- a/accel/stubs/meson.build +++ b/accel/stubs/meson.build @@ -1,6 +1,6 @@ -sysemu_stubs_ss = ss.source_set() -sysemu_stubs_ss.add(when: 'CONFIG_XEN', if_false: files('xen-stub.c')) -sysemu_stubs_ss.add(when: 'CONFIG_KVM', if_false: files('kvm-stub.c')) -sysemu_stubs_ss.add(when: 'CONFIG_TCG', if_false: files('tcg-stub.c')) +system_stubs_ss = ss.source_set() +system_stubs_ss.add(when: 'CONFIG_XEN', if_false: files('xen-stub.c')) +system_stubs_ss.add(when: 'CONFIG_KVM', if_false: files('kvm-stub.c')) +system_stubs_ss.add(when: 'CONFIG_TCG', if_false: files('tcg-stub.c')) -specific_ss.add_all(when: ['CONFIG_SYSTEM_ONLY'], if_true: sysemu_stubs_ss) +specific_ss.add_all(when: ['CONFIG_SYSTEM_ONLY'], if_true: system_stubs_ss) From 3f7d1bdab0e98190245394875acf0d6d04b5de5b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Wed, 4 Oct 2023 11:06:22 +0200 Subject: [PATCH 0389/1077] gdbstub: Rename 'softmmu' -> 'system' MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We have gdbstub/user.c for user emulation code, use gdbstub/system.c for system emulation part. Rename s/softmmu/system/ in meson and few comments. Signed-off-by: Philippe Mathieu-Daudé Message-ID: <20231004090629.37473-8-philmd@linaro.org> Signed-off-by: Paolo Bonzini --- gdbstub/internals.h | 4 ++-- gdbstub/meson.build | 10 +++++----- gdbstub/{softmmu.c => system.c} | 2 +- gdbstub/trace-events | 2 +- 4 files changed, 9 insertions(+), 9 deletions(-) rename gdbstub/{softmmu.c => system.c} (99%) diff --git a/gdbstub/internals.h b/gdbstub/internals.h index fee243081f..f7fd1bede5 100644 --- a/gdbstub/internals.h +++ b/gdbstub/internals.h @@ -103,7 +103,7 @@ static inline int tohex(int v) } /* - * Connection helpers for both softmmu and user backends + * Connection helpers for both system and user backends */ void gdb_put_strbuf(void); @@ -229,7 +229,7 @@ void gdb_breakpoint_remove_all(CPUState *cs); * @is_write: is it a write operation * * This function is specialised depending on the mode we are running - * in. For softmmu guests we can switch the interpretation of the + * in. For system guests we can switch the interpretation of the * address to a physical address. */ int gdb_target_memory_rw_debug(CPUState *cs, hwaddr addr, diff --git a/gdbstub/meson.build b/gdbstub/meson.build index a5a1f4e433..e5bccba34e 100644 --- a/gdbstub/meson.build +++ b/gdbstub/meson.build @@ -1,6 +1,6 @@ # # The main gdbstub still relies on per-build definitions of various -# types. The bits pushed to softmmu/user.c try to use guest agnostic +# types. The bits pushed to system/user.c try to use guest agnostic # types such as hwaddr. # @@ -12,7 +12,7 @@ gdb_system_ss = ss.source_set() # We build two versions of gdbstub, one for each mode gdb_user_ss.add(files('gdbstub.c', 'user.c')) -gdb_system_ss.add(files('gdbstub.c', 'softmmu.c')) +gdb_system_ss.add(files('gdbstub.c', 'system.c')) gdb_user_ss = gdb_user_ss.apply(config_targetos, strict: false) gdb_system_ss = gdb_system_ss.apply(config_targetos, strict: false) @@ -23,15 +23,15 @@ libgdb_user = static_library('gdb_user', c_args: '-DCONFIG_USER_ONLY', build_by_default: false) -libgdb_softmmu = static_library('gdb_softmmu', +libgdb_system = static_library('gdb_system', gdb_system_ss.sources() + genh, name_suffix: 'fa', build_by_default: false) gdb_user = declare_dependency(link_whole: libgdb_user) user_ss.add(gdb_user) -gdb_softmmu = declare_dependency(link_whole: libgdb_softmmu) -system_ss.add(gdb_softmmu) +gdb_system = declare_dependency(link_whole: libgdb_system) +system_ss.add(gdb_system) common_ss.add(files('syscalls.c')) diff --git a/gdbstub/softmmu.c b/gdbstub/system.c similarity index 99% rename from gdbstub/softmmu.c rename to gdbstub/system.c index 9f0b8b5497..189975b1d6 100644 --- a/gdbstub/softmmu.c +++ b/gdbstub/system.c @@ -104,7 +104,7 @@ static void gdb_chr_event(void *opaque, QEMUChrEvent event) } /* - * In softmmu mode we stop the VM and wait to send the syscall packet + * In system-mode we stop the VM and wait to send the syscall packet * until notification that the CPU has stopped. This must be done * because if the packet is sent now the reply from the syscall * request could be received while the CPU is still in the running diff --git a/gdbstub/trace-events b/gdbstub/trace-events index 7bc79a73c4..4fd126a38c 100644 --- a/gdbstub/trace-events +++ b/gdbstub/trace-events @@ -28,5 +28,5 @@ gdbstub_err_checksum_invalid(uint8_t ch) "got invalid command checksum digit: 0x gdbstub_err_checksum_incorrect(uint8_t expected, uint8_t got) "got command packet with incorrect checksum, expected=0x%02x, received=0x%02x" gdbstub_err_unexpected_runpkt(uint8_t ch) "unexpected packet (0x%02x) while target running" -# softmmu.c +# system.c gdbstub_hit_watchpoint(const char *type, int cpu_gdb_index, uint64_t vaddr) "Watchpoint hit, type=\"%s\" cpu=%d, vaddr=0x%" PRIx64 "" From f14eced5ac9ae2db10a661e0fdef52a2f0316699 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Wed, 4 Oct 2023 11:06:23 +0200 Subject: [PATCH 0390/1077] semihosting: Rename softmmu_FOO_user() -> uaccess_FOO_user() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add a check in 'softmmu-uaccess.h' that the header is only include in system emulation, and rename it as 'uaccess.h'. Rename the API methods: - softmmu_[un]lock_user*() -> uaccess_[un]lock_user*() - softmmu_strlen_user() -> uaccess_strlen_user(). Update a pair of comments. Signed-off-by: Philippe Mathieu-Daudé Message-ID: <20231004090629.37473-9-philmd@linaro.org> Signed-off-by: Paolo Bonzini --- .../{softmmu-uaccess.h => uaccess.h} | 24 +++++++++++-------- semihosting/arm-compat-semi.c | 4 ++-- semihosting/config.c | 2 +- semihosting/guestfd.c | 2 +- semihosting/syscalls.c | 2 +- semihosting/uaccess.c | 14 +++++------ stubs/semihost.c | 4 ++-- target/m68k/m68k-semi.c | 2 +- target/mips/tcg/sysemu/mips-semi.c | 2 +- target/nios2/nios2-semi.c | 2 +- 10 files changed, 31 insertions(+), 27 deletions(-) rename include/semihosting/{softmmu-uaccess.h => uaccess.h} (75%) diff --git a/include/semihosting/softmmu-uaccess.h b/include/semihosting/uaccess.h similarity index 75% rename from include/semihosting/softmmu-uaccess.h rename to include/semihosting/uaccess.h index 4f08dfc098..3963eafc3e 100644 --- a/include/semihosting/softmmu-uaccess.h +++ b/include/semihosting/uaccess.h @@ -7,8 +7,12 @@ * This code is licensed under the GPL */ -#ifndef SEMIHOSTING_SOFTMMU_UACCESS_H -#define SEMIHOSTING_SOFTMMU_UACCESS_H +#ifndef SEMIHOSTING_UACCESS_H +#define SEMIHOSTING_UACCESS_H + +#ifdef CONFIG_USER_ONLY +#error Cannot include semihosting/uaccess.h from user emulation +#endif #include "cpu.h" @@ -42,18 +46,18 @@ #define put_user_ual(arg, p) put_user_u32(arg, p) -void *softmmu_lock_user(CPUArchState *env, target_ulong addr, +void *uaccess_lock_user(CPUArchState *env, target_ulong addr, target_ulong len, bool copy); -#define lock_user(type, p, len, copy) softmmu_lock_user(env, p, len, copy) +#define lock_user(type, p, len, copy) uaccess_lock_user(env, p, len, copy) -char *softmmu_lock_user_string(CPUArchState *env, target_ulong addr); -#define lock_user_string(p) softmmu_lock_user_string(env, p) +char *uaccess_lock_user_string(CPUArchState *env, target_ulong addr); +#define lock_user_string(p) uaccess_lock_user_string(env, p) -void softmmu_unlock_user(CPUArchState *env, void *p, +void uaccess_unlock_user(CPUArchState *env, void *p, target_ulong addr, target_ulong len); -#define unlock_user(s, args, len) softmmu_unlock_user(env, s, args, len) +#define unlock_user(s, args, len) uaccess_unlock_user(env, s, args, len) -ssize_t softmmu_strlen_user(CPUArchState *env, target_ulong addr); -#define target_strlen(p) softmmu_strlen_user(env, p) +ssize_t uaccess_strlen_user(CPUArchState *env, target_ulong addr); +#define target_strlen(p) uaccess_strlen_user(env, p) #endif /* SEMIHOSTING_SOFTMMU_UACCESS_H */ diff --git a/semihosting/arm-compat-semi.c b/semihosting/arm-compat-semi.c index 29c5670fdf..d7a42a4da4 100644 --- a/semihosting/arm-compat-semi.c +++ b/semihosting/arm-compat-semi.c @@ -202,13 +202,13 @@ static LayoutInfo common_semi_find_bases(CPUState *cs) * The semihosting API has no concept of its errno being thread-safe, * as the API design predates SMP CPUs and was intended as a simple * real-hardware set of debug functionality. For QEMU, we make the - * errno be per-thread in linux-user mode; in softmmu it is a simple + * errno be per-thread in linux-user mode; in system-mode it is a simple * global, and we assume that the guest takes care of avoiding any races. */ #ifndef CONFIG_USER_ONLY static target_ulong syscall_err; -#include "semihosting/softmmu-uaccess.h" +#include "semihosting/uaccess.h" #endif static inline uint32_t get_swi_errno(CPUState *cs) diff --git a/semihosting/config.c b/semihosting/config.c index 8ca569735d..61e4016fc5 100644 --- a/semihosting/config.c +++ b/semihosting/config.c @@ -12,7 +12,7 @@ * linux-user targets. However in that use case no configuration of * the outputs and command lines is supported. * - * The config module is common to all softmmu targets however as vl.c + * The config module is common to all system targets however as vl.c * needs to link against the helpers. * * SPDX-License-Identifier: GPL-2.0-or-later diff --git a/semihosting/guestfd.c b/semihosting/guestfd.c index acb86b50dd..955c2efbd0 100644 --- a/semihosting/guestfd.c +++ b/semihosting/guestfd.c @@ -15,7 +15,7 @@ #ifdef CONFIG_USER_ONLY #include "qemu.h" #else -#include "semihosting/softmmu-uaccess.h" +#include "semihosting/uaccess.h" #include CONFIG_DEVICES #endif diff --git a/semihosting/syscalls.c b/semihosting/syscalls.c index 1ab4809567..c40348f996 100644 --- a/semihosting/syscalls.c +++ b/semihosting/syscalls.c @@ -15,7 +15,7 @@ #ifdef CONFIG_USER_ONLY #include "qemu.h" #else -#include "semihosting/softmmu-uaccess.h" +#include "semihosting/uaccess.h" #endif diff --git a/semihosting/uaccess.c b/semihosting/uaccess.c index 7505eb6d1b..5d889f9263 100644 --- a/semihosting/uaccess.c +++ b/semihosting/uaccess.c @@ -9,9 +9,9 @@ #include "qemu/osdep.h" #include "exec/exec-all.h" -#include "semihosting/softmmu-uaccess.h" +#include "semihosting/uaccess.h" -void *softmmu_lock_user(CPUArchState *env, target_ulong addr, +void *uaccess_lock_user(CPUArchState *env, target_ulong addr, target_ulong len, bool copy) { void *p = malloc(len); @@ -24,7 +24,7 @@ void *softmmu_lock_user(CPUArchState *env, target_ulong addr, return p; } -ssize_t softmmu_strlen_user(CPUArchState *env, target_ulong addr) +ssize_t uaccess_strlen_user(CPUArchState *env, target_ulong addr) { int mmu_idx = cpu_mmu_index(env, false); size_t len = 0; @@ -72,16 +72,16 @@ ssize_t softmmu_strlen_user(CPUArchState *env, target_ulong addr) } } -char *softmmu_lock_user_string(CPUArchState *env, target_ulong addr) +char *uaccess_lock_user_string(CPUArchState *env, target_ulong addr) { - ssize_t len = softmmu_strlen_user(env, addr); + ssize_t len = uaccess_strlen_user(env, addr); if (len < 0) { return NULL; } - return softmmu_lock_user(env, addr, len + 1, true); + return uaccess_lock_user(env, addr, len + 1, true); } -void softmmu_unlock_user(CPUArchState *env, void *p, +void uaccess_unlock_user(CPUArchState *env, void *p, target_ulong addr, target_ulong len) { if (len) { diff --git a/stubs/semihost.c b/stubs/semihost.c index aad7a70353..9343d385d7 100644 --- a/stubs/semihost.c +++ b/stubs/semihost.c @@ -1,9 +1,9 @@ /* - * Semihosting Stubs for SoftMMU + * Semihosting Stubs for system emulation * * Copyright (c) 2019 Linaro Ltd * - * Stubs for SoftMMU targets that don't actually do semihosting. + * Stubs for system targets that don't actually do semihosting. * * SPDX-License-Identifier: GPL-2.0-or-later */ diff --git a/target/m68k/m68k-semi.c b/target/m68k/m68k-semi.c index 80cd8d70db..b4ffb70f8b 100644 --- a/target/m68k/m68k-semi.c +++ b/target/m68k/m68k-semi.c @@ -27,7 +27,7 @@ #include "gdbstub/syscalls.h" #include "gdbstub/helpers.h" #include "semihosting/syscalls.h" -#include "semihosting/softmmu-uaccess.h" +#include "semihosting/uaccess.h" #include "hw/boards.h" #include "qemu/log.h" diff --git a/target/mips/tcg/sysemu/mips-semi.c b/target/mips/tcg/sysemu/mips-semi.c index b3e4e49ff7..5ba06e9573 100644 --- a/target/mips/tcg/sysemu/mips-semi.c +++ b/target/mips/tcg/sysemu/mips-semi.c @@ -22,7 +22,7 @@ #include "qemu/log.h" #include "gdbstub/syscalls.h" #include "gdbstub/helpers.h" -#include "semihosting/softmmu-uaccess.h" +#include "semihosting/uaccess.h" #include "semihosting/semihost.h" #include "semihosting/console.h" #include "semihosting/syscalls.h" diff --git a/target/nios2/nios2-semi.c b/target/nios2/nios2-semi.c index 9d0241c758..0b84fcb6b6 100644 --- a/target/nios2/nios2-semi.c +++ b/target/nios2/nios2-semi.c @@ -26,7 +26,7 @@ #include "gdbstub/syscalls.h" #include "gdbstub/helpers.h" #include "semihosting/syscalls.h" -#include "semihosting/softmmu-uaccess.h" +#include "semihosting/uaccess.h" #include "qemu/log.h" #define HOSTED_EXIT 0 From 5338977abdf952249db7ac77a7c3358895fa78b1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Wed, 4 Oct 2023 11:06:24 +0200 Subject: [PATCH 0391/1077] target/i386: Rename i386_softmmu_kvm_ss -> i386_kvm_ss MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Software MMU is TCG specific. Here 'softmmu' is misused for system emulation. Anyhow, since KVM is system emulation specific, just rename as 'i386_kvm_ss'. Signed-off-by: Philippe Mathieu-Daudé Message-ID: <20231004090629.37473-10-philmd@linaro.org> Signed-off-by: Paolo Bonzini --- target/i386/kvm/meson.build | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/target/i386/kvm/meson.build b/target/i386/kvm/meson.build index 5d9174bbb5..84d9143e60 100644 --- a/target/i386/kvm/meson.build +++ b/target/i386/kvm/meson.build @@ -1,14 +1,14 @@ -i386_softmmu_kvm_ss = ss.source_set() +i386_kvm_ss = ss.source_set() -i386_softmmu_kvm_ss.add(files( +i386_kvm_ss.add(files( 'kvm.c', 'kvm-cpu.c', )) -i386_softmmu_kvm_ss.add(when: 'CONFIG_XEN_EMU', if_true: files('xen-emu.c')) +i386_kvm_ss.add(when: 'CONFIG_XEN_EMU', if_true: files('xen-emu.c')) -i386_softmmu_kvm_ss.add(when: 'CONFIG_SEV', if_false: files('sev-stub.c')) +i386_kvm_ss.add(when: 'CONFIG_SEV', if_false: files('sev-stub.c')) i386_system_ss.add(when: 'CONFIG_HYPERV', if_true: files('hyperv.c'), if_false: files('hyperv-stub.c')) -i386_system_ss.add_all(when: 'CONFIG_KVM', if_true: i386_softmmu_kvm_ss) +i386_system_ss.add_all(when: 'CONFIG_KVM', if_true: i386_kvm_ss) From 21d2140dd8a0e44cd24a640f0316d02e7927f603 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Wed, 4 Oct 2023 11:06:26 +0200 Subject: [PATCH 0392/1077] meson: Rename softmmu_mods -> system_mods MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit See commit de6cd7599b ("meson: Replace softmmu_ss -> system_ss") for rationale. Signed-off-by: Philippe Mathieu-Daudé Message-ID: <20231004090629.37473-12-philmd@linaro.org> Signed-off-by: Paolo Bonzini --- meson.build | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/meson.build b/meson.build index 3bb64b536c..54907c7fa9 100644 --- a/meson.build +++ b/meson.build @@ -3480,7 +3480,7 @@ modinfo_generate = find_program('scripts/modinfo-generate.py') modinfo_files = [] block_mods = [] -softmmu_mods = [] +system_mods = [] foreach d, list : modules if not (d == 'block' ? have_block : have_system) continue @@ -3494,7 +3494,7 @@ foreach d, list : modules if d == 'block' block_mods += sl else - softmmu_mods += sl + system_mods += sl endif if module_ss.sources() != [] # FIXME: Should use sl.extract_all_objects(recursive: true) as @@ -3538,7 +3538,7 @@ foreach d, list : target_modules include_directories: target_inc, c_args: c_args, pic: true) - softmmu_mods += sl + system_mods += sl # FIXME: Should use sl.extract_all_objects(recursive: true) too. modinfo_files += custom_target(module_name + '.modinfo', output: module_name + '.modinfo', @@ -3581,7 +3581,7 @@ block_syms = custom_target('block.syms', output: 'block.syms', capture: true, command: [undefsym, nm, '@INPUT@']) qemu_syms = custom_target('qemu.syms', output: 'qemu.syms', - input: [libqemuutil, softmmu_mods], + input: [libqemuutil, system_mods], capture: true, command: [undefsym, nm, '@INPUT@']) @@ -3666,7 +3666,7 @@ common_ss.add(hwcore) ########### emulator_modules = [] -foreach m : block_mods + softmmu_mods +foreach m : block_mods + system_mods emulator_modules += shared_module(m.name(), build_by_default: true, name_prefix: '', From 01c85e60a4d0675f0ad203fe1fe119381e7ad15b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Wed, 4 Oct 2023 11:06:27 +0200 Subject: [PATCH 0393/1077] meson: Rename target_softmmu_arch -> target_system_arch MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Finish the convertion started with commit de6cd7599b ("meson: Replace softmmu_ss -> system_ss"). If the $target_type is 'system', then use the target_system_arch[] source set :) Mechanical change doing: $ sed -i -e s/target_softmmu_arch/target_system_arch/g \ $(git grep -l target_softmmu_arch) Signed-off-by: Philippe Mathieu-Daudé Message-ID: <20231004090629.37473-13-philmd@linaro.org> Signed-off-by: Paolo Bonzini --- docs/devel/build-system.rst | 4 ++-- meson.build | 4 ++-- target/alpha/meson.build | 2 +- target/arm/meson.build | 2 +- target/avr/meson.build | 2 +- target/cris/meson.build | 2 +- target/hppa/meson.build | 2 +- target/i386/meson.build | 2 +- target/loongarch/meson.build | 2 +- target/m68k/meson.build | 2 +- target/microblaze/meson.build | 2 +- target/mips/meson.build | 2 +- target/nios2/meson.build | 2 +- target/openrisc/meson.build | 2 +- target/ppc/meson.build | 2 +- target/riscv/meson.build | 2 +- target/rx/meson.build | 2 +- target/s390x/meson.build | 2 +- target/sh4/meson.build | 2 +- target/sparc/meson.build | 2 +- target/tricore/meson.build | 2 +- target/xtensa/meson.build | 2 +- 22 files changed, 24 insertions(+), 24 deletions(-) diff --git a/docs/devel/build-system.rst b/docs/devel/build-system.rst index 0f990bb3e9..21f78da7d1 100644 --- a/docs/devel/build-system.rst +++ b/docs/devel/build-system.rst @@ -225,14 +225,14 @@ Target-dependent emulator sourcesets: The sourceset is only used for system emulators. Each subdirectory in ``target/`` instead should add one sourceset to each - of the ``target_arch`` and ``target_softmmu_arch``, which are used respectively + of the ``target_arch`` and ``target_system_arch``, which are used respectively for all emulators and for system emulators only. For example:: arm_ss = ss.source_set() arm_system_ss = ss.source_set() ... target_arch += {'arm': arm_ss} - target_softmmu_arch += {'arm': arm_system_ss} + target_system_arch += {'arm': arm_system_ss} Module sourcesets: There are two dictionaries for modules: ``modules`` is used for diff --git a/meson.build b/meson.build index 54907c7fa9..167cb70956 100644 --- a/meson.build +++ b/meson.build @@ -3198,7 +3198,7 @@ modules = {} target_modules = {} hw_arch = {} target_arch = {} -target_softmmu_arch = {} +target_system_arch = {} target_user_arch = {} ############### @@ -3718,7 +3718,7 @@ foreach target : target_dirs endif if target.endswith('-softmmu') target_type='system' - t = target_softmmu_arch[target_base_arch].apply(config_target, strict: false) + t = target_system_arch[target_base_arch].apply(config_target, strict: false) arch_srcs += t.sources() arch_deps += t.dependencies() diff --git a/target/alpha/meson.build b/target/alpha/meson.build index 3f5253c002..d3502dd823 100644 --- a/target/alpha/meson.build +++ b/target/alpha/meson.build @@ -15,4 +15,4 @@ alpha_system_ss = ss.source_set() alpha_system_ss.add(files('machine.c')) target_arch += {'alpha': alpha_ss} -target_softmmu_arch += {'alpha': alpha_system_ss} +target_system_arch += {'alpha': alpha_system_ss} diff --git a/target/arm/meson.build b/target/arm/meson.build index e645e456da..5d04a8e94f 100644 --- a/target/arm/meson.build +++ b/target/arm/meson.build @@ -35,4 +35,4 @@ else endif target_arch += {'arm': arm_ss} -target_softmmu_arch += {'arm': arm_system_ss} +target_system_arch += {'arm': arm_system_ss} diff --git a/target/avr/meson.build b/target/avr/meson.build index a24cf6d26d..3e172bde1c 100644 --- a/target/avr/meson.build +++ b/target/avr/meson.build @@ -17,4 +17,4 @@ avr_ss.add(files( avr_system_ss.add(files('machine.c')) target_arch += {'avr': avr_ss} -target_softmmu_arch += {'avr': avr_system_ss} +target_system_arch += {'avr': avr_system_ss} diff --git a/target/cris/meson.build b/target/cris/meson.build index 07dc3a5682..bbfcdf7f7a 100644 --- a/target/cris/meson.build +++ b/target/cris/meson.build @@ -14,4 +14,4 @@ cris_system_ss.add(files( )) target_arch += {'cris': cris_ss} -target_softmmu_arch += {'cris': cris_system_ss} +target_system_arch += {'cris': cris_system_ss} diff --git a/target/hppa/meson.build b/target/hppa/meson.build index 59b68e82e2..f47e54f5fa 100644 --- a/target/hppa/meson.build +++ b/target/hppa/meson.build @@ -20,4 +20,4 @@ hppa_system_ss.add(files( )) target_arch += {'hppa': hppa_ss} -target_softmmu_arch += {'hppa': hppa_system_ss} +target_system_arch += {'hppa': hppa_system_ss} diff --git a/target/i386/meson.build b/target/i386/meson.build index 6f1036d469..7c74bfa859 100644 --- a/target/i386/meson.build +++ b/target/i386/meson.build @@ -31,5 +31,5 @@ subdir('hvf') subdir('tcg') target_arch += {'i386': i386_ss} -target_softmmu_arch += {'i386': i386_system_ss} +target_system_arch += {'i386': i386_system_ss} target_user_arch += {'i386': i386_user_ss} diff --git a/target/loongarch/meson.build b/target/loongarch/meson.build index 7fbf045a5d..18e8191e2b 100644 --- a/target/loongarch/meson.build +++ b/target/loongarch/meson.build @@ -30,4 +30,4 @@ common_ss.add(when: 'CONFIG_LOONGARCH_DIS', if_true: [files('disas.c'), gen]) loongarch_ss.add_all(when: 'CONFIG_TCG', if_true: [loongarch_tcg_ss]) target_arch += {'loongarch': loongarch_ss} -target_softmmu_arch += {'loongarch': loongarch_system_ss} +target_system_arch += {'loongarch': loongarch_system_ss} diff --git a/target/m68k/meson.build b/target/m68k/meson.build index 355db26c6f..8d3f9ce288 100644 --- a/target/m68k/meson.build +++ b/target/m68k/meson.build @@ -16,4 +16,4 @@ m68k_system_ss.add(files( )) target_arch += {'m68k': m68k_ss} -target_softmmu_arch += {'m68k': m68k_system_ss} +target_system_arch += {'m68k': m68k_system_ss} diff --git a/target/microblaze/meson.build b/target/microblaze/meson.build index 50fd9ff378..3ed4fbb67a 100644 --- a/target/microblaze/meson.build +++ b/target/microblaze/meson.build @@ -17,4 +17,4 @@ microblaze_system_ss.add(files( )) target_arch += {'microblaze': microblaze_ss} -target_softmmu_arch += {'microblaze': microblaze_system_ss} +target_system_arch += {'microblaze': microblaze_system_ss} diff --git a/target/mips/meson.build b/target/mips/meson.build index f35e8f0eca..e57ef24ecf 100644 --- a/target/mips/meson.build +++ b/target/mips/meson.build @@ -19,5 +19,5 @@ endif mips_ss.add(when: 'CONFIG_KVM', if_true: files('kvm.c')) target_arch += {'mips': mips_ss} -target_softmmu_arch += {'mips': mips_system_ss} +target_system_arch += {'mips': mips_system_ss} target_user_arch += {'mips': mips_user_ss} diff --git a/target/nios2/meson.build b/target/nios2/meson.build index 8f0f9dc628..12d8abf0bd 100644 --- a/target/nios2/meson.build +++ b/target/nios2/meson.build @@ -14,4 +14,4 @@ nios2_system_ss.add(files( )) target_arch += {'nios2': nios2_ss} -target_softmmu_arch += {'nios2': nios2_system_ss} +target_system_arch += {'nios2': nios2_system_ss} diff --git a/target/openrisc/meson.build b/target/openrisc/meson.build index c1cd943f78..31608b6dc7 100644 --- a/target/openrisc/meson.build +++ b/target/openrisc/meson.build @@ -22,4 +22,4 @@ openrisc_system_ss.add(files( )) target_arch += {'openrisc': openrisc_ss} -target_softmmu_arch += {'openrisc': openrisc_system_ss} +target_system_arch += {'openrisc': openrisc_system_ss} diff --git a/target/ppc/meson.build b/target/ppc/meson.build index 4c2635039e..97ceb6e7c0 100644 --- a/target/ppc/meson.build +++ b/target/ppc/meson.build @@ -55,4 +55,4 @@ ppc_system_ss.add(when: 'TARGET_PPC64', if_true: files( )) target_arch += {'ppc': ppc_ss} -target_softmmu_arch += {'ppc': ppc_system_ss} +target_system_arch += {'ppc': ppc_system_ss} diff --git a/target/riscv/meson.build b/target/riscv/meson.build index 660078bda1..ff60b21d04 100644 --- a/target/riscv/meson.build +++ b/target/riscv/meson.build @@ -39,4 +39,4 @@ riscv_system_ss.add(files( )) target_arch += {'riscv': riscv_ss} -target_softmmu_arch += {'riscv': riscv_system_ss} +target_system_arch += {'riscv': riscv_system_ss} diff --git a/target/rx/meson.build b/target/rx/meson.build index 8de0ad49b9..d196737ce3 100644 --- a/target/rx/meson.build +++ b/target/rx/meson.build @@ -13,4 +13,4 @@ rx_ss.add(files( 'disas.c')) target_arch += {'rx': rx_ss} -target_softmmu_arch += {'rx': ss.source_set()} +target_system_arch += {'rx': ss.source_set()} diff --git a/target/s390x/meson.build b/target/s390x/meson.build index 42ed38942a..02ca43d9f0 100644 --- a/target/s390x/meson.build +++ b/target/s390x/meson.build @@ -40,5 +40,5 @@ subdir('tcg') subdir('kvm') target_arch += {'s390x': s390x_ss} -target_softmmu_arch += {'s390x': s390x_system_ss} +target_system_arch += {'s390x': s390x_system_ss} target_user_arch += {'s390x': s390x_user_ss} diff --git a/target/sh4/meson.build b/target/sh4/meson.build index a78e9ec7e4..fe09f96684 100644 --- a/target/sh4/meson.build +++ b/target/sh4/meson.build @@ -11,4 +11,4 @@ sh4_system_ss = ss.source_set() sh4_system_ss.add(files('monitor.c')) target_arch += {'sh4': sh4_ss} -target_softmmu_arch += {'sh4': sh4_system_ss} +target_system_arch += {'sh4': sh4_system_ss} diff --git a/target/sparc/meson.build b/target/sparc/meson.build index d32e67b287..48025cce76 100644 --- a/target/sparc/meson.build +++ b/target/sparc/meson.build @@ -20,4 +20,4 @@ sparc_system_ss.add(files( )) target_arch += {'sparc': sparc_ss} -target_softmmu_arch += {'sparc': sparc_system_ss} +target_system_arch += {'sparc': sparc_system_ss} diff --git a/target/tricore/meson.build b/target/tricore/meson.build index 34825b6048..45f49f0128 100644 --- a/target/tricore/meson.build +++ b/target/tricore/meson.build @@ -12,4 +12,4 @@ tricore_ss.add(zlib) tricore_system_ss = ss.source_set() target_arch += {'tricore': tricore_ss} -target_softmmu_arch += {'tricore': tricore_system_ss} +target_system_arch += {'tricore': tricore_system_ss} diff --git a/target/xtensa/meson.build b/target/xtensa/meson.build index 95692bd75f..f8d60101e3 100644 --- a/target/xtensa/meson.build +++ b/target/xtensa/meson.build @@ -24,4 +24,4 @@ xtensa_system_ss.add(files( )) target_arch += {'xtensa': xtensa_ss} -target_softmmu_arch += {'xtensa': xtensa_system_ss} +target_system_arch += {'xtensa': xtensa_system_ss} From 8d7f2e767d8cd058c817dbe31430b89f2e11535d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Wed, 4 Oct 2023 11:06:28 +0200 Subject: [PATCH 0394/1077] system: Rename softmmu/ directory as system/ MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The softmmu/ directory contains files specific to system emulation. Rename it as system/. Update meson rules, the MAINTAINERS file and all the documentation and comments. Signed-off-by: Philippe Mathieu-Daudé Message-ID: <20231004090629.37473-14-philmd@linaro.org> Signed-off-by: Paolo Bonzini --- MAINTAINERS | 42 +++++++++---------- accel/tcg/icount-common.c | 2 +- docs/devel/qtest.rst | 2 +- .../sysemu/cpu-timers-internal.h | 0 include/sysemu/runstate-action.h | 2 +- meson.build | 8 ++-- scripts/checkpatch.pl | 2 +- scripts/coverity-scan/COMPONENTS.md | 2 +- scripts/get_maintainer.pl | 2 +- scripts/oss-fuzz/build.sh | 6 +-- softmmu/trace.h | 1 - {softmmu => system}/arch_init.c | 0 {softmmu => system}/async-teardown.c | 0 {softmmu => system}/balloon.c | 0 {softmmu => system}/bootdevice.c | 0 {softmmu => system}/cpu-throttle.c | 0 {softmmu => system}/cpu-timers.c | 2 +- {softmmu => system}/cpus.c | 0 {softmmu => system}/datadir.c | 0 {softmmu => system}/device_tree.c | 0 {softmmu => system}/dirtylimit.c | 0 {softmmu => system}/dma-helpers.c | 0 {softmmu => system}/globals.c | 0 {softmmu => system}/ioport.c | 0 {softmmu => system}/main.c | 0 {softmmu => system}/memory.c | 0 {softmmu => system}/memory_mapping.c | 0 {softmmu => system}/meson.build | 0 {softmmu => system}/physmem.c | 6 ++- {softmmu => system}/qdev-monitor.c | 0 {softmmu => system}/qemu-seccomp.c | 0 {softmmu => system}/qtest.c | 0 {softmmu => system}/rtc.c | 0 {softmmu => system}/runstate-action.c | 0 {softmmu => system}/runstate-hmp-cmds.c | 0 {softmmu => system}/runstate.c | 0 {softmmu => system}/tpm-hmp-cmds.c | 0 {softmmu => system}/tpm.c | 0 {softmmu => system}/trace-events | 0 system/trace.h | 1 + {softmmu => system}/vl.c | 0 {softmmu => system}/watchpoint.c | 0 tests/unit/meson.build | 2 +- 43 files changed, 41 insertions(+), 39 deletions(-) rename softmmu/timers-state.h => include/sysemu/cpu-timers-internal.h (100%) delete mode 100644 softmmu/trace.h rename {softmmu => system}/arch_init.c (100%) rename {softmmu => system}/async-teardown.c (100%) rename {softmmu => system}/balloon.c (100%) rename {softmmu => system}/bootdevice.c (100%) rename {softmmu => system}/cpu-throttle.c (100%) rename {softmmu => system}/cpu-timers.c (99%) rename {softmmu => system}/cpus.c (100%) rename {softmmu => system}/datadir.c (100%) rename {softmmu => system}/device_tree.c (100%) rename {softmmu => system}/dirtylimit.c (100%) rename {softmmu => system}/dma-helpers.c (100%) rename {softmmu => system}/globals.c (100%) rename {softmmu => system}/ioport.c (100%) rename {softmmu => system}/main.c (100%) rename {softmmu => system}/memory.c (100%) rename {softmmu => system}/memory_mapping.c (100%) rename {softmmu => system}/meson.build (100%) rename {softmmu => system}/physmem.c (99%) rename {softmmu => system}/qdev-monitor.c (100%) rename {softmmu => system}/qemu-seccomp.c (100%) rename {softmmu => system}/qtest.c (100%) rename {softmmu => system}/rtc.c (100%) rename {softmmu => system}/runstate-action.c (100%) rename {softmmu => system}/runstate-hmp-cmds.c (100%) rename {softmmu => system}/runstate.c (100%) rename {softmmu => system}/tpm-hmp-cmds.c (100%) rename {softmmu => system}/tpm.c (100%) rename {softmmu => system}/trace-events (100%) create mode 100644 system/trace.h rename {softmmu => system}/vl.c (100%) rename {softmmu => system}/watchpoint.c (100%) diff --git a/MAINTAINERS b/MAINTAINERS index ea91f9e804..a5ce4c0856 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -137,8 +137,8 @@ Overall TCG CPUs M: Richard Henderson R: Paolo Bonzini S: Maintained -F: softmmu/cpus.c -F: softmmu/watchpoint.c +F: system/cpus.c +F: system/watchpoint.c F: cpu-common.c F: cpu-target.c F: page-vary-target.c @@ -2108,7 +2108,7 @@ S: Maintained F: docs/interop/virtio-balloon-stats.rst F: hw/virtio/virtio-balloon*.c F: include/hw/virtio/virtio-balloon.h -F: softmmu/balloon.c +F: system/balloon.c F: include/sysemu/balloon.h virtio-9p @@ -2795,7 +2795,7 @@ Device Tree M: Alistair Francis R: David Gibson S: Maintained -F: softmmu/device_tree.c +F: system/device_tree.c F: include/sysemu/device_tree.h Dump @@ -2851,11 +2851,11 @@ F: include/exec/memory.h F: include/exec/ram_addr.h F: include/exec/ramblock.h F: include/sysemu/memory_mapping.h -F: softmmu/dma-helpers.c -F: softmmu/ioport.c -F: softmmu/memory.c -F: softmmu/memory_mapping.c -F: softmmu/physmem.c +F: system/dma-helpers.c +F: system/ioport.c +F: system/memory.c +F: system/memory_mapping.c +F: system/physmem.c F: include/exec/memory-internal.h F: scripts/coccinelle/memory-region-housekeeping.cocci @@ -2908,12 +2908,12 @@ F: include/sysemu/runstate.h F: include/sysemu/runstate-action.h F: util/main-loop.c F: util/qemu-timer.c -F: softmmu/vl.c -F: softmmu/main.c -F: softmmu/cpus.c -F: softmmu/cpu-throttle.c -F: softmmu/cpu-timers.c -F: softmmu/runstate* +F: system/vl.c +F: system/main.c +F: system/cpus.c +F: system/cpu-throttle.c +F: system/cpu-timers.c +F: system/runstate* F: qapi/run-state.json Read, Copy, Update (RCU) @@ -3087,7 +3087,7 @@ F: qapi/qom.json F: qapi/qdev.json F: scripts/coccinelle/qom-parent-type.cocci F: scripts/qom-cast-macro-clean-cocci-gen.py -F: softmmu/qdev-monitor.c +F: system/qdev-monitor.c F: stubs/qdev.c F: qom/ F: tests/unit/check-qom-interface.c @@ -3121,7 +3121,7 @@ M: Thomas Huth M: Laurent Vivier R: Paolo Bonzini S: Maintained -F: softmmu/qtest.c +F: system/qtest.c F: accel/qtest/ F: tests/qtest/ F: docs/devel/qgraph.rst @@ -3197,7 +3197,7 @@ F: scripts/simpletrace.py TPM M: Stefan Berger S: Maintained -F: softmmu/tpm* +F: system/tpm* F: hw/tpm/* F: include/hw/acpi/tpm.h F: include/sysemu/tpm* @@ -3242,7 +3242,7 @@ F: migration/rdma* Migration dirty limit and dirty page rate M: Hyman Huang S: Maintained -F: softmmu/dirtylimit.c +F: system/dirtylimit.c F: include/sysemu/dirtylimit.h F: migration/dirtyrate.c F: migration/dirtyrate.h @@ -3266,7 +3266,7 @@ F: scripts/xml-preprocess* Seccomp M: Daniel P. Berrange S: Odd Fixes -F: softmmu/qemu-seccomp.c +F: system/qemu-seccomp.c F: include/sysemu/seccomp.h F: tests/unit/test-seccomp.c @@ -3685,7 +3685,7 @@ T: git https://github.com/stefanha/qemu.git block Bootdevice M: Gonglei S: Maintained -F: softmmu/bootdevice.c +F: system/bootdevice.c Quorum M: Alberto Garcia diff --git a/accel/tcg/icount-common.c b/accel/tcg/icount-common.c index 0bf5bb5e21..ec57192be8 100644 --- a/accel/tcg/icount-common.c +++ b/accel/tcg/icount-common.c @@ -37,7 +37,7 @@ #include "hw/core/cpu.h" #include "sysemu/cpu-timers.h" #include "sysemu/cpu-throttle.h" -#include "softmmu/timers-state.h" +#include "sysemu/cpu-timers-internal.h" /* * ICOUNT: Instruction Counter diff --git a/docs/devel/qtest.rst b/docs/devel/qtest.rst index 0455aa06ab..c5b8546b3e 100644 --- a/docs/devel/qtest.rst +++ b/docs/devel/qtest.rst @@ -81,7 +81,7 @@ which you can run manually. QTest Protocol -------------- -.. kernel-doc:: softmmu/qtest.c +.. kernel-doc:: system/qtest.c :doc: QTest Protocol diff --git a/softmmu/timers-state.h b/include/sysemu/cpu-timers-internal.h similarity index 100% rename from softmmu/timers-state.h rename to include/sysemu/cpu-timers-internal.h diff --git a/include/sysemu/runstate-action.h b/include/sysemu/runstate-action.h index cff45a047b..db4e3099ae 100644 --- a/include/sysemu/runstate-action.h +++ b/include/sysemu/runstate-action.h @@ -11,7 +11,7 @@ #include "qapi/qapi-commands-run-state.h" -/* in softmmu/runstate-action.c */ +/* in system/runstate-action.c */ extern RebootAction reboot_action; extern ShutdownAction shutdown_action; extern PanicAction panic_action; diff --git a/meson.build b/meson.build index 167cb70956..79aef19bdc 100644 --- a/meson.build +++ b/meson.build @@ -3291,7 +3291,7 @@ if have_system 'hw/gpio', 'migration', 'net', - 'softmmu', + 'system', 'ui', 'hw/remote', ] @@ -3418,7 +3418,7 @@ endif common_ss.add(files('cpu-common.c')) specific_ss.add(files('cpu-target.c')) -subdir('softmmu') +subdir('system') # Work around a gcc bug/misfeature wherein constant propagation looks # through an alias: @@ -3797,14 +3797,14 @@ foreach target : target_dirs execs = [{ 'name': 'qemu-system-' + target_name, 'win_subsystem': 'console', - 'sources': files('softmmu/main.c'), + 'sources': files('system/main.c'), 'dependencies': [] }] if targetos == 'windows' and (sdl.found() or gtk.found()) execs += [{ 'name': 'qemu-system-' + target_name + 'w', 'win_subsystem': 'windows', - 'sources': files('softmmu/main.c'), + 'sources': files('system/main.c'), 'dependencies': [] }] endif diff --git a/scripts/checkpatch.pl b/scripts/checkpatch.pl index 1ad9ccb74b..6e4100d2a4 100755 --- a/scripts/checkpatch.pl +++ b/scripts/checkpatch.pl @@ -466,7 +466,7 @@ sub top_of_kernel_tree { my @tree_check = ( "COPYING", "MAINTAINERS", "Makefile", "README.rst", "docs", "VERSION", - "linux-user", "softmmu" + "linux-user", "system" ); foreach my $check (@tree_check) { diff --git a/scripts/coverity-scan/COMPONENTS.md b/scripts/coverity-scan/COMPONENTS.md index 883da95aff..0e62f10aad 100644 --- a/scripts/coverity-scan/COMPONENTS.md +++ b/scripts/coverity-scan/COMPONENTS.md @@ -148,7 +148,7 @@ tcg ~ (/qemu)?(/accel/tcg|/replay|/tcg)/.* sysemu - ~ (/qemu)?(/softmmu/.*|/accel/.*) + ~ (/qemu)?(/system/.*|/accel/.*) (headers) ~ (/qemu)?(/include/.*) diff --git a/scripts/get_maintainer.pl b/scripts/get_maintainer.pl index e5499b94b4..02fa828100 100755 --- a/scripts/get_maintainer.pl +++ b/scripts/get_maintainer.pl @@ -796,7 +796,7 @@ sub top_of_tree { && (-d "${lk_path}docs") && (-f "${lk_path}VERSION") && (-d "${lk_path}linux-user/") - && (-d "${lk_path}softmmu/")) { + && (-d "${lk_path}system/")) { return 1; } return 0; diff --git a/scripts/oss-fuzz/build.sh b/scripts/oss-fuzz/build.sh index 3bda0d72c7..5238f83343 100755 --- a/scripts/oss-fuzz/build.sh +++ b/scripts/oss-fuzz/build.sh @@ -43,10 +43,10 @@ EXTRA_CFLAGS="$CFLAGS -U __OPTIMIZE__" if ! { [ -e "./COPYING" ] && [ -e "./MAINTAINERS" ] && [ -e "./Makefile" ] && - [ -e "./docs" ] && + [ -d "./docs" ] && [ -e "./VERSION" ] && - [ -e "./linux-user" ] && - [ -e "./softmmu" ];} ; then + [ -d "./linux-user" ] && + [ -d "./system" ];} ; then fatal "Please run the script from the top of the QEMU tree" fi diff --git a/softmmu/trace.h b/softmmu/trace.h deleted file mode 100644 index 2ad1011572..0000000000 --- a/softmmu/trace.h +++ /dev/null @@ -1 +0,0 @@ -#include "trace/trace-softmmu.h" diff --git a/softmmu/arch_init.c b/system/arch_init.c similarity index 100% rename from softmmu/arch_init.c rename to system/arch_init.c diff --git a/softmmu/async-teardown.c b/system/async-teardown.c similarity index 100% rename from softmmu/async-teardown.c rename to system/async-teardown.c diff --git a/softmmu/balloon.c b/system/balloon.c similarity index 100% rename from softmmu/balloon.c rename to system/balloon.c diff --git a/softmmu/bootdevice.c b/system/bootdevice.c similarity index 100% rename from softmmu/bootdevice.c rename to system/bootdevice.c diff --git a/softmmu/cpu-throttle.c b/system/cpu-throttle.c similarity index 100% rename from softmmu/cpu-throttle.c rename to system/cpu-throttle.c diff --git a/softmmu/cpu-timers.c b/system/cpu-timers.c similarity index 99% rename from softmmu/cpu-timers.c rename to system/cpu-timers.c index 117408cb83..7452d97b67 100644 --- a/softmmu/cpu-timers.c +++ b/system/cpu-timers.c @@ -36,7 +36,7 @@ #include "hw/core/cpu.h" #include "sysemu/cpu-timers.h" #include "sysemu/cpu-throttle.h" -#include "timers-state.h" +#include "sysemu/cpu-timers-internal.h" /* clock and ticks */ diff --git a/softmmu/cpus.c b/system/cpus.c similarity index 100% rename from softmmu/cpus.c rename to system/cpus.c diff --git a/softmmu/datadir.c b/system/datadir.c similarity index 100% rename from softmmu/datadir.c rename to system/datadir.c diff --git a/softmmu/device_tree.c b/system/device_tree.c similarity index 100% rename from softmmu/device_tree.c rename to system/device_tree.c diff --git a/softmmu/dirtylimit.c b/system/dirtylimit.c similarity index 100% rename from softmmu/dirtylimit.c rename to system/dirtylimit.c diff --git a/softmmu/dma-helpers.c b/system/dma-helpers.c similarity index 100% rename from softmmu/dma-helpers.c rename to system/dma-helpers.c diff --git a/softmmu/globals.c b/system/globals.c similarity index 100% rename from softmmu/globals.c rename to system/globals.c diff --git a/softmmu/ioport.c b/system/ioport.c similarity index 100% rename from softmmu/ioport.c rename to system/ioport.c diff --git a/softmmu/main.c b/system/main.c similarity index 100% rename from softmmu/main.c rename to system/main.c diff --git a/softmmu/memory.c b/system/memory.c similarity index 100% rename from softmmu/memory.c rename to system/memory.c diff --git a/softmmu/memory_mapping.c b/system/memory_mapping.c similarity index 100% rename from softmmu/memory_mapping.c rename to system/memory_mapping.c diff --git a/softmmu/meson.build b/system/meson.build similarity index 100% rename from softmmu/meson.build rename to system/meson.build diff --git a/softmmu/physmem.c b/system/physmem.c similarity index 99% rename from softmmu/physmem.c rename to system/physmem.c index 309653c722..edc3ed8ab9 100644 --- a/softmmu/physmem.c +++ b/system/physmem.c @@ -2301,8 +2301,10 @@ RAMBlock *qemu_ram_block_by_name(const char *name) return NULL; } -/* Some of the softmmu routines need to translate from a host pointer - (typically a TLB entry) back to a ram offset. */ +/* + * Some of the system routines need to translate from a host pointer + * (typically a TLB entry) back to a ram offset. + */ ram_addr_t qemu_ram_addr_from_host(void *ptr) { RAMBlock *block; diff --git a/softmmu/qdev-monitor.c b/system/qdev-monitor.c similarity index 100% rename from softmmu/qdev-monitor.c rename to system/qdev-monitor.c diff --git a/softmmu/qemu-seccomp.c b/system/qemu-seccomp.c similarity index 100% rename from softmmu/qemu-seccomp.c rename to system/qemu-seccomp.c diff --git a/softmmu/qtest.c b/system/qtest.c similarity index 100% rename from softmmu/qtest.c rename to system/qtest.c diff --git a/softmmu/rtc.c b/system/rtc.c similarity index 100% rename from softmmu/rtc.c rename to system/rtc.c diff --git a/softmmu/runstate-action.c b/system/runstate-action.c similarity index 100% rename from softmmu/runstate-action.c rename to system/runstate-action.c diff --git a/softmmu/runstate-hmp-cmds.c b/system/runstate-hmp-cmds.c similarity index 100% rename from softmmu/runstate-hmp-cmds.c rename to system/runstate-hmp-cmds.c diff --git a/softmmu/runstate.c b/system/runstate.c similarity index 100% rename from softmmu/runstate.c rename to system/runstate.c diff --git a/softmmu/tpm-hmp-cmds.c b/system/tpm-hmp-cmds.c similarity index 100% rename from softmmu/tpm-hmp-cmds.c rename to system/tpm-hmp-cmds.c diff --git a/softmmu/tpm.c b/system/tpm.c similarity index 100% rename from softmmu/tpm.c rename to system/tpm.c diff --git a/softmmu/trace-events b/system/trace-events similarity index 100% rename from softmmu/trace-events rename to system/trace-events diff --git a/system/trace.h b/system/trace.h new file mode 100644 index 0000000000..cd0136dcdc --- /dev/null +++ b/system/trace.h @@ -0,0 +1 @@ +#include "trace/trace-system.h" diff --git a/softmmu/vl.c b/system/vl.c similarity index 100% rename from softmmu/vl.c rename to system/vl.c diff --git a/softmmu/watchpoint.c b/system/watchpoint.c similarity index 100% rename from softmmu/watchpoint.c rename to system/watchpoint.c diff --git a/tests/unit/meson.build b/tests/unit/meson.build index 1977b302e2..f33ae64b8d 100644 --- a/tests/unit/meson.build +++ b/tests/unit/meson.build @@ -59,7 +59,7 @@ if have_system or have_tools } if seccomp.found() - tests += {'test-seccomp': ['../../softmmu/qemu-seccomp.c', seccomp]} + tests += {'test-seccomp': ['../../system/qemu-seccomp.c', seccomp]} endif endif From 24f9c07ac0b6acc38b8790b101d32944a2b64739 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Wed, 4 Oct 2023 15:46:56 +0200 Subject: [PATCH 0395/1077] configure: change $softmmu to $system "softmmu" is a deprecated moniker, do the easy change matching the variable to the command line option. Signed-off-by: Paolo Bonzini --- configure | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/configure b/configure index e08127045d..97a5e8de49 100755 --- a/configure +++ b/configure @@ -252,7 +252,7 @@ docs="auto" EXESUF="" prefix="/usr/local" qemu_suffix="qemu" -softmmu="yes" +system="yes" linux_user="" bsd_user="" plugins="$default_feature" @@ -740,9 +740,9 @@ for opt do ;; --enable-tcg) tcg="enabled" ;; - --disable-system) softmmu="no" + --disable-system) system="no" ;; - --enable-system) softmmu="yes" + --enable-system) system="yes" ;; --disable-user) linux_user="no" ; @@ -864,7 +864,7 @@ else error_exit "user mode emulation not supported on this architecture" fi fi -if [ "$softmmu" = "yes" ]; then +if [ "$system" = "yes" ]; then mak_wilds="${mak_wilds} $source_path/configs/targets/*-softmmu.mak" fi @@ -1756,7 +1756,7 @@ for target in $target_list; do case $target in xtensa*-linux-user) - # the toolchain is not complete with headers, only build softmmu tests + # the toolchain is not complete with headers, only build system tests continue ;; *-softmmu) From a492e287e5d5d2b888e5f2580b4e9e41b6057a05 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Thu, 5 Oct 2023 14:48:50 +0200 Subject: [PATCH 0396/1077] cutils: squelch compiler warnings with custom paths Setting --bindir= to an absolute path that is shorter than the prefix causes GCC to complain about array accesses out of bounds. The code however is safe, so disable the warning and explain why we are doing so. Signed-off-by: Paolo Bonzini --- util/cutils.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/util/cutils.c b/util/cutils.c index 25373198ad..3856e304c5 100644 --- a/util/cutils.c +++ b/util/cutils.c @@ -1012,8 +1012,17 @@ int qemu_pstrcmp0(const char **str1, const char **str2) static inline bool starts_with_prefix(const char *dir) { size_t prefix_len = strlen(CONFIG_PREFIX); + /* + * dir[prefix_len] is only accessed if the length of dir is + * >= prefix_len, so no out of bounds access is possible. + */ +#pragma GCC diagnostic push +#if !defined(__clang__) || __has_warning("-Warray-bounds=") +#pragma GCC diagnostic ignored "-Warray-bounds=" +#endif return !memcmp(dir, CONFIG_PREFIX, prefix_len) && (!dir[prefix_len] || G_IS_DIR_SEPARATOR(dir[prefix_len])); +#pragma GCC diagnostic pop } /* Return the next path component in dir, and store its length in *p_len. */ From c7c5caeb1f314c5662a3b2985fe3befebf45b650 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Thu, 5 Oct 2023 12:36:39 +0200 Subject: [PATCH 0397/1077] audio: error hints need a trailing \n Signed-off-by: Paolo Bonzini --- audio/audio.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/audio/audio.c b/audio/audio.c index 730bf2498d..98621576d9 100644 --- a/audio/audio.c +++ b/audio/audio.c @@ -1833,7 +1833,7 @@ bool AUD_register_card (const char *name, QEMUSoundCard *card, Error **errp) card->state = audio_init(NULL, errp); if (!card->state) { if (!QSIMPLEQ_EMPTY(&audiodevs)) { - error_append_hint(errp, "Perhaps you wanted to set audiodev=%s?", + error_append_hint(errp, "Perhaps you wanted to set audiodev=%s?\n", QSIMPLEQ_FIRST(&audiodevs)->dev->id); } return false; From c753bf479ab75fe245c2de6a414b60b9e25a2bd7 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Thu, 5 Oct 2023 11:55:03 +0200 Subject: [PATCH 0398/1077] audio: disable default backends if -audio/-audiodev is used Match what is done for other options, for example -monitor, and also the behavior of QEMU 8.1 (see the "legacy_config" variable). Require the user to specify a backend if one is specified on the command line. Signed-off-by: Paolo Bonzini --- audio/audio.c | 9 +-------- audio/audio.h | 1 + docs/about/removed-features.rst | 3 +++ system/vl.c | 7 +++++++ 4 files changed, 12 insertions(+), 8 deletions(-) diff --git a/audio/audio.c b/audio/audio.c index 98621576d9..67a7e25254 100644 --- a/audio/audio.c +++ b/audio/audio.c @@ -1688,14 +1688,10 @@ static const VMStateDescription vmstate_audio = { static void audio_validate_opts(Audiodev *dev, Error **errp); -static void audio_create_default_audiodevs(void) +void audio_create_default_audiodevs(void) { const char *drvname = getenv("QEMU_AUDIO_DRV"); - if (!defaults_enabled()) { - return; - } - /* QEMU_AUDIO_DRV=none is used by libqtest. */ if (drvname && !g_str_equal(drvname, "none")) { error_report("Please use -audiodev instead of QEMU_AUDIO_*"); @@ -1827,9 +1823,6 @@ bool AUD_register_card (const char *name, QEMUSoundCard *card, Error **errp) } card->state = QTAILQ_FIRST(&audio_states); } else { - if (QSIMPLEQ_EMPTY(&default_audiodevs)) { - audio_create_default_audiodevs(); - } card->state = audio_init(NULL, errp); if (!card->state) { if (!QSIMPLEQ_EMPTY(&audiodevs)) { diff --git a/audio/audio.h b/audio/audio.h index 80f3f92124..53b1d7e622 100644 --- a/audio/audio.h +++ b/audio/audio.h @@ -170,6 +170,7 @@ void audio_sample_from_uint64(void *samples, int pos, void audio_define(Audiodev *audio); void audio_parse_option(const char *opt); +void audio_create_default_audiodevs(void); void audio_init_audiodevs(void); void audio_help(void); diff --git a/docs/about/removed-features.rst b/docs/about/removed-features.rst index e83ed087f6..8a0a8fe076 100644 --- a/docs/about/removed-features.rst +++ b/docs/about/removed-features.rst @@ -442,6 +442,9 @@ line using a ``secret`` object instance. The ``-audiodev`` and ``-audio`` command line options are now the only way to specify audio backend settings. +Note that the default audio backend must be configured on the command +line if the ``-nodefaults`` options is used. + Creating vnc without ``audiodev=`` property (removed in 8.2) '''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' diff --git a/system/vl.c b/system/vl.c index 98e071e63b..7ca92d4490 100644 --- a/system/vl.c +++ b/system/vl.c @@ -184,6 +184,7 @@ static const char *qtest_log; static bool opt_one_insn_per_tb; static int has_defaults = 1; +static int default_audio = 1; static int default_serial = 1; static int default_parallel = 1; static int default_monitor = 1; @@ -1327,6 +1328,7 @@ static void qemu_disable_default_devices(void) default_sdcard = 0; } if (!has_defaults) { + default_audio = 0; default_monitor = 0; default_net = 0; default_vga = 0; @@ -1963,6 +1965,9 @@ static void qemu_create_early_backends(void) */ configure_blockdev(&bdo_queue, machine_class, snapshot); audio_init_audiodevs(); + if (default_audio) { + audio_create_default_audiodevs(); + } } @@ -2925,6 +2930,7 @@ void qemu_init(int argc, char **argv) break; #endif case QEMU_OPTION_audiodev: + default_audio = 0; audio_parse_option(optarg); break; case QEMU_OPTION_audio: { @@ -2933,6 +2939,7 @@ void qemu_init(int argc, char **argv) Audiodev *dev = NULL; Visitor *v; QDict *dict = keyval_parse(optarg, "driver", &help, &error_fatal); + default_audio = 0; if (help || (qdict_haskey(dict, "driver") && is_help_option(qdict_get_str(dict, "driver")))) { audio_help(); From 8f527a3c0d2866df1affe8f0fb8ab73fbbb8ac52 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Thu, 5 Oct 2023 12:17:28 +0200 Subject: [PATCH 0399/1077] audio: extract audio_define_default It will be used soon to define a default audio device from the command line. Signed-off-by: Paolo Bonzini --- audio/audio.c | 19 ++++++++++++------- audio/audio.h | 1 + 2 files changed, 13 insertions(+), 7 deletions(-) diff --git a/audio/audio.c b/audio/audio.c index 67a7e25254..887219e0ce 100644 --- a/audio/audio.c +++ b/audio/audio.c @@ -1686,8 +1686,6 @@ static const VMStateDescription vmstate_audio = { } }; -static void audio_validate_opts(Audiodev *dev, Error **errp); - void audio_create_default_audiodevs(void) { const char *drvname = getenv("QEMU_AUDIO_DRV"); @@ -1706,7 +1704,6 @@ void audio_create_default_audiodevs(void) if (audio_driver_lookup(audio_prio_list[i])) { QDict *dict = qdict_new(); Audiodev *dev = NULL; - AudiodevListEntry *e; Visitor *v; qdict_put_str(dict, "driver", audio_prio_list[i]); @@ -1717,10 +1714,7 @@ void audio_create_default_audiodevs(void) visit_type_Audiodev(v, NULL, &dev, &error_fatal); visit_free(v); - audio_validate_opts(dev, &error_abort); - e = g_new0(AudiodevListEntry, 1); - e->dev = dev; - QSIMPLEQ_INSERT_TAIL(&default_audiodevs, e, next); + audio_define_default(dev, &error_abort); } } } @@ -2165,6 +2159,17 @@ void audio_define(Audiodev *dev) QSIMPLEQ_INSERT_TAIL(&audiodevs, e, next); } +void audio_define_default(Audiodev *dev, Error **errp) +{ + AudiodevListEntry *e; + + audio_validate_opts(dev, errp); + + e = g_new0(AudiodevListEntry, 1); + e->dev = dev; + QSIMPLEQ_INSERT_TAIL(&default_audiodevs, e, next); +} + void audio_init_audiodevs(void) { AudiodevListEntry *e; diff --git a/audio/audio.h b/audio/audio.h index 53b1d7e622..6da5e8f6f0 100644 --- a/audio/audio.h +++ b/audio/audio.h @@ -169,6 +169,7 @@ void audio_sample_from_uint64(void *samples, int pos, uint64_t left, uint64_t right); void audio_define(Audiodev *audio); +void audio_define_default(Audiodev *dev, Error **errp); void audio_parse_option(const char *opt); void audio_create_default_audiodevs(void); void audio_init_audiodevs(void); From 1ebdbff4c37d820b6a97d4c6f24aa38dae302b51 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Thu, 21 Sep 2023 10:23:58 +0200 Subject: [PATCH 0400/1077] audio: extend -audio to allow creating a default backend If "-audio BACKEND" is used without a model, the resulting backend will be used whenever the audiodev property is not specified. Signed-off-by: Paolo Bonzini --- audio/audio.c | 2 +- qemu-options.hx | 29 +++++++++++++++++++++-------- system/vl.c | 27 +++++++++++++++------------ 3 files changed, 37 insertions(+), 21 deletions(-) diff --git a/audio/audio.c b/audio/audio.c index 887219e0ce..a5e6eb4952 100644 --- a/audio/audio.c +++ b/audio/audio.c @@ -1820,7 +1820,7 @@ bool AUD_register_card (const char *name, QEMUSoundCard *card, Error **errp) card->state = audio_init(NULL, errp); if (!card->state) { if (!QSIMPLEQ_EMPTY(&audiodevs)) { - error_append_hint(errp, "Perhaps you wanted to set audiodev=%s?\n", + error_append_hint(errp, "Perhaps you wanted to use -audio or set audiodev=%s?\n", QSIMPLEQ_FIRST(&audiodevs)->dev->id); } return false; diff --git a/qemu-options.hx b/qemu-options.hx index 840b83d237..54a7e94970 100644 --- a/qemu-options.hx +++ b/qemu-options.hx @@ -728,20 +728,22 @@ ERST DEF("audio", HAS_ARG, QEMU_OPTION_audio, + "-audio [driver=]driver[,prop[=value][,...]]\n" + " specifies default audio backend when `audiodev` is not\n" + " used to create a machine or sound device;" + " options are the same as for -audiodev\n" "-audio [driver=]driver,model=value[,prop[=value][,...]]\n" " specifies the audio backend and device to use;\n" " apart from 'model', options are the same as for -audiodev.\n" " use '-audio model=help' to show possible devices.\n", QEMU_ARCH_ALL) SRST -``-audio [driver=]driver,model=value[,prop[=value][,...]]`` - This option is a shortcut for configuring both the guest audio - hardware and the host audio backend in one go. - The driver option is the same as with the corresponding ``-audiodev`` option below. - The guest hardware model can be set with ``model=modelname``. - - Use ``driver=help`` to list the available drivers, - and ``model=help`` to list the available device types. +``-audio [driver=]driver[,model=value][,prop[=value][,...]]`` + If the ``model`` option is specified, ``-audio`` is a shortcut + for configuring both the guest audio hardware and the host audio + backend in one go. The guest hardware model can be set with + ``model=modelname``. Use ``model=help`` to list the available + device types. The following two example do exactly the same, to show how ``-audio`` can be used to shorten the command line length: @@ -750,6 +752,17 @@ SRST |qemu_system| -audiodev pa,id=pa -device sb16,audiodev=pa |qemu_system| -audio pa,model=sb16 + + If the ``model`` option is not specified, ``-audio`` is used to + configure a default audio backend that will be used whenever the + ``audiodev`` property is not set on a device or machine. In + particular, ``-audio none`` ensures that no audio is produced even + for machines that have embedded sound hardware. + + In both cases, the driver option is the same as with the corresponding + ``-audiodev`` option below. Use ``driver=help`` to list the available + drivers. + ERST DEF("audiodev", HAS_ARG, QEMU_OPTION_audiodev, diff --git a/system/vl.c b/system/vl.c index 7ca92d4490..72be5a4976 100644 --- a/system/vl.c +++ b/system/vl.c @@ -2935,7 +2935,7 @@ void qemu_init(int argc, char **argv) break; case QEMU_OPTION_audio: { bool help; - char *model; + char *model = NULL; Audiodev *dev = NULL; Visitor *v; QDict *dict = keyval_parse(optarg, "driver", &help, &error_fatal); @@ -2948,22 +2948,25 @@ void qemu_init(int argc, char **argv) if (!qdict_haskey(dict, "id")) { qdict_put_str(dict, "id", "audiodev0"); } - if (!qdict_haskey(dict, "model")) { - error_setg(&error_fatal, "Parameter 'model' is missing"); - } - model = g_strdup(qdict_get_str(dict, "model")); - qdict_del(dict, "model"); - if (is_help_option(model)) { - show_valid_soundhw(); - exit(0); + if (qdict_haskey(dict, "model")) { + model = g_strdup(qdict_get_str(dict, "model")); + qdict_del(dict, "model"); + if (is_help_option(model)) { + show_valid_soundhw(); + exit(0); + } } v = qobject_input_visitor_new_keyval(QOBJECT(dict)); qobject_unref(dict); visit_type_Audiodev(v, NULL, &dev, &error_fatal); visit_free(v); - audio_define(dev); - select_soundhw(model, dev->id); - g_free(model); + if (model) { + audio_define(dev); + select_soundhw(model, dev->id); + g_free(model); + } else { + audio_define_default(dev, &error_fatal); + } break; } case QEMU_OPTION_h: From 22f84d4f7882d881a5f8574430da62c7ce5a0731 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Thu, 5 Oct 2023 17:09:36 +0200 Subject: [PATCH 0401/1077] audio: do not use first -audiodev as default audio device It is now possible to specify the options for the default audio device using -audio, so there is no need anymore to use a fake -audiodev option. Remove the fall back to QTAILQ_FIRST(&audio_states), instead remember the AudioState that was created from default_audiodevs and use that one. Signed-off-by: Paolo Bonzini --- audio/audio.c | 25 +++++++------------------ docs/about/deprecated.rst | 6 ------ docs/about/removed-features.rst | 15 +++++++++++++++ 3 files changed, 22 insertions(+), 24 deletions(-) diff --git a/audio/audio.c b/audio/audio.c index a5e6eb4952..bd4bcabcca 100644 --- a/audio/audio.c +++ b/audio/audio.c @@ -104,6 +104,7 @@ static audio_driver *audio_driver_lookup(const char *name) static QTAILQ_HEAD(AudioStateHead, AudioState) audio_states = QTAILQ_HEAD_INITIALIZER(audio_states); +static AudioState *default_audio_state; const struct mixeng_volume nominal_volume = { .mute = 0, @@ -1660,6 +1661,7 @@ static void free_audio_state(AudioState *s) void audio_cleanup(void) { + default_audio_state = NULL; while (!QTAILQ_EMPTY(&audio_states)) { AudioState *s = QTAILQ_FIRST(&audio_states); QTAILQ_REMOVE(&audio_states, s, list); @@ -1760,6 +1762,7 @@ static AudioState *audio_init(Audiodev *dev, Error **errp) goto out; } } else { + assert(!default_audio_state); for (;;) { AudiodevListEntry *e = QSIMPLEQ_FIRST(&default_audiodevs); if (!e) { @@ -1801,24 +1804,9 @@ out: bool AUD_register_card (const char *name, QEMUSoundCard *card, Error **errp) { if (!card->state) { - if (!QTAILQ_EMPTY(&audio_states)) { - /* - * FIXME: once it is possible to create an arbitrary - * default device via -audio DRIVER,OPT=VALUE (no "model"), - * replace this special case with the default AudioState*, - * storing it in a separate global. For now, keep the - * warning to encourage moving off magic use of the first - * -audiodev. - */ - if (QSIMPLEQ_EMPTY(&default_audiodevs)) { - dolog("Device %s: audiodev default parameter is deprecated, please " - "specify audiodev=%s\n", name, - QTAILQ_FIRST(&audio_states)->dev->id); - } - card->state = QTAILQ_FIRST(&audio_states); - } else { - card->state = audio_init(NULL, errp); - if (!card->state) { + if (!default_audio_state) { + default_audio_state = audio_init(NULL, errp); + if (!default_audio_state) { if (!QSIMPLEQ_EMPTY(&audiodevs)) { error_append_hint(errp, "Perhaps you wanted to use -audio or set audiodev=%s?\n", QSIMPLEQ_FIRST(&audiodevs)->dev->id); @@ -1826,6 +1814,7 @@ bool AUD_register_card (const char *name, QEMUSoundCard *card, Error **errp) return false; } } + card->state = default_audio_state; } card->name = g_strdup (name); diff --git a/docs/about/deprecated.rst b/docs/about/deprecated.rst index 3b074b9ed4..8b136320e2 100644 --- a/docs/about/deprecated.rst +++ b/docs/about/deprecated.rst @@ -23,12 +23,6 @@ deprecated. System emulator command line arguments -------------------------------------- -Creating sound card devices without ``audiodev=`` property (since 4.2) -'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' - -When not using the deprecated legacy audio config, each sound card -should specify an ``audiodev=`` property. - Short-form boolean options (since 6.0) '''''''''''''''''''''''''''''''''''''' diff --git a/docs/about/removed-features.rst b/docs/about/removed-features.rst index 8a0a8fe076..ed94b4cd0c 100644 --- a/docs/about/removed-features.rst +++ b/docs/about/removed-features.rst @@ -442,6 +442,21 @@ line using a ``secret`` object instance. The ``-audiodev`` and ``-audio`` command line options are now the only way to specify audio backend settings. +Using ``-audiodev`` to define the default audio backend (removed in 8.2) +'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' + +If no audiodev property is specified, previous versions would use the +first ``-audiodev`` command line option as a fallback. Starting with +version 8.2, audio backends created with ``-audiodev`` will only be +used by clients (sound cards, machines with embedded sound hardware, VNC) +that refer to it in an ``audiodev=`` property. + +In order to configure a default audio backend, use the ``-audio`` +command line option without specifying a ``model``; while previous +versions of QEMU required a model, starting with version 8.2 +QEMU does not require a model and will not create any sound card +in this case. + Note that the default audio backend must be configured on the command line if the ``-nodefaults`` options is used. From 63a13c08055072e92129a1d0ffeeecdcac6ad3d4 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Thu, 5 Oct 2023 18:42:54 +0200 Subject: [PATCH 0402/1077] audio: reintroduce default audio backend for VNC Make VNC use the default backend again if one is defined. The recently introduced support for disabling the VNC audio extension is still used, in case no default backend exists. Signed-off-by: Paolo Bonzini --- audio/audio.c | 28 ++++++++++++++++++---------- audio/audio.h | 1 + docs/about/removed-features.rst | 6 ------ ui/vnc.c | 2 ++ 4 files changed, 21 insertions(+), 16 deletions(-) diff --git a/audio/audio.c b/audio/audio.c index bd4bcabcca..73b65dc3b9 100644 --- a/audio/audio.c +++ b/audio/audio.c @@ -1801,20 +1801,28 @@ out: return NULL; } +AudioState *audio_get_default_audio_state(Error **errp) +{ + if (!default_audio_state) { + default_audio_state = audio_init(NULL, errp); + if (!default_audio_state) { + if (!QSIMPLEQ_EMPTY(&audiodevs)) { + error_append_hint(errp, "Perhaps you wanted to use -audio or set audiodev=%s?\n", + QSIMPLEQ_FIRST(&audiodevs)->dev->id); + } + } + } + + return default_audio_state; +} + bool AUD_register_card (const char *name, QEMUSoundCard *card, Error **errp) { if (!card->state) { - if (!default_audio_state) { - default_audio_state = audio_init(NULL, errp); - if (!default_audio_state) { - if (!QSIMPLEQ_EMPTY(&audiodevs)) { - error_append_hint(errp, "Perhaps you wanted to use -audio or set audiodev=%s?\n", - QSIMPLEQ_FIRST(&audiodevs)->dev->id); - } - return false; - } + card->state = audio_get_default_audio_state(errp); + if (!card->state) { + return false; } - card->state = default_audio_state; } card->name = g_strdup (name); diff --git a/audio/audio.h b/audio/audio.h index 6da5e8f6f0..fcc22307be 100644 --- a/audio/audio.h +++ b/audio/audio.h @@ -176,6 +176,7 @@ void audio_init_audiodevs(void); void audio_help(void); AudioState *audio_state_by_name(const char *name, Error **errp); +AudioState *audio_get_default_audio_state(Error **errp); const char *audio_get_id(QEMUSoundCard *card); #define DEFINE_AUDIO_PROPERTIES(_s, _f) \ diff --git a/docs/about/removed-features.rst b/docs/about/removed-features.rst index ed94b4cd0c..f04036987b 100644 --- a/docs/about/removed-features.rst +++ b/docs/about/removed-features.rst @@ -460,12 +460,6 @@ in this case. Note that the default audio backend must be configured on the command line if the ``-nodefaults`` options is used. -Creating vnc without ``audiodev=`` property (removed in 8.2) -'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' - -When using vnc, you should specify an ``audiodev=`` property if -you plan to transmit audio through the VNC protocol. - QEMU Machine Protocol (QMP) commands ------------------------------------ diff --git a/ui/vnc.c b/ui/vnc.c index 6056028e49..4f23a0fa79 100644 --- a/ui/vnc.c +++ b/ui/vnc.c @@ -4185,6 +4185,8 @@ void vnc_display_open(const char *id, Error **errp) if (!vd->audio_state) { goto fail; } + } else { + vd->audio_state = audio_get_default_audio_state(NULL); } device_id = qemu_opt_get(opts, "display"); From 912eef205ae9ccfd477c343a51a7c2dcfae2ba43 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Thu, 5 Oct 2023 11:45:55 +0200 Subject: [PATCH 0403/1077] audio, qtest: get rid of QEMU_AUDIO_DRV Default audio devices can now be created with "-audio". Tests for soundcards were already using "-audiodev" if they want to specify a particular backend, for the others remove the last remnants of legacy audio configuration. Signed-off-by: Paolo Bonzini --- audio/audio.c | 12 ------------ tests/qtest/libqtest.c | 4 +--- 2 files changed, 1 insertion(+), 15 deletions(-) diff --git a/audio/audio.c b/audio/audio.c index 73b65dc3b9..e9815d6812 100644 --- a/audio/audio.c +++ b/audio/audio.c @@ -1690,19 +1690,7 @@ static const VMStateDescription vmstate_audio = { void audio_create_default_audiodevs(void) { - const char *drvname = getenv("QEMU_AUDIO_DRV"); - - /* QEMU_AUDIO_DRV=none is used by libqtest. */ - if (drvname && !g_str_equal(drvname, "none")) { - error_report("Please use -audiodev instead of QEMU_AUDIO_*"); - exit(1); - } - for (int i = 0; audio_prio_list[i]; i++) { - if (drvname && !g_str_equal(drvname, audio_prio_list[i])) { - continue; - } - if (audio_driver_lookup(audio_prio_list[i])) { QDict *dict = qdict_new(); Audiodev *dev = NULL; diff --git a/tests/qtest/libqtest.c b/tests/qtest/libqtest.c index b1eba71ffe..3f94a4f477 100644 --- a/tests/qtest/libqtest.c +++ b/tests/qtest/libqtest.c @@ -421,9 +421,6 @@ static QTestState *G_GNUC_PRINTF(1, 2) qtest_spawn_qemu(const char *fmt, ...) int sig = SIGKILL; procctl(P_PID, getpid(), PROC_PDEATHSIG_CTL, &sig); #endif /* __FreeBSD__ */ - if (!g_setenv("QEMU_AUDIO_DRV", "none", true)) { - exit(1); - } execlp("/bin/sh", "sh", "-c", command->str, NULL); exit(1); } @@ -464,6 +461,7 @@ QTestState *qtest_init_without_qmp_handshake(const char *extra_args) "-chardev socket,path=%s,id=char0 " "-mon chardev=char0,mode=control " "-display none " + "-audio none " "%s" " -accel qtest", socket_path, From 34a68001f16208a574cbef0cd2d4e2d681faa604 Mon Sep 17 00:00:00 2001 From: Andrei Gudkov Date: Tue, 5 Sep 2023 10:05:43 +0300 Subject: [PATCH 0404/1077] migration/calc-dirty-rate: millisecond-granularity period This patch allows to measure dirty page rate for sub-second intervals of time. An optional argument is introduced -- calc-time-unit. For example: {"execute": "calc-dirty-rate", "arguments": {"calc-time": 500, "calc-time-unit": "millisecond"} } Millisecond granularity allows to make predictions whether migration will succeed or not. To do this, calculate dirty rate with calc-time set to max allowed downtime (e.g. 300ms), convert measured rate into volume of dirtied memory, and divide by network throughput. If the value is lower than max allowed downtime, then migration will converge. Measurement results for single thread randomly writing to a 1/4/24GiB memory region: +----------------+-----------------------------------------------+ | calc-time | dirty rate MiB/s | | (milliseconds) +----------------+---------------+--------------+ | | theoretical | page-sampling | dirty-bitmap | | | (at 3M wr/sec) | | | +----------------+----------------+---------------+--------------+ | 1GiB | +----------------+----------------+---------------+--------------+ | 100 | 6996 | 7100 | 3192 | | 200 | 4606 | 4660 | 2655 | | 300 | 3305 | 3280 | 2371 | | 400 | 2534 | 2525 | 2154 | | 500 | 2041 | 2044 | 1871 | | 750 | 1365 | 1341 | 1358 | | 1000 | 1024 | 1052 | 1025 | | 1500 | 683 | 678 | 684 | | 2000 | 512 | 507 | 513 | +----------------+----------------+---------------+--------------+ | 4GiB | +----------------+----------------+---------------+--------------+ | 100 | 10232 | 8880 | 4070 | | 200 | 8954 | 8049 | 3195 | | 300 | 7889 | 7193 | 2881 | | 400 | 6996 | 6530 | 2700 | | 500 | 6245 | 5772 | 2312 | | 750 | 4829 | 4586 | 2465 | | 1000 | 3865 | 3780 | 2178 | | 1500 | 2694 | 2633 | 2004 | | 2000 | 2041 | 2031 | 1789 | +----------------+----------------+---------------+--------------+ | 24GiB | +----------------+----------------+---------------+--------------+ | 100 | 11495 | 8640 | 5597 | | 200 | 11226 | 8616 | 3527 | | 300 | 10965 | 8386 | 2355 | | 400 | 10713 | 8370 | 2179 | | 500 | 10469 | 8196 | 2098 | | 750 | 9890 | 7885 | 2556 | | 1000 | 9354 | 7506 | 2084 | | 1500 | 8397 | 6944 | 2075 | | 2000 | 7574 | 6402 | 2062 | +----------------+----------------+---------------+--------------+ Theoretical values are computed according to the following formula: size * (1 - (1-(4096/size))^(time*wps)) / (time * 2^20), where size is in bytes, time is in seconds, and wps is number of writes per second. Signed-off-by: Andrei Gudkov Reviewed-by: Hyman Huang Message-Id: Signed-off-by: Hyman Huang --- migration/dirtyrate.c | 107 +++++++++++++++++++++++++++++------------- migration/dirtyrate.h | 12 +++-- qapi/migration.json | 58 ++++++++++++++++++----- 3 files changed, 128 insertions(+), 49 deletions(-) diff --git a/migration/dirtyrate.c b/migration/dirtyrate.c index bccb3515e3..a461b28bb5 100644 --- a/migration/dirtyrate.c +++ b/migration/dirtyrate.c @@ -189,10 +189,9 @@ retry: return duration; } -static bool is_sample_period_valid(int64_t sec) +static bool is_calc_time_valid(int64_t msec) { - if (sec < MIN_FETCH_DIRTYRATE_TIME_SEC || - sec > MAX_FETCH_DIRTYRATE_TIME_SEC) { + if ((msec < MIN_CALC_TIME_MS) || (msec > MAX_CALC_TIME_MS)) { return false; } @@ -216,7 +215,39 @@ static int dirtyrate_set_state(int *state, int old_state, int new_state) } } -static struct DirtyRateInfo *query_dirty_rate_info(void) +/* Decimal power of given time unit relative to one second */ +static int time_unit_to_power(TimeUnit time_unit) +{ + switch (time_unit) { + case TIME_UNIT_SECOND: + return 0; + case TIME_UNIT_MILLISECOND: + return -3; + default: + assert(false); /* unreachable */ + return 0; + } +} + +static int64_t convert_time_unit(int64_t value, TimeUnit unit_from, + TimeUnit unit_to) +{ + int power = time_unit_to_power(unit_from) - + time_unit_to_power(unit_to); + while (power < 0) { + value /= 10; + power += 1; + } + while (power > 0) { + value *= 10; + power -= 1; + } + return value; +} + + +static struct DirtyRateInfo * +query_dirty_rate_info(TimeUnit calc_time_unit) { int i; int64_t dirty_rate = DirtyStat.dirty_rate; @@ -225,7 +256,10 @@ static struct DirtyRateInfo *query_dirty_rate_info(void) info->status = CalculatingState; info->start_time = DirtyStat.start_time; - info->calc_time = DirtyStat.calc_time; + info->calc_time = convert_time_unit(DirtyStat.calc_time_ms, + TIME_UNIT_MILLISECOND, + calc_time_unit); + info->calc_time_unit = calc_time_unit; info->sample_pages = DirtyStat.sample_pages; info->mode = dirtyrate_mode; @@ -264,7 +298,7 @@ static void init_dirtyrate_stat(int64_t start_time, { DirtyStat.dirty_rate = -1; DirtyStat.start_time = start_time; - DirtyStat.calc_time = config.sample_period_seconds; + DirtyStat.calc_time_ms = config.calc_time_ms; DirtyStat.sample_pages = config.sample_pages_per_gigabytes; switch (config.mode) { @@ -574,7 +608,6 @@ static inline void dirtyrate_manual_reset_protect(void) static void calculate_dirtyrate_dirty_bitmap(struct DirtyRateConfig config) { - int64_t msec = 0; int64_t start_time; DirtyPageRecord dirty_pages; @@ -602,9 +635,7 @@ static void calculate_dirtyrate_dirty_bitmap(struct DirtyRateConfig config) start_time = qemu_clock_get_ms(QEMU_CLOCK_REALTIME); DirtyStat.start_time = start_time / 1000; - msec = config.sample_period_seconds * 1000; - msec = dirty_stat_wait(msec, start_time); - DirtyStat.calc_time = msec / 1000; + DirtyStat.calc_time_ms = dirty_stat_wait(config.calc_time_ms, start_time); /* * do two things. @@ -615,12 +646,12 @@ static void calculate_dirtyrate_dirty_bitmap(struct DirtyRateConfig config) record_dirtypages_bitmap(&dirty_pages, false); - DirtyStat.dirty_rate = do_calculate_dirtyrate(dirty_pages, msec); + DirtyStat.dirty_rate = do_calculate_dirtyrate(dirty_pages, + DirtyStat.calc_time_ms); } static void calculate_dirtyrate_dirty_ring(struct DirtyRateConfig config) { - int64_t duration; uint64_t dirtyrate = 0; uint64_t dirtyrate_sum = 0; int i = 0; @@ -631,12 +662,10 @@ static void calculate_dirtyrate_dirty_ring(struct DirtyRateConfig config) DirtyStat.start_time = qemu_clock_get_ms(QEMU_CLOCK_REALTIME) / 1000; /* calculate vcpu dirtyrate */ - duration = vcpu_calculate_dirtyrate(config.sample_period_seconds * 1000, - &DirtyStat.dirty_ring, - GLOBAL_DIRTY_DIRTY_RATE, - true); - - DirtyStat.calc_time = duration / 1000; + DirtyStat.calc_time_ms = vcpu_calculate_dirtyrate(config.calc_time_ms, + &DirtyStat.dirty_ring, + GLOBAL_DIRTY_DIRTY_RATE, + true); /* calculate vm dirtyrate */ for (i = 0; i < DirtyStat.dirty_ring.nvcpu; i++) { @@ -652,7 +681,6 @@ static void calculate_dirtyrate_sample_vm(struct DirtyRateConfig config) { struct RamblockDirtyInfo *block_dinfo = NULL; int block_count = 0; - int64_t msec = 0; int64_t initial_time; rcu_read_lock(); @@ -662,17 +690,16 @@ static void calculate_dirtyrate_sample_vm(struct DirtyRateConfig config) } rcu_read_unlock(); - msec = config.sample_period_seconds * 1000; - msec = dirty_stat_wait(msec, initial_time); + DirtyStat.calc_time_ms = dirty_stat_wait(config.calc_time_ms, + initial_time); DirtyStat.start_time = initial_time / 1000; - DirtyStat.calc_time = msec / 1000; rcu_read_lock(); if (!compare_page_hash_info(block_dinfo, block_count)) { goto out; } - update_dirtyrate(msec); + update_dirtyrate(DirtyStat.calc_time_ms); out: rcu_read_unlock(); @@ -718,6 +745,8 @@ void *get_dirtyrate_thread(void *arg) } void qmp_calc_dirty_rate(int64_t calc_time, + bool has_calc_time_unit, + TimeUnit calc_time_unit, bool has_sample_pages, int64_t sample_pages, bool has_mode, @@ -737,10 +766,15 @@ void qmp_calc_dirty_rate(int64_t calc_time, return; } - if (!is_sample_period_valid(calc_time)) { - error_setg(errp, "calc-time is out of range[%d, %d].", - MIN_FETCH_DIRTYRATE_TIME_SEC, - MAX_FETCH_DIRTYRATE_TIME_SEC); + int64_t calc_time_ms = convert_time_unit( + calc_time, + has_calc_time_unit ? calc_time_unit : TIME_UNIT_SECOND, + TIME_UNIT_MILLISECOND + ); + + if (!is_calc_time_valid(calc_time_ms)) { + error_setg(errp, "Calculation time is out of range [%dms, %dms].", + MIN_CALC_TIME_MS, MAX_CALC_TIME_MS); return; } @@ -787,7 +821,7 @@ void qmp_calc_dirty_rate(int64_t calc_time, return; } - config.sample_period_seconds = calc_time; + config.calc_time_ms = calc_time_ms; config.sample_pages_per_gigabytes = sample_pages; config.mode = mode; @@ -806,14 +840,18 @@ void qmp_calc_dirty_rate(int64_t calc_time, (void *)&config, QEMU_THREAD_DETACHED); } -struct DirtyRateInfo *qmp_query_dirty_rate(Error **errp) + +struct DirtyRateInfo *qmp_query_dirty_rate(bool has_calc_time_unit, + TimeUnit calc_time_unit, + Error **errp) { - return query_dirty_rate_info(); + return query_dirty_rate_info( + has_calc_time_unit ? calc_time_unit : TIME_UNIT_SECOND); } void hmp_info_dirty_rate(Monitor *mon, const QDict *qdict) { - DirtyRateInfo *info = query_dirty_rate_info(); + DirtyRateInfo *info = query_dirty_rate_info(TIME_UNIT_SECOND); monitor_printf(mon, "Status: %s\n", DirtyRateStatus_str(info->status)); @@ -873,8 +911,11 @@ void hmp_calc_dirty_rate(Monitor *mon, const QDict *qdict) mode = DIRTY_RATE_MEASURE_MODE_DIRTY_RING; } - qmp_calc_dirty_rate(sec, has_sample_pages, sample_pages, true, - mode, &err); + qmp_calc_dirty_rate(sec, /* calc-time */ + false, TIME_UNIT_SECOND, /* calc-time-unit */ + has_sample_pages, sample_pages, + true, mode, + &err); if (err) { hmp_handle_error(mon, err); return; diff --git a/migration/dirtyrate.h b/migration/dirtyrate.h index 594a5c0bb6..869c060941 100644 --- a/migration/dirtyrate.h +++ b/migration/dirtyrate.h @@ -31,10 +31,12 @@ #define MIN_RAMBLOCK_SIZE 128 /* - * Take 1s as minimum time for calculation duration + * Allowed range for dirty page rate calculation (in milliseconds). + * Lower limit relates to the smallest realistic downtime it + * makes sense to impose on migration. */ -#define MIN_FETCH_DIRTYRATE_TIME_SEC 1 -#define MAX_FETCH_DIRTYRATE_TIME_SEC 60 +#define MIN_CALC_TIME_MS 50 +#define MAX_CALC_TIME_MS 60000 /* * Take 1/16 pages in 1G as the maxmum sample page count @@ -44,7 +46,7 @@ struct DirtyRateConfig { uint64_t sample_pages_per_gigabytes; /* sample pages per GB */ - int64_t sample_period_seconds; /* time duration between two sampling */ + int64_t calc_time_ms; /* desired calculation time (in milliseconds) */ DirtyRateMeasureMode mode; /* mode of dirtyrate measurement */ }; @@ -73,7 +75,7 @@ typedef struct SampleVMStat { struct DirtyRateStat { int64_t dirty_rate; /* dirty rate in MB/s */ int64_t start_time; /* calculation start time in units of second */ - int64_t calc_time; /* time duration of two sampling in units of second */ + int64_t calc_time_ms; /* actual calculation time (in milliseconds) */ uint64_t sample_pages; /* sample pages per GB */ union { SampleVMStat page_sampling; diff --git a/qapi/migration.json b/qapi/migration.json index 8843e74b59..1717aa4bbd 100644 --- a/qapi/migration.json +++ b/qapi/migration.json @@ -1836,6 +1836,21 @@ { 'enum': 'DirtyRateMeasureMode', 'data': ['page-sampling', 'dirty-ring', 'dirty-bitmap'] } +## +# @TimeUnit: +# +# Specifies unit in which time-related value is specified. +# +# @second: value is in seconds +# +# @millisecond: value is in milliseconds +# +# Since 8.2 +# +## +{ 'enum': 'TimeUnit', + 'data': ['second', 'millisecond'] } + ## # @DirtyRateInfo: # @@ -1848,8 +1863,10 @@ # # @start-time: start time in units of second for calculation # -# @calc-time: time period for which dirty page rate was measured -# (in seconds) +# @calc-time: time period for which dirty page rate was measured, +# expressed and rounded down to @calc-time-unit. +# +# @calc-time-unit: time unit of @calc-time (Since 8.2) # # @sample-pages: number of sampled pages per GiB of guest memory. # Valid only in page-sampling mode (Since 6.1) @@ -1866,6 +1883,7 @@ 'status': 'DirtyRateStatus', 'start-time': 'int64', 'calc-time': 'int64', + 'calc-time-unit': 'TimeUnit', 'sample-pages': 'uint64', 'mode': 'DirtyRateMeasureMode', '*vcpu-dirty-rate': [ 'DirtyRateVcpu' ] } } @@ -1901,12 +1919,16 @@ # This mode tracks page modification per each vCPU separately. It # requires that KVM accelerator property "dirty-ring-size" is set. # -# @calc-time: time period in units of second for which dirty page rate -# is calculated. Note that larger @calc-time values will -# typically result in smaller dirty page rates because page -# dirtying is a one-time event. Once some page is counted as -# dirty during @calc-time period, further writes to this page will -# not increase dirty page rate anymore. +# @calc-time: time period for which dirty page rate is calculated. +# By default it is specified in seconds, but the unit can be set +# explicitly with @calc-time-unit. Note that larger @calc-time +# values will typically result in smaller dirty page rates because +# page dirtying is a one-time event. Once some page is counted +# as dirty during @calc-time period, further writes to this page +# will not increase dirty page rate anymore. +# +# @calc-time-unit: time unit in which @calc-time is specified. +# By default it is seconds. (Since 8.2) # # @sample-pages: number of sampled pages per each GiB of guest memory. # Default value is 512. For 4KiB guest pages this corresponds to @@ -1924,8 +1946,16 @@ # -> {"execute": "calc-dirty-rate", "arguments": {"calc-time": 1, # 'sample-pages': 512} } # <- { "return": {} } +# +# Measure dirty rate using dirty bitmap for 500 milliseconds: +# +# -> {"execute": "calc-dirty-rate", "arguments": {"calc-time": 500, +# "calc-time-unit": "millisecond", "mode": "dirty-bitmap"} } +# +# <- { "return": {} } ## { 'command': 'calc-dirty-rate', 'data': {'calc-time': 'int64', + '*calc-time-unit': 'TimeUnit', '*sample-pages': 'int', '*mode': 'DirtyRateMeasureMode'} } @@ -1934,6 +1964,9 @@ # # Query results of the most recent invocation of @calc-dirty-rate. # +# @calc-time-unit: time unit in which to report calculation time. +# By default it is reported in seconds. (Since 8.2) +# # Since: 5.2 # # Examples: @@ -1941,14 +1974,17 @@ # 1. Measurement is in progress: # # <- {"status": "measuring", "sample-pages": 512, -# "mode": "page-sampling", "start-time": 3665220, "calc-time": 10} +# "mode": "page-sampling", "start-time": 3665220, "calc-time": 10, +# "calc-time-unit": "second"} # # 2. Measurement has been completed: # # <- {"status": "measured", "sample-pages": 512, "dirty-rate": 108, -# "mode": "page-sampling", "start-time": 3665220, "calc-time": 10} +# "mode": "page-sampling", "start-time": 3665220, "calc-time": 10, +# "calc-time-unit": "second"} ## -{ 'command': 'query-dirty-rate', 'returns': 'DirtyRateInfo' } +{ 'command': 'query-dirty-rate', 'data': {'*calc-time-unit': 'TimeUnit' }, + 'returns': 'DirtyRateInfo' } ## # @DirtyLimitInfo: From 320a6ccc769dc09ae7ad0b4838e322018f334bf4 Mon Sep 17 00:00:00 2001 From: Andrei Gudkov Date: Tue, 5 Sep 2023 12:18:39 +0300 Subject: [PATCH 0405/1077] migration/dirtyrate: use QEMU_CLOCK_HOST to report start-time Currently query-dirty-rate uses QEMU_CLOCK_REALTIME as the source for start-time field. This translates to clock_gettime(CLOCK_MONOTONIC), i.e. number of seconds since host boot. This is not very useful. The only reasonable use case of start-time I can imagine is to check whether previously completed measurements are too old or not. But this makes sense only if start-time is reported as host wall-clock time. This patch replaces source of start-time from QEMU_CLOCK_REALTIME to QEMU_CLOCK_HOST. Signed-off-by: Andrei Gudkov Reviewed-by: Hyman Huang Message-Id: <399861531e3b24a1ecea2ba453fb2c3d129fb03a.1693905328.git.gudkov.andrei@huawei.com> Signed-off-by: Hyman Huang --- migration/dirtyrate.c | 15 ++++++--------- qapi/migration.json | 4 ++-- 2 files changed, 8 insertions(+), 11 deletions(-) diff --git a/migration/dirtyrate.c b/migration/dirtyrate.c index a461b28bb5..036ac017fc 100644 --- a/migration/dirtyrate.c +++ b/migration/dirtyrate.c @@ -293,11 +293,10 @@ query_dirty_rate_info(TimeUnit calc_time_unit) return info; } -static void init_dirtyrate_stat(int64_t start_time, - struct DirtyRateConfig config) +static void init_dirtyrate_stat(struct DirtyRateConfig config) { DirtyStat.dirty_rate = -1; - DirtyStat.start_time = start_time; + DirtyStat.start_time = qemu_clock_get_ms(QEMU_CLOCK_HOST) / 1000; DirtyStat.calc_time_ms = config.calc_time_ms; DirtyStat.sample_pages = config.sample_pages_per_gigabytes; @@ -633,7 +632,7 @@ static void calculate_dirtyrate_dirty_bitmap(struct DirtyRateConfig config) record_dirtypages_bitmap(&dirty_pages, true); start_time = qemu_clock_get_ms(QEMU_CLOCK_REALTIME); - DirtyStat.start_time = start_time / 1000; + DirtyStat.start_time = qemu_clock_get_ms(QEMU_CLOCK_HOST) / 1000; DirtyStat.calc_time_ms = dirty_stat_wait(config.calc_time_ms, start_time); @@ -659,7 +658,7 @@ static void calculate_dirtyrate_dirty_ring(struct DirtyRateConfig config) /* start log sync */ global_dirty_log_change(GLOBAL_DIRTY_DIRTY_RATE, true); - DirtyStat.start_time = qemu_clock_get_ms(QEMU_CLOCK_REALTIME) / 1000; + DirtyStat.start_time = qemu_clock_get_ms(QEMU_CLOCK_HOST) / 1000; /* calculate vcpu dirtyrate */ DirtyStat.calc_time_ms = vcpu_calculate_dirtyrate(config.calc_time_ms, @@ -685,6 +684,7 @@ static void calculate_dirtyrate_sample_vm(struct DirtyRateConfig config) rcu_read_lock(); initial_time = qemu_clock_get_ms(QEMU_CLOCK_REALTIME); + DirtyStat.start_time = qemu_clock_get_ms(QEMU_CLOCK_HOST) / 1000; if (!record_ramblock_hash_info(&block_dinfo, config, &block_count)) { goto out; } @@ -692,7 +692,6 @@ static void calculate_dirtyrate_sample_vm(struct DirtyRateConfig config) DirtyStat.calc_time_ms = dirty_stat_wait(config.calc_time_ms, initial_time); - DirtyStat.start_time = initial_time / 1000; rcu_read_lock(); if (!compare_page_hash_info(block_dinfo, block_count)) { @@ -756,7 +755,6 @@ void qmp_calc_dirty_rate(int64_t calc_time, static struct DirtyRateConfig config; QemuThread thread; int ret; - int64_t start_time; /* * If the dirty rate is already being measured, don't attempt to start. @@ -833,8 +831,7 @@ void qmp_calc_dirty_rate(int64_t calc_time, **/ dirtyrate_mode = mode; - start_time = qemu_clock_get_ms(QEMU_CLOCK_REALTIME) / 1000; - init_dirtyrate_stat(start_time, config); + init_dirtyrate_stat(config); qemu_thread_create(&thread, "get_dirtyrate", get_dirtyrate_thread, (void *)&config, QEMU_THREAD_DETACHED); diff --git a/qapi/migration.json b/qapi/migration.json index 1717aa4bbd..d8f3bbd7b0 100644 --- a/qapi/migration.json +++ b/qapi/migration.json @@ -1974,13 +1974,13 @@ # 1. Measurement is in progress: # # <- {"status": "measuring", "sample-pages": 512, -# "mode": "page-sampling", "start-time": 3665220, "calc-time": 10, +# "mode": "page-sampling", "start-time": 1693900454, "calc-time": 10, # "calc-time-unit": "second"} # # 2. Measurement has been completed: # # <- {"status": "measured", "sample-pages": 512, "dirty-rate": 108, -# "mode": "page-sampling", "start-time": 3665220, "calc-time": 10, +# "mode": "page-sampling", "start-time": 1693900454, "calc-time": 10, # "calc-time-unit": "second"} ## { 'command': 'query-dirty-rate', 'data': {'*calc-time-unit': 'TimeUnit' }, From 7ff1b8c088ca958b4e55edf8e407375ab215f717 Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Mon, 9 Oct 2023 16:53:58 +0200 Subject: [PATCH 0406/1077] tests/bios-tables-test: tcg-emulate opteron for mmio64 test seabios starts to make the placement of the 64bit mmio window depend on the physical address space. Run the testcase with a fixed processor on tcg to avoid different results depending on the host machine. Signed-off-by: Gerd Hoffmann --- tests/qtest/bios-tables-test.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/qtest/bios-tables-test.c b/tests/qtest/bios-tables-test.c index f8e03dfd46..9f4bc15aab 100644 --- a/tests/qtest/bios-tables-test.c +++ b/tests/qtest/bios-tables-test.c @@ -1082,11 +1082,13 @@ static void test_acpi_q35_tcg_mmio64(void) test_data data = { .machine = MACHINE_Q35, .variant = ".mmio64", + .tcg_only = true, .required_struct_types = base_required_struct_types, .required_struct_types_len = ARRAY_SIZE(base_required_struct_types) }; test_acpi_one("-m 128M,slots=1,maxmem=2G " + "-cpu Opteron_G1 " "-object memory-backend-ram,id=ram0,size=128M " "-numa node,memdev=ram0 " "-device pci-testdev,membar=2G", From 9a5ac9c261c374bd47bcb347ec1688b56eb954c2 Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Mon, 9 Oct 2023 16:59:55 +0200 Subject: [PATCH 0407/1077] tests/acpi: enable tests/data/acpi/q35/DSDT.mmio64 updates Signed-off-by: Gerd Hoffmann --- tests/qtest/bios-tables-test-allowed-diff.h | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/qtest/bios-tables-test-allowed-diff.h b/tests/qtest/bios-tables-test-allowed-diff.h index dfb8523c8b..a251b20a1b 100644 --- a/tests/qtest/bios-tables-test-allowed-diff.h +++ b/tests/qtest/bios-tables-test-allowed-diff.h @@ -1 +1,2 @@ /* List of comma-separated changed AML files to ignore */ +"tests/data/acpi/q35/DSDT.mmio64", From 784155cdcb02ffaae44afecab93861070e7d652d Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Mon, 11 Sep 2023 17:20:26 +0200 Subject: [PATCH 0408/1077] seabios: update submodule to git snapshot MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit git shortlog ------------ Gerd Hoffmann (7): disable array bounds warning better kvm detection detect physical address space size move 64bit pci window to end of address space be less conservative with the 64bit pci io window qemu: log reservations in fw_cfg e820 table check for e820 conflict José Martínez (1): Fix high memory zone initialization in CSM mode Lukas Stockner via SeaBIOS (1): virtio-blk: Fix integer overflow for large max IO sizes Mark Cave-Ayland (3): esp-scsi: flush FIFO before sending SCSI command esp-scsi: check for INTR_BS/INTR_FC instead of STAT_TC for command completion esp-scsi: handle non-DMA SCSI commands with no data phase Niklas Cassel via SeaBIOS (1): ahci: handle TFES irq correctly Tony Titus via SeaBIOS (1): Increase BUILD_MAX_E820 to 128 Signed-off-by: Gerd Hoffmann --- roms/seabios | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/roms/seabios b/roms/seabios index ea1b7a0733..1e1da7a963 160000 --- a/roms/seabios +++ b/roms/seabios @@ -1 +1 @@ -Subproject commit ea1b7a0733906b8425d948ae94fba63c32b1d425 +Subproject commit 1e1da7a963007d03a4e0e9a9e0ff17990bb1608d From 14f5a7bae4cb5ca45a03e16b5bb0c5d766fd51b7 Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Fri, 29 Sep 2023 13:15:44 +0200 Subject: [PATCH 0409/1077] seabios: update binaries to git snapshot Signed-off-by: Gerd Hoffmann --- pc-bios/bios-256k.bin | Bin 262144 -> 262144 bytes pc-bios/bios-microvm.bin | Bin 131072 -> 131072 bytes pc-bios/bios.bin | Bin 131072 -> 131072 bytes pc-bios/vgabios-ati.bin | Bin 39936 -> 39424 bytes pc-bios/vgabios-bochs-display.bin | Bin 28672 -> 28672 bytes pc-bios/vgabios-cirrus.bin | Bin 39424 -> 38912 bytes pc-bios/vgabios-qxl.bin | Bin 39936 -> 39424 bytes pc-bios/vgabios-ramfb.bin | Bin 29184 -> 28672 bytes pc-bios/vgabios-stdvga.bin | Bin 39936 -> 39424 bytes pc-bios/vgabios-virtio.bin | Bin 39936 -> 39424 bytes pc-bios/vgabios-vmware.bin | Bin 39936 -> 39424 bytes pc-bios/vgabios.bin | Bin 39424 -> 38912 bytes 12 files changed, 0 insertions(+), 0 deletions(-) diff --git a/pc-bios/bios-256k.bin b/pc-bios/bios-256k.bin index f70aa72c60d1af58a5359e1733e397b13d429611..8d1dc0dff3af2a7db8a35d8eb4d2ac26bfe9d6c7 100644 GIT binary patch delta 93023 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 MgfxsV_p(F(0a4Jdu>b%7 delta 92920 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%0DR1@wQ(^plh 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 diff --git a/pc-bios/bios-microvm.bin b/pc-bios/bios-microvm.bin index 94792cf3f436187513f777d262fc582525a34b65..1a96d55862f909c40b8a256e7b32695888dece76 100644 GIT binary patch delta 49822 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 delta 49634 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 E08poNasU7T delta 20407 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 F{{fliqRs#S diff --git a/pc-bios/vgabios-ati.bin b/pc-bios/vgabios-ati.bin index 9fb862777fe76ab9f2f503f62356d866aa2f8cdf..27b785e3f8a3e77c66863cbe0e8c952af2b44b27 100644 GIT binary patch delta 10744 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 delta 11046 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

?Ag#&|*U{(i} zdgP5tx5)hqHY_C8t?m_6`j%T-Q_XTliVw7W1HxCRgp6@oo^+2ns#36n=cN?xijLsB z9I@lBDPRAFN_S)wgi}Sr7Gh+tZQVR?jdFD zV0oiVx)+r3Xhug(FukUXuk_I6bS2yuRXd2rPxMb0&CD1^A=qZGAS1bc*`~9mZk@)ot5#sPVR0rIV<*DoP)guG+!x> zE#{hwbI?)DG1q)Q=T5*q!(5q|T!f@_&RjFRNNFK6R3bLSG?{Bs_(H&38JAYX>|<=v zuPW!Y-DG>lBzTtFpqTsHi+I69YDCpPc)~j!o>)4Fw- zMOsia0t?$k9~(V(r?A|{-X1%Tw_ti`AEt<9@tK9fGx=;~=6E8rotfEF>s0WmFq)?( z6V5NvaZ{t^;7%_dK1-KywVvYYEl~;ldrlGZ1@?31JfnUlH{;A3+?lv5&_-EflG0O4 zc?;Corl)m(&S$Ic8@c44yyfDqQk7#+?ZN@L?;d&he$Yc}Kx2-=p;AlB&mmnO+4(D! zmqA)GPB|oSotwMQ-*S>m+3EX+rI&)LX}?xwt`R`#1GM;UF#z#QnfIBCMU8vLb3LkT zloi*``B7zYRwDY}BUXOv)S%{~CTPU+kE245M)C0g(f_r!Y$zY|rfLvPomDS93UBju_qs-MxxfuB837*T=^!N@ zK1cKZ=GI1Tr*x+L7u<8*iP#=*rs@2&dp9Y%@_p9JiG&*1#0jH|UID|7VA9n{n(Xwp z6Gw0#GBNJU0rwE}M)uQo#^6`p zfM9f16sF$AML4MLB2MQBFwPZ$)@eB0(kc&wZF&43y^C~&FO;urg>oABhW-=jj$SY3 zW%1P4OUmM9E&W(Ie-0n<6)qxFlo z_k5$^RQ=4&p*VSHHl76foPCqPUA_p-9~?g!jdg;rTNHN|3f>+;+&M!)P##6FN8`fn zZ5t$(Pe7?dM?0s5XQPS{g1^=MC%h?XBPUC9^fG_Sv4?T_?(6H-Yv2|$ER>t@4T}jT zJZ&-Z$qma`OwzI~T6914duOp_*=AyAzU*;i7(1AqlKsms5jHCe^eFJ!JD<7?^2)yS zzN9a`&x@d(DA21(=yP^EJ98$l2K8L$NUkkBxrX-i5js(jx|qlYTEAx&a2gK5M9OwY z@B`kLApC)$B7F@pI;NwJ;O0}1)HTjoIX}(YHKYu8il02uDm){-N!)Sr5O3FFcbwDv zyHo+;$J=lHx6Vpinl)DRza^A;_=CtVq-;JcsMTLJ?=7eZ)FIEFT9uH2pwt7nPDtg{2*%CrdtgTA*_UOc&tC41uUB^xPaN9&PHBSql z>%o0Sc@)F-yLI<*)9Z^=_*SH^M19_mv_3&mM>7l&va_n35lLIlLxfa_ zpubny`&na-nOtSzoP2VKnWxTzBX6FXYUQ2XG*rh1l@p_^yQ3XVDvdl!nau?}nUBIn z7{&40JQU982p(W3r;Z_Ec6Dlom~?{2YUrq1*|LId&P`_dxdVxlkMzn70!do_V}v4r zhBY@7kDjRpcVfI2hI?d&GckujF5hvkY z2(6N7e}ziU;QC&gifXQAjd>#lBCz(n`wH3>CjSg3snE!_Jg~Qi zd3n`E_~q9C+$zZQ6puUHcP$uIP3v(aS~EYsyIOWPBX6|ucdkmFxj79tXjBwt&^rFs zg-l*JCQ?i?YX!b=U#*(|Se(agsVVX%9&cNf*qg7U)}?5Y;en}mZ3tV1G6x<7%jOUH zHL<#9C~5Wdm+Xz{X~W-CB(g)I-)LYV`*ym8XqetQRX87HgRMCvj(M%)ahHF`I-k76 zx~yvr|M63AFI_!ChdT<4WbQR5mv-Myrw;RO-q+PNvs$Z#y`3LN#;_y#GqANMe=pm2 z|BD)DY3VvPd4@q#ICJg-=9@8*Et`>b=)D=o2zz$snM04x>KJFwHfNhHhU~2D?5tc% zo?+~g_3I2pkGTxCEu~wx8Z654gzQYi+6_;;T^pXe-^-sCYrCSg|f`)xxnDzgO C0orr` diff --git a/pc-bios/vgabios-cirrus.bin b/pc-bios/vgabios-cirrus.bin index c429540cde59fbeef00ffe1b75350400dfd2ee45..2b0202928f44787fe0e3d59814c36ddb26fef5d5 100644 GIT binary patch delta 9153 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 delta 9637 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 delta 9346 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 diff --git a/pc-bios/vgabios-stdvga.bin b/pc-bios/vgabios-stdvga.bin index 4cd0d52e772608b4db6a19809cc88a7a59cf0a8d..84588dd25de49ff93563e37c19e8f8748e539fa3 100644 GIT binary patch delta 9038 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 ITe?pCUmqdRT>t<8 diff --git a/pc-bios/vgabios-virtio.bin b/pc-bios/vgabios-virtio.bin index 976c78667c6d1cc3cb9ddf2af0a5b940eaafc64f..41308e0cafe751a4c5ef13fc3c143d35e6cc256b 100644 GIT binary patch delta 9038 zcmb7J30PEDmVWP50R;lDG`O*eil9*u#En=gh=4}Xii!)aG3_n4c0nqdNlam?h!hyw z?i(|vTc=5D&!iJOW7C=TzHy z4a;Kozq7e)4#OTBmoj^;i4{q4rov=jQ$gDAd6TC1>=`-}Qx9hZW5&FnssG)KmnB*; zrpM=TCf6~!naO9sLD~URVMd@qquQQU3|iH8SurT8twP>@hS{5TGi%L9djMrF;fuAQ z2_;wtTv-Q<&VfH*)3kmc2GUA!BN?T=Ys%a5do?$fCh^Aqq@DeIQRV@5_7P??--HTw zGr0jMi_+d@UpVo^WZ$~oY_&r}qW}SOZ=2YIEe8nSE&*B409e+y*#pMxciGt%u+QFR z4_cvNzTT&&1qS><(wC7n@sI+#DSSkIEa!b*1b8uN$nip={=1(Qa1 zGqJWb{kJjFLmet|FYO%9p#*fm&&{143qEOu^m>YwlreR~8# zJ@Os)tQn?skDu|4k)8a3Z$J63Jk&3#cTo#Vb=L{CMRrzO6<^~wwP$P#n{HzAB8aId z3urF58<@3vDL?J^k`|l=@^sylDQVcDJ*|;!wem`r0a6s%ZspZrCRf5jP7v-i9j1IB zb%J!7YSZpYlBsCRO;ggAySbxSg;dhkR$O!NqHdcqVATJ_?42gDQa@iw%6qKKjiB8$ zGpkbr96Dxifx%QA+}35LMk&cYcro~pJh9-4_Ig(7?8U5CRA}1heAzn^(lN5qJEHFxnd==1>=;S&j_5i@61^kZ zj*-4%#6yQIV2jxz*V5p&&K~w0c!pfEnvG8Bp@=2*M(0xxvF$C*P)RL2rlo)ZI|QoA zcn7oA1%hdKbe)ihwJzwk(K+Y`n|e3cWRNI!#FQ+P#?+g~7BrX&)9x9an~9>)8E_vVfXJ08 zUQQkfPPpx<7lOhcgZWggz*xY)e`MHdy_^SDT@d0mduy+m{F5H@l~#rK>Ny$~YV4UMujBvOb6iYyc!AtXH?)MJ%oIf}aO?0{!2b}m|4O(a)(<(L)K~ozdE2d|2RCR$3QnxM%cdFXR;?Bs0@(!NXXQ7dzE3bXDp`$PC8 z`6k(AkG7bi$Y%vbCSUaULBt*I?3R{a%^+nZ&?p zaSalbdT4VvOL}a9@Y*PDHo^~ESa~v3U0fAY7`#lvA}mhsip}0(`EBMdY?aK62wrpC zFTVN=kLw>AmE20kE4Y&{U>bbf0SI!ksW7wAJ)W=bA2C!TfPS3CJ|5HqO2E)stU_>G z{{*=7aD-5Pu77fX;}T18-zN0@`LOOhA$o%RN4_CCTu$Z1(f#^fCg?!6N)rDvn~TH< zbtgEC&bg1hh(fqCy7%C_E;5FPfGa?aB8>APTmaE+0hnw71CPMKL!&dJ={G^Wc}ajT zpE_WroWnmJ5UcFG)$W-VL^C(+^?0C2**a)QvN=>+sbUylMgdcV>|w6~K#jZy-sy}2 zFYdlft#G(rR4C`hBe4gN+%u89k=d<|GkaJ%&;&!!%>^f^IJ4f4M+KDk$p6L9+-hD+ zy!jNNiYHW-^Ki?&mNn*n%>DpmYUMpxJ4dD=#QGWqUp+pQ;SBcHyp~^(Ia-qQTH;jO z+p;AjuVsLm?~+;R0O%Jv_kyb#E9a@U_ocj+7u5XI2qq1{TB*hE)C!H!d8@&75+EB@ z+plHI=)4xodNuz~fcl1L6I4+cD~%V}jyJH<&El=BfnrCw4j(XmS5F`?=O*N}Y|c${ ztwGu^8f!aY_Jt6&ZseZhI+)cS`FyduPqwPfQ3NLRu;%$KzhMv1v6j|2FhkM8oML~lQq|Mc`iSGMs&{^7Qnv><9 zcoih=Sx%$#Q9YZ2d6V{|UA z2Yw_}go4xVk)0G)6b9u})QKQ_Gdf2SU}L+oV-bgo%sR4+QwYYu?SP5GCv>i)ANZB1 z?p!}e=XYoh8O9UdXV6H$3i0mX3kD_mJreJE{C9(5{6@?rm|47TP>g=gN=e!@oeG(8 zRZNm{c%1j*O&VtmtaRBqe;;sf9$`COkiydF*~U~Ee#O{^Y8q`(~G-&q>-d|D@ zex45>e8?|3hiDw-w+HtR+m{{3-YLl@_Z!Amp9^MNs~p*&RqDv*Lx;q6b%1k(+jA`G zEGl20D#n)&8E6qX3Oa{@L1d(^W|4PMwl{)jCyItO3KUbm+^JKo;j+>B^xvrTD6a-9 zjYwb3F{T2zN=y5DipX|g*xxJcZv`8~Ibk6BpZ|pZXo1Avd^N^oe>oXU5ao$?tXEp86f3X7U=tAt^OmPw#iE4!rf4DF!r2f* zyZKfB%`1`XAO-CfPW{cW?v@IYOb6}J9kfyO5^aC;bt+>#W+6zCO^6qTq)Eh4kcyLn z?;fb9o-~~JGK1su>KbM+5#)HXTY-@D4e$7+Cq-Xc~DZQ1)_#=D=i%@KGzxLHJd&?y@pbgQ$ z=&XHQTpP3ZsNhmy1*=8IXfOYEFaH>$jj^J+18EcX9)U8e7~-LZ{o`nFuQ6HRvpCNm zq^gH}cH=@;UQ0IN*>C|uM_s4Sba-n`=Wo&$R8vLAa-0&I*$Pj~%I@Q)9 zwFfrU*3_}DMXXdD!pcuWgty_Xc-%4-TgYVXz6g@zkUYS`aRsWu9F$9tuvINu0ysI5 z+qAEu7-QEEu(0L;GngRp`EPv5!)j6F{o``3s69N`+$sNnKFm7nwmSn$fUjsgQR&Pc z@;!>Y8ZQlWC%}st5&r+|19)z`8*sErYoz)htx*(at;2gpuN4XA*Y{X9n=fXJ&NYt^ z@>N?l+^a?iiYF!ZS+*}5hlwi0|D3+4#e$j7N0bYansd6v!6A?)taWYZEtz|}g3ux= zqUevnc<3?G#-9O37lA(&?N@^(JSo{S)K5Dg+ z{3eedJv1_Tha|Z}x1T_#LJzlp4PSvBUpf5c(PPuEpy|g}ScDL6H6gQRvlV$_>_5a< zLlc{iL&J(UX|pT#i?P2p;Se!T6gThQfq;y=_><8I%F-VOx7J13j>?@AIJ3XSweZ$xQmh=$>w(o1Q-m!Z^o4CngyW#7JnxxT#3%%$CCQT z4axDGmSXls;f*XWhV31gBeaEzEJPeDR&<|7B73Ki>z`TM9m*0qqI^x(e}h#ZY4c}B zbSpnE+9#rrQBcWOf6g18nW;+>t6z2V#IeKsL~X!kGuYNP@>KUF!7X8F7W~$8+t_ra zgz-ECDLm5@9@|vEN zp3dU;#|=UMtpE7oBR`fvJ--q4=i0m!Hd}qj$Y(d*nwi-BsHno$EZWOiu3cK5fOLNo>|W(HCkTn8SOf#9Cm0 zm2N!(T6Q;fSjum{1x|`*#FsEz;1L}ZwP<2 zH|O0z6}jj;(4q5)!~7Jw+ADOZpN-BXH|WUk8sdi#+K8aT%0%|De{=7>xT4^w9G*Kd zOSXNDg0^I=~VK0e!2<9Y+tzJelm6Y%)1uoOD37^+ehuOJb$N zaCe3H9?(&}7S75=`>b>$B^P?)?Cm7Fy%21v{%PAoUlF*?I=E!gSb0ewA%)>r z5yckJ7MigGJsJDfYZCO)UN0=Tg~=_=rh<$JQ%y$r3|F+)6LS#7-YF+1#-u$1U4OVb z>^?!Dy?BK`N}DLRa6|eKIhwCbAFSw4@VC+p%EA-;eEQJ7FdQ5>9^Apw5Z7K*V#EM& z7{M=&hC4sy{W78h7bA6|j>W*`IzBUF=2JILQlPOJTU`%P^kMu?9Y35gPyUwcCxaFa)Z$(V9&b zG(ByB%BHF0mCNK!Ds@Ch!z*MPqQN*?8}0GZg0{}oehDh^?|_Y!x# zxT79*y%=clS8Wp%IJlphUneu`$u`#k*$|-Sk3}J6`AK(m(3gg8s_lku({O`IKe%j) zFa)Xj4mw;No)tp()LusCxU*!Ju82Sbns2G$YW@@-*Hy(3rrNFrfa9kSAOZ}bs?8kW zy41xGuG)&a7-p#XXS#sb&b{0@|6^jj`PqfhfBx2ky7OetF;w+kO@*_%gGPw!O}>6= zZ_BW1lN}#px&Z#rg7Cb@e(JWtT{_CuqEYDl-A7pJg6WD8ez*p{OwIDQ zYl`W2sjTK0dyna;qhkspmq~0U+Gs1%g$Y(&5S=VC5(j=2sAQEc80n$&V6IC?yKg`p z?=!7?VDneRNNQK3^Y!CAdD@7s&d-rm)I-(oC=^mg=h|AHKW&(@@C$xu+E}CNU_$+9 z4Z~p?SUI#r^`y}m;}GW=t=Z|S@TVU_Jmy0@baAj$W_?Ukd;MA2W}*0cDBfk|DVcqG zef1e+6b>2bJ4Q%;^yy*#q|fQ{rs+_=?OSQnVEPH|eQA>pt+IT(Ob=JoV?1m|V&LCDVWlJ# zqjT9OJbOm0yqG_k9ueR837hX4j&^z~iY__|G`XVv+96wyI-Gte0-M|05Vwx<&u7Hx z%PUyf3L&k{2%xSq9%S6Cql(SwtSaSi7>DURor$7SUTqu{?3u|fCFQ#=@yEspC3y!A zeJ)h_gAXq;hAYWAeD-tk%8A4L_2&jgQ6UIpIxK9Zlp1WE#ecnwpMGu(n%jOeQTf0B42O&DMzN#W!{460He<3N`2k3}16kP^@%6DdI>AU{zckgPhIe!Q z7oyleF?E!9+eTrzvj~rz;nTBXbRP?1$!Ga1Si@!U>Lh?|EzU(&Sz6G*2l)K-`rzSZ?Co=fvP{n6pHA?JK@#PDEIsAdm(E zKjUWe7yQdP@ya?UpD=fnyq1rjJ6hhvUz|HwnYWAYojX--J$QTWW{u3aX+gt5!@`h2 z%ayf~Brs6wEouE>?WJwfzk;RgZ~O<3Jgtn)Cu0tjCKqG@=J!8HVz&;J9~7qEGXrB0H6hIpVCaUh-# zSK+*m%kM{yCFww$v~<0P31S#EwsZzCM{ym%6(nf{!&<^y@*~6hF-HvV!1EPc>v08J z0Gy}PNk0c(;{`T$0#*g=Vp-M&3&ibA5bRzc9)V{RE<&vL!fL&+?W*ex8wfZH0e2O^ zSAZCL2FIO&uLE)ON=dqei(tEXVYUAPmJk!{Q}6*&oz5!>I^1HpR1aJviK8o}MCo08 z?8dbUGf|p(%0EM#2N)0HgRQHY;^a(z>+L>iiE+c@5~7C34^NCAJ$y{mz?sW`5jFYw z+^E!?bsINEC5Y*v34@}Rtz2u)UAboCGf^)t&)K+g-P)+(afwMoN5rug636i8ej7R< vVZ=~V!t#V)JU{yRq*00S@k7_=EMI0`xh6Mm!}4F6dqS~Hd<>I!+z)28H-ee%Zc4KP!?1(NRULTP5Fch>WybhOTsOqW z7+8QYJ{VWPS<&gvP9pZTz-0lr#`t7q#t4?u%xn!T#Y{_Vh*z_s8=m!y@qt*c4(naP zBFBg+n>HS6)nSksufi&s@oHS>#s^{*RXi?p<5jGOd!-Yel``YU0Do@0mYs2KX)3p~ zYGE@tvEA6tEDf592VeE-c*M3d)xxc;oooCf_AZr@Me~k)R@^LG{Z%Z7+5XPvu@~7K zh-W1j!HPnXp)}pcP@?-I*s+7WZYQ(YeOYb07d`9(N&z^N_e~1IaLFzve_D^hQt&MA zn;DG9lT5tB#9Ahv!G!ERhSHgVg%7-B>vE~^fl9Wn4D~8}Aj#IB#4SzCc8gg3yaJe} z?I2^?#cX%Bv)b>yDnQN-`H(D3+nLygd(Ixcu13WQVxP8x6TH)BT13qQHp9TgC6H@b4rrWronw}x zEBP|txA$-Um;~9%Y>n7xzyLu5O9*0OBiRB`&Q=594FI7z499eL1;J2e zx?xB&-8GJ4M}*4G&hle>*Qqy415W;w@X>UERr~q~Lg7QTu@9}>#wUa$}F%dPl-Ptajrj1-a%C-z3NK z)gc9;6Jn)@Z7k!w5v+|3dX?YW{yFLIR(l|r?Mzuj}ezzFYx z9$HbhswAzKG0NHEt@V+Mo4vv0R`!#!)uq^M_FgIMpeP;wf!lix6fbZ`uVs=f@oC`; zq*yQhpW&m$zw=AsIpS~lh=_4nvm`_599XVpW2xcXnkd*XKUm&XA951EHvapFThezo_im1iz{)pxW$!s+8vm*H0P$@e74?Eo z#sipeB7Y+wjORrS6}R%rC=FPvjT#`P^P5q9BL5*+9tO*se?~~gq7E{+vk-3xkBN>p z8ya+W!C=!}PrH;qD(SStj)$Cm@NCI-JsSTG?e7n*#ra( zwds3^AJ3U1kCLBWXXz}<^)WoKz?%`w37<;e`R`gIn;4$rV1uN?`!(;0WrK{{NFN7h; zBApk-M({o{iQ%0;5M9LgyHD-xG+z|+j<}1r#w-=5^XYvyiofC~`fL{K`0Uul;wt_r zu6=l5-+9uApZFO~Z@#H-)UYsYFcRtLZnx!?#U2!jFUZ#S1?=ns(v=tNG!_;GtYB{M z+e-}K-}W6NCUIG_O5Dv&nuTI5Z_;FrehU*iF~JuT!b{E=N^|a!P+#h{vgpo)ve>B# zT_#>|TlT#+uJ1QN`tlN=(6c8W=I_Tp?dR(~A3QDL2l{O=-xL_QDZhd=Bv-AEVQCMM zKtsUG9kblcb7|0W!KEP;wZhlhyW#L6V78Xjvf@rtC|fOJ%{xrbR%;M~UUY5PG>#Y? zRF5o;XG3XrD=`fu1e=t{5P4u9Wf$W4U(7{LCtTMAez1R^+Teh&FyCE=J7a7vuWJA15S`6O?}q=(2f8kWh7sUGEt4 zP$3aAIGm4+k9cmUlMJC9s3qq;rqB)-2m34rGu|e?{<{GKr5Qhh zgDA756((D@5uw@zcraBEJsIwb7?QzWxJ0Jv7HfUjKFAjM&!oHkb?lMmaSyQRX8 zWFxAhHM%x`QcO-OQa|E=y$LpM)3vb)paw1Fv?4m#8bGO`2|=Ju>-XlDt_X@8<~G4( zC)&wWQ_vjONt70?YvBsW4DeArtaPQ}fo6-u-UP9vPP-Pl+zpcmHcR?UEbLfmqWlwp zeW;x~1kBd1GzEAdD(CM6V3^YjJCbDUyP`R)uw#I1F1{|Z>H&xVdPm=LPA7=Wm#y1? zxk4^JE;8FW+P(_gkq>+69gkX^^+3s&ty@I%=)#V5a`6rzT?W!ILMn@9)yWF6<`!1H zUKusEfDu-s#sgx7GZgbp#=eCe>y5*m2D69?<*gp9dZ>b1(ZcRS$&D^52)wMvO+MI* z%7qM7uhu)_9yzCokQ4Fvt|F~gLL;%E%#si5uG8?k^|%ptg(o%fv`7WtF)qO<8=2V& zRkyGjs%;Rjc)&n^Gg#OJZ9uWW(OpOEY++L{grY&QEE}Z)65p#>gT~5ETp3UAI>*5d zxC#ECGOAFa{7i(}*q|25OQ7C^oy z=9?BU+a=PvTe6A@5K|zCyzj6EvMvJ4Y1eSxG%##tG+CtHF@@f=c4>6%cg*$}anp8^ z+3u5$#0qB+`Dt)hFshRTcQrBxMWQK)<&K?Crf`ZspE%MtLm9ur-%L#N-K325yecul zcfT@@Vq%SB4t;3#h}Px!nGs_;@ACI%Foz%*l73>PBf?oQomji%wje#6FB)OhxZ7wx&6V71gCL1_#yYi}~ci z14GimF+y}ROFLsyGw+GHyl`-$8D}oViflQsDO)xyLEfipMdrLgFRmDV);UlXaZaSCeYYs2fRpYA%b~N2`nCsDwl1AjhmfOFjS9M! z2O+ST{hrmZ2ri!hm4nT5Yg|YN#Wum1q z#Jxu6({$&KiE|q>GS8!nY!b6{hM7pTq#$MbWG{~~nBCS;(s+ybJVGLVno_2EbT@+? zZU+58$wNhO3+xF~2+4P!JV~VXF5Glf#djg~I-iPLWYm&e{8z!bY#z>GWlNO!=fF;J z4p~4aGcxtOo~(KZNlbZ!j>e0wU(qI5O*+YTe+*p@Pob;r@|KqJ^Y?a?w5 z?)6Kc_eL-DmAalY5G5L(dY=KMohLP+MUhMOFwBBfcm>Jn0$WH_+@59e!YtSOZnCAA zrjQ{o|L3#UU10OOkdb`B1+1AB)vIua;IYO=>kJV%czZpR$W!>dj}S^jh6^+qDRxMCu~lO*zWL6_K^Ixhdav zuLeq>kNUyW3;+s=70VRi(A%g(ksMki{&G zooJ+)dOL$uSOl#F%8ZkLX2mMIT>OytO^ryPgl6ej?M`Me2AQ0PjkDu$Od;Kl?5TIC z_~O+5>X%=oJQ;M3|6A%_Y3qOUvBTezoZs@Q;n~s$-*WE}pGd5Xe?Gzzy5Tt6pAPYs z*HV8&@A#ydPZ_yJvcJcxMh=a&{}#(cZ8?rZZ7>3t1y6z9Px)LNH8$(z53rA1)dE^C z@fMp8Ddh?ZEKY%i-C_%HCd!SZ{pO}9Fc{)eU{bNw^A5z*w2i+#DkbsCwzN7^f5kTL zG8o6>Ko}PKu2%`}zok)e&)Bou_=QoE)mnwpq#ya<(Qy&+R0=e0qa+Qz6#r3zP=kQD zYIIG4NkN>}N(Tv75Q-0&ys3>Hz^1Qs(cF>Gbz|a^cICT|QVAbbVnkM#z&_fU?>3fN zM;MMcb6D;N3c-sm{{EQPdO@>_I;rv?U%Ji?qx|TdHX`(|@Pm42kwTn=L&_JY`O>u6 z>ch(H{Xg*iX{miH^B|N-tf-Sb-*r*hgyNCPHZE}g=d;Y3t}@2&ggZX%6t#&%+#^z(jj`Bu9Jh7hVkNwOaIj24yCx1;YPtrz8>A8Hec3=-XG*^dCNieIPGmmf3 z4iR1aFWS^G)d(^|8=7!+NFrsEeaSS?dZ02_-gk!0hCXteAWv8ve1PSCr^t5cO&&aM zN_?+{iVNH%lO#Q}T9+!p7TfY_pn=}52{^vpMz;9M+qvGG#{RN(kh-83 z4Si*+&4&gEucLjPYCjqW%hpIW4SLDe4Ql5-o-sZ>JQ*x|lu220q7MvWXFlIHexMnq zS?dZ$lw26f4rIFVE-=57gtsu99hmnFD2g3e(+xUDSW{zBAU}pplW$P%Toy~k^9ADw zw&pmB=USzBKA>FFn(|}O*Uj$@m5;S_b{hHk^ns+U+;oljKirlcmzoFadPmJQ#p7*l zh1XFgA61U$4j8YgC%yyZZdGvJzXtzb>YTIFD|EX{pC@%hLVb-&s(YgZpv99=B_%spm=>}1#yIyiq1iUy>%1Eis~JTOr~Dp-kE(v zNB)RSZbYkTQXfOZq?nmbk&nuZRaYrE_b&6rnG?l{{7;!fL=``kIas=Mj6cZKO3yX& z(Ym4iU=uhm-M?e7O$u{g zHk!W^@0(GY-bWiKTQj^0%;?lwBc+0As@t0s#cb* zKS%|Av_0hFQ*`9pHwRzlluiplbGa8*2y<4_ z*%kJLF#qApXy#_%tSVP!K>C_`JcT(k0t}^#VhSJn%A3aoAkh$RLqgdL=wNor)&T*) z#@90xbZDR{A9M7MaA+UVc;8rjjl+>w?|A#m@&@Q3r!~PAK7*#0#4Z=uYy;~=Qp`Q+ zwmkZp66jIef7J29sS$BKaQ;=i;g_HNHt^1= z!=$y%JbBt!>8Hc|)oGEV0*)vLewE4LJmiONNH=A@qwTPA1f^I1?#K2&QjDkt3p?ND z2d4Fnym|`aih;O-pBCim@A%zmLx&{!kz(~?fgVO+bqWPTDLn5M3e;9q1!aQE1luZ3 zB}G^9Dbru+u}!UTAFK_7(eoqI`}Ny+2#|gGVTQ6_OE@Lt*nn0AzCcl{0`nLB8dXM{L4MB>Q=1?$^`d_s0a%%Oucy(BBx>GXZZCSK+p*?pwDhd9q39@u!0 zRR=?tdWY^HZ_XYlO*q6KX2&FdeUL414)dkWda8YAKi@9Y?+@4=zUcP0bu~W7Z(aZsD)Z>Mz-Ui(4fBc$Po$N5j*z{Bz@WQ-*S`^?DNDVDSOtf3(zCe-<71iD>|`0hDTlIv@Jd`^P;d4=e@ zCVqcTeEfE0mVjfJGeR_!Wk__iAv?^#;Q{_nnTU^{8!p?ofv~$gRA4LT4i;PaJ986o z-8XlsboIY@WKN&xcNBU$(0j&CTbj8(Cs{P`qMXs<3cerLwfs)bV5wyrk9~2PcyI6O z7uS37YYWcpwJ!_~G{3w~5bQAJ$vA%)a36wuBz}STQS?X@dJ8H)7<+Z6@UL(wd+YxR zuG&Mlb?pH`+EG=;^+H>V?o%{DO~X|K@2l`2OKSa$@ujUycC92M7Oe2=wf&X z-VwvWxIbDW2yOTUnSop=H44unx8fxsH{sreEGxJ#iK044A>73T;eG_%&vCEBj|c~Q za8(}MF4aAay9Ib=LJm=ouYfT0433{hz6QeUfU_7s!VUG{s{REo5hmQ8uy<0O+9L@% z<6^onAMa>$+BL#(ArTKT_^rkpjn{nX{~{~^$4z+erdMtyi8J`Cf9R`AO-fBl(WEA) zrY4U`Nz)|GUbRv)d6`j@k@tFjz9vO^Jv4QYX89|xnT)Tj&3|6==Bm8>S6+WjlbSSq z%+QfZY{l@={LCMs1|$zPtXh_`eDt#9(Zh$QB@bPfw`#fRm9@sCH&(rBN_ssH&LOGx JE?c@z{9i;=&{qHe diff --git a/pc-bios/vgabios-vmware.bin b/pc-bios/vgabios-vmware.bin index 119a2b188bc54ef8883194ff85a0a004b72beaae..d382d0af94cbfe12e9928e9a14cb4144c22a2ed6 100644 GIT binary patch delta 9038 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 delta 9346 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 ITe?pCUj-1)`Tzg` diff --git a/pc-bios/vgabios.bin b/pc-bios/vgabios.bin index cac6131e1b1c472d462b34c83eb1a1b79a640ee9..62799d0113ef57933830aadffd6becc6c34c4244 100644 GIT binary patch delta 8843 zcmb7K4P2B}x_{qy1{e^0M@2U2&S4{~xok}Fu&r0yF~mY^Sm+mQ>+yDcv8^X1 zu1Z$so}FOC{fUG~=Dx*JE--g9bDwAK!wd_>+5onbMmD47ict{oqpM?~=UIdw+lc_S z=?PK5wkRQ%)!$_9``b>Jdsv0^G6=eF-2be1>qEAaE#uD*h}>VUOq7SM$!Eo9RM%M@ z%VzGsvL$RW!yX$~G50YmE0dC}rRl-e67$=pVId1qhh?m6hGwvXAh+B_K=A0hSGH_Jc9^ZC2k3_Svu4 zy*6l==Lhw*V_`#JAuGPCzENXk&Mj|A>Klh$^@Rgiv8OPaIolLWFlP%MhYcreMggPP z3}hWC$9)D?B}0oJLVju4Z>et_VKvtjmUdcw!^1+M#Riu4C04Tft1J}4E3>_0Etx){ zrXC1;$89jBJN$HTqO9?I!Gq*ad2~oxzp_@A>8lfJi|eYk!+d?ntiD5A*<34=S3pc< z*+6sNcaAxauHvUcUeJTHaGqtDIn#_Cy3LJbt2LLq4Uyu>c5AM5XL1cJ_z}ZWoSc)za?v_VU{O7Yr{eL&pD*xM#M+Dnf!K$??EY*q?UO z%$%AII1J3)3WGVk|K)BAbV^Ik{tMkdkw>)N^jj?1tNRFZpJL8deWBIf6Hgf0RtZm? zT3jaia`^#cjQy2%=5Am$S`>3$R-tK&_KUzsWar4*z=*MPWJzEoymQ1H7%_B?qy|Rx zog)Lqh@TEy&Q`J&-c{Y(yL#As@C>|xHja4-#zt`ib*)J@)W*=eOa_W^2#1NdZynK`Xpy?)`aY`Xg&Gro~H1$ zhkzRiWm&Y(_qkCE3Tv^cgB2;LG}~R&L7tkA0RZZ3>U-I{_AI>6+X^IoR?IY&D$18!uN3d_i=o zyp;bkdWifRzBhUbyv7%uHS&KT@dhk!vAWGStZtiTtu+cJrL!#G$1LS8d|KZ;(@Vh84lE(S5`%rfj_R$Y*>{+`1%64s zNp{(%J+UnAaY2#E7yN$E{}$H_%(pV^P+UIeg)u7iWDYF>qR5 ziv*>9vN@KeJ+MP~?G!f~;fJlPDjljWKb%fFWdK($9;7&e|Y4C9iAjrwq(m9R3DSX}F{-bmP=*L;?<6Z-x1PrakDg?Lu zhrnfoBSiBvgVV!27g>hyCZXr6V|w$HgsJj>@#hm_(jraJ`PTylbnGw01@R6vgVp_@MQsgBlU z+et!|OsMQ<;g*ip^|nFGeGg=g$-A(2u}njV^|cDV`g|zE8Qg7-)-_~~_H;*UlIr@E zY>#xb4pED}GOHK@{UYa{_cmi?j_UfIH)^w^zRt+Qy~o%5amNP+5l zRklxXwA%C4;`adcHPI%hvKUs8EU+Cp$0|09x5{%AJE{!$fa!bt0)eeC#nHOC(Cl50 zv|l#Kb=(#VA?kg|Jx2^Ms}~|z#VE1(#dGZ5*RXOQRR+4B0$Mb?<)L?q;Q95#5aJoK z?PkJ=mo1I16yKHzpZPl!?;^QxY zq&r))X!je~Of1jVe6X6bIVeVuslL_lZpVk%m~U!VA;51AP@%+Xz9qbwgtq}?e?)Dt zXzu{4?@j>Wc|6UH7VQm za(V8^VRn(DpmP`)L`Ldr7I_zCdn0((P&BMppqQ#$&7eACWsCO6U#Rq`Ito@Ak-nM} zttD`k){gfKnN^+YGMAySs`K>Csyy@nc!rKuo$$ZgOEUE2M%9E4^^9L(h;B`+>Qe#% zg&SBhy<3pT#d_O$2(QaL<}yPGgS(9kN#0db2WFZ8@#E4kv9zDTM-tU1>QrQzjo#?_usfqK6 z8!%L-^s{}%s{TYwZ*4!TQxQ6xm)ocmt2&IqCL$0MC{KHcMJac!2|~Q3iy(#$^E>*N zfJCl=6tr79>$TCn?bRfiPTCVXX`|>R+M%{+M_rfCEO={e*Kg7mRCAb)c}7j zku2O}s>MzR3OBMMX@vecnd6l$IK^=JX$q(p8~^*M&V!y?2Kw~l~? z^@iC%l*AQU@PZ#>S=`+ta-pa-{MdXMpx0|G4ELsQh95!M6hd1?R05ch&{4(J29Tot z0OGbYv=9!5h39ZuGB;AnH#dq}t8Gl*1fR$muijzH*itcL(bnHb6jxo#;4!sg?>sGa zz*7%%a6V8F(l-u7dDWc-eNQn`3UT*a+A zZ#0!n!KiRGlg>tUR+6=BJ7ooD>ob9ja48MDT1r+ZIC$%XnTD}qf;I736BC|np;WkihuC-_3PJF9Ig#x_H?1NJ@32i& z7U#c15EJRI8FT9~myWr_J*)EJTix^W1$vZFktpBu2m{M|RuH+$Pfc9a8`=;`pd2eK z7Cn=tJToo1XZJ6~*<2JK3aam@dS0A1C*)QCcKErpn27B=Xi2kRuz|~uW+|7~@R^Us z+IOR9fZtKy2`3Y_=kgjWJ7(4#G<<+2i7O3yL`M(h0yPJ>Ak~m6O9Bc0I7>TWTLH`2 z39q7Zg@UZD5fBx6e+h7p2CkF#gZ%@yfv|)?!%&`IrH`;&-t=g4k5G(lJ5f$WXbVxk z&PPugA9UTKO|9k6O!_bZQTs?b+xp=08c9-%m$!+6g`CgI*3D@iX?0dgxqPZ=XoO=2 z9m;F28d=4xMZCZ?5-qRYrZM9_mQWEjqt$en0$WZ9_I?EN7QG-N34RZx2JxfI!Sdc0 z5`5pw!zRy6(8R}5FImU7I)V!%zi$4hRE)Amh zFx3@iDC$kGA*$<{V0uBMiVE?14fJkQUH3!irMK!@Vep>iQ>Lc((JkrJEv2Gq!7$Ri zeE#~>q2pkEH9jL^(z2fHKwm%H1r~ae;Fk4a2Ojy^P&7L*WeIPd8l6a0Us)WLeHRMH zvUSH%_SJ~8?|`_coh*n$CzB_qrwkUZ{-C`uth^SK&}s7^Q2D+ruVu~??HDn7zvQm; z!H=6k%%TO~5Ps)wc3el%cUg29aD4FCdZ7uOw@ScV{VSc&y(2>q5F25ItWqQk_t$sc zPb%xaDxcpzF~pt(;e4YjoJ5`~jfa~z|73lkB{TY4YiGpH^Coc1^f-fCz^uH=H%*_WY|(ht^bv9bzcGD;!cXvC zW|Q*u2|nLEibUZs_gA7$@wd$h;a5z^n*xGZhn7SvK0FFe7= zX64A=@K>^8l_!q#-(}5J!jJO@SyO}4WLBAz!_#NH61HlC%VS%Rw0rdi{?&}M+*KQ} z{Yu(dNBQE-en{eOwjN85ohSP;S>#Ml$weyl9w)$=)Z%){J59zf4#n%i@?}Bz zMPLyd+;+u!EEC5a+@r+ZDDJ5Iyqm&Jp{i@D0>2DVi|b@ES?@mC6s8tWLdnvljcH%u z-TS4fr|Pmo@>8FjN{-y}E*h9ydKP-%-duEhH^PC}*^7aomq0N;Us}|1;@?KF) zF{n`h2X zNXChpsC4bF{(uJFtRB|Vg}p&8()&99Ze~CG??1J=@iDO*;aDE)co3q#Jfd4?jaW7w z?Y6rJEZxxZp&u(e7HuyK1p)aFwTKPWp^mL9ryql|n-krA=Aw8_EQxzcVhhl_%KJ}Y ziRO!g5RkE}=&H~0A7+huWOOL$b*@}A7e?UvMk*RX zKU)1xDl(usRqU301+cf`Wb~!^+}Ud*b{YilMpLBv@^*f7_CTe-hkrA>ztVPy2hSN0 zo`i12tA}6&J-mZ?%A8)~HywiXtR?z5!K2akt^W{a(N_2;vW(uwke_K^s(Ed0tn!+N zzcnW{Jns;zfXyO${n@r-%HRsYOiDoNGe zi$Pqq#QLkRFZ@CX9Q*<&w42`F1o8g!ViiX|ub-E!%&z1*%dmJV*I-Zr39F#aR#z>s z1ALZcBD%^hOUCl&(RuLYz#s$XDUseaqtCnzB{4DMnSeT}fzxBtxJ=MR;``D62kD-H)Qm_JByl=C;~k z1u^n?ZeEZk|C!qt?t@_2HeUTy(p5pM}qj*exi20E)hFR=Hh# zeT**=z~2ATTALZ$)BE3uZH^rNzYC+4DQEb}g^7j;09v#oXZZbv2?_aPm4vK?uA#Lo zQ$fcCsRRK7bvw#JcaYNsVhIsR7rYa8Y;|CiRo_p|J6acIltNQl7T_9oRbHA-sFL;Dz)$ zVC_Fa{P%$MU?W|wlN1BY6HHtVF#IkMJ`F_M@Z5}RJ+7et2W&849g4k9l7EIcFMxP9 zo)dA6#1--*$C9+KUE2MeUuwiK!<-S%hd47d`GZSbQg#_m>}3aKwOCDDqMuv7=YCWU^`UT6?Qh@>;&9H z0AB`T=ouV$1-=Hv$$*K)MX)^su=;-jONa@!7c8DsX9!4wj+j_3MPZI4@z5%zN*b)= zBCcmJ6R*or{t;piVEl;puUy-dWKK;QlavxaCV5P1@`N!HcaTUjT;II z;#0)*sFdOHPpy5SgYo_Ttcqt8M!ZvNN8IBAn z>-M&rot59g?6;@wbaB^K0SyN*1ST}5)8$}hyPkSVf#J1}$p`x|*pd)tU{%J1NZhw1#28qB zF(DXtz}dEw{ryDjGl9zjaE%Em%8bb@^%S$UvQ#rIu_Zyxwq5qDXG{phdd*nxJQg`l zOxd&vSgRQ?ISDGPl9QmuePKc%R#7G3wlG1(hPYQc;aMpsAp`ge6SS<;xuc`n&gz8i z;KX)$53{stYHocxtnUun!&F5(SufZ4M;ur#rHE!#2`fJ(Tm4n6klDUti`Wya0ODB% zMzErgY^cogF;wXO1a|BouX~GG?7pn2*NX=40HqY1$%keI;dR+NOn$!wFU!HRd}w|! zh95KWMJG?3N^3e-d|eFxypP^@AE1cF2chVcNsQ9y|;8>m66`uvCSuHv!Pm9Fn>2EkoJXKgq^1^bv1- zgKDAKW~!yh`&s8*qQ8sTnn36@7OTRhK6ki3j_ldP*4e!X3KX%2y>4JPx9%sRuR?ta za>Z#k`m$O!vdfLmY-d+I%j!mb5<1sk_z``Jjd2a|>%+~pz6Y%Q$(XJa-i zZ#O>8%I(J0%yL&UX_)1fWSYV(y^{O~J4A5a3vyT0$bV>pBHCR!Y#!hMOMg?dMiGYO z3MB(ewY&TWAp2F!ufxDHO||kLnps@uMF`Us1Ze6hmoH0g->>?c1Pqq>F~0M^ct;O` z{487FRLkY_?m8=Yr+2jY5WnJ`74}7+Gf9L-4=xH-wxoA_b(_!h3HO7-#nbFDQxAXI zCsBNnSNe<+7xQ<0GKa_Yv20hHVg+&cTfqt5?=vT&;TD@`VB#{!wW<&_&bUr9%du5_ zh3^ae8{gS;^I_-mL0vEjvYXl3u+f0gf(Dil#KbnT1)`j<2EZEtLUS07>#hrep~`gG zkZHPZoXU<0wf+6o#}8~&Z50WH~1GE1Mz$jl*l!eYw=JiUy?PMg3V4~{lh_cL1; zYjQ*~%Xt}LL+{w)frJf0)_NepgOJ4@NZ=qO*8@=xLMD44szJyo1>#-bEjB62Bh)TEtc9tM3nNkBq>|mwD~*0x^^SG<>x9GLMRS#3%a} zOgM=@7ZAovq9%wtd2N&itTjcA7PI*GQL&M~2$tKy^7fw*lCh|R4DJhvH-yJTN1F|; zI=f)7=`Lk{y=mTkU+4D1Q}OYLz>bzdh=$6ALoQoS8G~T5?DJlOT6e@yQD|o~5ir!I z3lKlXIa7|2pI%~FEZ6lmJmoe^J*(*XZ5Kv8uu{df>I^#y4=Rf-wAhc;FtL|B>4<0f zV+ewox+BIhhHBlxL_?(-&pJHAGdhh!ST@^sTR`A3z2yp4);R@_Z821?w!6F#h9HY9 zzAY|-$HpXu_y0h25#O)hx3iOcY0NJ19o`+YT%612#%>jV%TL5^7n}KlxZjAY`TMxX z^1u;`q{%<=PR(%s(uk;uVc1|K($V!n%d3hzB9xz%t$!4-v$IH7Ua-?RSQM~=xqZYi zF@S$LB125(vSzjTE;nh4#3tUM$w_|!6Z$d17ZbuOIt`VDH%O>Y4q91se_~bKV+vg+ zo^@OHjUKKaIaB)RYd&-6P(IP$kH0_C*LyK|TE-8L++zM-VBn_uJkpSSaB~dHyp04J z0$zSJ%Y!^u2CWoa8d6a=e64p74le>`cSRE`?>B|AwIbI1k?Gl54MNZpt}QQ3CkDs1 zAWLIxsLbysrh$ZDlX@2-4~$iIA)a|)E^<2Ix@PhtqheEj{Dlx7KmgI3U0CN=Bp2QR zW*8qC7sfY4`EX5qmKelW#4i(V{AhfPn9I+_k4k7KB#;x7{~FL`i;y6p>QuYlk#Sog z5i%~EPf3WF^p=whp%JdYAfQl3vSdBSmRcsY;{Q5(WXddy9IEQSOdqoq(Q#Js)aqS zBqlf7o$pFzeJMtiO6znz{-mYCZqxw?3ib{dyiM1`W`Y`2R@jYDVQU4Y)(%939DibB60PI8Ud{e+|?J84%2cmMmA^^jjRo0g*TVEB;VP$=zWpnu@k=2bxIM6#r zoOU`vWU*|09hgtcZ)ooVZ+Pc69Yfxi=z~KzVe3NlRS>I;kB&WeFqFi}l2&d=JYrDw@dr`TNu3FT3NBkXUo(MS+kFP4y>LxT28)`1OQFn=6FIn4-cq%-piKnG1 zIFfN0-tv*AoltcbYoJ00!HWls@i&8om!J(O7C5>~2&7#s53f)(C|2d8Za@}%25Zo} zvJ+SK{ktx7u)}VGKd6i6qbk9{Qivx}_AHIfy#LMW`* zzJ%`C%A{9$$=G;x%yJ@7b&=PMjhrZan+!p`IEtnIjE#q-!;f&hL2;0Ff#srv4Kq2Y z9<2*gEF_j+8vA6x7hZz!mI&);_<-j>bkJ8*LIiWT|G4<*vZ7?RcS{jfz!TZJQ$cK7 zb8QhgsH-jFv&W4IsRhS~*QZ!!r%BDc-(b9KT#^|FFvW^&g|I1GJ}f~#r0Yf+y-Xj@ z8-CU~P)mF+0p76Mp_VNVi+abq=cp=aI0kOIka~0D;C5 zYdAw=)?lXxfxMWx;l#iIRdqXSB${vpD9tV+WL&?>4u7P8&JbZR1?$Ar9Di>mVXI73 zu`75sV0ie*^&?ug+n~}S)>O2Ct*fxR0SXGQIYIuQV7A;EZu({*w|jr>S;LJH7mplm zxgBP@NaPOFZiv>ItE}NO;`#yPpmc>HKhwEHgYBg(a78z{giUl>4OaRxf%2WB@Y$BEwFn`AtYbFH@FtNq`!FtFeD0K;f zzQ?Nf2(D$U;W$~7d;JRNz0J#fZ=8)N(R$zaY$)vvsR{jxVk(Yd7No-SNKR*25m9k_ zmcLt0n&q% zqdZ&@SzC{r@-_ErpalA;A3U7_ppb}R*TniYg&c(ff79Pls_A-^jzteujeKWnh+G@t|A~rQP&_P*%jY-F*YesU)7wMzbgg>4;KQ zW=~0IGI>f7&e#3us+op6gH%`qeFn;mvwvpgD!W{Mn~z9~NTh^j>09egW-tbsoQF-f z-Hz<3cc}Pp(nhK6>nKkKo#y|Rc0k(sKYZGx7bNGG{NSW~>EFNP-jm;xSQY6_icQQ`ajW z_FmzgQxk@7q0FALn`B&WMA-`d&L^^csuCWQ9yLC&#C`fn+$WU4UxU;o3MCYIVK|T! z6EZ8luF#9+3)7z(2I(szr|N+0y_+?nL}*V>3GM%a^12NTJd0hzslu;=2V~^?hA$@R zh4SSY(L+*pD=wn&a+Yt;$d$?%|12XWF$=W~Y6m+`{MF6iu8g5Eth=Nk@L~E$TwUTJ znc?}KN~E1-o-i$g$?Rd8@3762Jk#u0Oj0*HI}|5UQaf|02D= z&A2f$CFCyv?Kn~0jI;w6Ms>;mo;lSUHReahcu(eE6E4B1vvAxl1D;&I^sZ7^ksIL* zlixGmV5zTV{G*4*4AJbS)r$ZtJ7UUc!qX=xdC@Nc09&9G*~@2c6pSPN@(n$~#D3N?Oq(RF?ci6nFBFMBrK7ZH0zd6t8bsZm z--%izuRw3tOq`sqAy9wn?cD55@BXrNth#gln-9GpvZebv)qeCIEL$Vh^fFAg zZc#gLaQpPE@Cw?CTbq=y9`%6*s!MqIBV)|4wJ3EKMZ5smo2+-FAoV<$je@0k9b;#jtxvP-B?XSuMB&H*zu4Mjh`_&Wt> z_;=_{EO*ZFrC>@CqFzZcwr_5{om>?pl<-Y6bkb9WykUk$iu#nFo3T|2Ea6MDMw_QY zK;L^A7tup7Emv#|9A){te*i&|jO|Pp_A^CytYHj>#^+eWL_A$<_N!6+WycKQDy=*Z z;xs~-&6=)Co^YAk?-~wa<3|O!q6g_P+y`Beek%NF0(q9QBEo1H#-*V+FNmd~E+2O% z8$Bz$(HBo18tQ&lWaD73cz1sdafDun&Ot8+X3U%>F2AD)>C+2?(Fhxai8s^lI#3rI z-H%=3Fh@nzR&e6-ENPZx*=@QWavgY=H)FYwckJ}Q0m zJ&(;EC#rZ}_Bd%pJAXb~E4|y!Kggai5{8BI&dnb&H_W+@st%oU9MOYmoI{gW&5}xCx+z}cLtM8y=Tf+ftRpCJIU>Dr19M6go zxF#-|?@I8^uFQ(n2FliKuTnGmtJX-VbPl=WO0iTXcT88@Q71Z23R*bhdaS#OB7Vab z&{ep+d7f)$4L5HK)cVQRITCudzH<2&BD0+6cODV7{&M*&)ItyRY}@`@8!B6`t4q_g zvTXf9Dvi|+k;^}!v)Q2n{GKKs%8t}Kx;n|$oJoP&U_)hgj9k9R+j&LOM$6VK{$OsX zY&H37qtJc#cYYrbqm4o1FF-qAE|My6VPxX!uL0iFCR5j&Iv(Fco;OaM(wMT_zVh~r0M@ABwkB3Rg1%$F zY#ki{Z2abh$_s5T5amb{75wa@vxdDHZzc8_COzJ)`aW(~pEu2Pa9n$uxjWpX$_^g}0Oa524OlU+GJ z(x*54Sp7mp|6S0(^JSj#*oes0Cn3QYNHF+**SP-zAN_aZW@`RwGUZIH(3YoxZ;^hi`f5+*rwUln2k9 z6ga1m)sYPJj`OEne)$TsWjXGYRKQ_qyrMZrD?L5tU z@?#~4U-h$~(rYM)ISl}mL@ZIyrh<@BY zf2^c=naldfz#y#Y%5_r#U=%S3IG>~UpZn+cC~G;_d$Ib-iUeljJmQ?|MFP}LlC2BG z(gMs0}tw(WV&JIk~8vg5Q2c?Nr&iUer#O%eV2p`e<-})wv*>BNL0U~tahW58y6(x{e%H)5O6SZ zMu>*0Y>5sVWOdmn=i%r|0#+(*N^`098*h8+=sL}A%yd^Cgv2i_7$K)3$IxPGv^Igh6DM%F!{BA+Ibom1BFPJK> z=g%%2Cr#eX|Fm$9c;mqL3k$sXw8bCAuwDQB?{7(_X}AY-AoX} zsKbT*z}bUq7p@_Km%^}$=+@q2cn7`_!yEDZ4K6*dATyB5q&DH#$a6i&Dfc1E3htAl zsD>MY@BkBpyAOoJ@Dy+n;b0H0%7Z(gy8Cgv(d;!7a)^R_9)zK15WXMzThQzP;t^bg z8|uMT{R>+N4QUK2Jy+t690`S(9|K^3{vR|$sE7an From c1774bdb11d01fad8c18633a5306c1721e719bac Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Mon, 9 Oct 2023 17:32:12 +0200 Subject: [PATCH 0410/1077] tests/acpi: update expected data files DefinitionBlock ("", "DSDT", 1, "BOCHS ", "BXPC ", 0x00000001) { Scope (\) { OperationRegion (DBG, SystemIO, 0x0402, One) Field (DBG, ByteAcc, NoLock, Preserve) { DBGB, 8 } DWordMemory (ResourceProducer, PosDecode, MinFixed, MaxFixed, NonCacheable, ReadWrite, 0x00000000, // Granularity 0x08000000, // Range Minimum 0xAFFFFFFF, // Range Maximum 0x00000000, // Translation Offset 0xA8000000, // Length ,, , AddressRangeMemory, TypeStatic) DWordMemory (ResourceProducer, PosDecode, MinFixed, MaxFixed, NonCacheable, ReadWrite, 0x00000000, // Granularity 0xC0000000, // Range Minimum 0xFEBFFFFF, // Range Maximum 0x00000000, // Translation Offset 0x3EC00000, // Length ,, , AddressRangeMemory, TypeStatic) QWordMemory (ResourceProducer, PosDecode, MinFixed, MaxFixed, Cacheable, ReadWrite, 0x0000000000000000, // Granularity - 0x0000000200000000, // Range Minimum - 0x00000009FFFFFFFF, // Range Maximum + 0x000000FF00000000, // Range Minimum + 0x00000106FFFFFFFF, // Range Maximum 0x0000000000000000, // Translation Offset 0x0000000800000000, // Length ,, , AddressRangeMemory, TypeStatic) }) Signed-off-by: Gerd Hoffmann --- tests/data/acpi/q35/DSDT.mmio64 | Bin 9485 -> 9485 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/tests/data/acpi/q35/DSDT.mmio64 b/tests/data/acpi/q35/DSDT.mmio64 index 8459b82c958b842cd7b92c2145977634fb9c6e5d..bdf36c4d575bfc4eb2eac3f00c9b7b4270f88677 100644 GIT binary patch delta 35 pcmeD6>h`-Q3+n&? delta 35 pcmeD6>hCN{Ne!fq~&a5O6YV)>FFA1OT%k3hMv> From e83f3600f9ff7d9e0d014f328e64c49bb81b945c Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Mon, 9 Oct 2023 17:33:21 +0200 Subject: [PATCH 0411/1077] tests/acpi: disable tests/data/acpi/q35/DSDT.mmio64 updates Signed-off-by: Gerd Hoffmann --- tests/qtest/bios-tables-test-allowed-diff.h | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/qtest/bios-tables-test-allowed-diff.h b/tests/qtest/bios-tables-test-allowed-diff.h index a251b20a1b..dfb8523c8b 100644 --- a/tests/qtest/bios-tables-test-allowed-diff.h +++ b/tests/qtest/bios-tables-test-allowed-diff.h @@ -1,2 +1 @@ /* List of comma-separated changed AML files to ignore */ -"tests/data/acpi/q35/DSDT.mmio64", From 00e3b29d065f3b88bb3726afbd5c73f8b2bff1b4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Volker=20R=C3=BCmelin?= Date: Sun, 17 Sep 2023 08:58:06 +0200 Subject: [PATCH 0412/1077] hw/audio/es1370: reset current sample counter MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Reset the current sample counter when writing the Channel Sample Count Register. The Linux ens1370 driver and the AROS sb128 driver expect the current sample counter counts down from sample count to 0 after a write to the Channel Sample Count Register. Currently the current sample counter starts from 0 after a reset or the last count when the counter was stopped. The current sample counter is used to raise an interrupt whenever a complete buffer was transferred. When the counter starts with a value lower than the reload value, the interrupt triggeres before the buffer was completly transferred. This may lead to corrupted audio streams. Tested-by: Rene Engel Signed-off-by: Volker Rümelin Reviewed-by: Marc-André Lureau Tested-by: BALATON Zoltan Message-Id: <20230917065813.6692-1-vr_qemu@t-online.de> --- hw/audio/es1370.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/audio/es1370.c b/hw/audio/es1370.c index 90f73d4c23..0567721eb7 100644 --- a/hw/audio/es1370.c +++ b/hw/audio/es1370.c @@ -502,7 +502,7 @@ static void es1370_write(void *opaque, hwaddr addr, uint64_t val, unsigned size) case ES1370_REG_DAC2_SCOUNT: case ES1370_REG_ADC_SCOUNT: d += (addr - ES1370_REG_DAC1_SCOUNT) >> 2; - d->scount = (val & 0xffff) | (d->scount & ~0xffff); + d->scount = (val & 0xffff) << 16 | (val & 0xffff); ldebug ("chan %td CURR_SAMP_CT %d, SAMP_CT %d\n", d - &s->chan[0], val >> 16, (val & 0xffff)); break; From 0116f746d054a87864397fa45267cbcfe0aa89fc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Volker=20R=C3=BCmelin?= Date: Sun, 17 Sep 2023 08:58:07 +0200 Subject: [PATCH 0413/1077] hw/audio/es1370: replace bit-rotted code with tracepoints MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit It seems that nobody has enabled the debug code of the ES1370 device for a long time. Since then, the code has bit-rotted. Replace the bit-rotten code with tracepoints. Tested-by: Rene Engel Signed-off-by: Volker Rümelin Reviewed-by: Marc-André Lureau Tested-by: BALATON Zoltan Message-Id: <20230917065813.6692-2-vr_qemu@t-online.de> --- hw/audio/es1370.c | 55 ++++++++++++++----------------------------- hw/audio/trace-events | 10 ++++++++ 2 files changed, 28 insertions(+), 37 deletions(-) diff --git a/hw/audio/es1370.c b/hw/audio/es1370.c index 0567721eb7..2b55e31a9a 100644 --- a/hw/audio/es1370.c +++ b/hw/audio/es1370.c @@ -34,6 +34,7 @@ #include "qemu/module.h" #include "sysemu/dma.h" #include "qom/object.h" +#include "trace.h" /* Missing stuff: SCTRL_P[12](END|ST)INC @@ -166,8 +167,6 @@ static void es1370_adc_callback (void *opaque, int avail); #ifdef DEBUG_ES1370 -#define ldebug(...) AUD_log ("es1370", __VA_ARGS__) - static void print_ctl (uint32_t val) { char buf[1024]; @@ -239,7 +238,6 @@ static void print_sctl (uint32_t val) ); } #else -#define ldebug(...) #define print_ctl(...) #define print_sctl(...) #endif @@ -411,12 +409,9 @@ static void es1370_update_voices (ES1370State *s, uint32_t ctl, uint32_t sctl) if ((old_fmt != new_fmt) || (old_freq != new_freq)) { d->shift = (new_fmt & 1) + (new_fmt >> 1); - ldebug ("channel %zu, freq = %d, nchannels %d, fmt %d, shift %d\n", - i, - new_freq, - 1 << (new_fmt & 1), - (new_fmt & 2) ? AUDIO_FORMAT_S16 : AUDIO_FORMAT_U8, - d->shift); + trace_es1370_stream_format(i, new_freq, + new_fmt & 2 ? "s16" : "u8", new_fmt & 1 ? "stereo" : "mono", + d->shift); if (new_freq) { struct audsettings as; @@ -503,8 +498,8 @@ static void es1370_write(void *opaque, hwaddr addr, uint64_t val, unsigned size) case ES1370_REG_ADC_SCOUNT: d += (addr - ES1370_REG_DAC1_SCOUNT) >> 2; d->scount = (val & 0xffff) << 16 | (val & 0xffff); - ldebug ("chan %td CURR_SAMP_CT %d, SAMP_CT %d\n", - d - &s->chan[0], val >> 16, (val & 0xffff)); + trace_es1370_sample_count_wr(d - &s->chan[0], + d->scount >> 16, d->scount & 0xffff); break; case ES1370_REG_ADC_FRAMEADR: @@ -515,7 +510,7 @@ static void es1370_write(void *opaque, hwaddr addr, uint64_t val, unsigned size) d += (addr - ES1370_REG_DAC1_FRAMEADR) >> 3; frameadr: d->frame_addr = val; - ldebug ("chan %td frame address %#x\n", d - &s->chan[0], val); + trace_es1370_frame_address_wr(d - &s->chan[0], d->frame_addr); break; case ES1370_REG_PHANTOM_FRAMECNT: @@ -534,8 +529,8 @@ static void es1370_write(void *opaque, hwaddr addr, uint64_t val, unsigned size) framecnt: d->frame_cnt = val; d->leftover = 0; - ldebug ("chan %td frame count %d, buffer size %d\n", - d - &s->chan[0], val >> 16, val & 0xffff); + trace_es1370_frame_count_wr(d - &s->chan[0], + d->frame_cnt >> 16, d->frame_cnt & 0xffff); break; default: @@ -573,17 +568,9 @@ static uint64_t es1370_read(void *opaque, hwaddr addr, unsigned size) case ES1370_REG_DAC2_SCOUNT: case ES1370_REG_ADC_SCOUNT: d += (addr - ES1370_REG_DAC1_SCOUNT) >> 2; + trace_es1370_sample_count_rd(d - &s->chan[0], + d->scount >> 16, d->scount & 0xffff); val = d->scount; -#ifdef DEBUG_ES1370 - { - uint32_t curr_count = d->scount >> 16; - uint32_t count = d->scount & 0xffff; - - curr_count <<= d->shift; - count <<= d->shift; - dolog ("read scount curr %d, total %d\n", curr_count, count); - } -#endif break; case ES1370_REG_ADC_FRAMECNT: @@ -593,17 +580,9 @@ static uint64_t es1370_read(void *opaque, hwaddr addr, unsigned size) case ES1370_REG_DAC2_FRAMECNT: d += (addr - ES1370_REG_DAC1_FRAMECNT) >> 3; framecnt: + trace_es1370_frame_count_rd(d - &s->chan[0], + d->frame_cnt >> 16, d->frame_cnt & 0xffff); val = d->frame_cnt; -#ifdef DEBUG_ES1370 - { - uint32_t size = ((d->frame_cnt & 0xffff) + 1) << 2; - uint32_t curr = ((d->frame_cnt >> 16) + 1) << 2; - if (curr > size) { - dolog ("read framecnt curr %d, size %d %d\n", curr, size, - curr > size); - } - } -#endif break; case ES1370_REG_ADC_FRAMEADR: @@ -613,6 +592,7 @@ static uint64_t es1370_read(void *opaque, hwaddr addr, unsigned size) case ES1370_REG_DAC2_FRAMEADR: d += (addr - ES1370_REG_DAC1_FRAMEADR) >> 3; frameadr: + trace_es1370_frame_address_rd(d - &s->chan[0], d->frame_addr); val = d->frame_addr; break; @@ -689,9 +669,6 @@ static void es1370_transfer_audio (ES1370State *s, struct chan *d, int loop_sel, if (csc_bytes == transferred) { *irq = 1; d->scount = sc | (sc << 16); - ldebug ("sc = %d, rate = %f\n", - (sc + 1) << d->shift, - (sc + 1) / (double) 44100); } else { *irq = 0; @@ -713,6 +690,10 @@ static void es1370_transfer_audio (ES1370State *s, struct chan *d, int loop_sel, } d->leftover = (transferred + d->leftover) & 3; + trace_es1370_transfer_audio(index, + d->frame_cnt >> 16, d->frame_cnt & 0xffff, + d->scount >> 16, d->scount & 0xffff, + d->leftover, *irq); } static void es1370_run_channel (ES1370State *s, size_t chan, int free_or_avail) diff --git a/hw/audio/trace-events b/hw/audio/trace-events index 89ef2996e5..9ae2f717b6 100644 --- a/hw/audio/trace-events +++ b/hw/audio/trace-events @@ -6,6 +6,16 @@ cs4231_mem_readl_reg(uint32_t reg, uint32_t ret) "read reg %d: 0x%08x" cs4231_mem_writel_reg(uint32_t reg, uint32_t old, uint32_t val) "write reg %d: 0x%08x -> 0x%08x" cs4231_mem_writel_dreg(uint32_t reg, uint32_t old, uint32_t val) "write dreg %d: 0x%02x -> 0x%02x" +# es1370.c +es1370_frame_address_rd(int ch, uint32_t addr) "ch=%d addr=0x%08x" +es1370_frame_address_wr(int ch, uint32_t addr) "ch=%d addr=0x%08x" +es1370_frame_count_rd(int ch, uint32_t curr, uint32_t size) "ch=%d CURR_CT=%u BUF_SIZE=%u" +es1370_frame_count_wr(int ch, uint32_t curr, uint32_t size) "ch=%d CURR_CT=%u BUF_SIZE=%u" +es1370_sample_count_rd(int ch, uint32_t curr, uint32_t num) "ch=%d CURR_SAMP_CT=%u SAMP_CT=%u" +es1370_sample_count_wr(int ch, uint32_t curr, uint32_t num) "ch=%d CURR_SAMP_CT=%u SAMP_CT=%u" +es1370_stream_format(int ch, uint32_t freq, const char *fmt, const char *mode, uint32_t shift) "ch=%d fmt=%u:%s:%s shift=%u" +es1370_transfer_audio(int ch, uint32_t f_curr, uint32_t f_size, uint32_t s_curr, uint32_t s_num, uint32_t leftover, int irq) "ch=%d CURR_CT=%u BUF_SIZE=%u CURR_SAMP_CT=%u SAMP_CT=%u leftover=%u irq=%d" + # hda-codec.c hda_audio_running(const char *stream, int nr, bool running) "st %s, nr %d, run %d" hda_audio_format(const char *stream, int chan, const char *fmt, int freq) "st %s, %d x %s @ %d Hz" From 190514258c337d0763f43ba55363b820a32c1dd7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Volker=20R=C3=BCmelin?= Date: Sun, 17 Sep 2023 08:58:08 +0200 Subject: [PATCH 0414/1077] hw/audio/es1370: remove unused dolog macro MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The dolog macro is unused. Remove the macro and use the now unused ES1370_VERBOSE macro to replace its inverse ES1370_SILENT macro. Tested-by: Rene Engel Signed-off-by: Volker Rümelin Reviewed-by: Marc-André Lureau Tested-by: BALATON Zoltan Message-Id: <20230917065813.6692-3-vr_qemu@t-online.de> --- hw/audio/es1370.c | 7 ------- 1 file changed, 7 deletions(-) diff --git a/hw/audio/es1370.c b/hw/audio/es1370.c index 2b55e31a9a..dd09fd59e1 100644 --- a/hw/audio/es1370.c +++ b/hw/audio/es1370.c @@ -24,7 +24,6 @@ /* #define DEBUG_ES1370 */ /* #define VERBOSE_ES1370 */ -#define SILENT_ES1370 #include "qemu/osdep.h" #include "hw/audio/soundhw.h" @@ -243,12 +242,6 @@ static void print_sctl (uint32_t val) #endif #ifdef VERBOSE_ES1370 -#define dolog(...) AUD_log ("es1370", __VA_ARGS__) -#else -#define dolog(...) -#endif - -#ifndef SILENT_ES1370 #define lwarn(...) AUD_log ("es1370: warning", __VA_ARGS__) #else #define lwarn(...) From 480e4c7abc9cb9e45b32563081841407016ed6aa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Volker=20R=C3=BCmelin?= Date: Sun, 17 Sep 2023 08:58:09 +0200 Subject: [PATCH 0415/1077] hw/audio/es1370: remove #ifdef ES1370_DEBUG to avoid bit rot MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Replace the #ifdef ES1370_DEBUG code with code that the compiler can optimize away to avoid bit rot. While at it, replace strcat() with pstrcat(). Tested-by: Rene Engel Signed-off-by: Volker Rümelin Reviewed-by: Marc-André Lureau Tested-by: BALATON Zoltan Message-Id: <20230917065813.6692-4-vr_qemu@t-online.de> --- hw/audio/es1370.c | 129 ++++++++++++++++++++++------------------------ 1 file changed, 63 insertions(+), 66 deletions(-) diff --git a/hw/audio/es1370.c b/hw/audio/es1370.c index dd09fd59e1..f111206709 100644 --- a/hw/audio/es1370.c +++ b/hw/audio/es1370.c @@ -22,7 +22,7 @@ * THE SOFTWARE. */ -/* #define DEBUG_ES1370 */ +#define DEBUG_ES1370 0 /* #define VERBOSE_ES1370 */ #include "qemu/osdep.h" @@ -30,6 +30,7 @@ #include "audio/audio.h" #include "hw/pci/pci_device.h" #include "migration/vmstate.h" +#include "qemu/cutils.h" #include "qemu/module.h" #include "sysemu/dma.h" #include "qom/object.h" @@ -164,82 +165,78 @@ static void es1370_dac1_callback (void *opaque, int free); static void es1370_dac2_callback (void *opaque, int free); static void es1370_adc_callback (void *opaque, int avail); -#ifdef DEBUG_ES1370 - -static void print_ctl (uint32_t val) +static void print_ctl(uint32_t val) { - char buf[1024]; + if (DEBUG_ES1370) { + char buf[1024]; - buf[0] = '\0'; -#define a(n) if (val & CTRL_##n) strcat (buf, " "#n) - a (ADC_STOP); - a (XCTL1); - a (OPEN); - a (MSFMTSEL); - a (M_SBB); - a (DAC_SYNC); - a (CCB_INTRM); - a (M_CB); - a (XCTL0); - a (BREQ); - a (DAC1_EN); - a (DAC2_EN); - a (ADC_EN); - a (UART_EN); - a (JYSTK_EN); - a (CDC_EN); - a (SERR_DIS); + buf[0] = '\0'; +#define a(n) if (val & CTRL_##n) pstrcat(buf, sizeof(buf), " "#n) + a(ADC_STOP); + a(XCTL1); + a(OPEN); + a(MSFMTSEL); + a(M_SBB); + a(DAC_SYNC); + a(CCB_INTRM); + a(M_CB); + a(XCTL0); + a(BREQ); + a(DAC1_EN); + a(DAC2_EN); + a(ADC_EN); + a(UART_EN); + a(JYSTK_EN); + a(CDC_EN); + a(SERR_DIS); #undef a - AUD_log ("es1370", "ctl - PCLKDIV %d(DAC2 freq %d), freq %d,%s\n", - (val & CTRL_PCLKDIV) >> CTRL_SH_PCLKDIV, - DAC2_DIVTOSR ((val & CTRL_PCLKDIV) >> CTRL_SH_PCLKDIV), - dac1_samplerate[(val & CTRL_WTSRSEL) >> CTRL_SH_WTSRSEL], - buf); + AUD_log("es1370", "ctl - PCLKDIV %d(DAC2 freq %d), freq %d,%s\n", + (val & CTRL_PCLKDIV) >> CTRL_SH_PCLKDIV, + DAC2_DIVTOSR((val & CTRL_PCLKDIV) >> CTRL_SH_PCLKDIV), + dac1_samplerate[(val & CTRL_WTSRSEL) >> CTRL_SH_WTSRSEL], + buf); + } } -static void print_sctl (uint32_t val) +static void print_sctl(uint32_t val) { - static const char *fmt_names[] = {"8M", "8S", "16M", "16S"}; - char buf[1024]; + if (DEBUG_ES1370) { + static const char *fmt_names[] = {"8M", "8S", "16M", "16S"}; + char buf[1024]; - buf[0] = '\0'; + buf[0] = '\0'; -#define a(n) if (val & SCTRL_##n) strcat (buf, " "#n) -#define b(n) if (!(val & SCTRL_##n)) strcat (buf, " "#n) - b (R1LOOPSEL); - b (P2LOOPSEL); - b (P1LOOPSEL); - a (P2PAUSE); - a (P1PAUSE); - a (R1INTEN); - a (P2INTEN); - a (P1INTEN); - a (P1SCTRLD); - a (P2DACSEN); - if (buf[0]) { - strcat (buf, "\n "); - } - else { - buf[0] = ' '; - buf[1] = '\0'; - } +#define a(n) if (val & SCTRL_##n) pstrcat(buf, sizeof(buf), " "#n) +#define b(n) if (!(val & SCTRL_##n)) pstrcat(buf, sizeof(buf), " "#n) + b(R1LOOPSEL); + b(P2LOOPSEL); + b(P1LOOPSEL); + a(P2PAUSE); + a(P1PAUSE); + a(R1INTEN); + a(P2INTEN); + a(P1INTEN); + a(P1SCTRLD); + a(P2DACSEN); + if (buf[0]) { + pstrcat(buf, sizeof(buf), "\n "); + } else { + buf[0] = ' '; + buf[1] = '\0'; + } #undef b #undef a - AUD_log ("es1370", - "%s" - "p2_end_inc %d, p2_st_inc %d, r1_fmt %s, p2_fmt %s, p1_fmt %s\n", - buf, - (val & SCTRL_P2ENDINC) >> SCTRL_SH_P2ENDINC, - (val & SCTRL_P2STINC) >> SCTRL_SH_P2STINC, - fmt_names [(val >> SCTRL_SH_R1FMT) & 3], - fmt_names [(val >> SCTRL_SH_P2FMT) & 3], - fmt_names [(val >> SCTRL_SH_P1FMT) & 3] - ); + AUD_log("es1370", + "%s p2_end_inc %d, p2_st_inc %d," + " r1_fmt %s, p2_fmt %s, p1_fmt %s\n", + buf, + (val & SCTRL_P2ENDINC) >> SCTRL_SH_P2ENDINC, + (val & SCTRL_P2STINC) >> SCTRL_SH_P2STINC, + fmt_names[(val >> SCTRL_SH_R1FMT) & 3], + fmt_names[(val >> SCTRL_SH_P2FMT) & 3], + fmt_names[(val >> SCTRL_SH_P1FMT) & 3]); + } } -#else -#define print_ctl(...) -#define print_sctl(...) -#endif #ifdef VERBOSE_ES1370 #define lwarn(...) AUD_log ("es1370: warning", __VA_ARGS__) From a4b342a3318667bb962ca28e2286dc2e53397c7a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Volker=20R=C3=BCmelin?= Date: Sun, 17 Sep 2023 08:58:10 +0200 Subject: [PATCH 0416/1077] hw/audio/es1370: remove #ifdef ES1370_VERBOSE to avoid bit rot MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Replace the #ifdef ES1370_VERBOSE code with code that the compiler can optimize away to avoid bit rot and fix the already rotten code. Tested-by: Rene Engel Signed-off-by: Volker Rümelin Reviewed-by: Marc-André Lureau Tested-by: BALATON Zoltan Message-Id: <20230917065813.6692-5-vr_qemu@t-online.de> --- hw/audio/es1370.c | 25 +++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/hw/audio/es1370.c b/hw/audio/es1370.c index f111206709..7c58337076 100644 --- a/hw/audio/es1370.c +++ b/hw/audio/es1370.c @@ -23,7 +23,7 @@ */ #define DEBUG_ES1370 0 -/* #define VERBOSE_ES1370 */ +#define VERBOSE_ES1370 0 #include "qemu/osdep.h" #include "hw/audio/soundhw.h" @@ -238,11 +238,12 @@ static void print_sctl(uint32_t val) } } -#ifdef VERBOSE_ES1370 -#define lwarn(...) AUD_log ("es1370: warning", __VA_ARGS__) -#else -#define lwarn(...) -#endif +#define lwarn(...) \ +do { \ + if (VERBOSE_ES1370) { \ + AUD_log("es1370: warning", __VA_ARGS__); \ + } \ +} while (0) #define TYPE_ES1370 "ES1370" OBJECT_DECLARE_SIMPLE_TYPE(ES1370State, ES1370) @@ -504,10 +505,10 @@ static void es1370_write(void *opaque, hwaddr addr, uint64_t val, unsigned size) break; case ES1370_REG_PHANTOM_FRAMECNT: - lwarn ("writing to phantom frame count %#x\n", val); + lwarn("writing to phantom frame count 0x%" PRIx64 "\n", val); break; case ES1370_REG_PHANTOM_FRAMEADR: - lwarn ("writing to phantom frame address %#x\n", val); + lwarn("writing to phantom frame address 0x%" PRIx64 "\n", val); break; case ES1370_REG_ADC_FRAMECNT: @@ -524,7 +525,7 @@ static void es1370_write(void *opaque, hwaddr addr, uint64_t val, unsigned size) break; default: - lwarn ("writel %#x <- %#x\n", addr, val); + lwarn("writel 0x%" PRIx64 " <- 0x%" PRIx64 "\n", addr, val); break; } } @@ -588,16 +589,16 @@ static uint64_t es1370_read(void *opaque, hwaddr addr, unsigned size) case ES1370_REG_PHANTOM_FRAMECNT: val = ~0U; - lwarn ("reading from phantom frame count\n"); + lwarn("reading from phantom frame count\n"); break; case ES1370_REG_PHANTOM_FRAMEADR: val = ~0U; - lwarn ("reading from phantom frame address\n"); + lwarn("reading from phantom frame address\n"); break; default: val = ~0U; - lwarn ("readl %#x -> %#x\n", addr, val); + lwarn("readl 0x%" PRIx64 " -> 0x%x\n", addr, val); break; } return val; From 02e7de686ae6d1ac3419e1c5bfc038599c493f4a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Volker=20R=C3=BCmelin?= Date: Sun, 17 Sep 2023 08:58:11 +0200 Subject: [PATCH 0417/1077] hw/audio/es1370: block structure coding style fixes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Change the block structure according to the QEMU Coding Style documentation. Signed-off-by: Volker Rümelin Reviewed-by: Marc-André Lureau Tested-by: BALATON Zoltan Message-Id: <20230917065813.6692-6-vr_qemu@t-online.de> --- hw/audio/es1370.c | 36 ++++++++++++++++-------------------- 1 file changed, 16 insertions(+), 20 deletions(-) diff --git a/hw/audio/es1370.c b/hw/audio/es1370.c index 7c58337076..b4c00df189 100644 --- a/hw/audio/es1370.c +++ b/hw/audio/es1370.c @@ -309,8 +309,7 @@ static void es1370_update_status (ES1370State *s, uint32_t new_status) if (level) { s->status = new_status | STAT_INTR; - } - else { + } else { s->status = new_status & ~STAT_INTR; } pci_set_irq(&s->dev, !!level); @@ -333,8 +332,7 @@ static void es1370_reset (ES1370State *s) if (i == ADC_CHANNEL) { AUD_close_in (&s->card, s->adc_voice); s->adc_voice = NULL; - } - else { + } else { AUD_close_out (&s->card, s->dac_voice[i]); s->dac_voice[i] = NULL; } @@ -421,8 +419,7 @@ static void es1370_update_voices (ES1370State *s, uint32_t ctl, uint32_t sctl) es1370_adc_callback, &as ); - } - else { + } else { s->dac_voice[i] = AUD_open_out ( &s->card, @@ -442,8 +439,7 @@ static void es1370_update_voices (ES1370State *s, uint32_t ctl, uint32_t sctl) if (i == ADC_CHANNEL) { AUD_set_active_in (s->adc_voice, on); - } - else { + } else { AUD_set_active_out (s->dac_voice[i], on); } } @@ -456,8 +452,9 @@ static void es1370_update_voices (ES1370State *s, uint32_t ctl, uint32_t sctl) static inline uint32_t es1370_fixup (ES1370State *s, uint32_t addr) { addr &= 0xff; - if (addr >= 0x30 && addr <= 0x3f) + if (addr >= 0x30 && addr <= 0x3f) { addr |= s->mempage << 8; + } return addr; } @@ -630,8 +627,9 @@ static void es1370_transfer_audio (ES1370State *s, struct chan *d, int loop_sel, to_copy = MIN ((size_t) temp, sizeof (tmpbuf)); acquired = AUD_read (s->adc_voice, tmpbuf, to_copy); - if (!acquired) + if (!acquired) { break; + } pci_dma_write (&s->dev, addr, tmpbuf, acquired); @@ -639,8 +637,7 @@ static void es1370_transfer_audio (ES1370State *s, struct chan *d, int loop_sel, addr += acquired; transferred += acquired; } - } - else { + } else { SWVoiceOut *voice = s->dac_voice[index]; while (temp > 0) { @@ -649,8 +646,9 @@ static void es1370_transfer_audio (ES1370State *s, struct chan *d, int loop_sel, to_copy = MIN ((size_t) temp, sizeof (tmpbuf)); pci_dma_read (&s->dev, addr, tmpbuf, to_copy); copied = AUD_write (voice, tmpbuf, to_copy); - if (!copied) + if (!copied) { break; + } temp -= copied; addr += copied; transferred += copied; @@ -660,8 +658,7 @@ static void es1370_transfer_audio (ES1370State *s, struct chan *d, int loop_sel, if (csc_bytes == transferred) { *irq = 1; d->scount = sc | (sc << 16); - } - else { + } else { *irq = 0; d->scount = sc | (((csc_bytes - transferred - 1) >> d->shift) << 16); } @@ -672,12 +669,12 @@ static void es1370_transfer_audio (ES1370State *s, struct chan *d, int loop_sel, /* Bah, how stupid is that having a 0 represent true value? i just spent few hours on this shit */ AUD_log ("es1370: warning", "non looping mode\n"); - } - else { + } else { d->frame_cnt = size; - if ((uint32_t) cnt <= d->frame_cnt) + if ((uint32_t) cnt <= d->frame_cnt) { d->frame_cnt |= cnt << 16; + } } d->leftover = (transferred + d->leftover) & 3; @@ -778,8 +775,7 @@ static int es1370_post_load (void *opaque, int version_id) AUD_close_in (&s->card, s->adc_voice); s->adc_voice = NULL; } - } - else { + } else { if (s->dac_voice[i]) { AUD_close_out (&s->card, s->dac_voice[i]); s->dac_voice[i] = NULL; From ca98851835645f46eaa5b98bbfb307650b42fc64 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Volker=20R=C3=BCmelin?= Date: Sun, 17 Sep 2023 08:58:12 +0200 Subject: [PATCH 0418/1077] hw/audio/es1370: change variable type and name MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Change the type of the variable temp to size_t to avoid a type cast. While at it, rename the variable name to to_transfer. This improves the readability of the code. Signed-off-by: Volker Rümelin Reviewed-by: Marc-André Lureau Tested-by: BALATON Zoltan Message-Id: <20230917065813.6692-7-vr_qemu@t-online.de> --- hw/audio/es1370.c | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/hw/audio/es1370.c b/hw/audio/es1370.c index b4c00df189..b47794f786 100644 --- a/hw/audio/es1370.c +++ b/hw/audio/es1370.c @@ -605,6 +605,7 @@ static void es1370_transfer_audio (ES1370State *s, struct chan *d, int loop_sel, int max, int *irq) { uint8_t tmpbuf[4096]; + size_t to_transfer; uint32_t addr = d->frame_addr; int sc = d->scount & 0xffff; int csc = d->scount >> 16; @@ -616,16 +617,16 @@ static void es1370_transfer_audio (ES1370State *s, struct chan *d, int loop_sel, } int left = ((size - cnt + 1) << 2) + d->leftover; int transferred = 0; - int temp = MIN (max, MIN (left, csc_bytes)); int index = d - &s->chan[0]; + to_transfer = MIN(max, MIN(left, csc_bytes)); addr += (cnt << 2) + d->leftover; if (index == ADC_CHANNEL) { - while (temp > 0) { + while (to_transfer > 0) { int acquired, to_copy; - to_copy = MIN ((size_t) temp, sizeof (tmpbuf)); + to_copy = MIN(to_transfer, sizeof(tmpbuf)); acquired = AUD_read (s->adc_voice, tmpbuf, to_copy); if (!acquired) { break; @@ -633,23 +634,23 @@ static void es1370_transfer_audio (ES1370State *s, struct chan *d, int loop_sel, pci_dma_write (&s->dev, addr, tmpbuf, acquired); - temp -= acquired; + to_transfer -= acquired; addr += acquired; transferred += acquired; } } else { SWVoiceOut *voice = s->dac_voice[index]; - while (temp > 0) { + while (to_transfer > 0) { int copied, to_copy; - to_copy = MIN ((size_t) temp, sizeof (tmpbuf)); + to_copy = MIN(to_transfer, sizeof(tmpbuf)); pci_dma_read (&s->dev, addr, tmpbuf, to_copy); copied = AUD_write (voice, tmpbuf, to_copy); if (!copied) { break; } - temp -= copied; + to_transfer -= copied; addr += copied; transferred += copied; } From 5bf1a71c5b7b2d1999f65c08b4d82b5dec9f3013 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Volker=20R=C3=BCmelin?= Date: Sun, 17 Sep 2023 08:58:13 +0200 Subject: [PATCH 0419/1077] hw/audio/es1370: trace lost interrupts MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit It turns out that there are drivers which assume that interrupts can't be lost. E.g. the AROS sb128 driver is such a driver. Add a lost interrupt tracepoint to debug this kind of issues. Signed-off-by: Volker Rümelin Reviewed-by: Marc-André Lureau Tested-by: BALATON Zoltan Message-Id: <20230917065813.6692-8-vr_qemu@t-online.de> --- hw/audio/es1370.c | 14 ++++++++++---- hw/audio/trace-events | 3 ++- 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/hw/audio/es1370.c b/hw/audio/es1370.c index b47794f786..91c47330ad 100644 --- a/hw/audio/es1370.c +++ b/hw/audio/es1370.c @@ -602,7 +602,7 @@ static uint64_t es1370_read(void *opaque, hwaddr addr, unsigned size) } static void es1370_transfer_audio (ES1370State *s, struct chan *d, int loop_sel, - int max, int *irq) + int max, bool *irq) { uint8_t tmpbuf[4096]; size_t to_transfer; @@ -657,10 +657,13 @@ static void es1370_transfer_audio (ES1370State *s, struct chan *d, int loop_sel, } if (csc_bytes == transferred) { - *irq = 1; + if (*irq) { + trace_es1370_lost_interrupt(index); + } + *irq = true; d->scount = sc | (sc << 16); } else { - *irq = 0; + *irq = false; d->scount = sc | (((csc_bytes - transferred - 1) >> d->shift) << 16); } @@ -688,7 +691,8 @@ static void es1370_transfer_audio (ES1370State *s, struct chan *d, int loop_sel, static void es1370_run_channel (ES1370State *s, size_t chan, int free_or_avail) { uint32_t new_status = s->status; - int max_bytes, irq; + int max_bytes; + bool irq; struct chan *d = &s->chan[chan]; const struct chan_bits *b = &es1370_chan_bits[chan]; @@ -702,6 +706,8 @@ static void es1370_run_channel (ES1370State *s, size_t chan, int free_or_avail) return; } + irq = s->sctl & b->sctl_inten && s->status & b->stat_int; + es1370_transfer_audio (s, d, b->sctl_loopsel, max_bytes, &irq); if (irq) { diff --git a/hw/audio/trace-events b/hw/audio/trace-events index 9ae2f717b6..059ce451f5 100644 --- a/hw/audio/trace-events +++ b/hw/audio/trace-events @@ -11,10 +11,11 @@ es1370_frame_address_rd(int ch, uint32_t addr) "ch=%d addr=0x%08x" es1370_frame_address_wr(int ch, uint32_t addr) "ch=%d addr=0x%08x" es1370_frame_count_rd(int ch, uint32_t curr, uint32_t size) "ch=%d CURR_CT=%u BUF_SIZE=%u" es1370_frame_count_wr(int ch, uint32_t curr, uint32_t size) "ch=%d CURR_CT=%u BUF_SIZE=%u" +es1370_lost_interrupt(int ch) "ch=%d lost interrupt" es1370_sample_count_rd(int ch, uint32_t curr, uint32_t num) "ch=%d CURR_SAMP_CT=%u SAMP_CT=%u" es1370_sample_count_wr(int ch, uint32_t curr, uint32_t num) "ch=%d CURR_SAMP_CT=%u SAMP_CT=%u" es1370_stream_format(int ch, uint32_t freq, const char *fmt, const char *mode, uint32_t shift) "ch=%d fmt=%u:%s:%s shift=%u" -es1370_transfer_audio(int ch, uint32_t f_curr, uint32_t f_size, uint32_t s_curr, uint32_t s_num, uint32_t leftover, int irq) "ch=%d CURR_CT=%u BUF_SIZE=%u CURR_SAMP_CT=%u SAMP_CT=%u leftover=%u irq=%d" +es1370_transfer_audio(int ch, uint32_t f_curr, uint32_t f_size, uint32_t s_curr, uint32_t s_num, uint32_t leftover, bool irq) "ch=%d CURR_CT=%u BUF_SIZE=%u CURR_SAMP_CT=%u SAMP_CT=%u leftover=%u irq=%d" # hda-codec.c hda_audio_running(const char *stream, int nr, bool running) "st %s, nr %d, run %d" From 404b78446aedbc660f41f7737bef3e8b1ec7d90d Mon Sep 17 00:00:00 2001 From: Marcin Juszkiewicz Date: Mon, 9 Oct 2023 17:40:40 +0100 Subject: [PATCH 0420/1077] tests/avocado: update firmware to enable OpenBSD test on sbsa-ref MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Update prebuilt firmware images: - Neoverse V1/N2 cpu support - non-secure EL2 virtual timer - XHCI controller in DSDT With those changes we can now run OpenBSD as part of sbsa-ref tests. Signed-off-by: Marcin Juszkiewicz Message-Id: <20230927120050.210187-2-marcin.juszkiewicz@linaro.org> [AJB: fix whitespace and longline] Reviewed-by: Philippe Mathieu-Daudé Tested-by: Philippe Mathieu-Daudé Signed-off-by: Alex Bennée Message-Id: <20231009164104.369749-2-alex.bennee@linaro.org> --- tests/avocado/machine_aarch64_sbsaref.py | 70 ++++++++++++++++++++---- 1 file changed, 60 insertions(+), 10 deletions(-) diff --git a/tests/avocado/machine_aarch64_sbsaref.py b/tests/avocado/machine_aarch64_sbsaref.py index a794245e7e..b272053eaf 100644 --- a/tests/avocado/machine_aarch64_sbsaref.py +++ b/tests/avocado/machine_aarch64_sbsaref.py @@ -28,33 +28,33 @@ class Aarch64SbsarefMachine(QemuSystemTest): """ Flash volumes generated using: - - Fedora GNU Toolchain version 13.1.1 20230511 (Red Hat 13.1.1-2) + - Fedora GNU Toolchain version 13.2.1 20230728 (Red Hat 13.2.1-1) - Trusted Firmware-A - https://github.com/ARM-software/arm-trusted-firmware/tree/c0d8ee38 + https://github.com/ARM-software/arm-trusted-firmware/tree/7c3ff62d - Tianocore EDK II https://github.com/tianocore/edk2/tree/0f9283429dd4 - https://github.com/tianocore/edk2-non-osi/tree/f0bb00937ad6 - https://github.com/tianocore/edk2-platforms/tree/7880b92e2a04 + https://github.com/tianocore/edk2/tree/ad1c0394b177 + https://github.com/tianocore/edk2-platforms/tree/d03a60523a60 """ # Secure BootRom (TF-A code) fs0_xz_url = ( - "https://fileserver.linaro.org/s/HrYMCjP7MEccjRP/" + "https://fileserver.linaro.org/s/rE43RJyTfxPtBkc/" "download/SBSA_FLASH0.fd.xz" ) - fs0_xz_hash = "447eff64a90b84ce47703c6ec41fbfc25befaaea" + fs0_xz_hash = "cdb8e4ffdaaa79292b7b465693f9e5fae6b7062d" tar_xz_path = self.fetch_asset(fs0_xz_url, asset_hash=fs0_xz_hash) archive.extract(tar_xz_path, self.workdir) fs0_path = os.path.join(self.workdir, "SBSA_FLASH0.fd") # Non-secure rom (UEFI and EFI variables) fs1_xz_url = ( - "https://fileserver.linaro.org/s/t8foNnMPz74DZZy/" + "https://fileserver.linaro.org/s/AGWPDXbcqJTKS4R/" "download/SBSA_FLASH1.fd.xz" ) - fs1_xz_hash = "13a9a262953787c7fc5a9155dfaa26e703631e02" + fs1_xz_hash = "411155ae6984334714dff08d5d628178e790c875" tar_xz_path = self.fetch_asset(fs1_xz_url, asset_hash=fs1_xz_hash) archive.extract(tar_xz_path, self.workdir) fs1_path = os.path.join(self.workdir, "SBSA_FLASH1.fd") @@ -144,7 +144,7 @@ class Aarch64SbsarefMachine(QemuSystemTest): def test_sbsaref_alpine_linux_neoverse_n1(self): """ - :avocado: tags=cpu:max + :avocado: tags=cpu:neoverse-n1 """ self.boot_alpine_linux("neoverse-n1") @@ -152,4 +152,54 @@ class Aarch64SbsarefMachine(QemuSystemTest): """ :avocado: tags=cpu:max """ - self.boot_alpine_linux("max,pauth-impdef=on") + self.boot_alpine_linux("max") + + + # This tests the whole boot chain from EFI to Userspace + # We only boot a whole OS for the current top level CPU and GIC + # Other test profiles should use more minimal boots + def boot_openbsd73(self, cpu): + self.fetch_firmware() + + img_url = ( + "https://cdn.openbsd.org/pub/OpenBSD/7.3/arm64/miniroot73.img" + ) + + img_hash = "7fc2c75401d6f01fbfa25f4953f72ad7d7c18650056d30755c44b9c129b707e5" + img_path = self.fetch_asset(img_url, algorithm="sha256", asset_hash=img_hash) + + self.vm.set_console() + self.vm.add_args( + "-cpu", + cpu, + "-drive", + f"file={img_path},format=raw", + "-device", + "virtio-rng-pci,rng=rng0", + "-object", + "rng-random,id=rng0,filename=/dev/urandom", + ) + + self.vm.launch() + wait_for_console_pattern(self, + "Welcome to the OpenBSD/arm64" + " 7.3 installation program.") + + def test_sbsaref_openbsd73_cortex_a57(self): + """ + :avocado: tags=cpu:cortex-a57 + """ + self.boot_openbsd73("cortex-a57") + + def test_sbsaref_openbsd73_neoverse_n1(self): + """ + :avocado: tags=cpu:neoverse-n1 + """ + self.boot_openbsd73("neoverse-n1") + + def test_sbsaref_openbsd73_max(self): + """ + :avocado: tags=cpu:max + """ + self.boot_openbsd73("max") + From a956ea5b3473cfbaf90a8525ec78dd9c62fd8e03 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20Benn=C3=A9e?= Date: Mon, 9 Oct 2023 17:40:41 +0100 Subject: [PATCH 0421/1077] tests/avocado: remove flaky test marking for test_sbsaref_edk2_firmware MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit After testing locally I decided to revert a5754847e0 (tests/avocado: Disable the test_sbsaref_edk2_firmware by default) as the test seems pretty stable: env QEMU_TEST_FLAKY_TESTS=1 retry.py -n 50 -c -- \ ./tests/venv/bin/avocado run \ ./tests/avocado/machine_aarch64_sbsaref.py:Aarch64SbsarefMachine.test_sbsaref_edk2_firmware yields: Results summary: 0: 50 times (100.00%), avg time 2.064 (0.04 varience/0.19 deviation) Ran command 50 times, 50 passes Maybe f0ec14c78c (tests/avocado: Fix console data loss) has made it more reliable? Cc: Thomas Huth Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Alex Bennée Message-Id: <20231009164104.369749-3-alex.bennee@linaro.org> --- tests/avocado/machine_aarch64_sbsaref.py | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/avocado/machine_aarch64_sbsaref.py b/tests/avocado/machine_aarch64_sbsaref.py index b272053eaf..bdd1efc768 100644 --- a/tests/avocado/machine_aarch64_sbsaref.py +++ b/tests/avocado/machine_aarch64_sbsaref.py @@ -75,7 +75,6 @@ class Aarch64SbsarefMachine(QemuSystemTest): "sbsa-ref", ) - @skipUnless(os.getenv('QEMU_TEST_FLAKY_TESTS'), 'Test is not reliable') def test_sbsaref_edk2_firmware(self): """ :avocado: tags=cpu:cortex-a57 From 3e3df0d84f8e23c56d64eef802c79d3de383b62f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20Benn=C3=A9e?= Date: Mon, 9 Oct 2023 17:40:42 +0100 Subject: [PATCH 0422/1077] tests/lcitool: add swtpm to the package list MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We need this to test some TPM stuff. Reviewed-by: "Daniel P. Berrangé" Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Alex Bennée Message-Id: <20231009164104.369749-4-alex.bennee@linaro.org> --- .gitlab-ci.d/cirrus/macos-12.vars | 2 +- tests/docker/dockerfiles/alpine.docker | 1 + tests/docker/dockerfiles/centos8.docker | 1 + tests/docker/dockerfiles/debian-amd64-cross.docker | 1 + tests/docker/dockerfiles/debian-amd64.docker | 1 + tests/docker/dockerfiles/debian-arm64-cross.docker | 1 + tests/docker/dockerfiles/debian-armhf-cross.docker | 1 + tests/docker/dockerfiles/debian-ppc64el-cross.docker | 1 + tests/docker/dockerfiles/debian-s390x-cross.docker | 1 + tests/docker/dockerfiles/fedora-win32-cross.docker | 1 + tests/docker/dockerfiles/fedora-win64-cross.docker | 1 + tests/docker/dockerfiles/fedora.docker | 1 + tests/docker/dockerfiles/opensuse-leap.docker | 1 + tests/docker/dockerfiles/ubuntu2204.docker | 1 + tests/lcitool/libvirt-ci | 2 +- tests/lcitool/projects/qemu.yml | 1 + 16 files changed, 16 insertions(+), 2 deletions(-) diff --git a/.gitlab-ci.d/cirrus/macos-12.vars b/.gitlab-ci.d/cirrus/macos-12.vars index 80eadaab29..5f3fb346d1 100644 --- a/.gitlab-ci.d/cirrus/macos-12.vars +++ b/.gitlab-ci.d/cirrus/macos-12.vars @@ -11,6 +11,6 @@ MAKE='/opt/homebrew/bin/gmake' NINJA='/opt/homebrew/bin/ninja' PACKAGING_COMMAND='brew' PIP3='/opt/homebrew/bin/pip3' -PKGS='bash bc bison bzip2 capstone ccache cmocka ctags curl dbus diffutils dtc flex gcovr gettext git glib gnu-sed gnutls gtk+3 jemalloc jpeg-turbo json-c libepoxy libffi libgcrypt libiscsi libnfs libpng libslirp libssh libtasn1 libusb llvm lzo make meson mtools ncurses nettle ninja pixman pkg-config python3 rpm2cpio sdl2 sdl2_image snappy socat sparse spice-protocol tesseract usbredir vde vte3 xorriso zlib zstd' +PKGS='bash bc bison bzip2 capstone ccache cmocka ctags curl dbus diffutils dtc flex gcovr gettext git glib gnu-sed gnutls gtk+3 jemalloc jpeg-turbo json-c libepoxy libffi libgcrypt libiscsi libnfs libpng libslirp libssh libtasn1 libusb llvm lzo make meson mtools ncurses nettle ninja pixman pkg-config python3 rpm2cpio sdl2 sdl2_image snappy socat sparse spice-protocol swtpm tesseract usbredir vde vte3 xorriso zlib zstd' PYPI_PKGS='PyYAML numpy pillow sphinx sphinx-rtd-theme tomli' PYTHON='/opt/homebrew/bin/python3' diff --git a/tests/docker/dockerfiles/alpine.docker b/tests/docker/dockerfiles/alpine.docker index d25649cb4f..42f6928627 100644 --- a/tests/docker/dockerfiles/alpine.docker +++ b/tests/docker/dockerfiles/alpine.docker @@ -100,6 +100,7 @@ RUN apk update && \ sparse \ spice-dev \ spice-protocol \ + swtpm \ tar \ tesseract-ocr \ usbredir-dev \ diff --git a/tests/docker/dockerfiles/centos8.docker b/tests/docker/dockerfiles/centos8.docker index 68bfe606f5..d97c30e96a 100644 --- a/tests/docker/dockerfiles/centos8.docker +++ b/tests/docker/dockerfiles/centos8.docker @@ -107,6 +107,7 @@ RUN dnf distro-sync -y && \ socat \ spice-protocol \ spice-server-devel \ + swtpm \ systemd-devel \ systemtap-sdt-devel \ tar \ diff --git a/tests/docker/dockerfiles/debian-amd64-cross.docker b/tests/docker/dockerfiles/debian-amd64-cross.docker index 0991938595..00bdc06021 100644 --- a/tests/docker/dockerfiles/debian-amd64-cross.docker +++ b/tests/docker/dockerfiles/debian-amd64-cross.docker @@ -55,6 +55,7 @@ RUN export DEBIAN_FRONTEND=noninteractive && \ sed \ socat \ sparse \ + swtpm \ tar \ tesseract-ocr \ tesseract-ocr-eng \ diff --git a/tests/docker/dockerfiles/debian-amd64.docker b/tests/docker/dockerfiles/debian-amd64.docker index 61dbc3ff24..9b50fb2f63 100644 --- a/tests/docker/dockerfiles/debian-amd64.docker +++ b/tests/docker/dockerfiles/debian-amd64.docker @@ -124,6 +124,7 @@ RUN export DEBIAN_FRONTEND=noninteractive && \ sed \ socat \ sparse \ + swtpm \ systemtap-sdt-dev \ tar \ tesseract-ocr \ diff --git a/tests/docker/dockerfiles/debian-arm64-cross.docker b/tests/docker/dockerfiles/debian-arm64-cross.docker index 74eabb274e..2dae3777f7 100644 --- a/tests/docker/dockerfiles/debian-arm64-cross.docker +++ b/tests/docker/dockerfiles/debian-arm64-cross.docker @@ -55,6 +55,7 @@ RUN export DEBIAN_FRONTEND=noninteractive && \ sed \ socat \ sparse \ + swtpm \ tar \ tesseract-ocr \ tesseract-ocr-eng \ diff --git a/tests/docker/dockerfiles/debian-armhf-cross.docker b/tests/docker/dockerfiles/debian-armhf-cross.docker index 1ebd6ebd00..180ed836e6 100644 --- a/tests/docker/dockerfiles/debian-armhf-cross.docker +++ b/tests/docker/dockerfiles/debian-armhf-cross.docker @@ -55,6 +55,7 @@ RUN export DEBIAN_FRONTEND=noninteractive && \ sed \ socat \ sparse \ + swtpm \ tar \ tesseract-ocr \ tesseract-ocr-eng \ diff --git a/tests/docker/dockerfiles/debian-ppc64el-cross.docker b/tests/docker/dockerfiles/debian-ppc64el-cross.docker index 59091fed02..d6be2f0cc5 100644 --- a/tests/docker/dockerfiles/debian-ppc64el-cross.docker +++ b/tests/docker/dockerfiles/debian-ppc64el-cross.docker @@ -55,6 +55,7 @@ RUN export DEBIAN_FRONTEND=noninteractive && \ sed \ socat \ sparse \ + swtpm \ tar \ tesseract-ocr \ tesseract-ocr-eng \ diff --git a/tests/docker/dockerfiles/debian-s390x-cross.docker b/tests/docker/dockerfiles/debian-s390x-cross.docker index 48b2f28310..ec0041d6aa 100644 --- a/tests/docker/dockerfiles/debian-s390x-cross.docker +++ b/tests/docker/dockerfiles/debian-s390x-cross.docker @@ -55,6 +55,7 @@ RUN export DEBIAN_FRONTEND=noninteractive && \ sed \ socat \ sparse \ + swtpm \ tar \ tesseract-ocr \ tesseract-ocr-eng \ diff --git a/tests/docker/dockerfiles/fedora-win32-cross.docker b/tests/docker/dockerfiles/fedora-win32-cross.docker index afa988574f..08799219f9 100644 --- a/tests/docker/dockerfiles/fedora-win32-cross.docker +++ b/tests/docker/dockerfiles/fedora-win32-cross.docker @@ -55,6 +55,7 @@ exec "$@"\n' > /usr/bin/nosync && \ socat \ sparse \ spice-protocol \ + swtpm \ tar \ tesseract \ tesseract-langpack-eng \ diff --git a/tests/docker/dockerfiles/fedora-win64-cross.docker b/tests/docker/dockerfiles/fedora-win64-cross.docker index cf93a0ca60..f8e4cb70d3 100644 --- a/tests/docker/dockerfiles/fedora-win64-cross.docker +++ b/tests/docker/dockerfiles/fedora-win64-cross.docker @@ -55,6 +55,7 @@ exec "$@"\n' > /usr/bin/nosync && \ socat \ sparse \ spice-protocol \ + swtpm \ tar \ tesseract \ tesseract-langpack-eng \ diff --git a/tests/docker/dockerfiles/fedora.docker b/tests/docker/dockerfiles/fedora.docker index f00e9e267c..9e9c71fa94 100644 --- a/tests/docker/dockerfiles/fedora.docker +++ b/tests/docker/dockerfiles/fedora.docker @@ -118,6 +118,7 @@ exec "$@"\n' > /usr/bin/nosync && \ sparse \ spice-protocol \ spice-server-devel \ + swtpm \ systemd-devel \ systemtap-sdt-devel \ tar \ diff --git a/tests/docker/dockerfiles/opensuse-leap.docker b/tests/docker/dockerfiles/opensuse-leap.docker index ed04b4d6da..dc0e36ce48 100644 --- a/tests/docker/dockerfiles/opensuse-leap.docker +++ b/tests/docker/dockerfiles/opensuse-leap.docker @@ -100,6 +100,7 @@ RUN zypper update -y && \ socat \ sparse \ spice-protocol-devel \ + swtpm \ systemd-devel \ systemtap-sdt-devel \ tar \ diff --git a/tests/docker/dockerfiles/ubuntu2204.docker b/tests/docker/dockerfiles/ubuntu2204.docker index 94c2c16118..2ca9cff79c 100644 --- a/tests/docker/dockerfiles/ubuntu2204.docker +++ b/tests/docker/dockerfiles/ubuntu2204.docker @@ -124,6 +124,7 @@ RUN export DEBIAN_FRONTEND=noninteractive && \ sed \ socat \ sparse \ + swtpm \ systemtap-sdt-dev \ tar \ tesseract-ocr \ diff --git a/tests/lcitool/libvirt-ci b/tests/lcitool/libvirt-ci index e3ed1e5da1..36bc517161 160000 --- a/tests/lcitool/libvirt-ci +++ b/tests/lcitool/libvirt-ci @@ -1 +1 @@ -Subproject commit e3ed1e5da101943e53d8d89424e17b22120743f5 +Subproject commit 36bc517161c45ead20224d47f2dc4fa428af6724 diff --git a/tests/lcitool/projects/qemu.yml b/tests/lcitool/projects/qemu.yml index 6f0885170d..82092c9f17 100644 --- a/tests/lcitool/projects/qemu.yml +++ b/tests/lcitool/projects/qemu.yml @@ -110,6 +110,7 @@ packages: - spice-protocol - spice-server - ssh-client + - swtpm - systemd - tar - tesseract From 78ebc00b068131d2e3c0f8e66c0ded3fadb248d0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20Benn=C3=A9e?= Date: Mon, 9 Oct 2023 17:40:43 +0100 Subject: [PATCH 0423/1077] gitlab: shuffle some targets and reduce avocado noise MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We move a couple of targets out of the avocado runs because there are no tests to run. Tricore already has some coverage. The cris target only really has check-tcg tests but its getting harder to find anything that packages the compiler. To reduce the noise of CANCEL messages we also set AVOCADO_TAGS appropriately so we filter down the number of tests we attempt. Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Alex Bennée Message-Id: <20231009164104.369749-5-alex.bennee@linaro.org> --- .gitlab-ci.d/buildtest.yml | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/.gitlab-ci.d/buildtest.yml b/.gitlab-ci.d/buildtest.yml index aee9101507..25af1bc41e 100644 --- a/.gitlab-ci.d/buildtest.yml +++ b/.gitlab-ci.d/buildtest.yml @@ -30,6 +30,7 @@ avocado-system-alpine: variables: IMAGE: alpine MAKE_CHECK_ARGS: check-avocado + AVOCADO_TAGS: arch:avr arch:loongarch64 arch:mips64 arch:mipsel build-system-ubuntu: extends: @@ -40,8 +41,7 @@ build-system-ubuntu: variables: IMAGE: ubuntu2204 CONFIGURE_ARGS: --enable-docs - TARGETS: alpha-softmmu cris-softmmu hppa-softmmu - microblazeel-softmmu mips64el-softmmu + TARGETS: alpha-softmmu microblazeel-softmmu mips64el-softmmu MAKE_CHECK_ARGS: check-build check-system-ubuntu: @@ -61,6 +61,7 @@ avocado-system-ubuntu: variables: IMAGE: ubuntu2204 MAKE_CHECK_ARGS: check-avocado + AVOCADO_TAGS: arch:alpha arch:microblaze arch:mips64el build-system-debian: extends: @@ -72,7 +73,7 @@ build-system-debian: IMAGE: debian-amd64 CONFIGURE_ARGS: --with-coroutine=sigaltstack TARGETS: arm-softmmu i386-softmmu riscv64-softmmu sh4eb-softmmu - sparc-softmmu xtensaeb-softmmu + sparc-softmmu xtensa-softmmu MAKE_CHECK_ARGS: check-build check-system-debian: @@ -92,6 +93,7 @@ avocado-system-debian: variables: IMAGE: debian-amd64 MAKE_CHECK_ARGS: check-avocado + AVOCADO_TAGS: arch:arm arch:i386 arch:riscv64 arch:sh4 arch:sparc arch:xtensa crash-test-debian: extends: .native_test_job_template @@ -114,7 +116,7 @@ build-system-fedora: variables: IMAGE: fedora CONFIGURE_ARGS: --disable-gcrypt --enable-nettle --enable-docs - TARGETS: tricore-softmmu microblaze-softmmu mips-softmmu + TARGETS: microblaze-softmmu mips-softmmu xtensa-softmmu m68k-softmmu riscv32-softmmu ppc-softmmu sparc64-softmmu MAKE_CHECK_ARGS: check-build @@ -135,6 +137,8 @@ avocado-system-fedora: variables: IMAGE: fedora MAKE_CHECK_ARGS: check-avocado + AVOCADO_TAGS: arch:microblaze arch:mips arch:xtensa arch:m68k + arch:riscv32 arch:ppc arch:sparc64 crash-test-fedora: extends: .native_test_job_template @@ -180,6 +184,8 @@ avocado-system-centos: variables: IMAGE: centos8 MAKE_CHECK_ARGS: check-avocado + AVOCADO_TAGS: arch:ppc64 arch:or1k arch:390x arch:x86_64 arch:rx + arch:sh4 arch:nios2 build-system-opensuse: extends: @@ -209,6 +215,7 @@ avocado-system-opensuse: variables: IMAGE: opensuse-leap MAKE_CHECK_ARGS: check-avocado + AVOCADO_TAGS: arch:s390x arch:x86_64 arch:aarch64 # This jobs explicitly disable TCG (--disable-tcg), KVM is detected by From c6919250921c4794f4029bfe3f9f1c5263328899 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20Benn=C3=A9e?= Date: Mon, 9 Oct 2023 17:40:44 +0100 Subject: [PATCH 0424/1077] tests/docker: make docker engine choice entirely configure driven MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Since 0b1a649047 (tests/docker: use direct RUNC call to build containers) we ended up with the potential for the remaining docker.py script calls to deviate from the direct RUNC calls. Fix this by dropping the use of ENGINE in the makefile and rely entirely on what we detect at configure time. We also tweak the RUNC detection so podman users can still run things from the source tree. Signed-off-by: Alex Bennée Reviewed-by: Alistair Francis Message-Id: <20231009164104.369749-6-alex.bennee@linaro.org> --- configure | 1 - tests/docker/Makefile.include | 9 +++------ 2 files changed, 3 insertions(+), 7 deletions(-) diff --git a/configure b/configure index 97a5e8de49..1f26639e4f 100755 --- a/configure +++ b/configure @@ -1694,7 +1694,6 @@ if test -n "$gdb_bin"; then fi if test "$container" != no; then - echo "ENGINE=$container" >> $config_host_mak echo "RUNC=$runc" >> $config_host_mak fi echo "SUBDIRS=$subdirs" >> $config_host_mak diff --git a/tests/docker/Makefile.include b/tests/docker/Makefile.include index dfabafab92..ab68b2dbad 100644 --- a/tests/docker/Makefile.include +++ b/tests/docker/Makefile.include @@ -16,9 +16,8 @@ DOCKER_DEFAULT_REGISTRY := registry.gitlab.com/qemu-project/qemu endif DOCKER_REGISTRY := $(if $(REGISTRY),$(REGISTRY),$(DOCKER_DEFAULT_REGISTRY)) -RUNC ?= docker -ENGINE ?= auto -DOCKER_SCRIPT=$(SRC_PATH)/tests/docker/docker.py --engine $(ENGINE) +RUNC ?= $(if $(shell command -v docker), docker, podman) +DOCKER_SCRIPT=$(SRC_PATH)/tests/docker/docker.py --engine $(RUNC) CUR_TIME := $(shell date +%Y-%m-%d-%H.%M.%S.$$$$) DOCKER_SRC_COPY := $(BUILD_DIR)/docker-src.$(CUR_TIME) @@ -158,7 +157,7 @@ $(foreach i,$(filter-out $(DOCKER_PARTIAL_IMAGES),$(DOCKER_IMAGES)), \ ) docker: - @echo 'Build QEMU and run tests inside Docker or Podman containers' + @echo 'Build QEMU and run tests inside $(RUNC) containers' @echo @echo 'Available targets:' @echo @@ -198,8 +197,6 @@ docker: @echo ' EXECUTABLE= Include executable in image.' @echo ' EXTRA_FILES=" [... ]"' @echo ' Include extra files in image.' - @echo ' ENGINE=auto/docker/podman' - @echo ' Specify which container engine to run.' @echo ' REGISTRY=url Cache builds from registry (default:$(DOCKER_REGISTRY))' docker-help: docker From 42ede11aeeb1c87e8121bbaafa3aa7b242e99a25 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20Benn=C3=A9e?= Date: Mon, 9 Oct 2023 17:40:45 +0100 Subject: [PATCH 0425/1077] configure: allow user to override docker engine MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit If you have both engines installed but one is broken you are stuck with the automagic. Allow the user to override the engine for this case. Signed-off-by: Alex Bennée Reviewed-by: Alistair Francis Message-Id: <20231009164104.369749-7-alex.bennee@linaro.org> --- configure | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/configure b/configure index 1f26639e4f..5c04e63bab 100755 --- a/configure +++ b/configure @@ -180,6 +180,7 @@ fi # some defaults, based on the host environment # default parameters +container_engine="auto" cpu="" cross_compile="no" cross_prefix="" @@ -787,6 +788,8 @@ for opt do ;; --disable-containers) use_containers="no" ;; + --container-engine=*) container_engine="$optarg" + ;; --gdb=*) gdb_bin="$optarg" ;; # everything else has the same name in configure and meson @@ -921,6 +924,7 @@ Advanced options (experts only): --enable-plugins enable plugins via shared library loading --disable-containers don't use containers for cross-building + --container-engine=TYPE which container engine to use [$container_engine] --gdb=GDB-path gdb to use for gdbstub tests [$gdb_bin] EOF meson_options_help @@ -1195,14 +1199,14 @@ fi container="no" runc="" if test $use_containers = "yes" && (has "docker" || has "podman"); then - case $($python "$source_path"/tests/docker/docker.py probe) in + case $($python "$source_path"/tests/docker/docker.py --engine "$container_engine" probe) in *docker) container=docker ;; podman) container=podman ;; no) container=no ;; esac if test "$container" != "no"; then docker_py="$python $source_path/tests/docker/docker.py --engine $container" - runc=$($python "$source_path"/tests/docker/docker.py probe) + runc=$container fi fi From e0f8951235b991eaa7a0e617976848b88d84c360 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20Benn=C3=A9e?= Date: Mon, 9 Oct 2023 17:40:46 +0100 Subject: [PATCH 0426/1077] configure: remove gcc version suffixes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The modern packaging of cross GCC's doesn't need the explicit version number at the end. Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Alex Bennée Message-Id: <20231009164104.369749-8-alex.bennee@linaro.org> --- configure | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/configure b/configure index 5c04e63bab..8fada85a71 100755 --- a/configure +++ b/configure @@ -1334,7 +1334,7 @@ probe_target_compiler() { # We don't have any bigendian build tools so we only use this for AArch64 container_image=debian-arm64-cross container_cross_prefix=aarch64-linux-gnu- - container_cross_cc=${container_cross_prefix}gcc-10 + container_cross_cc=${container_cross_prefix}gcc ;; alpha) container_image=debian-alpha-cross @@ -1397,7 +1397,7 @@ probe_target_compiler() { ppc) container_image=debian-powerpc-test-cross container_cross_prefix=powerpc-linux-gnu- - container_cross_cc=${container_cross_prefix}gcc-10 + container_cross_cc=${container_cross_prefix}gcc ;; ppc64|ppc64le) container_image=debian-powerpc-test-cross From af2e06c9f122a3bb83d11df85d21257808c414cb Mon Sep 17 00:00:00 2001 From: Akihiko Odaki Date: Mon, 9 Oct 2023 17:40:47 +0100 Subject: [PATCH 0427/1077] gdbstub: Fix target_xml initialization MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit target_xml is no longer a fixed-length array but a pointer to a variable-length memory. Fixes: 56e534bd11 ("gdbstub: refactor get_feature_xml") Signed-off-by: Akihiko Odaki Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Alistair Francis Message-Id: <20230912224107.29669-2-akihiko.odaki@daynix.com> Signed-off-by: Alex Bennée Message-Id: <20231009164104.369749-9-alex.bennee@linaro.org> --- gdbstub/system.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gdbstub/system.c b/gdbstub/system.c index 189975b1d6..48976873d2 100644 --- a/gdbstub/system.c +++ b/gdbstub/system.c @@ -292,7 +292,7 @@ static int find_cpu_clusters(Object *child, void *opaque) assert(cluster->cluster_id != UINT32_MAX); process->pid = cluster->cluster_id + 1; process->attached = false; - process->target_xml[0] = '\0'; + process->target_xml = NULL; return 0; } From 5d1ab242067cdff30a8fc875933b14e21bb53308 Mon Sep 17 00:00:00 2001 From: Akihiko Odaki Date: Mon, 9 Oct 2023 17:40:48 +0100 Subject: [PATCH 0428/1077] gdbstub: Fix target.xml response MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit It was failing to return target.xml after the first request. Fixes: 56e534bd11 ("gdbstub: refactor get_feature_xml") Signed-off-by: Akihiko Odaki Message-Id: <20230912224107.29669-3-akihiko.odaki@daynix.com> Signed-off-by: Alex Bennée Message-Id: <20231009164104.369749-10-alex.bennee@linaro.org> --- gdbstub/gdbstub.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gdbstub/gdbstub.c b/gdbstub/gdbstub.c index 8eea21450c..4f3762fccf 100644 --- a/gdbstub/gdbstub.c +++ b/gdbstub/gdbstub.c @@ -396,8 +396,8 @@ static const char *get_feature_xml(const char *p, const char **newp, g_string_append(xml, ""); process->target_xml = g_string_free(xml, false); - return process->target_xml; } + return process->target_xml; } /* Is it dynamically generated by the target? */ if (cc->gdb_get_dynamic_xml) { From fb13735ab418ef8a5f86a5fd6b056bdbafed0daa Mon Sep 17 00:00:00 2001 From: Akihiko Odaki Date: Mon, 9 Oct 2023 17:40:49 +0100 Subject: [PATCH 0429/1077] plugins: Check if vCPU is realized MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The created member of CPUState tells if the vCPU thread is started, and will be always false for the user space emulation that manages threads independently. Use the realized member of DeviceState, which is valid for both of the system and user space emulation. Fixes: 54cb65d858 ("plugin: add core code") Signed-off-by: Akihiko Odaki Message-Id: <20230912224107.29669-4-akihiko.odaki@daynix.com> Signed-off-by: Alex Bennée Message-Id: <20231009164104.369749-11-alex.bennee@linaro.org> --- plugins/core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/core.c b/plugins/core.c index 3c4e26c7ed..fcd33a2bff 100644 --- a/plugins/core.c +++ b/plugins/core.c @@ -64,7 +64,7 @@ static void plugin_cpu_update__locked(gpointer k, gpointer v, gpointer udata) CPUState *cpu = container_of(k, CPUState, cpu_index); run_on_cpu_data mask = RUN_ON_CPU_HOST_ULONG(*plugin.mask); - if (cpu->created) { + if (DEVICE(cpu)->realized) { async_run_on_cpu(cpu, plugin_cpu_update__async, mask); } else { plugin_cpu_update__async(cpu, mask); From 1063693e1c503517a489e38fca489525eaea26c1 Mon Sep 17 00:00:00 2001 From: Akihiko Odaki Date: Mon, 9 Oct 2023 17:40:50 +0100 Subject: [PATCH 0430/1077] contrib/plugins: Use GRWLock in execlog MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit execlog had the following comment: > As we could have multiple threads trying to do this we need to > serialise the expansion under a lock. Threads accessing already > created entries can continue without issue even if the ptr array > gets reallocated during resize. However, when the ptr array gets reallocated, the other threads may have a stale reference to the old buffer. This results in use-after-free. Use GRWLock to properly fix this issue. Fixes: 3d7caf145e ("contrib/plugins: add execlog to log instruction execution and memory access") Signed-off-by: Akihiko Odaki Reviewed-by: Alex Bennée Message-Id: <20230912224107.29669-5-akihiko.odaki@daynix.com> Signed-off-by: Alex Bennée Message-Id: <20231009164104.369749-12-alex.bennee@linaro.org> --- contrib/plugins/execlog.c | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/contrib/plugins/execlog.c b/contrib/plugins/execlog.c index 7129d526f8..82dc2f584e 100644 --- a/contrib/plugins/execlog.c +++ b/contrib/plugins/execlog.c @@ -19,7 +19,7 @@ QEMU_PLUGIN_EXPORT int qemu_plugin_version = QEMU_PLUGIN_VERSION; /* Store last executed instruction on each vCPU as a GString */ static GPtrArray *last_exec; -static GMutex expand_array_lock; +static GRWLock expand_array_lock; static GPtrArray *imatches; static GArray *amatches; @@ -28,18 +28,16 @@ static GArray *amatches; * Expand last_exec array. * * As we could have multiple threads trying to do this we need to - * serialise the expansion under a lock. Threads accessing already - * created entries can continue without issue even if the ptr array - * gets reallocated during resize. + * serialise the expansion under a lock. */ static void expand_last_exec(int cpu_index) { - g_mutex_lock(&expand_array_lock); + g_rw_lock_writer_lock(&expand_array_lock); while (cpu_index >= last_exec->len) { GString *s = g_string_new(NULL); g_ptr_array_add(last_exec, s); } - g_mutex_unlock(&expand_array_lock); + g_rw_lock_writer_unlock(&expand_array_lock); } /** @@ -51,8 +49,10 @@ static void vcpu_mem(unsigned int cpu_index, qemu_plugin_meminfo_t info, GString *s; /* Find vCPU in array */ + g_rw_lock_reader_lock(&expand_array_lock); g_assert(cpu_index < last_exec->len); s = g_ptr_array_index(last_exec, cpu_index); + g_rw_lock_reader_unlock(&expand_array_lock); /* Indicate type of memory access */ if (qemu_plugin_mem_is_store(info)) { @@ -80,10 +80,14 @@ static void vcpu_insn_exec(unsigned int cpu_index, void *udata) GString *s; /* Find or create vCPU in array */ + g_rw_lock_reader_lock(&expand_array_lock); if (cpu_index >= last_exec->len) { + g_rw_lock_reader_unlock(&expand_array_lock); expand_last_exec(cpu_index); + g_rw_lock_reader_lock(&expand_array_lock); } s = g_ptr_array_index(last_exec, cpu_index); + g_rw_lock_reader_unlock(&expand_array_lock); /* Print previous instruction in cache */ if (s->len) { From 956af7daad5a97ca20f8e24d0f4d91a8fca650ad Mon Sep 17 00:00:00 2001 From: Akihiko Odaki Date: Mon, 9 Oct 2023 17:40:51 +0100 Subject: [PATCH 0431/1077] gdbstub: Introduce GDBFeature structure MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Before this change, the information from a XML file was stored in an array that is not descriptive. Introduce a dedicated structure type to make it easier to understand and to extend with more fields. Signed-off-by: Akihiko Odaki Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Alex Bennée Reviewed-by: Richard Henderson Message-Id: <20230912224107.29669-6-akihiko.odaki@daynix.com> Signed-off-by: Alex Bennée Message-Id: <20231009164104.369749-13-alex.bennee@linaro.org> --- MAINTAINERS | 2 +- gdbstub/gdbstub.c | 6 ++-- include/exec/gdbstub.h | 9 ++++-- meson.build | 2 +- scripts/feature_to_c.py | 48 ++++++++++++++++++++++++++++ scripts/feature_to_c.sh | 69 ----------------------------------------- stubs/gdbstub.c | 6 ++-- 7 files changed, 63 insertions(+), 79 deletions(-) create mode 100755 scripts/feature_to_c.py delete mode 100644 scripts/feature_to_c.sh diff --git a/MAINTAINERS b/MAINTAINERS index 9e7dec4a58..c3cc12dc29 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -2842,7 +2842,7 @@ F: include/exec/gdbstub.h F: include/gdbstub/* F: gdb-xml/ F: tests/tcg/multiarch/gdbstub/ -F: scripts/feature_to_c.sh +F: scripts/feature_to_c.py F: scripts/probe-gdb-support.py Memory API diff --git a/gdbstub/gdbstub.c b/gdbstub/gdbstub.c index 4f3762fccf..bba2640293 100644 --- a/gdbstub/gdbstub.c +++ b/gdbstub/gdbstub.c @@ -408,11 +408,11 @@ static const char *get_feature_xml(const char *p, const char **newp, } } /* Is it one of the encoded gdb-xml/ files? */ - for (int i = 0; xml_builtin[i][0]; i++) { - const char *name = xml_builtin[i][0]; + for (int i = 0; gdb_static_features[i].xmlname; i++) { + const char *name = gdb_static_features[i].xmlname; if ((strncmp(name, p, len) == 0) && strlen(name) == len) { - return xml_builtin[i][1]; + return gdb_static_features[i].xml; } } diff --git a/include/exec/gdbstub.h b/include/exec/gdbstub.h index 16a139043f..705be2c5d7 100644 --- a/include/exec/gdbstub.h +++ b/include/exec/gdbstub.h @@ -10,6 +10,11 @@ #define GDB_WATCHPOINT_READ 3 #define GDB_WATCHPOINT_ACCESS 4 +typedef struct GDBFeature { + const char *xmlname; + const char *xml; +} GDBFeature; + /* Get or set a register. Returns the size of the register. */ typedef int (*gdb_get_reg_cb)(CPUArchState *env, GByteArray *buf, int reg); @@ -48,7 +53,7 @@ void gdb_set_stop_cpu(CPUState *cpu); */ bool gdb_has_xml(void); -/* in gdbstub-xml.c, generated by scripts/feature_to_c.sh */ -extern const char *const xml_builtin[][2]; +/* in gdbstub-xml.c, generated by scripts/feature_to_c.py */ +extern const GDBFeature gdb_static_features[]; #endif diff --git a/meson.build b/meson.build index 79aef19bdc..bd65a111aa 100644 --- a/meson.build +++ b/meson.build @@ -3693,7 +3693,7 @@ common_all = static_library('common', dependencies: common_all.dependencies(), name_suffix: 'fa') -feature_to_c = find_program('scripts/feature_to_c.sh') +feature_to_c = find_program('scripts/feature_to_c.py') if targetos == 'darwin' entitlement = find_program('scripts/entitlement.sh') diff --git a/scripts/feature_to_c.py b/scripts/feature_to_c.py new file mode 100755 index 0000000000..bcbcb83beb --- /dev/null +++ b/scripts/feature_to_c.py @@ -0,0 +1,48 @@ +#!/usr/bin/env python3 +# SPDX-License-Identifier: GPL-2.0-or-later + +import os, sys + +def writeliteral(indent, bytes): + sys.stdout.write(' ' * indent) + sys.stdout.write('"') + quoted = True + + for c in bytes: + if not quoted: + sys.stdout.write('\n') + sys.stdout.write(' ' * indent) + sys.stdout.write('"') + quoted = True + + if c == b'"'[0]: + sys.stdout.write('\\"') + elif c == b'\\'[0]: + sys.stdout.write('\\\\') + elif c == b'\n'[0]: + sys.stdout.write('\\n"') + quoted = False + elif c >= 32 and c < 127: + sys.stdout.write(c.to_bytes(1, 'big').decode()) + else: + sys.stdout.write(f'\{c:03o}') + + if quoted: + sys.stdout.write('"') + +sys.stdout.write('#include "qemu/osdep.h"\n' \ + '#include "exec/gdbstub.h"\n' \ + '\n' + 'const GDBFeature gdb_static_features[] = {\n') + +for input in sys.argv[1:]: + with open(input, 'rb') as file: + read = file.read() + + sys.stdout.write(' {\n') + writeliteral(8, bytes(os.path.basename(input), 'utf-8')) + sys.stdout.write(',\n') + writeliteral(8, read) + sys.stdout.write('\n },\n') + +sys.stdout.write(' { NULL }\n};\n') diff --git a/scripts/feature_to_c.sh b/scripts/feature_to_c.sh deleted file mode 100644 index c1f67c8f6a..0000000000 --- a/scripts/feature_to_c.sh +++ /dev/null @@ -1,69 +0,0 @@ -#!/bin/sh - -# Convert text files to compilable C arrays. -# -# Copyright (C) 2007 Free Software Foundation, Inc. -# -# This file is part of GDB. -# -# This program is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 2 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, see . - -if test -z "$1"; then - echo "Usage: $0 INPUTFILE..." - exit 1 -fi - -for input; do - arrayname=xml_feature_$(echo $input | sed 's,.*/,,; s/[-.]/_/g') - - ${AWK:-awk} 'BEGIN { n = 0 - printf "#include \"qemu/osdep.h\"\n" - print "static const char '$arrayname'[] = {" - for (i = 0; i < 255; i++) - _ord_[sprintf("%c", i)] = i - } { - split($0, line, ""); - printf " " - for (i = 1; i <= length($0); i++) { - c = line[i] - if (c == "'\''") { - printf "'\''\\'\'''\'', " - } else if (c == "\\") { - printf "'\''\\\\'\'', " - } else if (_ord_[c] >= 32 && _ord_[c] < 127) { - printf "'\''%s'\'', ", c - } else { - printf "'\''\\%03o'\'', ", _ord_[c] - } - if (i % 10 == 0) - printf "\n " - } - printf "'\''\\n'\'', \n" - } END { - print " 0 };" - }' < $input -done - -echo -echo '#include "exec/gdbstub.h"' -echo "const char *const xml_builtin[][2] = {" - -for input; do - basename=$(echo $input | sed 's,.*/,,') - arrayname=xml_feature_$(echo $input | sed 's,.*/,,; s/[-.]/_/g') - echo " { \"$basename\", $arrayname }," -done - -echo " { (char *)0, (char *)0 }" -echo "};" diff --git a/stubs/gdbstub.c b/stubs/gdbstub.c index 2b7aee50d3..580e20702b 100644 --- a/stubs/gdbstub.c +++ b/stubs/gdbstub.c @@ -1,6 +1,6 @@ #include "qemu/osdep.h" -#include "exec/gdbstub.h" /* xml_builtin */ +#include "exec/gdbstub.h" /* gdb_static_features */ -const char *const xml_builtin[][2] = { - { NULL, NULL } +const GDBFeature gdb_static_features[] = { + { NULL } }; From 48de6462809587a2165260b4daa8e6477fbd7b75 Mon Sep 17 00:00:00 2001 From: Akihiko Odaki Date: Mon, 9 Oct 2023 17:40:52 +0100 Subject: [PATCH 0432/1077] target/arm: Move the reference to arm-core.xml MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Some subclasses overwrite gdb_core_xml_file member but others don't. Always initialize the member in the subclasses for consistency. This especially helps for AArch64; in a following change, the file specified by gdb_core_xml_file is always looked up even if it's going to be overwritten later. Looking up arm-core.xml results in an error as it will not be embedded in the AArch64 build. Signed-off-by: Akihiko Odaki Reviewed-by: Richard Henderson Message-Id: <20230912224107.29669-7-akihiko.odaki@daynix.com> Signed-off-by: Alex Bennée Message-Id: <20231009164104.369749-14-alex.bennee@linaro.org> --- target/arm/cpu.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/target/arm/cpu.c b/target/arm/cpu.c index 831295d7cd..b65e8cfea3 100644 --- a/target/arm/cpu.c +++ b/target/arm/cpu.c @@ -2392,7 +2392,6 @@ static void arm_cpu_class_init(ObjectClass *oc, void *data) cc->sysemu_ops = &arm_sysemu_ops; #endif cc->gdb_num_core_regs = 26; - cc->gdb_core_xml_file = "arm-core.xml"; cc->gdb_arch_name = arm_gdb_arch_name; cc->gdb_get_dynamic_xml = arm_gdb_get_dynamic_xml; cc->gdb_stop_before_watchpoint = true; @@ -2414,8 +2413,10 @@ static void arm_cpu_instance_init(Object *obj) static void cpu_register_class_init(ObjectClass *oc, void *data) { ARMCPUClass *acc = ARM_CPU_CLASS(oc); + CPUClass *cc = CPU_CLASS(acc); acc->info = data; + cc->gdb_core_xml_file = "arm-core.xml"; } void arm_cpu_register(const ARMCPUInfo *info) From a650683871ba728ebce3d320941f48bac91f0f6a Mon Sep 17 00:00:00 2001 From: Akihiko Odaki Date: Mon, 9 Oct 2023 17:40:53 +0100 Subject: [PATCH 0433/1077] hw/core/cpu: Return static value with gdb_arch_name() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit All implementations of gdb_arch_name() returns dynamic duplicates of static strings. It's also unlikely that there will be an implementation of gdb_arch_name() that returns a truly dynamic value due to the nature of the function returning a well-known identifiers. Qualify the value gdb_arch_name() with const and make all of its implementations return static strings. Signed-off-by: Akihiko Odaki Reviewed-by: Alex Bennée Reviewed-by: Alistair Francis Message-Id: <20230912224107.29669-8-akihiko.odaki@daynix.com> Signed-off-by: Alex Bennée Message-Id: <20231009164104.369749-15-alex.bennee@linaro.org> --- gdbstub/gdbstub.c | 3 +-- include/hw/core/cpu.h | 2 +- target/arm/cpu.c | 6 +++--- target/arm/cpu64.c | 4 ++-- target/i386/cpu.c | 6 +++--- target/loongarch/cpu.c | 8 ++++---- target/ppc/gdbstub.c | 6 +++--- target/ppc/internal.h | 2 +- target/riscv/cpu.c | 6 +++--- target/s390x/cpu.c | 4 ++-- target/tricore/cpu.c | 4 ++-- 11 files changed, 25 insertions(+), 26 deletions(-) diff --git a/gdbstub/gdbstub.c b/gdbstub/gdbstub.c index bba2640293..a20169c27b 100644 --- a/gdbstub/gdbstub.c +++ b/gdbstub/gdbstub.c @@ -380,10 +380,9 @@ static const char *get_feature_xml(const char *p, const char **newp, ""); if (cc->gdb_arch_name) { - g_autofree gchar *arch = cc->gdb_arch_name(cpu); g_string_append_printf(xml, "%s", - arch); + cc->gdb_arch_name(cpu)); } g_string_append(xml, "gdb_core_xml_file); diff --git a/include/hw/core/cpu.h b/include/hw/core/cpu.h index e02bc5980f..7b8347ed5a 100644 --- a/include/hw/core/cpu.h +++ b/include/hw/core/cpu.h @@ -165,7 +165,7 @@ struct CPUClass { vaddr (*gdb_adjust_breakpoint)(CPUState *cpu, vaddr addr); const char *gdb_core_xml_file; - gchar * (*gdb_arch_name)(CPUState *cpu); + const gchar * (*gdb_arch_name)(CPUState *cpu); const char * (*gdb_get_dynamic_xml)(CPUState *cpu, const char *xmlname); void (*disas_set_info)(CPUState *cpu, disassemble_info *info); diff --git a/target/arm/cpu.c b/target/arm/cpu.c index b65e8cfea3..6c6c551573 100644 --- a/target/arm/cpu.c +++ b/target/arm/cpu.c @@ -2319,15 +2319,15 @@ static Property arm_cpu_properties[] = { DEFINE_PROP_END_OF_LIST() }; -static gchar *arm_gdb_arch_name(CPUState *cs) +static const gchar *arm_gdb_arch_name(CPUState *cs) { ARMCPU *cpu = ARM_CPU(cs); CPUARMState *env = &cpu->env; if (arm_feature(env, ARM_FEATURE_IWMMXT)) { - return g_strdup("iwmmxt"); + return "iwmmxt"; } - return g_strdup("arm"); + return "arm"; } #ifndef CONFIG_USER_ONLY diff --git a/target/arm/cpu64.c b/target/arm/cpu64.c index 811f3b38c2..1cb9d5b81a 100644 --- a/target/arm/cpu64.c +++ b/target/arm/cpu64.c @@ -781,9 +781,9 @@ static void aarch64_cpu_finalizefn(Object *obj) { } -static gchar *aarch64_gdb_arch_name(CPUState *cs) +static const gchar *aarch64_gdb_arch_name(CPUState *cs) { - return g_strdup("aarch64"); + return "aarch64"; } static void aarch64_cpu_class_init(ObjectClass *oc, void *data) diff --git a/target/i386/cpu.c b/target/i386/cpu.c index cec5d2b7b6..3aab05ddad 100644 --- a/target/i386/cpu.c +++ b/target/i386/cpu.c @@ -5916,12 +5916,12 @@ static void x86_cpu_load_model(X86CPU *cpu, X86CPUModel *model) memset(&env->user_features, 0, sizeof(env->user_features)); } -static gchar *x86_gdb_arch_name(CPUState *cs) +static const gchar *x86_gdb_arch_name(CPUState *cs) { #ifdef TARGET_X86_64 - return g_strdup("i386:x86-64"); + return "i386:x86-64"; #else - return g_strdup("i386"); + return "i386"; #endif } diff --git a/target/loongarch/cpu.c b/target/loongarch/cpu.c index 2bea7ca5d5..ef1bf89dac 100644 --- a/target/loongarch/cpu.c +++ b/target/loongarch/cpu.c @@ -766,9 +766,9 @@ static void loongarch_cpu_class_init(ObjectClass *c, void *data) #endif } -static gchar *loongarch32_gdb_arch_name(CPUState *cs) +static const gchar *loongarch32_gdb_arch_name(CPUState *cs) { - return g_strdup("loongarch32"); + return "loongarch32"; } static void loongarch32_cpu_class_init(ObjectClass *c, void *data) @@ -780,9 +780,9 @@ static void loongarch32_cpu_class_init(ObjectClass *c, void *data) cc->gdb_arch_name = loongarch32_gdb_arch_name; } -static gchar *loongarch64_gdb_arch_name(CPUState *cs) +static const gchar *loongarch64_gdb_arch_name(CPUState *cs) { - return g_strdup("loongarch64"); + return "loongarch64"; } static void loongarch64_cpu_class_init(ObjectClass *c, void *data) diff --git a/target/ppc/gdbstub.c b/target/ppc/gdbstub.c index 2ad11510bf..778ef73bd7 100644 --- a/target/ppc/gdbstub.c +++ b/target/ppc/gdbstub.c @@ -589,12 +589,12 @@ static int gdb_set_vsx_reg(CPUPPCState *env, uint8_t *mem_buf, int n) return 0; } -gchar *ppc_gdb_arch_name(CPUState *cs) +const gchar *ppc_gdb_arch_name(CPUState *cs) { #if defined(TARGET_PPC64) - return g_strdup("powerpc:common64"); + return "powerpc:common64"; #else - return g_strdup("powerpc:common"); + return "powerpc:common"; #endif } diff --git a/target/ppc/internal.h b/target/ppc/internal.h index 15803bc313..c881c67a8b 100644 --- a/target/ppc/internal.h +++ b/target/ppc/internal.h @@ -221,7 +221,7 @@ void destroy_ppc_opcodes(PowerPCCPU *cpu); /* gdbstub.c */ void ppc_gdb_init(CPUState *cs, PowerPCCPUClass *ppc); -gchar *ppc_gdb_arch_name(CPUState *cs); +const gchar *ppc_gdb_arch_name(CPUState *cs); /** * prot_for_access_type: diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c index ac2b94b6a6..f5572704de 100644 --- a/target/riscv/cpu.c +++ b/target/riscv/cpu.c @@ -2004,17 +2004,17 @@ static Property riscv_cpu_properties[] = { DEFINE_PROP_END_OF_LIST(), }; -static gchar *riscv_gdb_arch_name(CPUState *cs) +static const gchar *riscv_gdb_arch_name(CPUState *cs) { RISCVCPU *cpu = RISCV_CPU(cs); CPURISCVState *env = &cpu->env; switch (riscv_cpu_mxl(env)) { case MXL_RV32: - return g_strdup("riscv:rv32"); + return "riscv:rv32"; case MXL_RV64: case MXL_RV128: - return g_strdup("riscv:rv64"); + return "riscv:rv64"; default: g_assert_not_reached(); } diff --git a/target/s390x/cpu.c b/target/s390x/cpu.c index 4f7599d72c..6093ab0a12 100644 --- a/target/s390x/cpu.c +++ b/target/s390x/cpu.c @@ -282,9 +282,9 @@ static void s390_cpu_initfn(Object *obj) #endif } -static gchar *s390_gdb_arch_name(CPUState *cs) +static const gchar *s390_gdb_arch_name(CPUState *cs) { - return g_strdup("s390:64-bit"); + return "s390:64-bit"; } static Property s390x_cpu_properties[] = { diff --git a/target/tricore/cpu.c b/target/tricore/cpu.c index d1477622e6..5ca666ee12 100644 --- a/target/tricore/cpu.c +++ b/target/tricore/cpu.c @@ -29,9 +29,9 @@ static inline void set_feature(CPUTriCoreState *env, int feature) env->features |= 1ULL << feature; } -static gchar *tricore_gdb_arch_name(CPUState *cs) +static const gchar *tricore_gdb_arch_name(CPUState *cs) { - return g_strdup("tricore"); + return "tricore"; } static void tricore_cpu_set_pc(CPUState *cs, vaddr value) From 6d8f77a6a152c1c64c5ee79e31fe3510b020cd0e Mon Sep 17 00:00:00 2001 From: Akihiko Odaki Date: Mon, 9 Oct 2023 17:40:54 +0100 Subject: [PATCH 0434/1077] gdbstub: Use g_markup_printf_escaped() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit g_markup_printf_escaped() is a safer alternative to simple printf() as it automatically escapes values. Signed-off-by: Akihiko Odaki Message-Id: <20230912224107.29669-9-akihiko.odaki@daynix.com> Signed-off-by: Alex Bennée Message-Id: <20231009164104.369749-16-alex.bennee@linaro.org> --- gdbstub/gdbstub.c | 36 +++++++++++++++++++++--------------- 1 file changed, 21 insertions(+), 15 deletions(-) diff --git a/gdbstub/gdbstub.c b/gdbstub/gdbstub.c index a20169c27b..3dc847f835 100644 --- a/gdbstub/gdbstub.c +++ b/gdbstub/gdbstub.c @@ -373,28 +373,34 @@ static const char *get_feature_xml(const char *p, const char **newp, if (strncmp(p, "target.xml", len) == 0) { if (!process->target_xml) { GDBRegisterState *r; - GString *xml = g_string_new(""); + g_autoptr(GPtrArray) xml = g_ptr_array_new_with_free_func(g_free); - g_string_append(xml, - "" - ""); + g_ptr_array_add( + xml, + g_strdup("" + "" + "")); if (cc->gdb_arch_name) { - g_string_append_printf(xml, - "%s", - cc->gdb_arch_name(cpu)); + g_ptr_array_add( + xml, + g_markup_printf_escaped("%s", + cc->gdb_arch_name(cpu))); } - g_string_append(xml, "gdb_core_xml_file); - g_string_append(xml, "\"/>"); + g_ptr_array_add( + xml, + g_markup_printf_escaped("", + cc->gdb_core_xml_file)); for (r = cpu->gdb_regs; r; r = r->next) { - g_string_append(xml, "xml); - g_string_append(xml, "\"/>"); + g_ptr_array_add( + xml, + g_markup_printf_escaped("", + r->xml)); } - g_string_append(xml, ""); + g_ptr_array_add(xml, g_strdup("")); + g_ptr_array_add(xml, NULL); - process->target_xml = g_string_free(xml, false); + process->target_xml = g_strjoinv(NULL, (void *)xml->pdata); } return process->target_xml; } From dd2f7e2974b1cefe00cb5077ae58134ef973070d Mon Sep 17 00:00:00 2001 From: Akihiko Odaki Date: Mon, 9 Oct 2023 17:40:55 +0100 Subject: [PATCH 0435/1077] target/arm: Remove references to gdb_has_xml MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit GDB has XML support since 6.7 which was released in 2007. It's time to remove support for old GDB versions without XML support. Signed-off-by: Akihiko Odaki Acked-by: Alex Bennée Reviewed-by: Alistair Francis Message-Id: <20230912224107.29669-10-akihiko.odaki@daynix.com> Signed-off-by: Alex Bennée Message-Id: <20231009164104.369749-17-alex.bennee@linaro.org> --- target/arm/gdbstub.c | 32 ++------------------------------ 1 file changed, 2 insertions(+), 30 deletions(-) diff --git a/target/arm/gdbstub.c b/target/arm/gdbstub.c index 8fc8351df7..b7ace24bfc 100644 --- a/target/arm/gdbstub.c +++ b/target/arm/gdbstub.c @@ -46,21 +46,7 @@ int arm_cpu_gdb_read_register(CPUState *cs, GByteArray *mem_buf, int n) /* Core integer register. */ return gdb_get_reg32(mem_buf, env->regs[n]); } - if (n < 24) { - /* FPA registers. */ - if (gdb_has_xml()) { - return 0; - } - return gdb_get_zeroes(mem_buf, 12); - } - switch (n) { - case 24: - /* FPA status register. */ - if (gdb_has_xml()) { - return 0; - } - return gdb_get_reg32(mem_buf, 0); - case 25: + if (n == 25) { /* CPSR, or XPSR for M-profile */ if (arm_feature(env, ARM_FEATURE_M)) { return gdb_get_reg32(mem_buf, xpsr_read(env)); @@ -100,21 +86,7 @@ int arm_cpu_gdb_write_register(CPUState *cs, uint8_t *mem_buf, int n) env->regs[n] = tmp; return 4; } - if (n < 24) { /* 16-23 */ - /* FPA registers (ignored). */ - if (gdb_has_xml()) { - return 0; - } - return 12; - } - switch (n) { - case 24: - /* FPA status register (ignored). */ - if (gdb_has_xml()) { - return 0; - } - return 4; - case 25: + if (n == 25) { /* CPSR, or XPSR for M-profile */ if (arm_feature(env, ARM_FEATURE_M)) { /* From 8e6d3ea2f5163e12baf86692b1fb1de2fea66625 Mon Sep 17 00:00:00 2001 From: Akihiko Odaki Date: Mon, 9 Oct 2023 17:40:56 +0100 Subject: [PATCH 0436/1077] target/ppc: Remove references to gdb_has_xml MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit GDB has XML support since 6.7 which was released in 2007. It's time to remove support for old GDB versions without XML support. Signed-off-by: Akihiko Odaki Message-Id: <20230912224107.29669-11-akihiko.odaki@daynix.com> Signed-off-by: Alex Bennée Message-Id: <20231009164104.369749-18-alex.bennee@linaro.org> --- target/ppc/gdbstub.c | 18 ------------------ 1 file changed, 18 deletions(-) diff --git a/target/ppc/gdbstub.c b/target/ppc/gdbstub.c index 778ef73bd7..ec5731e5d6 100644 --- a/target/ppc/gdbstub.c +++ b/target/ppc/gdbstub.c @@ -54,12 +54,6 @@ static int ppc_gdb_register_len(int n) case 0 ... 31: /* gprs */ return sizeof(target_ulong); - case 32 ... 63: - /* fprs */ - if (gdb_has_xml()) { - return 0; - } - return 8; case 66: /* cr */ case 69: @@ -74,12 +68,6 @@ static int ppc_gdb_register_len(int n) case 68: /* ctr */ return sizeof(target_ulong); - case 70: - /* fpscr */ - if (gdb_has_xml()) { - return 0; - } - return sizeof(target_ulong); default: return 0; } @@ -132,9 +120,6 @@ int ppc_cpu_gdb_read_register(CPUState *cs, GByteArray *buf, int n) if (n < 32) { /* gprs */ gdb_get_regl(buf, env->gpr[n]); - } else if (n < 64) { - /* fprs */ - gdb_get_reg64(buf, *cpu_fpr_ptr(env, n - 32)); } else { switch (n) { case 64: @@ -158,9 +143,6 @@ int ppc_cpu_gdb_read_register(CPUState *cs, GByteArray *buf, int n) case 69: gdb_get_reg32(buf, cpu_read_xer(env)); break; - case 70: - gdb_get_reg32(buf, env->fpscr); - break; } } mem_buf = buf->data + buf->len - r; From 213316d401e72b218d8edd9b88d72df6ecf0cc49 Mon Sep 17 00:00:00 2001 From: Akihiko Odaki Date: Mon, 9 Oct 2023 17:40:57 +0100 Subject: [PATCH 0437/1077] gdbstub: Remove gdb_has_xml variable MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit GDB has XML support since 6.7 which was released in 2007. It's time to remove support for old GDB versions without XML support. Signed-off-by: Akihiko Odaki Reviewed-by: Alistair Francis Message-Id: <20230912224107.29669-12-akihiko.odaki@daynix.com> Signed-off-by: Alex Bennée Message-Id: <20231009164104.369749-19-alex.bennee@linaro.org> --- gdbstub/gdbstub.c | 15 --------------- gdbstub/internals.h | 2 -- include/exec/gdbstub.h | 8 -------- 3 files changed, 25 deletions(-) diff --git a/gdbstub/gdbstub.c b/gdbstub/gdbstub.c index 3dc847f835..62608a5389 100644 --- a/gdbstub/gdbstub.c +++ b/gdbstub/gdbstub.c @@ -349,11 +349,6 @@ static CPUState *gdb_get_cpu(uint32_t pid, uint32_t tid) } } -bool gdb_has_xml(void) -{ - return !!gdb_get_cpu_process(gdbserver_state.g_cpu)->target_xml; -} - static const char *get_feature_xml(const char *p, const char **newp, GDBProcess *process) { @@ -1086,11 +1081,6 @@ static void handle_set_reg(GArray *params, void *user_ctx) { int reg_size; - if (!gdb_get_cpu_process(gdbserver_state.g_cpu)->target_xml) { - gdb_put_packet(""); - return; - } - if (params->len != 2) { gdb_put_packet("E22"); return; @@ -1107,11 +1097,6 @@ static void handle_get_reg(GArray *params, void *user_ctx) { int reg_size; - if (!gdb_get_cpu_process(gdbserver_state.g_cpu)->target_xml) { - gdb_put_packet(""); - return; - } - if (!params->len) { gdb_put_packet("E14"); return; diff --git a/gdbstub/internals.h b/gdbstub/internals.h index f7fd1bede5..465c24b36e 100644 --- a/gdbstub/internals.h +++ b/gdbstub/internals.h @@ -32,8 +32,6 @@ enum { typedef struct GDBProcess { uint32_t pid; bool attached; - - /* If gdb sends qXfer:features:read:target.xml this will be populated */ char *target_xml; } GDBProcess; diff --git a/include/exec/gdbstub.h b/include/exec/gdbstub.h index 705be2c5d7..1a01c35f8e 100644 --- a/include/exec/gdbstub.h +++ b/include/exec/gdbstub.h @@ -45,14 +45,6 @@ int gdbserver_start(const char *port_or_device); void gdb_set_stop_cpu(CPUState *cpu); -/** - * gdb_has_xml() - report of gdb supports modern target descriptions - * - * This will report true if the gdb negotiated qXfer:features:read - * target descriptions. - */ -bool gdb_has_xml(void); - /* in gdbstub-xml.c, generated by scripts/feature_to_c.py */ extern const GDBFeature gdb_static_features[]; From 73c392c26b0c96eb07272ea21cc0062ce534b6a3 Mon Sep 17 00:00:00 2001 From: Akihiko Odaki Date: Mon, 9 Oct 2023 17:40:58 +0100 Subject: [PATCH 0438/1077] gdbstub: Replace gdb_regs with an array MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit An array is a more appropriate data structure than a list for gdb_regs since it is initialized only with append operation and read-only after initialization. Signed-off-by: Akihiko Odaki Reviewed-by: Alistair Francis Message-Id: <20230912224107.29669-13-akihiko.odaki@daynix.com> [AJB: fixed a checkpatch violation] Signed-off-by: Alex Bennée Message-Id: <20231009164104.369749-20-alex.bennee@linaro.org> --- gdbstub/gdbstub.c | 33 ++++++++++++++++++++------------- include/hw/core/cpu.h | 2 +- 2 files changed, 21 insertions(+), 14 deletions(-) diff --git a/gdbstub/gdbstub.c b/gdbstub/gdbstub.c index 62608a5389..b1532118d1 100644 --- a/gdbstub/gdbstub.c +++ b/gdbstub/gdbstub.c @@ -51,7 +51,6 @@ typedef struct GDBRegisterState { gdb_get_reg_cb get_reg; gdb_set_reg_cb set_reg; const char *xml; - struct GDBRegisterState *next; } GDBRegisterState; GDBState gdbserver_state; @@ -386,7 +385,8 @@ static const char *get_feature_xml(const char *p, const char **newp, xml, g_markup_printf_escaped("", cc->gdb_core_xml_file)); - for (r = cpu->gdb_regs; r; r = r->next) { + for (guint i = 0; i < cpu->gdb_regs->len; i++) { + r = &g_array_index(cpu->gdb_regs, GDBRegisterState, i); g_ptr_array_add( xml, g_markup_printf_escaped("", @@ -430,7 +430,8 @@ static int gdb_read_register(CPUState *cpu, GByteArray *buf, int reg) return cc->gdb_read_register(cpu, buf, reg); } - for (r = cpu->gdb_regs; r; r = r->next) { + for (guint i = 0; i < cpu->gdb_regs->len; i++) { + r = &g_array_index(cpu->gdb_regs, GDBRegisterState, i); if (r->base_reg <= reg && reg < r->base_reg + r->num_regs) { return r->get_reg(env, buf, reg - r->base_reg); } @@ -448,7 +449,8 @@ static int gdb_write_register(CPUState *cpu, uint8_t *mem_buf, int reg) return cc->gdb_write_register(cpu, mem_buf, reg); } - for (r = cpu->gdb_regs; r; r = r->next) { + for (guint i = 0; i < cpu->gdb_regs->len; i++) { + r = &g_array_index(cpu->gdb_regs, GDBRegisterState, i); if (r->base_reg <= reg && reg < r->base_reg + r->num_regs) { return r->set_reg(env, mem_buf, reg - r->base_reg); } @@ -461,17 +463,23 @@ void gdb_register_coprocessor(CPUState *cpu, int num_regs, const char *xml, int g_pos) { GDBRegisterState *s; - GDBRegisterState **p; + guint i; - p = &cpu->gdb_regs; - while (*p) { - /* Check for duplicates. */ - if (strcmp((*p)->xml, xml) == 0) - return; - p = &(*p)->next; + if (cpu->gdb_regs) { + for (i = 0; i < cpu->gdb_regs->len; i++) { + /* Check for duplicates. */ + s = &g_array_index(cpu->gdb_regs, GDBRegisterState, i); + if (strcmp(s->xml, xml) == 0) { + return; + } + } + } else { + cpu->gdb_regs = g_array_new(false, false, sizeof(GDBRegisterState)); + i = 0; } - s = g_new0(GDBRegisterState, 1); + g_array_set_size(cpu->gdb_regs, i + 1); + s = &g_array_index(cpu->gdb_regs, GDBRegisterState, i); s->base_reg = cpu->gdb_num_regs; s->num_regs = num_regs; s->get_reg = get_reg; @@ -480,7 +488,6 @@ void gdb_register_coprocessor(CPUState *cpu, /* Add to end of list. */ cpu->gdb_num_regs += num_regs; - *p = s; if (g_pos) { if (g_pos != s->base_reg) { error_report("Error: Bad gdb register numbering for '%s', " diff --git a/include/hw/core/cpu.h b/include/hw/core/cpu.h index 7b8347ed5a..3968369554 100644 --- a/include/hw/core/cpu.h +++ b/include/hw/core/cpu.h @@ -502,7 +502,7 @@ struct CPUState { CPUJumpCache *tb_jmp_cache; - struct GDBRegisterState *gdb_regs; + GArray *gdb_regs; int gdb_num_regs; int gdb_num_g_regs; QTAILQ_ENTRY(CPUState) node; From 28a4f0bacf62f10c6f258c753df1f5d04cd17bd8 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Mon, 9 Oct 2023 17:40:59 +0100 Subject: [PATCH 0439/1077] accel/tcg: Add plugin_enabled to DisasContextBase MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Richard Henderson Message-Id: <20230824181233.1568795-2-richard.henderson@linaro.org> Signed-off-by: Alex Bennée Message-Id: <20231009164104.369749-21-alex.bennee@linaro.org> --- accel/tcg/translator.c | 1 + include/exec/translator.h | 2 ++ 2 files changed, 3 insertions(+) diff --git a/accel/tcg/translator.c b/accel/tcg/translator.c index e7abcd86c1..c5da7b32a5 100644 --- a/accel/tcg/translator.c +++ b/accel/tcg/translator.c @@ -158,6 +158,7 @@ void translator_loop(CPUState *cpu, TranslationBlock *tb, int *max_insns, } else { plugin_enabled = plugin_gen_tb_start(cpu, db, false); } + db->plugin_enabled = plugin_enabled; while (true) { *max_insns = ++db->num_insns; diff --git a/include/exec/translator.h b/include/exec/translator.h index 9d9e980819..6d3f59d095 100644 --- a/include/exec/translator.h +++ b/include/exec/translator.h @@ -73,6 +73,7 @@ typedef enum DisasJumpType { * @max_insns: Maximum number of instructions to be translated in this TB. * @singlestep_enabled: "Hardware" single stepping enabled. * @saved_can_do_io: Known value of cpu->neg.can_do_io, or -1 for unknown. + * @plugin_enabled: TCG plugin enabled in this TB. * * Architecture-agnostic disassembly context. */ @@ -85,6 +86,7 @@ typedef struct DisasContextBase { int max_insns; bool singlestep_enabled; int8_t saved_can_do_io; + bool plugin_enabled; void *host_addr[2]; } DisasContextBase; From 4f9ef4eebcc366fee20cce55aac659c6913bbf49 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Mon, 9 Oct 2023 17:41:00 +0100 Subject: [PATCH 0440/1077] target/sh4: Disable decode_gusa when plugins enabled MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Richard Henderson Message-Id: <20230824181233.1568795-3-richard.henderson@linaro.org> [AJB: fixed s/cpu_env/tcg_env/ during re-base] Signed-off-by: Alex Bennée Message-Id: <20231009164104.369749-22-alex.bennee@linaro.org> --- target/sh4/translate.c | 41 +++++++++++++++++++++++++++++------------ 1 file changed, 29 insertions(+), 12 deletions(-) diff --git a/target/sh4/translate.c b/target/sh4/translate.c index cbd8dfc02f..220a06bdce 100644 --- a/target/sh4/translate.c +++ b/target/sh4/translate.c @@ -1816,6 +1816,18 @@ static void decode_opc(DisasContext * ctx) } #ifdef CONFIG_USER_ONLY +/* + * Restart with the EXCLUSIVE bit set, within a TB run via + * cpu_exec_step_atomic holding the exclusive lock. + */ +static void gen_restart_exclusive(DisasContext *ctx) +{ + ctx->envflags |= TB_FLAG_GUSA_EXCLUSIVE; + gen_save_cpu_state(ctx, false); + gen_helper_exclusive(tcg_env); + ctx->base.is_jmp = DISAS_NORETURN; +} + /* For uniprocessors, SH4 uses optimistic restartable atomic sequences. Upon an interrupt, a real kernel would simply notice magic values in the registers and reset the PC to the start of the sequence. @@ -2149,12 +2161,7 @@ static void decode_gusa(DisasContext *ctx, CPUSH4State *env) qemu_log_mask(LOG_UNIMP, "Unrecognized gUSA sequence %08x-%08x\n", pc, pc_end); - /* Restart with the EXCLUSIVE bit set, within a TB run via - cpu_exec_step_atomic holding the exclusive lock. */ - ctx->envflags |= TB_FLAG_GUSA_EXCLUSIVE; - gen_save_cpu_state(ctx, false); - gen_helper_exclusive(tcg_env); - ctx->base.is_jmp = DISAS_NORETURN; + gen_restart_exclusive(ctx); /* We're not executing an instruction, but we must report one for the purposes of accounting within the TB. We might as well report the @@ -2242,12 +2249,22 @@ static void sh4_tr_translate_insn(DisasContextBase *dcbase, CPUState *cs) #ifdef CONFIG_USER_ONLY if (unlikely(ctx->envflags & TB_FLAG_GUSA_MASK) && !(ctx->envflags & TB_FLAG_GUSA_EXCLUSIVE)) { - /* We're in an gUSA region, and we have not already fallen - back on using an exclusive region. Attempt to parse the - region into a single supported atomic operation. Failure - is handled within the parser by raising an exception to - retry using an exclusive region. */ - decode_gusa(ctx, env); + /* + * We're in an gUSA region, and we have not already fallen + * back on using an exclusive region. Attempt to parse the + * region into a single supported atomic operation. Failure + * is handled within the parser by raising an exception to + * retry using an exclusive region. + * + * Parsing the region in one block conflicts with plugins, + * so always use exclusive mode if plugins enabled. + */ + if (ctx->base.plugin_enabled) { + gen_restart_exclusive(ctx); + ctx->base.pc_next += 2; + } else { + decode_gusa(ctx, env); + } return; } #endif From a392277dcf00e7bf6f7a0ecc9075ea154532c436 Mon Sep 17 00:00:00 2001 From: Matt Borgerson Date: Mon, 9 Oct 2023 17:41:01 +0100 Subject: [PATCH 0441/1077] plugins: Set final instruction count in plugin_gen_tb_end MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Translation logic may partially decode an instruction, then abort and remove the instruction from the TB. This can happen for example when an instruction spans two pages. In this case, plugins may get an incorrect result when calling qemu_plugin_tb_n_insns to query for the number of instructions in the TB. This patch updates plugin_gen_tb_end to set the final instruction count. Signed-off-by: Matt Borgerson [AJB: added g_assert to defed API] Message-Id: Signed-off-by: Alex Bennée Message-Id: <20231009164104.369749-23-alex.bennee@linaro.org> --- accel/tcg/plugin-gen.c | 6 +++++- accel/tcg/translator.c | 2 +- include/exec/plugin-gen.h | 4 ++-- 3 files changed, 8 insertions(+), 4 deletions(-) diff --git a/accel/tcg/plugin-gen.c b/accel/tcg/plugin-gen.c index d31c9993ea..39b3c9351f 100644 --- a/accel/tcg/plugin-gen.c +++ b/accel/tcg/plugin-gen.c @@ -866,10 +866,14 @@ void plugin_gen_insn_end(void) * do any clean-up here and make sure things are reset in * plugin_gen_tb_start. */ -void plugin_gen_tb_end(CPUState *cpu) +void plugin_gen_tb_end(CPUState *cpu, size_t num_insns) { struct qemu_plugin_tb *ptb = tcg_ctx->plugin_tb; + /* translator may have removed instructions, update final count */ + g_assert(num_insns <= ptb->n); + ptb->n = num_insns; + /* collect instrumentation requests */ qemu_plugin_tb_trans_cb(cpu, ptb); diff --git a/accel/tcg/translator.c b/accel/tcg/translator.c index c5da7b32a5..575b9812ad 100644 --- a/accel/tcg/translator.c +++ b/accel/tcg/translator.c @@ -210,7 +210,7 @@ void translator_loop(CPUState *cpu, TranslationBlock *tb, int *max_insns, gen_tb_end(tb, cflags, icount_start_insn, db->num_insns); if (plugin_enabled) { - plugin_gen_tb_end(cpu); + plugin_gen_tb_end(cpu, db->num_insns); } /* The disas_log hook may use these values rather than recompute. */ diff --git a/include/exec/plugin-gen.h b/include/exec/plugin-gen.h index 52828781bc..c4552b5061 100644 --- a/include/exec/plugin-gen.h +++ b/include/exec/plugin-gen.h @@ -20,7 +20,7 @@ struct DisasContextBase; bool plugin_gen_tb_start(CPUState *cpu, const struct DisasContextBase *db, bool supress); -void plugin_gen_tb_end(CPUState *cpu); +void plugin_gen_tb_end(CPUState *cpu, size_t num_insns); void plugin_gen_insn_start(CPUState *cpu, const struct DisasContextBase *db); void plugin_gen_insn_end(void); @@ -42,7 +42,7 @@ void plugin_gen_insn_start(CPUState *cpu, const struct DisasContextBase *db) static inline void plugin_gen_insn_end(void) { } -static inline void plugin_gen_tb_end(CPUState *cpu) +static inline void plugin_gen_tb_end(CPUState *cpu, size_t num_insns) { } static inline void plugin_gen_disable_mem_helpers(void) From 60cb16c0d87ae0939f4c53c2444a168fdf790a44 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20Benn=C3=A9e?= Date: Mon, 9 Oct 2023 17:41:02 +0100 Subject: [PATCH 0442/1077] contrib/plugins: fix coverity warning in cache MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Coverity complains that appends_stats_line can be fed a 0 leading to the undefined behaviour of a divide by 0. Fixes: CID 1519044 Fixes: CID 1519047 Signed-off-by: Alex Bennée Message-Id: <20231009164104.369749-24-alex.bennee@linaro.org> --- contrib/plugins/cache.c | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/contrib/plugins/cache.c b/contrib/plugins/cache.c index 4fca3edd07..9e7ade3b37 100644 --- a/contrib/plugins/cache.c +++ b/contrib/plugins/cache.c @@ -535,15 +535,13 @@ static void caches_free(Cache **caches) } } -static void append_stats_line(GString *line, uint64_t l1_daccess, - uint64_t l1_dmisses, uint64_t l1_iaccess, - uint64_t l1_imisses, uint64_t l2_access, - uint64_t l2_misses) +static void append_stats_line(GString *line, + uint64_t l1_daccess, uint64_t l1_dmisses, + uint64_t l1_iaccess, uint64_t l1_imisses, + uint64_t l2_access, uint64_t l2_misses) { - double l1_dmiss_rate, l1_imiss_rate, l2_miss_rate; - - l1_dmiss_rate = ((double) l1_dmisses) / (l1_daccess) * 100.0; - l1_imiss_rate = ((double) l1_imisses) / (l1_iaccess) * 100.0; + double l1_dmiss_rate = ((double) l1_dmisses) / (l1_daccess) * 100.0; + double l1_imiss_rate = ((double) l1_imisses) / (l1_iaccess) * 100.0; g_string_append_printf(line, "%-14" PRIu64 " %-12" PRIu64 " %9.4lf%%" " %-14" PRIu64 " %-12" PRIu64 " %9.4lf%%", @@ -554,8 +552,8 @@ static void append_stats_line(GString *line, uint64_t l1_daccess, l1_imisses, l1_iaccess ? l1_imiss_rate : 0.0); - if (use_l2) { - l2_miss_rate = ((double) l2_misses) / (l2_access) * 100.0; + if (l2_access && l2_misses) { + double l2_miss_rate = ((double) l2_misses) / (l2_access) * 100.0; g_string_append_printf(line, " %-12" PRIu64 " %-11" PRIu64 " %10.4lf%%", l2_access, From ec7ee95db90984509bb0824d62d1272f53cbec19 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20Benn=C3=A9e?= Date: Mon, 9 Oct 2023 17:41:03 +0100 Subject: [PATCH 0443/1077] contrib/plugins: fix coverity warning in lockstep MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Coverity complains that e don't check for a truncation when copying in the path. Bail if we can't copy the whole path into sockaddr. Fixes: CID 1519045 Fixes: CID 1519046 Signed-off-by: Alex Bennée Message-Id: <20231009164104.369749-25-alex.bennee@linaro.org> --- contrib/plugins/lockstep.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/plugins/lockstep.c b/contrib/plugins/lockstep.c index 682b11feb2..f0cb8792c6 100644 --- a/contrib/plugins/lockstep.c +++ b/contrib/plugins/lockstep.c @@ -245,6 +245,7 @@ static void vcpu_tb_trans(qemu_plugin_id_t id, struct qemu_plugin_tb *tb) static bool setup_socket(const char *path) { struct sockaddr_un sockaddr; + const gsize pathlen = sizeof(sockaddr.sun_path) - 1; int fd; fd = socket(AF_UNIX, SOCK_STREAM, 0); @@ -254,7 +255,11 @@ static bool setup_socket(const char *path) } sockaddr.sun_family = AF_UNIX; - g_strlcpy(sockaddr.sun_path, path, sizeof(sockaddr.sun_path) - 1); + if (g_strlcpy(sockaddr.sun_path, path, pathlen) >= pathlen) { + perror("bad path"); + return false; + } + if (bind(fd, (struct sockaddr *)&sockaddr, sizeof(sockaddr)) < 0) { perror("bind socket"); close(fd); @@ -287,6 +292,7 @@ static bool connect_socket(const char *path) { int fd; struct sockaddr_un sockaddr; + const gsize pathlen = sizeof(sockaddr.sun_path) - 1; fd = socket(AF_UNIX, SOCK_STREAM, 0); if (fd < 0) { @@ -295,7 +301,10 @@ static bool connect_socket(const char *path) } sockaddr.sun_family = AF_UNIX; - g_strlcpy(sockaddr.sun_path, path, sizeof(sockaddr.sun_path) - 1); + if (g_strlcpy(sockaddr.sun_path, path, pathlen) >= pathlen) { + perror("bad path"); + return false; + } if (connect(fd, (struct sockaddr *)&sockaddr, sizeof(sockaddr)) < 0) { perror("failed to connect"); From 5b982f3bdeee8f0b2215d53012fea4da7c558cc6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20Benn=C3=A9e?= Date: Mon, 9 Oct 2023 17:41:04 +0100 Subject: [PATCH 0444/1077] contrib/plugins: fix coverity warning in hotblocks MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Coverity complains that we have an unbalance use of mutex leading to potential deadlocks. Fixes: CID 1519048 Fixes: a208ba09bd ("tests/plugin: add a hotblocks plugin") Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Alex Bennée Message-Id: <20231009164104.369749-26-alex.bennee@linaro.org> --- contrib/plugins/hotblocks.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contrib/plugins/hotblocks.c b/contrib/plugins/hotblocks.c index 6b74d25fea..4de1b13494 100644 --- a/contrib/plugins/hotblocks.c +++ b/contrib/plugins/hotblocks.c @@ -69,8 +69,8 @@ static void plugin_exit(qemu_plugin_id_t id, void *p) } g_list_free(it); - g_mutex_unlock(&lock); } + g_mutex_unlock(&lock); qemu_plugin_outs(report->str); } From 86dec715a7339fc61c3bdb9715993b277b2089db Mon Sep 17 00:00:00 2001 From: Peter Xu Date: Tue, 5 Sep 2023 12:23:32 -0400 Subject: [PATCH 0445/1077] migration/qmp: Fix crash on setting tls-authz with null MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit QEMU will crash if anyone tries to set tls-authz (which is a type StrOrNull) with 'null' value. Fix it in the easy way by converting it to qstring just like the other two tls parameters. Cc: qemu-stable@nongnu.org # v4.0+ Fixes: d2f1d29b95 ("migration: add support for a "tls-authz" migration parameter") Reviewed-by: Daniel P. Berrangé Reviewed-by: Fabiano Rosas Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Juan Quintela Signed-off-by: Peter Xu Signed-off-by: Juan Quintela Message-ID: <20230905162335.235619-2-peterx@redhat.com> --- migration/options.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/migration/options.c b/migration/options.c index 1d1e1321b0..6bbfd4853d 100644 --- a/migration/options.c +++ b/migration/options.c @@ -1408,20 +1408,25 @@ void qmp_migrate_set_parameters(MigrateSetParameters *params, Error **errp) { MigrationParameters tmp; - /* TODO Rewrite "" to null instead */ + /* TODO Rewrite "" to null instead for all three tls_* parameters */ if (params->tls_creds && params->tls_creds->type == QTYPE_QNULL) { qobject_unref(params->tls_creds->u.n); params->tls_creds->type = QTYPE_QSTRING; params->tls_creds->u.s = strdup(""); } - /* TODO Rewrite "" to null instead */ if (params->tls_hostname && params->tls_hostname->type == QTYPE_QNULL) { qobject_unref(params->tls_hostname->u.n); params->tls_hostname->type = QTYPE_QSTRING; params->tls_hostname->u.s = strdup(""); } + if (params->tls_authz + && params->tls_authz->type == QTYPE_QNULL) { + qobject_unref(params->tls_authz->u.n); + params->tls_authz->type = QTYPE_QSTRING; + params->tls_authz->u.s = strdup(""); + } migrate_params_test_apply(params, &tmp); From 9d47929034eb8f3e67411926bdd1e8246d2797ed Mon Sep 17 00:00:00 2001 From: Fabiano Rosas Date: Wed, 12 Jul 2023 16:07:37 -0300 Subject: [PATCH 0446/1077] tests/qtest: migration: Expose migrate_set_capability The following patch will make use of this function from within migrate-helpers.c, so move it there. Reviewed-by: Juan Quintela Reviewed-by: Thomas Huth Reviewed-by: Peter Xu Signed-off-by: Fabiano Rosas Signed-off-by: Juan Quintela Message-ID: <20230712190742.22294-2-farosas@suse.de> --- tests/qtest/migration-helpers.c | 11 +++++++++++ tests/qtest/migration-helpers.h | 3 +++ tests/qtest/migration-test.c | 11 ----------- 3 files changed, 14 insertions(+), 11 deletions(-) diff --git a/tests/qtest/migration-helpers.c b/tests/qtest/migration-helpers.c index be00c52d00..2df198c99e 100644 --- a/tests/qtest/migration-helpers.c +++ b/tests/qtest/migration-helpers.c @@ -70,6 +70,17 @@ void migrate_qmp(QTestState *who, const char *uri, const char *fmt, ...) "{ 'execute': 'migrate', 'arguments': %p}", args); } +void migrate_set_capability(QTestState *who, const char *capability, + bool value) +{ + qtest_qmp_assert_success(who, + "{ 'execute': 'migrate-set-capabilities'," + "'arguments': { " + "'capabilities': [ { " + "'capability': %s, 'state': %i } ] } }", + capability, value); +} + /* * Note: caller is responsible to free the returned object via * qobject_unref() after use diff --git a/tests/qtest/migration-helpers.h b/tests/qtest/migration-helpers.h index 009e250e90..484d7c960f 100644 --- a/tests/qtest/migration-helpers.h +++ b/tests/qtest/migration-helpers.h @@ -23,6 +23,9 @@ bool migrate_watch_for_resume(QTestState *who, const char *name, G_GNUC_PRINTF(3, 4) void migrate_qmp(QTestState *who, const char *uri, const char *fmt, ...); +void migrate_set_capability(QTestState *who, const char *capability, + bool value); + QDict *migrate_query(QTestState *who); QDict *migrate_query_not_failed(QTestState *who); diff --git a/tests/qtest/migration-test.c b/tests/qtest/migration-test.c index 46f1c275a2..48778565a3 100644 --- a/tests/qtest/migration-test.c +++ b/tests/qtest/migration-test.c @@ -605,17 +605,6 @@ static void migrate_cancel(QTestState *who) qtest_qmp_assert_success(who, "{ 'execute': 'migrate_cancel' }"); } -static void migrate_set_capability(QTestState *who, const char *capability, - bool value) -{ - qtest_qmp_assert_success(who, - "{ 'execute': 'migrate-set-capabilities'," - "'arguments': { " - "'capabilities': [ { " - "'capability': %s, 'state': %i } ] } }", - capability, value); -} - static void migrate_postcopy_start(QTestState *from, QTestState *to) { qtest_qmp_assert_success(from, "{ 'execute': 'migrate-start-postcopy' }"); From 28fa97e00698eecc9a7f7eeca43ccbdee3d33b3e Mon Sep 17 00:00:00 2001 From: Fabiano Rosas Date: Wed, 12 Jul 2023 16:07:38 -0300 Subject: [PATCH 0447/1077] tests/qtest: migration: Add migrate_incoming_qmp helper file-based migration requires the target to initiate its migration after the source has finished writing out the data in the file. Currently there's no easy way to initiate 'migrate-incoming', allow this by introducing migrate_incoming_qmp helper, similarly to migrate_qmp. Also make sure migration events are enabled and wait for the incoming migration to start before returning. This avoid a race when querying the migration status too soon after issuing the command. Reviewed-by: Peter Xu Reviewed-by: Juan Quintela Signed-off-by: Fabiano Rosas Signed-off-by: Juan Quintela Message-ID: <20230712190742.22294-3-farosas@suse.de> --- tests/qtest/migration-helpers.c | 29 +++++++++++++++++++++++++++++ tests/qtest/migration-helpers.h | 4 ++++ 2 files changed, 33 insertions(+) diff --git a/tests/qtest/migration-helpers.c b/tests/qtest/migration-helpers.c index 2df198c99e..08f5ee1179 100644 --- a/tests/qtest/migration-helpers.c +++ b/tests/qtest/migration-helpers.c @@ -81,6 +81,35 @@ void migrate_set_capability(QTestState *who, const char *capability, capability, value); } +void migrate_incoming_qmp(QTestState *to, const char *uri, const char *fmt, ...) +{ + va_list ap; + QDict *args, *rsp, *data; + + va_start(ap, fmt); + args = qdict_from_vjsonf_nofail(fmt, ap); + va_end(ap); + + g_assert(!qdict_haskey(args, "uri")); + qdict_put_str(args, "uri", uri); + + migrate_set_capability(to, "events", true); + + rsp = qtest_qmp(to, "{ 'execute': 'migrate-incoming', 'arguments': %p}", + args); + g_assert(qdict_haskey(rsp, "return")); + qobject_unref(rsp); + + rsp = qtest_qmp_eventwait_ref(to, "MIGRATION"); + g_assert(qdict_haskey(rsp, "data")); + + data = qdict_get_qdict(rsp, "data"); + g_assert(qdict_haskey(data, "status")); + g_assert_cmpstr(qdict_get_str(data, "status"), ==, "setup"); + + qobject_unref(rsp); +} + /* * Note: caller is responsible to free the returned object via * qobject_unref() after use diff --git a/tests/qtest/migration-helpers.h b/tests/qtest/migration-helpers.h index 484d7c960f..57d295a4fe 100644 --- a/tests/qtest/migration-helpers.h +++ b/tests/qtest/migration-helpers.h @@ -23,6 +23,10 @@ bool migrate_watch_for_resume(QTestState *who, const char *name, G_GNUC_PRINTF(3, 4) void migrate_qmp(QTestState *who, const char *uri, const char *fmt, ...); +G_GNUC_PRINTF(3, 4) +void migrate_incoming_qmp(QTestState *who, const char *uri, + const char *fmt, ...); + void migrate_set_capability(QTestState *who, const char *capability, bool value); From 6830e53b4bd96fe00b72730a3546c5b65ea840a6 Mon Sep 17 00:00:00 2001 From: Fabiano Rosas Date: Wed, 12 Jul 2023 16:07:39 -0300 Subject: [PATCH 0448/1077] tests/qtest: migration: Use migrate_incoming_qmp where appropriate Use the new migrate_incoming_qmp helper in the places that currently open-code calling migrate-incoming. Reviewed-by: Juan Quintela Reviewed-by: Peter Xu Signed-off-by: Fabiano Rosas Signed-off-by: Juan Quintela Message-ID: <20230712190742.22294-4-farosas@suse.de> --- tests/qtest/meson.build | 1 + tests/qtest/migration-test.c | 12 ++--- tests/qtest/virtio-net-failover.c | 77 ++++--------------------------- 3 files changed, 14 insertions(+), 76 deletions(-) diff --git a/tests/qtest/meson.build b/tests/qtest/meson.build index 1fba07f4ed..66795cfcd2 100644 --- a/tests/qtest/meson.build +++ b/tests/qtest/meson.build @@ -317,6 +317,7 @@ qtests = { 'tpm-tis-i2c-test': [io, tpmemu_files, 'qtest_aspeed.c'], 'tpm-tis-device-swtpm-test': [io, tpmemu_files, 'tpm-tis-util.c'], 'tpm-tis-device-test': [io, tpmemu_files, 'tpm-tis-util.c'], + 'virtio-net-failover': files('migration-helpers.c'), 'vmgenid-test': files('boot-sector.c', 'acpi-utils.c'), 'netdev-socket': files('netdev-socket.c', '../unit/socket-helpers.c'), } diff --git a/tests/qtest/migration-test.c b/tests/qtest/migration-test.c index 48778565a3..84660b3e3d 100644 --- a/tests/qtest/migration-test.c +++ b/tests/qtest/migration-test.c @@ -1970,8 +1970,7 @@ static void *test_migrate_fd_start_hook(QTestState *from, close(pair[0]); /* Start incoming migration from the 1st socket */ - qtest_qmp_assert_success(to, "{ 'execute': 'migrate-incoming'," - " 'arguments': { 'uri': 'fd:fd-mig' }}"); + migrate_incoming_qmp(to, "fd:fd-mig", "{}"); /* Send the 2nd socket to the target */ qtest_qmp_fds_assert_success(from, &pair[1], 1, @@ -2193,8 +2192,7 @@ test_migrate_precopy_tcp_multifd_start_common(QTestState *from, migrate_set_capability(to, "multifd", true); /* Start incoming migration from the 1st socket */ - qtest_qmp_assert_success(to, "{ 'execute': 'migrate-incoming'," - " 'arguments': { 'uri': 'tcp:127.0.0.1:0' }}"); + migrate_incoming_qmp(to, "tcp:127.0.0.1:0", "{}"); return NULL; } @@ -2447,8 +2445,7 @@ static void test_multifd_tcp_cancel(void) migrate_set_capability(to, "multifd", true); /* Start incoming migration from the 1st socket */ - qtest_qmp_assert_success(to, "{ 'execute': 'migrate-incoming'," - " 'arguments': { 'uri': 'tcp:127.0.0.1:0' }}"); + migrate_incoming_qmp(to, "tcp:127.0.0.1:0", "{}"); /* Wait for the first serial output from the source */ wait_for_serial("src_serial"); @@ -2478,8 +2475,7 @@ static void test_multifd_tcp_cancel(void) migrate_set_capability(to2, "multifd", true); /* Start incoming migration from the 1st socket */ - qtest_qmp_assert_success(to2, "{ 'execute': 'migrate-incoming'," - " 'arguments': { 'uri': 'tcp:127.0.0.1:0' }}"); + migrate_incoming_qmp(to2, "tcp:127.0.0.1:0", "{}"); g_free(uri); uri = migrate_get_socket_address(to2, "socket-address"); diff --git a/tests/qtest/virtio-net-failover.c b/tests/qtest/virtio-net-failover.c index 4a809590bf..0d40bc1f2d 100644 --- a/tests/qtest/virtio-net-failover.c +++ b/tests/qtest/virtio-net-failover.c @@ -11,6 +11,7 @@ #include "libqtest.h" #include "libqos/pci.h" #include "libqos/pci-pc.h" +#include "migration-helpers.h" #include "qapi/qmp/qdict.h" #include "qapi/qmp/qlist.h" #include "qapi/qmp/qjson.h" @@ -736,26 +737,10 @@ static void test_migrate_out(gconstpointer opaque) machine_stop(qts); } -static QDict *get_migration_event(QTestState *qts) -{ - QDict *resp; - QDict *data; - - resp = qtest_qmp_eventwait_ref(qts, "MIGRATION"); - g_assert(qdict_haskey(resp, "data")); - - data = qdict_get_qdict(resp, "data"); - g_assert(qdict_haskey(data, "status")); - qobject_ref(data); - qobject_unref(resp); - - return data; -} - static void test_migrate_in(gconstpointer opaque) { QTestState *qts; - QDict *resp, *args, *ret; + QDict *resp, *ret; g_autofree gchar *uri = g_strdup_printf("exec: cat %s", (gchar *)opaque); qts = machine_start(BASE_MACHINE @@ -787,18 +772,7 @@ static void test_migrate_in(gconstpointer opaque) check_one_card(qts, true, "standby0", MAC_STANDBY0); check_one_card(qts, false, "primary0", MAC_PRIMARY0); - args = qdict_from_jsonf_nofail("{}"); - g_assert_nonnull(args); - qdict_put_str(args, "uri", uri); - - resp = qtest_qmp(qts, "{ 'execute': 'migrate-incoming', 'arguments': %p}", - args); - g_assert(qdict_haskey(resp, "return")); - qobject_unref(resp); - - resp = get_migration_event(qts); - g_assert_cmpstr(qdict_get_str(resp, "status"), ==, "setup"); - qobject_unref(resp); + migrate_incoming_qmp(qts, uri, "{}"); resp = get_failover_negociated_event(qts); g_assert_cmpstr(qdict_get_str(resp, "device-id"), ==, "standby0"); @@ -888,7 +862,7 @@ static void test_off_migrate_out(gconstpointer opaque) static void test_off_migrate_in(gconstpointer opaque) { QTestState *qts; - QDict *resp, *args, *ret; + QDict *ret; g_autofree gchar *uri = g_strdup_printf("exec: cat %s", (gchar *)opaque); qts = machine_start(BASE_MACHINE @@ -920,18 +894,7 @@ static void test_off_migrate_in(gconstpointer opaque) check_one_card(qts, true, "standby0", MAC_STANDBY0); check_one_card(qts, true, "primary0", MAC_PRIMARY0); - args = qdict_from_jsonf_nofail("{}"); - g_assert_nonnull(args); - qdict_put_str(args, "uri", uri); - - resp = qtest_qmp(qts, "{ 'execute': 'migrate-incoming', 'arguments': %p}", - args); - g_assert(qdict_haskey(resp, "return")); - qobject_unref(resp); - - resp = get_migration_event(qts); - g_assert_cmpstr(qdict_get_str(resp, "status"), ==, "setup"); - qobject_unref(resp); + migrate_incoming_qmp(qts, uri, "{}"); check_one_card(qts, true, "standby0", MAC_STANDBY0); check_one_card(qts, true, "primary0", MAC_PRIMARY0); @@ -1026,7 +989,7 @@ static void test_guest_off_migrate_out(gconstpointer opaque) static void test_guest_off_migrate_in(gconstpointer opaque) { QTestState *qts; - QDict *resp, *args, *ret; + QDict *ret; g_autofree gchar *uri = g_strdup_printf("exec: cat %s", (gchar *)opaque); qts = machine_start(BASE_MACHINE @@ -1058,18 +1021,7 @@ static void test_guest_off_migrate_in(gconstpointer opaque) check_one_card(qts, true, "standby0", MAC_STANDBY0); check_one_card(qts, false, "primary0", MAC_PRIMARY0); - args = qdict_from_jsonf_nofail("{}"); - g_assert_nonnull(args); - qdict_put_str(args, "uri", uri); - - resp = qtest_qmp(qts, "{ 'execute': 'migrate-incoming', 'arguments': %p}", - args); - g_assert(qdict_haskey(resp, "return")); - qobject_unref(resp); - - resp = get_migration_event(qts); - g_assert_cmpstr(qdict_get_str(resp, "status"), ==, "setup"); - qobject_unref(resp); + migrate_incoming_qmp(qts, uri, "{}"); check_one_card(qts, true, "standby0", MAC_STANDBY0); check_one_card(qts, false, "primary0", MAC_PRIMARY0); @@ -1728,7 +1680,7 @@ static void test_multi_out(gconstpointer opaque) static void test_multi_in(gconstpointer opaque) { QTestState *qts; - QDict *resp, *args, *ret; + QDict *resp, *ret; g_autofree gchar *uri = g_strdup_printf("exec: cat %s", (gchar *)opaque); qts = machine_start(BASE_MACHINE @@ -1794,18 +1746,7 @@ static void test_multi_in(gconstpointer opaque) check_one_card(qts, true, "standby1", MAC_STANDBY1); check_one_card(qts, false, "primary1", MAC_PRIMARY1); - args = qdict_from_jsonf_nofail("{}"); - g_assert_nonnull(args); - qdict_put_str(args, "uri", uri); - - resp = qtest_qmp(qts, "{ 'execute': 'migrate-incoming', 'arguments': %p}", - args); - g_assert(qdict_haskey(resp, "return")); - qobject_unref(resp); - - resp = get_migration_event(qts); - g_assert_cmpstr(qdict_get_str(resp, "status"), ==, "setup"); - qobject_unref(resp); + migrate_incoming_qmp(qts, uri, "{}"); resp = get_failover_negociated_event(qts); g_assert_cmpstr(qdict_get_str(resp, "device-id"), ==, "standby0"); From 4111a732e80894256c9053577f0e9369eeea807b Mon Sep 17 00:00:00 2001 From: Fabiano Rosas Date: Wed, 12 Jul 2023 16:07:40 -0300 Subject: [PATCH 0449/1077] migration: Set migration status early in incoming side We are sending a migration event of MIGRATION_STATUS_SETUP at qemu_start_incoming_migration but never actually setting the state. This creates a window between qmp_migrate_incoming and process_incoming_migration_co where the migration status is still MIGRATION_STATUS_NONE. Calling query-migrate during this time will return an empty response even though the incoming migration command has already been issued. Commit 7cf1fe6d68 ("migration: Add migration events on target side") has added support to the 'events' capability to the incoming part of migration, but chose to send the SETUP event without setting the state. I'm assuming this was a mistake. This introduces a change in behavior, any QMP client waiting for the SETUP event will hang, unless it has previously enabled the 'events' capability. Having the capability enabled is sufficient to continue to receive the event. Reviewed-by: Peter Xu Reviewed-by: Juan Quintela Signed-off-by: Fabiano Rosas Signed-off-by: Juan Quintela Message-ID: <20230712190742.22294-5-farosas@suse.de> --- migration/migration.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/migration/migration.c b/migration/migration.c index 585d3c8f55..2057e42134 100644 --- a/migration/migration.c +++ b/migration/migration.c @@ -431,13 +431,16 @@ void migrate_add_address(SocketAddress *address) static void qemu_start_incoming_migration(const char *uri, Error **errp) { const char *p = NULL; + MigrationIncomingState *mis = migration_incoming_get_current(); /* URI is not suitable for migration? */ if (!migration_channels_and_uri_compatible(uri, errp)) { return; } - qapi_event_send_migration(MIGRATION_STATUS_SETUP); + migrate_set_state(&mis->state, MIGRATION_STATUS_NONE, + MIGRATION_STATUS_SETUP); + if (strstart(uri, "tcp:", &p) || strstart(uri, "unix:", NULL) || strstart(uri, "vsock:", NULL)) { @@ -531,7 +534,7 @@ process_incoming_migration_co(void *opaque) mis->largest_page_size = qemu_ram_pagesize_largest(); postcopy_state_set(POSTCOPY_INCOMING_NONE); - migrate_set_state(&mis->state, MIGRATION_STATUS_NONE, + migrate_set_state(&mis->state, MIGRATION_STATUS_SETUP, MIGRATION_STATUS_ACTIVE); mis->loadvm_co = qemu_coroutine_self(); From 5274274c262edc6738ddc5c590dc0a08dd1090b1 Mon Sep 17 00:00:00 2001 From: Fabiano Rosas Date: Wed, 12 Jul 2023 16:07:41 -0300 Subject: [PATCH 0450/1077] tests/qtest: migration: Add support for negative testing of qmp_migrate There is currently no way to write a test for errors that happened in qmp_migrate before the migration has started. Add a version of qmp_migrate that ensures an error happens. To make use of it a test needs to set MigrateCommon.result as MIG_TEST_QMP_ERROR. Reviewed-by: Peter Xu Reviewed-by: Juan Quintela Signed-off-by: Fabiano Rosas Signed-off-by: Juan Quintela Message-ID: <20230712190742.22294-6-farosas@suse.de> --- tests/qtest/libqtest.c | 33 +++++++++++++++++++++++++++++++++ tests/qtest/libqtest.h | 28 ++++++++++++++++++++++++++++ tests/qtest/migration-helpers.c | 20 ++++++++++++++++++++ tests/qtest/migration-helpers.h | 3 +++ tests/qtest/migration-test.c | 16 ++++++++++++---- 5 files changed, 96 insertions(+), 4 deletions(-) diff --git a/tests/qtest/libqtest.c b/tests/qtest/libqtest.c index 3f94a4f477..dc7a55634c 100644 --- a/tests/qtest/libqtest.c +++ b/tests/qtest/libqtest.c @@ -1259,6 +1259,28 @@ void qtest_memset(QTestState *s, uint64_t addr, uint8_t pattern, size_t size) qtest_rsp(s); } +QDict *qtest_vqmp_assert_failure_ref(QTestState *qts, + const char *fmt, va_list args) +{ + QDict *response; + QDict *ret; + + response = qtest_vqmp(qts, fmt, args); + + g_assert(response); + if (!qdict_haskey(response, "error")) { + g_autoptr(GString) s = qobject_to_json_pretty(QOBJECT(response), true); + g_test_message("%s", s->str); + } + g_assert(qdict_haskey(response, "error")); + g_assert(!qdict_haskey(response, "return")); + ret = qdict_get_qdict(response, "error"); + qobject_ref(ret); + qobject_unref(response); + + return ret; +} + QDict *qtest_vqmp_assert_success_ref(QTestState *qts, const char *fmt, va_list args) { @@ -1321,6 +1343,17 @@ void qtest_vqmp_fds_assert_success(QTestState *qts, int *fds, size_t nfds, } #endif /* !_WIN32 */ +QDict *qtest_qmp_assert_failure_ref(QTestState *qts, const char *fmt, ...) +{ + QDict *response; + va_list ap; + + va_start(ap, fmt); + response = qtest_vqmp_assert_failure_ref(qts, fmt, ap); + va_end(ap); + return response; +} + QDict *qtest_qmp_assert_success_ref(QTestState *qts, const char *fmt, ...) { QDict *response; diff --git a/tests/qtest/libqtest.h b/tests/qtest/libqtest.h index e53e350e3a..5fe3d13466 100644 --- a/tests/qtest/libqtest.h +++ b/tests/qtest/libqtest.h @@ -810,6 +810,34 @@ void qtest_vqmp_fds_assert_success(QTestState *qts, int *fds, size_t nfds, G_GNUC_PRINTF(4, 0); #endif /* !_WIN32 */ +/** + * qtest_qmp_assert_failure_ref: + * @qts: QTestState instance to operate on + * @fmt: QMP message to send to qemu, formatted like + * qobject_from_jsonf_nofail(). See parse_interpolation() for what's + * supported after '%'. + * + * Sends a QMP message to QEMU, asserts that an 'error' key is present in + * the response, and returns the response. + */ +QDict *qtest_qmp_assert_failure_ref(QTestState *qts, const char *fmt, ...) + G_GNUC_PRINTF(2, 3); + +/** + * qtest_vqmp_assert_failure_ref: + * @qts: QTestState instance to operate on + * @fmt: QMP message to send to qemu, formatted like + * qobject_from_jsonf_nofail(). See parse_interpolation() for what's + * supported after '%'. + * @args: variable arguments for @fmt + * + * Sends a QMP message to QEMU, asserts that an 'error' key is present in + * the response, and returns the response. + */ +QDict *qtest_vqmp_assert_failure_ref(QTestState *qts, + const char *fmt, va_list args) + G_GNUC_PRINTF(2, 0); + /** * qtest_qmp_assert_success_ref: * @qts: QTestState instance to operate on diff --git a/tests/qtest/migration-helpers.c b/tests/qtest/migration-helpers.c index 08f5ee1179..0c185db450 100644 --- a/tests/qtest/migration-helpers.c +++ b/tests/qtest/migration-helpers.c @@ -49,6 +49,26 @@ bool migrate_watch_for_resume(QTestState *who, const char *name, return false; } +void migrate_qmp_fail(QTestState *who, const char *uri, const char *fmt, ...) +{ + va_list ap; + QDict *args, *err; + + va_start(ap, fmt); + args = qdict_from_vjsonf_nofail(fmt, ap); + va_end(ap); + + g_assert(!qdict_haskey(args, "uri")); + qdict_put_str(args, "uri", uri); + + err = qtest_qmp_assert_failure_ref( + who, "{ 'execute': 'migrate', 'arguments': %p}", args); + + g_assert(qdict_haskey(err, "desc")); + + qobject_unref(err); +} + /* * Send QMP command "migrate". * Arguments are built from @fmt... (formatted like diff --git a/tests/qtest/migration-helpers.h b/tests/qtest/migration-helpers.h index 57d295a4fe..4f51d0f8bc 100644 --- a/tests/qtest/migration-helpers.h +++ b/tests/qtest/migration-helpers.h @@ -27,6 +27,9 @@ G_GNUC_PRINTF(3, 4) void migrate_incoming_qmp(QTestState *who, const char *uri, const char *fmt, ...); +G_GNUC_PRINTF(3, 4) +void migrate_qmp_fail(QTestState *who, const char *uri, const char *fmt, ...); + void migrate_set_capability(QTestState *who, const char *capability, bool value); diff --git a/tests/qtest/migration-test.c b/tests/qtest/migration-test.c index 84660b3e3d..8eb2053dbb 100644 --- a/tests/qtest/migration-test.c +++ b/tests/qtest/migration-test.c @@ -697,6 +697,8 @@ typedef struct { MIG_TEST_FAIL, /* This test should fail, dest qemu should fail with abnormal status */ MIG_TEST_FAIL_DEST_QUIT_ERR, + /* The QMP command for this migration should fail with an error */ + MIG_TEST_QMP_ERROR, } result; /* @@ -1503,6 +1505,7 @@ static void test_precopy_common(MigrateCommon *args) { QTestState *from, *to; void *data_hook = NULL; + g_autofree char *connect_uri = NULL; if (test_migrate_start(&from, &to, args->listen_uri, &args->start)) { return; @@ -1537,13 +1540,17 @@ static void test_precopy_common(MigrateCommon *args) } if (!args->connect_uri) { - g_autofree char *local_connect_uri = - migrate_get_socket_address(to, "socket-address"); - migrate_qmp(from, local_connect_uri, "{}"); + connect_uri = migrate_get_socket_address(to, "socket-address"); } else { - migrate_qmp(from, args->connect_uri, "{}"); + connect_uri = g_strdup(args->connect_uri); } + if (args->result == MIG_TEST_QMP_ERROR) { + migrate_qmp_fail(from, connect_uri, "{}"); + goto finish; + } + + migrate_qmp(from, connect_uri, "{}"); if (args->result != MIG_TEST_SUCCEED) { bool allow_active = args->result == MIG_TEST_FAIL; @@ -1595,6 +1602,7 @@ static void test_precopy_common(MigrateCommon *args) wait_for_serial("dest_serial"); } +finish: if (args->finish_hook) { args->finish_hook(from, to, data_hook); } From 0e99bb8f54418231baa084f1d8270e7500e48245 Mon Sep 17 00:00:00 2001 From: Peter Xu Date: Wed, 4 Oct 2023 18:02:39 -0400 Subject: [PATCH 0451/1077] migration: Allow RECOVER->PAUSED convertion for dest qemu There's a bug on dest that if a double fault triggered on dest qemu (a network issue during postcopy-recover), we won't set PAUSED correctly because we assumed we always came from ACTIVE. Fix that by always overwriting the state to PAUSE. We could also check for these two states, but maybe it's an overkill. We did the same on the src QEMU to unconditionally switch to PAUSE anyway. Reviewed-by: Fabiano Rosas Reviewed-by: Juan Quintela Signed-off-by: Peter Xu Signed-off-by: Juan Quintela Message-ID: <20231004220240.167175-10-peterx@redhat.com> --- migration/savevm.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/migration/savevm.c b/migration/savevm.c index 60eec7c31f..497ce02bd7 100644 --- a/migration/savevm.c +++ b/migration/savevm.c @@ -2734,7 +2734,8 @@ static bool postcopy_pause_incoming(MigrationIncomingState *mis) qemu_mutex_unlock(&mis->postcopy_prio_thread_mutex); } - migrate_set_state(&mis->state, MIGRATION_STATUS_POSTCOPY_ACTIVE, + /* Current state can be either ACTIVE or RECOVER */ + migrate_set_state(&mis->state, mis->state, MIGRATION_STATUS_POSTCOPY_PAUSED); /* Notify the fault thread for the invalidated file handle */ From b72eacf3c014ba7cbccee57a791589822e175580 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Thu, 28 Sep 2023 15:19:27 +0200 Subject: [PATCH 0452/1077] migration/rdma: Clean up qemu_rdma_poll()'s return type qemu_rdma_poll()'s return type is uint64_t, even though it returns 0, -1, or @ret, which is int. Its callers assign the return value to int variables, then check whether it's negative. Unclean. Return int instead. Signed-off-by: Markus Armbruster Reviewed-by: Fabiano Rosas Reviewed-by: Li Zhijian Reviewed-by: Juan Quintela Signed-off-by: Juan Quintela Message-ID: <20230928132019.2544702-2-armbru@redhat.com> --- migration/rdma.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/migration/rdma.c b/migration/rdma.c index cd5e1afe60..e72864d1cf 100644 --- a/migration/rdma.c +++ b/migration/rdma.c @@ -1469,8 +1469,8 @@ static uint64_t qemu_rdma_make_wrid(uint64_t wr_id, uint64_t index, * (of any kind) has completed. * Return the work request ID that completed. */ -static uint64_t qemu_rdma_poll(RDMAContext *rdma, struct ibv_cq *cq, - uint64_t *wr_id_out, uint32_t *byte_len) +static int qemu_rdma_poll(RDMAContext *rdma, struct ibv_cq *cq, + uint64_t *wr_id_out, uint32_t *byte_len) { int ret; struct ibv_wc wc; From c07d19622ce5ece8097c393ad5974f0ecea50185 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Thu, 28 Sep 2023 15:19:28 +0200 Subject: [PATCH 0453/1077] migration/rdma: Clean up qemu_rdma_data_init()'s return type qemu_rdma_data_init() return type is void *. It actually returns RDMAContext *, and all its callers assign the value to an RDMAContext *. Unclean. Return RDMAContext * instead. Signed-off-by: Markus Armbruster Reviewed-by: Fabiano Rosas Reviewed-by: Li Zhijian Reviewed-by: Juan Quintela Signed-off-by: Juan Quintela Message-ID: <20230928132019.2544702-3-armbru@redhat.com> --- migration/rdma.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/migration/rdma.c b/migration/rdma.c index e72864d1cf..1432fb80ec 100644 --- a/migration/rdma.c +++ b/migration/rdma.c @@ -2759,7 +2759,7 @@ static void qemu_rdma_return_path_dest_init(RDMAContext *rdma_return_path, rdma_return_path->is_return_path = true; } -static void *qemu_rdma_data_init(const char *host_port, Error **errp) +static RDMAContext *qemu_rdma_data_init(const char *host_port, Error **errp) { RDMAContext *rdma = NULL; InetSocketAddress *addr; From 1720a2a8758431810a1d7bdb51780d87bb55b4b4 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Thu, 28 Sep 2023 15:19:29 +0200 Subject: [PATCH 0454/1077] migration/rdma: Clean up rdma_delete_block()'s return type rdma_delete_block() always returns 0, which its only caller ignores. Return void instead. Signed-off-by: Markus Armbruster Reviewed-by: Fabiano Rosas Reviewed-by: Li Zhijian Reviewed-by: Juan Quintela Signed-off-by: Juan Quintela Message-ID: <20230928132019.2544702-4-armbru@redhat.com> --- migration/rdma.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/migration/rdma.c b/migration/rdma.c index 1432fb80ec..65ed814d88 100644 --- a/migration/rdma.c +++ b/migration/rdma.c @@ -668,7 +668,7 @@ static int qemu_rdma_init_ram_blocks(RDMAContext *rdma) * Note: If used outside of cleanup, the caller must ensure that the destination * block structures are also updated */ -static int rdma_delete_block(RDMAContext *rdma, RDMALocalBlock *block) +static void rdma_delete_block(RDMAContext *rdma, RDMALocalBlock *block) { RDMALocalBlocks *local = &rdma->local_ram_blocks; RDMALocalBlock *old = local->block; @@ -754,8 +754,6 @@ static int rdma_delete_block(RDMAContext *rdma, RDMALocalBlock *block) &local->block[x]); } } - - return 0; } /* From b5631d5bda04b8653c9232682bebad9584c9857c Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Thu, 28 Sep 2023 15:19:30 +0200 Subject: [PATCH 0455/1077] migration/rdma: Drop fragile wr_id formatting wrid_desc[] uses 4001 pointers to map four integer values to strings. print_wrid() accesses wrid_desc[] out of bounds when passed a negative argument. It returns null for values 2..1999 and 2001..3999. qemu_rdma_poll() and qemu_rdma_block_for_wrid() print wrid_desc[wr_id] and passes print_wrid(wr_id) to tracepoints. Could conceivably crash trying to format a null string. I believe access out of bounds is not possible. Not worth cleaning up. Dumb down to show just numeric wr_id. Signed-off-by: Markus Armbruster Reviewed-by: Fabiano Rosas Reviewed-by: Li Zhijian Reviewed-by: Juan Quintela Signed-off-by: Juan Quintela Message-ID: <20230928132019.2544702-5-armbru@redhat.com> --- migration/rdma.c | 32 +++++++------------------------- migration/trace-events | 8 ++++---- 2 files changed, 11 insertions(+), 29 deletions(-) diff --git a/migration/rdma.c b/migration/rdma.c index 65ed814d88..8f297c9e46 100644 --- a/migration/rdma.c +++ b/migration/rdma.c @@ -133,13 +133,6 @@ enum { RDMA_WRID_RECV_CONTROL = 4000, }; -static const char *wrid_desc[] = { - [RDMA_WRID_NONE] = "NONE", - [RDMA_WRID_RDMA_WRITE] = "WRITE RDMA", - [RDMA_WRID_SEND_CONTROL] = "CONTROL SEND", - [RDMA_WRID_RECV_CONTROL] = "CONTROL RECV", -}; - /* * Work request IDs for IB SEND messages only (not RDMA writes). * This is used by the migration protocol to transmit @@ -535,7 +528,6 @@ static void network_to_result(RDMARegisterResult *result) result->host_addr = ntohll(result->host_addr); }; -const char *print_wrid(int wrid); static int qemu_rdma_exchange_send(RDMAContext *rdma, RDMAControlHeader *head, uint8_t *data, RDMAControlHeader *resp, int *resp_idx, @@ -1362,14 +1354,6 @@ static int qemu_rdma_reg_control(RDMAContext *rdma, int idx) return -1; } -const char *print_wrid(int wrid) -{ - if (wrid >= RDMA_WRID_RECV_CONTROL) { - return wrid_desc[RDMA_WRID_RECV_CONTROL]; - } - return wrid_desc[wrid]; -} - /* * Perform a non-optimized memory unregistration after every transfer * for demonstration purposes, only if pin-all is not requested. @@ -1491,15 +1475,15 @@ static int qemu_rdma_poll(RDMAContext *rdma, struct ibv_cq *cq, if (wc.status != IBV_WC_SUCCESS) { fprintf(stderr, "ibv_poll_cq wc.status=%d %s!\n", wc.status, ibv_wc_status_str(wc.status)); - fprintf(stderr, "ibv_poll_cq wrid=%s!\n", wrid_desc[wr_id]); + fprintf(stderr, "ibv_poll_cq wrid=%" PRIu64 "!\n", wr_id); return -1; } if (rdma->control_ready_expected && (wr_id >= RDMA_WRID_RECV_CONTROL)) { - trace_qemu_rdma_poll_recv(wrid_desc[RDMA_WRID_RECV_CONTROL], - wr_id - RDMA_WRID_RECV_CONTROL, wr_id, rdma->nb_sent); + trace_qemu_rdma_poll_recv(wr_id - RDMA_WRID_RECV_CONTROL, wr_id, + rdma->nb_sent); rdma->control_ready_expected = 0; } @@ -1510,7 +1494,7 @@ static int qemu_rdma_poll(RDMAContext *rdma, struct ibv_cq *cq, (wc.wr_id & RDMA_WRID_BLOCK_MASK) >> RDMA_WRID_BLOCK_SHIFT; RDMALocalBlock *block = &(rdma->local_ram_blocks.block[index]); - trace_qemu_rdma_poll_write(print_wrid(wr_id), wr_id, rdma->nb_sent, + trace_qemu_rdma_poll_write(wr_id, rdma->nb_sent, index, chunk, block->local_host_addr, (void *)(uintptr_t)block->remote_host_addr); @@ -1520,7 +1504,7 @@ static int qemu_rdma_poll(RDMAContext *rdma, struct ibv_cq *cq, rdma->nb_sent--; } } else { - trace_qemu_rdma_poll_other(print_wrid(wr_id), wr_id, rdma->nb_sent); + trace_qemu_rdma_poll_other(wr_id, rdma->nb_sent); } *wr_id_out = wc.wr_id; @@ -1665,8 +1649,7 @@ static int qemu_rdma_block_for_wrid(RDMAContext *rdma, int wrid_requested, break; } if (wr_id != wrid_requested) { - trace_qemu_rdma_block_for_wrid_miss(print_wrid(wrid_requested), - wrid_requested, print_wrid(wr_id), wr_id); + trace_qemu_rdma_block_for_wrid_miss(wrid_requested, wr_id); } } @@ -1705,8 +1688,7 @@ static int qemu_rdma_block_for_wrid(RDMAContext *rdma, int wrid_requested, break; } if (wr_id != wrid_requested) { - trace_qemu_rdma_block_for_wrid_miss(print_wrid(wrid_requested), - wrid_requested, print_wrid(wr_id), wr_id); + trace_qemu_rdma_block_for_wrid_miss(wrid_requested, wr_id); } } diff --git a/migration/trace-events b/migration/trace-events index 002abe3a4e..19f9ee7c6d 100644 --- a/migration/trace-events +++ b/migration/trace-events @@ -208,7 +208,7 @@ qemu_rdma_accept_incoming_migration(void) "" qemu_rdma_accept_incoming_migration_accepted(void) "" qemu_rdma_accept_pin_state(bool pin) "%d" qemu_rdma_accept_pin_verbsc(void *verbs) "Verbs context after listen: %p" -qemu_rdma_block_for_wrid_miss(const char *wcompstr, int wcomp, const char *gcompstr, uint64_t req) "A Wanted wrid %s (%d) but got %s (%" PRIu64 ")" +qemu_rdma_block_for_wrid_miss(int wcomp, uint64_t req) "A Wanted wrid %d but got %" PRIu64 qemu_rdma_cleanup_disconnect(void) "" qemu_rdma_close(void) "" qemu_rdma_connect_pin_all_requested(void) "" @@ -222,9 +222,9 @@ qemu_rdma_exchange_send_waiting(const char *desc) "Waiting for response %s" qemu_rdma_exchange_send_received(const char *desc) "Response %s received." qemu_rdma_fill(size_t control_len, size_t size) "RDMA %zd of %zd bytes already in buffer" qemu_rdma_init_ram_blocks(int blocks) "Allocated %d local ram block structures" -qemu_rdma_poll_recv(const char *compstr, int64_t comp, int64_t id, int sent) "completion %s #%" PRId64 " received (%" PRId64 ") left %d" -qemu_rdma_poll_write(const char *compstr, int64_t comp, int left, uint64_t block, uint64_t chunk, void *local, void *remote) "completions %s (%" PRId64 ") left %d, block %" PRIu64 ", chunk: %" PRIu64 " %p %p" -qemu_rdma_poll_other(const char *compstr, int64_t comp, int left) "other completion %s (%" PRId64 ") received left %d" +qemu_rdma_poll_recv(int64_t comp, int64_t id, int sent) "completion %" PRId64 " received (%" PRId64 ") left %d" +qemu_rdma_poll_write(int64_t comp, int left, uint64_t block, uint64_t chunk, void *local, void *remote) "completions %" PRId64 " left %d, block %" PRIu64 ", chunk: %" PRIu64 " %p %p" +qemu_rdma_poll_other(int64_t comp, int left) "other completion %" PRId64 " received left %d" qemu_rdma_post_send_control(const char *desc) "CONTROL: sending %s.." qemu_rdma_register_and_get_keys(uint64_t len, void *start) "Registering %" PRIu64 " bytes @ %p" qemu_rdma_register_odp_mr(const char *name) "Try to register On-Demand Paging memory region: %s" From 87a24ca3f2054d1b3268ceb141751a1fff32cc9c Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Thu, 28 Sep 2023 15:19:31 +0200 Subject: [PATCH 0456/1077] migration/rdma: Consistently use uint64_t for work request IDs We use int instead of uint64_t in a few places. Change them to uint64_t. This cleans up a comparison of signed qemu_rdma_block_for_wrid() parameter @wrid_requested with unsigned @wr_id. Harmless, because the actual arguments are non-negative enumeration constants. Signed-off-by: Markus Armbruster Reviewed-by: Fabiano Rosas Reviewed-by: Li Zhijian Reviewed-by: Juan Quintela Signed-off-by: Juan Quintela Message-ID: <20230928132019.2544702-6-armbru@redhat.com> --- migration/rdma.c | 7 ++++--- migration/trace-events | 8 ++++---- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/migration/rdma.c b/migration/rdma.c index 8f297c9e46..d1e727f30b 100644 --- a/migration/rdma.c +++ b/migration/rdma.c @@ -1599,13 +1599,13 @@ static int qemu_rdma_wait_comp_channel(RDMAContext *rdma, return rdma->error_state; } -static struct ibv_comp_channel *to_channel(RDMAContext *rdma, int wrid) +static struct ibv_comp_channel *to_channel(RDMAContext *rdma, uint64_t wrid) { return wrid < RDMA_WRID_RECV_CONTROL ? rdma->send_comp_channel : rdma->recv_comp_channel; } -static struct ibv_cq *to_cq(RDMAContext *rdma, int wrid) +static struct ibv_cq *to_cq(RDMAContext *rdma, uint64_t wrid) { return wrid < RDMA_WRID_RECV_CONTROL ? rdma->send_cq : rdma->recv_cq; } @@ -1623,7 +1623,8 @@ static struct ibv_cq *to_cq(RDMAContext *rdma, int wrid) * completions only need to be recorded, but do not actually * need further processing. */ -static int qemu_rdma_block_for_wrid(RDMAContext *rdma, int wrid_requested, +static int qemu_rdma_block_for_wrid(RDMAContext *rdma, + uint64_t wrid_requested, uint32_t *byte_len) { int num_cq_events = 0, ret = 0; diff --git a/migration/trace-events b/migration/trace-events index 19f9ee7c6d..6a50994402 100644 --- a/migration/trace-events +++ b/migration/trace-events @@ -208,7 +208,7 @@ qemu_rdma_accept_incoming_migration(void) "" qemu_rdma_accept_incoming_migration_accepted(void) "" qemu_rdma_accept_pin_state(bool pin) "%d" qemu_rdma_accept_pin_verbsc(void *verbs) "Verbs context after listen: %p" -qemu_rdma_block_for_wrid_miss(int wcomp, uint64_t req) "A Wanted wrid %d but got %" PRIu64 +qemu_rdma_block_for_wrid_miss(uint64_t wcomp, uint64_t req) "A Wanted wrid %" PRIu64 " but got %" PRIu64 qemu_rdma_cleanup_disconnect(void) "" qemu_rdma_close(void) "" qemu_rdma_connect_pin_all_requested(void) "" @@ -222,9 +222,9 @@ qemu_rdma_exchange_send_waiting(const char *desc) "Waiting for response %s" qemu_rdma_exchange_send_received(const char *desc) "Response %s received." qemu_rdma_fill(size_t control_len, size_t size) "RDMA %zd of %zd bytes already in buffer" qemu_rdma_init_ram_blocks(int blocks) "Allocated %d local ram block structures" -qemu_rdma_poll_recv(int64_t comp, int64_t id, int sent) "completion %" PRId64 " received (%" PRId64 ") left %d" -qemu_rdma_poll_write(int64_t comp, int left, uint64_t block, uint64_t chunk, void *local, void *remote) "completions %" PRId64 " left %d, block %" PRIu64 ", chunk: %" PRIu64 " %p %p" -qemu_rdma_poll_other(int64_t comp, int left) "other completion %" PRId64 " received left %d" +qemu_rdma_poll_recv(uint64_t comp, int64_t id, int sent) "completion %" PRIu64 " received (%" PRId64 ") left %d" +qemu_rdma_poll_write(uint64_t comp, int left, uint64_t block, uint64_t chunk, void *local, void *remote) "completions %" PRIu64 " left %d, block %" PRIu64 ", chunk: %" PRIu64 " %p %p" +qemu_rdma_poll_other(uint64_t comp, int left) "other completion %" PRIu64 " received left %d" qemu_rdma_post_send_control(const char *desc) "CONTROL: sending %s.." qemu_rdma_register_and_get_keys(uint64_t len, void *start) "Registering %" PRIu64 " bytes @ %p" qemu_rdma_register_odp_mr(const char *name) "Try to register On-Demand Paging memory region: %s" From 25352b371b37b038d50b75ec0a3557e77f1d74e3 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Thu, 28 Sep 2023 15:19:32 +0200 Subject: [PATCH 0457/1077] migration/rdma: Fix unwanted integer truncation qio_channel_rdma_readv() assigns the size_t value of qemu_rdma_fill() to an int variable before it adds it to @done / subtracts it from @want, both size_t. Truncation when qemu_rdma_fill() copies more than INT_MAX bytes. Seems vanishingly unlikely, but needs fixing all the same. Fixes: 6ddd2d76ca6f (migration: convert RDMA to use QIOChannel interface) Signed-off-by: Markus Armbruster Reviewed-by: Fabiano Rosas Reviewed-by: Juan Quintela Signed-off-by: Juan Quintela Message-ID: <20230928132019.2544702-7-armbru@redhat.com> --- migration/rdma.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/migration/rdma.c b/migration/rdma.c index d1e727f30b..ff8e475f59 100644 --- a/migration/rdma.c +++ b/migration/rdma.c @@ -2871,7 +2871,7 @@ static ssize_t qio_channel_rdma_readv(QIOChannel *ioc, RDMAControlHeader head; int ret = 0; ssize_t i; - size_t done = 0; + size_t done = 0, len; RCU_READ_LOCK_GUARD(); rdma = qatomic_rcu_read(&rioc->rdmain); @@ -2892,9 +2892,9 @@ static ssize_t qio_channel_rdma_readv(QIOChannel *ioc, * were given and dish out the bytes until we run * out of bytes. */ - ret = qemu_rdma_fill(rdma, data, want, 0); - done += ret; - want -= ret; + len = qemu_rdma_fill(rdma, data, want, 0); + done += len; + want -= len; /* Got what we needed, so go to next iovec */ if (want == 0) { continue; @@ -2921,9 +2921,9 @@ static ssize_t qio_channel_rdma_readv(QIOChannel *ioc, /* * SEND was received with new bytes, now try again. */ - ret = qemu_rdma_fill(rdma, data, want, 0); - done += ret; - want -= ret; + len = qemu_rdma_fill(rdma, data, want, 0); + done += len; + want -= len; /* Still didn't get enough, so lets just return */ if (want) { From 8ff58b05a3f6294731b9defb1d821e2f8703c8f1 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Thu, 28 Sep 2023 15:19:33 +0200 Subject: [PATCH 0458/1077] migration/rdma: Clean up two more harmless signed vs. unsigned issues qemu_rdma_exchange_get_response() compares int parameter @expecting with uint32_t head->type. Actual arguments are non-negative enumeration constants, RDMAControlHeader uint32_t member type, or qemu_rdma_exchange_recv() int parameter expecting. Actual arguments for the latter are non-negative enumeration constants. Change both parameters to uint32_t. In qio_channel_rdma_readv(), loop control variable @i is ssize_t, and counts from 0 up to @niov, which is size_t. Change @i to size_t. While there, make qio_channel_rdma_readv() and qio_channel_rdma_writev() more consistent: change the former's @done to ssize_t, and delete the latter's useless initialization of @len. Signed-off-by: Markus Armbruster Reviewed-by: Fabiano Rosas Reviewed-by: Juan Quintela Signed-off-by: Juan Quintela Message-ID: <20230928132019.2544702-8-armbru@redhat.com> --- migration/rdma.c | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/migration/rdma.c b/migration/rdma.c index ff8e475f59..1aac50b0de 100644 --- a/migration/rdma.c +++ b/migration/rdma.c @@ -1801,7 +1801,7 @@ static int qemu_rdma_post_recv_control(RDMAContext *rdma, int idx) * Block and wait for a RECV control channel message to arrive. */ static int qemu_rdma_exchange_get_response(RDMAContext *rdma, - RDMAControlHeader *head, int expecting, int idx) + RDMAControlHeader *head, uint32_t expecting, int idx) { uint32_t byte_len; int ret = qemu_rdma_block_for_wrid(rdma, RDMA_WRID_RECV_CONTROL + idx, @@ -1961,7 +1961,7 @@ static int qemu_rdma_exchange_send(RDMAContext *rdma, RDMAControlHeader *head, * control-channel message. */ static int qemu_rdma_exchange_recv(RDMAContext *rdma, RDMAControlHeader *head, - int expecting) + uint32_t expecting) { RDMAControlHeader ready = { .len = 0, @@ -2784,8 +2784,7 @@ static ssize_t qio_channel_rdma_writev(QIOChannel *ioc, RDMAContext *rdma; int ret; ssize_t done = 0; - size_t i; - size_t len = 0; + size_t i, len; RCU_READ_LOCK_GUARD(); rdma = qatomic_rcu_read(&rioc->rdmaout); @@ -2870,8 +2869,8 @@ static ssize_t qio_channel_rdma_readv(QIOChannel *ioc, RDMAContext *rdma; RDMAControlHeader head; int ret = 0; - ssize_t i; - size_t done = 0, len; + ssize_t done = 0; + size_t i, len; RCU_READ_LOCK_GUARD(); rdma = qatomic_rcu_read(&rioc->rdmain); From 36cc822d857ddf151a32a9f6fe851209ef4f089d Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Thu, 28 Sep 2023 15:19:34 +0200 Subject: [PATCH 0459/1077] migration/rdma: Give qio_channel_rdma_source_funcs internal linkage Signed-off-by: Markus Armbruster Reviewed-by: Fabiano Rosas Reviewed-by: Li Zhijian Reviewed-by: Juan Quintela Signed-off-by: Juan Quintela Message-ID: <20230928132019.2544702-9-armbru@redhat.com> --- migration/rdma.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/migration/rdma.c b/migration/rdma.c index 1aac50b0de..1159f990af 100644 --- a/migration/rdma.c +++ b/migration/rdma.c @@ -3075,7 +3075,7 @@ qio_channel_rdma_source_finalize(GSource *source) object_unref(OBJECT(ssource->rioc)); } -GSourceFuncs qio_channel_rdma_source_funcs = { +static GSourceFuncs qio_channel_rdma_source_funcs = { qio_channel_rdma_source_prepare, qio_channel_rdma_source_check, qio_channel_rdma_source_dispatch, From 9a6afb11705b5bd6332289d226fae783ffcc0e1d Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Thu, 28 Sep 2023 15:19:35 +0200 Subject: [PATCH 0460/1077] migration/rdma: Fix qemu_rdma_accept() to return failure on errors qemu_rdma_accept() returns 0 in some cases even when it didn't complete its job due to errors. Impact is not obvious. I figure the caller will soon fail again with a misleading error message. Fix it to return -1 on any failure. Signed-off-by: Markus Armbruster Reviewed-by: Fabiano Rosas Reviewed-by: Li Zhijian Reviewed-by: Juan Quintela Signed-off-by: Juan Quintela Message-ID: <20230928132019.2544702-10-armbru@redhat.com> --- migration/rdma.c | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/migration/rdma.c b/migration/rdma.c index 1159f990af..8fd1b314b5 100644 --- a/migration/rdma.c +++ b/migration/rdma.c @@ -3360,6 +3360,7 @@ static int qemu_rdma_accept(RDMAContext *rdma) if (cm_event->event != RDMA_CM_EVENT_CONNECT_REQUEST) { rdma_ack_cm_event(cm_event); + ret = -1; goto err_rdma_dest_wait; } @@ -3372,6 +3373,7 @@ static int qemu_rdma_accept(RDMAContext *rdma) rdma_return_path = qemu_rdma_data_init(rdma->host_port, NULL); if (rdma_return_path == NULL) { rdma_ack_cm_event(cm_event); + ret = -1; goto err_rdma_dest_wait; } @@ -3383,10 +3385,11 @@ static int qemu_rdma_accept(RDMAContext *rdma) network_to_caps(&cap); if (cap.version < 1 || cap.version > RDMA_CONTROL_VERSION_CURRENT) { - error_report("Unknown source RDMA version: %d, bailing...", - cap.version); - rdma_ack_cm_event(cm_event); - goto err_rdma_dest_wait; + error_report("Unknown source RDMA version: %d, bailing...", + cap.version); + rdma_ack_cm_event(cm_event); + ret = -1; + goto err_rdma_dest_wait; } /* @@ -3416,9 +3419,10 @@ static int qemu_rdma_accept(RDMAContext *rdma) if (!rdma->verbs) { rdma->verbs = verbs; } else if (rdma->verbs != verbs) { - error_report("ibv context not matching %p, %p!", rdma->verbs, - verbs); - goto err_rdma_dest_wait; + error_report("ibv context not matching %p, %p!", rdma->verbs, + verbs); + ret = -1; + goto err_rdma_dest_wait; } qemu_rdma_dump_id("dest_init", verbs); @@ -3475,6 +3479,7 @@ static int qemu_rdma_accept(RDMAContext *rdma) if (cm_event->event != RDMA_CM_EVENT_ESTABLISHED) { error_report("rdma_accept not event established"); rdma_ack_cm_event(cm_event); + ret = -1; goto err_rdma_dest_wait; } From 3c03f21cb5ee0ded870987ea32217297f639afa0 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Thu, 28 Sep 2023 15:19:36 +0200 Subject: [PATCH 0461/1077] migration/rdma: Put @errp parameter last include/qapi/error.h demands: * - Functions that use Error to report errors have an Error **errp * parameter. It should be the last parameter, except for functions * taking variable arguments. qemu_rdma_connect() does not conform. Clean it up. Signed-off-by: Markus Armbruster Reviewed-by: Fabiano Rosas Reviewed-by: Li Zhijian Reviewed-by: Juan Quintela Signed-off-by: Juan Quintela Message-ID: <20230928132019.2544702-11-armbru@redhat.com> --- migration/rdma.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/migration/rdma.c b/migration/rdma.c index 8fd1b314b5..bc6d8248f2 100644 --- a/migration/rdma.c +++ b/migration/rdma.c @@ -2552,7 +2552,8 @@ static int qemu_get_cm_event_timeout(RDMAContext *rdma, } } -static int qemu_rdma_connect(RDMAContext *rdma, Error **errp, bool return_path) +static int qemu_rdma_connect(RDMAContext *rdma, bool return_path, + Error **errp) { RDMACapabilities cap = { .version = RDMA_CONTROL_VERSION_CURRENT, @@ -4183,7 +4184,7 @@ void rdma_start_outgoing_migration(void *opaque, } trace_rdma_start_outgoing_migration_after_rdma_source_init(); - ret = qemu_rdma_connect(rdma, errp, false); + ret = qemu_rdma_connect(rdma, false, errp); if (ret) { goto err; @@ -4204,7 +4205,7 @@ void rdma_start_outgoing_migration(void *opaque, goto return_path_err; } - ret = qemu_rdma_connect(rdma_return_path, errp, true); + ret = qemu_rdma_connect(rdma_return_path, true, errp); if (ret) { goto return_path_err; From b16defbbfe3ffe9601edda4f7886a295dea8f408 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Thu, 28 Sep 2023 15:19:37 +0200 Subject: [PATCH 0462/1077] migration/rdma: Eliminate error_propagate() When all we do with an Error we receive into a local variable is propagating to somewhere else, we can just as well receive it there right away. Signed-off-by: Markus Armbruster Reviewed-by: Fabiano Rosas Reviewed-by: Li Zhijian Reviewed-by: Juan Quintela Signed-off-by: Juan Quintela Message-ID: <20230928132019.2544702-12-armbru@redhat.com> --- migration/rdma.c | 19 +++++++------------ 1 file changed, 7 insertions(+), 12 deletions(-) diff --git a/migration/rdma.c b/migration/rdma.c index bc6d8248f2..c858d3fbe4 100644 --- a/migration/rdma.c +++ b/migration/rdma.c @@ -2465,7 +2465,6 @@ static void qemu_rdma_cleanup(RDMAContext *rdma) static int qemu_rdma_source_init(RDMAContext *rdma, bool pin_all, Error **errp) { int ret, idx; - Error *local_err = NULL, **temp = &local_err; /* * Will be validated against destination's actual capabilities @@ -2473,14 +2472,14 @@ static int qemu_rdma_source_init(RDMAContext *rdma, bool pin_all, Error **errp) */ rdma->pin_all = pin_all; - ret = qemu_rdma_resolve_host(rdma, temp); + ret = qemu_rdma_resolve_host(rdma, errp); if (ret) { goto err_rdma_source_init; } ret = qemu_rdma_alloc_pd_cq(rdma); if (ret) { - ERROR(temp, "rdma migration: error allocating pd and cq! Your mlock()" + ERROR(errp, "rdma migration: error allocating pd and cq! Your mlock()" " limits may be too low. Please check $ ulimit -a # and " "search for 'ulimit -l' in the output"); goto err_rdma_source_init; @@ -2488,13 +2487,13 @@ static int qemu_rdma_source_init(RDMAContext *rdma, bool pin_all, Error **errp) ret = qemu_rdma_alloc_qp(rdma); if (ret) { - ERROR(temp, "rdma migration: error allocating qp!"); + ERROR(errp, "rdma migration: error allocating qp!"); goto err_rdma_source_init; } ret = qemu_rdma_init_ram_blocks(rdma); if (ret) { - ERROR(temp, "rdma migration: error initializing ram blocks!"); + ERROR(errp, "rdma migration: error initializing ram blocks!"); goto err_rdma_source_init; } @@ -2509,7 +2508,7 @@ static int qemu_rdma_source_init(RDMAContext *rdma, bool pin_all, Error **errp) for (idx = 0; idx < RDMA_WRID_MAX; idx++) { ret = qemu_rdma_reg_control(rdma, idx); if (ret) { - ERROR(temp, "rdma migration: error registering %d control!", + ERROR(errp, "rdma migration: error registering %d control!", idx); goto err_rdma_source_init; } @@ -2518,7 +2517,6 @@ static int qemu_rdma_source_init(RDMAContext *rdma, bool pin_all, Error **errp) return 0; err_rdma_source_init: - error_propagate(errp, local_err); qemu_rdma_cleanup(rdma); return -1; } @@ -4111,7 +4109,6 @@ void rdma_start_incoming_migration(const char *host_port, Error **errp) { int ret; RDMAContext *rdma; - Error *local_err = NULL; trace_rdma_start_incoming_migration(); @@ -4121,13 +4118,12 @@ void rdma_start_incoming_migration(const char *host_port, Error **errp) return; } - rdma = qemu_rdma_data_init(host_port, &local_err); + rdma = qemu_rdma_data_init(host_port, errp); if (rdma == NULL) { goto err; } - ret = qemu_rdma_dest_init(rdma, &local_err); - + ret = qemu_rdma_dest_init(rdma, errp); if (ret) { goto err; } @@ -4150,7 +4146,6 @@ void rdma_start_incoming_migration(const char *host_port, Error **errp) cleanup_rdma: qemu_rdma_cleanup(rdma); err: - error_propagate(errp, local_err); if (rdma) { g_free(rdma->host); g_free(rdma->host_port); From 0610d7a1d84f97e764474f5f5b65019640f73f4f Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Thu, 28 Sep 2023 15:19:38 +0200 Subject: [PATCH 0463/1077] migration/rdma: Drop rdma_add_block() error handling rdma_add_block() can't fail. Return void, and drop the unreachable error handling. Signed-off-by: Markus Armbruster Reviewed-by: Fabiano Rosas Reviewed-by: Li Zhijian Reviewed-by: Juan Quintela Signed-off-by: Juan Quintela Message-ID: <20230928132019.2544702-13-armbru@redhat.com> --- migration/rdma.c | 30 +++++++++--------------------- 1 file changed, 9 insertions(+), 21 deletions(-) diff --git a/migration/rdma.c b/migration/rdma.c index c858d3fbe4..466725dbf0 100644 --- a/migration/rdma.c +++ b/migration/rdma.c @@ -559,9 +559,9 @@ static inline uint8_t *ram_chunk_end(const RDMALocalBlock *rdma_ram_block, return result; } -static int rdma_add_block(RDMAContext *rdma, const char *block_name, - void *host_addr, - ram_addr_t block_offset, uint64_t length) +static void rdma_add_block(RDMAContext *rdma, const char *block_name, + void *host_addr, + ram_addr_t block_offset, uint64_t length) { RDMALocalBlocks *local = &rdma->local_ram_blocks; RDMALocalBlock *block; @@ -615,8 +615,6 @@ static int rdma_add_block(RDMAContext *rdma, const char *block_name, block->nb_chunks); local->nb_blocks++; - - return 0; } /* @@ -630,7 +628,8 @@ static int qemu_rdma_init_one_block(RAMBlock *rb, void *opaque) void *host_addr = qemu_ram_get_host_addr(rb); ram_addr_t block_offset = qemu_ram_get_offset(rb); ram_addr_t length = qemu_ram_get_used_length(rb); - return rdma_add_block(opaque, block_name, host_addr, block_offset, length); + rdma_add_block(opaque, block_name, host_addr, block_offset, length); + return 0; } /* @@ -638,7 +637,7 @@ static int qemu_rdma_init_one_block(RAMBlock *rb, void *opaque) * identify chunk boundaries inside each RAMBlock and also be referenced * during dynamic page registration. */ -static int qemu_rdma_init_ram_blocks(RDMAContext *rdma) +static void qemu_rdma_init_ram_blocks(RDMAContext *rdma) { RDMALocalBlocks *local = &rdma->local_ram_blocks; int ret; @@ -646,14 +645,11 @@ static int qemu_rdma_init_ram_blocks(RDMAContext *rdma) assert(rdma->blockmap == NULL); memset(local, 0, sizeof *local); ret = foreach_not_ignored_block(qemu_rdma_init_one_block, rdma); - if (ret) { - return ret; - } + assert(!ret); trace_qemu_rdma_init_ram_blocks(local->nb_blocks); rdma->dest_blocks = g_new0(RDMADestBlock, rdma->local_ram_blocks.nb_blocks); local->init = true; - return 0; } /* @@ -2491,11 +2487,7 @@ static int qemu_rdma_source_init(RDMAContext *rdma, bool pin_all, Error **errp) goto err_rdma_source_init; } - ret = qemu_rdma_init_ram_blocks(rdma); - if (ret) { - ERROR(errp, "rdma migration: error initializing ram blocks!"); - goto err_rdma_source_init; - } + qemu_rdma_init_ram_blocks(rdma); /* Build the hash that maps from offset to RAMBlock */ rdma->blockmap = g_hash_table_new(g_direct_hash, g_direct_equal); @@ -3438,11 +3430,7 @@ static int qemu_rdma_accept(RDMAContext *rdma) goto err_rdma_dest_wait; } - ret = qemu_rdma_init_ram_blocks(rdma); - if (ret) { - error_report("rdma migration: error initializing ram blocks!"); - goto err_rdma_dest_wait; - } + qemu_rdma_init_ram_blocks(rdma); for (idx = 0; idx < RDMA_WRID_MAX; idx++) { ret = qemu_rdma_reg_control(rdma, idx); From 87e6bdabf033b681370d634226f1416bfcd9478a Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Thu, 28 Sep 2023 15:19:39 +0200 Subject: [PATCH 0464/1077] migration/rdma: Drop qemu_rdma_search_ram_block() error handling qemu_rdma_search_ram_block() can't fail. Return void, and drop the unreachable error handling. Signed-off-by: Markus Armbruster Reviewed-by: Li Zhijian Reviewed-by: Juan Quintela Signed-off-by: Juan Quintela Message-ID: <20230928132019.2544702-14-armbru@redhat.com> --- migration/rdma.c | 24 ++++++++---------------- 1 file changed, 8 insertions(+), 16 deletions(-) diff --git a/migration/rdma.c b/migration/rdma.c index 466725dbf0..b412dad542 100644 --- a/migration/rdma.c +++ b/migration/rdma.c @@ -1231,15 +1231,13 @@ static int qemu_rdma_reg_whole_ram_blocks(RDMAContext *rdma) * * Once the block is found, also identify which 'chunk' within that * block that the page belongs to. - * - * This search cannot fail or the migration will fail. */ -static int qemu_rdma_search_ram_block(RDMAContext *rdma, - uintptr_t block_offset, - uint64_t offset, - uint64_t length, - uint64_t *block_index, - uint64_t *chunk_index) +static void qemu_rdma_search_ram_block(RDMAContext *rdma, + uintptr_t block_offset, + uint64_t offset, + uint64_t length, + uint64_t *block_index, + uint64_t *chunk_index) { uint64_t current_addr = block_offset + offset; RDMALocalBlock *block = g_hash_table_lookup(rdma->blockmap, @@ -1251,8 +1249,6 @@ static int qemu_rdma_search_ram_block(RDMAContext *rdma, *block_index = block->index; *chunk_index = ram_chunk_index(block->local_host_addr, block->local_host_addr + (current_addr - block->offset)); - - return 0; } /* @@ -2341,12 +2337,8 @@ static int qemu_rdma_write(RDMAContext *rdma, rdma->current_length = 0; rdma->current_addr = current_addr; - ret = qemu_rdma_search_ram_block(rdma, block_offset, - offset, len, &index, &chunk); - if (ret) { - error_report("ram block search failed"); - return ret; - } + qemu_rdma_search_ram_block(rdma, block_offset, + offset, len, &index, &chunk); rdma->current_index = index; rdma->current_chunk = chunk; } From 6a3792d78dab35002120cd5aa468103c38cf9590 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Thu, 28 Sep 2023 15:19:40 +0200 Subject: [PATCH 0465/1077] migration/rdma: Make qemu_rdma_buffer_mergeable() return bool qemu_rdma_buffer_mergeable() is semantically a predicate. It returns int 0 or 1. Return bool instead, and fix the function name's spelling. Signed-off-by: Markus Armbruster Reviewed-by: Fabiano Rosas Reviewed-by: Li Zhijian Reviewed-by: Juan Quintela Signed-off-by: Juan Quintela Message-ID: <20230928132019.2544702-15-armbru@redhat.com> --- migration/rdma.c | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/migration/rdma.c b/migration/rdma.c index b412dad542..2e62d2cd0a 100644 --- a/migration/rdma.c +++ b/migration/rdma.c @@ -2264,7 +2264,7 @@ static int qemu_rdma_write_flush(RDMAContext *rdma) return 0; } -static inline int qemu_rdma_buffer_mergable(RDMAContext *rdma, +static inline bool qemu_rdma_buffer_mergeable(RDMAContext *rdma, uint64_t offset, uint64_t len) { RDMALocalBlock *block; @@ -2272,11 +2272,11 @@ static inline int qemu_rdma_buffer_mergable(RDMAContext *rdma, uint8_t *chunk_end; if (rdma->current_index < 0) { - return 0; + return false; } if (rdma->current_chunk < 0) { - return 0; + return false; } block = &(rdma->local_ram_blocks.block[rdma->current_index]); @@ -2284,29 +2284,29 @@ static inline int qemu_rdma_buffer_mergable(RDMAContext *rdma, chunk_end = ram_chunk_end(block, rdma->current_chunk); if (rdma->current_length == 0) { - return 0; + return false; } /* * Only merge into chunk sequentially. */ if (offset != (rdma->current_addr + rdma->current_length)) { - return 0; + return false; } if (offset < block->offset) { - return 0; + return false; } if ((offset + len) > (block->offset + block->length)) { - return 0; + return false; } if ((host_addr + len) > chunk_end) { - return 0; + return false; } - return 1; + return true; } /* @@ -2329,7 +2329,7 @@ static int qemu_rdma_write(RDMAContext *rdma, int ret; /* If we cannot merge it, we flush the current buffer first. */ - if (!qemu_rdma_buffer_mergable(rdma, current_addr, len)) { + if (!qemu_rdma_buffer_mergeable(rdma, current_addr, len)) { ret = qemu_rdma_write_flush(rdma); if (ret) { return ret; From 89997ac31839cde1746bf5d8d830e1d2db595e98 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Thu, 28 Sep 2023 15:19:41 +0200 Subject: [PATCH 0466/1077] migration/rdma: Use bool for two RDMAContext flags @error_reported and @received_error are flags. The latter is even assigned bool true. Change them from int to bool. Signed-off-by: Markus Armbruster Reviewed-by: Fabiano Rosas Reviewed-by: Li Zhijian Reviewed-by: Juan Quintela Signed-off-by: Juan Quintela Message-ID: <20230928132019.2544702-16-armbru@redhat.com> --- migration/rdma.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/migration/rdma.c b/migration/rdma.c index 2e62d2cd0a..dffca30382 100644 --- a/migration/rdma.c +++ b/migration/rdma.c @@ -91,7 +91,7 @@ static uint32_t known_capabilities = RDMA_CAPABILITY_PIN_ALL; if (!rdma->error_reported) { \ error_report("RDMA is in an error state waiting migration" \ " to abort!"); \ - rdma->error_reported = 1; \ + rdma->error_reported = true; \ } \ return rdma->error_state; \ } \ @@ -365,8 +365,8 @@ typedef struct RDMAContext { * and remember the error state. */ int error_state; - int error_reported; - int received_error; + bool error_reported; + bool received_error; /* * Description of ram blocks used throughout the code. From 0bc2604508462184fa0ffb9a6c62c6f9a40a428d Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Thu, 28 Sep 2023 15:19:42 +0200 Subject: [PATCH 0467/1077] migration/rdma: Fix or document problematic uses of errno We use errno after calling Libibverbs functions that are not documented to set errno (manual page does not mention errno), or where the documentation is unclear ("returns [...] the value of errno on failure"). While this could be read as "sets errno and returns it", a glance at the source code[*] kills that hope: static inline int ibv_post_send(struct ibv_qp *qp, struct ibv_send_wr *wr, struct ibv_send_wr **bad_wr) { return qp->context->ops.post_send(qp, wr, bad_wr); } The callback can be static int mana_post_send(struct ibv_qp *ibqp, struct ibv_send_wr *wr, struct ibv_send_wr **bad) { /* This version of driver supports RAW QP only. * Posting WR is done directly in the application. */ return EOPNOTSUPP; } Neither of them touches errno. One of these errno uses is easy to fix, so do that now. Several more will go away later in the series; add temporary FIXME commments. Three will remain; add TODO comments. TODO, not FIXME, because the bug might be in Libibverbs documentation. [*] https://github.com/linux-rdma/rdma-core.git commit 55fa316b4b18f258d8ac1ceb4aa5a7a35b094dcf Signed-off-by: Markus Armbruster Reviewed-by: Juan Quintela Signed-off-by: Juan Quintela Message-ID: <20230928132019.2544702-17-armbru@redhat.com> --- migration/rdma.c | 45 +++++++++++++++++++++++++++++++++++++++------ 1 file changed, 39 insertions(+), 6 deletions(-) diff --git a/migration/rdma.c b/migration/rdma.c index dffca30382..35b0129ae6 100644 --- a/migration/rdma.c +++ b/migration/rdma.c @@ -853,6 +853,12 @@ static int qemu_rdma_broken_ipv6_kernel(struct ibv_context *verbs, Error **errp) for (x = 0; x < num_devices; x++) { verbs = ibv_open_device(dev_list[x]); + /* + * ibv_open_device() is not documented to set errno. If + * it does, it's somebody else's doc bug. If it doesn't, + * the use of errno below is wrong. + * TODO Find out whether ibv_open_device() sets errno. + */ if (!verbs) { if (errno == EPERM) { continue; @@ -1162,11 +1168,7 @@ static void qemu_rdma_advise_prefetch_mr(struct ibv_pd *pd, uint64_t addr, ret = ibv_advise_mr(pd, advice, IBV_ADVISE_MR_FLAG_FLUSH, &sg_list, 1); /* ignore the error */ - if (ret) { - trace_qemu_rdma_advise_mr(name, len, addr, strerror(errno)); - } else { - trace_qemu_rdma_advise_mr(name, len, addr, "successed"); - } + trace_qemu_rdma_advise_mr(name, len, addr, strerror(ret)); #endif } @@ -1183,7 +1185,12 @@ static int qemu_rdma_reg_whole_ram_blocks(RDMAContext *rdma) local->block[i].local_host_addr, local->block[i].length, access ); - + /* + * ibv_reg_mr() is not documented to set errno. If it does, + * it's somebody else's doc bug. If it doesn't, the use of + * errno below is wrong. + * TODO Find out whether ibv_reg_mr() sets errno. + */ if (!local->block[i].mr && errno == ENOTSUP && rdma_support_odp(rdma->verbs)) { access |= IBV_ACCESS_ON_DEMAND; @@ -1291,6 +1298,12 @@ static int qemu_rdma_register_and_get_keys(RDMAContext *rdma, trace_qemu_rdma_register_and_get_keys(len, chunk_start); block->pmr[chunk] = ibv_reg_mr(rdma->pd, chunk_start, len, access); + /* + * ibv_reg_mr() is not documented to set errno. If it does, + * it's somebody else's doc bug. If it doesn't, the use of + * errno below is wrong. + * TODO Find out whether ibv_reg_mr() sets errno. + */ if (!block->pmr[chunk] && errno == ENOTSUP && rdma_support_odp(rdma->verbs)) { access |= IBV_ACCESS_ON_DEMAND; @@ -1408,6 +1421,11 @@ static int qemu_rdma_unregister_waiting(RDMAContext *rdma) block->remote_keys[chunk] = 0; if (ret != 0) { + /* + * FIXME perror() is problematic, bcause ibv_dereg_mr() is + * not documented to set errno. Will go away later in + * this series. + */ perror("unregistration chunk failed"); return -ret; } @@ -1658,6 +1676,11 @@ static int qemu_rdma_block_for_wrid(RDMAContext *rdma, ret = ibv_get_cq_event(ch, &cq, &cq_ctx); if (ret) { + /* + * FIXME perror() is problematic, because ibv_reg_mr() is + * not documented to set errno. Will go away later in + * this series. + */ perror("ibv_get_cq_event"); goto err_block_for_wrid; } @@ -2210,6 +2233,11 @@ retry: goto retry; } else if (ret > 0) { + /* + * FIXME perror() is problematic, because whether + * ibv_post_send() sets errno is unclear. Will go away later + * in this series. + */ perror("rdma migration: post rdma write failed"); return -ret; } @@ -2579,6 +2607,11 @@ static int qemu_rdma_connect(RDMAContext *rdma, bool return_path, ret = rdma_get_cm_event(rdma->channel, &cm_event); } if (ret) { + /* + * FIXME perror() is wrong, because + * qemu_get_cm_event_timeout() can fail without setting errno. + * Will go away later in this series. + */ perror("rdma_get_cm_event after rdma_connect"); ERROR(errp, "connecting to destination!"); goto err_rdma_source_connect; From 1b6e1da6e7505f9b152ca2d0be2059eeb7e55708 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Thu, 28 Sep 2023 15:19:43 +0200 Subject: [PATCH 0468/1077] migration/rdma: Ditch useless numeric error codes in error messages Several error messages include numeric error codes returned by failed functions: * ibv_poll_cq() returns an unspecified negative value. Useless. * rdma_accept and rdma_get_cm_event() return -1. Useless. * qemu_rdma_poll() returns either -1 or an unspecified negative value. Useless. * qemu_rdma_block_for_wrid(), qemu_rdma_write_flush(), qemu_rdma_exchange_send(), qemu_rdma_exchange_recv(), qemu_rdma_write() return a negative value that may or may not be an errno value. While reporting human-readable errno information (which a number is not) can be useful, reporting an error code that may or may not be an errno value is useless. Drop these error codes from the error messages. Signed-off-by: Markus Armbruster Reviewed-by: Fabiano Rosas Reviewed-by: Li Zhijian Reviewed-by: Juan Quintela Signed-off-by: Juan Quintela Message-ID: <20230928132019.2544702-18-armbru@redhat.com> --- migration/rdma.c | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/migration/rdma.c b/migration/rdma.c index 35b0129ae6..c4197c6437 100644 --- a/migration/rdma.c +++ b/migration/rdma.c @@ -1476,7 +1476,7 @@ static int qemu_rdma_poll(RDMAContext *rdma, struct ibv_cq *cq, } if (ret < 0) { - error_report("ibv_poll_cq return %d", ret); + error_report("ibv_poll_cq failed"); return ret; } @@ -2226,7 +2226,7 @@ retry: ret = qemu_rdma_block_for_wrid(rdma, RDMA_WRID_RDMA_WRITE, NULL); if (ret < 0) { error_report("rdma migration: failed to make " - "room in full send queue! %d", ret); + "room in full send queue!"); return ret; } @@ -2819,7 +2819,7 @@ static ssize_t qio_channel_rdma_writev(QIOChannel *ioc, ret = qemu_rdma_write_flush(rdma); if (ret < 0) { rdma->error_state = ret; - error_setg(errp, "qemu_rdma_write_flush returned %d", ret); + error_setg(errp, "qemu_rdma_write_flush failed"); return -1; } @@ -2839,7 +2839,7 @@ static ssize_t qio_channel_rdma_writev(QIOChannel *ioc, if (ret < 0) { rdma->error_state = ret; - error_setg(errp, "qemu_rdma_exchange_send returned %d", ret); + error_setg(errp, "qemu_rdma_exchange_send failed"); return -1; } @@ -2929,7 +2929,7 @@ static ssize_t qio_channel_rdma_readv(QIOChannel *ioc, if (ret < 0) { rdma->error_state = ret; - error_setg(errp, "qemu_rdma_exchange_recv returned %d", ret); + error_setg(errp, "qemu_rdma_exchange_recv failed"); return -1; } @@ -3271,7 +3271,7 @@ static int qemu_rdma_save_page(QEMUFile *f, ram_addr_t block_offset, */ ret = qemu_rdma_write(rdma, block_offset, offset, size); if (ret < 0) { - error_report("rdma migration: write error! %d", ret); + error_report("rdma migration: write error"); goto err; } @@ -3287,7 +3287,7 @@ static int qemu_rdma_save_page(QEMUFile *f, ram_addr_t block_offset, ret = qemu_rdma_poll(rdma, rdma->recv_cq, &wr_id_in, NULL); if (ret < 0) { - error_report("rdma migration: polling error! %d", ret); + error_report("rdma migration: polling error"); goto err; } @@ -3303,7 +3303,7 @@ static int qemu_rdma_save_page(QEMUFile *f, ram_addr_t block_offset, ret = qemu_rdma_poll(rdma, rdma->send_cq, &wr_id_in, NULL); if (ret < 0) { - error_report("rdma migration: polling error! %d", ret); + error_report("rdma migration: polling error"); goto err; } @@ -3478,13 +3478,13 @@ static int qemu_rdma_accept(RDMAContext *rdma) ret = rdma_accept(rdma->cm_id, &conn_param); if (ret) { - error_report("rdma_accept returns %d", ret); + error_report("rdma_accept failed"); goto err_rdma_dest_wait; } ret = rdma_get_cm_event(rdma->channel, &cm_event); if (ret) { - error_report("rdma_accept get_cm_event failed %d", ret); + error_report("rdma_accept get_cm_event failed"); goto err_rdma_dest_wait; } From 8e262e0b3d41ade37354cf9fa28bcbba2e273caf Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Thu, 28 Sep 2023 15:19:44 +0200 Subject: [PATCH 0469/1077] migration/rdma: Fix io_writev(), io_readv() methods to obey contract QIOChannelClass methods qio_channel_rdma_readv() and qio_channel_rdma_writev() violate their method contract when rdma->error_state is non-zero: 1. They return whatever is in rdma->error_state then. Only -1 will be fine. -2 will be misinterpreted as "would block". Anything less than -2 isn't defined in the contract. A positive value would be misinterpreted as success, but I believe that's not actually possible. 2. They neglect to set an error then. If something up the call stack dereferences the error when failure is returned, it will crash. If it ignores the return value and checks the error instead, it will miss the error. Crap like this happens when return statements hide in macros, especially when their uses are far away from the definition. I elected not to investigate how callers are impacted. Expand the two bad macro uses, so we can set an error and return -1. The next commit will then get rid of the macro altogether. Signed-off-by: Markus Armbruster Reviewed-by: Fabiano Rosas Reviewed-by: Li Zhijian Reviewed-by: Juan Quintela Signed-off-by: Juan Quintela Message-ID: <20230928132019.2544702-19-armbru@redhat.com> --- migration/rdma.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/migration/rdma.c b/migration/rdma.c index c4197c6437..18be228e3b 100644 --- a/migration/rdma.c +++ b/migration/rdma.c @@ -2810,7 +2810,11 @@ static ssize_t qio_channel_rdma_writev(QIOChannel *ioc, return -1; } - CHECK_ERROR_STATE(); + if (rdma->error_state) { + error_setg(errp, + "RDMA is in an error state waiting migration to abort!"); + return -1; + } /* * Push out any writes that @@ -2896,7 +2900,11 @@ static ssize_t qio_channel_rdma_readv(QIOChannel *ioc, return -1; } - CHECK_ERROR_STATE(); + if (rdma->error_state) { + error_setg(errp, + "RDMA is in an error state waiting migration to abort!"); + return -1; + } for (i = 0; i < niov; i++) { size_t want = iov[i].iov_len; From de3e05e8b9c21dd70c34b744d1b14ec5f5707512 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Thu, 28 Sep 2023 15:19:45 +0200 Subject: [PATCH 0470/1077] migration/rdma: Replace dangerous macro CHECK_ERROR_STATE() Hiding return statements in macros is a bad idea. Use a function instead, and open code the return part. Signed-off-by: Markus Armbruster Reviewed-by: Fabiano Rosas Reviewed-by: Li Zhijian Reviewed-by: Juan Quintela Signed-off-by: Juan Quintela Message-ID: <20230928132019.2544702-20-armbru@redhat.com> --- migration/rdma.c | 43 +++++++++++++++++++++++++++---------------- 1 file changed, 27 insertions(+), 16 deletions(-) diff --git a/migration/rdma.c b/migration/rdma.c index 18be228e3b..30e2c817f2 100644 --- a/migration/rdma.c +++ b/migration/rdma.c @@ -85,18 +85,6 @@ */ static uint32_t known_capabilities = RDMA_CAPABILITY_PIN_ALL; -#define CHECK_ERROR_STATE() \ - do { \ - if (rdma->error_state) { \ - if (!rdma->error_reported) { \ - error_report("RDMA is in an error state waiting migration" \ - " to abort!"); \ - rdma->error_reported = true; \ - } \ - return rdma->error_state; \ - } \ - } while (0) - /* * A work request ID is 64-bits and we split up these bits * into 3 parts: @@ -451,6 +439,16 @@ typedef struct QEMU_PACKED { uint64_t chunks; /* how many sequential chunks to register */ } RDMARegister; +static int check_error_state(RDMAContext *rdma) +{ + if (rdma->error_state && !rdma->error_reported) { + error_report("RDMA is in an error state waiting migration" + " to abort!"); + rdma->error_reported = true; + } + return rdma->error_state; +} + static void register_to_network(RDMAContext *rdma, RDMARegister *reg) { RDMALocalBlock *local_block; @@ -3268,7 +3266,10 @@ static int qemu_rdma_save_page(QEMUFile *f, ram_addr_t block_offset, return -EIO; } - CHECK_ERROR_STATE(); + ret = check_error_state(rdma); + if (ret) { + return ret; + } qemu_fflush(f); @@ -3574,7 +3575,10 @@ static int qemu_rdma_registration_handle(QEMUFile *f) return -EIO; } - CHECK_ERROR_STATE(); + ret = check_error_state(rdma); + if (ret) { + return ret; + } local = &rdma->local_ram_blocks; do { @@ -3878,6 +3882,7 @@ static int qemu_rdma_registration_start(QEMUFile *f, { QIOChannelRDMA *rioc = QIO_CHANNEL_RDMA(qemu_file_get_ioc(f)); RDMAContext *rdma; + int ret; if (migration_in_postcopy()) { return 0; @@ -3889,7 +3894,10 @@ static int qemu_rdma_registration_start(QEMUFile *f, return -EIO; } - CHECK_ERROR_STATE(); + ret = check_error_state(rdma); + if (ret) { + return ret; + } trace_qemu_rdma_registration_start(flags); qemu_put_be64(f, RAM_SAVE_FLAG_HOOK); @@ -3920,7 +3928,10 @@ static int qemu_rdma_registration_stop(QEMUFile *f, return -EIO; } - CHECK_ERROR_STATE(); + ret = check_error_state(rdma); + if (ret) { + return ret; + } qemu_fflush(f); ret = qemu_rdma_drain_cq(rdma); From 142bd685ae10e1354b579a92db02c473f57080f0 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Thu, 28 Sep 2023 15:19:46 +0200 Subject: [PATCH 0471/1077] migration/rdma: Fix qemu_rdma_broken_ipv6_kernel() to set error qemu_rdma_resolve_host() and qemu_rdma_dest_init() try addresses until they find on that works. If none works, they return the first Error set by qemu_rdma_broken_ipv6_kernel(), or else return a generic one. qemu_rdma_broken_ipv6_kernel() neglects to set an Error when ibv_open_device() fails. If a later address fails differently, we use that Error instead, or else the generic one. Harmless enough, but needs fixing all the same. Signed-off-by: Markus Armbruster Reviewed-by: Fabiano Rosas Reviewed-by: Li Zhijian Reviewed-by: Juan Quintela Signed-off-by: Juan Quintela Message-ID: <20230928132019.2544702-21-armbru@redhat.com> --- migration/rdma.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/migration/rdma.c b/migration/rdma.c index 30e2c817f2..9c576bdcba 100644 --- a/migration/rdma.c +++ b/migration/rdma.c @@ -861,6 +861,8 @@ static int qemu_rdma_broken_ipv6_kernel(struct ibv_context *verbs, Error **errp) if (errno == EPERM) { continue; } else { + error_setg_errno(errp, errno, + "could not open RDMA device context"); return -EINVAL; } } From f35c0d9b0773e3ad143eeaf8d7ef3d4ce85a7e7f Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Thu, 28 Sep 2023 15:19:47 +0200 Subject: [PATCH 0472/1077] migration/rdma: Fix qemu_get_cm_event_timeout() to always set error qemu_get_cm_event_timeout() neglects to set an error when it fails because rdma_get_cm_event() fails. Harmless, as its caller qemu_rdma_connect() substitutes a generic error then. Fix it anyway. qemu_rdma_connect() also sets the generic error when its own call of rdma_get_cm_event() fails. Make the error handling more obvious: set a specific error right after rdma_get_cm_event() fails. Delete the generic error. Signed-off-by: Markus Armbruster Reviewed-by: Peter Xu Reviewed-by: Li Zhijian Reviewed-by: Juan Quintela Signed-off-by: Juan Quintela Message-ID: <20230928132019.2544702-22-armbru@redhat.com> --- migration/rdma.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/migration/rdma.c b/migration/rdma.c index 9c576bdcba..0039295a15 100644 --- a/migration/rdma.c +++ b/migration/rdma.c @@ -2555,7 +2555,11 @@ static int qemu_get_cm_event_timeout(RDMAContext *rdma, ERROR(errp, "failed to poll cm event, errno=%i", errno); return -1; } else if (poll_fd.revents & POLLIN) { - return rdma_get_cm_event(rdma->channel, cm_event); + if (rdma_get_cm_event(rdma->channel, cm_event) < 0) { + ERROR(errp, "failed to get cm event"); + return -1; + } + return 0; } else { ERROR(errp, "no POLLIN event, revent=%x", poll_fd.revents); return -1; @@ -2605,6 +2609,9 @@ static int qemu_rdma_connect(RDMAContext *rdma, bool return_path, ret = qemu_get_cm_event_timeout(rdma, &cm_event, 5000, errp); } else { ret = rdma_get_cm_event(rdma->channel, &cm_event); + if (ret < 0) { + ERROR(errp, "failed to get cm event"); + } } if (ret) { /* @@ -2613,7 +2620,6 @@ static int qemu_rdma_connect(RDMAContext *rdma, bool return_path, * Will go away later in this series. */ perror("rdma_get_cm_event after rdma_connect"); - ERROR(errp, "connecting to destination!"); goto err_rdma_source_connect; } From d63f4016b1d154e9ab62e849e6fbb6ded344bcb2 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Thu, 28 Sep 2023 15:19:48 +0200 Subject: [PATCH 0473/1077] migration/rdma: Drop dead qemu_rdma_data_init() code for !@host_port qemu_rdma_data_init() neglects to set an Error when it fails because @host_port is null. Fortunately, no caller passes null, so this is merely a latent bug. Drop the flawed code handling null argument. Signed-off-by: Markus Armbruster Reviewed-by: Fabiano Rosas Reviewed-by: Juan Quintela Signed-off-by: Juan Quintela Message-ID: <20230928132019.2544702-23-armbru@redhat.com> --- migration/rdma.c | 29 +++++++++++++---------------- 1 file changed, 13 insertions(+), 16 deletions(-) diff --git a/migration/rdma.c b/migration/rdma.c index 0039295a15..55eb8222ea 100644 --- a/migration/rdma.c +++ b/migration/rdma.c @@ -2767,25 +2767,22 @@ static RDMAContext *qemu_rdma_data_init(const char *host_port, Error **errp) RDMAContext *rdma = NULL; InetSocketAddress *addr; - if (host_port) { - rdma = g_new0(RDMAContext, 1); - rdma->current_index = -1; - rdma->current_chunk = -1; + rdma = g_new0(RDMAContext, 1); + rdma->current_index = -1; + rdma->current_chunk = -1; - addr = g_new(InetSocketAddress, 1); - if (!inet_parse(addr, host_port, NULL)) { - rdma->port = atoi(addr->port); - rdma->host = g_strdup(addr->host); - rdma->host_port = g_strdup(host_port); - } else { - ERROR(errp, "bad RDMA migration address '%s'", host_port); - g_free(rdma); - rdma = NULL; - } - - qapi_free_InetSocketAddress(addr); + addr = g_new(InetSocketAddress, 1); + if (!inet_parse(addr, host_port, NULL)) { + rdma->port = atoi(addr->port); + rdma->host = g_strdup(addr->host); + rdma->host_port = g_strdup(host_port); + } else { + ERROR(errp, "bad RDMA migration address '%s'", host_port); + g_free(rdma); + rdma = NULL; } + qapi_free_InetSocketAddress(addr); return rdma; } From 0110c6b86a828c9c2f42fbed4fc0da30ad7bf6eb Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Thu, 28 Sep 2023 15:19:49 +0200 Subject: [PATCH 0474/1077] migration/rdma: Fix QEMUFileHooks method return values The QEMUFileHooks methods don't come with a written contract. Digging through the code calling them, we find: * save_page(): Negative values RAM_SAVE_CONTROL_DELAYED and RAM_SAVE_CONTROL_NOT_SUPP are special. Any other negative value is an unspecified error. qemu_rdma_save_page() returns -EIO or rdma->error_state on error. I believe the latter is always negative. Nothing stops either of them to clash with the special values, though. Feels unlikely, but fix it anyway to return only the special values and -1. * before_ram_iterate(), after_ram_iterate(): Negative value means error. qemu_rdma_registration_start() and qemu_rdma_registration_stop() comply as far as I can tell. Make them comply *obviously*, by returning -1 on error. * hook_ram_load: Negative value means error. rdma_load_hook() already returns -1 on error. Leave it alone. Signed-off-by: Markus Armbruster Reviewed-by: Li Zhijian Reviewed-by: Juan Quintela Signed-off-by: Juan Quintela Message-ID: <20230928132019.2544702-24-armbru@redhat.com> --- migration/rdma.c | 79 +++++++++++++++++++++++------------------------- 1 file changed, 37 insertions(+), 42 deletions(-) diff --git a/migration/rdma.c b/migration/rdma.c index 55eb8222ea..974edde6a3 100644 --- a/migration/rdma.c +++ b/migration/rdma.c @@ -3268,12 +3268,11 @@ static int qemu_rdma_save_page(QEMUFile *f, ram_addr_t block_offset, rdma = qatomic_rcu_read(&rioc->rdmaout); if (!rdma) { - return -EIO; + return -1; } - ret = check_error_state(rdma); - if (ret) { - return ret; + if (check_error_state(rdma)) { + return -1; } qemu_fflush(f); @@ -3329,9 +3328,10 @@ static int qemu_rdma_save_page(QEMUFile *f, ram_addr_t block_offset, } return RAM_SAVE_CONTROL_DELAYED; + err: rdma->error_state = ret; - return ret; + return -1; } static void rdma_accept_incoming_migration(void *opaque); @@ -3577,12 +3577,11 @@ static int qemu_rdma_registration_handle(QEMUFile *f) rdma = qatomic_rcu_read(&rioc->rdmain); if (!rdma) { - return -EIO; + return -1; } - ret = check_error_state(rdma); - if (ret) { - return ret; + if (check_error_state(rdma)) { + return -1; } local = &rdma->local_ram_blocks; @@ -3615,7 +3614,7 @@ static int qemu_rdma_registration_handle(QEMUFile *f) (unsigned int)comp->block_idx, rdma->local_ram_blocks.nb_blocks); ret = -EIO; - goto out; + goto err; } block = &(rdma->local_ram_blocks.block[comp->block_idx]); @@ -3627,7 +3626,7 @@ static int qemu_rdma_registration_handle(QEMUFile *f) case RDMA_CONTROL_REGISTER_FINISHED: trace_qemu_rdma_registration_handle_finished(); - goto out; + return 0; case RDMA_CONTROL_RAM_BLOCKS_REQUEST: trace_qemu_rdma_registration_handle_ram_blocks(); @@ -3648,7 +3647,7 @@ static int qemu_rdma_registration_handle(QEMUFile *f) if (ret) { error_report("rdma migration: error dest " "registering ram blocks"); - goto out; + goto err; } } @@ -3687,7 +3686,7 @@ static int qemu_rdma_registration_handle(QEMUFile *f) if (ret < 0) { error_report("rdma migration: error sending remote info"); - goto out; + goto err; } break; @@ -3714,7 +3713,7 @@ static int qemu_rdma_registration_handle(QEMUFile *f) (unsigned int)reg->current_index, rdma->local_ram_blocks.nb_blocks); ret = -ENOENT; - goto out; + goto err; } block = &(rdma->local_ram_blocks.block[reg->current_index]); if (block->is_ram_block) { @@ -3724,7 +3723,7 @@ static int qemu_rdma_registration_handle(QEMUFile *f) block->block_name, block->offset, reg->key.current_addr); ret = -ERANGE; - goto out; + goto err; } host_addr = (block->local_host_addr + (reg->key.current_addr - block->offset)); @@ -3740,7 +3739,7 @@ static int qemu_rdma_registration_handle(QEMUFile *f) " chunk: %" PRIx64, block->block_name, reg->key.chunk); ret = -ERANGE; - goto out; + goto err; } } chunk_start = ram_chunk_start(block, chunk); @@ -3752,7 +3751,7 @@ static int qemu_rdma_registration_handle(QEMUFile *f) chunk, chunk_start, chunk_end)) { error_report("cannot get rkey"); ret = -EINVAL; - goto out; + goto err; } reg_result->rkey = tmp_rkey; @@ -3769,7 +3768,7 @@ static int qemu_rdma_registration_handle(QEMUFile *f) if (ret < 0) { error_report("Failed to send control buffer"); - goto out; + goto err; } break; case RDMA_CONTROL_UNREGISTER_REQUEST: @@ -3792,7 +3791,7 @@ static int qemu_rdma_registration_handle(QEMUFile *f) if (ret != 0) { perror("rdma unregistration chunk failed"); ret = -ret; - goto out; + goto err; } rdma->total_registrations--; @@ -3805,24 +3804,23 @@ static int qemu_rdma_registration_handle(QEMUFile *f) if (ret < 0) { error_report("Failed to send control buffer"); - goto out; + goto err; } break; case RDMA_CONTROL_REGISTER_RESULT: error_report("Invalid RESULT message at dest."); ret = -EIO; - goto out; + goto err; default: error_report("Unknown control message %s", control_desc(head.type)); ret = -EIO; - goto out; + goto err; } } while (1); -out: - if (ret < 0) { - rdma->error_state = ret; - } - return ret; + +err: + rdma->error_state = ret; + return -1; } /* Destination: @@ -3844,7 +3842,7 @@ rdma_block_notification_handle(QEMUFile *f, const char *name) rdma = qatomic_rcu_read(&rioc->rdmain); if (!rdma) { - return -EIO; + return -1; } /* Find the matching RAMBlock in our local list */ @@ -3857,7 +3855,7 @@ rdma_block_notification_handle(QEMUFile *f, const char *name) if (found == -1) { error_report("RAMBlock '%s' not found on destination", name); - return -ENOENT; + return -1; } rdma->local_ram_blocks.block[curr].src_index = rdma->next_src_index; @@ -3887,7 +3885,6 @@ static int qemu_rdma_registration_start(QEMUFile *f, { QIOChannelRDMA *rioc = QIO_CHANNEL_RDMA(qemu_file_get_ioc(f)); RDMAContext *rdma; - int ret; if (migration_in_postcopy()) { return 0; @@ -3896,12 +3893,11 @@ static int qemu_rdma_registration_start(QEMUFile *f, RCU_READ_LOCK_GUARD(); rdma = qatomic_rcu_read(&rioc->rdmaout); if (!rdma) { - return -EIO; + return -1; } - ret = check_error_state(rdma); - if (ret) { - return ret; + if (check_error_state(rdma)) { + return -1; } trace_qemu_rdma_registration_start(flags); @@ -3930,12 +3926,11 @@ static int qemu_rdma_registration_stop(QEMUFile *f, RCU_READ_LOCK_GUARD(); rdma = qatomic_rcu_read(&rioc->rdmaout); if (!rdma) { - return -EIO; + return -1; } - ret = check_error_state(rdma); - if (ret) { - return ret; + if (check_error_state(rdma)) { + return -1; } qemu_fflush(f); @@ -3966,7 +3961,7 @@ static int qemu_rdma_registration_stop(QEMUFile *f, qemu_rdma_reg_whole_ram_blocks : NULL); if (ret < 0) { fprintf(stderr, "receiving remote info!"); - return ret; + return -1; } nb_dest_blocks = resp.len / sizeof(RDMADestBlock); @@ -3989,7 +3984,7 @@ static int qemu_rdma_registration_stop(QEMUFile *f, "not identical on both the source and destination.", local->nb_blocks, nb_dest_blocks); rdma->error_state = -EINVAL; - return -EINVAL; + return -1; } qemu_rdma_move_header(rdma, reg_result_idx, &resp); @@ -4005,7 +4000,7 @@ static int qemu_rdma_registration_stop(QEMUFile *f, local->block[i].length, rdma->dest_blocks[i].length); rdma->error_state = -EINVAL; - return -EINVAL; + return -1; } local->block[i].remote_host_addr = rdma->dest_blocks[i].remote_host_addr; @@ -4025,7 +4020,7 @@ static int qemu_rdma_registration_stop(QEMUFile *f, return 0; err: rdma->error_state = ret; - return ret; + return -1; } static const QEMUFileHooks rdma_read_hooks = { From 07249822212ec56484ecfb5594d2ec94c84961fa Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Thu, 28 Sep 2023 15:19:50 +0200 Subject: [PATCH 0475/1077] migration/rdma: Fix rdma_getaddrinfo() error checking rdma_getaddrinfo() returns 0 on success. On error, it returns one of the EAI_ error codes like getaddrinfo() does, or -1 with errno set. This is broken by design: POSIX implicitly specifies the EAI_ error codes to be non-zero, no more. They could clash with -1. Nothing we can do about this design flaw. Both callers of rdma_getaddrinfo() only recognize negative values as error. Works only because systems elect to make the EAI_ error codes negative. Best not to rely on that: change the callers to treat any non-zero value as failure. Also change them to return -1 instead of the value received from getaddrinfo() on failure, to avoid positive error values. Signed-off-by: Markus Armbruster Reviewed-by: Li Zhijian Reviewed-by: Juan Quintela Signed-off-by: Juan Quintela Message-ID: <20230928132019.2544702-25-armbru@redhat.com> --- migration/rdma.c | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/migration/rdma.c b/migration/rdma.c index 974edde6a3..dd0b073792 100644 --- a/migration/rdma.c +++ b/migration/rdma.c @@ -941,14 +941,14 @@ static int qemu_rdma_resolve_host(RDMAContext *rdma, Error **errp) if (rdma->host == NULL || !strcmp(rdma->host, "")) { ERROR(errp, "RDMA hostname has not been set"); - return -EINVAL; + return -1; } /* create CM channel */ rdma->channel = rdma_create_event_channel(); if (!rdma->channel) { ERROR(errp, "could not create CM channel"); - return -EINVAL; + return -1; } /* create CM id */ @@ -962,7 +962,7 @@ static int qemu_rdma_resolve_host(RDMAContext *rdma, Error **errp) port_str[15] = '\0'; ret = rdma_getaddrinfo(rdma->host, port_str, NULL, &res); - if (ret < 0) { + if (ret) { ERROR(errp, "could not rdma_getaddrinfo address %s", rdma->host); goto err_resolve_get_addr; } @@ -1004,7 +1004,6 @@ route: rdma_event_str(cm_event->event)); error_report("rdma_resolve_addr"); rdma_ack_cm_event(cm_event); - ret = -EINVAL; goto err_resolve_get_addr; } rdma_ack_cm_event(cm_event); @@ -1025,7 +1024,6 @@ route: ERROR(errp, "result not equal to event_route_resolved: %s", rdma_event_str(cm_event->event)); rdma_ack_cm_event(cm_event); - ret = -EINVAL; goto err_resolve_get_addr; } rdma_ack_cm_event(cm_event); @@ -1040,7 +1038,7 @@ err_resolve_get_addr: err_resolve_create_id: rdma_destroy_event_channel(rdma->channel); rdma->channel = NULL; - return ret; + return -1; } /* @@ -2695,7 +2693,7 @@ static int qemu_rdma_dest_init(RDMAContext *rdma, Error **errp) port_str[15] = '\0'; ret = rdma_getaddrinfo(rdma->host, port_str, NULL, &res); - if (ret < 0) { + if (ret) { ERROR(errp, "could not rdma_getaddrinfo address %s", rdma->host); goto err_dest_init_bind_addr; } @@ -2739,7 +2737,7 @@ err_dest_init_create_listen_id: rdma_destroy_event_channel(rdma->channel); rdma->channel = NULL; rdma->error_state = ret; - return ret; + return -1; } From 8c6513f75048e6cc55d9e6db2c2e0e7b02a166bc Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Thu, 28 Sep 2023 15:19:51 +0200 Subject: [PATCH 0476/1077] migration/rdma: Return -1 instead of negative errno code Several functions return negative errno codes on failure. Callers check for specific codes exactly never. For some of the functions, callers couldn't check even if they wanted to, because the functions also return negative values that aren't errno codes, leaving readers confused on what the function actually returns. Clean up and simplify: return -1 instead of negative errno code. Signed-off-by: Markus Armbruster Reviewed-by: Li Zhijian Reviewed-by: Juan Quintela Signed-off-by: Juan Quintela Message-ID: <20230928132019.2544702-26-armbru@redhat.com> --- migration/rdma.c | 44 ++++++++++++++++++++++---------------------- 1 file changed, 22 insertions(+), 22 deletions(-) diff --git a/migration/rdma.c b/migration/rdma.c index dd0b073792..bc39b7ab2e 100644 --- a/migration/rdma.c +++ b/migration/rdma.c @@ -863,14 +863,14 @@ static int qemu_rdma_broken_ipv6_kernel(struct ibv_context *verbs, Error **errp) } else { error_setg_errno(errp, errno, "could not open RDMA device context"); - return -EINVAL; + return -1; } } if (ibv_query_port(verbs, 1, &port_attr)) { ibv_close_device(verbs); ERROR(errp, "Could not query initial IB port"); - return -EINVAL; + return -1; } if (port_attr.link_layer == IBV_LINK_LAYER_INFINIBAND) { @@ -895,7 +895,7 @@ static int qemu_rdma_broken_ipv6_kernel(struct ibv_context *verbs, Error **errp) ERROR(errp, "You only have RoCE / iWARP devices in your systems" " and your management software has specified '[::]'" ", but IPv6 over RoCE / iWARP is not supported in Linux."); - return -ENONET; + return -1; } } @@ -911,13 +911,13 @@ static int qemu_rdma_broken_ipv6_kernel(struct ibv_context *verbs, Error **errp) /* IB ports start with 1, not 0 */ if (ibv_query_port(verbs, 1, &port_attr)) { ERROR(errp, "Could not query initial IB port"); - return -EINVAL; + return -1; } if (port_attr.link_layer == IBV_LINK_LAYER_ETHERNET) { ERROR(errp, "Linux kernel's RoCE / iWARP does not support IPv6 " "(but patches on linux-rdma in progress)"); - return -ENONET; + return -1; } #endif @@ -1425,7 +1425,7 @@ static int qemu_rdma_unregister_waiting(RDMAContext *rdma) * this series. */ perror("unregistration chunk failed"); - return -ret; + return -1; } rdma->total_registrations--; @@ -1570,7 +1570,7 @@ static int qemu_rdma_wait_comp_channel(RDMAContext *rdma, if (ret) { error_report("failed to get cm event while wait " "completion channel"); - return -EPIPE; + return -1; } error_report("receive cm event while wait comp channel," @@ -1578,7 +1578,7 @@ static int qemu_rdma_wait_comp_channel(RDMAContext *rdma, if (cm_event->event == RDMA_CM_EVENT_DISCONNECTED || cm_event->event == RDMA_CM_EVENT_DEVICE_REMOVAL) { rdma_ack_cm_event(cm_event); - return -EPIPE; + return -1; } rdma_ack_cm_event(cm_event); } @@ -1591,18 +1591,18 @@ static int qemu_rdma_wait_comp_channel(RDMAContext *rdma, * I don't trust errno from qemu_poll_ns */ error_report("%s: poll failed", __func__); - return -EPIPE; + return -1; } if (migrate_get_current()->state == MIGRATION_STATUS_CANCELLING) { /* Bail out and let the cancellation happen */ - return -EPIPE; + return -1; } } } if (rdma->received_error) { - return -EPIPE; + return -1; } return rdma->error_state; } @@ -1772,7 +1772,7 @@ static int qemu_rdma_post_send_control(RDMAContext *rdma, uint8_t *buf, if (ret > 0) { error_report("Failed to use post IB SEND for control"); - return -ret; + return -1; } ret = qemu_rdma_block_for_wrid(rdma, RDMA_WRID_SEND_CONTROL, NULL); @@ -1841,15 +1841,15 @@ static int qemu_rdma_exchange_get_response(RDMAContext *rdma, if (head->type == RDMA_CONTROL_ERROR) { rdma->received_error = true; } - return -EIO; + return -1; } if (head->len > RDMA_CONTROL_MAX_BUFFER - sizeof(*head)) { error_report("too long length: %d", head->len); - return -EINVAL; + return -1; } if (sizeof(*head) + head->len != byte_len) { error_report("Malformed length: %d byte_len %d", head->len, byte_len); - return -EINVAL; + return -1; } return 0; @@ -2115,7 +2115,7 @@ retry: (uint8_t *) &comp, NULL, NULL, NULL); if (ret < 0) { - return -EIO; + return -1; } /* @@ -2159,7 +2159,7 @@ retry: &sge.lkey, NULL, chunk, chunk_start, chunk_end)) { error_report("cannot get lkey"); - return -EINVAL; + return -1; } reg_result = (RDMARegisterResult *) @@ -2178,7 +2178,7 @@ retry: &sge.lkey, NULL, chunk, chunk_start, chunk_end)) { error_report("cannot get lkey!"); - return -EINVAL; + return -1; } } @@ -2190,7 +2190,7 @@ retry: &sge.lkey, NULL, chunk, chunk_start, chunk_end)) { error_report("cannot get lkey!"); - return -EINVAL; + return -1; } } @@ -2237,7 +2237,7 @@ retry: * in this series. */ perror("rdma migration: post rdma write failed"); - return -ret; + return -1; } set_bit(chunk, block->transit_bitmap); @@ -2969,14 +2969,14 @@ static int qemu_rdma_drain_cq(RDMAContext *rdma) int ret; if (qemu_rdma_write_flush(rdma) < 0) { - return -EIO; + return -1; } while (rdma->nb_sent) { ret = qemu_rdma_block_for_wrid(rdma, RDMA_WRID_RDMA_WRITE, NULL); if (ret < 0) { error_report("rdma migration: complete polling error!"); - return -EIO; + return -1; } } From ec486974539d84bf04bc65dfda1844accfcb6c28 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Thu, 28 Sep 2023 15:19:52 +0200 Subject: [PATCH 0477/1077] migration/rdma: Dumb down remaining int error values to -1 This is just to make the error value more obvious. Callers don't mind. Signed-off-by: Markus Armbruster Reviewed-by: Li Zhijian Reviewed-by: Juan Quintela Signed-off-by: Juan Quintela Message-ID: <20230928132019.2544702-27-armbru@redhat.com> --- migration/rdma.c | 45 +++++++++++++++++++++++---------------------- 1 file changed, 23 insertions(+), 22 deletions(-) diff --git a/migration/rdma.c b/migration/rdma.c index bc39b7ab2e..3c7518d65a 100644 --- a/migration/rdma.c +++ b/migration/rdma.c @@ -1434,7 +1434,7 @@ static int qemu_rdma_unregister_waiting(RDMAContext *rdma) ret = qemu_rdma_exchange_send(rdma, &head, (uint8_t *) ®, &resp, NULL, NULL); if (ret < 0) { - return ret; + return -1; } trace_qemu_rdma_unregister_waiting_complete(chunk); @@ -1475,7 +1475,7 @@ static int qemu_rdma_poll(RDMAContext *rdma, struct ibv_cq *cq, if (ret < 0) { error_report("ibv_poll_cq failed"); - return ret; + return -1; } wr_id = wc.wr_id & RDMA_WRID_TYPE_MASK; @@ -1604,7 +1604,7 @@ static int qemu_rdma_wait_comp_channel(RDMAContext *rdma, if (rdma->received_error) { return -1; } - return rdma->error_state; + return -!!rdma->error_state; } static struct ibv_comp_channel *to_channel(RDMAContext *rdma, uint64_t wrid) @@ -1649,7 +1649,7 @@ static int qemu_rdma_block_for_wrid(RDMAContext *rdma, while (wr_id != wrid_requested) { ret = qemu_rdma_poll(rdma, poll_cq, &wr_id_in, byte_len); if (ret < 0) { - return ret; + return -1; } wr_id = wr_id_in & RDMA_WRID_TYPE_MASK; @@ -1723,7 +1723,7 @@ err_block_for_wrid: } rdma->error_state = ret; - return ret; + return -1; } /* @@ -1778,9 +1778,10 @@ static int qemu_rdma_post_send_control(RDMAContext *rdma, uint8_t *buf, ret = qemu_rdma_block_for_wrid(rdma, RDMA_WRID_SEND_CONTROL, NULL); if (ret < 0) { error_report("rdma migration: send polling control error"); + return -1; } - return ret; + return 0; } /* @@ -1822,7 +1823,7 @@ static int qemu_rdma_exchange_get_response(RDMAContext *rdma, if (ret < 0) { error_report("rdma migration: recv polling control error!"); - return ret; + return -1; } network_to_control((void *) rdma->wr_data[idx].control); @@ -1902,7 +1903,7 @@ static int qemu_rdma_exchange_send(RDMAContext *rdma, RDMAControlHeader *head, RDMA_CONTROL_READY, RDMA_WRID_READY); if (ret < 0) { - return ret; + return -1; } } @@ -1914,7 +1915,7 @@ static int qemu_rdma_exchange_send(RDMAContext *rdma, RDMAControlHeader *head, if (ret) { error_report("rdma migration: error posting" " extra control recv for anticipated result!"); - return ret; + return -1; } } @@ -1924,7 +1925,7 @@ static int qemu_rdma_exchange_send(RDMAContext *rdma, RDMAControlHeader *head, ret = qemu_rdma_post_recv_control(rdma, RDMA_WRID_READY); if (ret) { error_report("rdma migration: error posting first control recv!"); - return ret; + return -1; } /* @@ -1934,7 +1935,7 @@ static int qemu_rdma_exchange_send(RDMAContext *rdma, RDMAControlHeader *head, if (ret < 0) { error_report("Failed to send control buffer!"); - return ret; + return -1; } /* @@ -1945,7 +1946,7 @@ static int qemu_rdma_exchange_send(RDMAContext *rdma, RDMAControlHeader *head, trace_qemu_rdma_exchange_send_issue_callback(); ret = callback(rdma); if (ret < 0) { - return ret; + return -1; } } @@ -1954,7 +1955,7 @@ static int qemu_rdma_exchange_send(RDMAContext *rdma, RDMAControlHeader *head, resp->type, RDMA_WRID_DATA); if (ret < 0) { - return ret; + return -1; } qemu_rdma_move_header(rdma, RDMA_WRID_DATA, resp); @@ -1990,7 +1991,7 @@ static int qemu_rdma_exchange_recv(RDMAContext *rdma, RDMAControlHeader *head, if (ret < 0) { error_report("Failed to send control buffer!"); - return ret; + return -1; } /* @@ -2000,7 +2001,7 @@ static int qemu_rdma_exchange_recv(RDMAContext *rdma, RDMAControlHeader *head, expecting, RDMA_WRID_READY); if (ret < 0) { - return ret; + return -1; } qemu_rdma_move_header(rdma, RDMA_WRID_READY, head); @@ -2011,7 +2012,7 @@ static int qemu_rdma_exchange_recv(RDMAContext *rdma, RDMAControlHeader *head, ret = qemu_rdma_post_recv_control(rdma, RDMA_WRID_READY); if (ret) { error_report("rdma migration: error posting second control recv!"); - return ret; + return -1; } return 0; @@ -2084,7 +2085,7 @@ retry: "block %d chunk %" PRIu64 " current %" PRIu64 " len %" PRIu64 " %d", current_index, chunk, sge.addr, length, rdma->nb_sent); - return ret; + return -1; } } @@ -2151,7 +2152,7 @@ retry: ret = qemu_rdma_exchange_send(rdma, &head, (uint8_t *) ®, &resp, ®_result_idx, NULL); if (ret < 0) { - return ret; + return -1; } /* try to overlap this single registration with the one we sent. */ @@ -2225,7 +2226,7 @@ retry: if (ret < 0) { error_report("rdma migration: failed to make " "room in full send queue!"); - return ret; + return -1; } goto retry; @@ -2276,7 +2277,7 @@ static int qemu_rdma_write_flush(RDMAContext *rdma) rdma->current_index, rdma->current_addr, rdma->current_length); if (ret < 0) { - return ret; + return -1; } if (ret == 0) { @@ -2358,7 +2359,7 @@ static int qemu_rdma_write(RDMAContext *rdma, if (!qemu_rdma_buffer_mergeable(rdma, current_addr, len)) { ret = qemu_rdma_write_flush(rdma); if (ret) { - return ret; + return -1; } rdma->current_length = 0; rdma->current_addr = current_addr; @@ -3524,7 +3525,7 @@ err_rdma_dest_wait: rdma->error_state = ret; qemu_rdma_cleanup(rdma); g_free(rdma_return_path); - return ret; + return -1; } static int dest_ram_sort_func(const void *a, const void *b) From b86c94a49ea54653015edcc5f32603abbf2aa556 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Thu, 28 Sep 2023 15:19:53 +0200 Subject: [PATCH 0478/1077] migration/rdma: Replace int error_state by bool errored All we do with the value of RDMAContext member @error_state is test whether it's zero. Change to bool and rename to @errored. Signed-off-by: Markus Armbruster Reviewed-by: Li Zhijian Reviewed-by: Juan Quintela Signed-off-by: Juan Quintela Message-ID: <20230928132019.2544702-28-armbru@redhat.com> --- migration/rdma.c | 66 ++++++++++++++++++++++++------------------------ 1 file changed, 33 insertions(+), 33 deletions(-) diff --git a/migration/rdma.c b/migration/rdma.c index 3c7518d65a..a57ec3791a 100644 --- a/migration/rdma.c +++ b/migration/rdma.c @@ -352,7 +352,7 @@ typedef struct RDMAContext { * memory registration, then do not attempt any future work * and remember the error state. */ - int error_state; + bool errored; bool error_reported; bool received_error; @@ -439,14 +439,14 @@ typedef struct QEMU_PACKED { uint64_t chunks; /* how many sequential chunks to register */ } RDMARegister; -static int check_error_state(RDMAContext *rdma) +static bool rdma_errored(RDMAContext *rdma) { - if (rdma->error_state && !rdma->error_reported) { + if (rdma->errored && !rdma->error_reported) { error_report("RDMA is in an error state waiting migration" " to abort!"); rdma->error_reported = true; } - return rdma->error_state; + return rdma->errored; } static void register_to_network(RDMAContext *rdma, RDMARegister *reg) @@ -1547,7 +1547,7 @@ static int qemu_rdma_wait_comp_channel(RDMAContext *rdma, * But we need to be able to handle 'cancel' or an error * without hanging forever. */ - while (!rdma->error_state && !rdma->received_error) { + while (!rdma->errored && !rdma->received_error) { GPollFD pfds[2]; pfds[0].fd = comp_channel->fd; pfds[0].events = G_IO_IN | G_IO_HUP | G_IO_ERR; @@ -1604,7 +1604,7 @@ static int qemu_rdma_wait_comp_channel(RDMAContext *rdma, if (rdma->received_error) { return -1; } - return -!!rdma->error_state; + return -rdma->errored; } static struct ibv_comp_channel *to_channel(RDMAContext *rdma, uint64_t wrid) @@ -1722,7 +1722,7 @@ err_block_for_wrid: ibv_ack_cq_events(cq, num_cq_events); } - rdma->error_state = ret; + rdma->errored = true; return -1; } @@ -2386,7 +2386,7 @@ static void qemu_rdma_cleanup(RDMAContext *rdma) int idx; if (rdma->cm_id && rdma->connected) { - if ((rdma->error_state || + if ((rdma->errored || migrate_get_current()->state == MIGRATION_STATUS_CANCELLING) && !rdma->received_error) { RDMAControlHeader head = { .len = 0, @@ -2672,14 +2672,14 @@ static int qemu_rdma_dest_init(RDMAContext *rdma, Error **errp) if (!rdma->host || !rdma->host[0]) { ERROR(errp, "RDMA host is not set!"); - rdma->error_state = -EINVAL; + rdma->errored = true; return -1; } /* create CM channel */ rdma->channel = rdma_create_event_channel(); if (!rdma->channel) { ERROR(errp, "could not create rdma event channel"); - rdma->error_state = -EINVAL; + rdma->errored = true; return -1; } @@ -2737,7 +2737,7 @@ err_dest_init_bind_addr: err_dest_init_create_listen_id: rdma_destroy_event_channel(rdma->channel); rdma->channel = NULL; - rdma->error_state = ret; + rdma->errored = true; return -1; } @@ -2812,7 +2812,7 @@ static ssize_t qio_channel_rdma_writev(QIOChannel *ioc, return -1; } - if (rdma->error_state) { + if (rdma->errored) { error_setg(errp, "RDMA is in an error state waiting migration to abort!"); return -1; @@ -2824,7 +2824,7 @@ static ssize_t qio_channel_rdma_writev(QIOChannel *ioc, */ ret = qemu_rdma_write_flush(rdma); if (ret < 0) { - rdma->error_state = ret; + rdma->errored = true; error_setg(errp, "qemu_rdma_write_flush failed"); return -1; } @@ -2844,7 +2844,7 @@ static ssize_t qio_channel_rdma_writev(QIOChannel *ioc, ret = qemu_rdma_exchange_send(rdma, &head, data, NULL, NULL, NULL); if (ret < 0) { - rdma->error_state = ret; + rdma->errored = true; error_setg(errp, "qemu_rdma_exchange_send failed"); return -1; } @@ -2902,7 +2902,7 @@ static ssize_t qio_channel_rdma_readv(QIOChannel *ioc, return -1; } - if (rdma->error_state) { + if (rdma->errored) { error_setg(errp, "RDMA is in an error state waiting migration to abort!"); return -1; @@ -2938,7 +2938,7 @@ static ssize_t qio_channel_rdma_readv(QIOChannel *ioc, ret = qemu_rdma_exchange_recv(rdma, &head, RDMA_CONTROL_QEMU_FILE); if (ret < 0) { - rdma->error_state = ret; + rdma->errored = true; error_setg(errp, "qemu_rdma_exchange_recv failed"); return -1; } @@ -3212,21 +3212,21 @@ qio_channel_rdma_shutdown(QIOChannel *ioc, switch (how) { case QIO_CHANNEL_SHUTDOWN_READ: if (rdmain) { - rdmain->error_state = -1; + rdmain->errored = true; } break; case QIO_CHANNEL_SHUTDOWN_WRITE: if (rdmaout) { - rdmaout->error_state = -1; + rdmaout->errored = true; } break; case QIO_CHANNEL_SHUTDOWN_BOTH: default: if (rdmain) { - rdmain->error_state = -1; + rdmain->errored = true; } if (rdmaout) { - rdmaout->error_state = -1; + rdmaout->errored = true; } break; } @@ -3270,7 +3270,7 @@ static int qemu_rdma_save_page(QEMUFile *f, ram_addr_t block_offset, return -1; } - if (check_error_state(rdma)) { + if (rdma_errored(rdma)) { return -1; } @@ -3329,7 +3329,7 @@ static int qemu_rdma_save_page(QEMUFile *f, ram_addr_t block_offset, return RAM_SAVE_CONTROL_DELAYED; err: - rdma->error_state = ret; + rdma->errored = true; return -1; } @@ -3350,13 +3350,13 @@ static void rdma_cm_poll_handler(void *opaque) if (cm_event->event == RDMA_CM_EVENT_DISCONNECTED || cm_event->event == RDMA_CM_EVENT_DEVICE_REMOVAL) { - if (!rdma->error_state && + if (!rdma->errored && migration_incoming_get_current()->state != MIGRATION_STATUS_COMPLETED) { error_report("receive cm event, cm event is %d", cm_event->event); - rdma->error_state = -EPIPE; + rdma->errored = true; if (rdma->return_path) { - rdma->return_path->error_state = -EPIPE; + rdma->return_path->errored = true; } } rdma_ack_cm_event(cm_event); @@ -3522,7 +3522,7 @@ static int qemu_rdma_accept(RDMAContext *rdma) return 0; err_rdma_dest_wait: - rdma->error_state = ret; + rdma->errored = true; qemu_rdma_cleanup(rdma); g_free(rdma_return_path); return -1; @@ -3579,7 +3579,7 @@ static int qemu_rdma_registration_handle(QEMUFile *f) return -1; } - if (check_error_state(rdma)) { + if (rdma_errored(rdma)) { return -1; } @@ -3818,7 +3818,7 @@ static int qemu_rdma_registration_handle(QEMUFile *f) } while (1); err: - rdma->error_state = ret; + rdma->errored = true; return -1; } @@ -3895,7 +3895,7 @@ static int qemu_rdma_registration_start(QEMUFile *f, return -1; } - if (check_error_state(rdma)) { + if (rdma_errored(rdma)) { return -1; } @@ -3928,7 +3928,7 @@ static int qemu_rdma_registration_stop(QEMUFile *f, return -1; } - if (check_error_state(rdma)) { + if (rdma_errored(rdma)) { return -1; } @@ -3982,7 +3982,7 @@ static int qemu_rdma_registration_stop(QEMUFile *f, "Your QEMU command line parameters are probably " "not identical on both the source and destination.", local->nb_blocks, nb_dest_blocks); - rdma->error_state = -EINVAL; + rdma->errored = true; return -1; } @@ -3998,7 +3998,7 @@ static int qemu_rdma_registration_stop(QEMUFile *f, "vs %" PRIu64, local->block[i].block_name, i, local->block[i].length, rdma->dest_blocks[i].length); - rdma->error_state = -EINVAL; + rdma->errored = true; return -1; } local->block[i].remote_host_addr = @@ -4018,7 +4018,7 @@ static int qemu_rdma_registration_stop(QEMUFile *f, return 0; err: - rdma->error_state = ret; + rdma->errored = true; return -1; } From c0d77702d2e787053d2b139e07220208d6e635c6 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Thu, 28 Sep 2023 15:19:54 +0200 Subject: [PATCH 0479/1077] migration/rdma: Drop superfluous assignments to @ret Signed-off-by: Markus Armbruster Reviewed-by: Li Zhijian Reviewed-by: Juan Quintela Signed-off-by: Juan Quintela Message-ID: <20230928132019.2544702-29-armbru@redhat.com> --- migration/rdma.c | 35 ++++++++++------------------------- 1 file changed, 10 insertions(+), 25 deletions(-) diff --git a/migration/rdma.c b/migration/rdma.c index a57ec3791a..08a82d5e57 100644 --- a/migration/rdma.c +++ b/migration/rdma.c @@ -1530,7 +1530,7 @@ static int qemu_rdma_wait_comp_channel(RDMAContext *rdma, struct ibv_comp_channel *comp_channel) { struct rdma_cm_event *cm_event; - int ret = -1; + int ret; /* * Coroutine doesn't start until migration_fd_process_incoming() @@ -1635,7 +1635,7 @@ static int qemu_rdma_block_for_wrid(RDMAContext *rdma, uint64_t wrid_requested, uint32_t *byte_len) { - int num_cq_events = 0, ret = 0; + int num_cq_events = 0, ret; struct ibv_cq *cq; void *cq_ctx; uint64_t wr_id = RDMA_WRID_NONE, wr_id_in; @@ -1685,8 +1685,7 @@ static int qemu_rdma_block_for_wrid(RDMAContext *rdma, num_cq_events++; - ret = -ibv_req_notify_cq(cq, 0); - if (ret) { + if (ibv_req_notify_cq(cq, 0)) { goto err_block_for_wrid; } @@ -1733,7 +1732,7 @@ err_block_for_wrid: static int qemu_rdma_post_send_control(RDMAContext *rdma, uint8_t *buf, RDMAControlHeader *head) { - int ret = 0; + int ret; RDMAWorkRequestData *wr = &rdma->wr_data[RDMA_WRID_CONTROL]; struct ibv_send_wr *bad_wr; struct ibv_sge sge = { @@ -1890,7 +1889,7 @@ static int qemu_rdma_exchange_send(RDMAContext *rdma, RDMAControlHeader *head, int *resp_idx, int (*callback)(RDMAContext *rdma)) { - int ret = 0; + int ret; /* * Wait until the dest is ready before attempting to deliver the message @@ -2890,7 +2889,7 @@ static ssize_t qio_channel_rdma_readv(QIOChannel *ioc, QIOChannelRDMA *rioc = QIO_CHANNEL_RDMA(ioc); RDMAContext *rdma; RDMAControlHeader head; - int ret = 0; + int ret; ssize_t done = 0; size_t i, len; @@ -3379,7 +3378,7 @@ static int qemu_rdma_accept(RDMAContext *rdma) RDMAContext *rdma_return_path = NULL; struct rdma_cm_event *cm_event; struct ibv_context *verbs; - int ret = -EINVAL; + int ret; int idx; ret = rdma_get_cm_event(rdma->channel, &cm_event); @@ -3389,7 +3388,6 @@ static int qemu_rdma_accept(RDMAContext *rdma) if (cm_event->event != RDMA_CM_EVENT_CONNECT_REQUEST) { rdma_ack_cm_event(cm_event); - ret = -1; goto err_rdma_dest_wait; } @@ -3402,7 +3400,6 @@ static int qemu_rdma_accept(RDMAContext *rdma) rdma_return_path = qemu_rdma_data_init(rdma->host_port, NULL); if (rdma_return_path == NULL) { rdma_ack_cm_event(cm_event); - ret = -1; goto err_rdma_dest_wait; } @@ -3417,7 +3414,6 @@ static int qemu_rdma_accept(RDMAContext *rdma) error_report("Unknown source RDMA version: %d, bailing...", cap.version); rdma_ack_cm_event(cm_event); - ret = -1; goto err_rdma_dest_wait; } @@ -3450,7 +3446,6 @@ static int qemu_rdma_accept(RDMAContext *rdma) } else if (rdma->verbs != verbs) { error_report("ibv context not matching %p, %p!", rdma->verbs, verbs); - ret = -1; goto err_rdma_dest_wait; } @@ -3504,7 +3499,6 @@ static int qemu_rdma_accept(RDMAContext *rdma) if (cm_event->event != RDMA_CM_EVENT_ESTABLISHED) { error_report("rdma_accept not event established"); rdma_ack_cm_event(cm_event); - ret = -1; goto err_rdma_dest_wait; } @@ -3567,7 +3561,7 @@ static int qemu_rdma_registration_handle(QEMUFile *f) static RDMARegisterResult results[RDMA_CONTROL_MAX_COMMANDS_PER_MESSAGE]; RDMALocalBlock *block; void *host_addr; - int ret = 0; + int ret; int idx = 0; int count = 0; int i = 0; @@ -3596,7 +3590,6 @@ static int qemu_rdma_registration_handle(QEMUFile *f) if (head.repeat > RDMA_CONTROL_MAX_COMMANDS_PER_MESSAGE) { error_report("rdma: Too many requests in this message (%d)." "Bailing.", head.repeat); - ret = -EIO; break; } @@ -3612,7 +3605,6 @@ static int qemu_rdma_registration_handle(QEMUFile *f) error_report("rdma: 'compress' bad block index %u (vs %d)", (unsigned int)comp->block_idx, rdma->local_ram_blocks.nb_blocks); - ret = -EIO; goto err; } block = &(rdma->local_ram_blocks.block[comp->block_idx]); @@ -3711,7 +3703,6 @@ static int qemu_rdma_registration_handle(QEMUFile *f) error_report("rdma: 'register' bad block index %u (vs %d)", (unsigned int)reg->current_index, rdma->local_ram_blocks.nb_blocks); - ret = -ENOENT; goto err; } block = &(rdma->local_ram_blocks.block[reg->current_index]); @@ -3721,7 +3712,6 @@ static int qemu_rdma_registration_handle(QEMUFile *f) " offset: %" PRIx64 " current_addr: %" PRIx64, block->block_name, block->offset, reg->key.current_addr); - ret = -ERANGE; goto err; } host_addr = (block->local_host_addr + @@ -3737,7 +3727,6 @@ static int qemu_rdma_registration_handle(QEMUFile *f) error_report("rdma: bad chunk for block %s" " chunk: %" PRIx64, block->block_name, reg->key.chunk); - ret = -ERANGE; goto err; } } @@ -3749,7 +3738,6 @@ static int qemu_rdma_registration_handle(QEMUFile *f) (uintptr_t)host_addr, NULL, &tmp_rkey, chunk, chunk_start, chunk_end)) { error_report("cannot get rkey"); - ret = -EINVAL; goto err; } reg_result->rkey = tmp_rkey; @@ -3789,7 +3777,6 @@ static int qemu_rdma_registration_handle(QEMUFile *f) if (ret != 0) { perror("rdma unregistration chunk failed"); - ret = -ret; goto err; } @@ -3808,11 +3795,9 @@ static int qemu_rdma_registration_handle(QEMUFile *f) break; case RDMA_CONTROL_REGISTER_RESULT: error_report("Invalid RESULT message at dest."); - ret = -EIO; goto err; default: error_report("Unknown control message %s", control_desc(head.type)); - ret = -EIO; goto err; } } while (1); @@ -3916,7 +3901,7 @@ static int qemu_rdma_registration_stop(QEMUFile *f, QIOChannelRDMA *rioc = QIO_CHANNEL_RDMA(qemu_file_get_ioc(f)); RDMAContext *rdma; RDMAControlHeader head = { .len = 0, .repeat = 1 }; - int ret = 0; + int ret; if (migration_in_postcopy()) { return 0; @@ -4190,7 +4175,7 @@ void rdma_start_outgoing_migration(void *opaque, MigrationState *s = opaque; RDMAContext *rdma_return_path = NULL; RDMAContext *rdma; - int ret = 0; + int ret; /* Avoid ram_block_discard_disable(), cannot change during migration. */ if (ram_block_discard_is_required()) { From 4a1021796252598957876a530c8d5d2ed7fd693e Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Thu, 28 Sep 2023 15:19:55 +0200 Subject: [PATCH 0480/1077] migration/rdma: Check negative error values the same way everywhere When a function returns 0 on success, negative value on error, checking for non-zero suffices, but checking for negative is clearer. So do that. Signed-off-by: Markus Armbruster Reviewed-by: Fabiano Rosas Reviewed-by: Juan Quintela Signed-off-by: Juan Quintela Message-ID: <20230928132019.2544702-30-armbru@redhat.com> --- migration/rdma.c | 82 ++++++++++++++++++++++++------------------------ 1 file changed, 41 insertions(+), 41 deletions(-) diff --git a/migration/rdma.c b/migration/rdma.c index 08a82d5e57..b0125b01cf 100644 --- a/migration/rdma.c +++ b/migration/rdma.c @@ -953,7 +953,7 @@ static int qemu_rdma_resolve_host(RDMAContext *rdma, Error **errp) /* create CM id */ ret = rdma_create_id(rdma->channel, &rdma->cm_id, NULL, RDMA_PS_TCP); - if (ret) { + if (ret < 0) { ERROR(errp, "could not create channel id"); goto err_resolve_create_id; } @@ -974,10 +974,10 @@ static int qemu_rdma_resolve_host(RDMAContext *rdma, Error **errp) ret = rdma_resolve_addr(rdma->cm_id, NULL, e->ai_dst_addr, RDMA_RESOLVE_TIMEOUT_MS); - if (!ret) { + if (ret >= 0) { if (e->ai_family == AF_INET6) { ret = qemu_rdma_broken_ipv6_kernel(rdma->cm_id->verbs, errp); - if (ret) { + if (ret < 0) { continue; } } @@ -994,7 +994,7 @@ route: qemu_rdma_dump_gid("source_resolve_addr", rdma->cm_id); ret = rdma_get_cm_event(rdma->channel, &cm_event); - if (ret) { + if (ret < 0) { ERROR(errp, "could not perform event_addr_resolved"); goto err_resolve_get_addr; } @@ -1010,13 +1010,13 @@ route: /* resolve route */ ret = rdma_resolve_route(rdma->cm_id, RDMA_RESOLVE_TIMEOUT_MS); - if (ret) { + if (ret < 0) { ERROR(errp, "could not resolve rdma route"); goto err_resolve_get_addr; } ret = rdma_get_cm_event(rdma->channel, &cm_event); - if (ret) { + if (ret < 0) { ERROR(errp, "could not perform event_route_resolved"); goto err_resolve_get_addr; } @@ -1124,7 +1124,7 @@ static int qemu_rdma_alloc_qp(RDMAContext *rdma) attr.qp_type = IBV_QPT_RC; ret = rdma_create_qp(rdma->cm_id, rdma->pd, &attr); - if (ret) { + if (ret < 0) { return -1; } @@ -1567,7 +1567,7 @@ static int qemu_rdma_wait_comp_channel(RDMAContext *rdma, if (pfds[1].revents) { ret = rdma_get_cm_event(rdma->channel, &cm_event); - if (ret) { + if (ret < 0) { error_report("failed to get cm event while wait " "completion channel"); return -1; @@ -1668,12 +1668,12 @@ static int qemu_rdma_block_for_wrid(RDMAContext *rdma, while (1) { ret = qemu_rdma_wait_comp_channel(rdma, ch); - if (ret) { + if (ret < 0) { goto err_block_for_wrid; } ret = ibv_get_cq_event(ch, &cq, &cq_ctx); - if (ret) { + if (ret < 0) { /* * FIXME perror() is problematic, because ibv_reg_mr() is * not documented to set errno. Will go away later in @@ -1911,7 +1911,7 @@ static int qemu_rdma_exchange_send(RDMAContext *rdma, RDMAControlHeader *head, */ if (resp) { ret = qemu_rdma_post_recv_control(rdma, RDMA_WRID_DATA); - if (ret) { + if (ret < 0) { error_report("rdma migration: error posting" " extra control recv for anticipated result!"); return -1; @@ -1922,7 +1922,7 @@ static int qemu_rdma_exchange_send(RDMAContext *rdma, RDMAControlHeader *head, * Post a WR to replace the one we just consumed for the READY message. */ ret = qemu_rdma_post_recv_control(rdma, RDMA_WRID_READY); - if (ret) { + if (ret < 0) { error_report("rdma migration: error posting first control recv!"); return -1; } @@ -2009,7 +2009,7 @@ static int qemu_rdma_exchange_recv(RDMAContext *rdma, RDMAControlHeader *head, * Post a new RECV work request to replace the one we just consumed. */ ret = qemu_rdma_post_recv_control(rdma, RDMA_WRID_READY); - if (ret) { + if (ret < 0) { error_report("rdma migration: error posting second control recv!"); return -1; } @@ -2357,7 +2357,7 @@ static int qemu_rdma_write(RDMAContext *rdma, /* If we cannot merge it, we flush the current buffer first. */ if (!qemu_rdma_buffer_mergeable(rdma, current_addr, len)) { ret = qemu_rdma_write_flush(rdma); - if (ret) { + if (ret < 0) { return -1; } rdma->current_length = 0; @@ -2487,12 +2487,12 @@ static int qemu_rdma_source_init(RDMAContext *rdma, bool pin_all, Error **errp) rdma->pin_all = pin_all; ret = qemu_rdma_resolve_host(rdma, errp); - if (ret) { + if (ret < 0) { goto err_rdma_source_init; } ret = qemu_rdma_alloc_pd_cq(rdma); - if (ret) { + if (ret < 0) { ERROR(errp, "rdma migration: error allocating pd and cq! Your mlock()" " limits may be too low. Please check $ ulimit -a # and " "search for 'ulimit -l' in the output"); @@ -2500,7 +2500,7 @@ static int qemu_rdma_source_init(RDMAContext *rdma, bool pin_all, Error **errp) } ret = qemu_rdma_alloc_qp(rdma); - if (ret) { + if (ret < 0) { ERROR(errp, "rdma migration: error allocating qp!"); goto err_rdma_source_init; } @@ -2517,7 +2517,7 @@ static int qemu_rdma_source_init(RDMAContext *rdma, bool pin_all, Error **errp) for (idx = 0; idx < RDMA_WRID_MAX; idx++) { ret = qemu_rdma_reg_control(rdma, idx); - if (ret) { + if (ret < 0) { ERROR(errp, "rdma migration: error registering %d control!", idx); goto err_rdma_source_init; @@ -2591,13 +2591,13 @@ static int qemu_rdma_connect(RDMAContext *rdma, bool return_path, caps_to_network(&cap); ret = qemu_rdma_post_recv_control(rdma, RDMA_WRID_READY); - if (ret) { + if (ret < 0) { ERROR(errp, "posting second control recv"); goto err_rdma_source_connect; } ret = rdma_connect(rdma->cm_id, &conn_param); - if (ret) { + if (ret < 0) { perror("rdma_connect"); ERROR(errp, "connecting to destination!"); goto err_rdma_source_connect; @@ -2611,7 +2611,7 @@ static int qemu_rdma_connect(RDMAContext *rdma, bool return_path, ERROR(errp, "failed to get cm event"); } } - if (ret) { + if (ret < 0) { /* * FIXME perror() is wrong, because * qemu_get_cm_event_timeout() can fail without setting errno. @@ -2684,7 +2684,7 @@ static int qemu_rdma_dest_init(RDMAContext *rdma, Error **errp) /* create CM id */ ret = rdma_create_id(rdma->channel, &listen_id, NULL, RDMA_PS_TCP); - if (ret) { + if (ret < 0) { ERROR(errp, "could not create cm_id!"); goto err_dest_init_create_listen_id; } @@ -2700,7 +2700,7 @@ static int qemu_rdma_dest_init(RDMAContext *rdma, Error **errp) ret = rdma_set_option(listen_id, RDMA_OPTION_ID, RDMA_OPTION_ID_REUSEADDR, &reuse, sizeof reuse); - if (ret) { + if (ret < 0) { ERROR(errp, "Error: could not set REUSEADDR option"); goto err_dest_init_bind_addr; } @@ -2709,12 +2709,12 @@ static int qemu_rdma_dest_init(RDMAContext *rdma, Error **errp) &((struct sockaddr_in *) e->ai_dst_addr)->sin_addr, ip, sizeof ip); trace_qemu_rdma_dest_init_trying(rdma->host, ip); ret = rdma_bind_addr(listen_id, e->ai_dst_addr); - if (ret) { + if (ret < 0) { continue; } if (e->ai_family == AF_INET6) { ret = qemu_rdma_broken_ipv6_kernel(listen_id->verbs, errp); - if (ret) { + if (ret < 0) { continue; } } @@ -3342,7 +3342,7 @@ static void rdma_cm_poll_handler(void *opaque) MigrationIncomingState *mis = migration_incoming_get_current(); ret = rdma_get_cm_event(rdma->channel, &cm_event); - if (ret) { + if (ret < 0) { error_report("get_cm_event failed %d", errno); return; } @@ -3382,7 +3382,7 @@ static int qemu_rdma_accept(RDMAContext *rdma) int idx; ret = rdma_get_cm_event(rdma->channel, &cm_event); - if (ret) { + if (ret < 0) { goto err_rdma_dest_wait; } @@ -3452,13 +3452,13 @@ static int qemu_rdma_accept(RDMAContext *rdma) qemu_rdma_dump_id("dest_init", verbs); ret = qemu_rdma_alloc_pd_cq(rdma); - if (ret) { + if (ret < 0) { error_report("rdma migration: error allocating pd and cq!"); goto err_rdma_dest_wait; } ret = qemu_rdma_alloc_qp(rdma); - if (ret) { + if (ret < 0) { error_report("rdma migration: error allocating qp!"); goto err_rdma_dest_wait; } @@ -3467,7 +3467,7 @@ static int qemu_rdma_accept(RDMAContext *rdma) for (idx = 0; idx < RDMA_WRID_MAX; idx++) { ret = qemu_rdma_reg_control(rdma, idx); - if (ret) { + if (ret < 0) { error_report("rdma: error registering %d control", idx); goto err_rdma_dest_wait; } @@ -3485,13 +3485,13 @@ static int qemu_rdma_accept(RDMAContext *rdma) } ret = rdma_accept(rdma->cm_id, &conn_param); - if (ret) { + if (ret < 0) { error_report("rdma_accept failed"); goto err_rdma_dest_wait; } ret = rdma_get_cm_event(rdma->channel, &cm_event); - if (ret) { + if (ret < 0) { error_report("rdma_accept get_cm_event failed"); goto err_rdma_dest_wait; } @@ -3506,7 +3506,7 @@ static int qemu_rdma_accept(RDMAContext *rdma) rdma->connected = true; ret = qemu_rdma_post_recv_control(rdma, RDMA_WRID_READY); - if (ret) { + if (ret < 0) { error_report("rdma migration: error posting second control recv"); goto err_rdma_dest_wait; } @@ -3635,7 +3635,7 @@ static int qemu_rdma_registration_handle(QEMUFile *f) if (rdma->pin_all) { ret = qemu_rdma_reg_whole_ram_blocks(rdma); - if (ret) { + if (ret < 0) { error_report("rdma migration: error dest " "registering ram blocks"); goto err; @@ -4096,7 +4096,7 @@ static void rdma_accept_incoming_migration(void *opaque) trace_qemu_rdma_accept_incoming_migration(); ret = qemu_rdma_accept(rdma); - if (ret) { + if (ret < 0) { fprintf(stderr, "RDMA ERROR: Migration initialization failed\n"); return; } @@ -4140,7 +4140,7 @@ void rdma_start_incoming_migration(const char *host_port, Error **errp) } ret = qemu_rdma_dest_init(rdma, errp); - if (ret) { + if (ret < 0) { goto err; } @@ -4148,7 +4148,7 @@ void rdma_start_incoming_migration(const char *host_port, Error **errp) ret = rdma_listen(rdma->listen_id, 5); - if (ret) { + if (ret < 0) { ERROR(errp, "listening on socket!"); goto cleanup_rdma; } @@ -4190,14 +4190,14 @@ void rdma_start_outgoing_migration(void *opaque, ret = qemu_rdma_source_init(rdma, migrate_rdma_pin_all(), errp); - if (ret) { + if (ret < 0) { goto err; } trace_rdma_start_outgoing_migration_after_rdma_source_init(); ret = qemu_rdma_connect(rdma, false, errp); - if (ret) { + if (ret < 0) { goto err; } @@ -4212,13 +4212,13 @@ void rdma_start_outgoing_migration(void *opaque, ret = qemu_rdma_source_init(rdma_return_path, migrate_rdma_pin_all(), errp); - if (ret) { + if (ret < 0) { goto return_path_err; } ret = qemu_rdma_connect(rdma_return_path, true, errp); - if (ret) { + if (ret < 0) { goto return_path_err; } From e518b0050d41adf764aa06373acf0fbd696b8a0e Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Thu, 28 Sep 2023 15:19:56 +0200 Subject: [PATCH 0481/1077] migration/rdma: Plug a memory leak and improve a message When migration capability @rdma-pin-all is true, but the server cannot honor it, qemu_rdma_connect() calls macro ERROR(), then returns success. ERROR() sets an error. Since qemu_rdma_connect() returns success, its caller rdma_start_outgoing_migration() duly assumes @errp is still clear. The Error object leaks. ERROR() additionally reports the situation to the user as an error: RDMA ERROR: Server cannot support pinning all memory. Will register memory dynamically. Is this an error or not? It actually isn't; we disable @rdma-pin-all and carry on. "Correcting" the user's configuration decisions that way feels problematic, but that's a topic for another day. Replace ERROR() by warn_report(). This plugs the memory leak, and emits a clearer message to the user. Signed-off-by: Markus Armbruster Reviewed-by: Li Zhijian Reviewed-by: Juan Quintela Signed-off-by: Juan Quintela Message-ID: <20230928132019.2544702-31-armbru@redhat.com> --- migration/rdma.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/migration/rdma.c b/migration/rdma.c index b0125b01cf..00e3c430f4 100644 --- a/migration/rdma.c +++ b/migration/rdma.c @@ -2637,8 +2637,8 @@ static int qemu_rdma_connect(RDMAContext *rdma, bool return_path, * and disable them otherwise. */ if (rdma->pin_all && !(cap.flags & RDMA_CAPABILITY_PIN_ALL)) { - ERROR(errp, "Server cannot support pinning all memory. " - "Will register memory dynamically."); + warn_report("RDMA: Server cannot support pinning all memory. " + "Will register memory dynamically."); rdma->pin_all = false; } From 1718f238d1ee3c40496a36d6e4dc88ad21a04896 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Thu, 28 Sep 2023 15:19:57 +0200 Subject: [PATCH 0482/1077] migration/rdma: Delete inappropriate error_report() in macro ERROR() Functions that use an Error **errp parameter to return errors should not also report them to the user, because reporting is the caller's job. When the caller does, the error is reported twice. When it doesn't (because it recovered from the error), there is no error to report, i.e. the report is bogus. Macro ERROR() violates this principle. Delete the error_report() there. Signed-off-by: Markus Armbruster Reviewed-by: Li Zhijian Tested-by: Li Zhijian Reviewed-by: Juan Quintela Signed-off-by: Juan Quintela Message-ID: <20230928132019.2544702-32-armbru@redhat.com> --- migration/rdma.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/migration/rdma.c b/migration/rdma.c index 00e3c430f4..6c0e6cda2c 100644 --- a/migration/rdma.c +++ b/migration/rdma.c @@ -40,12 +40,8 @@ #include "options.h" #include -/* - * Print and error on both the Monitor and the Log file. - */ #define ERROR(errp, fmt, ...) \ do { \ - fprintf(stderr, "RDMA ERROR: " fmt "\n", ## __VA_ARGS__); \ if (errp && (*(errp) == NULL)) { \ error_setg(errp, "RDMA ERROR: " fmt, ## __VA_ARGS__); \ } \ From 8fd471bd777d70dce7826c2b903e0e791ead764e Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Thu, 28 Sep 2023 15:19:58 +0200 Subject: [PATCH 0483/1077] migration/rdma: Retire macro ERROR() ERROR() has become "error_setg() unless an error has been set already". Hiding the conditional in the macro is in the way of further work. Replace the macro uses by their expansion, and delete the macro. Signed-off-by: Markus Armbruster Reviewed-by: Li Zhijian Reviewed-by: Juan Quintela Signed-off-by: Juan Quintela Message-ID: <20230928132019.2544702-33-armbru@redhat.com> --- migration/rdma.c | 168 +++++++++++++++++++++++++++++++++-------------- 1 file changed, 120 insertions(+), 48 deletions(-) diff --git a/migration/rdma.c b/migration/rdma.c index 6c0e6cda2c..4074509f06 100644 --- a/migration/rdma.c +++ b/migration/rdma.c @@ -40,13 +40,6 @@ #include "options.h" #include -#define ERROR(errp, fmt, ...) \ - do { \ - if (errp && (*(errp) == NULL)) { \ - error_setg(errp, "RDMA ERROR: " fmt, ## __VA_ARGS__); \ - } \ - } while (0) - #define RDMA_RESOLVE_TIMEOUT_MS 10000 /* Do not merge data if larger than this. */ @@ -865,7 +858,10 @@ static int qemu_rdma_broken_ipv6_kernel(struct ibv_context *verbs, Error **errp) if (ibv_query_port(verbs, 1, &port_attr)) { ibv_close_device(verbs); - ERROR(errp, "Could not query initial IB port"); + if (errp && !*errp) { + error_setg(errp, + "RDMA ERROR: Could not query initial IB port"); + } return -1; } @@ -888,9 +884,12 @@ static int qemu_rdma_broken_ipv6_kernel(struct ibv_context *verbs, Error **errp) " migrate over the IB fabric until the kernel " " fixes the bug.\n"); } else { - ERROR(errp, "You only have RoCE / iWARP devices in your systems" - " and your management software has specified '[::]'" - ", but IPv6 over RoCE / iWARP is not supported in Linux."); + if (errp && !*errp) { + error_setg(errp, "RDMA ERROR: " + "You only have RoCE / iWARP devices in your systems" + " and your management software has specified '[::]'" + ", but IPv6 over RoCE / iWARP is not supported in Linux."); + } return -1; } } @@ -906,13 +905,18 @@ static int qemu_rdma_broken_ipv6_kernel(struct ibv_context *verbs, Error **errp) /* IB ports start with 1, not 0 */ if (ibv_query_port(verbs, 1, &port_attr)) { - ERROR(errp, "Could not query initial IB port"); + if (errp && !*errp) { + error_setg(errp, "RDMA ERROR: Could not query initial IB port"); + } return -1; } if (port_attr.link_layer == IBV_LINK_LAYER_ETHERNET) { - ERROR(errp, "Linux kernel's RoCE / iWARP does not support IPv6 " - "(but patches on linux-rdma in progress)"); + if (errp && !*errp) { + error_setg(errp, "RDMA ERROR: " + "Linux kernel's RoCE / iWARP does not support IPv6 " + "(but patches on linux-rdma in progress)"); + } return -1; } @@ -936,21 +940,27 @@ static int qemu_rdma_resolve_host(RDMAContext *rdma, Error **errp) struct rdma_addrinfo *e; if (rdma->host == NULL || !strcmp(rdma->host, "")) { - ERROR(errp, "RDMA hostname has not been set"); + if (errp && !*errp) { + error_setg(errp, "RDMA ERROR: RDMA hostname has not been set"); + } return -1; } /* create CM channel */ rdma->channel = rdma_create_event_channel(); if (!rdma->channel) { - ERROR(errp, "could not create CM channel"); + if (errp && !*errp) { + error_setg(errp, "RDMA ERROR: could not create CM channel"); + } return -1; } /* create CM id */ ret = rdma_create_id(rdma->channel, &rdma->cm_id, NULL, RDMA_PS_TCP); if (ret < 0) { - ERROR(errp, "could not create channel id"); + if (errp && !*errp) { + error_setg(errp, "RDMA ERROR: could not create channel id"); + } goto err_resolve_create_id; } @@ -959,7 +969,10 @@ static int qemu_rdma_resolve_host(RDMAContext *rdma, Error **errp) ret = rdma_getaddrinfo(rdma->host, port_str, NULL, &res); if (ret) { - ERROR(errp, "could not rdma_getaddrinfo address %s", rdma->host); + if (errp && !*errp) { + error_setg(errp, "RDMA ERROR: could not rdma_getaddrinfo address %s", + rdma->host); + } goto err_resolve_get_addr; } @@ -982,7 +995,10 @@ static int qemu_rdma_resolve_host(RDMAContext *rdma, Error **errp) } rdma_freeaddrinfo(res); - ERROR(errp, "could not resolve address %s", rdma->host); + if (errp && !*errp) { + error_setg(errp, "RDMA ERROR: could not resolve address %s", + rdma->host); + } goto err_resolve_get_addr; route: @@ -991,13 +1007,18 @@ route: ret = rdma_get_cm_event(rdma->channel, &cm_event); if (ret < 0) { - ERROR(errp, "could not perform event_addr_resolved"); + if (errp && !*errp) { + error_setg(errp, "RDMA ERROR: could not perform event_addr_resolved"); + } goto err_resolve_get_addr; } if (cm_event->event != RDMA_CM_EVENT_ADDR_RESOLVED) { - ERROR(errp, "result not equal to event_addr_resolved %s", - rdma_event_str(cm_event->event)); + if (errp && !*errp) { + error_setg(errp, + "RDMA ERROR: result not equal to event_addr_resolved %s", + rdma_event_str(cm_event->event)); + } error_report("rdma_resolve_addr"); rdma_ack_cm_event(cm_event); goto err_resolve_get_addr; @@ -1007,18 +1028,25 @@ route: /* resolve route */ ret = rdma_resolve_route(rdma->cm_id, RDMA_RESOLVE_TIMEOUT_MS); if (ret < 0) { - ERROR(errp, "could not resolve rdma route"); + if (errp && !*errp) { + error_setg(errp, "RDMA ERROR: could not resolve rdma route"); + } goto err_resolve_get_addr; } ret = rdma_get_cm_event(rdma->channel, &cm_event); if (ret < 0) { - ERROR(errp, "could not perform event_route_resolved"); + if (errp && !*errp) { + error_setg(errp, "RDMA ERROR: could not perform event_route_resolved"); + } goto err_resolve_get_addr; } if (cm_event->event != RDMA_CM_EVENT_ROUTE_RESOLVED) { - ERROR(errp, "result not equal to event_route_resolved: %s", - rdma_event_str(cm_event->event)); + if (errp && !*errp) { + error_setg(errp, "RDMA ERROR: " + "result not equal to event_route_resolved: %s", + rdma_event_str(cm_event->event)); + } rdma_ack_cm_event(cm_event); goto err_resolve_get_addr; } @@ -2489,15 +2517,20 @@ static int qemu_rdma_source_init(RDMAContext *rdma, bool pin_all, Error **errp) ret = qemu_rdma_alloc_pd_cq(rdma); if (ret < 0) { - ERROR(errp, "rdma migration: error allocating pd and cq! Your mlock()" - " limits may be too low. Please check $ ulimit -a # and " - "search for 'ulimit -l' in the output"); + if (errp && !*errp) { + error_setg(errp, "RDMA ERROR: " + "rdma migration: error allocating pd and cq! Your mlock()" + " limits may be too low. Please check $ ulimit -a # and " + "search for 'ulimit -l' in the output"); + } goto err_rdma_source_init; } ret = qemu_rdma_alloc_qp(rdma); if (ret < 0) { - ERROR(errp, "rdma migration: error allocating qp!"); + if (errp && !*errp) { + error_setg(errp, "RDMA ERROR: rdma migration: error allocating qp!"); + } goto err_rdma_source_init; } @@ -2514,8 +2547,11 @@ static int qemu_rdma_source_init(RDMAContext *rdma, bool pin_all, Error **errp) for (idx = 0; idx < RDMA_WRID_MAX; idx++) { ret = qemu_rdma_reg_control(rdma, idx); if (ret < 0) { - ERROR(errp, "rdma migration: error registering %d control!", - idx); + if (errp && !*errp) { + error_setg(errp, + "RDMA ERROR: rdma migration: error registering %d control!", + idx); + } goto err_rdma_source_init; } } @@ -2543,19 +2579,29 @@ static int qemu_get_cm_event_timeout(RDMAContext *rdma, } while (ret < 0 && errno == EINTR); if (ret == 0) { - ERROR(errp, "poll cm event timeout"); + if (errp && !*errp) { + error_setg(errp, "RDMA ERROR: poll cm event timeout"); + } return -1; } else if (ret < 0) { - ERROR(errp, "failed to poll cm event, errno=%i", errno); + if (errp && !*errp) { + error_setg(errp, "RDMA ERROR: failed to poll cm event, errno=%i", + errno); + } return -1; } else if (poll_fd.revents & POLLIN) { if (rdma_get_cm_event(rdma->channel, cm_event) < 0) { - ERROR(errp, "failed to get cm event"); + if (errp && !*errp) { + error_setg(errp, "RDMA ERROR: failed to get cm event"); + } return -1; } return 0; } else { - ERROR(errp, "no POLLIN event, revent=%x", poll_fd.revents); + if (errp && !*errp) { + error_setg(errp, "RDMA ERROR: no POLLIN event, revent=%x", + poll_fd.revents); + } return -1; } } @@ -2588,14 +2634,18 @@ static int qemu_rdma_connect(RDMAContext *rdma, bool return_path, ret = qemu_rdma_post_recv_control(rdma, RDMA_WRID_READY); if (ret < 0) { - ERROR(errp, "posting second control recv"); + if (errp && !*errp) { + error_setg(errp, "RDMA ERROR: posting second control recv"); + } goto err_rdma_source_connect; } ret = rdma_connect(rdma->cm_id, &conn_param); if (ret < 0) { perror("rdma_connect"); - ERROR(errp, "connecting to destination!"); + if (errp && !*errp) { + error_setg(errp, "RDMA ERROR: connecting to destination!"); + } goto err_rdma_source_connect; } @@ -2604,7 +2654,9 @@ static int qemu_rdma_connect(RDMAContext *rdma, bool return_path, } else { ret = rdma_get_cm_event(rdma->channel, &cm_event); if (ret < 0) { - ERROR(errp, "failed to get cm event"); + if (errp && !*errp) { + error_setg(errp, "RDMA ERROR: failed to get cm event"); + } } } if (ret < 0) { @@ -2619,7 +2671,9 @@ static int qemu_rdma_connect(RDMAContext *rdma, bool return_path, if (cm_event->event != RDMA_CM_EVENT_ESTABLISHED) { error_report("rdma_get_cm_event != EVENT_ESTABLISHED after rdma_connect"); - ERROR(errp, "connecting to destination!"); + if (errp && !*errp) { + error_setg(errp, "RDMA ERROR: connecting to destination!"); + } rdma_ack_cm_event(cm_event); goto err_rdma_source_connect; } @@ -2666,14 +2720,18 @@ static int qemu_rdma_dest_init(RDMAContext *rdma, Error **errp) } if (!rdma->host || !rdma->host[0]) { - ERROR(errp, "RDMA host is not set!"); + if (errp && !*errp) { + error_setg(errp, "RDMA ERROR: RDMA host is not set!"); + } rdma->errored = true; return -1; } /* create CM channel */ rdma->channel = rdma_create_event_channel(); if (!rdma->channel) { - ERROR(errp, "could not create rdma event channel"); + if (errp && !*errp) { + error_setg(errp, "RDMA ERROR: could not create rdma event channel"); + } rdma->errored = true; return -1; } @@ -2681,7 +2739,9 @@ static int qemu_rdma_dest_init(RDMAContext *rdma, Error **errp) /* create CM id */ ret = rdma_create_id(rdma->channel, &listen_id, NULL, RDMA_PS_TCP); if (ret < 0) { - ERROR(errp, "could not create cm_id!"); + if (errp && !*errp) { + error_setg(errp, "RDMA ERROR: could not create cm_id!"); + } goto err_dest_init_create_listen_id; } @@ -2690,14 +2750,19 @@ static int qemu_rdma_dest_init(RDMAContext *rdma, Error **errp) ret = rdma_getaddrinfo(rdma->host, port_str, NULL, &res); if (ret) { - ERROR(errp, "could not rdma_getaddrinfo address %s", rdma->host); + if (errp && !*errp) { + error_setg(errp, "RDMA ERROR: could not rdma_getaddrinfo address %s", + rdma->host); + } goto err_dest_init_bind_addr; } ret = rdma_set_option(listen_id, RDMA_OPTION_ID, RDMA_OPTION_ID_REUSEADDR, &reuse, sizeof reuse); if (ret < 0) { - ERROR(errp, "Error: could not set REUSEADDR option"); + if (errp && !*errp) { + error_setg(errp, "RDMA ERROR: Error: could not set REUSEADDR option"); + } goto err_dest_init_bind_addr; } for (e = res; e != NULL; e = e->ai_next) { @@ -2719,7 +2784,9 @@ static int qemu_rdma_dest_init(RDMAContext *rdma, Error **errp) rdma_freeaddrinfo(res); if (!e) { - ERROR(errp, "Error: could not rdma_bind_addr!"); + if (errp && !*errp) { + error_setg(errp, "RDMA ERROR: Error: could not rdma_bind_addr!"); + } goto err_dest_init_bind_addr; } @@ -2771,7 +2838,10 @@ static RDMAContext *qemu_rdma_data_init(const char *host_port, Error **errp) rdma->host = g_strdup(addr->host); rdma->host_port = g_strdup(host_port); } else { - ERROR(errp, "bad RDMA migration address '%s'", host_port); + if (errp && !*errp) { + error_setg(errp, "RDMA ERROR: bad RDMA migration address '%s'", + host_port); + } g_free(rdma); rdma = NULL; } @@ -4145,7 +4215,9 @@ void rdma_start_incoming_migration(const char *host_port, Error **errp) ret = rdma_listen(rdma->listen_id, 5); if (ret < 0) { - ERROR(errp, "listening on socket!"); + if (errp && !*errp) { + error_setg(errp, "RDMA ERROR: listening on socket!"); + } goto cleanup_rdma; } From 071d5ae4f35c4d4b80553feaa3786b9ff7a32b02 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Thu, 28 Sep 2023 15:19:59 +0200 Subject: [PATCH 0484/1077] migration/rdma: Fix error handling around rdma_getaddrinfo() qemu_rdma_resolve_host() and qemu_rdma_dest_init() iterate over addresses to find one that works, holding onto the first Error from qemu_rdma_broken_ipv6_kernel() for use when no address works. Issues: 1. If @errp was &error_abort or &error_fatal, we'd terminate instead of trying the next address. Can't actually happen, since no caller passes these arguments. 2. When @errp is a pointer to a variable containing NULL, and qemu_rdma_broken_ipv6_kernel() fails, the variable no longer contains NULL. Subsequent iterations pass it again, violating Error usage rules. Dangerous, as setting an error would then trip error_setv()'s assertion. Works only because qemu_rdma_broken_ipv6_kernel() and the code following the loops carefully avoids setting a second error. 3. If qemu_rdma_broken_ipv6_kernel() fails, and then a later iteration finds a working address, @errp still holds the first error from qemu_rdma_broken_ipv6_kernel(). If we then run into another error, we report the qemu_rdma_broken_ipv6_kernel() failure instead. 4. If we don't run into another error, we leak the Error object. Use a local error variable, and propagate to @errp. This fixes 3. and also cleans up 1 and partly 2. Free this error when we have a working address. This fixes 4. Pass the local error variable to qemu_rdma_broken_ipv6_kernel() only until it fails. Pass null on any later iterations. This cleans up the remainder of 2. Signed-off-by: Markus Armbruster Reviewed-by: Li Zhijian Reviewed-by: Juan Quintela Signed-off-by: Juan Quintela Message-ID: <20230928132019.2544702-34-armbru@redhat.com> --- migration/rdma.c | 25 +++++++++++++++++++++---- 1 file changed, 21 insertions(+), 4 deletions(-) diff --git a/migration/rdma.c b/migration/rdma.c index 4074509f06..3fb899f963 100644 --- a/migration/rdma.c +++ b/migration/rdma.c @@ -932,6 +932,7 @@ static int qemu_rdma_broken_ipv6_kernel(struct ibv_context *verbs, Error **errp) */ static int qemu_rdma_resolve_host(RDMAContext *rdma, Error **errp) { + Error *err = NULL; int ret; struct rdma_addrinfo *res; char port_str[16]; @@ -976,7 +977,10 @@ static int qemu_rdma_resolve_host(RDMAContext *rdma, Error **errp) goto err_resolve_get_addr; } + /* Try all addresses, saving the first error in @err */ for (e = res; e != NULL; e = e->ai_next) { + Error **local_errp = err ? NULL : &err; + inet_ntop(e->ai_family, &((struct sockaddr_in *) e->ai_dst_addr)->sin_addr, ip, sizeof ip); trace_qemu_rdma_resolve_host_trying(rdma->host, ip); @@ -985,17 +989,21 @@ static int qemu_rdma_resolve_host(RDMAContext *rdma, Error **errp) RDMA_RESOLVE_TIMEOUT_MS); if (ret >= 0) { if (e->ai_family == AF_INET6) { - ret = qemu_rdma_broken_ipv6_kernel(rdma->cm_id->verbs, errp); + ret = qemu_rdma_broken_ipv6_kernel(rdma->cm_id->verbs, + local_errp); if (ret < 0) { continue; } } + error_free(err); goto route; } } rdma_freeaddrinfo(res); - if (errp && !*errp) { + if (err) { + error_propagate(errp, err); + } else { error_setg(errp, "RDMA ERROR: could not resolve address %s", rdma->host); } @@ -2707,6 +2715,7 @@ err_rdma_source_connect: static int qemu_rdma_dest_init(RDMAContext *rdma, Error **errp) { + Error *err = NULL; int ret, idx; struct rdma_cm_id *listen_id; char ip[40] = "unknown"; @@ -2765,7 +2774,11 @@ static int qemu_rdma_dest_init(RDMAContext *rdma, Error **errp) } goto err_dest_init_bind_addr; } + + /* Try all addresses, saving the first error in @err */ for (e = res; e != NULL; e = e->ai_next) { + Error **local_errp = err ? NULL : &err; + inet_ntop(e->ai_family, &((struct sockaddr_in *) e->ai_dst_addr)->sin_addr, ip, sizeof ip); trace_qemu_rdma_dest_init_trying(rdma->host, ip); @@ -2774,17 +2787,21 @@ static int qemu_rdma_dest_init(RDMAContext *rdma, Error **errp) continue; } if (e->ai_family == AF_INET6) { - ret = qemu_rdma_broken_ipv6_kernel(listen_id->verbs, errp); + ret = qemu_rdma_broken_ipv6_kernel(listen_id->verbs, + local_errp); if (ret < 0) { continue; } } + error_free(err); break; } rdma_freeaddrinfo(res); if (!e) { - if (errp && !*errp) { + if (err) { + error_propagate(errp, err); + } else { error_setg(errp, "RDMA ERROR: Error: could not rdma_bind_addr!"); } goto err_dest_init_bind_addr; From dcf07e72a4c929a06a5735e80b429f49b2278b9f Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Thu, 28 Sep 2023 15:20:00 +0200 Subject: [PATCH 0485/1077] migration/rdma: Drop "@errp is clear" guards around error_setg() These guards are all redundant now. Signed-off-by: Markus Armbruster Reviewed-by: Li Zhijian Reviewed-by: Juan Quintela Signed-off-by: Juan Quintela Message-ID: <20230928132019.2544702-35-armbru@redhat.com> --- migration/rdma.c | 164 +++++++++++++++-------------------------------- 1 file changed, 51 insertions(+), 113 deletions(-) diff --git a/migration/rdma.c b/migration/rdma.c index 3fb899f963..fdb527af39 100644 --- a/migration/rdma.c +++ b/migration/rdma.c @@ -858,10 +858,8 @@ static int qemu_rdma_broken_ipv6_kernel(struct ibv_context *verbs, Error **errp) if (ibv_query_port(verbs, 1, &port_attr)) { ibv_close_device(verbs); - if (errp && !*errp) { - error_setg(errp, - "RDMA ERROR: Could not query initial IB port"); - } + error_setg(errp, + "RDMA ERROR: Could not query initial IB port"); return -1; } @@ -884,12 +882,10 @@ static int qemu_rdma_broken_ipv6_kernel(struct ibv_context *verbs, Error **errp) " migrate over the IB fabric until the kernel " " fixes the bug.\n"); } else { - if (errp && !*errp) { - error_setg(errp, "RDMA ERROR: " - "You only have RoCE / iWARP devices in your systems" - " and your management software has specified '[::]'" - ", but IPv6 over RoCE / iWARP is not supported in Linux."); - } + error_setg(errp, "RDMA ERROR: " + "You only have RoCE / iWARP devices in your systems" + " and your management software has specified '[::]'" + ", but IPv6 over RoCE / iWARP is not supported in Linux."); return -1; } } @@ -905,18 +901,14 @@ static int qemu_rdma_broken_ipv6_kernel(struct ibv_context *verbs, Error **errp) /* IB ports start with 1, not 0 */ if (ibv_query_port(verbs, 1, &port_attr)) { - if (errp && !*errp) { - error_setg(errp, "RDMA ERROR: Could not query initial IB port"); - } + error_setg(errp, "RDMA ERROR: Could not query initial IB port"); return -1; } if (port_attr.link_layer == IBV_LINK_LAYER_ETHERNET) { - if (errp && !*errp) { - error_setg(errp, "RDMA ERROR: " - "Linux kernel's RoCE / iWARP does not support IPv6 " - "(but patches on linux-rdma in progress)"); - } + error_setg(errp, "RDMA ERROR: " + "Linux kernel's RoCE / iWARP does not support IPv6 " + "(but patches on linux-rdma in progress)"); return -1; } @@ -941,27 +933,21 @@ static int qemu_rdma_resolve_host(RDMAContext *rdma, Error **errp) struct rdma_addrinfo *e; if (rdma->host == NULL || !strcmp(rdma->host, "")) { - if (errp && !*errp) { - error_setg(errp, "RDMA ERROR: RDMA hostname has not been set"); - } + error_setg(errp, "RDMA ERROR: RDMA hostname has not been set"); return -1; } /* create CM channel */ rdma->channel = rdma_create_event_channel(); if (!rdma->channel) { - if (errp && !*errp) { - error_setg(errp, "RDMA ERROR: could not create CM channel"); - } + error_setg(errp, "RDMA ERROR: could not create CM channel"); return -1; } /* create CM id */ ret = rdma_create_id(rdma->channel, &rdma->cm_id, NULL, RDMA_PS_TCP); if (ret < 0) { - if (errp && !*errp) { - error_setg(errp, "RDMA ERROR: could not create channel id"); - } + error_setg(errp, "RDMA ERROR: could not create channel id"); goto err_resolve_create_id; } @@ -970,10 +956,8 @@ static int qemu_rdma_resolve_host(RDMAContext *rdma, Error **errp) ret = rdma_getaddrinfo(rdma->host, port_str, NULL, &res); if (ret) { - if (errp && !*errp) { - error_setg(errp, "RDMA ERROR: could not rdma_getaddrinfo address %s", - rdma->host); - } + error_setg(errp, "RDMA ERROR: could not rdma_getaddrinfo address %s", + rdma->host); goto err_resolve_get_addr; } @@ -1015,18 +999,14 @@ route: ret = rdma_get_cm_event(rdma->channel, &cm_event); if (ret < 0) { - if (errp && !*errp) { - error_setg(errp, "RDMA ERROR: could not perform event_addr_resolved"); - } + error_setg(errp, "RDMA ERROR: could not perform event_addr_resolved"); goto err_resolve_get_addr; } if (cm_event->event != RDMA_CM_EVENT_ADDR_RESOLVED) { - if (errp && !*errp) { - error_setg(errp, - "RDMA ERROR: result not equal to event_addr_resolved %s", - rdma_event_str(cm_event->event)); - } + error_setg(errp, + "RDMA ERROR: result not equal to event_addr_resolved %s", + rdma_event_str(cm_event->event)); error_report("rdma_resolve_addr"); rdma_ack_cm_event(cm_event); goto err_resolve_get_addr; @@ -1036,25 +1016,19 @@ route: /* resolve route */ ret = rdma_resolve_route(rdma->cm_id, RDMA_RESOLVE_TIMEOUT_MS); if (ret < 0) { - if (errp && !*errp) { - error_setg(errp, "RDMA ERROR: could not resolve rdma route"); - } + error_setg(errp, "RDMA ERROR: could not resolve rdma route"); goto err_resolve_get_addr; } ret = rdma_get_cm_event(rdma->channel, &cm_event); if (ret < 0) { - if (errp && !*errp) { - error_setg(errp, "RDMA ERROR: could not perform event_route_resolved"); - } + error_setg(errp, "RDMA ERROR: could not perform event_route_resolved"); goto err_resolve_get_addr; } if (cm_event->event != RDMA_CM_EVENT_ROUTE_RESOLVED) { - if (errp && !*errp) { - error_setg(errp, "RDMA ERROR: " - "result not equal to event_route_resolved: %s", - rdma_event_str(cm_event->event)); - } + error_setg(errp, "RDMA ERROR: " + "result not equal to event_route_resolved: %s", + rdma_event_str(cm_event->event)); rdma_ack_cm_event(cm_event); goto err_resolve_get_addr; } @@ -2525,20 +2499,16 @@ static int qemu_rdma_source_init(RDMAContext *rdma, bool pin_all, Error **errp) ret = qemu_rdma_alloc_pd_cq(rdma); if (ret < 0) { - if (errp && !*errp) { - error_setg(errp, "RDMA ERROR: " - "rdma migration: error allocating pd and cq! Your mlock()" - " limits may be too low. Please check $ ulimit -a # and " - "search for 'ulimit -l' in the output"); - } + error_setg(errp, "RDMA ERROR: " + "rdma migration: error allocating pd and cq! Your mlock()" + " limits may be too low. Please check $ ulimit -a # and " + "search for 'ulimit -l' in the output"); goto err_rdma_source_init; } ret = qemu_rdma_alloc_qp(rdma); if (ret < 0) { - if (errp && !*errp) { - error_setg(errp, "RDMA ERROR: rdma migration: error allocating qp!"); - } + error_setg(errp, "RDMA ERROR: rdma migration: error allocating qp!"); goto err_rdma_source_init; } @@ -2555,11 +2525,9 @@ static int qemu_rdma_source_init(RDMAContext *rdma, bool pin_all, Error **errp) for (idx = 0; idx < RDMA_WRID_MAX; idx++) { ret = qemu_rdma_reg_control(rdma, idx); if (ret < 0) { - if (errp && !*errp) { - error_setg(errp, - "RDMA ERROR: rdma migration: error registering %d control!", - idx); - } + error_setg(errp, + "RDMA ERROR: rdma migration: error registering %d control!", + idx); goto err_rdma_source_init; } } @@ -2587,29 +2555,21 @@ static int qemu_get_cm_event_timeout(RDMAContext *rdma, } while (ret < 0 && errno == EINTR); if (ret == 0) { - if (errp && !*errp) { - error_setg(errp, "RDMA ERROR: poll cm event timeout"); - } + error_setg(errp, "RDMA ERROR: poll cm event timeout"); return -1; } else if (ret < 0) { - if (errp && !*errp) { - error_setg(errp, "RDMA ERROR: failed to poll cm event, errno=%i", - errno); - } + error_setg(errp, "RDMA ERROR: failed to poll cm event, errno=%i", + errno); return -1; } else if (poll_fd.revents & POLLIN) { if (rdma_get_cm_event(rdma->channel, cm_event) < 0) { - if (errp && !*errp) { - error_setg(errp, "RDMA ERROR: failed to get cm event"); - } + error_setg(errp, "RDMA ERROR: failed to get cm event"); return -1; } return 0; } else { - if (errp && !*errp) { - error_setg(errp, "RDMA ERROR: no POLLIN event, revent=%x", - poll_fd.revents); - } + error_setg(errp, "RDMA ERROR: no POLLIN event, revent=%x", + poll_fd.revents); return -1; } } @@ -2642,18 +2602,14 @@ static int qemu_rdma_connect(RDMAContext *rdma, bool return_path, ret = qemu_rdma_post_recv_control(rdma, RDMA_WRID_READY); if (ret < 0) { - if (errp && !*errp) { - error_setg(errp, "RDMA ERROR: posting second control recv"); - } + error_setg(errp, "RDMA ERROR: posting second control recv"); goto err_rdma_source_connect; } ret = rdma_connect(rdma->cm_id, &conn_param); if (ret < 0) { perror("rdma_connect"); - if (errp && !*errp) { - error_setg(errp, "RDMA ERROR: connecting to destination!"); - } + error_setg(errp, "RDMA ERROR: connecting to destination!"); goto err_rdma_source_connect; } @@ -2662,9 +2618,7 @@ static int qemu_rdma_connect(RDMAContext *rdma, bool return_path, } else { ret = rdma_get_cm_event(rdma->channel, &cm_event); if (ret < 0) { - if (errp && !*errp) { - error_setg(errp, "RDMA ERROR: failed to get cm event"); - } + error_setg(errp, "RDMA ERROR: failed to get cm event"); } } if (ret < 0) { @@ -2679,9 +2633,7 @@ static int qemu_rdma_connect(RDMAContext *rdma, bool return_path, if (cm_event->event != RDMA_CM_EVENT_ESTABLISHED) { error_report("rdma_get_cm_event != EVENT_ESTABLISHED after rdma_connect"); - if (errp && !*errp) { - error_setg(errp, "RDMA ERROR: connecting to destination!"); - } + error_setg(errp, "RDMA ERROR: connecting to destination!"); rdma_ack_cm_event(cm_event); goto err_rdma_source_connect; } @@ -2729,18 +2681,14 @@ static int qemu_rdma_dest_init(RDMAContext *rdma, Error **errp) } if (!rdma->host || !rdma->host[0]) { - if (errp && !*errp) { - error_setg(errp, "RDMA ERROR: RDMA host is not set!"); - } + error_setg(errp, "RDMA ERROR: RDMA host is not set!"); rdma->errored = true; return -1; } /* create CM channel */ rdma->channel = rdma_create_event_channel(); if (!rdma->channel) { - if (errp && !*errp) { - error_setg(errp, "RDMA ERROR: could not create rdma event channel"); - } + error_setg(errp, "RDMA ERROR: could not create rdma event channel"); rdma->errored = true; return -1; } @@ -2748,9 +2696,7 @@ static int qemu_rdma_dest_init(RDMAContext *rdma, Error **errp) /* create CM id */ ret = rdma_create_id(rdma->channel, &listen_id, NULL, RDMA_PS_TCP); if (ret < 0) { - if (errp && !*errp) { - error_setg(errp, "RDMA ERROR: could not create cm_id!"); - } + error_setg(errp, "RDMA ERROR: could not create cm_id!"); goto err_dest_init_create_listen_id; } @@ -2759,19 +2705,15 @@ static int qemu_rdma_dest_init(RDMAContext *rdma, Error **errp) ret = rdma_getaddrinfo(rdma->host, port_str, NULL, &res); if (ret) { - if (errp && !*errp) { - error_setg(errp, "RDMA ERROR: could not rdma_getaddrinfo address %s", - rdma->host); - } + error_setg(errp, "RDMA ERROR: could not rdma_getaddrinfo address %s", + rdma->host); goto err_dest_init_bind_addr; } ret = rdma_set_option(listen_id, RDMA_OPTION_ID, RDMA_OPTION_ID_REUSEADDR, &reuse, sizeof reuse); if (ret < 0) { - if (errp && !*errp) { - error_setg(errp, "RDMA ERROR: Error: could not set REUSEADDR option"); - } + error_setg(errp, "RDMA ERROR: Error: could not set REUSEADDR option"); goto err_dest_init_bind_addr; } @@ -2855,10 +2797,8 @@ static RDMAContext *qemu_rdma_data_init(const char *host_port, Error **errp) rdma->host = g_strdup(addr->host); rdma->host_port = g_strdup(host_port); } else { - if (errp && !*errp) { - error_setg(errp, "RDMA ERROR: bad RDMA migration address '%s'", - host_port); - } + error_setg(errp, "RDMA ERROR: bad RDMA migration address '%s'", + host_port); g_free(rdma); rdma = NULL; } @@ -4232,9 +4172,7 @@ void rdma_start_incoming_migration(const char *host_port, Error **errp) ret = rdma_listen(rdma->listen_id, 5); if (ret < 0) { - if (errp && !*errp) { - error_setg(errp, "RDMA ERROR: listening on socket!"); - } + error_setg(errp, "RDMA ERROR: listening on socket!"); goto cleanup_rdma; } From 96f363d839f5fdae370afb9a9f843782dd1b38f8 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Thu, 28 Sep 2023 15:20:01 +0200 Subject: [PATCH 0486/1077] migration/rdma: Convert qemu_rdma_exchange_recv() to Error Functions that use an Error **errp parameter to return errors should not also report them to the user, because reporting is the caller's job. When the caller does, the error is reported twice. When it doesn't (because it recovered from the error), there is no error to report, i.e. the report is bogus. qio_channel_rdma_readv() violates this principle: it calls error_report() via qemu_rdma_exchange_recv(). I elected not to investigate how callers handle the error, i.e. precise impact is not known. Clean this up by converting qemu_rdma_exchange_recv() to Error. Necessitates setting an error when qemu_rdma_exchange_get_response() failed. Since this error will go away later in this series, simply use "FIXME temporary error message" there. Signed-off-by: Markus Armbruster Reviewed-by: Li Zhijian Reviewed-by: Juan Quintela Signed-off-by: Juan Quintela Message-ID: <20230928132019.2544702-36-armbru@redhat.com> --- migration/rdma.c | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/migration/rdma.c b/migration/rdma.c index fdb527af39..b13fec6328 100644 --- a/migration/rdma.c +++ b/migration/rdma.c @@ -1980,7 +1980,7 @@ static int qemu_rdma_exchange_send(RDMAContext *rdma, RDMAControlHeader *head, * control-channel message. */ static int qemu_rdma_exchange_recv(RDMAContext *rdma, RDMAControlHeader *head, - uint32_t expecting) + uint32_t expecting, Error **errp) { RDMAControlHeader ready = { .len = 0, @@ -1995,7 +1995,7 @@ static int qemu_rdma_exchange_recv(RDMAContext *rdma, RDMAControlHeader *head, ret = qemu_rdma_post_send_control(rdma, NULL, &ready); if (ret < 0) { - error_report("Failed to send control buffer!"); + error_setg(errp, "Failed to send control buffer!"); return -1; } @@ -2006,6 +2006,7 @@ static int qemu_rdma_exchange_recv(RDMAContext *rdma, RDMAControlHeader *head, expecting, RDMA_WRID_READY); if (ret < 0) { + error_setg(errp, "FIXME temporary error message"); return -1; } @@ -2016,7 +2017,7 @@ static int qemu_rdma_exchange_recv(RDMAContext *rdma, RDMAControlHeader *head, */ ret = qemu_rdma_post_recv_control(rdma, RDMA_WRID_READY); if (ret < 0) { - error_report("rdma migration: error posting second control recv!"); + error_setg(errp, "rdma migration: error posting second control recv!"); return -1; } @@ -2957,11 +2958,11 @@ static ssize_t qio_channel_rdma_readv(QIOChannel *ioc, /* We've got nothing at all, so lets wait for * more to arrive */ - ret = qemu_rdma_exchange_recv(rdma, &head, RDMA_CONTROL_QEMU_FILE); + ret = qemu_rdma_exchange_recv(rdma, &head, RDMA_CONTROL_QEMU_FILE, + errp); if (ret < 0) { rdma->errored = true; - error_setg(errp, "qemu_rdma_exchange_recv failed"); return -1; } @@ -3575,6 +3576,7 @@ static int qemu_rdma_registration_handle(QEMUFile *f) RDMAControlHeader blocks = { .type = RDMA_CONTROL_RAM_BLOCKS_RESULT, .repeat = 1 }; QIOChannelRDMA *rioc = QIO_CHANNEL_RDMA(qemu_file_get_ioc(f)); + Error *err = NULL; RDMAContext *rdma; RDMALocalBlocks *local; RDMAControlHeader head; @@ -3604,9 +3606,10 @@ static int qemu_rdma_registration_handle(QEMUFile *f) do { trace_qemu_rdma_registration_handle_wait(); - ret = qemu_rdma_exchange_recv(rdma, &head, RDMA_CONTROL_NONE); + ret = qemu_rdma_exchange_recv(rdma, &head, RDMA_CONTROL_NONE, &err); if (ret < 0) { + error_report_err(err); break; } From c4c78dce0b5ebf28c2b54a79905e44f47544aeee Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Thu, 28 Sep 2023 15:20:02 +0200 Subject: [PATCH 0487/1077] migration/rdma: Convert qemu_rdma_exchange_send() to Error Functions that use an Error **errp parameter to return errors should not also report them to the user, because reporting is the caller's job. When the caller does, the error is reported twice. When it doesn't (because it recovered from the error), there is no error to report, i.e. the report is bogus. qio_channel_rdma_writev() violates this principle: it calls error_report() via qemu_rdma_exchange_send(). I elected not to investigate how callers handle the error, i.e. precise impact is not known. Clean this up by converting qemu_rdma_exchange_send() to Error. Necessitates setting an error when qemu_rdma_post_recv_control(), callback(), or qemu_rdma_exchange_get_response() failed. Since these errors will go away later in this series, simply use "FIXME temporary error message" there. Signed-off-by: Markus Armbruster Reviewed-by: Li Zhijian Reviewed-by: Juan Quintela Signed-off-by: Juan Quintela Message-ID: <20230928132019.2544702-37-armbru@redhat.com> --- migration/rdma.c | 40 +++++++++++++++++++++++++++------------- 1 file changed, 27 insertions(+), 13 deletions(-) diff --git a/migration/rdma.c b/migration/rdma.c index b13fec6328..7866cf9bb7 100644 --- a/migration/rdma.c +++ b/migration/rdma.c @@ -518,7 +518,8 @@ static void network_to_result(RDMARegisterResult *result) static int qemu_rdma_exchange_send(RDMAContext *rdma, RDMAControlHeader *head, uint8_t *data, RDMAControlHeader *resp, int *resp_idx, - int (*callback)(RDMAContext *rdma)); + int (*callback)(RDMAContext *rdma), + Error **errp); static inline uint64_t ram_chunk_index(const uint8_t *start, const uint8_t *host) @@ -1376,6 +1377,8 @@ static int qemu_rdma_reg_control(RDMAContext *rdma, int idx) */ static int qemu_rdma_unregister_waiting(RDMAContext *rdma) { + Error *err = NULL; + while (rdma->unregistrations[rdma->unregister_current]) { int ret; uint64_t wr_id = rdma->unregistrations[rdma->unregister_current]; @@ -1438,8 +1441,9 @@ static int qemu_rdma_unregister_waiting(RDMAContext *rdma) reg.key.chunk = chunk; register_to_network(rdma, ®); ret = qemu_rdma_exchange_send(rdma, &head, (uint8_t *) ®, - &resp, NULL, NULL); + &resp, NULL, NULL, &err); if (ret < 0) { + error_report_err(err); return -1; } @@ -1893,7 +1897,8 @@ static void qemu_rdma_move_header(RDMAContext *rdma, int idx, static int qemu_rdma_exchange_send(RDMAContext *rdma, RDMAControlHeader *head, uint8_t *data, RDMAControlHeader *resp, int *resp_idx, - int (*callback)(RDMAContext *rdma)) + int (*callback)(RDMAContext *rdma), + Error **errp) { int ret; @@ -1908,6 +1913,7 @@ static int qemu_rdma_exchange_send(RDMAContext *rdma, RDMAControlHeader *head, RDMA_CONTROL_READY, RDMA_WRID_READY); if (ret < 0) { + error_setg(errp, "FIXME temporary error message"); return -1; } } @@ -1918,7 +1924,7 @@ static int qemu_rdma_exchange_send(RDMAContext *rdma, RDMAControlHeader *head, if (resp) { ret = qemu_rdma_post_recv_control(rdma, RDMA_WRID_DATA); if (ret < 0) { - error_report("rdma migration: error posting" + error_setg(errp, "rdma migration: error posting" " extra control recv for anticipated result!"); return -1; } @@ -1929,7 +1935,7 @@ static int qemu_rdma_exchange_send(RDMAContext *rdma, RDMAControlHeader *head, */ ret = qemu_rdma_post_recv_control(rdma, RDMA_WRID_READY); if (ret < 0) { - error_report("rdma migration: error posting first control recv!"); + error_setg(errp, "rdma migration: error posting first control recv!"); return -1; } @@ -1939,7 +1945,7 @@ static int qemu_rdma_exchange_send(RDMAContext *rdma, RDMAControlHeader *head, ret = qemu_rdma_post_send_control(rdma, data, head); if (ret < 0) { - error_report("Failed to send control buffer!"); + error_setg(errp, "Failed to send control buffer!"); return -1; } @@ -1951,6 +1957,7 @@ static int qemu_rdma_exchange_send(RDMAContext *rdma, RDMAControlHeader *head, trace_qemu_rdma_exchange_send_issue_callback(); ret = callback(rdma); if (ret < 0) { + error_setg(errp, "FIXME temporary error message"); return -1; } } @@ -1960,6 +1967,7 @@ static int qemu_rdma_exchange_send(RDMAContext *rdma, RDMAControlHeader *head, resp->type, RDMA_WRID_DATA); if (ret < 0) { + error_setg(errp, "FIXME temporary error message"); return -1; } @@ -2034,6 +2042,7 @@ static int qemu_rdma_write_one(RDMAContext *rdma, int current_index, uint64_t current_addr, uint64_t length) { + Error *err = NULL; struct ibv_sge sge; struct ibv_send_wr send_wr = { 0 }; struct ibv_send_wr *bad_wr; @@ -2119,9 +2128,10 @@ retry: compress_to_network(rdma, &comp); ret = qemu_rdma_exchange_send(rdma, &head, - (uint8_t *) &comp, NULL, NULL, NULL); + (uint8_t *) &comp, NULL, NULL, NULL, &err); if (ret < 0) { + error_report_err(err); return -1; } @@ -2156,8 +2166,9 @@ retry: register_to_network(rdma, ®); ret = qemu_rdma_exchange_send(rdma, &head, (uint8_t *) ®, - &resp, ®_result_idx, NULL); + &resp, ®_result_idx, NULL, &err); if (ret < 0) { + error_report_err(err); return -1; } @@ -2864,11 +2875,11 @@ static ssize_t qio_channel_rdma_writev(QIOChannel *ioc, head.len = len; head.type = RDMA_CONTROL_QEMU_FILE; - ret = qemu_rdma_exchange_send(rdma, &head, data, NULL, NULL, NULL); + ret = qemu_rdma_exchange_send(rdma, &head, + data, NULL, NULL, NULL, errp); if (ret < 0) { rdma->errored = true; - error_setg(errp, "qemu_rdma_exchange_send failed"); return -1; } @@ -3925,6 +3936,7 @@ static int qemu_rdma_registration_stop(QEMUFile *f, uint64_t flags, void *data) { QIOChannelRDMA *rioc = QIO_CHANNEL_RDMA(qemu_file_get_ioc(f)); + Error *err = NULL; RDMAContext *rdma; RDMAControlHeader head = { .len = 0, .repeat = 1 }; int ret; @@ -3968,9 +3980,10 @@ static int qemu_rdma_registration_stop(QEMUFile *f, */ ret = qemu_rdma_exchange_send(rdma, &head, NULL, &resp, ®_result_idx, rdma->pin_all ? - qemu_rdma_reg_whole_ram_blocks : NULL); + qemu_rdma_reg_whole_ram_blocks : NULL, + &err); if (ret < 0) { - fprintf(stderr, "receiving remote info!"); + error_report_err(err); return -1; } @@ -4021,9 +4034,10 @@ static int qemu_rdma_registration_stop(QEMUFile *f, trace_qemu_rdma_registration_stop(flags); head.type = RDMA_CONTROL_REGISTER_FINISHED; - ret = qemu_rdma_exchange_send(rdma, &head, NULL, NULL, NULL, NULL); + ret = qemu_rdma_exchange_send(rdma, &head, NULL, NULL, NULL, NULL, &err); if (ret < 0) { + error_report_err(err); goto err; } From 3765ec1f432065e451fe86c54b93fc19a49f0cf4 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Thu, 28 Sep 2023 15:20:03 +0200 Subject: [PATCH 0488/1077] migration/rdma: Convert qemu_rdma_exchange_get_response() to Error Functions that use an Error **errp parameter to return errors should not also report them to the user, because reporting is the caller's job. When the caller does, the error is reported twice. When it doesn't (because it recovered from the error), there is no error to report, i.e. the report is bogus. qemu_rdma_exchange_send() and qemu_rdma_exchange_recv() violate this principle: they call error_report() via qemu_rdma_exchange_get_response(). I elected not to investigate how callers handle the error, i.e. precise impact is not known. Clean this up by converting qemu_rdma_exchange_get_response() to Error. Signed-off-by: Markus Armbruster Reviewed-by: Li Zhijian Reviewed-by: Juan Quintela Signed-off-by: Juan Quintela Message-ID: <20230928132019.2544702-38-armbru@redhat.com> --- migration/rdma.c | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/migration/rdma.c b/migration/rdma.c index 7866cf9bb7..87f2e6129e 100644 --- a/migration/rdma.c +++ b/migration/rdma.c @@ -1824,14 +1824,15 @@ static int qemu_rdma_post_recv_control(RDMAContext *rdma, int idx) * Block and wait for a RECV control channel message to arrive. */ static int qemu_rdma_exchange_get_response(RDMAContext *rdma, - RDMAControlHeader *head, uint32_t expecting, int idx) + RDMAControlHeader *head, uint32_t expecting, int idx, + Error **errp) { uint32_t byte_len; int ret = qemu_rdma_block_for_wrid(rdma, RDMA_WRID_RECV_CONTROL + idx, &byte_len); if (ret < 0) { - error_report("rdma migration: recv polling control error!"); + error_setg(errp, "rdma migration: recv polling control error!"); return -1; } @@ -1844,7 +1845,7 @@ static int qemu_rdma_exchange_get_response(RDMAContext *rdma, trace_qemu_rdma_exchange_get_response_none(control_desc(head->type), head->type); } else if (head->type != expecting || head->type == RDMA_CONTROL_ERROR) { - error_report("Was expecting a %s (%d) control message" + error_setg(errp, "Was expecting a %s (%d) control message" ", but got: %s (%d), length: %d", control_desc(expecting), expecting, control_desc(head->type), head->type, head->len); @@ -1854,11 +1855,12 @@ static int qemu_rdma_exchange_get_response(RDMAContext *rdma, return -1; } if (head->len > RDMA_CONTROL_MAX_BUFFER - sizeof(*head)) { - error_report("too long length: %d", head->len); + error_setg(errp, "too long length: %d", head->len); return -1; } if (sizeof(*head) + head->len != byte_len) { - error_report("Malformed length: %d byte_len %d", head->len, byte_len); + error_setg(errp, "Malformed length: %d byte_len %d", + head->len, byte_len); return -1; } @@ -1911,9 +1913,8 @@ static int qemu_rdma_exchange_send(RDMAContext *rdma, RDMAControlHeader *head, ret = qemu_rdma_exchange_get_response(rdma, &resp_ignored, RDMA_CONTROL_READY, - RDMA_WRID_READY); + RDMA_WRID_READY, errp); if (ret < 0) { - error_setg(errp, "FIXME temporary error message"); return -1; } } @@ -1964,10 +1965,10 @@ static int qemu_rdma_exchange_send(RDMAContext *rdma, RDMAControlHeader *head, trace_qemu_rdma_exchange_send_waiting(control_desc(resp->type)); ret = qemu_rdma_exchange_get_response(rdma, resp, - resp->type, RDMA_WRID_DATA); + resp->type, RDMA_WRID_DATA, + errp); if (ret < 0) { - error_setg(errp, "FIXME temporary error message"); return -1; } @@ -2011,10 +2012,9 @@ static int qemu_rdma_exchange_recv(RDMAContext *rdma, RDMAControlHeader *head, * Block and wait for the message. */ ret = qemu_rdma_exchange_get_response(rdma, head, - expecting, RDMA_WRID_READY); + expecting, RDMA_WRID_READY, errp); if (ret < 0) { - error_setg(errp, "FIXME temporary error message"); return -1; } From de1aa35f8dbb9666360648148e57ceacb1bf8b5b Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Thu, 28 Sep 2023 15:20:04 +0200 Subject: [PATCH 0489/1077] migration/rdma: Convert qemu_rdma_reg_whole_ram_blocks() to Error Functions that use an Error **errp parameter to return errors should not also report them to the user, because reporting is the caller's job. When the caller does, the error is reported twice. When it doesn't (because it recovered from the error), there is no error to report, i.e. the report is bogus. qemu_rdma_exchange_send() violates this principle: it calls error_report() via callback qemu_rdma_reg_whole_ram_blocks(). I elected not to investigate how callers handle the error, i.e. precise impact is not known. Clean this up by converting the callback to Error. Signed-off-by: Markus Armbruster Reviewed-by: Li Zhijian Reviewed-by: Juan Quintela Signed-off-by: Juan Quintela Message-ID: <20230928132019.2544702-39-armbru@redhat.com> --- migration/rdma.c | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/migration/rdma.c b/migration/rdma.c index 87f2e6129e..189932097e 100644 --- a/migration/rdma.c +++ b/migration/rdma.c @@ -518,7 +518,8 @@ static void network_to_result(RDMARegisterResult *result) static int qemu_rdma_exchange_send(RDMAContext *rdma, RDMAControlHeader *head, uint8_t *data, RDMAControlHeader *resp, int *resp_idx, - int (*callback)(RDMAContext *rdma), + int (*callback)(RDMAContext *rdma, + Error **errp), Error **errp); static inline uint64_t ram_chunk_index(const uint8_t *start, @@ -1177,7 +1178,7 @@ static void qemu_rdma_advise_prefetch_mr(struct ibv_pd *pd, uint64_t addr, #endif } -static int qemu_rdma_reg_whole_ram_blocks(RDMAContext *rdma) +static int qemu_rdma_reg_whole_ram_blocks(RDMAContext *rdma, Error **errp) { int i; RDMALocalBlocks *local = &rdma->local_ram_blocks; @@ -1217,16 +1218,16 @@ static int qemu_rdma_reg_whole_ram_blocks(RDMAContext *rdma) } if (!local->block[i].mr) { - perror("Failed to register local dest ram block!"); - break; + error_setg_errno(errp, errno, + "Failed to register local dest ram block!"); + goto err; } rdma->total_registrations++; } - if (i >= local->nb_blocks) { - return 0; - } + return 0; +err: for (i--; i >= 0; i--) { ibv_dereg_mr(local->block[i].mr); local->block[i].mr = NULL; @@ -1899,7 +1900,8 @@ static void qemu_rdma_move_header(RDMAContext *rdma, int idx, static int qemu_rdma_exchange_send(RDMAContext *rdma, RDMAControlHeader *head, uint8_t *data, RDMAControlHeader *resp, int *resp_idx, - int (*callback)(RDMAContext *rdma), + int (*callback)(RDMAContext *rdma, + Error **errp), Error **errp) { int ret; @@ -1956,9 +1958,8 @@ static int qemu_rdma_exchange_send(RDMAContext *rdma, RDMAControlHeader *head, if (resp) { if (callback) { trace_qemu_rdma_exchange_send_issue_callback(); - ret = callback(rdma); + ret = callback(rdma, errp); if (ret < 0) { - error_setg(errp, "FIXME temporary error message"); return -1; } } @@ -3671,10 +3672,9 @@ static int qemu_rdma_registration_handle(QEMUFile *f) } if (rdma->pin_all) { - ret = qemu_rdma_reg_whole_ram_blocks(rdma); + ret = qemu_rdma_reg_whole_ram_blocks(rdma, &err); if (ret < 0) { - error_report("rdma migration: error dest " - "registering ram blocks"); + error_report_err(err); goto err; } } From 56095477812860325295609fbeaf15741e01f53c Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Thu, 28 Sep 2023 15:20:05 +0200 Subject: [PATCH 0490/1077] migration/rdma: Convert qemu_rdma_write_flush() to Error Functions that use an Error **errp parameter to return errors should not also report them to the user, because reporting is the caller's job. When the caller does, the error is reported twice. When it doesn't (because it recovered from the error), there is no error to report, i.e. the report is bogus. qio_channel_rdma_writev() violates this principle: it calls error_report() via qemu_rdma_write_flush(). I elected not to investigate how callers handle the error, i.e. precise impact is not known. Clean this up by converting qemu_rdma_write_flush() to Error. Necessitates setting an error when qemu_rdma_write_one() failed. Since this error will go away later in this series, simply use "FIXME temporary error message" there. Signed-off-by: Markus Armbruster Reviewed-by: Li Zhijian Reviewed-by: Juan Quintela Signed-off-by: Juan Quintela Message-ID: <20230928132019.2544702-40-armbru@redhat.com> --- migration/rdma.c | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/migration/rdma.c b/migration/rdma.c index 189932097e..1a74c6d955 100644 --- a/migration/rdma.c +++ b/migration/rdma.c @@ -2283,7 +2283,7 @@ retry: * We support sending out multiple chunks at the same time. * Not all of them need to get signaled in the completion queue. */ -static int qemu_rdma_write_flush(RDMAContext *rdma) +static int qemu_rdma_write_flush(RDMAContext *rdma, Error **errp) { int ret; @@ -2295,6 +2295,7 @@ static int qemu_rdma_write_flush(RDMAContext *rdma) rdma->current_index, rdma->current_addr, rdma->current_length); if (ret < 0) { + error_setg(errp, "FIXME temporary error message"); return -1; } @@ -2368,6 +2369,7 @@ static int qemu_rdma_write(RDMAContext *rdma, uint64_t block_offset, uint64_t offset, uint64_t len) { + Error *err = NULL; uint64_t current_addr = block_offset + offset; uint64_t index = rdma->current_index; uint64_t chunk = rdma->current_chunk; @@ -2375,8 +2377,9 @@ static int qemu_rdma_write(RDMAContext *rdma, /* If we cannot merge it, we flush the current buffer first. */ if (!qemu_rdma_buffer_mergeable(rdma, current_addr, len)) { - ret = qemu_rdma_write_flush(rdma); + ret = qemu_rdma_write_flush(rdma, &err); if (ret < 0) { + error_report_err(err); return -1; } rdma->current_length = 0; @@ -2393,7 +2396,10 @@ static int qemu_rdma_write(RDMAContext *rdma, /* flush it if buffer is too large */ if (rdma->current_length >= RDMA_MERGE_MAX) { - return qemu_rdma_write_flush(rdma); + if (qemu_rdma_write_flush(rdma, &err) < 0) { + error_report_err(err); + return -1; + } } return 0; @@ -2857,10 +2863,9 @@ static ssize_t qio_channel_rdma_writev(QIOChannel *ioc, * Push out any writes that * we're queued up for VM's ram. */ - ret = qemu_rdma_write_flush(rdma); + ret = qemu_rdma_write_flush(rdma, errp); if (ret < 0) { rdma->errored = true; - error_setg(errp, "qemu_rdma_write_flush failed"); return -1; } @@ -3002,9 +3007,11 @@ static ssize_t qio_channel_rdma_readv(QIOChannel *ioc, */ static int qemu_rdma_drain_cq(RDMAContext *rdma) { + Error *err = NULL; int ret; - if (qemu_rdma_write_flush(rdma) < 0) { + if (qemu_rdma_write_flush(rdma, &err) < 0) { + error_report_err(err); return -1; } From 557c34ca60d863047320a178ebcd06ba8d30c057 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Thu, 28 Sep 2023 15:20:06 +0200 Subject: [PATCH 0491/1077] migration/rdma: Convert qemu_rdma_write_one() to Error Functions that use an Error **errp parameter to return errors should not also report them to the user, because reporting is the caller's job. When the caller does, the error is reported twice. When it doesn't (because it recovered from the error), there is no error to report, i.e. the report is bogus. qemu_rdma_write_flush() violates this principle: it calls error_report() via qemu_rdma_write_one(). I elected not to investigate how callers handle the error, i.e. precise impact is not known. Clean this up by converting qemu_rdma_write_one() to Error. Bonus: resolves a FIXME about problematic use of errno. Signed-off-by: Markus Armbruster Reviewed-by: Li Zhijian Reviewed-by: Juan Quintela Signed-off-by: Juan Quintela Message-ID: <20230928132019.2544702-41-armbru@redhat.com> --- migration/rdma.c | 32 ++++++++++++-------------------- 1 file changed, 12 insertions(+), 20 deletions(-) diff --git a/migration/rdma.c b/migration/rdma.c index 1a74c6d955..369d30c895 100644 --- a/migration/rdma.c +++ b/migration/rdma.c @@ -2041,9 +2041,8 @@ static int qemu_rdma_exchange_recv(RDMAContext *rdma, RDMAControlHeader *head, */ static int qemu_rdma_write_one(RDMAContext *rdma, int current_index, uint64_t current_addr, - uint64_t length) + uint64_t length, Error **errp) { - Error *err = NULL; struct ibv_sge sge; struct ibv_send_wr send_wr = { 0 }; struct ibv_send_wr *bad_wr; @@ -2097,7 +2096,7 @@ retry: ret = qemu_rdma_block_for_wrid(rdma, RDMA_WRID_RDMA_WRITE, NULL); if (ret < 0) { - error_report("Failed to Wait for previous write to complete " + error_setg(errp, "Failed to Wait for previous write to complete " "block %d chunk %" PRIu64 " current %" PRIu64 " len %" PRIu64 " %d", current_index, chunk, sge.addr, length, rdma->nb_sent); @@ -2129,10 +2128,9 @@ retry: compress_to_network(rdma, &comp); ret = qemu_rdma_exchange_send(rdma, &head, - (uint8_t *) &comp, NULL, NULL, NULL, &err); + (uint8_t *) &comp, NULL, NULL, NULL, errp); if (ret < 0) { - error_report_err(err); return -1; } @@ -2167,9 +2165,8 @@ retry: register_to_network(rdma, ®); ret = qemu_rdma_exchange_send(rdma, &head, (uint8_t *) ®, - &resp, ®_result_idx, NULL, &err); + &resp, ®_result_idx, NULL, errp); if (ret < 0) { - error_report_err(err); return -1; } @@ -2177,7 +2174,7 @@ retry: if (qemu_rdma_register_and_get_keys(rdma, block, sge.addr, &sge.lkey, NULL, chunk, chunk_start, chunk_end)) { - error_report("cannot get lkey"); + error_setg(errp, "cannot get lkey"); return -1; } @@ -2196,7 +2193,7 @@ retry: if (qemu_rdma_register_and_get_keys(rdma, block, sge.addr, &sge.lkey, NULL, chunk, chunk_start, chunk_end)) { - error_report("cannot get lkey!"); + error_setg(errp, "cannot get lkey!"); return -1; } } @@ -2208,7 +2205,7 @@ retry: if (qemu_rdma_register_and_get_keys(rdma, block, sge.addr, &sge.lkey, NULL, chunk, chunk_start, chunk_end)) { - error_report("cannot get lkey!"); + error_setg(errp, "cannot get lkey!"); return -1; } } @@ -2242,7 +2239,7 @@ retry: trace_qemu_rdma_write_one_queue_full(); ret = qemu_rdma_block_for_wrid(rdma, RDMA_WRID_RDMA_WRITE, NULL); if (ret < 0) { - error_report("rdma migration: failed to make " + error_setg(errp, "rdma migration: failed to make " "room in full send queue!"); return -1; } @@ -2250,12 +2247,8 @@ retry: goto retry; } else if (ret > 0) { - /* - * FIXME perror() is problematic, because whether - * ibv_post_send() sets errno is unclear. Will go away later - * in this series. - */ - perror("rdma migration: post rdma write failed"); + error_setg_errno(errp, ret, + "rdma migration: post rdma write failed"); return -1; } @@ -2291,11 +2284,10 @@ static int qemu_rdma_write_flush(RDMAContext *rdma, Error **errp) return 0; } - ret = qemu_rdma_write_one(rdma, - rdma->current_index, rdma->current_addr, rdma->current_length); + ret = qemu_rdma_write_one(rdma, rdma->current_index, rdma->current_addr, + rdma->current_length, errp); if (ret < 0) { - error_setg(errp, "FIXME temporary error message"); return -1; } From 446e559c433184b797bf3f3e1b4366c908a4fb6d Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Thu, 28 Sep 2023 15:20:07 +0200 Subject: [PATCH 0492/1077] migration/rdma: Convert qemu_rdma_write() to Error Just for consistency with qemu_rdma_write_one() and qemu_rdma_write_flush(), and for slightly simpler code. Signed-off-by: Markus Armbruster Reviewed-by: Li Zhijian Reviewed-by: Juan Quintela Signed-off-by: Juan Quintela Message-ID: <20230928132019.2544702-42-armbru@redhat.com> --- migration/rdma.c | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/migration/rdma.c b/migration/rdma.c index 369d30c895..9f45f6a91d 100644 --- a/migration/rdma.c +++ b/migration/rdma.c @@ -2359,9 +2359,8 @@ static inline bool qemu_rdma_buffer_mergeable(RDMAContext *rdma, */ static int qemu_rdma_write(RDMAContext *rdma, uint64_t block_offset, uint64_t offset, - uint64_t len) + uint64_t len, Error **errp) { - Error *err = NULL; uint64_t current_addr = block_offset + offset; uint64_t index = rdma->current_index; uint64_t chunk = rdma->current_chunk; @@ -2369,9 +2368,8 @@ static int qemu_rdma_write(RDMAContext *rdma, /* If we cannot merge it, we flush the current buffer first. */ if (!qemu_rdma_buffer_mergeable(rdma, current_addr, len)) { - ret = qemu_rdma_write_flush(rdma, &err); + ret = qemu_rdma_write_flush(rdma, errp); if (ret < 0) { - error_report_err(err); return -1; } rdma->current_length = 0; @@ -2388,10 +2386,7 @@ static int qemu_rdma_write(RDMAContext *rdma, /* flush it if buffer is too large */ if (rdma->current_length >= RDMA_MERGE_MAX) { - if (qemu_rdma_write_flush(rdma, &err) < 0) { - error_report_err(err); - return -1; - } + return qemu_rdma_write_flush(rdma, errp); } return 0; @@ -3290,6 +3285,7 @@ static int qemu_rdma_save_page(QEMUFile *f, ram_addr_t block_offset, ram_addr_t offset, size_t size) { QIOChannelRDMA *rioc = QIO_CHANNEL_RDMA(qemu_file_get_ioc(f)); + Error *err = NULL; RDMAContext *rdma; int ret; @@ -3315,9 +3311,9 @@ static int qemu_rdma_save_page(QEMUFile *f, ram_addr_t block_offset, * is full, or the page doesn't belong to the current chunk, * an actual RDMA write will occur and a new chunk will be formed. */ - ret = qemu_rdma_write(rdma, block_offset, offset, size); + ret = qemu_rdma_write(rdma, block_offset, offset, size, &err); if (ret < 0) { - error_report("rdma migration: write error"); + error_report_err(err); goto err; } From f3805964f8cd79a534c20dfc95ed3000145a5d82 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Thu, 28 Sep 2023 15:20:08 +0200 Subject: [PATCH 0493/1077] migration/rdma: Convert qemu_rdma_post_send_control() to Error Functions that use an Error **errp parameter to return errors should not also report them to the user, because reporting is the caller's job. When the caller does, the error is reported twice. When it doesn't (because it recovered from the error), there is no error to report, i.e. the report is bogus. qemu_rdma_exchange_send() violates this principle: it calls error_report() via qemu_rdma_post_send_control(). I elected not to investigate how callers handle the error, i.e. precise impact is not known. Clean this up by converting qemu_rdma_post_send_control() to Error. Signed-off-by: Markus Armbruster Reviewed-by: Li Zhijian Reviewed-by: Juan Quintela Signed-off-by: Juan Quintela Message-ID: <20230928132019.2544702-43-armbru@redhat.com> --- migration/rdma.c | 31 +++++++++++++++++-------------- 1 file changed, 17 insertions(+), 14 deletions(-) diff --git a/migration/rdma.c b/migration/rdma.c index 9f45f6a91d..aeb0a8921e 100644 --- a/migration/rdma.c +++ b/migration/rdma.c @@ -1741,7 +1741,8 @@ err_block_for_wrid: * containing some data and block until the post completes. */ static int qemu_rdma_post_send_control(RDMAContext *rdma, uint8_t *buf, - RDMAControlHeader *head) + RDMAControlHeader *head, + Error **errp) { int ret; RDMAWorkRequestData *wr = &rdma->wr_data[RDMA_WRID_CONTROL]; @@ -1781,13 +1782,13 @@ static int qemu_rdma_post_send_control(RDMAContext *rdma, uint8_t *buf, ret = ibv_post_send(rdma->qp, &send_wr, &bad_wr); if (ret > 0) { - error_report("Failed to use post IB SEND for control"); + error_setg(errp, "Failed to use post IB SEND for control"); return -1; } ret = qemu_rdma_block_for_wrid(rdma, RDMA_WRID_SEND_CONTROL, NULL); if (ret < 0) { - error_report("rdma migration: send polling control error"); + error_setg(errp, "rdma migration: send polling control error"); return -1; } @@ -1945,10 +1946,9 @@ static int qemu_rdma_exchange_send(RDMAContext *rdma, RDMAControlHeader *head, /* * Deliver the control message that was requested. */ - ret = qemu_rdma_post_send_control(rdma, data, head); + ret = qemu_rdma_post_send_control(rdma, data, head, errp); if (ret < 0) { - error_setg(errp, "Failed to send control buffer!"); return -1; } @@ -2002,10 +2002,9 @@ static int qemu_rdma_exchange_recv(RDMAContext *rdma, RDMAControlHeader *head, /* * Inform the source that we're ready to receive a message. */ - ret = qemu_rdma_post_send_control(rdma, NULL, &ready); + ret = qemu_rdma_post_send_control(rdma, NULL, &ready, errp); if (ret < 0) { - error_setg(errp, "Failed to send control buffer!"); return -1; } @@ -2394,6 +2393,7 @@ static int qemu_rdma_write(RDMAContext *rdma, static void qemu_rdma_cleanup(RDMAContext *rdma) { + Error *err = NULL; int idx; if (rdma->cm_id && rdma->connected) { @@ -2405,7 +2405,9 @@ static void qemu_rdma_cleanup(RDMAContext *rdma) .repeat = 1, }; error_report("Early error. Sending error."); - qemu_rdma_post_send_control(rdma, NULL, &head); + if (qemu_rdma_post_send_control(rdma, NULL, &head, &err) < 0) { + error_report_err(err); + } } rdma_disconnect(rdma->cm_id); @@ -3705,10 +3707,11 @@ static int qemu_rdma_registration_handle(QEMUFile *f) ret = qemu_rdma_post_send_control(rdma, - (uint8_t *) rdma->dest_blocks, &blocks); + (uint8_t *) rdma->dest_blocks, &blocks, + &err); if (ret < 0) { - error_report("rdma migration: error sending remote info"); + error_report_err(err); goto err; } @@ -3783,10 +3786,10 @@ static int qemu_rdma_registration_handle(QEMUFile *f) } ret = qemu_rdma_post_send_control(rdma, - (uint8_t *) results, ®_resp); + (uint8_t *) results, ®_resp, &err); if (ret < 0) { - error_report("Failed to send control buffer"); + error_report_err(err); goto err; } break; @@ -3818,10 +3821,10 @@ static int qemu_rdma_registration_handle(QEMUFile *f) reg->key.chunk); } - ret = qemu_rdma_post_send_control(rdma, NULL, &unreg_resp); + ret = qemu_rdma_post_send_control(rdma, NULL, &unreg_resp, &err); if (ret < 0) { - error_report("Failed to send control buffer"); + error_report_err(err); goto err; } break; From 3c0c3eba8d9279249b451ff9d9a14e3f8a14bba8 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Thu, 28 Sep 2023 15:20:09 +0200 Subject: [PATCH 0494/1077] migration/rdma: Convert qemu_rdma_post_recv_control() to Error Just for symmetry with qemu_rdma_post_send_control(). Error messages lose detail I consider of no use to users. Signed-off-by: Markus Armbruster Reviewed-by: Li Zhijian Reviewed-by: Juan Quintela Signed-off-by: Juan Quintela Message-ID: <20230928132019.2544702-44-armbru@redhat.com> --- migration/rdma.c | 22 ++++++++++------------ 1 file changed, 10 insertions(+), 12 deletions(-) diff --git a/migration/rdma.c b/migration/rdma.c index aeb0a8921e..41ea2edcda 100644 --- a/migration/rdma.c +++ b/migration/rdma.c @@ -1799,7 +1799,8 @@ static int qemu_rdma_post_send_control(RDMAContext *rdma, uint8_t *buf, * Post a RECV work request in anticipation of some future receipt * of data on the control channel. */ -static int qemu_rdma_post_recv_control(RDMAContext *rdma, int idx) +static int qemu_rdma_post_recv_control(RDMAContext *rdma, int idx, + Error **errp) { struct ibv_recv_wr *bad_wr; struct ibv_sge sge = { @@ -1816,6 +1817,7 @@ static int qemu_rdma_post_recv_control(RDMAContext *rdma, int idx) if (ibv_post_recv(rdma->qp, &recv_wr, &bad_wr)) { + error_setg(errp, "error posting control recv"); return -1; } @@ -1926,10 +1928,8 @@ static int qemu_rdma_exchange_send(RDMAContext *rdma, RDMAControlHeader *head, * If the user is expecting a response, post a WR in anticipation of it. */ if (resp) { - ret = qemu_rdma_post_recv_control(rdma, RDMA_WRID_DATA); + ret = qemu_rdma_post_recv_control(rdma, RDMA_WRID_DATA, errp); if (ret < 0) { - error_setg(errp, "rdma migration: error posting" - " extra control recv for anticipated result!"); return -1; } } @@ -1937,9 +1937,8 @@ static int qemu_rdma_exchange_send(RDMAContext *rdma, RDMAControlHeader *head, /* * Post a WR to replace the one we just consumed for the READY message. */ - ret = qemu_rdma_post_recv_control(rdma, RDMA_WRID_READY); + ret = qemu_rdma_post_recv_control(rdma, RDMA_WRID_READY, errp); if (ret < 0) { - error_setg(errp, "rdma migration: error posting first control recv!"); return -1; } @@ -2023,9 +2022,8 @@ static int qemu_rdma_exchange_recv(RDMAContext *rdma, RDMAControlHeader *head, /* * Post a new RECV work request to replace the one we just consumed. */ - ret = qemu_rdma_post_recv_control(rdma, RDMA_WRID_READY); + ret = qemu_rdma_post_recv_control(rdma, RDMA_WRID_READY, errp); if (ret < 0) { - error_setg(errp, "rdma migration: error posting second control recv!"); return -1; } @@ -2608,9 +2606,8 @@ static int qemu_rdma_connect(RDMAContext *rdma, bool return_path, caps_to_network(&cap); - ret = qemu_rdma_post_recv_control(rdma, RDMA_WRID_READY); + ret = qemu_rdma_post_recv_control(rdma, RDMA_WRID_READY, errp); if (ret < 0) { - error_setg(errp, "RDMA ERROR: posting second control recv"); goto err_rdma_source_connect; } @@ -3402,6 +3399,7 @@ static void rdma_cm_poll_handler(void *opaque) static int qemu_rdma_accept(RDMAContext *rdma) { + Error *err = NULL; RDMACapabilities cap; struct rdma_conn_param conn_param = { .responder_resources = 2, @@ -3538,9 +3536,9 @@ static int qemu_rdma_accept(RDMAContext *rdma) rdma_ack_cm_event(cm_event); rdma->connected = true; - ret = qemu_rdma_post_recv_control(rdma, RDMA_WRID_READY); + ret = qemu_rdma_post_recv_control(rdma, RDMA_WRID_READY, &err); if (ret < 0) { - error_report("rdma migration: error posting second control recv"); + error_report_err(err); goto err_rdma_dest_wait; } From 07d5b946539694e8a91b0153514c126649d2da3e Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Thu, 28 Sep 2023 15:20:10 +0200 Subject: [PATCH 0495/1077] migration/rdma: Convert qemu_rdma_alloc_pd_cq() to Error Functions that use an Error **errp parameter to return errors should not also report them to the user, because reporting is the caller's job. When the caller does, the error is reported twice. When it doesn't (because it recovered from the error), there is no error to report, i.e. the report is bogus. qemu_rdma_source_init() violates this principle: it calls error_report() via qemu_rdma_alloc_pd_cq(). I elected not to investigate how callers handle the error, i.e. precise impact is not known. Clean this up by converting qemu_rdma_alloc_pd_cq() to Error. The conversion loses a piece of advice on one of two failure paths: Your mlock() limits may be too low. Please check $ ulimit -a # and search for 'ulimit -l' in the output Not worth retaining. Signed-off-by: Markus Armbruster Reviewed-by: Li Zhijian Reviewed-by: Juan Quintela Signed-off-by: Juan Quintela Message-ID: <20230928132019.2544702-45-armbru@redhat.com> --- migration/rdma.c | 22 +++++++++------------- 1 file changed, 9 insertions(+), 13 deletions(-) diff --git a/migration/rdma.c b/migration/rdma.c index 41ea2edcda..ee9221d5d2 100644 --- a/migration/rdma.c +++ b/migration/rdma.c @@ -1052,19 +1052,19 @@ err_resolve_create_id: /* * Create protection domain and completion queues */ -static int qemu_rdma_alloc_pd_cq(RDMAContext *rdma) +static int qemu_rdma_alloc_pd_cq(RDMAContext *rdma, Error **errp) { /* allocate pd */ rdma->pd = ibv_alloc_pd(rdma->verbs); if (!rdma->pd) { - error_report("failed to allocate protection domain"); + error_setg(errp, "failed to allocate protection domain"); return -1; } /* create receive completion channel */ rdma->recv_comp_channel = ibv_create_comp_channel(rdma->verbs); if (!rdma->recv_comp_channel) { - error_report("failed to allocate receive completion channel"); + error_setg(errp, "failed to allocate receive completion channel"); goto err_alloc_pd_cq; } @@ -1074,21 +1074,21 @@ static int qemu_rdma_alloc_pd_cq(RDMAContext *rdma) rdma->recv_cq = ibv_create_cq(rdma->verbs, (RDMA_SIGNALED_SEND_MAX * 3), NULL, rdma->recv_comp_channel, 0); if (!rdma->recv_cq) { - error_report("failed to allocate receive completion queue"); + error_setg(errp, "failed to allocate receive completion queue"); goto err_alloc_pd_cq; } /* create send completion channel */ rdma->send_comp_channel = ibv_create_comp_channel(rdma->verbs); if (!rdma->send_comp_channel) { - error_report("failed to allocate send completion channel"); + error_setg(errp, "failed to allocate send completion channel"); goto err_alloc_pd_cq; } rdma->send_cq = ibv_create_cq(rdma->verbs, (RDMA_SIGNALED_SEND_MAX * 3), NULL, rdma->send_comp_channel, 0); if (!rdma->send_cq) { - error_report("failed to allocate send completion queue"); + error_setg(errp, "failed to allocate send completion queue"); goto err_alloc_pd_cq; } @@ -2503,12 +2503,8 @@ static int qemu_rdma_source_init(RDMAContext *rdma, bool pin_all, Error **errp) goto err_rdma_source_init; } - ret = qemu_rdma_alloc_pd_cq(rdma); + ret = qemu_rdma_alloc_pd_cq(rdma, errp); if (ret < 0) { - error_setg(errp, "RDMA ERROR: " - "rdma migration: error allocating pd and cq! Your mlock()" - " limits may be too low. Please check $ ulimit -a # and " - "search for 'ulimit -l' in the output"); goto err_rdma_source_init; } @@ -3482,9 +3478,9 @@ static int qemu_rdma_accept(RDMAContext *rdma) qemu_rdma_dump_id("dest_init", verbs); - ret = qemu_rdma_alloc_pd_cq(rdma); + ret = qemu_rdma_alloc_pd_cq(rdma, &err); if (ret < 0) { - error_report("rdma migration: error allocating pd and cq!"); + error_report_err(err); goto err_rdma_dest_wait; } From e6696d3ee9b8a0632dd12b20081ebd21bb7b646d Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Thu, 28 Sep 2023 15:20:11 +0200 Subject: [PATCH 0496/1077] migration/rdma: Silence qemu_rdma_resolve_host() Functions that use an Error **errp parameter to return errors should not also report them to the user, because reporting is the caller's job. When the caller does, the error is reported twice. When it doesn't (because it recovered from the error), there is no error to report, i.e. the report is bogus. qemu_rdma_resolve_host() violates this principle: it calls error_report(). Clean this up: drop error_report(). Signed-off-by: Markus Armbruster Reviewed-by: Li Zhijian Reviewed-by: Juan Quintela Signed-off-by: Juan Quintela Message-ID: <20230928132019.2544702-46-armbru@redhat.com> --- migration/rdma.c | 1 - 1 file changed, 1 deletion(-) diff --git a/migration/rdma.c b/migration/rdma.c index ee9221d5d2..3c7a407d25 100644 --- a/migration/rdma.c +++ b/migration/rdma.c @@ -1009,7 +1009,6 @@ route: error_setg(errp, "RDMA ERROR: result not equal to event_addr_resolved %s", rdma_event_str(cm_event->event)); - error_report("rdma_resolve_addr"); rdma_ack_cm_event(cm_event); goto err_resolve_get_addr; } From 35b1561e3ec56fc3cae283d1b00053be6445a2db Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Thu, 28 Sep 2023 15:20:12 +0200 Subject: [PATCH 0497/1077] migration/rdma: Silence qemu_rdma_connect() Functions that use an Error **errp parameter to return errors should not also report them to the user, because reporting is the caller's job. When the caller does, the error is reported twice. When it doesn't (because it recovered from the error), there is no error to report, i.e. the report is bogus. qemu_rdma_connect() violates this principle: it calls error_report() and perror(). I elected not to investigate how callers handle the error, i.e. precise impact is not known. Clean this up: replace perror() by changing error_setg() to error_setg_errno(), and drop error_report(). I believe the callers' error reports suffice then. If they don't, we need to convert to Error instead. Bonus: resolves a FIXME about problematic use of errno. Signed-off-by: Markus Armbruster Reviewed-by: Li Zhijian Reviewed-by: Juan Quintela Signed-off-by: Juan Quintela Message-ID: <20230928132019.2544702-47-armbru@redhat.com> --- migration/rdma.c | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/migration/rdma.c b/migration/rdma.c index 3c7a407d25..8e1e8c4d47 100644 --- a/migration/rdma.c +++ b/migration/rdma.c @@ -2608,8 +2608,8 @@ static int qemu_rdma_connect(RDMAContext *rdma, bool return_path, ret = rdma_connect(rdma->cm_id, &conn_param); if (ret < 0) { - perror("rdma_connect"); - error_setg(errp, "RDMA ERROR: connecting to destination!"); + error_setg_errno(errp, errno, + "RDMA ERROR: connecting to destination!"); goto err_rdma_source_connect; } @@ -2618,21 +2618,15 @@ static int qemu_rdma_connect(RDMAContext *rdma, bool return_path, } else { ret = rdma_get_cm_event(rdma->channel, &cm_event); if (ret < 0) { - error_setg(errp, "RDMA ERROR: failed to get cm event"); + error_setg_errno(errp, errno, + "RDMA ERROR: failed to get cm event"); } } if (ret < 0) { - /* - * FIXME perror() is wrong, because - * qemu_get_cm_event_timeout() can fail without setting errno. - * Will go away later in this series. - */ - perror("rdma_get_cm_event after rdma_connect"); goto err_rdma_source_connect; } if (cm_event->event != RDMA_CM_EVENT_ESTABLISHED) { - error_report("rdma_get_cm_event != EVENT_ESTABLISHED after rdma_connect"); error_setg(errp, "RDMA ERROR: connecting to destination!"); rdma_ack_cm_event(cm_event); goto err_rdma_source_connect; From 01efb106373551e92efde579b16c1b8aa4ee9354 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Thu, 28 Sep 2023 15:20:13 +0200 Subject: [PATCH 0498/1077] migration/rdma: Silence qemu_rdma_reg_control() Functions that use an Error **errp parameter to return errors should not also report them to the user, because reporting is the caller's job. When the caller does, the error is reported twice. When it doesn't (because it recovered from the error), there is no error to report, i.e. the report is bogus. qemu_rdma_source_init() and qemu_rdma_accept() violate this principle: they call error_report() via qemu_rdma_reg_control(). I elected not to investigate how callers handle the error, i.e. precise impact is not known. Clean this up by dropping the error reporting from qemu_rdma_reg_control(). I believe the callers' error reports suffice. If they don't, we need to convert to Error instead. Signed-off-by: Markus Armbruster Reviewed-by: Li Zhijian Reviewed-by: Juan Quintela Signed-off-by: Juan Quintela Message-ID: <20230928132019.2544702-48-armbru@redhat.com> --- migration/rdma.c | 1 - 1 file changed, 1 deletion(-) diff --git a/migration/rdma.c b/migration/rdma.c index 8e1e8c4d47..6a8ff8fa96 100644 --- a/migration/rdma.c +++ b/migration/rdma.c @@ -1360,7 +1360,6 @@ static int qemu_rdma_reg_control(RDMAContext *rdma, int idx) rdma->total_registrations++; return 0; } - error_report("qemu_rdma_reg_control failed"); return -1; } From 8dee156c1d60fd386bf19ac6bbccc04ef56a9f02 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Thu, 28 Sep 2023 15:20:14 +0200 Subject: [PATCH 0499/1077] migration/rdma: Don't report received completion events as error When qemu_rdma_wait_comp_channel() receives an event from the completion channel, it reports an error "receive cm event while wait comp channel,cm event is T", where T is the numeric event type. However, the function fails only when T is a disconnect or device removal. Events other than these two are not actually an error, and reporting them as an error is wrong. If we need to report them to the user, we should use something else, and what to use depends on why we need to report them to the user. For now, report this error only when the function actually fails. Signed-off-by: Markus Armbruster Reviewed-by: Li Zhijian Reviewed-by: Juan Quintela Signed-off-by: Juan Quintela Message-ID: <20230928132019.2544702-49-armbru@redhat.com> --- migration/rdma.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/migration/rdma.c b/migration/rdma.c index 6a8ff8fa96..b5bb47108e 100644 --- a/migration/rdma.c +++ b/migration/rdma.c @@ -1582,11 +1582,11 @@ static int qemu_rdma_wait_comp_channel(RDMAContext *rdma, return -1; } - error_report("receive cm event while wait comp channel," - "cm event is %d", cm_event->event); if (cm_event->event == RDMA_CM_EVENT_DISCONNECTED || cm_event->event == RDMA_CM_EVENT_DEVICE_REMOVAL) { rdma_ack_cm_event(cm_event); + error_report("receive cm event while wait comp channel," + "cm event is %d", cm_event->event); return -1; } rdma_ack_cm_event(cm_event); From 7555c7713d4bf03caa610ed2d2df481c2150b044 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Thu, 28 Sep 2023 15:20:15 +0200 Subject: [PATCH 0500/1077] migration/rdma: Silence qemu_rdma_block_for_wrid() Functions that use an Error **errp parameter to return errors should not also report them to the user, because reporting is the caller's job. When the caller does, the error is reported twice. When it doesn't (because it recovered from the error), there is no error to report, i.e. the report is bogus. qemu_rdma_post_send_control(), qemu_rdma_exchange_get_response(), and qemu_rdma_write_one() violate this principle: they call error_report(), fprintf(stderr, ...), and perror() via qemu_rdma_block_for_wrid(), qemu_rdma_poll(), and qemu_rdma_wait_comp_channel(). I elected not to investigate how callers handle the error, i.e. precise impact is not known. Clean this up by dropping the error reporting from qemu_rdma_poll(), qemu_rdma_wait_comp_channel(), and qemu_rdma_block_for_wrid(). I believe the callers' error reports suffice. If they don't, we need to convert to Error instead. Bonus: resolves a FIXME about problematic use of errno. Signed-off-by: Markus Armbruster Reviewed-by: Li Zhijian Reviewed-by: Juan Quintela Signed-off-by: Juan Quintela Message-ID: <20230928132019.2544702-50-armbru@redhat.com> --- migration/rdma.c | 16 ---------------- 1 file changed, 16 deletions(-) diff --git a/migration/rdma.c b/migration/rdma.c index b5bb47108e..459dcb002e 100644 --- a/migration/rdma.c +++ b/migration/rdma.c @@ -1483,17 +1483,12 @@ static int qemu_rdma_poll(RDMAContext *rdma, struct ibv_cq *cq, } if (ret < 0) { - error_report("ibv_poll_cq failed"); return -1; } wr_id = wc.wr_id & RDMA_WRID_TYPE_MASK; if (wc.status != IBV_WC_SUCCESS) { - fprintf(stderr, "ibv_poll_cq wc.status=%d %s!\n", - wc.status, ibv_wc_status_str(wc.status)); - fprintf(stderr, "ibv_poll_cq wrid=%" PRIu64 "!\n", wr_id); - return -1; } @@ -1577,16 +1572,12 @@ static int qemu_rdma_wait_comp_channel(RDMAContext *rdma, if (pfds[1].revents) { ret = rdma_get_cm_event(rdma->channel, &cm_event); if (ret < 0) { - error_report("failed to get cm event while wait " - "completion channel"); return -1; } if (cm_event->event == RDMA_CM_EVENT_DISCONNECTED || cm_event->event == RDMA_CM_EVENT_DEVICE_REMOVAL) { rdma_ack_cm_event(cm_event); - error_report("receive cm event while wait comp channel," - "cm event is %d", cm_event->event); return -1; } rdma_ack_cm_event(cm_event); @@ -1599,7 +1590,6 @@ static int qemu_rdma_wait_comp_channel(RDMAContext *rdma, default: /* Error of some type - * I don't trust errno from qemu_poll_ns */ - error_report("%s: poll failed", __func__); return -1; } @@ -1683,12 +1673,6 @@ static int qemu_rdma_block_for_wrid(RDMAContext *rdma, ret = ibv_get_cq_event(ch, &cq, &cq_ctx); if (ret < 0) { - /* - * FIXME perror() is problematic, because ibv_reg_mr() is - * not documented to set errno. Will go away later in - * this series. - */ - perror("ibv_get_cq_event"); goto err_block_for_wrid; } From b765d21e4aba49dc5c87f3b05532b6b9cc64a2a5 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Thu, 28 Sep 2023 15:20:16 +0200 Subject: [PATCH 0501/1077] migration/rdma: Silence qemu_rdma_register_and_get_keys() Functions that use an Error **errp parameter to return errors should not also report them to the user, because reporting is the caller's job. When the caller does, the error is reported twice. When it doesn't (because it recovered from the error), there is no error to report, i.e. the report is bogus. qemu_rdma_write_one() violates this principle: it reports errors to stderr via qemu_rdma_register_and_get_keys(). I elected not to investigate how callers handle the error, i.e. precise impact is not known. Clean this up: silence qemu_rdma_register_and_get_keys(). I believe the caller's error reports suffice. If they don't, we need to convert to Error instead. Signed-off-by: Markus Armbruster Reviewed-by: Li Zhijian Reviewed-by: Juan Quintela Signed-off-by: Juan Quintela Message-ID: <20230928132019.2544702-51-armbru@redhat.com> --- migration/rdma.c | 9 --------- 1 file changed, 9 deletions(-) diff --git a/migration/rdma.c b/migration/rdma.c index 459dcb002e..025523bf70 100644 --- a/migration/rdma.c +++ b/migration/rdma.c @@ -1325,15 +1325,6 @@ static int qemu_rdma_register_and_get_keys(RDMAContext *rdma, } } if (!block->pmr[chunk]) { - perror("Failed to register chunk!"); - fprintf(stderr, "Chunk details: block: %d chunk index %d" - " start %" PRIuPTR " end %" PRIuPTR - " host %" PRIuPTR - " local %" PRIuPTR " registrations: %d\n", - block->index, chunk, (uintptr_t)chunk_start, - (uintptr_t)chunk_end, host_addr, - (uintptr_t)block->local_host_addr, - rdma->total_registrations); return -1; } rdma->total_registrations++; From 5cec563d0cc4d2ce4983f31c472f022f9fd57d7a Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Thu, 28 Sep 2023 15:20:17 +0200 Subject: [PATCH 0502/1077] migration/rdma: Downgrade qemu_rdma_cleanup() errors to warnings Functions that use an Error **errp parameter to return errors should not also report them to the user, because reporting is the caller's job. When the caller does, the error is reported twice. When it doesn't (because it recovered from the error), there is no error to report, i.e. the report is bogus. qemu_rdma_source_init(), qemu_rdma_connect(), rdma_start_incoming_migration(), and rdma_start_outgoing_migration() violate this principle: they call error_report() via qemu_rdma_cleanup(). Moreover, qemu_rdma_cleanup() can't fail. It is called on error paths, and QIOChannel close and finalization. Are the conditions it reports really errors? I doubt it. Downgrade qemu_rdma_cleanup()'s errors to warnings. Signed-off-by: Markus Armbruster Reviewed-by: Fabiano Rosas Reviewed-by: Juan Quintela Signed-off-by: Juan Quintela Message-ID: <20230928132019.2544702-52-armbru@redhat.com> --- migration/rdma.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/migration/rdma.c b/migration/rdma.c index 025523bf70..9d5b3b76eb 100644 --- a/migration/rdma.c +++ b/migration/rdma.c @@ -2375,9 +2375,9 @@ static void qemu_rdma_cleanup(RDMAContext *rdma) .type = RDMA_CONTROL_ERROR, .repeat = 1, }; - error_report("Early error. Sending error."); + warn_report("Early error. Sending error."); if (qemu_rdma_post_send_control(rdma, NULL, &head, &err) < 0) { - error_report_err(err); + warn_report_err(err); } } From ff4c9194599fff94164e0ffa4b5da968973d0523 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Thu, 28 Sep 2023 15:20:18 +0200 Subject: [PATCH 0503/1077] migration/rdma: Use error_report() & friends instead of stderr error_report() obeys -msg, reports the current error location if any, and reports to the current monitor if any. Reporting to stderr directly with fprintf() or perror() is wrong, because it loses all this. Fix the offenders. Bonus: resolves a FIXME about problematic use of errno. Signed-off-by: Markus Armbruster Reviewed-by: Juan Quintela Signed-off-by: Juan Quintela Message-ID: <20230928132019.2544702-53-armbru@redhat.com> --- migration/rdma.c | 44 +++++++++++++++++++++----------------------- 1 file changed, 21 insertions(+), 23 deletions(-) diff --git a/migration/rdma.c b/migration/rdma.c index 9d5b3b76eb..ab2ea85c45 100644 --- a/migration/rdma.c +++ b/migration/rdma.c @@ -877,12 +877,12 @@ static int qemu_rdma_broken_ipv6_kernel(struct ibv_context *verbs, Error **errp) if (roce_found) { if (ib_found) { - fprintf(stderr, "WARN: migrations may fail:" - " IPv6 over RoCE / iWARP in linux" - " is broken. But since you appear to have a" - " mixed RoCE / IB environment, be sure to only" - " migrate over the IB fabric until the kernel " - " fixes the bug.\n"); + warn_report("migrations may fail:" + " IPv6 over RoCE / iWARP in linux" + " is broken. But since you appear to have a" + " mixed RoCE / IB environment, be sure to only" + " migrate over the IB fabric until the kernel " + " fixes the bug."); } else { error_setg(errp, "RDMA ERROR: " "You only have RoCE / iWARP devices in your systems" @@ -1418,12 +1418,8 @@ static int qemu_rdma_unregister_waiting(RDMAContext *rdma) block->remote_keys[chunk] = 0; if (ret != 0) { - /* - * FIXME perror() is problematic, bcause ibv_dereg_mr() is - * not documented to set errno. Will go away later in - * this series. - */ - perror("unregistration chunk failed"); + error_report("unregistration chunk failed: %s", + strerror(ret)); return -1; } rdma->total_registrations--; @@ -3772,7 +3768,8 @@ static int qemu_rdma_registration_handle(QEMUFile *f) block->pmr[reg->key.chunk] = NULL; if (ret != 0) { - perror("rdma unregistration chunk failed"); + error_report("rdma unregistration chunk failed: %s", + strerror(errno)); goto err; } @@ -3961,10 +3958,10 @@ static int qemu_rdma_registration_stop(QEMUFile *f, */ if (local->nb_blocks != nb_dest_blocks) { - fprintf(stderr, "ram blocks mismatch (Number of blocks %d vs %d) " - "Your QEMU command line parameters are probably " - "not identical on both the source and destination.", - local->nb_blocks, nb_dest_blocks); + error_report("ram blocks mismatch (Number of blocks %d vs %d)", + local->nb_blocks, nb_dest_blocks); + error_printf("Your QEMU command line parameters are probably " + "not identical on both the source and destination."); rdma->errored = true; return -1; } @@ -3977,10 +3974,11 @@ static int qemu_rdma_registration_stop(QEMUFile *f, /* We require that the blocks are in the same order */ if (rdma->dest_blocks[i].length != local->block[i].length) { - fprintf(stderr, "Block %s/%d has a different length %" PRIu64 - "vs %" PRIu64, local->block[i].block_name, i, - local->block[i].length, - rdma->dest_blocks[i].length); + error_report("Block %s/%d has a different length %" PRIu64 + "vs %" PRIu64, + local->block[i].block_name, i, + local->block[i].length, + rdma->dest_blocks[i].length); rdma->errored = true; return -1; } @@ -4096,7 +4094,7 @@ static void rdma_accept_incoming_migration(void *opaque) ret = qemu_rdma_accept(rdma); if (ret < 0) { - fprintf(stderr, "RDMA ERROR: Migration initialization failed\n"); + error_report("RDMA ERROR: Migration initialization failed"); return; } @@ -4108,7 +4106,7 @@ static void rdma_accept_incoming_migration(void *opaque) f = rdma_new_input(rdma); if (f == NULL) { - fprintf(stderr, "RDMA ERROR: could not open RDMA for input\n"); + error_report("RDMA ERROR: could not open RDMA for input"); qemu_rdma_cleanup(rdma); return; } From 2c88739cfd6f8b499c60e1384507e011721ae467 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Thu, 28 Sep 2023 15:20:19 +0200 Subject: [PATCH 0504/1077] migration/rdma: Replace flawed device detail dump by tracing qemu_rdma_dump_id() dumps RDMA device details to stdout. rdma_start_outgoing_migration() calls it via qemu_rdma_source_init() and qemu_rdma_resolve_host() to show source device details. rdma_start_incoming_migration() arranges its call via rdma_accept_incoming_migration() and qemu_rdma_accept() to show destination device details. Two issues: 1. rdma_start_outgoing_migration() can run in HMP context. The information should arguably go the monitor, not stdout. 2. ibv_query_port() failure is reported as error. Its callers remain unaware of this failure (qemu_rdma_dump_id() can't fail), so reporting this to the user as an error is problematic. Fixable, but the device detail dump is noise, except when troubleshooting. Tracing is a better fit. Similar function qemu_rdma_dump_id() was converted to tracing in commit 733252deb8b (Tracify migration/rdma.c). Convert qemu_rdma_dump_id(), too. While there, touch up qemu_rdma_dump_gid()'s outdated comment. Signed-off-by: Markus Armbruster Reviewed-by: Fabiano Rosas Reviewed-by: Juan Quintela Signed-off-by: Juan Quintela Message-ID: <20230928132019.2544702-54-armbru@redhat.com> --- migration/rdma.c | 23 ++++++++--------------- migration/trace-events | 2 ++ 2 files changed, 10 insertions(+), 15 deletions(-) diff --git a/migration/rdma.c b/migration/rdma.c index ab2ea85c45..f6fc226c9b 100644 --- a/migration/rdma.c +++ b/migration/rdma.c @@ -734,38 +734,31 @@ static void rdma_delete_block(RDMAContext *rdma, RDMALocalBlock *block) } /* - * Put in the log file which RDMA device was opened and the details - * associated with that device. + * Trace RDMA device open, with device details. */ static void qemu_rdma_dump_id(const char *who, struct ibv_context *verbs) { struct ibv_port_attr port; if (ibv_query_port(verbs, 1, &port)) { - error_report("Failed to query port information"); + trace_qemu_rdma_dump_id_failed(who); return; } - printf("%s RDMA Device opened: kernel name %s " - "uverbs device name %s, " - "infiniband_verbs class device path %s, " - "infiniband class device path %s, " - "transport: (%d) %s\n", - who, + trace_qemu_rdma_dump_id(who, verbs->device->name, verbs->device->dev_name, verbs->device->dev_path, verbs->device->ibdev_path, port.link_layer, - (port.link_layer == IBV_LINK_LAYER_INFINIBAND) ? "Infiniband" : - ((port.link_layer == IBV_LINK_LAYER_ETHERNET) - ? "Ethernet" : "Unknown")); + port.link_layer == IBV_LINK_LAYER_INFINIBAND ? "Infiniband" + : port.link_layer == IBV_LINK_LAYER_ETHERNET ? "Ethernet" + : "Unknown"); } /* - * Put in the log file the RDMA gid addressing information, - * useful for folks who have trouble understanding the - * RDMA device hierarchy in the kernel. + * Trace RDMA gid addressing information. + * Useful for understanding the RDMA device hierarchy in the kernel. */ static void qemu_rdma_dump_gid(const char *who, struct rdma_cm_id *id) { diff --git a/migration/trace-events b/migration/trace-events index 6a50994402..ee9c8f4d63 100644 --- a/migration/trace-events +++ b/migration/trace-events @@ -214,6 +214,8 @@ qemu_rdma_close(void) "" qemu_rdma_connect_pin_all_requested(void) "" qemu_rdma_connect_pin_all_outcome(bool pin) "%d" qemu_rdma_dest_init_trying(const char *host, const char *ip) "%s => %s" +qemu_rdma_dump_id_failed(const char *who) "%s RDMA Device opened, but can't query port information" +qemu_rdma_dump_id(const char *who, const char *name, const char *dev_name, const char *dev_path, const char *ibdev_path, int transport, const char *transport_name) "%s RDMA Device opened: kernel name %s uverbs device name %s, infiniband_verbs class device path %s, infiniband class device path %s, transport: (%d) %s" qemu_rdma_dump_gid(const char *who, const char *src, const char *dst) "%s Source GID: %s, Dest GID: %s" qemu_rdma_exchange_get_response_start(const char *desc) "CONTROL: %s receiving..." qemu_rdma_exchange_get_response_none(const char *desc, int type) "Surprise: got %s (%d)" From c94143e587875bd70c280d72b1b70d9eefaf6854 Mon Sep 17 00:00:00 2001 From: Peter Xu Date: Wed, 4 Oct 2023 18:02:31 -0400 Subject: [PATCH 0505/1077] migration: Display error in query-migrate irrelevant of status Display it as long as being set, irrelevant of FAILED status. E.g., it may also be applicable to PAUSED stage of postcopy, to provide hint on what has gone wrong. The error_mutex seems to be overlooked when referencing the error, add it to be very safe. This will change QAPI behavior by showing up error message outside !FAILED status, but it's intended and doesn't expect to break anyone. Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=2018404 Reviewed-by: Fabiano Rosas Reviewed-by: Juan Quintela Signed-off-by: Peter Xu Signed-off-by: Juan Quintela Message-ID: <20231004220240.167175-2-peterx@redhat.com> --- migration/migration.c | 8 +++++--- qapi/migration.json | 5 ++--- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/migration/migration.c b/migration/migration.c index 2057e42134..57f9e9ed0c 100644 --- a/migration/migration.c +++ b/migration/migration.c @@ -1060,9 +1060,6 @@ static void fill_source_migration_info(MigrationInfo *info) break; case MIGRATION_STATUS_FAILED: info->has_status = true; - if (s->error) { - info->error_desc = g_strdup(error_get_pretty(s->error)); - } break; case MIGRATION_STATUS_CANCELLED: info->has_status = true; @@ -1072,6 +1069,11 @@ static void fill_source_migration_info(MigrationInfo *info) break; } info->status = state; + + QEMU_LOCK_GUARD(&s->error_mutex); + if (s->error) { + info->error_desc = g_strdup(error_get_pretty(s->error)); + } } static void fill_destination_migration_info(MigrationInfo *info) diff --git a/qapi/migration.json b/qapi/migration.json index d8f3bbd7b0..d7dfaa5db9 100644 --- a/qapi/migration.json +++ b/qapi/migration.json @@ -230,9 +230,8 @@ # throttled during auto-converge. This is only present when # auto-converge has started throttling guest cpus. (Since 2.7) # -# @error-desc: the human readable error description string, when -# @status is 'failed'. Clients should not attempt to parse the -# error strings. (Since 2.7) +# @error-desc: the human readable error description string. Clients +# should not attempt to parse the error strings. (Since 2.7) # # @postcopy-blocktime: total time when all vCPU were blocked during # postcopy live migration. This is only present when the From 2b2f6f411efa83c70409fa6de2e61ec28221c757 Mon Sep 17 00:00:00 2001 From: Peter Xu Date: Wed, 4 Oct 2023 18:02:32 -0400 Subject: [PATCH 0506/1077] migration: Introduce migrate_has_error() Introduce a helper to detect whether MigrationState.error is set for whatever reason. This is preparation work for any thread (e.g. source return path thread) to setup errors in an unified way to MigrationState, rather than relying on its own way to set errors (mark_source_rp_bad()). Reviewed-by: Fabiano Rosas Reviewed-by: Juan Quintela Signed-off-by: Peter Xu Signed-off-by: Juan Quintela Message-ID: <20231004220240.167175-3-peterx@redhat.com> --- migration/migration.c | 7 +++++++ migration/migration.h | 1 + 2 files changed, 8 insertions(+) diff --git a/migration/migration.c b/migration/migration.c index 57f9e9ed0c..409eb3e916 100644 --- a/migration/migration.c +++ b/migration/migration.c @@ -1234,6 +1234,13 @@ void migrate_set_error(MigrationState *s, const Error *error) } } +bool migrate_has_error(MigrationState *s) +{ + /* The lock is not helpful here, but still follow the rule */ + QEMU_LOCK_GUARD(&s->error_mutex); + return qatomic_read(&s->error); +} + static void migrate_error_free(MigrationState *s) { QEMU_LOCK_GUARD(&s->error_mutex); diff --git a/migration/migration.h b/migration/migration.h index 972597f4de..4106a1dc54 100644 --- a/migration/migration.h +++ b/migration/migration.h @@ -476,6 +476,7 @@ bool migration_has_all_channels(void); uint64_t migrate_max_downtime(void); void migrate_set_error(MigrationState *s, const Error *error); +bool migrate_has_error(MigrationState *s); void migrate_fd_connect(MigrationState *s, Error *error_in); From f4b897f4854c579cedc4d5ebb6db16c03a1eaeb1 Mon Sep 17 00:00:00 2001 From: Peter Xu Date: Wed, 4 Oct 2023 18:02:35 -0400 Subject: [PATCH 0507/1077] qemufile: Always return a verbose error There're a lot of cases where we only have an errno set in last_error but without a detailed error description. When this happens, try to generate an error contains the errno as a descriptive error. This will be helpful in cases where one relies on the Error*. E.g., migration state only caches Error* in MigrationState.error. With this, we'll display correct error messages in e.g. query-migrate when the error was only set by qemu_file_set_error(). Reviewed-by: Fabiano Rosas Reviewed-by: Juan Quintela Signed-off-by: Peter Xu Signed-off-by: Juan Quintela Message-ID: <20231004220240.167175-6-peterx@redhat.com> --- migration/qemu-file.c | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/migration/qemu-file.c b/migration/qemu-file.c index 5e8207dae4..7fb659296f 100644 --- a/migration/qemu-file.c +++ b/migration/qemu-file.c @@ -142,15 +142,24 @@ void qemu_file_set_hooks(QEMUFile *f, const QEMUFileHooks *hooks) * * Return negative error value if there has been an error on previous * operations, return 0 if no error happened. - * Optional, it returns Error* in errp, but it may be NULL even if return value - * is not 0. * + * If errp is specified, a verbose error message will be copied over. */ static int qemu_file_get_error_obj(QEMUFile *f, Error **errp) { - if (errp) { - *errp = f->last_error_obj ? error_copy(f->last_error_obj) : NULL; + if (!f->last_error) { + return 0; } + + /* There is an error */ + if (errp) { + if (f->last_error_obj) { + *errp = error_copy(f->last_error_obj); + } else { + error_setg_errno(errp, -f->last_error, "Channel error"); + } + } + return f->last_error; } From 1015ff5476ceed0ff76156c1b60e76f9d21db497 Mon Sep 17 00:00:00 2001 From: Peter Xu Date: Wed, 4 Oct 2023 18:02:36 -0400 Subject: [PATCH 0508/1077] migration: Remember num of ramblocks to sync during recovery Instead of only relying on the count of rp_sem, make the counter be part of RAMState so it can be used in both threads to synchronize on the process. rp_sem will be further reused in follow up patches, as a way to kick the main thread, e.g., on recovery failures. Reviewed-by: Fabiano Rosas Reviewed-by: Juan Quintela Signed-off-by: Peter Xu Signed-off-by: Juan Quintela Message-ID: <20231004220240.167175-7-peterx@redhat.com> --- migration/ram.c | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/migration/ram.c b/migration/ram.c index e4bfd39f08..6c40d9af0c 100644 --- a/migration/ram.c +++ b/migration/ram.c @@ -394,6 +394,14 @@ struct RAMState { /* Queue of outstanding page requests from the destination */ QemuMutex src_page_req_mutex; QSIMPLEQ_HEAD(, RAMSrcPageRequest) src_page_requests; + + /* + * This is only used when postcopy is in recovery phase, to communicate + * between the migration thread and the return path thread on dirty + * bitmap synchronizations. This field is unused in other stages of + * RAM migration. + */ + unsigned int postcopy_bmap_sync_requested; }; typedef struct RAMState RAMState; @@ -4119,20 +4127,20 @@ static int ram_dirty_bitmap_sync_all(MigrationState *s, RAMState *rs) { RAMBlock *block; QEMUFile *file = s->to_dst_file; - int ramblock_count = 0; trace_ram_dirty_bitmap_sync_start(); + qatomic_set(&rs->postcopy_bmap_sync_requested, 0); RAMBLOCK_FOREACH_NOT_IGNORED(block) { qemu_savevm_send_recv_bitmap(file, block->idstr); trace_ram_dirty_bitmap_request(block->idstr); - ramblock_count++; + qatomic_inc(&rs->postcopy_bmap_sync_requested); } trace_ram_dirty_bitmap_sync_wait(); /* Wait until all the ramblocks' dirty bitmap synced */ - while (ramblock_count--) { + while (qatomic_read(&rs->postcopy_bmap_sync_requested)) { qemu_sem_wait(&s->rp_state.rp_sem); } @@ -4159,6 +4167,7 @@ int ram_dirty_bitmap_reload(MigrationState *s, RAMBlock *block) unsigned long *le_bitmap, nbits = block->used_length >> TARGET_PAGE_BITS; uint64_t local_size = DIV_ROUND_UP(nbits, 8); uint64_t size, end_mark; + RAMState *rs = ram_state; trace_ram_dirty_bitmap_reload_begin(block->idstr); @@ -4225,6 +4234,8 @@ int ram_dirty_bitmap_reload(MigrationState *s, RAMBlock *block) /* We'll recalculate migration_dirty_pages in ram_state_resume_prepare(). */ trace_ram_dirty_bitmap_reload_complete(block->idstr); + qatomic_dec(&rs->postcopy_bmap_sync_requested); + /* * We succeeded to sync bitmap for current ramblock. If this is * the last one to sync, we need to notify the main send thread. From 5e79a4bf032213fd59aa614781751fe76584f8e8 Mon Sep 17 00:00:00 2001 From: Peter Xu Date: Wed, 4 Oct 2023 18:02:37 -0400 Subject: [PATCH 0509/1077] migration: Add migration_rp_wait|kick() It's just a simple wrapper for rp_sem on either wait() or kick(), make it even clearer on how it is used. Prepared to be used even for other things. Reviewed-by: Fabiano Rosas Signed-off-by: Peter Xu Message-ID: <20231004220240.167175-8-peterx@redhat.com> Signed-off-by: Juan Quintela --- migration/migration.c | 14 ++++++++++++-- migration/migration.h | 15 +++++++++++++++ migration/ram.c | 16 +++++++--------- 3 files changed, 34 insertions(+), 11 deletions(-) diff --git a/migration/migration.c b/migration/migration.c index 409eb3e916..1c6c81ad49 100644 --- a/migration/migration.c +++ b/migration/migration.c @@ -1763,6 +1763,16 @@ static void mark_source_rp_bad(MigrationState *s) s->rp_state.error = true; } +void migration_rp_wait(MigrationState *s) +{ + qemu_sem_wait(&s->rp_state.rp_sem); +} + +void migration_rp_kick(MigrationState *s) +{ + qemu_sem_post(&s->rp_state.rp_sem); +} + static struct rp_cmd_args { ssize_t len; /* -1 = variable */ const char *name; @@ -1835,7 +1845,7 @@ static int migrate_handle_rp_resume_ack(MigrationState *s, uint32_t value) MIGRATION_STATUS_POSTCOPY_ACTIVE); /* Notify send thread that time to continue send pages */ - qemu_sem_post(&s->rp_state.rp_sem); + migration_rp_kick(s); return 0; } @@ -2464,7 +2474,7 @@ static int postcopy_resume_handshake(MigrationState *s) qemu_savevm_send_postcopy_resume(s->to_dst_file); while (s->state == MIGRATION_STATUS_POSTCOPY_RECOVER) { - qemu_sem_wait(&s->rp_state.rp_sem); + migration_rp_wait(s); } if (s->state == MIGRATION_STATUS_POSTCOPY_ACTIVE) { diff --git a/migration/migration.h b/migration/migration.h index 4106a1dc54..cd5534337c 100644 --- a/migration/migration.h +++ b/migration/migration.h @@ -316,6 +316,12 @@ struct MigrationState { * be cleared in the rp_thread! */ bool rp_thread_created; + /* + * Used to synchronize between migration main thread and return + * path thread. The migration thread can wait() on this sem, while + * other threads (e.g., return path thread) can kick it using a + * post(). + */ QemuSemaphore rp_sem; /* * We post to this when we got one PONG from dest. So far it's an @@ -527,4 +533,13 @@ void migration_populate_vfio_info(MigrationInfo *info); void migration_reset_vfio_bytes_transferred(void); void postcopy_temp_page_reset(PostcopyTmpPage *tmp_page); +/* Migration thread waiting for return path thread. */ +void migration_rp_wait(MigrationState *s); +/* + * Kick the migration thread waiting for return path messages. NOTE: the + * name can be slightly confusing (when read as "kick the rp thread"), just + * to remember the target is always the migration thread. + */ +void migration_rp_kick(MigrationState *s); + #endif diff --git a/migration/ram.c b/migration/ram.c index 6c40d9af0c..2f5ce4d60b 100644 --- a/migration/ram.c +++ b/migration/ram.c @@ -4141,7 +4141,7 @@ static int ram_dirty_bitmap_sync_all(MigrationState *s, RAMState *rs) /* Wait until all the ramblocks' dirty bitmap synced */ while (qatomic_read(&rs->postcopy_bmap_sync_requested)) { - qemu_sem_wait(&s->rp_state.rp_sem); + migration_rp_wait(s); } trace_ram_dirty_bitmap_sync_complete(); @@ -4149,11 +4149,6 @@ static int ram_dirty_bitmap_sync_all(MigrationState *s, RAMState *rs) return 0; } -static void ram_dirty_bitmap_reload_notify(MigrationState *s) -{ - qemu_sem_post(&s->rp_state.rp_sem); -} - /* * Read the received bitmap, revert it as the initial dirty bitmap. * This is only used when the postcopy migration is paused but wants @@ -4237,10 +4232,13 @@ int ram_dirty_bitmap_reload(MigrationState *s, RAMBlock *block) qatomic_dec(&rs->postcopy_bmap_sync_requested); /* - * We succeeded to sync bitmap for current ramblock. If this is - * the last one to sync, we need to notify the main send thread. + * We succeeded to sync bitmap for current ramblock. Always kick the + * migration thread to check whether all requested bitmaps are + * reloaded. NOTE: it's racy to only kick when requested==0, because + * we don't know whether the migration thread may still be increasing + * it. */ - ram_dirty_bitmap_reload_notify(s); + migration_rp_kick(s); ret = 0; out: From b3175081a1215339b741ee92a00d5678a3094249 Mon Sep 17 00:00:00 2001 From: Jianlin Li Date: Fri, 22 Sep 2023 15:38:35 +0800 Subject: [PATCH 0510/1077] Update AMD memory encryption document links. The previous links for the white paper and programmer's manual are no longer available. Replace them with the new ones. Signed-off-by: Jianlin Li Reviewed-by: Michael Tokarev Signed-off-by: Michael Tokarev --- docs/system/i386/amd-memory-encryption.rst | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/system/i386/amd-memory-encryption.rst b/docs/system/i386/amd-memory-encryption.rst index dcf4add0e7..e9bc142bc1 100644 --- a/docs/system/i386/amd-memory-encryption.rst +++ b/docs/system/i386/amd-memory-encryption.rst @@ -183,13 +183,13 @@ References ---------- `AMD Memory Encryption whitepaper -`_ +`_ .. [SEVAPI] `Secure Encrypted Virtualization API `_ .. [APMVOL2] `AMD64 Architecture Programmer's Manual Volume 2: System Programming - `_ + `_ KVM Forum slides: @@ -199,7 +199,7 @@ KVM Forum slides: `_ `AMD64 Architecture Programmer's Manual: -`_ +`_ * SME is section 7.10 * SEV is section 15.34 From 99bb31585cccd474b852deb29bd982e2ee542871 Mon Sep 17 00:00:00 2001 From: Akihiko Odaki Date: Thu, 10 Nov 2022 19:06:20 +0900 Subject: [PATCH 0511/1077] qga: Remove platform GUID definitions GUID_DEVINTERFACE_DISK and GUID_DEVINTERFACE_STORAGEPORT are already defined by MinGW-w64. They are not only unnecessary, but can lead to duplicate definition errors at link time with some unknown condition. Signed-off-by: Akihiko Odaki Reviewed-by: Konstantin Kostiuk Signed-off-by: Konstantin Kostiuk --- qga/commands-win32.c | 7 ------- 1 file changed, 7 deletions(-) diff --git a/qga/commands-win32.c b/qga/commands-win32.c index 6beae659b7..697c65507c 100644 --- a/qga/commands-win32.c +++ b/qga/commands-win32.c @@ -501,13 +501,6 @@ static GuestDiskBusType find_bus_type(STORAGE_BUS_TYPE bus) return win2qemu[(int)bus]; } -DEFINE_GUID(GUID_DEVINTERFACE_DISK, - 0x53f56307L, 0xb6bf, 0x11d0, 0x94, 0xf2, - 0x00, 0xa0, 0xc9, 0x1e, 0xfb, 0x8b); -DEFINE_GUID(GUID_DEVINTERFACE_STORAGEPORT, - 0x2accfe60L, 0xc130, 0x11d2, 0xb0, 0x82, - 0x00, 0xa0, 0xc9, 0x1e, 0xfb, 0x8b); - static void get_pci_address_for_device(GuestPCIAddress *pci, HDEVINFO dev_info) { From d6f67b83b81bf49b5c62e77143ed39c020e51830 Mon Sep 17 00:00:00 2001 From: Daniel Xu Date: Sun, 1 Oct 2023 12:38:25 -0600 Subject: [PATCH 0512/1077] qga: Fix memory leak when output stream is unused If capture-output is requested but one of the channels goes unused (eg. we attempt to capture stderr but the command never writes to stderr), we can leak memory. guest_exec_output_watch() is (from what I understand) unconditionally called for both streams if output capture is requested. The first call will always pass the `p->size == p->length` check b/c both values are 0. Then GUEST_EXEC_IO_SIZE bytes will be allocated for the stream. But when we reap the exited process there's a `gei->err.length > 0` check to actually free the buffer. Which does not get run if the command doesn't write to the stream. Fix by making free() unconditional. Reviewed-by: Konstantin Kostiuk Signed-off-by: Daniel Xu Signed-off-by: Konstantin Kostiuk --- qga/commands.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/qga/commands.c b/qga/commands.c index 09c683e263..ce172edd2d 100644 --- a/qga/commands.c +++ b/qga/commands.c @@ -206,15 +206,15 @@ GuestExecStatus *qmp_guest_exec_status(int64_t pid, Error **errp) #endif if (gei->out.length > 0) { ges->out_data = g_base64_encode(gei->out.data, gei->out.length); - g_free(gei->out.data); ges->has_out_truncated = gei->out.truncated; } + g_free(gei->out.data); if (gei->err.length > 0) { ges->err_data = g_base64_encode(gei->err.data, gei->err.length); - g_free(gei->err.data); ges->has_err_truncated = gei->err.truncated; } + g_free(gei->err.data); QTAILQ_REMOVE(&guest_exec_state.processes, gei, next); g_free(gei); From f897ef0d47d332d4c4498aed1140c6856fe56d79 Mon Sep 17 00:00:00 2001 From: Daniel Xu Date: Sun, 1 Oct 2023 12:38:26 -0600 Subject: [PATCH 0513/1077] qapi: qga: Clarify when out-data and err-data are populated If output is being captured for a guest-exec invocation, the out-data and err-data fields of guest-exec-status are only populated after the process is reaped. This is somewhat counter intuitive and too late to change. Thus, it would be good to document the behavior. Signed-off-by: Daniel Xu Reviewed-by: Konstantin Kostiuk Signed-off-by: Konstantin Kostiuk --- qga/qapi-schema.json | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/qga/qapi-schema.json b/qga/qapi-schema.json index b720dd4379..876e2a8ea8 100644 --- a/qga/qapi-schema.json +++ b/qga/qapi-schema.json @@ -1220,11 +1220,13 @@ # @signal: signal number (linux) or unhandled exception code (windows) # if the process was abnormally terminated. # -# @out-data: base64-encoded stdout of the process +# @out-data: base64-encoded stdout of the process. This field will only +# be populated after the process exits. # -# @err-data: base64-encoded stderr of the process Note: @out-data and +# @err-data: base64-encoded stderr of the process. Note: @out-data and # @err-data are present only if 'capture-output' was specified for -# 'guest-exec' +# 'guest-exec'. This field will only be populated after the process +# exits. # # @out-truncated: true if stdout was not fully captured due to size # limitation. From 91e11db7bcc486db2dc2bdab94ac5de62c02ce9a Mon Sep 17 00:00:00 2001 From: John Snow Date: Thu, 28 Sep 2023 00:49:38 -0400 Subject: [PATCH 0514/1077] python/machine: move socket setup out of _base_args property MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This property isn't meant to do much else besides return a list of strings, so move this setup back out into _pre_launch(). Signed-off-by: John Snow Reviewed-by: Ani Sinha Reviewed-by: Daniel P. Berrangé Message-id: 20230928044943.849073-2-jsnow@redhat.com Signed-off-by: John Snow --- python/qemu/machine/machine.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/python/qemu/machine/machine.py b/python/qemu/machine/machine.py index 35d5a672db..345610d6e4 100644 --- a/python/qemu/machine/machine.py +++ b/python/qemu/machine/machine.py @@ -301,9 +301,7 @@ class QEMUMachine: if self._qmp_set: if self._sock_pair: - fd = self._sock_pair[0].fileno() - os.set_inheritable(fd, True) - moncdev = f"socket,id=mon,fd={fd}" + moncdev = f"socket,id=mon,fd={self._sock_pair[0].fileno()}" elif isinstance(self._monitor_address, tuple): moncdev = "socket,id=mon,host={},port={}".format( *self._monitor_address @@ -340,6 +338,7 @@ class QEMUMachine: if self._qmp_set: if self._monitor_address is None: self._sock_pair = socket.socketpair() + os.set_inheritable(self._sock_pair[0].fileno(), True) sock = self._sock_pair[1] if isinstance(self._monitor_address, str): self._remove_files.append(self._monitor_address) From 612b3ba218092825467810b1a38de2026dac2bfc Mon Sep 17 00:00:00 2001 From: John Snow Date: Thu, 28 Sep 2023 00:49:39 -0400 Subject: [PATCH 0515/1077] python/machine: close sock_pair in cleanup path MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit If everything has gone smoothly, we'll already have closed the socket we gave to the child during post_launch. The other half of the pair that we gave to the QMP connection should, likewise, be definitively closed by now. However, in the cleanup path, it's possible we've created the socketpair but flubbed the launch and need to clean up resources. These resources *would* be handled by the garbage collector, but that can happen at unpredictable times. Nicer to just clean them up synchronously on the exit path, here. Signed-off-by: John Snow Reviewed-by: Ani Sinha Reviewed-by: Daniel P. Berrangé Message-id: 20230928044943.849073-3-jsnow@redhat.com Signed-off-by: John Snow --- python/qemu/machine/machine.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/python/qemu/machine/machine.py b/python/qemu/machine/machine.py index 345610d6e4..e26109e6f0 100644 --- a/python/qemu/machine/machine.py +++ b/python/qemu/machine/machine.py @@ -396,6 +396,11 @@ class QEMUMachine: finally: assert self._qmp_connection is None + if self._sock_pair: + self._sock_pair[0].close() + self._sock_pair[1].close() + self._sock_pair = None + self._close_qemu_log_file() self._load_io_log() From 5f263cb1ccfb6f038fe706d9876d1cea8871a83a Mon Sep 17 00:00:00 2001 From: John Snow Date: Thu, 28 Sep 2023 00:49:40 -0400 Subject: [PATCH 0516/1077] python/console_socket: accept existing FD in initializer MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Useful if we want to use ConsoleSocket() for a socket created by socketpair(). Signed-off-by: John Snow Reviewed-by: Ani Sinha Reviewed-by: Daniel P. Berrangé Message-id: 20230928044943.849073-4-jsnow@redhat.com Signed-off-by: John Snow --- python/qemu/machine/console_socket.py | 29 +++++++++++++++++++-------- 1 file changed, 21 insertions(+), 8 deletions(-) diff --git a/python/qemu/machine/console_socket.py b/python/qemu/machine/console_socket.py index 4e28ba9bb2..0a4e09ffc7 100644 --- a/python/qemu/machine/console_socket.py +++ b/python/qemu/machine/console_socket.py @@ -24,19 +24,32 @@ class ConsoleSocket(socket.socket): """ ConsoleSocket represents a socket attached to a char device. - Optionally (if drain==True), drains the socket and places the bytes - into an in memory buffer for later processing. - - Optionally a file path can be passed in and we will also - dump the characters to this file for debugging purposes. + :param address: An AF_UNIX path or address. + :param sock_fd: Optionally, an existing socket file descriptor. + One of address or sock_fd must be specified. + :param file: Optionally, a filename to log to. + :param drain: Optionally, drains the socket and places the bytes + into an in memory buffer for later processing. """ - def __init__(self, address: str, file: Optional[str] = None, + def __init__(self, + address: Optional[str] = None, + sock_fd: Optional[int] = None, + file: Optional[str] = None, drain: bool = False): + if address is None and sock_fd is None: + raise ValueError("one of 'address' or 'sock_fd' must be specified") + if address is not None and sock_fd is not None: + raise ValueError("can't specify both 'address' and 'sock_fd'") + self._recv_timeout_sec = 300.0 self._sleep_time = 0.5 self._buffer: Deque[int] = deque() - socket.socket.__init__(self, socket.AF_UNIX, socket.SOCK_STREAM) - self.connect(address) + if address is not None: + socket.socket.__init__(self, socket.AF_UNIX, socket.SOCK_STREAM) + self.connect(address) + else: + assert sock_fd is not None + socket.socket.__init__(self, fileno=sock_fd) self._logfile = None if file: # pylint: disable=consider-using-with From 1d4796cd008373a1c1657473f7c7e82eaf32ea1b Mon Sep 17 00:00:00 2001 From: John Snow Date: Thu, 28 Sep 2023 00:49:41 -0400 Subject: [PATCH 0517/1077] python/machine: use socketpair() for console connections MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Create a socketpair for the console output. This should help eliminate race conditions around console text early in the boot process that might otherwise have been dropped on the floor before being able to connect to QEMU under "server,nowait". Signed-off-by: John Snow Reviewed-by: Ani Sinha Reviewed-by: Daniel P. Berrangé Message-id: 20230928044943.849073-5-jsnow@redhat.com Signed-off-by: John Snow --- python/qemu/machine/machine.py | 30 +++++++++++++++++++++++++++--- 1 file changed, 27 insertions(+), 3 deletions(-) diff --git a/python/qemu/machine/machine.py b/python/qemu/machine/machine.py index e26109e6f0..4156b8cf7d 100644 --- a/python/qemu/machine/machine.py +++ b/python/qemu/machine/machine.py @@ -159,6 +159,8 @@ class QEMUMachine: self._name = name or f"{id(self):x}" self._sock_pair: Optional[Tuple[socket.socket, socket.socket]] = None + self._cons_sock_pair: Optional[ + Tuple[socket.socket, socket.socket]] = None self._temp_dir: Optional[str] = None self._base_temp_dir = base_temp_dir self._sock_dir = sock_dir @@ -316,8 +318,9 @@ class QEMUMachine: for _ in range(self._console_index): args.extend(['-serial', 'null']) if self._console_set: - chardev = ('socket,id=console,path=%s,server=on,wait=off' % - self._console_address) + assert self._cons_sock_pair is not None + fd = self._cons_sock_pair[0].fileno() + chardev = f"socket,id=console,fd={fd}" args.extend(['-chardev', chardev]) if self._console_device_type is None: args.extend(['-serial', 'chardev:console']) @@ -352,6 +355,10 @@ class QEMUMachine: nickname=self._name ) + if self._console_set: + self._cons_sock_pair = socket.socketpair() + os.set_inheritable(self._cons_sock_pair[0].fileno(), True) + # NOTE: Make sure any opened resources are *definitely* freed in # _post_shutdown()! # pylint: disable=consider-using-with @@ -369,6 +376,9 @@ class QEMUMachine: def _post_launch(self) -> None: if self._sock_pair: self._sock_pair[0].close() + if self._cons_sock_pair: + self._cons_sock_pair[0].close() + if self._qmp_connection: if self._sock_pair: self._qmp.connect() @@ -524,6 +534,11 @@ class QEMUMachine: self._console_socket.close() self._console_socket = None + if self._cons_sock_pair: + self._cons_sock_pair[0].close() + self._cons_sock_pair[1].close() + self._cons_sock_pair = None + def _hard_shutdown(self) -> None: """ Perform early cleanup, kill the VM, and wait for it to terminate. @@ -885,10 +900,19 @@ class QEMUMachine: """ if self._console_socket is None: LOG.debug("Opening console socket") + if not self._console_set: + raise QEMUMachineError( + "Attempt to access console socket with no connection") + assert self._cons_sock_pair is not None + # os.dup() is used here for sock_fd because otherwise we'd + # have two rich python socket objects that would each try to + # close the same underlying fd when either one gets garbage + # collected. self._console_socket = console_socket.ConsoleSocket( - self._console_address, + sock_fd=os.dup(self._cons_sock_pair[1].fileno()), file=self._console_log_path, drain=self._drain_console) + self._cons_sock_pair[1].close() return self._console_socket @property From d39673781361ed528c2afba7197f26481caab482 Mon Sep 17 00:00:00 2001 From: John Snow Date: Thu, 28 Sep 2023 00:49:42 -0400 Subject: [PATCH 0518/1077] python/machine: use socketpair() for qtest connection MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Like the QMP and console sockets, begin using socketpairs for the qtest connection, too. After this patch, we'll be able to remove the vestigial sock_dir argument, but that cleanup is best done in its own patch. Signed-off-by: John Snow Reviewed-by: Daniel P. Berrangé Message-id: 20230928044943.849073-6-jsnow@redhat.com Signed-off-by: John Snow --- python/qemu/machine/qtest.py | 49 +++++++++++++++++++++++++++++------- 1 file changed, 40 insertions(+), 9 deletions(-) diff --git a/python/qemu/machine/qtest.py b/python/qemu/machine/qtest.py index 1c46138bd0..8180d3ab01 100644 --- a/python/qemu/machine/qtest.py +++ b/python/qemu/machine/qtest.py @@ -24,6 +24,7 @@ from typing import ( Optional, Sequence, TextIO, + Tuple, ) from qemu.qmp import SocketAddrT @@ -38,23 +39,41 @@ class QEMUQtestProtocol: :param address: QEMU address, can be either a unix socket path (string) or a tuple in the form ( address, port ) for a TCP connection - :param server: server mode, listens on the socket (bool) + :param sock: An existing socket can be provided as an alternative to + an address. One of address or sock must be provided. + :param server: server mode, listens on the socket. Only meaningful + in conjunction with an address and not an existing + socket. + :raise socket.error: on socket connection errors .. note:: No connection is established by __init__(), this is done by the connect() or accept() methods. """ - def __init__(self, address: SocketAddrT, + def __init__(self, + address: Optional[SocketAddrT] = None, + sock: Optional[socket.socket] = None, server: bool = False): + if address is None and sock is None: + raise ValueError("Either 'address' or 'sock' must be specified") + if address is not None and sock is not None: + raise ValueError( + "Either 'address' or 'sock' must be specified, but not both") + if sock is not None and server: + raise ValueError("server=True is meaningless when passing socket") + self._address = address - self._sock = self._get_sock() + self._sock = sock or self._get_sock() self._sockfile: Optional[TextIO] = None + if server: + assert self._address is not None self._sock.bind(self._address) self._sock.listen(1) def _get_sock(self) -> socket.socket: + assert self._address is not None if isinstance(self._address, tuple): family = socket.AF_INET else: @@ -67,7 +86,8 @@ class QEMUQtestProtocol: @raise socket.error on socket connection errors """ - self._sock.connect(self._address) + if self._address is not None: + self._sock.connect(self._address) self._sockfile = self._sock.makefile(mode='r') def accept(self) -> None: @@ -127,29 +147,40 @@ class QEMUQtestMachine(QEMUMachine): base_temp_dir=base_temp_dir, sock_dir=sock_dir, qmp_timer=qmp_timer) self._qtest: Optional[QEMUQtestProtocol] = None - self._qtest_path = os.path.join(sock_dir, name + "-qtest.sock") + self._qtest_sock_pair: Optional[ + Tuple[socket.socket, socket.socket]] = None @property def _base_args(self) -> List[str]: args = super()._base_args + assert self._qtest_sock_pair is not None + fd = self._qtest_sock_pair[0].fileno() args.extend([ - '-qtest', f"unix:path={self._qtest_path}", + '-chardev', f"socket,id=qtest,fd={fd}", + '-qtest', 'chardev:qtest', '-accel', 'qtest' ]) return args def _pre_launch(self) -> None: + self._qtest_sock_pair = socket.socketpair() + os.set_inheritable(self._qtest_sock_pair[0].fileno(), True) super()._pre_launch() - self._qtest = QEMUQtestProtocol(self._qtest_path, server=True) + self._qtest = QEMUQtestProtocol(sock=self._qtest_sock_pair[1]) def _post_launch(self) -> None: assert self._qtest is not None super()._post_launch() - self._qtest.accept() + if self._qtest_sock_pair: + self._qtest_sock_pair[0].close() + self._qtest.connect() def _post_shutdown(self) -> None: + if self._qtest_sock_pair: + self._qtest_sock_pair[0].close() + self._qtest_sock_pair[1].close() + self._qtest_sock_pair = None super()._post_shutdown() - self._remove_if_exists(self._qtest_path) def qtest(self, cmd: str) -> str: """ From 46d4747ab59721e657c0012d2f2ca6f3aeb7085d Mon Sep 17 00:00:00 2001 From: John Snow Date: Thu, 28 Sep 2023 00:49:43 -0400 Subject: [PATCH 0519/1077] python/machine: remove unused sock_dir argument MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit By using a socketpair for all of the sockets managed by the VM class and its extensions, we don't need the sock_dir argument anymore, so remove it. We only added this argument so that we could specify a second, shorter temporary directory for cases where the temp/log dirs were "too long" as a socket name on macOS. We don't need it for this class now. In one case, avocado testing takes over responsibility for creating an appropriate sockdir. Signed-off-by: John Snow Reviewed-by: Daniel P. Berrangé Message-id: 20230928044943.849073-7-jsnow@redhat.com Signed-off-by: John Snow --- python/qemu/machine/machine.py | 18 ------------------ python/qemu/machine/qtest.py | 5 +---- tests/avocado/acpi-bits.py | 5 +---- tests/avocado/avocado_qemu/__init__.py | 2 +- tests/avocado/machine_aspeed.py | 5 ++++- tests/qemu-iotests/iotests.py | 2 +- tests/qemu-iotests/tests/copy-before-write | 3 +-- 7 files changed, 9 insertions(+), 31 deletions(-) diff --git a/python/qemu/machine/machine.py b/python/qemu/machine/machine.py index 4156b8cf7d..d539e91268 100644 --- a/python/qemu/machine/machine.py +++ b/python/qemu/machine/machine.py @@ -127,7 +127,6 @@ class QEMUMachine: name: Optional[str] = None, base_temp_dir: str = "/var/tmp", monitor_address: Optional[SocketAddrT] = None, - sock_dir: Optional[str] = None, drain_console: bool = False, console_log: Optional[str] = None, log_dir: Optional[str] = None, @@ -141,7 +140,6 @@ class QEMUMachine: @param name: prefix for socket and log file names (default: qemu-PID) @param base_temp_dir: default location where temp files are created @param monitor_address: address for QMP monitor - @param sock_dir: where to create socket (defaults to base_temp_dir) @param drain_console: (optional) True to drain console socket to buffer @param console_log: (optional) path to console log file @param log_dir: where to create and keep log files @@ -163,7 +161,6 @@ class QEMUMachine: Tuple[socket.socket, socket.socket]] = None self._temp_dir: Optional[str] = None self._base_temp_dir = base_temp_dir - self._sock_dir = sock_dir self._log_dir = log_dir self._monitor_address = monitor_address @@ -189,9 +186,6 @@ class QEMUMachine: self._console_index = 0 self._console_set = False self._console_device_type: Optional[str] = None - self._console_address = os.path.join( - self.sock_dir, f"{self._name}.con" - ) self._console_socket: Optional[socket.socket] = None self._console_file: Optional[socket.SocketIO] = None self._remove_files: List[str] = [] @@ -335,9 +329,6 @@ class QEMUMachine: return self._args def _pre_launch(self) -> None: - if self._console_set: - self._remove_files.append(self._console_address) - if self._qmp_set: if self._monitor_address is None: self._sock_pair = socket.socketpair() @@ -937,15 +928,6 @@ class QEMUMachine: dir=self._base_temp_dir) return self._temp_dir - @property - def sock_dir(self) -> str: - """ - Returns the directory used for sockfiles by this machine. - """ - if self._sock_dir: - return self._sock_dir - return self.temp_dir - @property def log_dir(self) -> str: """ diff --git a/python/qemu/machine/qtest.py b/python/qemu/machine/qtest.py index 8180d3ab01..4f5ede85b2 100644 --- a/python/qemu/machine/qtest.py +++ b/python/qemu/machine/qtest.py @@ -135,17 +135,14 @@ class QEMUQtestMachine(QEMUMachine): wrapper: Sequence[str] = (), name: Optional[str] = None, base_temp_dir: str = "/var/tmp", - sock_dir: Optional[str] = None, qmp_timer: Optional[float] = None): # pylint: disable=too-many-arguments if name is None: name = "qemu-%d" % os.getpid() - if sock_dir is None: - sock_dir = base_temp_dir super().__init__(binary, args, wrapper=wrapper, name=name, base_temp_dir=base_temp_dir, - sock_dir=sock_dir, qmp_timer=qmp_timer) + qmp_timer=qmp_timer) self._qtest: Optional[QEMUQtestProtocol] = None self._qtest_sock_pair: Optional[ Tuple[socket.socket, socket.socket]] = None diff --git a/tests/avocado/acpi-bits.py b/tests/avocado/acpi-bits.py index bb3f818689..eca13dc518 100644 --- a/tests/avocado/acpi-bits.py +++ b/tests/avocado/acpi-bits.py @@ -92,17 +92,14 @@ class QEMUBitsMachine(QEMUMachine): # pylint: disable=too-few-public-methods base_temp_dir: str = "/var/tmp", debugcon_log: str = "debugcon-log.txt", debugcon_addr: str = "0x403", - sock_dir: Optional[str] = None, qmp_timer: Optional[float] = None): # pylint: disable=too-many-arguments if name is None: name = "qemu-bits-%d" % os.getpid() - if sock_dir is None: - sock_dir = base_temp_dir super().__init__(binary, args, wrapper=wrapper, name=name, base_temp_dir=base_temp_dir, - sock_dir=sock_dir, qmp_timer=qmp_timer) + qmp_timer=qmp_timer) self.debugcon_log = debugcon_log self.debugcon_addr = debugcon_addr self.base_temp_dir = base_temp_dir diff --git a/tests/avocado/avocado_qemu/__init__.py b/tests/avocado/avocado_qemu/__init__.py index 0172a359b7..0589534f28 100644 --- a/tests/avocado/avocado_qemu/__init__.py +++ b/tests/avocado/avocado_qemu/__init__.py @@ -322,7 +322,7 @@ class QemuSystemTest(QemuBaseTest): def _new_vm(self, name, *args): self._sd = tempfile.TemporaryDirectory(prefix="qemu_") vm = QEMUMachine(self.qemu_bin, base_temp_dir=self.workdir, - sock_dir=self._sd.name, log_dir=self.logdir) + log_dir=self.logdir) self.log.debug('QEMUMachine "%s" created', name) self.log.debug('QEMUMachine "%s" temp_dir: %s', name, vm.temp_dir) self.log.debug('QEMUMachine "%s" log_dir: %s', name, vm.log_dir) diff --git a/tests/avocado/machine_aspeed.py b/tests/avocado/machine_aspeed.py index 90f1b7cb77..f691ee3fb8 100644 --- a/tests/avocado/machine_aspeed.py +++ b/tests/avocado/machine_aspeed.py @@ -247,7 +247,10 @@ class AST2x00Machine(QemuSystemTest): image_path = self.fetch_asset(image_url, asset_hash=image_hash, algorithm='sha256') - socket = os.path.join(self.vm.sock_dir, 'swtpm-socket') + # force creation of VM object, which also defines self._sd + vm = self.vm + + socket = os.path.join(self._sd.name, 'swtpm-socket') subprocess.run(['swtpm', 'socket', '-d', '--tpm2', '--tpmstate', f'dir={self.vm.temp_dir}', diff --git a/tests/qemu-iotests/iotests.py b/tests/qemu-iotests/iotests.py index ef66fbd62b..145c682713 100644 --- a/tests/qemu-iotests/iotests.py +++ b/tests/qemu-iotests/iotests.py @@ -823,7 +823,7 @@ class VM(qtest.QEMUQtestMachine): super().__init__(qemu_prog, qemu_opts, wrapper=wrapper, name=name, base_temp_dir=test_dir, - sock_dir=sock_dir, qmp_timer=timer) + qmp_timer=timer) self._num_drives = 0 def _post_shutdown(self) -> None: diff --git a/tests/qemu-iotests/tests/copy-before-write b/tests/qemu-iotests/tests/copy-before-write index 2ffe092b31..d3987db942 100755 --- a/tests/qemu-iotests/tests/copy-before-write +++ b/tests/qemu-iotests/tests/copy-before-write @@ -44,8 +44,7 @@ class TestCbwError(iotests.QMPTestCase): opts = ['-nodefaults', '-display', 'none', '-machine', 'none'] self.vm = QEMUMachine(iotests.qemu_prog, opts, - base_temp_dir=iotests.test_dir, - sock_dir=iotests.sock_dir) + base_temp_dir=iotests.test_dir) self.vm.launch() def do_cbw_error(self, on_cbw_error): From ff2e08132f332b6b64d69774dd9a40a2b74fd04c Mon Sep 17 00:00:00 2001 From: John Snow Date: Fri, 6 Oct 2023 15:52:40 -0400 Subject: [PATCH 0520/1077] Python/iotests: Add type hint for nbd module The test bails gracefully if this module isn't installed, but linters need a little help understanding that. It's enough to just declare the type in this case. (Fixes pylint complaining about use of an uninitialized variable because it isn't wise enough to understand the notrun call is noreturn.) Signed-off-by: John Snow Reviewed-by: Eric Blake Reviewed-by: Vladimir Sementsov-Ogievskiy Message-id: 20231006195243.3131140-2-jsnow@redhat.com Signed-off-by: John Snow --- tests/qemu-iotests/tests/nbd-multiconn | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tests/qemu-iotests/tests/nbd-multiconn b/tests/qemu-iotests/tests/nbd-multiconn index 478a1eaba2..7e686a786e 100755 --- a/tests/qemu-iotests/tests/nbd-multiconn +++ b/tests/qemu-iotests/tests/nbd-multiconn @@ -20,6 +20,8 @@ import os from contextlib import contextmanager +from types import ModuleType + import iotests from iotests import qemu_img_create, qemu_io @@ -28,7 +30,7 @@ disk = os.path.join(iotests.test_dir, 'disk') size = '4M' nbd_sock = os.path.join(iotests.sock_dir, 'nbd_sock') nbd_uri = 'nbd+unix:///{}?socket=' + nbd_sock - +nbd: ModuleType @contextmanager def open_nbd(export_name): From acf873873ae38e68371b0c53c42d3530636ff94e Mon Sep 17 00:00:00 2001 From: John Snow Date: Fri, 6 Oct 2023 15:52:41 -0400 Subject: [PATCH 0521/1077] python/qmp: remove Server.wait_closed() call for Python 3.12 This patch is a backport from https://gitlab.com/qemu-project/python-qemu-qmp/-/commit/e03a3334b6a477beb09b293708632f2c06fe9f61 According to Guido in https://github.com/python/cpython/issues/104344 , this call was never meant to wait for the server to shut down - that is handled synchronously - but instead, this waits for all connections to close. Or, it would have, if it wasn't broken since it was introduced. 3.12 fixes the bug, which now causes a hang in our code. The fix is just to remove the wait. Signed-off-by: John Snow Reviewed-by: Vladimir Sementsov-Ogievskiy Message-id: 20231006195243.3131140-3-jsnow@redhat.com Signed-off-by: John Snow --- python/qemu/qmp/protocol.py | 1 - 1 file changed, 1 deletion(-) diff --git a/python/qemu/qmp/protocol.py b/python/qemu/qmp/protocol.py index 753182131f..a4ffdfad51 100644 --- a/python/qemu/qmp/protocol.py +++ b/python/qemu/qmp/protocol.py @@ -495,7 +495,6 @@ class AsyncProtocol(Generic[T]): try: self.logger.debug("Stopping server.") self._server.close() - await self._server.wait_closed() self.logger.debug("Server stopped.") finally: self._server = None From 761f241c97739f746dcf35d3f7a6ccc1e284d1dc Mon Sep 17 00:00:00 2001 From: John Snow Date: Fri, 6 Oct 2023 15:52:42 -0400 Subject: [PATCH 0522/1077] configure: fix error message to say Python 3.8 Signed-off-by: John Snow Reviewed-by: Vladimir Sementsov-Ogievskiy Message-id: 20231006195243.3131140-4-jsnow@redhat.com Signed-off-by: John Snow --- configure | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure b/configure index 8fada85a71..a49fc7b7e7 100755 --- a/configure +++ b/configure @@ -948,7 +948,7 @@ then # If first_python is set, there was a binary somewhere even though # it was not suitable. Use it for the error message. if test -n "$first_python"; then - error_exit "Cannot use '$first_python', Python >= 3.7 is required." \ + error_exit "Cannot use '$first_python', Python >= 3.8 is required." \ "Use --python=/path/to/python to specify a supported Python." else error_exit "Python not found. Use --python=/path/to/python" From 19a39e270bdedc3c526b2a53913d8fff88c907bf Mon Sep 17 00:00:00 2001 From: John Snow Date: Fri, 6 Oct 2023 15:52:43 -0400 Subject: [PATCH 0523/1077] Python: Enable python3.12 support Python 3.12 has released, so update the test infrastructure to test against this version. Update the configure script to look for it when an explicit Python interpreter isn't chosen. Signed-off-by: John Snow Reviewed-by: Vladimir Sementsov-Ogievskiy Message-id: 20231006195243.3131140-5-jsnow@redhat.com Signed-off-by: John Snow --- configure | 3 ++- python/setup.cfg | 3 ++- tests/docker/dockerfiles/python.docker | 6 +++++- 3 files changed, 9 insertions(+), 3 deletions(-) diff --git a/configure b/configure index a49fc7b7e7..96d0dd5ffc 100755 --- a/configure +++ b/configure @@ -562,7 +562,8 @@ first_python= if test -z "${PYTHON}"; then # A bare 'python' is traditionally python 2.x, but some distros # have it as python 3.x, so check in both places. - for binary in python3 python python3.11 python3.10 python3.9 python3.8; do + for binary in python3 python python3.12 python3.11 \ + python3.10 python3.9 python3.8; do if has "$binary"; then python=$(command -v "$binary") if check_py_version "$python"; then diff --git a/python/setup.cfg b/python/setup.cfg index 8c67dce457..48668609d3 100644 --- a/python/setup.cfg +++ b/python/setup.cfg @@ -18,6 +18,7 @@ classifiers = Programming Language :: Python :: 3.9 Programming Language :: Python :: 3.10 Programming Language :: Python :: 3.11 + Programming Language :: Python :: 3.12 Typing :: Typed [options] @@ -182,7 +183,7 @@ multi_line_output=3 # of python available on your system to run this test. [tox:tox] -envlist = py38, py39, py310, py311 +envlist = py38, py39, py310, py311, py312 skip_missing_interpreters = true [testenv] diff --git a/tests/docker/dockerfiles/python.docker b/tests/docker/dockerfiles/python.docker index 383ccbdc3a..a3c1321190 100644 --- a/tests/docker/dockerfiles/python.docker +++ b/tests/docker/dockerfiles/python.docker @@ -11,7 +11,11 @@ ENV PACKAGES \ python3-pip \ python3-tox \ python3-virtualenv \ - python3.10 + python3.10 \ + python3.11 \ + python3.12 \ + python3.8 \ + python3.9 RUN dnf install -y $PACKAGES RUN rpm -q $PACKAGES | sort > /packages.txt From bb30277273fdacff4635a59d5181f7a093cab6a8 Mon Sep 17 00:00:00 2001 From: Pierre Labatut Date: Thu, 28 Sep 2023 12:56:59 +0000 Subject: [PATCH 0524/1077] Fix compilation when UFFDIO_REGISTER is not set. Signed-off-by: Pierre Labatut Signed-off-by: Michael Tokarev --- subprojects/libvhost-user/libvhost-user.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/subprojects/libvhost-user/libvhost-user.c b/subprojects/libvhost-user/libvhost-user.c index 051a611da3..ac6d5d01d3 100644 --- a/subprojects/libvhost-user/libvhost-user.c +++ b/subprojects/libvhost-user/libvhost-user.c @@ -631,9 +631,9 @@ static bool generate_faults(VuDev *dev) { unsigned int i; for (i = 0; i < dev->nregions; i++) { +#ifdef UFFDIO_REGISTER VuDevRegion *dev_region = &dev->regions[i]; int ret; -#ifdef UFFDIO_REGISTER struct uffdio_register reg_struct; /* From 740ee84db8732c11e2db8bba6630046634f3c5e9 Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Fri, 29 Sep 2023 16:09:35 +0200 Subject: [PATCH 0525/1077] MAINTAINERS: Add g364fb and ds1225y to the Jazz section MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit These devices are only used by the Jazz machine, so they should be listed in the corresponding section in MAINTAINERS. Signed-off-by: Thomas Huth Acked-by: Philippe Mathieu-Daudé Signed-off-by: Michael Tokarev --- MAINTAINERS | 2 ++ 1 file changed, 2 insertions(+) diff --git a/MAINTAINERS b/MAINTAINERS index 9e7dec4a58..93756ec21a 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1286,8 +1286,10 @@ M: Hervé Poussineau R: Aleksandar Rikalo S: Maintained F: hw/mips/jazz.c +F: hw/display/g364fb.c F: hw/display/jazz_led.c F: hw/dma/rc4030.c +F: hw/nvram/ds1225y.c Malta M: Philippe Mathieu-Daudé From 5d0ce90dd6881b044bf1a28dc966eee44bcc1dde Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Fri, 29 Sep 2023 14:37:27 +0200 Subject: [PATCH 0526/1077] MAINTAINERS: Add unowned RISC-V related files to the right sections MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit There are a bunch of RISC-V files that are currently not covered by the "get_maintainers.pl" script. Add them to the right sections in MAINTAINERS to fix this problem. Signed-off-by: Thomas Huth Acked-by: Christoph Müllner Reviewed-by: Daniel Henrique Barboza Reviewed-by: Philipp Tomsich Reviewed-by: LIU Zhiwei Signed-off-by: Michael Tokarev --- MAINTAINERS | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/MAINTAINERS b/MAINTAINERS index 93756ec21a..e80fca855a 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -318,8 +318,11 @@ R: Daniel Henrique Barboza R: Liu Zhiwei L: qemu-riscv@nongnu.org S: Supported +F: configs/targets/riscv* +F: docs/system/target-riscv.rst F: target/riscv/ F: hw/riscv/ +F: hw/intc/riscv* F: include/hw/riscv/ F: linux-user/host/riscv32/ F: linux-user/host/riscv64/ @@ -331,6 +334,7 @@ L: qemu-riscv@nongnu.org S: Supported F: target/riscv/insn_trans/trans_xthead.c.inc F: target/riscv/xthead*.decode +F: disas/riscv-xthead* RISC-V XVentanaCondOps extension M: Philipp Tomsich @@ -338,6 +342,7 @@ L: qemu-riscv@nongnu.org S: Maintained F: target/riscv/XVentanaCondOps.decode F: target/riscv/insn_trans/trans_xventanacondops.c.inc +F: disas/riscv-xventana* RENESAS RX CPUs R: Yoshinori Sato @@ -1527,6 +1532,7 @@ Microchip PolarFire SoC Icicle Kit M: Bin Meng L: qemu-riscv@nongnu.org S: Supported +F: docs/system/riscv/microchip-icicle-kit.rst F: hw/riscv/microchip_pfsoc.c F: hw/char/mchp_pfsoc_mmuart.c F: hw/misc/mchp_pfsoc_dmc.c @@ -1542,6 +1548,7 @@ Shakti C class SoC M: Vijai Kumar K L: qemu-riscv@nongnu.org S: Supported +F: docs/system/riscv/shakti-c.rst F: hw/riscv/shakti_c.c F: hw/char/shakti_uart.c F: include/hw/riscv/shakti_c.h @@ -1553,6 +1560,7 @@ M: Bin Meng M: Palmer Dabbelt L: qemu-riscv@nongnu.org S: Supported +F: docs/system/riscv/sifive_u.rst F: hw/*/*sifive*.c F: include/hw/*/*sifive*.h @@ -3573,7 +3581,7 @@ M: Alistair Francis L: qemu-riscv@nongnu.org S: Maintained F: tcg/riscv/ -F: disas/riscv.c +F: disas/riscv.[ch] S390 TCG target M: Richard Henderson From 63fc07233e7939d595ee4e8e24710c637b9785c0 Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Fri, 29 Sep 2023 14:44:39 +0200 Subject: [PATCH 0527/1077] MAINTAINERS: Add include folder to the hw/char/ section MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The "Character devices" section only covers hw/char/ but misses the corresponding include/hw/char/ folder. Add it now. Signed-off-by: Thomas Huth Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Michael Tokarev --- MAINTAINERS | 1 + 1 file changed, 1 insertion(+) diff --git a/MAINTAINERS b/MAINTAINERS index e80fca855a..0f9c4b263e 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1988,6 +1988,7 @@ M: Marc-André Lureau R: Paolo Bonzini S: Odd Fixes F: hw/char/ +F: include/hw/char/ Network devices M: Jason Wang From 145af2779c30d5a74c252b6146fa83e8d8120786 Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Fri, 29 Sep 2023 15:16:36 +0200 Subject: [PATCH 0528/1077] MAINTAINERS: Add the CI-related doc files to the CI section MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The docs/devel/ci* were not covered yet, add them to MAINTAINERS so that the right people are put on CC: for related patches. Signed-off-by: Thomas Huth Reviewed-by: Alex Bennée Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Michael Tokarev --- MAINTAINERS | 1 + 1 file changed, 1 insertion(+) diff --git a/MAINTAINERS b/MAINTAINERS index 0f9c4b263e..de2ef5add3 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -3918,6 +3918,7 @@ F: .github/workflows/lockdown.yml F: .gitlab-ci.yml F: .gitlab-ci.d/ F: .travis.yml +F: docs/devel/ci* F: scripts/ci/ F: tests/docker/ F: tests/vm/ From e05ea75f75c023c0520cd9ea2f6e93b008822347 Mon Sep 17 00:00:00 2001 From: Cornelia Huck Date: Fri, 29 Sep 2023 16:30:12 +0200 Subject: [PATCH 0529/1077] MAINTAINERS: add standard-headers to Hosts/LINUX MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The files in there are updated via update-linux-headers.sh. Signed-off-by: Cornelia Huck Reviewed-by: Thomas Huth Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Michael Tokarev --- MAINTAINERS | 1 + 1 file changed, 1 insertion(+) diff --git a/MAINTAINERS b/MAINTAINERS index de2ef5add3..6f947ffccb 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -562,6 +562,7 @@ M: Cornelia Huck M: Paolo Bonzini S: Maintained F: linux-headers/ +F: include/standard-headers/ F: scripts/update-linux-headers.sh POSIX From 39131a4e530afb6d926cab871d8bcc99a2df1288 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Mon, 20 Feb 2023 12:02:35 +0100 Subject: [PATCH 0530/1077] MAINTAINERS: Add section for overall sensors MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Sensor devices depend on some bus, not a particular board. While merged for a particular board, sensor devices don't depend on it. They depend on a bus technology, and can be used by any board exposing such bus. In order to help merging sensor patches, when they fall out of a particular board tree, add a section covering overall sensors, to help out with patch review and merge queue handling. Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Thomas Huth Signed-off-by: Michael Tokarev --- MAINTAINERS | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/MAINTAINERS b/MAINTAINERS index 6f947ffccb..b217080fee 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -3418,6 +3418,12 @@ M: Viktor Prutyanov S: Maintained F: contrib/elf2dmp/ +Overall sensors +M: Philippe Mathieu-Daudé +S: Odd Fixes +F: hw/sensor +F: include/hw/sensor + I2C and SMBus M: Corey Minyard S: Maintained From d02ce621ea98517a40510f1540813b5dedbe3a79 Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Fri, 29 Sep 2023 16:19:18 +0200 Subject: [PATCH 0531/1077] MAINTAINERS: Add some unowned files to the SBSA-REF section These files belong to the sbsa-ref machine and thus should be listed here. Signed-off-by: Thomas Huth Reviewed-by: Leif Lindholm Signed-off-by: Michael Tokarev --- MAINTAINERS | 3 +++ 1 file changed, 3 insertions(+) diff --git a/MAINTAINERS b/MAINTAINERS index b217080fee..0bab360c12 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -945,6 +945,9 @@ R: Marcin Juszkiewicz L: qemu-arm@nongnu.org S: Maintained F: hw/arm/sbsa-ref.c +F: hw/misc/sbsa_ec.c +F: hw/watchdog/sbsa_gwdt.c +F: include/hw/watchdog/sbsa_gwdt.h F: docs/system/arm/sbsa.rst F: tests/avocado/machine_aarch64_sbsaref.py From 17b8d8ac3309e2cfed0d8cb3861afdcc23f66ce0 Mon Sep 17 00:00:00 2001 From: Olaf Hering Date: Mon, 2 Oct 2023 12:18:44 +0200 Subject: [PATCH 0532/1077] roms: use PYTHON to invoke python python3 may not be the expected python version. Use PYTHON to invoke python. Fixes: 22e11539e1 ("edk2: replace build scripts") Signed-off-by: Olaf Hering Signed-off-by: Michael Tokarev --- roms/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/roms/Makefile b/roms/Makefile index 6859685290..67f709ba2d 100644 --- a/roms/Makefile +++ b/roms/Makefile @@ -147,7 +147,7 @@ skiboot: cp skiboot/skiboot.lid ../pc-bios/skiboot.lid efi: - python3 edk2-build.py --config edk2-build.config \ + $(PYTHON) edk2-build.py --config edk2-build.config \ --version-override "edk2-stable202302-for-qemu" \ --release-date "03/01/2023" rm -f ../pc-bios/edk2-*.fd.bz2 From 0848ca87b76b21639f314bd348ae8470db5b22e2 Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Fri, 6 Oct 2023 06:52:56 +0200 Subject: [PATCH 0533/1077] scripts/xml-preprocess: Make sure this script is invoked via the right Python MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit If a script is executable and has a shebang line, Meson treats it as a normal executable, so that this script here is run via the "python3" binary in the $PATH. However, "python3" might not be in the $PATH at all, or it might be a wrong version, so we should make sure to run this script via the Python version that has been chosen for the QEMU build process. The best way to do this is to remove the executable bit from the access mode bits. (See also commit 4b424c757188f7a4) Resolves: https://gitlab.com/qemu-project/qemu/-/issues/1918 Signed-off-by: Thomas Huth Reviewed-by: Marc-André Lureau Signed-off-by: Michael Tokarev --- scripts/xml-preprocess.py | 0 1 file changed, 0 insertions(+), 0 deletions(-) mode change 100755 => 100644 scripts/xml-preprocess.py diff --git a/scripts/xml-preprocess.py b/scripts/xml-preprocess.py old mode 100755 new mode 100644 From b216b5daa57ce068183ce865c163f4df01b74614 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Mon, 9 Oct 2023 11:09:52 +0200 Subject: [PATCH 0534/1077] cpus: Remove unused smp_cores/smp_threads declarations MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Commit a5e0b33119 ("vl.c: Replace smp global variables with smp machine properties") removed the last uses of the smp_cores / smp_threads variables but forgot to remove their declarations. Do it now. Signed-off-by: Philippe Mathieu-Daudé Signed-off-by: Michael Tokarev --- include/sysemu/cpus.h | 7 ------- 1 file changed, 7 deletions(-) diff --git a/include/sysemu/cpus.h b/include/sysemu/cpus.h index 0535a4c68a..b4a566cfe7 100644 --- a/include/sysemu/cpus.h +++ b/include/sysemu/cpus.h @@ -50,11 +50,4 @@ void cpu_synchronize_all_post_reset(void); void cpu_synchronize_all_post_init(void); void cpu_synchronize_all_pre_loadvm(void); -#ifndef CONFIG_USER_ONLY -/* vl.c */ -/* *-user doesn't have configurable SMP topology */ -extern int smp_cores; -extern int smp_threads; -#endif - #endif From 8ea3fceff4e0622f16441e261d125709c8819577 Mon Sep 17 00:00:00 2001 From: Daniel Henrique Barboza Date: Tue, 12 Sep 2023 10:24:04 -0300 Subject: [PATCH 0535/1077] target/riscv/cpu.c: split CPU options from riscv_cpu_extensions[] We'll add a new CPU type that will enable a considerable amount of extensions. To make it easier for us we'll do a few cleanups in our existing riscv_cpu_extensions[] array. Start by splitting all CPU non-boolean options from it. Create a new riscv_cpu_options[] array for them. Add all these properties in riscv_cpu_add_user_properties() as it is already being done today. 'mmu' and 'pmp' aren't really extensions in the usual way we think about RISC-V extensions. These are closer to CPU features/options, so move both to riscv_cpu_options[] too. In the near future we'll need to match all extensions with all entries in isa_edata_arr[], and so it happens that both 'mmu' and 'pmp' do not have a riscv,isa string (thus, no priv spec version restriction). This further emphasizes the point that these are more a CPU option than an extension. No functional changes made. Signed-off-by: Daniel Henrique Barboza Reviewed-by: Weiwei Li Reviewed-by: Alistair Francis Reviewed-by: Andrew Jones Message-ID: <20230912132423.268494-2-dbarboza@ventanamicro.com> Signed-off-by: Alistair Francis --- target/riscv/cpu.c | 33 +++++++++++++++++++++++---------- 1 file changed, 23 insertions(+), 10 deletions(-) diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c index f5572704de..03143c3686 100644 --- a/target/riscv/cpu.c +++ b/target/riscv/cpu.c @@ -1806,7 +1806,6 @@ static void riscv_cpu_add_misa_properties(Object *cpu_obj) static Property riscv_cpu_extensions[] = { /* Defaults for standard extensions */ - DEFINE_PROP_UINT8("pmu-num", RISCVCPU, cfg.pmu_num, 16), DEFINE_PROP_BOOL("sscofpmf", RISCVCPU, cfg.ext_sscofpmf, false), DEFINE_PROP_BOOL("Zifencei", RISCVCPU, cfg.ext_ifencei, true), DEFINE_PROP_BOOL("Zicsr", RISCVCPU, cfg.ext_icsr, true), @@ -1819,15 +1818,8 @@ static Property riscv_cpu_extensions[] = { DEFINE_PROP_BOOL("Zve32f", RISCVCPU, cfg.ext_zve32f, false), DEFINE_PROP_BOOL("Zve64f", RISCVCPU, cfg.ext_zve64f, false), DEFINE_PROP_BOOL("Zve64d", RISCVCPU, cfg.ext_zve64d, false), - DEFINE_PROP_BOOL("mmu", RISCVCPU, cfg.mmu, true), - DEFINE_PROP_BOOL("pmp", RISCVCPU, cfg.pmp, true), DEFINE_PROP_BOOL("sstc", RISCVCPU, cfg.ext_sstc, true), - DEFINE_PROP_STRING("priv_spec", RISCVCPU, cfg.priv_spec), - DEFINE_PROP_STRING("vext_spec", RISCVCPU, cfg.vext_spec), - DEFINE_PROP_UINT16("vlen", RISCVCPU, cfg.vlen, 128), - DEFINE_PROP_UINT16("elen", RISCVCPU, cfg.elen, 64), - DEFINE_PROP_BOOL("smstateen", RISCVCPU, cfg.ext_smstateen, false), DEFINE_PROP_BOOL("svadu", RISCVCPU, cfg.ext_svadu, true), DEFINE_PROP_BOOL("svinval", RISCVCPU, cfg.ext_svinval, false), @@ -1858,9 +1850,7 @@ static Property riscv_cpu_extensions[] = { DEFINE_PROP_BOOL("zhinxmin", RISCVCPU, cfg.ext_zhinxmin, false), DEFINE_PROP_BOOL("zicbom", RISCVCPU, cfg.ext_icbom, true), - DEFINE_PROP_UINT16("cbom_blocksize", RISCVCPU, cfg.cbom_blocksize, 64), DEFINE_PROP_BOOL("zicboz", RISCVCPU, cfg.ext_icboz, true), - DEFINE_PROP_UINT16("cboz_blocksize", RISCVCPU, cfg.cboz_blocksize, 64), DEFINE_PROP_BOOL("zmmul", RISCVCPU, cfg.ext_zmmul, false), @@ -1914,6 +1904,21 @@ static Property riscv_cpu_extensions[] = { DEFINE_PROP_END_OF_LIST(), }; +static Property riscv_cpu_options[] = { + DEFINE_PROP_UINT8("pmu-num", RISCVCPU, cfg.pmu_num, 16), + + DEFINE_PROP_BOOL("mmu", RISCVCPU, cfg.mmu, true), + DEFINE_PROP_BOOL("pmp", RISCVCPU, cfg.pmp, true), + + DEFINE_PROP_STRING("priv_spec", RISCVCPU, cfg.priv_spec), + DEFINE_PROP_STRING("vext_spec", RISCVCPU, cfg.vext_spec), + + DEFINE_PROP_UINT16("vlen", RISCVCPU, cfg.vlen, 128), + DEFINE_PROP_UINT16("elen", RISCVCPU, cfg.elen, 64), + + DEFINE_PROP_UINT16("cbom_blocksize", RISCVCPU, cfg.cbom_blocksize, 64), + DEFINE_PROP_UINT16("cboz_blocksize", RISCVCPU, cfg.cboz_blocksize, 64), +}; #ifndef CONFIG_USER_ONLY static void cpu_set_cfg_unavailable(Object *obj, Visitor *v, @@ -1982,6 +1987,14 @@ static void riscv_cpu_add_user_properties(Object *obj) #endif qdev_property_add_static(dev, prop); } + + for (int i = 0; i < ARRAY_SIZE(riscv_cpu_options); i++) { + /* Check if KVM created the property already */ + if (object_property_find(obj, riscv_cpu_options[i].name)) { + continue; + } + qdev_property_add_static(dev, &riscv_cpu_options[i]); + } } static Property riscv_cpu_properties[] = { From bfb37c693a8dd19f41f9017821a48c188eed41e7 Mon Sep 17 00:00:00 2001 From: Daniel Henrique Barboza Date: Tue, 12 Sep 2023 10:24:05 -0300 Subject: [PATCH 0536/1077] target/riscv/cpu.c: skip 'bool' check when filtering KVM props After the introduction of riscv_cpu_options[] all properties in riscv_cpu_extensions[] are booleans. This check is now obsolete. Signed-off-by: Daniel Henrique Barboza Reviewed-by: Alistair Francis Reviewed-by: Andrew Jones Message-ID: <20230912132423.268494-3-dbarboza@ventanamicro.com> Signed-off-by: Alistair Francis --- target/riscv/cpu.c | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c index 03143c3686..e02f399c81 100644 --- a/target/riscv/cpu.c +++ b/target/riscv/cpu.c @@ -1972,17 +1972,11 @@ static void riscv_cpu_add_user_properties(Object *obj) * Set the default to disabled for every extension * unknown to KVM and error out if the user attempts * to enable any of them. - * - * We're giving a pass for non-bool properties since they're - * not related to the availability of extensions and can be - * safely ignored as is. */ - if (prop->info == &qdev_prop_bool) { - object_property_add(obj, prop->name, "bool", - NULL, cpu_set_cfg_unavailable, - NULL, (void *)prop->name); - continue; - } + object_property_add(obj, prop->name, "bool", + NULL, cpu_set_cfg_unavailable, + NULL, (void *)prop->name); + continue; } #endif qdev_property_add_static(dev, prop); From 68aba1f2af89b0bc6231264dfcfc9e78e1fe2a10 Mon Sep 17 00:00:00 2001 From: Daniel Henrique Barboza Date: Tue, 12 Sep 2023 10:24:06 -0300 Subject: [PATCH 0537/1077] target/riscv/cpu.c: split kvm prop handling to its own helper Future patches will split the existing Property arrays even further, and the existing code in riscv_cpu_add_user_properties() will start to scale bad with it because it's dealing with KVM constraints mixed in with TCG constraints. We're going to pay a high price to share a couple of common lines of code between the two. Create a new kvm_riscv_cpu_add_kvm_properties() helper that will be forked from riscv_cpu_add_user_properties() if we're running KVM. The helper includes all properties that a KVM CPU will add. The rest of riscv_cpu_add_user_properties() body will then be relieved from having to deal with KVM constraints. The helper was declared in kvm_stubs.h, while being implemented in cpu.c, to allow '--enable-debug' builds to work. The compiler won't remove the kvm_riscv_cpu_add_kvm_properties() reference when 'kvm_enabled()' is false if we end up with an unused function. Even though being a KVM only helper we can't implement it in kvm.c due to its many dependencies inside cpu.c, so make it public in kvm_riscv.h and keep its implementation in cpu.c for now. We'll move it to kvm.c in the near future. Signed-off-by: Daniel Henrique Barboza Reviewed-by: Andrew Jones Message-ID: <20230912132423.268494-4-dbarboza@ventanamicro.com> Signed-off-by: Alistair Francis --- target/riscv/cpu.c | 65 +++++++++++++++++++++++++--------------- target/riscv/kvm_riscv.h | 3 ++ 2 files changed, 44 insertions(+), 24 deletions(-) diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c index e02f399c81..2a8fbd214a 100644 --- a/target/riscv/cpu.c +++ b/target/riscv/cpu.c @@ -1920,7 +1920,7 @@ static Property riscv_cpu_options[] = { DEFINE_PROP_UINT16("cboz_blocksize", RISCVCPU, cfg.cboz_blocksize, 64), }; -#ifndef CONFIG_USER_ONLY +#ifdef CONFIG_KVM static void cpu_set_cfg_unavailable(Object *obj, Visitor *v, const char *name, void *opaque, Error **errp) @@ -1937,6 +1937,44 @@ static void cpu_set_cfg_unavailable(Object *obj, Visitor *v, propname); } } + +static void riscv_cpu_add_kvm_unavail_prop(Object *obj, const char *prop_name) +{ + /* Check if KVM created the property already */ + if (object_property_find(obj, prop_name)) { + return; + } + + /* + * Set the default to disabled for every extension + * unknown to KVM and error out if the user attempts + * to enable any of them. + */ + object_property_add(obj, prop_name, "bool", + NULL, cpu_set_cfg_unavailable, + NULL, (void *)prop_name); +} + +void kvm_riscv_cpu_add_kvm_properties(Object *obj) +{ + Property *prop; + DeviceState *dev = DEVICE(obj); + + kvm_riscv_init_user_properties(obj); + riscv_cpu_add_misa_properties(obj); + + for (prop = riscv_cpu_extensions; prop && prop->name; prop++) { + riscv_cpu_add_kvm_unavail_prop(obj, prop->name); + } + + for (int i = 0; i < ARRAY_SIZE(riscv_cpu_options); i++) { + /* Check if KVM created the property already */ + if (object_property_find(obj, riscv_cpu_options[i].name)) { + continue; + } + qdev_property_add_static(dev, &riscv_cpu_options[i]); + } +} #endif /* @@ -1954,39 +1992,18 @@ static void riscv_cpu_add_user_properties(Object *obj) riscv_add_satp_mode_properties(obj); if (kvm_enabled()) { - kvm_riscv_init_user_properties(obj); + kvm_riscv_cpu_add_kvm_properties(obj); + return; } #endif riscv_cpu_add_misa_properties(obj); for (prop = riscv_cpu_extensions; prop && prop->name; prop++) { -#ifndef CONFIG_USER_ONLY - if (kvm_enabled()) { - /* Check if KVM created the property already */ - if (object_property_find(obj, prop->name)) { - continue; - } - - /* - * Set the default to disabled for every extension - * unknown to KVM and error out if the user attempts - * to enable any of them. - */ - object_property_add(obj, prop->name, "bool", - NULL, cpu_set_cfg_unavailable, - NULL, (void *)prop->name); - continue; - } -#endif qdev_property_add_static(dev, prop); } for (int i = 0; i < ARRAY_SIZE(riscv_cpu_options); i++) { - /* Check if KVM created the property already */ - if (object_property_find(obj, riscv_cpu_options[i].name)) { - continue; - } qdev_property_add_static(dev, &riscv_cpu_options[i]); } } diff --git a/target/riscv/kvm_riscv.h b/target/riscv/kvm_riscv.h index de8c209ebc..69e807fbfb 100644 --- a/target/riscv/kvm_riscv.h +++ b/target/riscv/kvm_riscv.h @@ -19,6 +19,9 @@ #ifndef QEMU_KVM_RISCV_H #define QEMU_KVM_RISCV_H +/* Temporarily implemented in cpu.c */ +void kvm_riscv_cpu_add_kvm_properties(Object *obj); + void kvm_riscv_init_user_properties(Object *cpu_obj); void kvm_riscv_reset_vcpu(RISCVCPU *cpu); void kvm_riscv_set_irq(RISCVCPU *cpu, int irq, int level); From d09d085a088bc7da92bbb68d9c2fed0e6dc8aed8 Mon Sep 17 00:00:00 2001 From: Daniel Henrique Barboza Date: Tue, 12 Sep 2023 10:24:07 -0300 Subject: [PATCH 0538/1077] target/riscv: add DEFINE_PROP_END_OF_LIST() to riscv_cpu_options[] MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add DEFINE_PROP_END_OF_LIST() and eliminate the ARRAY_SIZE() usage when iterating in the riscv_cpu_options[] array, making it similar to what we already do when working with riscv_cpu_extensions[]. We also have a more sophisticated motivation behind this change. In the future we might need to export riscv_cpu_options[] to other files, and ARRAY_LIST() doesn't work properly in that case because the array size isn't exposed to the header file. Here's a future sight of what we would deal with: ./target/riscv/kvm.c:1057:5: error: nested extern declaration of 'riscv_cpu_add_misa_properties' [-Werror=nested-externs] n file included from ../target/riscv/kvm.c:19: home/danielhb/work/qemu/include/qemu/osdep.h:473:31: error: invalid application of 'sizeof' to incomplete type 'const RISCVCPUMultiExtConfig[]' 473 | #define ARRAY_SIZE(x) ((sizeof(x) / sizeof((x)[0])) + \ | ^ ./target/riscv/kvm.c:1047:29: note: in expansion of macro 'ARRAY_SIZE' 1047 | for (int i = 0; i < ARRAY_SIZE(_array); i++) { \ | ^~~~~~~~~~ ./target/riscv/kvm.c:1059:5: note: in expansion of macro 'ADD_UNAVAIL_KVM_PROP_ARRAY' 1059 | ADD_UNAVAIL_KVM_PROP_ARRAY(obj, riscv_cpu_extensions); | ^~~~~~~~~~~~~~~~~~~~~~~~~~ home/danielhb/work/qemu/include/qemu/osdep.h:473:31: error: invalid application of 'sizeof' to incomplete type 'const RISCVCPUMultiExtConfig[]' 473 | #define ARRAY_SIZE(x) ((sizeof(x) / sizeof((x)[0])) + \ | ^ ./target/riscv/kvm.c:1047:29: note: in expansion of macro 'ARRAY_SIZE' 1047 | for (int i = 0; i < ARRAY_SIZE(_array); i++) { \ Homogenize the present and change the future by using DEFINE_PROP_END_OF_LIST() in riscv_cpu_options[]. Signed-off-by: Daniel Henrique Barboza Reviewed-by: Andrew Jones Reviewed-by: Alistair Francis Reviewed-by: Philippe Mathieu-Daudé Message-ID: <20230912132423.268494-5-dbarboza@ventanamicro.com> Signed-off-by: Alistair Francis --- target/riscv/cpu.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c index 2a8fbd214a..f7d3dd900c 100644 --- a/target/riscv/cpu.c +++ b/target/riscv/cpu.c @@ -1918,6 +1918,8 @@ static Property riscv_cpu_options[] = { DEFINE_PROP_UINT16("cbom_blocksize", RISCVCPU, cfg.cbom_blocksize, 64), DEFINE_PROP_UINT16("cboz_blocksize", RISCVCPU, cfg.cboz_blocksize, 64), + + DEFINE_PROP_END_OF_LIST(), }; #ifdef CONFIG_KVM @@ -1967,12 +1969,12 @@ void kvm_riscv_cpu_add_kvm_properties(Object *obj) riscv_cpu_add_kvm_unavail_prop(obj, prop->name); } - for (int i = 0; i < ARRAY_SIZE(riscv_cpu_options); i++) { + for (prop = riscv_cpu_options; prop && prop->name; prop++) { /* Check if KVM created the property already */ - if (object_property_find(obj, riscv_cpu_options[i].name)) { + if (object_property_find(obj, prop->name)) { continue; } - qdev_property_add_static(dev, &riscv_cpu_options[i]); + qdev_property_add_static(dev, prop); } } #endif @@ -2003,8 +2005,8 @@ static void riscv_cpu_add_user_properties(Object *obj) qdev_property_add_static(dev, prop); } - for (int i = 0; i < ARRAY_SIZE(riscv_cpu_options); i++) { - qdev_property_add_static(dev, &riscv_cpu_options[i]); + for (prop = riscv_cpu_options; prop && prop->name; prop++) { + qdev_property_add_static(dev, prop); } } From b955fd1a009153bf398ad91c84a9d9a85574193a Mon Sep 17 00:00:00 2001 From: Daniel Henrique Barboza Date: Tue, 12 Sep 2023 10:24:08 -0300 Subject: [PATCH 0539/1077] target/riscv/cpu.c: split non-ratified exts from riscv_cpu_extensions[] Create a new riscv_cpu_experimental_exts[] to store the non-ratified extensions properties. Once they are ratified we'll move them back to riscv_cpu_extensions[]. riscv_cpu_add_user_properties() and riscv_cpu_add_kvm_properties() are changed to keep adding non-ratified properties to users. Signed-off-by: Daniel Henrique Barboza Reviewed-by: Alistair Francis Reviewed-by: Andrew Jones Message-ID: <20230912132423.268494-6-dbarboza@ventanamicro.com> Signed-off-by: Alistair Francis --- target/riscv/cpu.c | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c index f7d3dd900c..cba2c4998a 100644 --- a/target/riscv/cpu.c +++ b/target/riscv/cpu.c @@ -1877,8 +1877,11 @@ static Property riscv_cpu_extensions[] = { DEFINE_PROP_BOOL("xtheadsync", RISCVCPU, cfg.ext_xtheadsync, false), DEFINE_PROP_BOOL("xventanacondops", RISCVCPU, cfg.ext_XVentanaCondOps, false), - /* These are experimental so mark with 'x-' */ + DEFINE_PROP_END_OF_LIST(), +}; +/* These are experimental so mark with 'x-' */ +static Property riscv_cpu_experimental_exts[] = { /* ePMP 0.9.3 */ DEFINE_PROP_BOOL("x-epmp", RISCVCPU, cfg.epmp, false), DEFINE_PROP_BOOL("x-smaia", RISCVCPU, cfg.ext_smaia, false), @@ -1969,6 +1972,10 @@ void kvm_riscv_cpu_add_kvm_properties(Object *obj) riscv_cpu_add_kvm_unavail_prop(obj, prop->name); } + for (prop = riscv_cpu_experimental_exts; prop && prop->name; prop++) { + riscv_cpu_add_kvm_unavail_prop(obj, prop->name); + } + for (prop = riscv_cpu_options; prop && prop->name; prop++) { /* Check if KVM created the property already */ if (object_property_find(obj, prop->name)) { @@ -2008,6 +2015,10 @@ static void riscv_cpu_add_user_properties(Object *obj) for (prop = riscv_cpu_options; prop && prop->name; prop++) { qdev_property_add_static(dev, prop); } + + for (prop = riscv_cpu_experimental_exts; prop && prop->name; prop++) { + qdev_property_add_static(dev, prop); + } } static Property riscv_cpu_properties[] = { From 82822b5d5a5fe2a7f780c9d27534ecaa42cacdec Mon Sep 17 00:00:00 2001 From: Daniel Henrique Barboza Date: Tue, 12 Sep 2023 10:24:09 -0300 Subject: [PATCH 0540/1077] target/riscv/cpu.c: split vendor exts from riscv_cpu_extensions[] Our goal is to make riscv_cpu_extensions[] hold only ratified, non-vendor extensions. Create a new riscv_cpu_vendor_exts[] array for them, changing riscv_cpu_add_user_properties() and riscv_cpu_add_kvm_properties() accordingly. Signed-off-by: Daniel Henrique Barboza Reviewed-by: Alistair Francis Reviewed-by: Andrew Jones Message-ID: <20230912132423.268494-7-dbarboza@ventanamicro.com> Signed-off-by: Alistair Francis --- target/riscv/cpu.c | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c index cba2c4998a..6289457514 100644 --- a/target/riscv/cpu.c +++ b/target/riscv/cpu.c @@ -1863,7 +1863,10 @@ static Property riscv_cpu_extensions[] = { DEFINE_PROP_BOOL("zcmt", RISCVCPU, cfg.ext_zcmt, false), DEFINE_PROP_BOOL("zicond", RISCVCPU, cfg.ext_zicond, false), - /* Vendor-specific custom extensions */ + DEFINE_PROP_END_OF_LIST(), +}; + +static Property riscv_cpu_vendor_exts[] = { DEFINE_PROP_BOOL("xtheadba", RISCVCPU, cfg.ext_xtheadba, false), DEFINE_PROP_BOOL("xtheadbb", RISCVCPU, cfg.ext_xtheadbb, false), DEFINE_PROP_BOOL("xtheadbs", RISCVCPU, cfg.ext_xtheadbs, false), @@ -1972,6 +1975,10 @@ void kvm_riscv_cpu_add_kvm_properties(Object *obj) riscv_cpu_add_kvm_unavail_prop(obj, prop->name); } + for (prop = riscv_cpu_vendor_exts; prop && prop->name; prop++) { + riscv_cpu_add_kvm_unavail_prop(obj, prop->name); + } + for (prop = riscv_cpu_experimental_exts; prop && prop->name; prop++) { riscv_cpu_add_kvm_unavail_prop(obj, prop->name); } @@ -2016,6 +2023,10 @@ static void riscv_cpu_add_user_properties(Object *obj) qdev_property_add_static(dev, prop); } + for (prop = riscv_cpu_vendor_exts; prop && prop->name; prop++) { + qdev_property_add_static(dev, prop); + } + for (prop = riscv_cpu_experimental_exts; prop && prop->name; prop++) { qdev_property_add_static(dev, prop); } From 370d7c8ef8fb4630fb422c4176477d134ac8793d Mon Sep 17 00:00:00 2001 From: Daniel Henrique Barboza Date: Tue, 12 Sep 2023 10:24:10 -0300 Subject: [PATCH 0541/1077] target/riscv/cpu.c: add riscv_cpu_add_qdev_prop_array() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The code inside riscv_cpu_add_user_properties() became quite repetitive after recent changes. Add a helper to hide the repetition away. Signed-off-by: Daniel Henrique Barboza Reviewed-by: Andrew Jones Reviewed-by: Alistair Francis Reviewed-by: Philippe Mathieu-Daudé Message-ID: <20230912132423.268494-8-dbarboza@ventanamicro.com> Signed-off-by: Alistair Francis --- target/riscv/cpu.c | 29 +++++++++++++---------------- 1 file changed, 13 insertions(+), 16 deletions(-) diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c index 6289457514..848b0d1c82 100644 --- a/target/riscv/cpu.c +++ b/target/riscv/cpu.c @@ -1928,6 +1928,15 @@ static Property riscv_cpu_options[] = { DEFINE_PROP_END_OF_LIST(), }; +static void riscv_cpu_add_qdev_prop_array(DeviceState *dev, Property *array) +{ + g_assert(array); + + for (Property *prop = array; prop && prop->name; prop++) { + qdev_property_add_static(dev, prop); + } +} + #ifdef CONFIG_KVM static void cpu_set_cfg_unavailable(Object *obj, Visitor *v, const char *name, @@ -2001,7 +2010,6 @@ void kvm_riscv_cpu_add_kvm_properties(Object *obj) */ static void riscv_cpu_add_user_properties(Object *obj) { - Property *prop; DeviceState *dev = DEVICE(obj); #ifndef CONFIG_USER_ONLY @@ -2015,21 +2023,10 @@ static void riscv_cpu_add_user_properties(Object *obj) riscv_cpu_add_misa_properties(obj); - for (prop = riscv_cpu_extensions; prop && prop->name; prop++) { - qdev_property_add_static(dev, prop); - } - - for (prop = riscv_cpu_options; prop && prop->name; prop++) { - qdev_property_add_static(dev, prop); - } - - for (prop = riscv_cpu_vendor_exts; prop && prop->name; prop++) { - qdev_property_add_static(dev, prop); - } - - for (prop = riscv_cpu_experimental_exts; prop && prop->name; prop++) { - qdev_property_add_static(dev, prop); - } + riscv_cpu_add_qdev_prop_array(dev, riscv_cpu_extensions); + riscv_cpu_add_qdev_prop_array(dev, riscv_cpu_options); + riscv_cpu_add_qdev_prop_array(dev, riscv_cpu_vendor_exts); + riscv_cpu_add_qdev_prop_array(dev, riscv_cpu_experimental_exts); } static Property riscv_cpu_properties[] = { From b55c39b3f57dfad1fca00aaa042ec569ab6e8ecd Mon Sep 17 00:00:00 2001 From: Daniel Henrique Barboza Date: Tue, 12 Sep 2023 10:24:11 -0300 Subject: [PATCH 0542/1077] target/riscv/cpu.c: add riscv_cpu_add_kvm_unavail_prop_array() Use a helper in riscv_cpu_add_kvm_properties() to eliminate some of its code repetition. Signed-off-by: Daniel Henrique Barboza Reviewed-by: Andrew Jones Reviewed-by: Alistair Francis Message-ID: <20230912132423.268494-9-dbarboza@ventanamicro.com> Signed-off-by: Alistair Francis --- target/riscv/cpu.c | 24 +++++++++++++----------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c index 848b0d1c82..3cc7cfd7ef 100644 --- a/target/riscv/cpu.c +++ b/target/riscv/cpu.c @@ -1972,6 +1972,16 @@ static void riscv_cpu_add_kvm_unavail_prop(Object *obj, const char *prop_name) NULL, (void *)prop_name); } +static void riscv_cpu_add_kvm_unavail_prop_array(Object *obj, + Property *array) +{ + g_assert(array); + + for (Property *prop = array; prop && prop->name; prop++) { + riscv_cpu_add_kvm_unavail_prop(obj, prop->name); + } +} + void kvm_riscv_cpu_add_kvm_properties(Object *obj) { Property *prop; @@ -1980,17 +1990,9 @@ void kvm_riscv_cpu_add_kvm_properties(Object *obj) kvm_riscv_init_user_properties(obj); riscv_cpu_add_misa_properties(obj); - for (prop = riscv_cpu_extensions; prop && prop->name; prop++) { - riscv_cpu_add_kvm_unavail_prop(obj, prop->name); - } - - for (prop = riscv_cpu_vendor_exts; prop && prop->name; prop++) { - riscv_cpu_add_kvm_unavail_prop(obj, prop->name); - } - - for (prop = riscv_cpu_experimental_exts; prop && prop->name; prop++) { - riscv_cpu_add_kvm_unavail_prop(obj, prop->name); - } + riscv_cpu_add_kvm_unavail_prop_array(obj, riscv_cpu_extensions); + riscv_cpu_add_kvm_unavail_prop_array(obj, riscv_cpu_vendor_exts); + riscv_cpu_add_kvm_unavail_prop_array(obj, riscv_cpu_experimental_exts); for (prop = riscv_cpu_options; prop && prop->name; prop++) { /* Check if KVM created the property already */ From cbaac1d22b80364e31f075c651912451018d4459 Mon Sep 17 00:00:00 2001 From: Daniel Henrique Barboza Date: Tue, 12 Sep 2023 10:24:12 -0300 Subject: [PATCH 0543/1077] target/riscv/cpu.c: limit cfg->vext_spec log message Inside riscv_cpu_validate_v() we're always throwing a log message if the user didn't set a vector version via 'vext_spec'. We're going to include one case with the 'max' CPU where env->vext_ver will be set in the cpu_init(). But that alone will not stop the "vector version is not specified" message from appearing. The usefulness of this log message is debatable for the generic CPUs, but for a 'max' CPU type, where we are supposed to deliver a CPU model with all features possible, it's strange to force users to set 'vext_spec' to get rid of this message. Change riscv_cpu_validate_v() to not throw this log message if env->vext_ver is already set. Signed-off-by: Daniel Henrique Barboza Reviewed-by: Alistair Francis Reviewed-by: Weiwei Li Message-ID: <20230912132423.268494-10-dbarboza@ventanamicro.com> Signed-off-by: Alistair Francis --- target/riscv/cpu.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c index 3cc7cfd7ef..7b9d0c7e52 100644 --- a/target/riscv/cpu.c +++ b/target/riscv/cpu.c @@ -959,8 +959,6 @@ static void riscv_cpu_disas_set_info(CPUState *s, disassemble_info *info) static void riscv_cpu_validate_v(CPURISCVState *env, RISCVCPUConfig *cfg, Error **errp) { - int vext_version = VEXT_VERSION_1_00_0; - if (!is_power_of_2(cfg->vlen)) { error_setg(errp, "Vector extension VLEN must be power of 2"); return; @@ -983,17 +981,18 @@ static void riscv_cpu_validate_v(CPURISCVState *env, RISCVCPUConfig *cfg, } if (cfg->vext_spec) { if (!g_strcmp0(cfg->vext_spec, "v1.0")) { - vext_version = VEXT_VERSION_1_00_0; + env->vext_ver = VEXT_VERSION_1_00_0; } else { error_setg(errp, "Unsupported vector spec version '%s'", cfg->vext_spec); return; } - } else { + } else if (env->vext_ver == 0) { qemu_log("vector version is not specified, " "use the default value v1.0\n"); + + env->vext_ver = VEXT_VERSION_1_00_0; } - env->vext_ver = vext_version; } static void riscv_cpu_validate_priv_spec(RISCVCPU *cpu, Error **errp) From b97e5a6b0a93f8e8b83c18c89c4c408fb7ae7cb0 Mon Sep 17 00:00:00 2001 From: Daniel Henrique Barboza Date: Tue, 12 Sep 2023 10:24:13 -0300 Subject: [PATCH 0544/1077] target/riscv: add 'max' CPU type The 'max' CPU type is used by tooling to determine what's the most capable CPU a current QEMU version implements. Other archs such as ARM implements this type. Let's add it to RISC-V. What we consider "most capable CPU" in this context are related to ratified, non-vendor extensions. This means that we want the 'max' CPU to enable all (possible) ratified extensions by default. The reasoning behind this design is (1) vendor extensions can conflict with each other and we won't play favorities deciding which one is default or not and (2) non-ratified extensions are always prone to changes, not being stable enough to be enabled by default. All this said, we're still not able to enable all ratified extensions due to conflicts between them. Zfinx and all its dependencies aren't enabled because of a conflict with RVF. zce, zcmp and zcmt are also disabled due to RVD conflicts. When running with 64 bits we're also disabling zcf. MISA bits RVG, RVJ and RVV are also being set manually since they're default disabled. This is the resulting 'riscv,isa' DT for this new CPU: rv64imafdcvh_zicbom_zicboz_zicsr_zifencei_zihintpause_zawrs_zfa_ zfh_zfhmin_zca_zcb_zcd_zba_zbb_zbc_zbkb_zbkc_zbkx_zbs_zk_zkn_zknd_ zkne_zknh_zkr_zks_zksed_zksh_zkt_zve32f_zve64f_zve64d_ smstateen_sscofpmf_sstc_svadu_svinval_svnapot_svpbmt Signed-off-by: Daniel Henrique Barboza Reviewed-by: Weiwei Li Reviewed-by: Alistair Francis Reviewed-by: Andrew Jones Message-ID: <20230912132423.268494-11-dbarboza@ventanamicro.com> Signed-off-by: Alistair Francis --- target/riscv/cpu-qom.h | 1 + target/riscv/cpu.c | 56 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 57 insertions(+) diff --git a/target/riscv/cpu-qom.h b/target/riscv/cpu-qom.h index 04af50983e..f3fbe37a2c 100644 --- a/target/riscv/cpu-qom.h +++ b/target/riscv/cpu-qom.h @@ -30,6 +30,7 @@ #define CPU_RESOLVING_TYPE TYPE_RISCV_CPU #define TYPE_RISCV_CPU_ANY RISCV_CPU_TYPE_NAME("any") +#define TYPE_RISCV_CPU_MAX RISCV_CPU_TYPE_NAME("max") #define TYPE_RISCV_CPU_BASE32 RISCV_CPU_TYPE_NAME("rv32") #define TYPE_RISCV_CPU_BASE64 RISCV_CPU_TYPE_NAME("rv64") #define TYPE_RISCV_CPU_BASE128 RISCV_CPU_TYPE_NAME("x-rv128") diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c index 7b9d0c7e52..c9de7ddb4e 100644 --- a/target/riscv/cpu.c +++ b/target/riscv/cpu.c @@ -259,6 +259,7 @@ static const char * const riscv_intr_names[] = { }; static void riscv_cpu_add_user_properties(Object *obj); +static void riscv_init_max_cpu_extensions(Object *obj); const char *riscv_cpu_get_trap_name(target_ulong cause, bool async) { @@ -396,6 +397,25 @@ static void riscv_any_cpu_init(Object *obj) cpu->cfg.pmp = true; } +static void riscv_max_cpu_init(Object *obj) +{ + RISCVCPU *cpu = RISCV_CPU(obj); + CPURISCVState *env = &cpu->env; + RISCVMXL mlx = MXL_RV64; + +#ifdef TARGET_RISCV32 + mlx = MXL_RV32; +#endif + set_misa(env, mlx, 0); + riscv_cpu_add_user_properties(obj); + riscv_init_max_cpu_extensions(obj); + env->priv_ver = PRIV_VERSION_LATEST; +#ifndef CONFIG_USER_ONLY + set_satp_mode_max_supported(RISCV_CPU(obj), mlx == MXL_RV32 ? + VM_1_10_SV32 : VM_1_10_SV57); +#endif +} + #if defined(TARGET_RISCV64) static void rv64_base_cpu_init(Object *obj) { @@ -2030,6 +2050,41 @@ static void riscv_cpu_add_user_properties(Object *obj) riscv_cpu_add_qdev_prop_array(dev, riscv_cpu_experimental_exts); } +/* + * The 'max' type CPU will have all possible ratified + * non-vendor extensions enabled. + */ +static void riscv_init_max_cpu_extensions(Object *obj) +{ + RISCVCPU *cpu = RISCV_CPU(obj); + CPURISCVState *env = &cpu->env; + Property *prop; + + /* Enable RVG, RVJ and RVV that are disabled by default */ + set_misa(env, env->misa_mxl, env->misa_ext | RVG | RVJ | RVV); + + for (prop = riscv_cpu_extensions; prop && prop->name; prop++) { + object_property_set_bool(obj, prop->name, true, NULL); + } + + /* set vector version */ + env->vext_ver = VEXT_VERSION_1_00_0; + + /* Zfinx is not compatible with F. Disable it */ + object_property_set_bool(obj, "zfinx", false, NULL); + object_property_set_bool(obj, "zdinx", false, NULL); + object_property_set_bool(obj, "zhinx", false, NULL); + object_property_set_bool(obj, "zhinxmin", false, NULL); + + object_property_set_bool(obj, "zce", false, NULL); + object_property_set_bool(obj, "zcmp", false, NULL); + object_property_set_bool(obj, "zcmt", false, NULL); + + if (env->misa_mxl != MXL_RV32) { + object_property_set_bool(obj, "zcf", false, NULL); + } +} + static Property riscv_cpu_properties[] = { DEFINE_PROP_BOOL("debug", RISCVCPU, cfg.debug, true), @@ -2368,6 +2423,7 @@ static const TypeInfo riscv_cpu_type_infos[] = { .abstract = true, }, DEFINE_DYNAMIC_CPU(TYPE_RISCV_CPU_ANY, riscv_any_cpu_init), + DEFINE_DYNAMIC_CPU(TYPE_RISCV_CPU_MAX, riscv_max_cpu_init), #if defined(CONFIG_KVM) DEFINE_CPU(TYPE_RISCV_CPU_HOST, riscv_host_cpu_init), #endif From dfe7d2280a80cb3a212b99d1aa8ef23ddc1022a4 Mon Sep 17 00:00:00 2001 From: Daniel Henrique Barboza Date: Tue, 12 Sep 2023 10:24:14 -0300 Subject: [PATCH 0545/1077] avocado, risc-v: add tuxboot tests for 'max' CPU MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add smoke tests to ensure that we'll not break the 'max' CPU type when adding new frozen/ratified RISC-V extensions. Signed-off-by: Daniel Henrique Barboza Reviewed-by: Alistair Francis Reviewed-by: Philippe Mathieu-Daudé Tested-by: Philippe Mathieu-Daudé Message-ID: <20230912132423.268494-12-dbarboza@ventanamicro.com> Signed-off-by: Alistair Francis --- tests/avocado/tuxrun_baselines.py | 32 +++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/tests/avocado/tuxrun_baselines.py b/tests/avocado/tuxrun_baselines.py index e12250eabb..c99bea6c0b 100644 --- a/tests/avocado/tuxrun_baselines.py +++ b/tests/avocado/tuxrun_baselines.py @@ -501,6 +501,38 @@ class TuxRunBaselineTest(QemuSystemTest): self.common_tuxrun(csums=sums) + def test_riscv32_maxcpu(self): + """ + :avocado: tags=arch:riscv32 + :avocado: tags=machine:virt + :avocado: tags=cpu:max + :avocado: tags=tuxboot:riscv32 + """ + sums = { "Image" : + "89599407d7334de629a40e7ad6503c73670359eb5f5ae9d686353a3d6deccbd5", + "fw_jump.elf" : + "f2ef28a0b77826f79d085d3e4aa686f1159b315eff9099a37046b18936676985", + "rootfs.ext4.zst" : + "7168d296d0283238ea73cd5a775b3dd608e55e04c7b92b76ecce31bb13108cba" } + + self.common_tuxrun(csums=sums) + + def test_riscv64_maxcpu(self): + """ + :avocado: tags=arch:riscv64 + :avocado: tags=machine:virt + :avocado: tags=cpu:max + :avocado: tags=tuxboot:riscv64 + """ + sums = { "Image" : + "cd634badc65e52fb63465ec99e309c0de0369f0841b7d9486f9729e119bac25e", + "fw_jump.elf" : + "6e3373abcab4305fe151b564a4c71110d833c21f2c0a1753b7935459e36aedcf", + "rootfs.ext4.zst" : + "b18e3a3bdf27be03da0b285e84cb71bf09eca071c3a087b42884b6982ed679eb" } + + self.common_tuxrun(csums=sums) + def test_s390(self): """ :avocado: tags=arch:s390x From f57d5f8004b70c3f7356eda574be7639d97ea2be Mon Sep 17 00:00:00 2001 From: Daniel Henrique Barboza Date: Tue, 12 Sep 2023 10:24:15 -0300 Subject: [PATCH 0546/1077] target/riscv: deprecate the 'any' CPU type MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The 'any' CPU type was introduced in commit dc5bd18fa5725 ("RISC-V CPU Core Definition"), being around since the beginning. It's not an easy CPU to use: it's undocumented and its name doesn't tell users much about what the CPU is supposed to bring. 'git log' doesn't help us either in knowing what was the original design of this CPU type. The closest we have is a comment from Alistair [1] where he recalls from memory that the 'any' CPU is supposed to behave like the newly added 'max' CPU. He also suggested that the 'any' CPU should be removed. The default CPUs are rv32 and rv64, so removing the 'any' CPU will have impact only on users that might have a script that uses '-cpu any'. And those users are better off using the default CPUs or the new 'max' CPU. We would love to just remove the code and be done with it, but one does not simply remove a feature in QEMU. We'll put the CPU in quarantine first, letting users know that we have the intent of removing it in the future. [1] https://lists.gnu.org/archive/html/qemu-devel/2023-07/msg02891.html Signed-off-by: Daniel Henrique Barboza Reviewed-by: Alistair Francis Reviewed-by: Andrew Jones Reviewed-by: Philippe Mathieu-Daudé Tested-by: Philippe Mathieu-Daudé Message-ID: <20230912132423.268494-13-dbarboza@ventanamicro.com> Signed-off-by: Alistair Francis --- docs/about/deprecated.rst | 12 ++++++++++++ target/riscv/cpu.c | 5 +++++ 2 files changed, 17 insertions(+) diff --git a/docs/about/deprecated.rst b/docs/about/deprecated.rst index 8b136320e2..5e3965a674 100644 --- a/docs/about/deprecated.rst +++ b/docs/about/deprecated.rst @@ -327,6 +327,18 @@ QEMU's ``vhost`` feature, which would eliminate the high latency costs under which the 9p ``proxy`` backend currently suffers. However as of to date nobody has indicated plans for such kind of reimplementation unfortunately. +RISC-V 'any' CPU type ``-cpu any`` (since 8.2) +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +The 'any' CPU type was introduced back in 2018 and has been around since the +initial RISC-V QEMU port. Its usage has always been unclear: users don't know +what to expect from a CPU called 'any', and in fact the CPU does not do anything +special that isn't already done by the default CPUs rv32/rv64. + +After the introduction of the 'max' CPU type, RISC-V now has a good coverage +of generic CPUs: rv32 and rv64 as default CPUs and 'max' as a feature complete +CPU for both 32 and 64 bit builds. Users are then discouraged to use the 'any' +CPU type starting in 8.2. Block device options '''''''''''''''''''' diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c index c9de7ddb4e..115c2d2fa4 100644 --- a/target/riscv/cpu.c +++ b/target/riscv/cpu.c @@ -1522,6 +1522,11 @@ static void riscv_cpu_realize(DeviceState *dev, Error **errp) RISCVCPUClass *mcc = RISCV_CPU_GET_CLASS(dev); Error *local_err = NULL; + if (object_dynamic_cast(OBJECT(dev), TYPE_RISCV_CPU_ANY) != NULL) { + warn_report("The 'any' CPU is deprecated and will be " + "removed in the future."); + } + cpu_exec_realizefn(cs, &local_err); if (local_err != NULL) { error_propagate(errp, local_err); From 5f2c80f1a014a90382752ad592ccc97183b53bae Mon Sep 17 00:00:00 2001 From: Daniel Henrique Barboza Date: Tue, 12 Sep 2023 10:24:16 -0300 Subject: [PATCH 0547/1077] target/riscv/cpu.c: use offset in isa_ext_is_enabled/update_enabled We'll have future usage for a function where, given an offset of the struct RISCVCPUConfig, the flag is updated to a certain val. Change all existing callers to use edata->ext_enable_offset instead of 'edata'. Signed-off-by: Daniel Henrique Barboza Reviewed-by: Alistair Francis Reviewed-by: Andrew Jones Message-ID: <20230912132423.268494-14-dbarboza@ventanamicro.com> Signed-off-by: Alistair Francis --- target/riscv/cpu.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c index 115c2d2fa4..5287569e5a 100644 --- a/target/riscv/cpu.c +++ b/target/riscv/cpu.c @@ -162,18 +162,17 @@ static const struct isa_ext_data isa_edata_arr[] = { ISA_EXT_DATA_ENTRY(xventanacondops, PRIV_VERSION_1_12_0, ext_XVentanaCondOps), }; -static bool isa_ext_is_enabled(RISCVCPU *cpu, - const struct isa_ext_data *edata) +static bool isa_ext_is_enabled(RISCVCPU *cpu, uint32_t ext_offset) { - bool *ext_enabled = (void *)&cpu->cfg + edata->ext_enable_offset; + bool *ext_enabled = (void *)&cpu->cfg + ext_offset; return *ext_enabled; } -static void isa_ext_update_enabled(RISCVCPU *cpu, - const struct isa_ext_data *edata, bool en) +static void isa_ext_update_enabled(RISCVCPU *cpu, uint32_t ext_offset, + bool en) { - bool *ext_enabled = (void *)&cpu->cfg + edata->ext_enable_offset; + bool *ext_enabled = (void *)&cpu->cfg + ext_offset; *ext_enabled = en; } @@ -1045,9 +1044,10 @@ static void riscv_cpu_disable_priv_spec_isa_exts(RISCVCPU *cpu) /* Force disable extensions if priv spec version does not match */ for (i = 0; i < ARRAY_SIZE(isa_edata_arr); i++) { - if (isa_ext_is_enabled(cpu, &isa_edata_arr[i]) && + if (isa_ext_is_enabled(cpu, isa_edata_arr[i].ext_enable_offset) && (env->priv_ver < isa_edata_arr[i].min_version)) { - isa_ext_update_enabled(cpu, &isa_edata_arr[i], false); + isa_ext_update_enabled(cpu, isa_edata_arr[i].ext_enable_offset, + false); #ifndef CONFIG_USER_ONLY warn_report("disabling %s extension for hart 0x" TARGET_FMT_lx " because privilege spec version does not match", @@ -2340,7 +2340,7 @@ static void riscv_isa_string_ext(RISCVCPU *cpu, char **isa_str, int i; for (i = 0; i < ARRAY_SIZE(isa_edata_arr); i++) { - if (isa_ext_is_enabled(cpu, &isa_edata_arr[i])) { + if (isa_ext_is_enabled(cpu, isa_edata_arr[i].ext_enable_offset)) { new = g_strconcat(old, "_", isa_edata_arr[i].name, NULL); g_free(old); old = new; From 238fd586e0bc06d104d2d095170945b97ea56e19 Mon Sep 17 00:00:00 2001 From: Daniel Henrique Barboza Date: Tue, 12 Sep 2023 10:24:17 -0300 Subject: [PATCH 0548/1077] target/riscv: make CPUCFG() macro public MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The RISC-V KVM driver uses a CPUCFG() macro that calculates the offset of a certain field in the struct RISCVCPUConfig. We're going to use this macro in target/riscv/cpu.c as well in the next patches. Make it public. Rename it to CPU_CFG_OFFSET() for more clarity while we're at it. Signed-off-by: Daniel Henrique Barboza Reviewed-by: Alistair Francis Reviewed-by: Andrew Jones Reviewed-by: Philippe Mathieu-Daudé Message-ID: <20230912132423.268494-15-dbarboza@ventanamicro.com> Signed-off-by: Alistair Francis --- target/riscv/cpu.c | 2 +- target/riscv/cpu.h | 2 ++ target/riscv/kvm.c | 8 +++----- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c index 5287569e5a..7544fff392 100644 --- a/target/riscv/cpu.c +++ b/target/riscv/cpu.c @@ -48,7 +48,7 @@ struct isa_ext_data { }; #define ISA_EXT_DATA_ENTRY(_name, _min_ver, _prop) \ - {#_name, _min_ver, offsetof(struct RISCVCPUConfig, _prop)} + {#_name, _min_ver, CPU_CFG_OFFSET(_prop)} /* * From vector_helper.c diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h index ef9cf21c0c..cce6dee729 100644 --- a/target/riscv/cpu.h +++ b/target/riscv/cpu.h @@ -62,6 +62,8 @@ const char *riscv_get_misa_ext_name(uint32_t bit); const char *riscv_get_misa_ext_description(uint32_t bit); +#define CPU_CFG_OFFSET(_prop) offsetof(struct RISCVCPUConfig, _prop) + /* Privileged specification version */ enum { PRIV_VERSION_1_10_0 = 0, diff --git a/target/riscv/kvm.c b/target/riscv/kvm.c index c01cfb03f4..14763ec0cd 100644 --- a/target/riscv/kvm.c +++ b/target/riscv/kvm.c @@ -205,10 +205,8 @@ static void kvm_riscv_update_cpu_misa_ext(RISCVCPU *cpu, CPUState *cs) } } -#define CPUCFG(_prop) offsetof(struct RISCVCPUConfig, _prop) - #define KVM_EXT_CFG(_name, _prop, _reg_id) \ - {.name = _name, .offset = CPUCFG(_prop), \ + {.name = _name, .offset = CPU_CFG_OFFSET(_prop), \ .kvm_reg_id = _reg_id} static KVMCPUConfig kvm_multi_ext_cfgs[] = { @@ -285,13 +283,13 @@ static void kvm_cpu_set_multi_ext_cfg(Object *obj, Visitor *v, static KVMCPUConfig kvm_cbom_blocksize = { .name = "cbom_blocksize", - .offset = CPUCFG(cbom_blocksize), + .offset = CPU_CFG_OFFSET(cbom_blocksize), .kvm_reg_id = KVM_REG_RISCV_CONFIG_REG(zicbom_block_size) }; static KVMCPUConfig kvm_cboz_blocksize = { .name = "cboz_blocksize", - .offset = CPUCFG(cboz_blocksize), + .offset = CPU_CFG_OFFSET(cboz_blocksize), .kvm_reg_id = KVM_REG_RISCV_CONFIG_REG(zicboz_block_size) }; From 997e71952d1eb8d60b0807d01cf3956d84728067 Mon Sep 17 00:00:00 2001 From: Daniel Henrique Barboza Date: Tue, 12 Sep 2023 10:24:18 -0300 Subject: [PATCH 0549/1077] target/riscv/cpu.c: introduce cpu_cfg_ext_auto_update() During realize() time we're activating a lot of extensions based on some criteria, e.g.: if (cpu->cfg.ext_zk) { cpu->cfg.ext_zkn = true; cpu->cfg.ext_zkr = true; cpu->cfg.ext_zkt = true; } This practice resulted in at least one case where we ended up enabling something we shouldn't: RVC enabling zca/zcd/zcf when using a CPU that has priv_spec older than 1.12.0. We're also not considering user choice. There's no way of doing it now but this is about to change in the next few patches. cpu_cfg_ext_auto_update() will check for priv version mismatches before enabling extensions. If we have a mismatch between the current priv version and the extension we want to enable, do not enable it. In the near future, this same function will also consider user choice when deciding if we're going to enable/disable an extension or not. For now let's use it to handle zca/zcd/zcf enablement if RVC is enabled. Signed-off-by: Daniel Henrique Barboza Reviewed-by: Alistair Francis Reviewed-by: Andrew Jones Message-ID: <20230912132423.268494-16-dbarboza@ventanamicro.com> Signed-off-by: Alistair Francis --- target/riscv/cpu.c | 43 ++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 40 insertions(+), 3 deletions(-) diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c index 7544fff392..bd73b61d3c 100644 --- a/target/riscv/cpu.c +++ b/target/riscv/cpu.c @@ -177,6 +177,43 @@ static void isa_ext_update_enabled(RISCVCPU *cpu, uint32_t ext_offset, *ext_enabled = en; } +static int cpu_cfg_ext_get_min_version(uint32_t ext_offset) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(isa_edata_arr); i++) { + if (isa_edata_arr[i].ext_enable_offset != ext_offset) { + continue; + } + + return isa_edata_arr[i].min_version; + } + + g_assert_not_reached(); +} + +static void cpu_cfg_ext_auto_update(RISCVCPU *cpu, uint32_t ext_offset, + bool value) +{ + CPURISCVState *env = &cpu->env; + bool prev_val = isa_ext_is_enabled(cpu, ext_offset); + int min_version; + + if (prev_val == value) { + return; + } + + if (value && env->priv_ver != PRIV_VERSION_LATEST) { + /* Do not enable it if priv_ver is older than min_version */ + min_version = cpu_cfg_ext_get_min_version(ext_offset); + if (env->priv_ver < min_version) { + return; + } + } + + isa_ext_update_enabled(cpu, ext_offset, value); +} + const char * const riscv_int_regnames[] = { "x0/zero", "x1/ra", "x2/sp", "x3/gp", "x4/tp", "x5/t0", "x6/t1", "x7/t2", "x8/s0", "x9/s1", "x10/a0", "x11/a1", "x12/a2", "x13/a3", @@ -1268,12 +1305,12 @@ void riscv_cpu_validate_set_extensions(RISCVCPU *cpu, Error **errp) /* zca, zcd and zcf has a PRIV 1.12.0 restriction */ if (riscv_has_ext(env, RVC) && env->priv_ver >= PRIV_VERSION_1_12_0) { - cpu->cfg.ext_zca = true; + cpu_cfg_ext_auto_update(cpu, CPU_CFG_OFFSET(ext_zca), true); if (riscv_has_ext(env, RVF) && env->misa_mxl_max == MXL_RV32) { - cpu->cfg.ext_zcf = true; + cpu_cfg_ext_auto_update(cpu, CPU_CFG_OFFSET(ext_zcf), true); } if (riscv_has_ext(env, RVD)) { - cpu->cfg.ext_zcd = true; + cpu_cfg_ext_auto_update(cpu, CPU_CFG_OFFSET(ext_zcd), true); } } From c72b3791278a398b121c8482171b1a8f66481420 Mon Sep 17 00:00:00 2001 From: Daniel Henrique Barboza Date: Tue, 12 Sep 2023 10:24:19 -0300 Subject: [PATCH 0550/1077] target/riscv/cpu.c: use cpu_cfg_ext_auto_update() during realize() Let's change the other instances in realize() where we're enabling an extension based on a certain criteria (e.g. it's a dependency of another extension). We're leaving icsr and ifencei being enabled during RVG for later - we'll want to error out in that case. Every other extension enablement during realize is now done via cpu_cfg_ext_auto_update(). The end goal is that only cpu init() functions will handle extension flags directly via "cpu->cfg.ext_N = true|false". Signed-off-by: Daniel Henrique Barboza Reviewed-by: Alistair Francis Reviewed-by: Andrew Jones Message-ID: <20230912132423.268494-17-dbarboza@ventanamicro.com> Signed-off-by: Alistair Francis --- target/riscv/cpu.c | 50 +++++++++++++++++++++++----------------------- 1 file changed, 25 insertions(+), 25 deletions(-) diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c index bd73b61d3c..25fef13ef0 100644 --- a/target/riscv/cpu.c +++ b/target/riscv/cpu.c @@ -1193,7 +1193,7 @@ void riscv_cpu_validate_set_extensions(RISCVCPU *cpu, Error **errp) } if (cpu->cfg.ext_zfh) { - cpu->cfg.ext_zfhmin = true; + cpu_cfg_ext_auto_update(cpu, CPU_CFG_OFFSET(ext_zfhmin), true); } if (cpu->cfg.ext_zfhmin && !riscv_has_ext(env, RVF)) { @@ -1219,17 +1219,17 @@ void riscv_cpu_validate_set_extensions(RISCVCPU *cpu, Error **errp) } /* The V vector extension depends on the Zve64d extension */ - cpu->cfg.ext_zve64d = true; + cpu_cfg_ext_auto_update(cpu, CPU_CFG_OFFSET(ext_zve64d), true); } /* The Zve64d extension depends on the Zve64f extension */ if (cpu->cfg.ext_zve64d) { - cpu->cfg.ext_zve64f = true; + cpu_cfg_ext_auto_update(cpu, CPU_CFG_OFFSET(ext_zve64f), true); } /* The Zve64f extension depends on the Zve32f extension */ if (cpu->cfg.ext_zve64f) { - cpu->cfg.ext_zve32f = true; + cpu_cfg_ext_auto_update(cpu, CPU_CFG_OFFSET(ext_zve32f), true); } if (cpu->cfg.ext_zve64d && !riscv_has_ext(env, RVD)) { @@ -1243,7 +1243,7 @@ void riscv_cpu_validate_set_extensions(RISCVCPU *cpu, Error **errp) } if (cpu->cfg.ext_zvfh) { - cpu->cfg.ext_zvfhmin = true; + cpu_cfg_ext_auto_update(cpu, CPU_CFG_OFFSET(ext_zvfhmin), true); } if (cpu->cfg.ext_zvfhmin && !cpu->cfg.ext_zve32f) { @@ -1273,7 +1273,7 @@ void riscv_cpu_validate_set_extensions(RISCVCPU *cpu, Error **errp) /* Set the ISA extensions, checks should have happened above */ if (cpu->cfg.ext_zhinx) { - cpu->cfg.ext_zhinxmin = true; + cpu_cfg_ext_auto_update(cpu, CPU_CFG_OFFSET(ext_zca), true); } if ((cpu->cfg.ext_zdinx || cpu->cfg.ext_zhinxmin) && !cpu->cfg.ext_zfinx) { @@ -1294,12 +1294,12 @@ void riscv_cpu_validate_set_extensions(RISCVCPU *cpu, Error **errp) } if (cpu->cfg.ext_zce) { - cpu->cfg.ext_zca = true; - cpu->cfg.ext_zcb = true; - cpu->cfg.ext_zcmp = true; - cpu->cfg.ext_zcmt = true; + cpu_cfg_ext_auto_update(cpu, CPU_CFG_OFFSET(ext_zca), true); + cpu_cfg_ext_auto_update(cpu, CPU_CFG_OFFSET(ext_zcb), true); + cpu_cfg_ext_auto_update(cpu, CPU_CFG_OFFSET(ext_zcmp), true); + cpu_cfg_ext_auto_update(cpu, CPU_CFG_OFFSET(ext_zcmt), true); if (riscv_has_ext(env, RVF) && env->misa_mxl_max == MXL_RV32) { - cpu->cfg.ext_zcf = true; + cpu_cfg_ext_auto_update(cpu, CPU_CFG_OFFSET(ext_zcf), true); } } @@ -1367,26 +1367,26 @@ void riscv_cpu_validate_set_extensions(RISCVCPU *cpu, Error **errp) } if (cpu->cfg.ext_zk) { - cpu->cfg.ext_zkn = true; - cpu->cfg.ext_zkr = true; - cpu->cfg.ext_zkt = true; + cpu_cfg_ext_auto_update(cpu, CPU_CFG_OFFSET(ext_zkn), true); + cpu_cfg_ext_auto_update(cpu, CPU_CFG_OFFSET(ext_zkr), true); + cpu_cfg_ext_auto_update(cpu, CPU_CFG_OFFSET(ext_zkt), true); } if (cpu->cfg.ext_zkn) { - cpu->cfg.ext_zbkb = true; - cpu->cfg.ext_zbkc = true; - cpu->cfg.ext_zbkx = true; - cpu->cfg.ext_zkne = true; - cpu->cfg.ext_zknd = true; - cpu->cfg.ext_zknh = true; + cpu_cfg_ext_auto_update(cpu, CPU_CFG_OFFSET(ext_zbkb), true); + cpu_cfg_ext_auto_update(cpu, CPU_CFG_OFFSET(ext_zbkc), true); + cpu_cfg_ext_auto_update(cpu, CPU_CFG_OFFSET(ext_zbkx), true); + cpu_cfg_ext_auto_update(cpu, CPU_CFG_OFFSET(ext_zkne), true); + cpu_cfg_ext_auto_update(cpu, CPU_CFG_OFFSET(ext_zknd), true); + cpu_cfg_ext_auto_update(cpu, CPU_CFG_OFFSET(ext_zknh), true); } if (cpu->cfg.ext_zks) { - cpu->cfg.ext_zbkb = true; - cpu->cfg.ext_zbkc = true; - cpu->cfg.ext_zbkx = true; - cpu->cfg.ext_zksed = true; - cpu->cfg.ext_zksh = true; + cpu_cfg_ext_auto_update(cpu, CPU_CFG_OFFSET(ext_zbkb), true); + cpu_cfg_ext_auto_update(cpu, CPU_CFG_OFFSET(ext_zbkc), true); + cpu_cfg_ext_auto_update(cpu, CPU_CFG_OFFSET(ext_zbkx), true); + cpu_cfg_ext_auto_update(cpu, CPU_CFG_OFFSET(ext_zksed), true); + cpu_cfg_ext_auto_update(cpu, CPU_CFG_OFFSET(ext_zksh), true); } /* From 549cbf789ef8669a835207e020db67d20045b1a9 Mon Sep 17 00:00:00 2001 From: Daniel Henrique Barboza Date: Tue, 12 Sep 2023 10:24:20 -0300 Subject: [PATCH 0551/1077] target/riscv/cpu.c: introduce RISCVCPUMultiExtConfig If we want to make better decisions when auto-enabling extensions during realize() we need a way to tell if an user set an extension manually. The RISC-V KVM driver has its own solution via a KVMCPUConfig struct that has an 'user_set' flag that is set during the Property set() callback. The set() callback also does init() time validations based on the current KVM driver capabilities. For TCG we would want a 'user_set' mechanic too, but we would look ad-hoc via cpu_cfg_ext_auto_update() if a certain extension was user set or not. If we copy what was made in the KVM side we would look for 'user_set' for one into 60+ extension structs spreaded in 3 arrays (riscv_cpu_extensions, riscv_cpu_experimental_exts, riscv_cpu_vendor_exts). We'll still need an extension struct but we won't be using the 'user_set' flag: - 'RISCVCPUMultiExtConfig' will be our specialized structure, similar to what we're already doing with the MISA extensions in 'RISCVCPUMisaExtConfig'. DEFINE_PROP_BOOL() for all 3 extensions arrays were replaced by MULTI_EXT_CFG_BOOL(), a macro that will init our specialized struct; - the 'multi_ext_user_opts' hash will be used to store the offset of each extension that the user set via the set() callback, cpu_set_multi_ext_cfg(). For now we're just initializing and populating it - next patch will use it to determine if a certain extension was user set; - cpu_add_multi_ext_prop() is a new helper that will replace the qdev_property_add_static() calls that our macros are doing to populate user properties. The macro was renamed to ADD_CPU_MULTIEXT_PROPS_ARRAY() for clarity. Note that the non-extension properties in riscv_cpu_options[] still need to be declared via qdev(). Signed-off-by: Daniel Henrique Barboza Reviewed-by: Alistair Francis Reviewed-by: Andrew Jones Message-ID: <20230912132423.268494-18-dbarboza@ventanamicro.com> Signed-off-by: Alistair Francis --- target/riscv/cpu.c | 246 ++++++++++++++++++++++++++++----------------- 1 file changed, 153 insertions(+), 93 deletions(-) diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c index 25fef13ef0..fba5ce7118 100644 --- a/target/riscv/cpu.c +++ b/target/riscv/cpu.c @@ -162,6 +162,9 @@ static const struct isa_ext_data isa_edata_arr[] = { ISA_EXT_DATA_ENTRY(xventanacondops, PRIV_VERSION_1_12_0, ext_XVentanaCondOps), }; +/* Hash that stores user set extensions */ +static GHashTable *multi_ext_user_opts; + static bool isa_ext_is_enabled(RISCVCPU *cpu, uint32_t ext_offset) { bool *ext_enabled = (void *)&cpu->cfg + ext_offset; @@ -1714,6 +1717,8 @@ static void riscv_cpu_init(Object *obj) qdev_init_gpio_in(DEVICE(obj), riscv_cpu_set_irq, IRQ_LOCAL_MAX + IRQ_LOCAL_GUEST_MAX); #endif /* CONFIG_USER_ONLY */ + + multi_ext_user_opts = g_hash_table_new(NULL, g_direct_equal); } typedef struct RISCVCPUMisaExtConfig { @@ -1865,108 +1870,118 @@ static void riscv_cpu_add_misa_properties(Object *cpu_obj) } } -static Property riscv_cpu_extensions[] = { +typedef struct RISCVCPUMultiExtConfig { + const char *name; + uint32_t offset; + bool enabled; +} RISCVCPUMultiExtConfig; + +#define MULTI_EXT_CFG_BOOL(_name, _prop, _defval) \ + {.name = _name, .offset = CPU_CFG_OFFSET(_prop), \ + .enabled = _defval} + +static RISCVCPUMultiExtConfig riscv_cpu_extensions[] = { /* Defaults for standard extensions */ - DEFINE_PROP_BOOL("sscofpmf", RISCVCPU, cfg.ext_sscofpmf, false), - DEFINE_PROP_BOOL("Zifencei", RISCVCPU, cfg.ext_ifencei, true), - DEFINE_PROP_BOOL("Zicsr", RISCVCPU, cfg.ext_icsr, true), - DEFINE_PROP_BOOL("Zihintntl", RISCVCPU, cfg.ext_zihintntl, true), - DEFINE_PROP_BOOL("Zihintpause", RISCVCPU, cfg.ext_zihintpause, true), - DEFINE_PROP_BOOL("Zawrs", RISCVCPU, cfg.ext_zawrs, true), - DEFINE_PROP_BOOL("Zfa", RISCVCPU, cfg.ext_zfa, true), - DEFINE_PROP_BOOL("Zfh", RISCVCPU, cfg.ext_zfh, false), - DEFINE_PROP_BOOL("Zfhmin", RISCVCPU, cfg.ext_zfhmin, false), - DEFINE_PROP_BOOL("Zve32f", RISCVCPU, cfg.ext_zve32f, false), - DEFINE_PROP_BOOL("Zve64f", RISCVCPU, cfg.ext_zve64f, false), - DEFINE_PROP_BOOL("Zve64d", RISCVCPU, cfg.ext_zve64d, false), - DEFINE_PROP_BOOL("sstc", RISCVCPU, cfg.ext_sstc, true), + MULTI_EXT_CFG_BOOL("sscofpmf", ext_sscofpmf, false), + MULTI_EXT_CFG_BOOL("Zifencei", ext_ifencei, true), + MULTI_EXT_CFG_BOOL("Zicsr", ext_icsr, true), + MULTI_EXT_CFG_BOOL("Zihintntl", ext_zihintntl, true), + MULTI_EXT_CFG_BOOL("Zihintpause", ext_zihintpause, true), + MULTI_EXT_CFG_BOOL("Zawrs", ext_zawrs, true), + MULTI_EXT_CFG_BOOL("Zfa", ext_zfa, true), + MULTI_EXT_CFG_BOOL("Zfh", ext_zfh, false), + MULTI_EXT_CFG_BOOL("Zfhmin", ext_zfhmin, false), + MULTI_EXT_CFG_BOOL("Zve32f", ext_zve32f, false), + MULTI_EXT_CFG_BOOL("Zve64f", ext_zve64f, false), + MULTI_EXT_CFG_BOOL("Zve64d", ext_zve64d, false), + MULTI_EXT_CFG_BOOL("sstc", ext_sstc, true), - DEFINE_PROP_BOOL("smstateen", RISCVCPU, cfg.ext_smstateen, false), - DEFINE_PROP_BOOL("svadu", RISCVCPU, cfg.ext_svadu, true), - DEFINE_PROP_BOOL("svinval", RISCVCPU, cfg.ext_svinval, false), - DEFINE_PROP_BOOL("svnapot", RISCVCPU, cfg.ext_svnapot, false), - DEFINE_PROP_BOOL("svpbmt", RISCVCPU, cfg.ext_svpbmt, false), + MULTI_EXT_CFG_BOOL("smstateen", ext_smstateen, false), + MULTI_EXT_CFG_BOOL("svadu", ext_svadu, true), + MULTI_EXT_CFG_BOOL("svinval", ext_svinval, false), + MULTI_EXT_CFG_BOOL("svnapot", ext_svnapot, false), + MULTI_EXT_CFG_BOOL("svpbmt", ext_svpbmt, false), - DEFINE_PROP_BOOL("zba", RISCVCPU, cfg.ext_zba, true), - DEFINE_PROP_BOOL("zbb", RISCVCPU, cfg.ext_zbb, true), - DEFINE_PROP_BOOL("zbc", RISCVCPU, cfg.ext_zbc, true), - DEFINE_PROP_BOOL("zbkb", RISCVCPU, cfg.ext_zbkb, false), - DEFINE_PROP_BOOL("zbkc", RISCVCPU, cfg.ext_zbkc, false), - DEFINE_PROP_BOOL("zbkx", RISCVCPU, cfg.ext_zbkx, false), - DEFINE_PROP_BOOL("zbs", RISCVCPU, cfg.ext_zbs, true), - DEFINE_PROP_BOOL("zk", RISCVCPU, cfg.ext_zk, false), - DEFINE_PROP_BOOL("zkn", RISCVCPU, cfg.ext_zkn, false), - DEFINE_PROP_BOOL("zknd", RISCVCPU, cfg.ext_zknd, false), - DEFINE_PROP_BOOL("zkne", RISCVCPU, cfg.ext_zkne, false), - DEFINE_PROP_BOOL("zknh", RISCVCPU, cfg.ext_zknh, false), - DEFINE_PROP_BOOL("zkr", RISCVCPU, cfg.ext_zkr, false), - DEFINE_PROP_BOOL("zks", RISCVCPU, cfg.ext_zks, false), - DEFINE_PROP_BOOL("zksed", RISCVCPU, cfg.ext_zksed, false), - DEFINE_PROP_BOOL("zksh", RISCVCPU, cfg.ext_zksh, false), - DEFINE_PROP_BOOL("zkt", RISCVCPU, cfg.ext_zkt, false), + MULTI_EXT_CFG_BOOL("zba", ext_zba, true), + MULTI_EXT_CFG_BOOL("zbb", ext_zbb, true), + MULTI_EXT_CFG_BOOL("zbc", ext_zbc, true), + MULTI_EXT_CFG_BOOL("zbkb", ext_zbkb, false), + MULTI_EXT_CFG_BOOL("zbkc", ext_zbkc, false), + MULTI_EXT_CFG_BOOL("zbkx", ext_zbkx, false), + MULTI_EXT_CFG_BOOL("zbs", ext_zbs, true), + MULTI_EXT_CFG_BOOL("zk", ext_zk, false), + MULTI_EXT_CFG_BOOL("zkn", ext_zkn, false), + MULTI_EXT_CFG_BOOL("zknd", ext_zknd, false), + MULTI_EXT_CFG_BOOL("zkne", ext_zkne, false), + MULTI_EXT_CFG_BOOL("zknh", ext_zknh, false), + MULTI_EXT_CFG_BOOL("zkr", ext_zkr, false), + MULTI_EXT_CFG_BOOL("zks", ext_zks, false), + MULTI_EXT_CFG_BOOL("zksed", ext_zksed, false), + MULTI_EXT_CFG_BOOL("zksh", ext_zksh, false), + MULTI_EXT_CFG_BOOL("zkt", ext_zkt, false), - DEFINE_PROP_BOOL("zdinx", RISCVCPU, cfg.ext_zdinx, false), - DEFINE_PROP_BOOL("zfinx", RISCVCPU, cfg.ext_zfinx, false), - DEFINE_PROP_BOOL("zhinx", RISCVCPU, cfg.ext_zhinx, false), - DEFINE_PROP_BOOL("zhinxmin", RISCVCPU, cfg.ext_zhinxmin, false), + MULTI_EXT_CFG_BOOL("zdinx", ext_zdinx, false), + MULTI_EXT_CFG_BOOL("zfinx", ext_zfinx, false), + MULTI_EXT_CFG_BOOL("zhinx", ext_zhinx, false), + MULTI_EXT_CFG_BOOL("zhinxmin", ext_zhinxmin, false), - DEFINE_PROP_BOOL("zicbom", RISCVCPU, cfg.ext_icbom, true), - DEFINE_PROP_BOOL("zicboz", RISCVCPU, cfg.ext_icboz, true), + MULTI_EXT_CFG_BOOL("zicbom", ext_icbom, true), + MULTI_EXT_CFG_BOOL("zicboz", ext_icboz, true), - DEFINE_PROP_BOOL("zmmul", RISCVCPU, cfg.ext_zmmul, false), + MULTI_EXT_CFG_BOOL("zmmul", ext_zmmul, false), - DEFINE_PROP_BOOL("zca", RISCVCPU, cfg.ext_zca, false), - DEFINE_PROP_BOOL("zcb", RISCVCPU, cfg.ext_zcb, false), - DEFINE_PROP_BOOL("zcd", RISCVCPU, cfg.ext_zcd, false), - DEFINE_PROP_BOOL("zce", RISCVCPU, cfg.ext_zce, false), - DEFINE_PROP_BOOL("zcf", RISCVCPU, cfg.ext_zcf, false), - DEFINE_PROP_BOOL("zcmp", RISCVCPU, cfg.ext_zcmp, false), - DEFINE_PROP_BOOL("zcmt", RISCVCPU, cfg.ext_zcmt, false), - DEFINE_PROP_BOOL("zicond", RISCVCPU, cfg.ext_zicond, false), + MULTI_EXT_CFG_BOOL("zca", ext_zca, false), + MULTI_EXT_CFG_BOOL("zcb", ext_zcb, false), + MULTI_EXT_CFG_BOOL("zcd", ext_zcd, false), + MULTI_EXT_CFG_BOOL("zce", ext_zce, false), + MULTI_EXT_CFG_BOOL("zcf", ext_zcf, false), + MULTI_EXT_CFG_BOOL("zcmp", ext_zcmp, false), + MULTI_EXT_CFG_BOOL("zcmt", ext_zcmt, false), + MULTI_EXT_CFG_BOOL("zicond", ext_zicond, false), DEFINE_PROP_END_OF_LIST(), }; -static Property riscv_cpu_vendor_exts[] = { - DEFINE_PROP_BOOL("xtheadba", RISCVCPU, cfg.ext_xtheadba, false), - DEFINE_PROP_BOOL("xtheadbb", RISCVCPU, cfg.ext_xtheadbb, false), - DEFINE_PROP_BOOL("xtheadbs", RISCVCPU, cfg.ext_xtheadbs, false), - DEFINE_PROP_BOOL("xtheadcmo", RISCVCPU, cfg.ext_xtheadcmo, false), - DEFINE_PROP_BOOL("xtheadcondmov", RISCVCPU, cfg.ext_xtheadcondmov, false), - DEFINE_PROP_BOOL("xtheadfmemidx", RISCVCPU, cfg.ext_xtheadfmemidx, false), - DEFINE_PROP_BOOL("xtheadfmv", RISCVCPU, cfg.ext_xtheadfmv, false), - DEFINE_PROP_BOOL("xtheadmac", RISCVCPU, cfg.ext_xtheadmac, false), - DEFINE_PROP_BOOL("xtheadmemidx", RISCVCPU, cfg.ext_xtheadmemidx, false), - DEFINE_PROP_BOOL("xtheadmempair", RISCVCPU, cfg.ext_xtheadmempair, false), - DEFINE_PROP_BOOL("xtheadsync", RISCVCPU, cfg.ext_xtheadsync, false), - DEFINE_PROP_BOOL("xventanacondops", RISCVCPU, cfg.ext_XVentanaCondOps, false), +static RISCVCPUMultiExtConfig riscv_cpu_vendor_exts[] = { + MULTI_EXT_CFG_BOOL("xtheadba", ext_xtheadba, false), + MULTI_EXT_CFG_BOOL("xtheadbb", ext_xtheadbb, false), + MULTI_EXT_CFG_BOOL("xtheadbs", ext_xtheadbs, false), + MULTI_EXT_CFG_BOOL("xtheadcmo", ext_xtheadcmo, false), + MULTI_EXT_CFG_BOOL("xtheadcondmov", ext_xtheadcondmov, false), + MULTI_EXT_CFG_BOOL("xtheadfmemidx", ext_xtheadfmemidx, false), + MULTI_EXT_CFG_BOOL("xtheadfmv", ext_xtheadfmv, false), + MULTI_EXT_CFG_BOOL("xtheadmac", ext_xtheadmac, false), + MULTI_EXT_CFG_BOOL("xtheadmemidx", ext_xtheadmemidx, false), + MULTI_EXT_CFG_BOOL("xtheadmempair", ext_xtheadmempair, false), + MULTI_EXT_CFG_BOOL("xtheadsync", ext_xtheadsync, false), + MULTI_EXT_CFG_BOOL("xventanacondops", ext_XVentanaCondOps, false), DEFINE_PROP_END_OF_LIST(), }; /* These are experimental so mark with 'x-' */ -static Property riscv_cpu_experimental_exts[] = { +static RISCVCPUMultiExtConfig riscv_cpu_experimental_exts[] = { /* ePMP 0.9.3 */ - DEFINE_PROP_BOOL("x-epmp", RISCVCPU, cfg.epmp, false), - DEFINE_PROP_BOOL("x-smaia", RISCVCPU, cfg.ext_smaia, false), - DEFINE_PROP_BOOL("x-ssaia", RISCVCPU, cfg.ext_ssaia, false), + MULTI_EXT_CFG_BOOL("x-epmp", epmp, false), + MULTI_EXT_CFG_BOOL("x-smaia", ext_smaia, false), + MULTI_EXT_CFG_BOOL("x-ssaia", ext_ssaia, false), - DEFINE_PROP_BOOL("x-zvfh", RISCVCPU, cfg.ext_zvfh, false), - DEFINE_PROP_BOOL("x-zvfhmin", RISCVCPU, cfg.ext_zvfhmin, false), + MULTI_EXT_CFG_BOOL("x-zvfh", ext_zvfh, false), + MULTI_EXT_CFG_BOOL("x-zvfhmin", ext_zvfhmin, false), - DEFINE_PROP_BOOL("x-zfbfmin", RISCVCPU, cfg.ext_zfbfmin, false), - DEFINE_PROP_BOOL("x-zvfbfmin", RISCVCPU, cfg.ext_zvfbfmin, false), - DEFINE_PROP_BOOL("x-zvfbfwma", RISCVCPU, cfg.ext_zvfbfwma, false), + MULTI_EXT_CFG_BOOL("x-zfbfmin", ext_zfbfmin, false), + MULTI_EXT_CFG_BOOL("x-zvfbfmin", ext_zvfbfmin, false), + MULTI_EXT_CFG_BOOL("x-zvfbfwma", ext_zvfbfwma, false), /* Vector cryptography extensions */ - DEFINE_PROP_BOOL("x-zvbb", RISCVCPU, cfg.ext_zvbb, false), - DEFINE_PROP_BOOL("x-zvbc", RISCVCPU, cfg.ext_zvbc, false), - DEFINE_PROP_BOOL("x-zvkg", RISCVCPU, cfg.ext_zvkg, false), - DEFINE_PROP_BOOL("x-zvkned", RISCVCPU, cfg.ext_zvkned, false), - DEFINE_PROP_BOOL("x-zvknha", RISCVCPU, cfg.ext_zvknha, false), - DEFINE_PROP_BOOL("x-zvknhb", RISCVCPU, cfg.ext_zvknhb, false), - DEFINE_PROP_BOOL("x-zvksed", RISCVCPU, cfg.ext_zvksed, false), - DEFINE_PROP_BOOL("x-zvksh", RISCVCPU, cfg.ext_zvksh, false), + MULTI_EXT_CFG_BOOL("x-zvbb", ext_zvbb, false), + MULTI_EXT_CFG_BOOL("x-zvbc", ext_zvbc, false), + MULTI_EXT_CFG_BOOL("x-zvkg", ext_zvkg, false), + MULTI_EXT_CFG_BOOL("x-zvkned", ext_zvkned, false), + MULTI_EXT_CFG_BOOL("x-zvknha", ext_zvknha, false), + MULTI_EXT_CFG_BOOL("x-zvknhb", ext_zvknhb, false), + MULTI_EXT_CFG_BOOL("x-zvksed", ext_zvksed, false), + MULTI_EXT_CFG_BOOL("x-zvksh", ext_zvksh, false), DEFINE_PROP_END_OF_LIST(), }; @@ -1989,12 +2004,56 @@ static Property riscv_cpu_options[] = { DEFINE_PROP_END_OF_LIST(), }; -static void riscv_cpu_add_qdev_prop_array(DeviceState *dev, Property *array) +static void cpu_set_multi_ext_cfg(Object *obj, Visitor *v, const char *name, + void *opaque, Error **errp) +{ + const RISCVCPUMultiExtConfig *multi_ext_cfg = opaque; + bool value; + + if (!visit_type_bool(v, name, &value, errp)) { + return; + } + + isa_ext_update_enabled(RISCV_CPU(obj), multi_ext_cfg->offset, value); + + g_hash_table_insert(multi_ext_user_opts, + GUINT_TO_POINTER(multi_ext_cfg->offset), + (gpointer)value); +} + +static void cpu_get_multi_ext_cfg(Object *obj, Visitor *v, const char *name, + void *opaque, Error **errp) +{ + const RISCVCPUMultiExtConfig *multi_ext_cfg = opaque; + bool value = isa_ext_is_enabled(RISCV_CPU(obj), multi_ext_cfg->offset); + + visit_type_bool(v, name, &value, errp); +} + +static void cpu_add_multi_ext_prop(Object *cpu_obj, + RISCVCPUMultiExtConfig *multi_cfg) +{ + object_property_add(cpu_obj, multi_cfg->name, "bool", + cpu_get_multi_ext_cfg, + cpu_set_multi_ext_cfg, + NULL, (void *)multi_cfg); + + /* + * Set def val directly instead of using + * object_property_set_bool() to save the set() + * callback hash for user inputs. + */ + isa_ext_update_enabled(RISCV_CPU(cpu_obj), multi_cfg->offset, + multi_cfg->enabled); +} + +static void riscv_cpu_add_multiext_prop_array(Object *obj, + RISCVCPUMultiExtConfig *array) { g_assert(array); - for (Property *prop = array; prop && prop->name; prop++) { - qdev_property_add_static(dev, prop); + for (RISCVCPUMultiExtConfig *prop = array; prop && prop->name; prop++) { + cpu_add_multi_ext_prop(obj, prop); } } @@ -2034,11 +2093,11 @@ static void riscv_cpu_add_kvm_unavail_prop(Object *obj, const char *prop_name) } static void riscv_cpu_add_kvm_unavail_prop_array(Object *obj, - Property *array) + RISCVCPUMultiExtConfig *array) { g_assert(array); - for (Property *prop = array; prop && prop->name; prop++) { + for (RISCVCPUMultiExtConfig *prop = array; prop && prop->name; prop++) { riscv_cpu_add_kvm_unavail_prop(obj, prop->name); } } @@ -2073,8 +2132,6 @@ void kvm_riscv_cpu_add_kvm_properties(Object *obj) */ static void riscv_cpu_add_user_properties(Object *obj) { - DeviceState *dev = DEVICE(obj); - #ifndef CONFIG_USER_ONLY riscv_add_satp_mode_properties(obj); @@ -2086,10 +2143,13 @@ static void riscv_cpu_add_user_properties(Object *obj) riscv_cpu_add_misa_properties(obj); - riscv_cpu_add_qdev_prop_array(dev, riscv_cpu_extensions); - riscv_cpu_add_qdev_prop_array(dev, riscv_cpu_options); - riscv_cpu_add_qdev_prop_array(dev, riscv_cpu_vendor_exts); - riscv_cpu_add_qdev_prop_array(dev, riscv_cpu_experimental_exts); + riscv_cpu_add_multiext_prop_array(obj, riscv_cpu_extensions); + riscv_cpu_add_multiext_prop_array(obj, riscv_cpu_vendor_exts); + riscv_cpu_add_multiext_prop_array(obj, riscv_cpu_experimental_exts); + + for (Property *prop = riscv_cpu_options; prop && prop->name; prop++) { + qdev_property_add_static(DEVICE(obj), prop); + } } /* @@ -2100,7 +2160,7 @@ static void riscv_init_max_cpu_extensions(Object *obj) { RISCVCPU *cpu = RISCV_CPU(obj); CPURISCVState *env = &cpu->env; - Property *prop; + RISCVCPUMultiExtConfig *prop; /* Enable RVG, RVJ and RVV that are disabled by default */ set_misa(env, env->misa_mxl, env->misa_ext | RVG | RVJ | RVV); From 25aa6f7202d5403ac123abe5cd5ff08f2e003f77 Mon Sep 17 00:00:00 2001 From: Daniel Henrique Barboza Date: Tue, 12 Sep 2023 10:24:21 -0300 Subject: [PATCH 0552/1077] target/riscv: use isa_ext_update_enabled() in init_max_cpu_extensions() Before adding support to detect if an extension was user set we need to handle how we're enabling extensions in riscv_init_max_cpu_extensions(). object_property_set_bool() calls the set() callback for the property, and we're going to use this callback to set the 'multi_ext_user_opts' hash. This means that, as is today, all extensions we're setting for the 'max' CPU will be seen as user set in the future. Let's change set_bool() to isa_ext_update_enabled() that will just enable/disable the flag on a certain offset. Signed-off-by: Daniel Henrique Barboza Reviewed-by: Alistair Francis Reviewed-by: Andrew Jones Message-ID: <20230912132423.268494-19-dbarboza@ventanamicro.com> Signed-off-by: Alistair Francis --- target/riscv/cpu.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c index fba5ce7118..821006f42a 100644 --- a/target/riscv/cpu.c +++ b/target/riscv/cpu.c @@ -2166,24 +2166,24 @@ static void riscv_init_max_cpu_extensions(Object *obj) set_misa(env, env->misa_mxl, env->misa_ext | RVG | RVJ | RVV); for (prop = riscv_cpu_extensions; prop && prop->name; prop++) { - object_property_set_bool(obj, prop->name, true, NULL); + isa_ext_update_enabled(cpu, prop->offset, true); } /* set vector version */ env->vext_ver = VEXT_VERSION_1_00_0; /* Zfinx is not compatible with F. Disable it */ - object_property_set_bool(obj, "zfinx", false, NULL); - object_property_set_bool(obj, "zdinx", false, NULL); - object_property_set_bool(obj, "zhinx", false, NULL); - object_property_set_bool(obj, "zhinxmin", false, NULL); + isa_ext_update_enabled(cpu, CPU_CFG_OFFSET(ext_zfinx), false); + isa_ext_update_enabled(cpu, CPU_CFG_OFFSET(ext_zdinx), false); + isa_ext_update_enabled(cpu, CPU_CFG_OFFSET(ext_zhinx), false); + isa_ext_update_enabled(cpu, CPU_CFG_OFFSET(ext_zhinxmin), false); - object_property_set_bool(obj, "zce", false, NULL); - object_property_set_bool(obj, "zcmp", false, NULL); - object_property_set_bool(obj, "zcmt", false, NULL); + isa_ext_update_enabled(cpu, CPU_CFG_OFFSET(ext_zce), false); + isa_ext_update_enabled(cpu, CPU_CFG_OFFSET(ext_zcmp), false); + isa_ext_update_enabled(cpu, CPU_CFG_OFFSET(ext_zcmt), false); if (env->misa_mxl != MXL_RV32) { - object_property_set_bool(obj, "zcf", false, NULL); + isa_ext_update_enabled(cpu, CPU_CFG_OFFSET(ext_zcf), false); } } From 0a9eb9b497f3d349da77073e704c1a010cb788e5 Mon Sep 17 00:00:00 2001 From: Daniel Henrique Barboza Date: Tue, 12 Sep 2023 10:24:22 -0300 Subject: [PATCH 0553/1077] target/riscv/cpu.c: honor user choice in cpu_cfg_ext_auto_update() Add a new cpu_cfg_ext_is_user_set() helper to check if an extension was set by the user in the command line. Use it inside cpu_cfg_ext_auto_update() to verify if the user set a certain extension and, if that's the case, do not change its value. This will make us honor user choice instead of overwriting the values. Users will then be informed whether they're using an incompatible set of extensions instead of QEMU setting a magic value that works. The reason why we're not implementing user choice for MISA extensions right now is because, today, we do not silently change any MISA bit during realize() time (we do warn when enabling bits if RVG is enabled). We do that - a lot - with multi-letter extensions though, so we're handling the most immediate concern first. After this patch, we'll now error out if the user explicitly set 'zce' to true and 'zca' to false: $ ./build/qemu-system-riscv64 -M virt -cpu rv64,zce=true,zca=false -nographic qemu-system-riscv64: Zcf/Zcd/Zcb/Zcmp/Zcmt extensions require Zca extension This didn't happen before because we were enabling 'zca' if 'zce' was enabled regardless if the user set 'zca' to false. Signed-off-by: Daniel Henrique Barboza Reviewed-by: Alistair Francis Reviewed-by: Andrew Jones Message-ID: <20230912132423.268494-20-dbarboza@ventanamicro.com> Signed-off-by: Alistair Francis --- target/riscv/cpu.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c index 821006f42a..d1a3ddadd0 100644 --- a/target/riscv/cpu.c +++ b/target/riscv/cpu.c @@ -195,6 +195,12 @@ static int cpu_cfg_ext_get_min_version(uint32_t ext_offset) g_assert_not_reached(); } +static bool cpu_cfg_ext_is_user_set(uint32_t ext_offset) +{ + return g_hash_table_contains(multi_ext_user_opts, + GUINT_TO_POINTER(ext_offset)); +} + static void cpu_cfg_ext_auto_update(RISCVCPU *cpu, uint32_t ext_offset, bool value) { @@ -206,6 +212,10 @@ static void cpu_cfg_ext_auto_update(RISCVCPU *cpu, uint32_t ext_offset, return; } + if (cpu_cfg_ext_is_user_set(ext_offset)) { + return; + } + if (value && env->priv_ver != PRIV_VERSION_LATEST) { /* Do not enable it if priv_ver is older than min_version */ min_version = cpu_cfg_ext_get_min_version(ext_offset); @@ -1843,6 +1853,12 @@ static RISCVCPUMisaExtConfig misa_ext_cfgs[] = { MISA_CFG(RVG, false), }; +/* + * We do not support user choice tracking for MISA + * extensions yet because, so far, we do not silently + * change MISA bits during realize() (RVG enables MISA + * bits but the user is warned about it). + */ static void riscv_cpu_add_misa_properties(Object *cpu_obj) { int i; From 67f94b09ac4f64d4a0595d1224ba3a425e565043 Mon Sep 17 00:00:00 2001 From: Daniel Henrique Barboza Date: Tue, 12 Sep 2023 10:24:23 -0300 Subject: [PATCH 0554/1077] target/riscv/cpu.c: consider user option with RVG Enabling RVG will enable a set of extensions that we're not checking if the user was okay enabling or not. And in this case we want to error out, instead of ignoring, otherwise we will be inconsistent enabling RVG without all its extensions. After this patch, disabling ifencei or icsr while enabling RVG will result in error: $ ./build/qemu-system-riscv64 -M virt -cpu rv64,g=true,Zifencei=false --nographic qemu-system-riscv64: RVG requires Zifencei but user set Zifencei to false Signed-off-by: Daniel Henrique Barboza Reviewed-by: Alistair Francis Reviewed-by: Andrew Jones Message-ID: <20230912132423.268494-21-dbarboza@ventanamicro.com> Signed-off-by: Alistair Francis --- target/riscv/cpu.c | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c index d1a3ddadd0..383e5df2a7 100644 --- a/target/riscv/cpu.c +++ b/target/riscv/cpu.c @@ -1153,9 +1153,23 @@ void riscv_cpu_validate_set_extensions(RISCVCPU *cpu, Error **errp) riscv_has_ext(env, RVA) && riscv_has_ext(env, RVF) && riscv_has_ext(env, RVD) && cpu->cfg.ext_icsr && cpu->cfg.ext_ifencei)) { + + if (cpu_cfg_ext_is_user_set(CPU_CFG_OFFSET(ext_icsr)) && + !cpu->cfg.ext_icsr) { + error_setg(errp, "RVG requires Zicsr but user set Zicsr to false"); + return; + } + + if (cpu_cfg_ext_is_user_set(CPU_CFG_OFFSET(ext_ifencei)) && + !cpu->cfg.ext_ifencei) { + error_setg(errp, "RVG requires Zifencei but user set " + "Zifencei to false"); + return; + } + warn_report("Setting G will also set IMAFD_Zicsr_Zifencei"); - cpu->cfg.ext_icsr = true; - cpu->cfg.ext_ifencei = true; + cpu_cfg_ext_auto_update(cpu, CPU_CFG_OFFSET(ext_icsr), true); + cpu_cfg_ext_auto_update(cpu, CPU_CFG_OFFSET(ext_ifencei), true); env->misa_ext |= RVI | RVM | RVA | RVF | RVD; env->misa_ext_mask |= RVI | RVM | RVA | RVF | RVD; From 8633951530cc923f1e7a6cd250f670f24c0ed817 Mon Sep 17 00:00:00 2001 From: "liguang.zhang" Date: Wed, 13 Sep 2023 17:13:21 +0800 Subject: [PATCH 0555/1077] target/riscv: Clear CSR values at reset and sync MPSTATE with host This patch fixes guest reboot errors when using KVM. There are two issues when rebooting a guest using KVM 1. When the guest initiates a reboot the host is unable to stop the vcpu 2. When running a SMP guest the qemu monitor system_reset causes a vcpu crash This can be fixed by clearing the CSR values at reset and syncing the MPSTATE with the host. Signed-off-by: liguang.zhang Reviewed-by: Alistair Francis Message-ID: <20230913091332.17355-1-18622748025@163.com> [ Changes by AF - Fixup commit message - Fixup patch style ] Signed-off-by: Alistair Francis --- target/riscv/kvm.c | 44 ++++++++++++++++++++++++++++++++++++++++ target/riscv/kvm_riscv.h | 1 + 2 files changed, 45 insertions(+) diff --git a/target/riscv/kvm.c b/target/riscv/kvm.c index 14763ec0cd..1e4e4456b3 100644 --- a/target/riscv/kvm.c +++ b/target/riscv/kvm.c @@ -51,6 +51,8 @@ void riscv_kvm_aplic_request(void *opaque, int irq, int level) kvm_set_irq(kvm_state, irq, !!level); } +static bool cap_has_mp_state; + static uint64_t kvm_riscv_reg_id(CPURISCVState *env, uint64_t type, uint64_t idx) { @@ -795,6 +797,24 @@ int kvm_arch_get_registers(CPUState *cs) return ret; } +int kvm_riscv_sync_mpstate_to_kvm(RISCVCPU *cpu, int state) +{ + if (cap_has_mp_state) { + struct kvm_mp_state mp_state = { + .mp_state = state + }; + + int ret = kvm_vcpu_ioctl(CPU(cpu), KVM_SET_MP_STATE, &mp_state); + if (ret) { + fprintf(stderr, "%s: failed to sync MP_STATE %d/%s\n", + __func__, ret, strerror(-ret)); + return -1; + } + } + + return 0; +} + int kvm_arch_put_registers(CPUState *cs, int level) { int ret = 0; @@ -814,6 +834,18 @@ int kvm_arch_put_registers(CPUState *cs, int level) return ret; } + if (KVM_PUT_RESET_STATE == level) { + RISCVCPU *cpu = RISCV_CPU(cs); + if (cs->cpu_index == 0) { + ret = kvm_riscv_sync_mpstate_to_kvm(cpu, KVM_MP_STATE_RUNNABLE); + } else { + ret = kvm_riscv_sync_mpstate_to_kvm(cpu, KVM_MP_STATE_STOPPED); + } + if (ret) { + return ret; + } + } + return ret; } @@ -926,6 +958,7 @@ int kvm_arch_get_default_type(MachineState *ms) int kvm_arch_init(MachineState *ms, KVMState *s) { + cap_has_mp_state = kvm_check_extension(s, KVM_CAP_MP_STATE); return 0; } @@ -1008,14 +1041,25 @@ int kvm_arch_handle_exit(CPUState *cs, struct kvm_run *run) void kvm_riscv_reset_vcpu(RISCVCPU *cpu) { CPURISCVState *env = &cpu->env; + int i; if (!kvm_enabled()) { return; } + for (i = 0; i < 32; i++) { + env->gpr[i] = 0; + } env->pc = cpu->env.kernel_addr; env->gpr[10] = kvm_arch_vcpu_id(CPU(cpu)); /* a0 */ env->gpr[11] = cpu->env.fdt_addr; /* a1 */ env->satp = 0; + env->mie = 0; + env->stvec = 0; + env->sscratch = 0; + env->sepc = 0; + env->scause = 0; + env->stval = 0; + env->mip = 0; } void kvm_riscv_set_irq(RISCVCPU *cpu, int irq, int level) diff --git a/target/riscv/kvm_riscv.h b/target/riscv/kvm_riscv.h index 69e807fbfb..44b850a046 100644 --- a/target/riscv/kvm_riscv.h +++ b/target/riscv/kvm_riscv.h @@ -30,5 +30,6 @@ void kvm_riscv_aia_create(MachineState *machine, uint64_t group_shift, uint64_t aplic_base, uint64_t imsic_base, uint64_t guest_num); void riscv_kvm_aplic_request(void *opaque, int irq, int level); +int kvm_riscv_sync_mpstate_to_kvm(RISCVCPU *cpu, int state); #endif From cffa9954908830276c93b430681f66cc0e599aef Mon Sep 17 00:00:00 2001 From: Alvin Chang Date: Thu, 7 Sep 2023 16:45:00 +0800 Subject: [PATCH 0556/1077] disas/riscv: Fix the typo of inverted order of pmpaddr13 and pmpaddr14 Fix the inverted order of pmpaddr13 and pmpaddr14 in csr_name(). Signed-off-by: Alvin Chang Reviewed-by: Alistair Francis Message-ID: <20230907084500.328-1-alvinga@andestech.com> Signed-off-by: Alistair Francis --- disas/riscv.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/disas/riscv.c b/disas/riscv.c index 3873a69157..8e89e1d115 100644 --- a/disas/riscv.c +++ b/disas/riscv.c @@ -2116,8 +2116,8 @@ static const char *csr_name(int csrno) case 0x03ba: return "pmpaddr10"; case 0x03bb: return "pmpaddr11"; case 0x03bc: return "pmpaddr12"; - case 0x03bd: return "pmpaddr14"; - case 0x03be: return "pmpaddr13"; + case 0x03bd: return "pmpaddr13"; + case 0x03be: return "pmpaddr14"; case 0x03bf: return "pmpaddr15"; case 0x0780: return "mtohost"; case 0x0781: return "mfromhost"; From 9c5180d7998b8e211ec038e5342b305e78e06e22 Mon Sep 17 00:00:00 2001 From: Daniel Henrique Barboza Date: Mon, 25 Sep 2023 14:56:51 -0300 Subject: [PATCH 0557/1077] target/riscv: introduce TCG AccelCPUClass target/riscv/cpu.c needs to handle all possible accelerators (TCG and KVM at this moment) during both init() and realize() time. This forces us to resort to a lot of "if tcg" and "if kvm" throughout the code, which isn't wrong, but can get cluttered over time. Splitting acceleration specific code from cpu.c to its own file will help to declutter the existing code and it will also make it easier to support KVM/TCG only builds in the future. We'll start by adding a new subdir called 'tcg' and a new file called 'tcg-cpu.c'. This file will be used to introduce a new accelerator class for TCG acceleration in RISC-V, allowing us to center all TCG exclusive code in its file instead of using 'cpu.c' for everything. This design is inpired by the work Claudio Fontana did in x86 a few years ago in commit f5cc5a5c1 ("i386: split cpu accelerators from cpu.c, using AccelCPUClass"). To avoid moving too much code at once we'll start by adding the new file and TCG AccelCPUClass declaration. The 'class_init' from the accel class will init 'tcg_ops', relieving the common riscv_cpu_class_init() from doing it. 'riscv_tcg_ops' is being exported from 'cpu.c' for now to avoid having to deal with moving code and files around right now. We'll focus on decoupling the realize() logic first. Signed-off-by: Daniel Henrique Barboza Reviewed-by: Andrew Jones Reviewed-by: LIU Zhiwei Reviewed-by: Alistair Francis Message-ID: <20230925175709.35696-2-dbarboza@ventanamicro.com> Signed-off-by: Alistair Francis --- target/riscv/cpu.c | 5 +--- target/riscv/cpu.h | 4 +++ target/riscv/meson.build | 2 ++ target/riscv/tcg/meson.build | 2 ++ target/riscv/tcg/tcg-cpu.c | 58 ++++++++++++++++++++++++++++++++++++ 5 files changed, 67 insertions(+), 4 deletions(-) create mode 100644 target/riscv/tcg/meson.build create mode 100644 target/riscv/tcg/tcg-cpu.c diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c index 383e5df2a7..89ce316294 100644 --- a/target/riscv/cpu.c +++ b/target/riscv/cpu.c @@ -2284,9 +2284,7 @@ static const struct SysemuCPUOps riscv_sysemu_ops = { }; #endif -#include "hw/core/tcg-cpu-ops.h" - -static const struct TCGCPUOps riscv_tcg_ops = { +const struct TCGCPUOps riscv_tcg_ops = { .initialize = riscv_translate_init, .synchronize_from_tb = riscv_cpu_synchronize_from_tb, .restore_state_to_opc = riscv_restore_state_to_opc, @@ -2445,7 +2443,6 @@ static void riscv_cpu_class_init(ObjectClass *c, void *data) #endif cc->gdb_arch_name = riscv_gdb_arch_name; cc->gdb_get_dynamic_xml = riscv_gdb_get_dynamic_xml; - cc->tcg_ops = &riscv_tcg_ops; object_class_property_add(c, "mvendorid", "uint32", cpu_get_mvendorid, cpu_set_mvendorid, NULL, NULL); diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h index cce6dee729..1bd736a1a0 100644 --- a/target/riscv/cpu.h +++ b/target/riscv/cpu.h @@ -707,6 +707,10 @@ enum riscv_pmu_event_idx { RISCV_PMU_EVENT_CACHE_ITLB_PREFETCH_MISS = 0x10021, }; +/* Export tcg_ops until we move everything to tcg/tcg-cpu.c */ +#include "hw/core/tcg-cpu-ops.h" +extern const struct TCGCPUOps riscv_tcg_ops; + /* CSR function table */ extern riscv_csr_operations csr_ops[CSR_TABLE_SIZE]; diff --git a/target/riscv/meson.build b/target/riscv/meson.build index ff60b21d04..b4ded65e41 100644 --- a/target/riscv/meson.build +++ b/target/riscv/meson.build @@ -38,5 +38,7 @@ riscv_system_ss.add(files( 'riscv-qmp-cmds.c', )) +subdir('tcg') + target_arch += {'riscv': riscv_ss} target_system_arch += {'riscv': riscv_system_ss} diff --git a/target/riscv/tcg/meson.build b/target/riscv/tcg/meson.build new file mode 100644 index 0000000000..061df3d74a --- /dev/null +++ b/target/riscv/tcg/meson.build @@ -0,0 +1,2 @@ +riscv_ss.add(when: 'CONFIG_TCG', if_true: files( + 'tcg-cpu.c')) diff --git a/target/riscv/tcg/tcg-cpu.c b/target/riscv/tcg/tcg-cpu.c new file mode 100644 index 0000000000..795a8f06b2 --- /dev/null +++ b/target/riscv/tcg/tcg-cpu.c @@ -0,0 +1,58 @@ +/* + * riscv TCG cpu class initialization + * + * Copyright (c) 2016-2017 Sagar Karandikar, sagark@eecs.berkeley.edu + * Copyright (c) 2017-2018 SiFive, Inc. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2 or later, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program. If not, see . + */ + +#include "qemu/osdep.h" +#include "cpu.h" +#include "qemu/accel.h" +#include "hw/core/accel-cpu.h" + +static void tcg_cpu_init_ops(AccelCPUClass *accel_cpu, CPUClass *cc) +{ + /* + * All cpus use the same set of operations. + * riscv_tcg_ops is being imported from cpu.c for now. + */ + cc->tcg_ops = &riscv_tcg_ops; +} + +static void tcg_cpu_class_init(CPUClass *cc) +{ + cc->init_accel_cpu = tcg_cpu_init_ops; +} + +static void tcg_cpu_accel_class_init(ObjectClass *oc, void *data) +{ + AccelCPUClass *acc = ACCEL_CPU_CLASS(oc); + + acc->cpu_class_init = tcg_cpu_class_init; +} + +static const TypeInfo tcg_cpu_accel_type_info = { + .name = ACCEL_CPU_NAME("tcg"), + + .parent = TYPE_ACCEL_CPU, + .class_init = tcg_cpu_accel_class_init, + .abstract = true, +}; + +static void tcg_cpu_accel_register_types(void) +{ + type_register_static(&tcg_cpu_accel_type_info); +} +type_init(tcg_cpu_accel_register_types); From 9dcecbd724ebadd8c957356e629aab9d724e9889 Mon Sep 17 00:00:00 2001 From: Daniel Henrique Barboza Date: Mon, 25 Sep 2023 14:56:52 -0300 Subject: [PATCH 0558/1077] target/riscv: move riscv_cpu_realize_tcg() to TCG::cpu_realizefn() riscv_cpu_realize_tcg() was added to allow TCG cpus to have a different realize() path during the common riscv_cpu_realize(), making it a good choice to start moving TCG exclusive code to tcg-cpu.c. Rename it to tcg_cpu_realizefn() and assign it as a implementation of accel::cpu_realizefn(). tcg_cpu_realizefn() will then be called during riscv_cpu_realize() via cpu_exec_realizefn(). We'll use a similar approach with KVM in the near future. riscv_cpu_validate_set_extensions() is too big and with too many dependencies to be moved in this same patch. We'll do that next. Signed-off-by: Daniel Henrique Barboza Reviewed-by: Andrew Jones Reviewed-by: LIU Zhiwei Message-ID: <20230925175709.35696-3-dbarboza@ventanamicro.com> [ Changes by AF: - Renames to fix build failures after rebase ] Signed-off-by: Alistair Francis --- target/riscv/cpu.c | 128 ----------------------------------- target/riscv/tcg/tcg-cpu.c | 133 +++++++++++++++++++++++++++++++++++++ 2 files changed, 133 insertions(+), 128 deletions(-) diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c index 89ce316294..11f57c1f32 100644 --- a/target/riscv/cpu.c +++ b/target/riscv/cpu.c @@ -23,9 +23,7 @@ #include "qemu/log.h" #include "cpu.h" #include "cpu_vendorid.h" -#include "pmu.h" #include "internals.h" -#include "time_helper.h" #include "exec/exec-all.h" #include "qapi/error.h" #include "qapi/visitor.h" @@ -1064,29 +1062,6 @@ static void riscv_cpu_validate_v(CPURISCVState *env, RISCVCPUConfig *cfg, } } -static void riscv_cpu_validate_priv_spec(RISCVCPU *cpu, Error **errp) -{ - CPURISCVState *env = &cpu->env; - int priv_version = -1; - - if (cpu->cfg.priv_spec) { - if (!g_strcmp0(cpu->cfg.priv_spec, "v1.12.0")) { - priv_version = PRIV_VERSION_1_12_0; - } else if (!g_strcmp0(cpu->cfg.priv_spec, "v1.11.0")) { - priv_version = PRIV_VERSION_1_11_0; - } else if (!g_strcmp0(cpu->cfg.priv_spec, "v1.10.0")) { - priv_version = PRIV_VERSION_1_10_0; - } else { - error_setg(errp, - "Unsupported privilege spec version '%s'", - cpu->cfg.priv_spec); - return; - } - - env->priv_ver = priv_version; - } -} - static void riscv_cpu_disable_priv_spec_isa_exts(RISCVCPU *cpu) { CPURISCVState *env = &cpu->env; @@ -1111,33 +1086,6 @@ static void riscv_cpu_disable_priv_spec_isa_exts(RISCVCPU *cpu) } } -static void riscv_cpu_validate_misa_mxl(RISCVCPU *cpu, Error **errp) -{ - RISCVCPUClass *mcc = RISCV_CPU_GET_CLASS(cpu); - CPUClass *cc = CPU_CLASS(mcc); - CPURISCVState *env = &cpu->env; - - /* Validate that MISA_MXL is set properly. */ - switch (env->misa_mxl_max) { -#ifdef TARGET_RISCV64 - case MXL_RV64: - case MXL_RV128: - cc->gdb_core_xml_file = "riscv-64bit-cpu.xml"; - break; -#endif - case MXL_RV32: - cc->gdb_core_xml_file = "riscv-32bit-cpu.xml"; - break; - default: - g_assert_not_reached(); - } - - if (env->misa_mxl_max != env->misa_mxl) { - error_setg(errp, "misa_mxl_max must be equal to misa_mxl"); - return; - } -} - /* * Check consistency between chosen extensions while setting * cpu->cfg accordingly. @@ -1511,74 +1459,6 @@ static void riscv_cpu_finalize_features(RISCVCPU *cpu, Error **errp) #endif } -static void riscv_cpu_validate_misa_priv(CPURISCVState *env, Error **errp) -{ - if (riscv_has_ext(env, RVH) && env->priv_ver < PRIV_VERSION_1_12_0) { - error_setg(errp, "H extension requires priv spec 1.12.0"); - return; - } -} - -static void riscv_cpu_realize_tcg(DeviceState *dev, Error **errp) -{ - RISCVCPU *cpu = RISCV_CPU(dev); - CPURISCVState *env = &cpu->env; - Error *local_err = NULL; - - if (object_dynamic_cast(OBJECT(dev), TYPE_RISCV_CPU_HOST)) { - error_setg(errp, "'host' CPU is not compatible with TCG acceleration"); - return; - } - - riscv_cpu_validate_misa_mxl(cpu, &local_err); - if (local_err != NULL) { - error_propagate(errp, local_err); - return; - } - - riscv_cpu_validate_priv_spec(cpu, &local_err); - if (local_err != NULL) { - error_propagate(errp, local_err); - return; - } - - riscv_cpu_validate_misa_priv(env, &local_err); - if (local_err != NULL) { - error_propagate(errp, local_err); - return; - } - - if (cpu->cfg.epmp && !cpu->cfg.pmp) { - /* - * Enhanced PMP should only be available - * on harts with PMP support - */ - error_setg(errp, "Invalid configuration: EPMP requires PMP support"); - return; - } - - riscv_cpu_validate_set_extensions(cpu, &local_err); - if (local_err != NULL) { - error_propagate(errp, local_err); - return; - } - -#ifndef CONFIG_USER_ONLY - CPU(dev)->tcg_cflags |= CF_PCREL; - - if (cpu->cfg.ext_sstc) { - riscv_timer_init(cpu); - } - - if (cpu->cfg.pmu_num) { - if (!riscv_pmu_init(cpu, cpu->cfg.pmu_num) && cpu->cfg.ext_sscofpmf) { - cpu->pmu_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, - riscv_pmu_timer_cb, cpu); - } - } -#endif -} - static void riscv_cpu_realize(DeviceState *dev, Error **errp) { CPUState *cs = CPU(dev); @@ -1597,14 +1477,6 @@ static void riscv_cpu_realize(DeviceState *dev, Error **errp) return; } - if (tcg_enabled()) { - riscv_cpu_realize_tcg(dev, &local_err); - if (local_err != NULL) { - error_propagate(errp, local_err); - return; - } - } - riscv_cpu_finalize_features(cpu, &local_err); if (local_err != NULL) { error_propagate(errp, local_err); diff --git a/target/riscv/tcg/tcg-cpu.c b/target/riscv/tcg/tcg-cpu.c index 795a8f06b2..fe7e03594d 100644 --- a/target/riscv/tcg/tcg-cpu.c +++ b/target/riscv/tcg/tcg-cpu.c @@ -18,10 +18,142 @@ */ #include "qemu/osdep.h" +#include "exec/exec-all.h" #include "cpu.h" +#include "pmu.h" +#include "time_helper.h" +#include "qapi/error.h" #include "qemu/accel.h" #include "hw/core/accel-cpu.h" + +static void riscv_cpu_validate_misa_priv(CPURISCVState *env, Error **errp) +{ + if (riscv_has_ext(env, RVH) && env->priv_ver < PRIV_VERSION_1_12_0) { + error_setg(errp, "H extension requires priv spec 1.12.0"); + return; + } +} + +static void riscv_cpu_validate_misa_mxl(RISCVCPU *cpu, Error **errp) +{ + RISCVCPUClass *mcc = RISCV_CPU_GET_CLASS(cpu); + CPUClass *cc = CPU_CLASS(mcc); + CPURISCVState *env = &cpu->env; + + /* Validate that MISA_MXL is set properly. */ + switch (env->misa_mxl_max) { +#ifdef TARGET_RISCV64 + case MXL_RV64: + case MXL_RV128: + cc->gdb_core_xml_file = "riscv-64bit-cpu.xml"; + break; +#endif + case MXL_RV32: + cc->gdb_core_xml_file = "riscv-32bit-cpu.xml"; + break; + default: + g_assert_not_reached(); + } + + if (env->misa_mxl_max != env->misa_mxl) { + error_setg(errp, "misa_mxl_max must be equal to misa_mxl"); + return; + } +} + +static void riscv_cpu_validate_priv_spec(RISCVCPU *cpu, Error **errp) +{ + CPURISCVState *env = &cpu->env; + int priv_version = -1; + + if (cpu->cfg.priv_spec) { + if (!g_strcmp0(cpu->cfg.priv_spec, "v1.12.0")) { + priv_version = PRIV_VERSION_1_12_0; + } else if (!g_strcmp0(cpu->cfg.priv_spec, "v1.11.0")) { + priv_version = PRIV_VERSION_1_11_0; + } else if (!g_strcmp0(cpu->cfg.priv_spec, "v1.10.0")) { + priv_version = PRIV_VERSION_1_10_0; + } else { + error_setg(errp, + "Unsupported privilege spec version '%s'", + cpu->cfg.priv_spec); + return; + } + + env->priv_ver = priv_version; + } +} + +/* + * We'll get here via the following path: + * + * riscv_cpu_realize() + * -> cpu_exec_realizefn() + * -> tcg_cpu_realize() (via accel_cpu_common_realize()) + */ +static bool tcg_cpu_realize(CPUState *cs, Error **errp) +{ + RISCVCPU *cpu = RISCV_CPU(cs); + CPURISCVState *env = &cpu->env; + Error *local_err = NULL; + + if (object_dynamic_cast(OBJECT(cpu), TYPE_RISCV_CPU_HOST)) { + error_setg(errp, "'host' CPU is not compatible with TCG acceleration"); + return false; + } + + riscv_cpu_validate_misa_mxl(cpu, &local_err); + if (local_err != NULL) { + error_propagate(errp, local_err); + return false; + } + + riscv_cpu_validate_priv_spec(cpu, &local_err); + if (local_err != NULL) { + error_propagate(errp, local_err); + return false; + } + + riscv_cpu_validate_misa_priv(env, &local_err); + if (local_err != NULL) { + error_propagate(errp, local_err); + return false; + } + + if (cpu->cfg.epmp && !cpu->cfg.pmp) { + /* + * Enhanced PMP should only be available + * on harts with PMP support + */ + error_setg(errp, "Invalid configuration: EPMP requires PMP support"); + return false; + } + + riscv_cpu_validate_set_extensions(cpu, &local_err); + if (local_err != NULL) { + error_propagate(errp, local_err); + return false; + } + +#ifndef CONFIG_USER_ONLY + CPU(cs)->tcg_cflags |= CF_PCREL; + + if (cpu->cfg.ext_sstc) { + riscv_timer_init(cpu); + } + + if (cpu->cfg.pmu_num) { + if (!riscv_pmu_init(cpu, cpu->cfg.pmu_num) && cpu->cfg.ext_sscofpmf) { + cpu->pmu_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, + riscv_pmu_timer_cb, cpu); + } + } +#endif + + return true; +} + static void tcg_cpu_init_ops(AccelCPUClass *accel_cpu, CPUClass *cc) { /* @@ -41,6 +173,7 @@ static void tcg_cpu_accel_class_init(ObjectClass *oc, void *data) AccelCPUClass *acc = ACCEL_CPU_CLASS(oc); acc->cpu_class_init = tcg_cpu_class_init; + acc->cpu_target_realize = tcg_cpu_realize; } static const TypeInfo tcg_cpu_accel_type_info = { From 36c1118d500b95d26d1f07deb93402f9d596cabf Mon Sep 17 00:00:00 2001 From: Daniel Henrique Barboza Date: Mon, 25 Sep 2023 14:56:53 -0300 Subject: [PATCH 0559/1077] target/riscv: move riscv_cpu_validate_set_extensions() to tcg-cpu.c This function is the core of the RISC-V validations for TCG CPUs, and it has a lot going on. Functions in cpu.c were made public to allow them to be used by the KVM accelerator class later on. 'cpu_cfg_ext_get_min_version()' is notably hard to move it to another file due to its dependency with isa_edata_arr[] array, thus make it public and use it as is for now. riscv_cpu_validate_set_extensions() is kept public because it's used by csr.c in write_misa(). Signed-off-by: Daniel Henrique Barboza Reviewed-by: Andrew Jones Reviewed-by: LIU Zhiwei Reviewed-by: Alistair Francis Message-ID: <20230925175709.35696-4-dbarboza@ventanamicro.com> Signed-off-by: Alistair Francis --- target/riscv/cpu.c | 361 +------------------------------------ target/riscv/cpu.h | 8 +- target/riscv/csr.c | 1 + target/riscv/tcg/tcg-cpu.c | 357 ++++++++++++++++++++++++++++++++++++ target/riscv/tcg/tcg-cpu.h | 27 +++ 5 files changed, 397 insertions(+), 357 deletions(-) create mode 100644 target/riscv/tcg/tcg-cpu.h diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c index 11f57c1f32..943aca2c20 100644 --- a/target/riscv/cpu.c +++ b/target/riscv/cpu.c @@ -163,22 +163,21 @@ static const struct isa_ext_data isa_edata_arr[] = { /* Hash that stores user set extensions */ static GHashTable *multi_ext_user_opts; -static bool isa_ext_is_enabled(RISCVCPU *cpu, uint32_t ext_offset) +bool isa_ext_is_enabled(RISCVCPU *cpu, uint32_t ext_offset) { bool *ext_enabled = (void *)&cpu->cfg + ext_offset; return *ext_enabled; } -static void isa_ext_update_enabled(RISCVCPU *cpu, uint32_t ext_offset, - bool en) +void isa_ext_update_enabled(RISCVCPU *cpu, uint32_t ext_offset, bool en) { bool *ext_enabled = (void *)&cpu->cfg + ext_offset; *ext_enabled = en; } -static int cpu_cfg_ext_get_min_version(uint32_t ext_offset) +int cpu_cfg_ext_get_min_version(uint32_t ext_offset) { int i; @@ -193,38 +192,12 @@ static int cpu_cfg_ext_get_min_version(uint32_t ext_offset) g_assert_not_reached(); } -static bool cpu_cfg_ext_is_user_set(uint32_t ext_offset) +bool cpu_cfg_ext_is_user_set(uint32_t ext_offset) { return g_hash_table_contains(multi_ext_user_opts, GUINT_TO_POINTER(ext_offset)); } -static void cpu_cfg_ext_auto_update(RISCVCPU *cpu, uint32_t ext_offset, - bool value) -{ - CPURISCVState *env = &cpu->env; - bool prev_val = isa_ext_is_enabled(cpu, ext_offset); - int min_version; - - if (prev_val == value) { - return; - } - - if (cpu_cfg_ext_is_user_set(ext_offset)) { - return; - } - - if (value && env->priv_ver != PRIV_VERSION_LATEST) { - /* Do not enable it if priv_ver is older than min_version */ - min_version = cpu_cfg_ext_get_min_version(ext_offset); - if (env->priv_ver < min_version) { - return; - } - } - - isa_ext_update_enabled(cpu, ext_offset, value); -} - const char * const riscv_int_regnames[] = { "x0/zero", "x1/ra", "x2/sp", "x3/gp", "x4/tp", "x5/t0", "x6/t1", "x7/t2", "x8/s0", "x9/s1", "x10/a0", "x11/a1", "x12/a2", "x13/a3", @@ -1023,46 +996,7 @@ static void riscv_cpu_disas_set_info(CPUState *s, disassemble_info *info) } } -static void riscv_cpu_validate_v(CPURISCVState *env, RISCVCPUConfig *cfg, - Error **errp) -{ - if (!is_power_of_2(cfg->vlen)) { - error_setg(errp, "Vector extension VLEN must be power of 2"); - return; - } - if (cfg->vlen > RV_VLEN_MAX || cfg->vlen < 128) { - error_setg(errp, - "Vector extension implementation only supports VLEN " - "in the range [128, %d]", RV_VLEN_MAX); - return; - } - if (!is_power_of_2(cfg->elen)) { - error_setg(errp, "Vector extension ELEN must be power of 2"); - return; - } - if (cfg->elen > 64 || cfg->elen < 8) { - error_setg(errp, - "Vector extension implementation only supports ELEN " - "in the range [8, 64]"); - return; - } - if (cfg->vext_spec) { - if (!g_strcmp0(cfg->vext_spec, "v1.0")) { - env->vext_ver = VEXT_VERSION_1_00_0; - } else { - error_setg(errp, "Unsupported vector spec version '%s'", - cfg->vext_spec); - return; - } - } else if (env->vext_ver == 0) { - qemu_log("vector version is not specified, " - "use the default value v1.0\n"); - - env->vext_ver = VEXT_VERSION_1_00_0; - } -} - -static void riscv_cpu_disable_priv_spec_isa_exts(RISCVCPU *cpu) +void riscv_cpu_disable_priv_spec_isa_exts(RISCVCPU *cpu) { CPURISCVState *env = &cpu->env; int i; @@ -1086,291 +1020,6 @@ static void riscv_cpu_disable_priv_spec_isa_exts(RISCVCPU *cpu) } } -/* - * Check consistency between chosen extensions while setting - * cpu->cfg accordingly. - */ -void riscv_cpu_validate_set_extensions(RISCVCPU *cpu, Error **errp) -{ - CPURISCVState *env = &cpu->env; - Error *local_err = NULL; - - /* Do some ISA extension error checking */ - if (riscv_has_ext(env, RVG) && - !(riscv_has_ext(env, RVI) && riscv_has_ext(env, RVM) && - riscv_has_ext(env, RVA) && riscv_has_ext(env, RVF) && - riscv_has_ext(env, RVD) && - cpu->cfg.ext_icsr && cpu->cfg.ext_ifencei)) { - - if (cpu_cfg_ext_is_user_set(CPU_CFG_OFFSET(ext_icsr)) && - !cpu->cfg.ext_icsr) { - error_setg(errp, "RVG requires Zicsr but user set Zicsr to false"); - return; - } - - if (cpu_cfg_ext_is_user_set(CPU_CFG_OFFSET(ext_ifencei)) && - !cpu->cfg.ext_ifencei) { - error_setg(errp, "RVG requires Zifencei but user set " - "Zifencei to false"); - return; - } - - warn_report("Setting G will also set IMAFD_Zicsr_Zifencei"); - cpu_cfg_ext_auto_update(cpu, CPU_CFG_OFFSET(ext_icsr), true); - cpu_cfg_ext_auto_update(cpu, CPU_CFG_OFFSET(ext_ifencei), true); - - env->misa_ext |= RVI | RVM | RVA | RVF | RVD; - env->misa_ext_mask |= RVI | RVM | RVA | RVF | RVD; - } - - if (riscv_has_ext(env, RVI) && riscv_has_ext(env, RVE)) { - error_setg(errp, - "I and E extensions are incompatible"); - return; - } - - if (!riscv_has_ext(env, RVI) && !riscv_has_ext(env, RVE)) { - error_setg(errp, - "Either I or E extension must be set"); - return; - } - - if (riscv_has_ext(env, RVS) && !riscv_has_ext(env, RVU)) { - error_setg(errp, - "Setting S extension without U extension is illegal"); - return; - } - - if (riscv_has_ext(env, RVH) && !riscv_has_ext(env, RVI)) { - error_setg(errp, - "H depends on an I base integer ISA with 32 x registers"); - return; - } - - if (riscv_has_ext(env, RVH) && !riscv_has_ext(env, RVS)) { - error_setg(errp, "H extension implicitly requires S-mode"); - return; - } - - if (riscv_has_ext(env, RVF) && !cpu->cfg.ext_icsr) { - error_setg(errp, "F extension requires Zicsr"); - return; - } - - if ((cpu->cfg.ext_zawrs) && !riscv_has_ext(env, RVA)) { - error_setg(errp, "Zawrs extension requires A extension"); - return; - } - - if (cpu->cfg.ext_zfa && !riscv_has_ext(env, RVF)) { - error_setg(errp, "Zfa extension requires F extension"); - return; - } - - if (cpu->cfg.ext_zfh) { - cpu_cfg_ext_auto_update(cpu, CPU_CFG_OFFSET(ext_zfhmin), true); - } - - if (cpu->cfg.ext_zfhmin && !riscv_has_ext(env, RVF)) { - error_setg(errp, "Zfh/Zfhmin extensions require F extension"); - return; - } - - if (cpu->cfg.ext_zfbfmin && !riscv_has_ext(env, RVF)) { - error_setg(errp, "Zfbfmin extension depends on F extension"); - return; - } - - if (riscv_has_ext(env, RVD) && !riscv_has_ext(env, RVF)) { - error_setg(errp, "D extension requires F extension"); - return; - } - - if (riscv_has_ext(env, RVV)) { - riscv_cpu_validate_v(env, &cpu->cfg, &local_err); - if (local_err != NULL) { - error_propagate(errp, local_err); - return; - } - - /* The V vector extension depends on the Zve64d extension */ - cpu_cfg_ext_auto_update(cpu, CPU_CFG_OFFSET(ext_zve64d), true); - } - - /* The Zve64d extension depends on the Zve64f extension */ - if (cpu->cfg.ext_zve64d) { - cpu_cfg_ext_auto_update(cpu, CPU_CFG_OFFSET(ext_zve64f), true); - } - - /* The Zve64f extension depends on the Zve32f extension */ - if (cpu->cfg.ext_zve64f) { - cpu_cfg_ext_auto_update(cpu, CPU_CFG_OFFSET(ext_zve32f), true); - } - - if (cpu->cfg.ext_zve64d && !riscv_has_ext(env, RVD)) { - error_setg(errp, "Zve64d/V extensions require D extension"); - return; - } - - if (cpu->cfg.ext_zve32f && !riscv_has_ext(env, RVF)) { - error_setg(errp, "Zve32f/Zve64f extensions require F extension"); - return; - } - - if (cpu->cfg.ext_zvfh) { - cpu_cfg_ext_auto_update(cpu, CPU_CFG_OFFSET(ext_zvfhmin), true); - } - - if (cpu->cfg.ext_zvfhmin && !cpu->cfg.ext_zve32f) { - error_setg(errp, "Zvfh/Zvfhmin extensions require Zve32f extension"); - return; - } - - if (cpu->cfg.ext_zvfh && !cpu->cfg.ext_zfhmin) { - error_setg(errp, "Zvfh extensions requires Zfhmin extension"); - return; - } - - if (cpu->cfg.ext_zvfbfmin && !cpu->cfg.ext_zfbfmin) { - error_setg(errp, "Zvfbfmin extension depends on Zfbfmin extension"); - return; - } - - if (cpu->cfg.ext_zvfbfmin && !cpu->cfg.ext_zve32f) { - error_setg(errp, "Zvfbfmin extension depends on Zve32f extension"); - return; - } - - if (cpu->cfg.ext_zvfbfwma && !cpu->cfg.ext_zvfbfmin) { - error_setg(errp, "Zvfbfwma extension depends on Zvfbfmin extension"); - return; - } - - /* Set the ISA extensions, checks should have happened above */ - if (cpu->cfg.ext_zhinx) { - cpu_cfg_ext_auto_update(cpu, CPU_CFG_OFFSET(ext_zca), true); - } - - if ((cpu->cfg.ext_zdinx || cpu->cfg.ext_zhinxmin) && !cpu->cfg.ext_zfinx) { - error_setg(errp, "Zdinx/Zhinx/Zhinxmin extensions require Zfinx"); - return; - } - - if (cpu->cfg.ext_zfinx) { - if (!cpu->cfg.ext_icsr) { - error_setg(errp, "Zfinx extension requires Zicsr"); - return; - } - if (riscv_has_ext(env, RVF)) { - error_setg(errp, - "Zfinx cannot be supported together with F extension"); - return; - } - } - - if (cpu->cfg.ext_zce) { - cpu_cfg_ext_auto_update(cpu, CPU_CFG_OFFSET(ext_zca), true); - cpu_cfg_ext_auto_update(cpu, CPU_CFG_OFFSET(ext_zcb), true); - cpu_cfg_ext_auto_update(cpu, CPU_CFG_OFFSET(ext_zcmp), true); - cpu_cfg_ext_auto_update(cpu, CPU_CFG_OFFSET(ext_zcmt), true); - if (riscv_has_ext(env, RVF) && env->misa_mxl_max == MXL_RV32) { - cpu_cfg_ext_auto_update(cpu, CPU_CFG_OFFSET(ext_zcf), true); - } - } - - /* zca, zcd and zcf has a PRIV 1.12.0 restriction */ - if (riscv_has_ext(env, RVC) && env->priv_ver >= PRIV_VERSION_1_12_0) { - cpu_cfg_ext_auto_update(cpu, CPU_CFG_OFFSET(ext_zca), true); - if (riscv_has_ext(env, RVF) && env->misa_mxl_max == MXL_RV32) { - cpu_cfg_ext_auto_update(cpu, CPU_CFG_OFFSET(ext_zcf), true); - } - if (riscv_has_ext(env, RVD)) { - cpu_cfg_ext_auto_update(cpu, CPU_CFG_OFFSET(ext_zcd), true); - } - } - - if (env->misa_mxl_max != MXL_RV32 && cpu->cfg.ext_zcf) { - error_setg(errp, "Zcf extension is only relevant to RV32"); - return; - } - - if (!riscv_has_ext(env, RVF) && cpu->cfg.ext_zcf) { - error_setg(errp, "Zcf extension requires F extension"); - return; - } - - if (!riscv_has_ext(env, RVD) && cpu->cfg.ext_zcd) { - error_setg(errp, "Zcd extension requires D extension"); - return; - } - - if ((cpu->cfg.ext_zcf || cpu->cfg.ext_zcd || cpu->cfg.ext_zcb || - cpu->cfg.ext_zcmp || cpu->cfg.ext_zcmt) && !cpu->cfg.ext_zca) { - error_setg(errp, "Zcf/Zcd/Zcb/Zcmp/Zcmt extensions require Zca " - "extension"); - return; - } - - if (cpu->cfg.ext_zcd && (cpu->cfg.ext_zcmp || cpu->cfg.ext_zcmt)) { - error_setg(errp, "Zcmp/Zcmt extensions are incompatible with " - "Zcd extension"); - return; - } - - if (cpu->cfg.ext_zcmt && !cpu->cfg.ext_icsr) { - error_setg(errp, "Zcmt extension requires Zicsr extension"); - return; - } - - /* - * In principle Zve*x would also suffice here, were they supported - * in qemu - */ - if ((cpu->cfg.ext_zvbb || cpu->cfg.ext_zvkg || cpu->cfg.ext_zvkned || - cpu->cfg.ext_zvknha || cpu->cfg.ext_zvksed || cpu->cfg.ext_zvksh) && - !cpu->cfg.ext_zve32f) { - error_setg(errp, - "Vector crypto extensions require V or Zve* extensions"); - return; - } - - if ((cpu->cfg.ext_zvbc || cpu->cfg.ext_zvknhb) && !cpu->cfg.ext_zve64f) { - error_setg( - errp, - "Zvbc and Zvknhb extensions require V or Zve64{f,d} extensions"); - return; - } - - if (cpu->cfg.ext_zk) { - cpu_cfg_ext_auto_update(cpu, CPU_CFG_OFFSET(ext_zkn), true); - cpu_cfg_ext_auto_update(cpu, CPU_CFG_OFFSET(ext_zkr), true); - cpu_cfg_ext_auto_update(cpu, CPU_CFG_OFFSET(ext_zkt), true); - } - - if (cpu->cfg.ext_zkn) { - cpu_cfg_ext_auto_update(cpu, CPU_CFG_OFFSET(ext_zbkb), true); - cpu_cfg_ext_auto_update(cpu, CPU_CFG_OFFSET(ext_zbkc), true); - cpu_cfg_ext_auto_update(cpu, CPU_CFG_OFFSET(ext_zbkx), true); - cpu_cfg_ext_auto_update(cpu, CPU_CFG_OFFSET(ext_zkne), true); - cpu_cfg_ext_auto_update(cpu, CPU_CFG_OFFSET(ext_zknd), true); - cpu_cfg_ext_auto_update(cpu, CPU_CFG_OFFSET(ext_zknh), true); - } - - if (cpu->cfg.ext_zks) { - cpu_cfg_ext_auto_update(cpu, CPU_CFG_OFFSET(ext_zbkb), true); - cpu_cfg_ext_auto_update(cpu, CPU_CFG_OFFSET(ext_zbkc), true); - cpu_cfg_ext_auto_update(cpu, CPU_CFG_OFFSET(ext_zbkx), true); - cpu_cfg_ext_auto_update(cpu, CPU_CFG_OFFSET(ext_zksed), true); - cpu_cfg_ext_auto_update(cpu, CPU_CFG_OFFSET(ext_zksh), true); - } - - /* - * Disable isa extensions based on priv spec after we - * validated and set everything we need. - */ - riscv_cpu_disable_priv_spec_isa_exts(cpu); -} - #ifndef CONFIG_USER_ONLY static void riscv_cpu_satp_mode_finalize(RISCVCPU *cpu, Error **errp) { diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h index 1bd736a1a0..e1e47d7509 100644 --- a/target/riscv/cpu.h +++ b/target/riscv/cpu.h @@ -445,7 +445,6 @@ bool riscv_cpu_tlb_fill(CPUState *cs, vaddr address, int size, bool probe, uintptr_t retaddr); char *riscv_isa_string(RISCVCPU *cpu); void riscv_cpu_list(void); -void riscv_cpu_validate_set_extensions(RISCVCPU *cpu, Error **errp); #define cpu_list riscv_cpu_list #define cpu_mmu_index riscv_cpu_mmu_index @@ -711,6 +710,13 @@ enum riscv_pmu_event_idx { #include "hw/core/tcg-cpu-ops.h" extern const struct TCGCPUOps riscv_tcg_ops; +/* used by tcg/tcg-cpu.c*/ +void isa_ext_update_enabled(RISCVCPU *cpu, uint32_t ext_offset, bool en); +bool cpu_cfg_ext_is_user_set(uint32_t ext_offset); +bool isa_ext_is_enabled(RISCVCPU *cpu, uint32_t ext_offset); +int cpu_cfg_ext_get_min_version(uint32_t ext_offset); +void riscv_cpu_disable_priv_spec_isa_exts(RISCVCPU *cpu); + /* CSR function table */ extern riscv_csr_operations csr_ops[CSR_TABLE_SIZE]; diff --git a/target/riscv/csr.c b/target/riscv/csr.c index 85a31dc420..4b4ab56c40 100644 --- a/target/riscv/csr.c +++ b/target/riscv/csr.c @@ -21,6 +21,7 @@ #include "qemu/log.h" #include "qemu/timer.h" #include "cpu.h" +#include "tcg/tcg-cpu.h" #include "pmu.h" #include "time_helper.h" #include "exec/exec-all.h" diff --git a/target/riscv/tcg/tcg-cpu.c b/target/riscv/tcg/tcg-cpu.c index fe7e03594d..0ea691fbba 100644 --- a/target/riscv/tcg/tcg-cpu.c +++ b/target/riscv/tcg/tcg-cpu.c @@ -19,14 +19,43 @@ #include "qemu/osdep.h" #include "exec/exec-all.h" +#include "tcg-cpu.h" #include "cpu.h" #include "pmu.h" #include "time_helper.h" #include "qapi/error.h" #include "qemu/accel.h" +#include "qemu/error-report.h" +#include "qemu/log.h" #include "hw/core/accel-cpu.h" +static void cpu_cfg_ext_auto_update(RISCVCPU *cpu, uint32_t ext_offset, + bool value) +{ + CPURISCVState *env = &cpu->env; + bool prev_val = isa_ext_is_enabled(cpu, ext_offset); + int min_version; + + if (prev_val == value) { + return; + } + + if (cpu_cfg_ext_is_user_set(ext_offset)) { + return; + } + + if (value && env->priv_ver != PRIV_VERSION_LATEST) { + /* Do not enable it if priv_ver is older than min_version */ + min_version = cpu_cfg_ext_get_min_version(ext_offset); + if (env->priv_ver < min_version) { + return; + } + } + + isa_ext_update_enabled(cpu, ext_offset, value); +} + static void riscv_cpu_validate_misa_priv(CPURISCVState *env, Error **errp) { if (riscv_has_ext(env, RVH) && env->priv_ver < PRIV_VERSION_1_12_0) { @@ -85,6 +114,334 @@ static void riscv_cpu_validate_priv_spec(RISCVCPU *cpu, Error **errp) } } +static void riscv_cpu_validate_v(CPURISCVState *env, RISCVCPUConfig *cfg, + Error **errp) +{ + if (!is_power_of_2(cfg->vlen)) { + error_setg(errp, "Vector extension VLEN must be power of 2"); + return; + } + + if (cfg->vlen > RV_VLEN_MAX || cfg->vlen < 128) { + error_setg(errp, + "Vector extension implementation only supports VLEN " + "in the range [128, %d]", RV_VLEN_MAX); + return; + } + + if (!is_power_of_2(cfg->elen)) { + error_setg(errp, "Vector extension ELEN must be power of 2"); + return; + } + + if (cfg->elen > 64 || cfg->elen < 8) { + error_setg(errp, + "Vector extension implementation only supports ELEN " + "in the range [8, 64]"); + return; + } + + if (cfg->vext_spec) { + if (!g_strcmp0(cfg->vext_spec, "v1.0")) { + env->vext_ver = VEXT_VERSION_1_00_0; + } else { + error_setg(errp, "Unsupported vector spec version '%s'", + cfg->vext_spec); + return; + } + } else if (env->vext_ver == 0) { + qemu_log("vector version is not specified, " + "use the default value v1.0\n"); + + env->vext_ver = VEXT_VERSION_1_00_0; + } +} + +/* + * Check consistency between chosen extensions while setting + * cpu->cfg accordingly. + */ +void riscv_cpu_validate_set_extensions(RISCVCPU *cpu, Error **errp) +{ + CPURISCVState *env = &cpu->env; + Error *local_err = NULL; + + /* Do some ISA extension error checking */ + if (riscv_has_ext(env, RVG) && + !(riscv_has_ext(env, RVI) && riscv_has_ext(env, RVM) && + riscv_has_ext(env, RVA) && riscv_has_ext(env, RVF) && + riscv_has_ext(env, RVD) && + cpu->cfg.ext_icsr && cpu->cfg.ext_ifencei)) { + + if (cpu_cfg_ext_is_user_set(CPU_CFG_OFFSET(ext_icsr)) && + !cpu->cfg.ext_icsr) { + error_setg(errp, "RVG requires Zicsr but user set Zicsr to false"); + return; + } + + if (cpu_cfg_ext_is_user_set(CPU_CFG_OFFSET(ext_ifencei)) && + !cpu->cfg.ext_ifencei) { + error_setg(errp, "RVG requires Zifencei but user set " + "Zifencei to false"); + return; + } + + warn_report("Setting G will also set IMAFD_Zicsr_Zifencei"); + cpu_cfg_ext_auto_update(cpu, CPU_CFG_OFFSET(ext_icsr), true); + cpu_cfg_ext_auto_update(cpu, CPU_CFG_OFFSET(ext_ifencei), true); + + env->misa_ext |= RVI | RVM | RVA | RVF | RVD; + env->misa_ext_mask |= RVI | RVM | RVA | RVF | RVD; + } + + if (riscv_has_ext(env, RVI) && riscv_has_ext(env, RVE)) { + error_setg(errp, + "I and E extensions are incompatible"); + return; + } + + if (!riscv_has_ext(env, RVI) && !riscv_has_ext(env, RVE)) { + error_setg(errp, + "Either I or E extension must be set"); + return; + } + + if (riscv_has_ext(env, RVS) && !riscv_has_ext(env, RVU)) { + error_setg(errp, + "Setting S extension without U extension is illegal"); + return; + } + + if (riscv_has_ext(env, RVH) && !riscv_has_ext(env, RVI)) { + error_setg(errp, + "H depends on an I base integer ISA with 32 x registers"); + return; + } + + if (riscv_has_ext(env, RVH) && !riscv_has_ext(env, RVS)) { + error_setg(errp, "H extension implicitly requires S-mode"); + return; + } + + if (riscv_has_ext(env, RVF) && !cpu->cfg.ext_icsr) { + error_setg(errp, "F extension requires Zicsr"); + return; + } + + if ((cpu->cfg.ext_zawrs) && !riscv_has_ext(env, RVA)) { + error_setg(errp, "Zawrs extension requires A extension"); + return; + } + + if (cpu->cfg.ext_zfa && !riscv_has_ext(env, RVF)) { + error_setg(errp, "Zfa extension requires F extension"); + return; + } + + if (cpu->cfg.ext_zfh) { + cpu_cfg_ext_auto_update(cpu, CPU_CFG_OFFSET(ext_zfhmin), true); + } + + if (cpu->cfg.ext_zfhmin && !riscv_has_ext(env, RVF)) { + error_setg(errp, "Zfh/Zfhmin extensions require F extension"); + return; + } + + if (cpu->cfg.ext_zfbfmin && !riscv_has_ext(env, RVF)) { + error_setg(errp, "Zfbfmin extension depends on F extension"); + return; + } + + if (riscv_has_ext(env, RVD) && !riscv_has_ext(env, RVF)) { + error_setg(errp, "D extension requires F extension"); + return; + } + + if (riscv_has_ext(env, RVV)) { + riscv_cpu_validate_v(env, &cpu->cfg, &local_err); + if (local_err != NULL) { + error_propagate(errp, local_err); + return; + } + + /* The V vector extension depends on the Zve64d extension */ + cpu_cfg_ext_auto_update(cpu, CPU_CFG_OFFSET(ext_zve64d), true); + } + + /* The Zve64d extension depends on the Zve64f extension */ + if (cpu->cfg.ext_zve64d) { + cpu_cfg_ext_auto_update(cpu, CPU_CFG_OFFSET(ext_zve64f), true); + } + + /* The Zve64f extension depends on the Zve32f extension */ + if (cpu->cfg.ext_zve64f) { + cpu_cfg_ext_auto_update(cpu, CPU_CFG_OFFSET(ext_zve32f), true); + } + + if (cpu->cfg.ext_zve64d && !riscv_has_ext(env, RVD)) { + error_setg(errp, "Zve64d/V extensions require D extension"); + return; + } + + if (cpu->cfg.ext_zve32f && !riscv_has_ext(env, RVF)) { + error_setg(errp, "Zve32f/Zve64f extensions require F extension"); + return; + } + + if (cpu->cfg.ext_zvfh) { + cpu_cfg_ext_auto_update(cpu, CPU_CFG_OFFSET(ext_zvfhmin), true); + } + + if (cpu->cfg.ext_zvfhmin && !cpu->cfg.ext_zve32f) { + error_setg(errp, "Zvfh/Zvfhmin extensions require Zve32f extension"); + return; + } + + if (cpu->cfg.ext_zvfh && !cpu->cfg.ext_zfhmin) { + error_setg(errp, "Zvfh extensions requires Zfhmin extension"); + return; + } + + if (cpu->cfg.ext_zvfbfmin && !cpu->cfg.ext_zfbfmin) { + error_setg(errp, "Zvfbfmin extension depends on Zfbfmin extension"); + return; + } + + if (cpu->cfg.ext_zvfbfmin && !cpu->cfg.ext_zve32f) { + error_setg(errp, "Zvfbfmin extension depends on Zve32f extension"); + return; + } + + if (cpu->cfg.ext_zvfbfwma && !cpu->cfg.ext_zvfbfmin) { + error_setg(errp, "Zvfbfwma extension depends on Zvfbfmin extension"); + return; + } + + /* Set the ISA extensions, checks should have happened above */ + if (cpu->cfg.ext_zhinx) { + cpu_cfg_ext_auto_update(cpu, CPU_CFG_OFFSET(ext_zca), true); + } + + if ((cpu->cfg.ext_zdinx || cpu->cfg.ext_zhinxmin) && !cpu->cfg.ext_zfinx) { + error_setg(errp, "Zdinx/Zhinx/Zhinxmin extensions require Zfinx"); + return; + } + + if (cpu->cfg.ext_zfinx) { + if (!cpu->cfg.ext_icsr) { + error_setg(errp, "Zfinx extension requires Zicsr"); + return; + } + if (riscv_has_ext(env, RVF)) { + error_setg(errp, + "Zfinx cannot be supported together with F extension"); + return; + } + } + + if (cpu->cfg.ext_zce) { + cpu_cfg_ext_auto_update(cpu, CPU_CFG_OFFSET(ext_zca), true); + cpu_cfg_ext_auto_update(cpu, CPU_CFG_OFFSET(ext_zcb), true); + cpu_cfg_ext_auto_update(cpu, CPU_CFG_OFFSET(ext_zcmp), true); + cpu_cfg_ext_auto_update(cpu, CPU_CFG_OFFSET(ext_zcmt), true); + if (riscv_has_ext(env, RVF) && env->misa_mxl_max == MXL_RV32) { + cpu_cfg_ext_auto_update(cpu, CPU_CFG_OFFSET(ext_zcf), true); + } + } + + /* zca, zcd and zcf has a PRIV 1.12.0 restriction */ + if (riscv_has_ext(env, RVC) && env->priv_ver >= PRIV_VERSION_1_12_0) { + cpu_cfg_ext_auto_update(cpu, CPU_CFG_OFFSET(ext_zca), true); + if (riscv_has_ext(env, RVF) && env->misa_mxl_max == MXL_RV32) { + cpu_cfg_ext_auto_update(cpu, CPU_CFG_OFFSET(ext_zcf), true); + } + if (riscv_has_ext(env, RVD)) { + cpu_cfg_ext_auto_update(cpu, CPU_CFG_OFFSET(ext_zcd), true); + } + } + + if (env->misa_mxl_max != MXL_RV32 && cpu->cfg.ext_zcf) { + error_setg(errp, "Zcf extension is only relevant to RV32"); + return; + } + + if (!riscv_has_ext(env, RVF) && cpu->cfg.ext_zcf) { + error_setg(errp, "Zcf extension requires F extension"); + return; + } + + if (!riscv_has_ext(env, RVD) && cpu->cfg.ext_zcd) { + error_setg(errp, "Zcd extension requires D extension"); + return; + } + + if ((cpu->cfg.ext_zcf || cpu->cfg.ext_zcd || cpu->cfg.ext_zcb || + cpu->cfg.ext_zcmp || cpu->cfg.ext_zcmt) && !cpu->cfg.ext_zca) { + error_setg(errp, "Zcf/Zcd/Zcb/Zcmp/Zcmt extensions require Zca " + "extension"); + return; + } + + if (cpu->cfg.ext_zcd && (cpu->cfg.ext_zcmp || cpu->cfg.ext_zcmt)) { + error_setg(errp, "Zcmp/Zcmt extensions are incompatible with " + "Zcd extension"); + return; + } + + if (cpu->cfg.ext_zcmt && !cpu->cfg.ext_icsr) { + error_setg(errp, "Zcmt extension requires Zicsr extension"); + return; + } + + /* + * In principle Zve*x would also suffice here, were they supported + * in qemu + */ + if ((cpu->cfg.ext_zvbb || cpu->cfg.ext_zvkg || cpu->cfg.ext_zvkned || + cpu->cfg.ext_zvknha || cpu->cfg.ext_zvksed || cpu->cfg.ext_zvksh) && + !cpu->cfg.ext_zve32f) { + error_setg(errp, + "Vector crypto extensions require V or Zve* extensions"); + return; + } + + if ((cpu->cfg.ext_zvbc || cpu->cfg.ext_zvknhb) && !cpu->cfg.ext_zve64f) { + error_setg( + errp, + "Zvbc and Zvknhb extensions require V or Zve64{f,d} extensions"); + return; + } + + if (cpu->cfg.ext_zk) { + cpu_cfg_ext_auto_update(cpu, CPU_CFG_OFFSET(ext_zkn), true); + cpu_cfg_ext_auto_update(cpu, CPU_CFG_OFFSET(ext_zkr), true); + cpu_cfg_ext_auto_update(cpu, CPU_CFG_OFFSET(ext_zkt), true); + } + + if (cpu->cfg.ext_zkn) { + cpu_cfg_ext_auto_update(cpu, CPU_CFG_OFFSET(ext_zbkb), true); + cpu_cfg_ext_auto_update(cpu, CPU_CFG_OFFSET(ext_zbkc), true); + cpu_cfg_ext_auto_update(cpu, CPU_CFG_OFFSET(ext_zbkx), true); + cpu_cfg_ext_auto_update(cpu, CPU_CFG_OFFSET(ext_zkne), true); + cpu_cfg_ext_auto_update(cpu, CPU_CFG_OFFSET(ext_zknd), true); + cpu_cfg_ext_auto_update(cpu, CPU_CFG_OFFSET(ext_zknh), true); + } + + if (cpu->cfg.ext_zks) { + cpu_cfg_ext_auto_update(cpu, CPU_CFG_OFFSET(ext_zbkb), true); + cpu_cfg_ext_auto_update(cpu, CPU_CFG_OFFSET(ext_zbkc), true); + cpu_cfg_ext_auto_update(cpu, CPU_CFG_OFFSET(ext_zbkx), true); + cpu_cfg_ext_auto_update(cpu, CPU_CFG_OFFSET(ext_zksed), true); + cpu_cfg_ext_auto_update(cpu, CPU_CFG_OFFSET(ext_zksh), true); + } + + /* + * Disable isa extensions based on priv spec after we + * validated and set everything we need. + */ + riscv_cpu_disable_priv_spec_isa_exts(cpu); +} + /* * We'll get here via the following path: * diff --git a/target/riscv/tcg/tcg-cpu.h b/target/riscv/tcg/tcg-cpu.h new file mode 100644 index 0000000000..630184759d --- /dev/null +++ b/target/riscv/tcg/tcg-cpu.h @@ -0,0 +1,27 @@ +/* + * riscv TCG cpu class initialization + * + * Copyright (c) 2023 Ventana Micro Systems Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see . + */ + +#ifndef RISCV_TCG_CPU_H +#define RISCV_TCG_CPU_H + +#include "cpu.h" + +void riscv_cpu_validate_set_extensions(RISCVCPU *cpu, Error **errp); + +#endif From e7443334a87b1cc43d20daacd72db44b530b7a28 Mon Sep 17 00:00:00 2001 From: Daniel Henrique Barboza Date: Mon, 25 Sep 2023 14:56:54 -0300 Subject: [PATCH 0560/1077] target/riscv: move riscv_tcg_ops to tcg-cpu.c MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Move the remaining of riscv_tcg_ops now that we have a working realize() implementation. Signed-off-by: Daniel Henrique Barboza Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Andrew Jones Reviewed-by: LIU Zhiwei Reviewed-by: Alistair Francis Message-ID: <20230925175709.35696-5-dbarboza@ventanamicro.com> Signed-off-by: Alistair Francis --- target/riscv/cpu.c | 58 ------------------------------------ target/riscv/cpu.h | 4 --- target/riscv/tcg/tcg-cpu.c | 60 +++++++++++++++++++++++++++++++++++++- 3 files changed, 59 insertions(+), 63 deletions(-) diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c index 943aca2c20..08cbd51ea1 100644 --- a/target/riscv/cpu.c +++ b/target/riscv/cpu.c @@ -838,24 +838,6 @@ static vaddr riscv_cpu_get_pc(CPUState *cs) return env->pc; } -static void riscv_cpu_synchronize_from_tb(CPUState *cs, - const TranslationBlock *tb) -{ - if (!(tb_cflags(tb) & CF_PCREL)) { - RISCVCPU *cpu = RISCV_CPU(cs); - CPURISCVState *env = &cpu->env; - RISCVMXL xl = FIELD_EX32(tb->flags, TB_FLAGS, XL); - - tcg_debug_assert(!(cs->tcg_cflags & CF_PCREL)); - - if (xl == MXL_RV32) { - env->pc = (int32_t) tb->pc; - } else { - env->pc = tb->pc; - } - } -} - static bool riscv_cpu_has_work(CPUState *cs) { #ifndef CONFIG_USER_ONLY @@ -871,29 +853,6 @@ static bool riscv_cpu_has_work(CPUState *cs) #endif } -static void riscv_restore_state_to_opc(CPUState *cs, - const TranslationBlock *tb, - const uint64_t *data) -{ - RISCVCPU *cpu = RISCV_CPU(cs); - CPURISCVState *env = &cpu->env; - RISCVMXL xl = FIELD_EX32(tb->flags, TB_FLAGS, XL); - target_ulong pc; - - if (tb_cflags(tb) & CF_PCREL) { - pc = (env->pc & TARGET_PAGE_MASK) | data[0]; - } else { - pc = data[0]; - } - - if (xl == MXL_RV32) { - env->pc = (int32_t)pc; - } else { - env->pc = pc; - } - env->bins = data[1]; -} - static void riscv_cpu_reset_hold(Object *obj) { #ifndef CONFIG_USER_ONLY @@ -1805,23 +1764,6 @@ static const struct SysemuCPUOps riscv_sysemu_ops = { }; #endif -const struct TCGCPUOps riscv_tcg_ops = { - .initialize = riscv_translate_init, - .synchronize_from_tb = riscv_cpu_synchronize_from_tb, - .restore_state_to_opc = riscv_restore_state_to_opc, - -#ifndef CONFIG_USER_ONLY - .tlb_fill = riscv_cpu_tlb_fill, - .cpu_exec_interrupt = riscv_cpu_exec_interrupt, - .do_interrupt = riscv_cpu_do_interrupt, - .do_transaction_failed = riscv_cpu_do_transaction_failed, - .do_unaligned_access = riscv_cpu_do_unaligned_access, - .debug_excp_handler = riscv_cpu_debug_excp_handler, - .debug_check_breakpoint = riscv_cpu_debug_check_breakpoint, - .debug_check_watchpoint = riscv_cpu_debug_check_watchpoint, -#endif /* !CONFIG_USER_ONLY */ -}; - static bool riscv_cpu_is_dynamic(Object *cpu_obj) { return object_dynamic_cast(cpu_obj, TYPE_RISCV_DYNAMIC_CPU) != NULL; diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h index e1e47d7509..3055d741c5 100644 --- a/target/riscv/cpu.h +++ b/target/riscv/cpu.h @@ -706,10 +706,6 @@ enum riscv_pmu_event_idx { RISCV_PMU_EVENT_CACHE_ITLB_PREFETCH_MISS = 0x10021, }; -/* Export tcg_ops until we move everything to tcg/tcg-cpu.c */ -#include "hw/core/tcg-cpu-ops.h" -extern const struct TCGCPUOps riscv_tcg_ops; - /* used by tcg/tcg-cpu.c*/ void isa_ext_update_enabled(RISCVCPU *cpu, uint32_t ext_offset, bool en); bool cpu_cfg_ext_is_user_set(uint32_t ext_offset); diff --git a/target/riscv/tcg/tcg-cpu.c b/target/riscv/tcg/tcg-cpu.c index 0ea691fbba..c92dfc20cb 100644 --- a/target/riscv/tcg/tcg-cpu.c +++ b/target/riscv/tcg/tcg-cpu.c @@ -28,7 +28,66 @@ #include "qemu/error-report.h" #include "qemu/log.h" #include "hw/core/accel-cpu.h" +#include "hw/core/tcg-cpu-ops.h" +#include "tcg/tcg.h" +static void riscv_cpu_synchronize_from_tb(CPUState *cs, + const TranslationBlock *tb) +{ + if (!(tb_cflags(tb) & CF_PCREL)) { + RISCVCPU *cpu = RISCV_CPU(cs); + CPURISCVState *env = &cpu->env; + RISCVMXL xl = FIELD_EX32(tb->flags, TB_FLAGS, XL); + + tcg_debug_assert(!(cs->tcg_cflags & CF_PCREL)); + + if (xl == MXL_RV32) { + env->pc = (int32_t) tb->pc; + } else { + env->pc = tb->pc; + } + } +} + +static void riscv_restore_state_to_opc(CPUState *cs, + const TranslationBlock *tb, + const uint64_t *data) +{ + RISCVCPU *cpu = RISCV_CPU(cs); + CPURISCVState *env = &cpu->env; + RISCVMXL xl = FIELD_EX32(tb->flags, TB_FLAGS, XL); + target_ulong pc; + + if (tb_cflags(tb) & CF_PCREL) { + pc = (env->pc & TARGET_PAGE_MASK) | data[0]; + } else { + pc = data[0]; + } + + if (xl == MXL_RV32) { + env->pc = (int32_t)pc; + } else { + env->pc = pc; + } + env->bins = data[1]; +} + +static const struct TCGCPUOps riscv_tcg_ops = { + .initialize = riscv_translate_init, + .synchronize_from_tb = riscv_cpu_synchronize_from_tb, + .restore_state_to_opc = riscv_restore_state_to_opc, + +#ifndef CONFIG_USER_ONLY + .tlb_fill = riscv_cpu_tlb_fill, + .cpu_exec_interrupt = riscv_cpu_exec_interrupt, + .do_interrupt = riscv_cpu_do_interrupt, + .do_transaction_failed = riscv_cpu_do_transaction_failed, + .do_unaligned_access = riscv_cpu_do_unaligned_access, + .debug_excp_handler = riscv_cpu_debug_excp_handler, + .debug_check_breakpoint = riscv_cpu_debug_check_breakpoint, + .debug_check_watchpoint = riscv_cpu_debug_check_watchpoint, +#endif /* !CONFIG_USER_ONLY */ +}; static void cpu_cfg_ext_auto_update(RISCVCPU *cpu, uint32_t ext_offset, bool value) @@ -515,7 +574,6 @@ static void tcg_cpu_init_ops(AccelCPUClass *accel_cpu, CPUClass *cc) { /* * All cpus use the same set of operations. - * riscv_tcg_ops is being imported from cpu.c for now. */ cc->tcg_ops = &riscv_tcg_ops; } From 977bbb04525682fd7a2ed8d28c0590bc2873db06 Mon Sep 17 00:00:00 2001 From: Daniel Henrique Barboza Date: Mon, 25 Sep 2023 14:56:55 -0300 Subject: [PATCH 0561/1077] target/riscv/cpu.c: add .instance_post_init() All generic CPUs call riscv_cpu_add_user_properties(). The 'max' CPU calls riscv_init_max_cpu_extensions(). Both can be moved to a common instance_post_init() callback, implemented in riscv_cpu_post_init(), called by all CPUs. The call order then becomes: riscv_cpu_init() -> cpu_init() of each CPU -> .instance_post_init() In the near future riscv_cpu_post_init() will call the init() function of the current accelerator, providing a hook for KVM and TCG accel classes to change the init() process of the CPU. Signed-off-by: Daniel Henrique Barboza Reviewed-by: Andrew Jones Reviewed-by: Alistair Francis Message-ID: <20230925175709.35696-6-dbarboza@ventanamicro.com> Signed-off-by: Alistair Francis --- target/riscv/cpu.c | 43 ++++++++++++++++++++++++++++++++----------- 1 file changed, 32 insertions(+), 11 deletions(-) diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c index 08cbd51ea1..a6a26c0268 100644 --- a/target/riscv/cpu.c +++ b/target/riscv/cpu.c @@ -427,8 +427,6 @@ static void riscv_max_cpu_init(Object *obj) mlx = MXL_RV32; #endif set_misa(env, mlx, 0); - riscv_cpu_add_user_properties(obj); - riscv_init_max_cpu_extensions(obj); env->priv_ver = PRIV_VERSION_LATEST; #ifndef CONFIG_USER_ONLY set_satp_mode_max_supported(RISCV_CPU(obj), mlx == MXL_RV32 ? @@ -442,7 +440,6 @@ static void rv64_base_cpu_init(Object *obj) CPURISCVState *env = &RISCV_CPU(obj)->env; /* We set this in the realise function */ set_misa(env, MXL_RV64, 0); - riscv_cpu_add_user_properties(obj); /* Set latest version of privileged specification */ env->priv_ver = PRIV_VERSION_LATEST; #ifndef CONFIG_USER_ONLY @@ -566,7 +563,6 @@ static void rv128_base_cpu_init(Object *obj) CPURISCVState *env = &RISCV_CPU(obj)->env; /* We set this in the realise function */ set_misa(env, MXL_RV128, 0); - riscv_cpu_add_user_properties(obj); /* Set latest version of privileged specification */ env->priv_ver = PRIV_VERSION_LATEST; #ifndef CONFIG_USER_ONLY @@ -579,7 +575,6 @@ static void rv32_base_cpu_init(Object *obj) CPURISCVState *env = &RISCV_CPU(obj)->env; /* We set this in the realise function */ set_misa(env, MXL_RV32, 0); - riscv_cpu_add_user_properties(obj); /* Set latest version of privileged specification */ env->priv_ver = PRIV_VERSION_LATEST; #ifndef CONFIG_USER_ONLY @@ -666,7 +661,6 @@ static void riscv_host_cpu_init(Object *obj) #elif defined(TARGET_RISCV64) set_misa(env, MXL_RV64, 0); #endif - riscv_cpu_add_user_properties(obj); } #endif /* CONFIG_KVM */ @@ -1215,6 +1209,37 @@ static void riscv_cpu_set_irq(void *opaque, int irq, int level) } #endif /* CONFIG_USER_ONLY */ +static bool riscv_cpu_is_dynamic(Object *cpu_obj) +{ + return object_dynamic_cast(cpu_obj, TYPE_RISCV_DYNAMIC_CPU) != NULL; +} + +static bool riscv_cpu_has_max_extensions(Object *cpu_obj) +{ + return object_dynamic_cast(cpu_obj, TYPE_RISCV_CPU_MAX) != NULL; +} + +static bool riscv_cpu_has_user_properties(Object *cpu_obj) +{ + if (kvm_enabled() && + object_dynamic_cast(cpu_obj, TYPE_RISCV_CPU_HOST) != NULL) { + return true; + } + + return riscv_cpu_is_dynamic(cpu_obj); +} + +static void riscv_cpu_post_init(Object *obj) +{ + if (riscv_cpu_has_user_properties(obj)) { + riscv_cpu_add_user_properties(obj); + } + + if (riscv_cpu_has_max_extensions(obj)) { + riscv_init_max_cpu_extensions(obj); + } +} + static void riscv_cpu_init(Object *obj) { #ifndef CONFIG_USER_ONLY @@ -1764,11 +1789,6 @@ static const struct SysemuCPUOps riscv_sysemu_ops = { }; #endif -static bool riscv_cpu_is_dynamic(Object *cpu_obj) -{ - return object_dynamic_cast(cpu_obj, TYPE_RISCV_DYNAMIC_CPU) != NULL; -} - static void cpu_set_mvendorid(Object *obj, Visitor *v, const char *name, void *opaque, Error **errp) { @@ -2005,6 +2025,7 @@ static const TypeInfo riscv_cpu_type_infos[] = { .instance_size = sizeof(RISCVCPU), .instance_align = __alignof(RISCVCPU), .instance_init = riscv_cpu_init, + .instance_post_init = riscv_cpu_post_init, .abstract = true, .class_size = sizeof(RISCVCPUClass), .class_init = riscv_cpu_class_init, From a7e87cd7bfd4580bc745cf12440f4e26329bc747 Mon Sep 17 00:00:00 2001 From: Daniel Henrique Barboza Date: Mon, 25 Sep 2023 14:56:56 -0300 Subject: [PATCH 0562/1077] target/riscv: move 'host' CPU declaration to kvm.c MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This CPU only exists if we're compiling with KVM so move it to the kvm specific file. Signed-off-by: Daniel Henrique Barboza Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Andrew Jones Reviewed-by: LIU Zhiwei Reviewed-by: Alistair Francis Message-ID: <20230925175709.35696-7-dbarboza@ventanamicro.com> Signed-off-by: Alistair Francis --- target/riscv/cpu.c | 15 --------------- target/riscv/kvm.c | 21 +++++++++++++++++++++ 2 files changed, 21 insertions(+), 15 deletions(-) diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c index a6a26c0268..d78f73aa55 100644 --- a/target/riscv/cpu.c +++ b/target/riscv/cpu.c @@ -652,18 +652,6 @@ static void rv32_imafcu_nommu_cpu_init(Object *obj) } #endif -#if defined(CONFIG_KVM) -static void riscv_host_cpu_init(Object *obj) -{ - CPURISCVState *env = &RISCV_CPU(obj)->env; -#if defined(TARGET_RISCV32) - set_misa(env, MXL_RV32, 0); -#elif defined(TARGET_RISCV64) - set_misa(env, MXL_RV64, 0); -#endif -} -#endif /* CONFIG_KVM */ - static ObjectClass *riscv_cpu_class_by_name(const char *cpu_model) { ObjectClass *oc; @@ -2037,9 +2025,6 @@ static const TypeInfo riscv_cpu_type_infos[] = { }, DEFINE_DYNAMIC_CPU(TYPE_RISCV_CPU_ANY, riscv_any_cpu_init), DEFINE_DYNAMIC_CPU(TYPE_RISCV_CPU_MAX, riscv_max_cpu_init), -#if defined(CONFIG_KVM) - DEFINE_CPU(TYPE_RISCV_CPU_HOST, riscv_host_cpu_init), -#endif #if defined(TARGET_RISCV32) DEFINE_DYNAMIC_CPU(TYPE_RISCV_CPU_BASE32, rv32_base_cpu_init), DEFINE_CPU(TYPE_RISCV_CPU_IBEX, rv32_ibex_cpu_init), diff --git a/target/riscv/kvm.c b/target/riscv/kvm.c index 1e4e4456b3..31d2ede4b6 100644 --- a/target/riscv/kvm.c +++ b/target/riscv/kvm.c @@ -1271,3 +1271,24 @@ void kvm_riscv_aia_create(MachineState *machine, uint64_t group_shift, kvm_msi_via_irqfd_allowed = kvm_irqfds_enabled(); } + +static void riscv_host_cpu_init(Object *obj) +{ + CPURISCVState *env = &RISCV_CPU(obj)->env; + +#if defined(TARGET_RISCV32) + env->misa_mxl_max = env->misa_mxl = MXL_RV32; +#elif defined(TARGET_RISCV64) + env->misa_mxl_max = env->misa_mxl = MXL_RV64; +#endif +} + +static const TypeInfo riscv_kvm_cpu_type_infos[] = { + { + .name = TYPE_RISCV_CPU_HOST, + .parent = TYPE_RISCV_CPU, + .instance_init = riscv_host_cpu_init, + } +}; + +DEFINE_TYPES(riscv_kvm_cpu_type_infos) From ec34cd732ce33af59a913444320f870c6309de51 Mon Sep 17 00:00:00 2001 From: Daniel Henrique Barboza Date: Mon, 25 Sep 2023 14:56:57 -0300 Subject: [PATCH 0563/1077] target/riscv/cpu.c: mark extensions arrays as 'const' We'll need to export these arrays to the accelerator classes in the next patches. Mark them as 'const' now because they should not be modified at runtime. Note that 'riscv_cpu_options' will also be exported, but can't be marked as 'const', because the properties are changed via qdev_property_add_static(). Signed-off-by: Daniel Henrique Barboza Reviewed-by: Andrew Jones Reviewed-by: LIU Zhiwei Reviewed-by: Alistair Francis Message-ID: <20230925175709.35696-8-dbarboza@ventanamicro.com> Signed-off-by: Alistair Francis --- target/riscv/cpu.c | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c index d78f73aa55..d831dc375b 100644 --- a/target/riscv/cpu.c +++ b/target/riscv/cpu.c @@ -1403,7 +1403,7 @@ typedef struct RISCVCPUMultiExtConfig { {.name = _name, .offset = CPU_CFG_OFFSET(_prop), \ .enabled = _defval} -static RISCVCPUMultiExtConfig riscv_cpu_extensions[] = { +static const RISCVCPUMultiExtConfig riscv_cpu_extensions[] = { /* Defaults for standard extensions */ MULTI_EXT_CFG_BOOL("sscofpmf", ext_sscofpmf, false), MULTI_EXT_CFG_BOOL("Zifencei", ext_ifencei, true), @@ -1465,7 +1465,7 @@ static RISCVCPUMultiExtConfig riscv_cpu_extensions[] = { DEFINE_PROP_END_OF_LIST(), }; -static RISCVCPUMultiExtConfig riscv_cpu_vendor_exts[] = { +static const RISCVCPUMultiExtConfig riscv_cpu_vendor_exts[] = { MULTI_EXT_CFG_BOOL("xtheadba", ext_xtheadba, false), MULTI_EXT_CFG_BOOL("xtheadbb", ext_xtheadbb, false), MULTI_EXT_CFG_BOOL("xtheadbs", ext_xtheadbs, false), @@ -1483,7 +1483,7 @@ static RISCVCPUMultiExtConfig riscv_cpu_vendor_exts[] = { }; /* These are experimental so mark with 'x-' */ -static RISCVCPUMultiExtConfig riscv_cpu_experimental_exts[] = { +static const RISCVCPUMultiExtConfig riscv_cpu_experimental_exts[] = { /* ePMP 0.9.3 */ MULTI_EXT_CFG_BOOL("x-epmp", epmp, false), MULTI_EXT_CFG_BOOL("x-smaia", ext_smaia, false), @@ -1554,7 +1554,7 @@ static void cpu_get_multi_ext_cfg(Object *obj, Visitor *v, const char *name, } static void cpu_add_multi_ext_prop(Object *cpu_obj, - RISCVCPUMultiExtConfig *multi_cfg) + const RISCVCPUMultiExtConfig *multi_cfg) { object_property_add(cpu_obj, multi_cfg->name, "bool", cpu_get_multi_ext_cfg, @@ -1571,11 +1571,13 @@ static void cpu_add_multi_ext_prop(Object *cpu_obj, } static void riscv_cpu_add_multiext_prop_array(Object *obj, - RISCVCPUMultiExtConfig *array) + const RISCVCPUMultiExtConfig *array) { + const RISCVCPUMultiExtConfig *prop; + g_assert(array); - for (RISCVCPUMultiExtConfig *prop = array; prop && prop->name; prop++) { + for (prop = array; prop && prop->name; prop++) { cpu_add_multi_ext_prop(obj, prop); } } @@ -1616,11 +1618,13 @@ static void riscv_cpu_add_kvm_unavail_prop(Object *obj, const char *prop_name) } static void riscv_cpu_add_kvm_unavail_prop_array(Object *obj, - RISCVCPUMultiExtConfig *array) + const RISCVCPUMultiExtConfig *array) { + const RISCVCPUMultiExtConfig *prop; + g_assert(array); - for (RISCVCPUMultiExtConfig *prop = array; prop && prop->name; prop++) { + for (prop = array; prop && prop->name; prop++) { riscv_cpu_add_kvm_unavail_prop(obj, prop->name); } } @@ -1683,7 +1687,7 @@ static void riscv_init_max_cpu_extensions(Object *obj) { RISCVCPU *cpu = RISCV_CPU(obj); CPURISCVState *env = &cpu->env; - RISCVCPUMultiExtConfig *prop; + const RISCVCPUMultiExtConfig *prop; /* Enable RVG, RVJ and RVV that are disabled by default */ set_misa(env, env->misa_mxl, env->misa_ext | RVG | RVJ | RVV); From 32fa177604a8f0e3be331add04da91fef28bfbbd Mon Sep 17 00:00:00 2001 From: Daniel Henrique Barboza Date: Mon, 25 Sep 2023 14:56:58 -0300 Subject: [PATCH 0564/1077] target/riscv: move riscv_cpu_add_kvm_properties() to kvm.c We'll introduce the KVM accelerator class with a 'cpu_instance_init' implementation that is going to be invoked during the common riscv_cpu_post_init() (via accel_cpu_instance_init()). This instance_init will execute KVM exclusive code that TCG doesn't care about, such as adding KVM specific properties, initing registers using a KVM scratch CPU and so on. The core of the forementioned cpu_instance_init impl is the current riscv_cpu_add_kvm_properties() that is being used by the common code via riscv_cpu_add_user_properties() in cpu.c. Move it to kvm.c, together will all the relevant artifacts, exporting and renaming it to kvm_riscv_cpu_add_kvm_properties() so cpu.c can keep using it for now. To make this work we'll need to export riscv_cpu_extensions, riscv_cpu_vendor_exts and riscv_cpu_experimental_exts from cpu.c as well. The TCG accelerator will also need to access those in the near future so this export will benefit us in the long run. Signed-off-by: Daniel Henrique Barboza Reviewed-by: Andrew Jones Reviewed-by: LIU Zhiwei Reviewed-by: Alistair Francis Message-ID: <20230925175709.35696-9-dbarboza@ventanamicro.com> Signed-off-by: Alistair Francis --- target/riscv/cpu.c | 85 +++------------------------------------- target/riscv/cpu.h | 14 +++++++ target/riscv/kvm.c | 68 +++++++++++++++++++++++++++++++- target/riscv/kvm_riscv.h | 3 -- 4 files changed, 86 insertions(+), 84 deletions(-) diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c index d831dc375b..c73500151f 100644 --- a/target/riscv/cpu.c +++ b/target/riscv/cpu.c @@ -1366,7 +1366,7 @@ static RISCVCPUMisaExtConfig misa_ext_cfgs[] = { * change MISA bits during realize() (RVG enables MISA * bits but the user is warned about it). */ -static void riscv_cpu_add_misa_properties(Object *cpu_obj) +void riscv_cpu_add_misa_properties(Object *cpu_obj) { int i; @@ -1393,17 +1393,11 @@ static void riscv_cpu_add_misa_properties(Object *cpu_obj) } } -typedef struct RISCVCPUMultiExtConfig { - const char *name; - uint32_t offset; - bool enabled; -} RISCVCPUMultiExtConfig; - #define MULTI_EXT_CFG_BOOL(_name, _prop, _defval) \ {.name = _name, .offset = CPU_CFG_OFFSET(_prop), \ .enabled = _defval} -static const RISCVCPUMultiExtConfig riscv_cpu_extensions[] = { +const RISCVCPUMultiExtConfig riscv_cpu_extensions[] = { /* Defaults for standard extensions */ MULTI_EXT_CFG_BOOL("sscofpmf", ext_sscofpmf, false), MULTI_EXT_CFG_BOOL("Zifencei", ext_ifencei, true), @@ -1465,7 +1459,7 @@ static const RISCVCPUMultiExtConfig riscv_cpu_extensions[] = { DEFINE_PROP_END_OF_LIST(), }; -static const RISCVCPUMultiExtConfig riscv_cpu_vendor_exts[] = { +const RISCVCPUMultiExtConfig riscv_cpu_vendor_exts[] = { MULTI_EXT_CFG_BOOL("xtheadba", ext_xtheadba, false), MULTI_EXT_CFG_BOOL("xtheadbb", ext_xtheadbb, false), MULTI_EXT_CFG_BOOL("xtheadbs", ext_xtheadbs, false), @@ -1483,7 +1477,7 @@ static const RISCVCPUMultiExtConfig riscv_cpu_vendor_exts[] = { }; /* These are experimental so mark with 'x-' */ -static const RISCVCPUMultiExtConfig riscv_cpu_experimental_exts[] = { +const RISCVCPUMultiExtConfig riscv_cpu_experimental_exts[] = { /* ePMP 0.9.3 */ MULTI_EXT_CFG_BOOL("x-epmp", epmp, false), MULTI_EXT_CFG_BOOL("x-smaia", ext_smaia, false), @@ -1509,7 +1503,7 @@ static const RISCVCPUMultiExtConfig riscv_cpu_experimental_exts[] = { DEFINE_PROP_END_OF_LIST(), }; -static Property riscv_cpu_options[] = { +Property riscv_cpu_options[] = { DEFINE_PROP_UINT8("pmu-num", RISCVCPU, cfg.pmu_num, 16), DEFINE_PROP_BOOL("mmu", RISCVCPU, cfg.mmu, true), @@ -1582,75 +1576,6 @@ static void riscv_cpu_add_multiext_prop_array(Object *obj, } } -#ifdef CONFIG_KVM -static void cpu_set_cfg_unavailable(Object *obj, Visitor *v, - const char *name, - void *opaque, Error **errp) -{ - const char *propname = opaque; - bool value; - - if (!visit_type_bool(v, name, &value, errp)) { - return; - } - - if (value) { - error_setg(errp, "extension %s is not available with KVM", - propname); - } -} - -static void riscv_cpu_add_kvm_unavail_prop(Object *obj, const char *prop_name) -{ - /* Check if KVM created the property already */ - if (object_property_find(obj, prop_name)) { - return; - } - - /* - * Set the default to disabled for every extension - * unknown to KVM and error out if the user attempts - * to enable any of them. - */ - object_property_add(obj, prop_name, "bool", - NULL, cpu_set_cfg_unavailable, - NULL, (void *)prop_name); -} - -static void riscv_cpu_add_kvm_unavail_prop_array(Object *obj, - const RISCVCPUMultiExtConfig *array) -{ - const RISCVCPUMultiExtConfig *prop; - - g_assert(array); - - for (prop = array; prop && prop->name; prop++) { - riscv_cpu_add_kvm_unavail_prop(obj, prop->name); - } -} - -void kvm_riscv_cpu_add_kvm_properties(Object *obj) -{ - Property *prop; - DeviceState *dev = DEVICE(obj); - - kvm_riscv_init_user_properties(obj); - riscv_cpu_add_misa_properties(obj); - - riscv_cpu_add_kvm_unavail_prop_array(obj, riscv_cpu_extensions); - riscv_cpu_add_kvm_unavail_prop_array(obj, riscv_cpu_vendor_exts); - riscv_cpu_add_kvm_unavail_prop_array(obj, riscv_cpu_experimental_exts); - - for (prop = riscv_cpu_options; prop && prop->name; prop++) { - /* Check if KVM created the property already */ - if (object_property_find(obj, prop->name)) { - continue; - } - qdev_property_add_static(dev, prop); - } -} -#endif - /* * Add CPU properties with user-facing flags. * diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h index 3055d741c5..0afa45aad1 100644 --- a/target/riscv/cpu.h +++ b/target/riscv/cpu.h @@ -22,6 +22,7 @@ #include "hw/core/cpu.h" #include "hw/registerfields.h" +#include "hw/qdev-properties.h" #include "exec/cpu-defs.h" #include "qemu/cpu-float.h" #include "qom/object.h" @@ -713,6 +714,19 @@ bool isa_ext_is_enabled(RISCVCPU *cpu, uint32_t ext_offset); int cpu_cfg_ext_get_min_version(uint32_t ext_offset); void riscv_cpu_disable_priv_spec_isa_exts(RISCVCPU *cpu); +typedef struct RISCVCPUMultiExtConfig { + const char *name; + uint32_t offset; + bool enabled; +} RISCVCPUMultiExtConfig; + +extern const RISCVCPUMultiExtConfig riscv_cpu_extensions[]; +extern const RISCVCPUMultiExtConfig riscv_cpu_vendor_exts[]; +extern const RISCVCPUMultiExtConfig riscv_cpu_experimental_exts[]; +extern Property riscv_cpu_options[]; + +void riscv_cpu_add_misa_properties(Object *cpu_obj); + /* CSR function table */ extern riscv_csr_operations csr_ops[CSR_TABLE_SIZE]; diff --git a/target/riscv/kvm.c b/target/riscv/kvm.c index 31d2ede4b6..e682a70311 100644 --- a/target/riscv/kvm.c +++ b/target/riscv/kvm.c @@ -345,6 +345,52 @@ static void kvm_riscv_update_cpu_cfg_isa_ext(RISCVCPU *cpu, CPUState *cs) } } +static void cpu_set_cfg_unavailable(Object *obj, Visitor *v, + const char *name, + void *opaque, Error **errp) +{ + const char *propname = opaque; + bool value; + + if (!visit_type_bool(v, name, &value, errp)) { + return; + } + + if (value) { + error_setg(errp, "extension %s is not available with KVM", + propname); + } +} + +static void riscv_cpu_add_kvm_unavail_prop(Object *obj, const char *prop_name) +{ + /* Check if KVM created the property already */ + if (object_property_find(obj, prop_name)) { + return; + } + + /* + * Set the default to disabled for every extension + * unknown to KVM and error out if the user attempts + * to enable any of them. + */ + object_property_add(obj, prop_name, "bool", + NULL, cpu_set_cfg_unavailable, + NULL, (void *)prop_name); +} + +static void riscv_cpu_add_kvm_unavail_prop_array(Object *obj, + const RISCVCPUMultiExtConfig *array) +{ + const RISCVCPUMultiExtConfig *prop; + + g_assert(array); + + for (prop = array; prop && prop->name; prop++) { + riscv_cpu_add_kvm_unavail_prop(obj, prop->name); + } +} + static void kvm_riscv_add_cpu_user_properties(Object *cpu_obj) { int i; @@ -754,7 +800,7 @@ static void kvm_riscv_init_multiext_cfg(RISCVCPU *cpu, KVMScratchCPU *kvmcpu) } } -void kvm_riscv_init_user_properties(Object *cpu_obj) +static void riscv_init_user_properties(Object *cpu_obj) { RISCVCPU *cpu = RISCV_CPU(cpu_obj); KVMScratchCPU kvmcpu; @@ -1272,6 +1318,26 @@ void kvm_riscv_aia_create(MachineState *machine, uint64_t group_shift, kvm_msi_via_irqfd_allowed = kvm_irqfds_enabled(); } +void kvm_riscv_cpu_add_kvm_properties(Object *obj) +{ + DeviceState *dev = DEVICE(obj); + + riscv_init_user_properties(obj); + riscv_cpu_add_misa_properties(obj); + + riscv_cpu_add_kvm_unavail_prop_array(obj, riscv_cpu_extensions); + riscv_cpu_add_kvm_unavail_prop_array(obj, riscv_cpu_vendor_exts); + riscv_cpu_add_kvm_unavail_prop_array(obj, riscv_cpu_experimental_exts); + + for (Property *prop = riscv_cpu_options; prop && prop->name; prop++) { + /* Check if KVM created the property already */ + if (object_property_find(obj, prop->name)) { + continue; + } + qdev_property_add_static(dev, prop); + } +} + static void riscv_host_cpu_init(Object *obj) { CPURISCVState *env = &RISCV_CPU(obj)->env; diff --git a/target/riscv/kvm_riscv.h b/target/riscv/kvm_riscv.h index 44b850a046..da9630c4af 100644 --- a/target/riscv/kvm_riscv.h +++ b/target/riscv/kvm_riscv.h @@ -19,10 +19,7 @@ #ifndef QEMU_KVM_RISCV_H #define QEMU_KVM_RISCV_H -/* Temporarily implemented in cpu.c */ void kvm_riscv_cpu_add_kvm_properties(Object *obj); - -void kvm_riscv_init_user_properties(Object *cpu_obj); void kvm_riscv_reset_vcpu(RISCVCPU *cpu); void kvm_riscv_set_irq(RISCVCPU *cpu, int irq, int level); void kvm_riscv_aia_create(MachineState *machine, uint64_t group_shift, From 7d0c302c53ce7508326092d3ed07497f82961ff7 Mon Sep 17 00:00:00 2001 From: Daniel Henrique Barboza Date: Mon, 25 Sep 2023 14:56:59 -0300 Subject: [PATCH 0565/1077] target/riscv: make riscv_add_satp_mode_properties() public This function is used for both accelerators. Make it public, and call it from kvm_riscv_cpu_add_kvm_properties(). This will make it easier to split KVM specific code for the KVM accelerator class in the next patch. Signed-off-by: Daniel Henrique Barboza Reviewed-by: Andrew Jones Reviewed-by: LIU Zhiwei Reviewed-by: Alistair Francis Message-ID: <20230925175709.35696-10-dbarboza@ventanamicro.com> Signed-off-by: Alistair Francis --- target/riscv/cpu.c | 5 ++--- target/riscv/cpu.h | 1 + target/riscv/kvm.c | 1 + 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c index c73500151f..143fbc1fbc 100644 --- a/target/riscv/cpu.c +++ b/target/riscv/cpu.c @@ -1115,7 +1115,7 @@ static void cpu_riscv_set_satp(Object *obj, Visitor *v, const char *name, satp_map->init |= 1 << satp; } -static void riscv_add_satp_mode_properties(Object *obj) +void riscv_add_satp_mode_properties(Object *obj) { RISCVCPU *cpu = RISCV_CPU(obj); @@ -1585,12 +1585,11 @@ static void riscv_cpu_add_multiext_prop_array(Object *obj, static void riscv_cpu_add_user_properties(Object *obj) { #ifndef CONFIG_USER_ONLY - riscv_add_satp_mode_properties(obj); - if (kvm_enabled()) { kvm_riscv_cpu_add_kvm_properties(obj); return; } + riscv_add_satp_mode_properties(obj); #endif riscv_cpu_add_misa_properties(obj); diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h index 0afa45aad1..d4b4ac3481 100644 --- a/target/riscv/cpu.h +++ b/target/riscv/cpu.h @@ -726,6 +726,7 @@ extern const RISCVCPUMultiExtConfig riscv_cpu_experimental_exts[]; extern Property riscv_cpu_options[]; void riscv_cpu_add_misa_properties(Object *cpu_obj); +void riscv_add_satp_mode_properties(Object *obj); /* CSR function table */ extern riscv_csr_operations csr_ops[CSR_TABLE_SIZE]; diff --git a/target/riscv/kvm.c b/target/riscv/kvm.c index e682a70311..e5e957121f 100644 --- a/target/riscv/kvm.c +++ b/target/riscv/kvm.c @@ -1323,6 +1323,7 @@ void kvm_riscv_cpu_add_kvm_properties(Object *obj) DeviceState *dev = DEVICE(obj); riscv_init_user_properties(obj); + riscv_add_satp_mode_properties(obj); riscv_cpu_add_misa_properties(obj); riscv_cpu_add_kvm_unavail_prop_array(obj, riscv_cpu_extensions); From 5c67bc73be9f896809b8ab4eb64020faa66ed491 Mon Sep 17 00:00:00 2001 From: Daniel Henrique Barboza Date: Mon, 25 Sep 2023 14:57:00 -0300 Subject: [PATCH 0566/1077] target/riscv: remove kvm-stub.c This file is not needed for some time now. Both kvm_riscv_reset_vcpu() and kvm_riscv_set_irq() have public declarations in kvm_riscv.h and are wrapped in 'if kvm_enabled()' blocks that the compiler will rip it out in non-KVM builds. Signed-off-by: Daniel Henrique Barboza Reviewed-by: Alistair Francis Message-ID: <20230925175709.35696-11-dbarboza@ventanamicro.com> Signed-off-by: Alistair Francis --- target/riscv/kvm-stub.c | 30 ------------------------------ target/riscv/meson.build | 2 +- 2 files changed, 1 insertion(+), 31 deletions(-) delete mode 100644 target/riscv/kvm-stub.c diff --git a/target/riscv/kvm-stub.c b/target/riscv/kvm-stub.c deleted file mode 100644 index 4e8fc31a21..0000000000 --- a/target/riscv/kvm-stub.c +++ /dev/null @@ -1,30 +0,0 @@ -/* - * QEMU KVM RISC-V specific function stubs - * - * Copyright (c) 2020 Huawei Technologies Co., Ltd - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2 or later, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program. If not, see . - */ -#include "qemu/osdep.h" -#include "cpu.h" -#include "kvm_riscv.h" - -void kvm_riscv_reset_vcpu(RISCVCPU *cpu) -{ - abort(); -} - -void kvm_riscv_set_irq(RISCVCPU *cpu, int irq, int level) -{ - abort(); -} diff --git a/target/riscv/meson.build b/target/riscv/meson.build index b4ded65e41..b30ebf5795 100644 --- a/target/riscv/meson.build +++ b/target/riscv/meson.build @@ -24,7 +24,7 @@ riscv_ss.add(files( 'zce_helper.c', 'vcrypto_helper.c' )) -riscv_ss.add(when: 'CONFIG_KVM', if_true: files('kvm.c'), if_false: files('kvm-stub.c')) +riscv_ss.add(when: 'CONFIG_KVM', if_true: files('kvm.c')) riscv_system_ss = ss.source_set() riscv_system_ss.add(files( From d86c25b292bf9685615cbb93d7b07f33a9b63104 Mon Sep 17 00:00:00 2001 From: Daniel Henrique Barboza Date: Mon, 25 Sep 2023 14:57:01 -0300 Subject: [PATCH 0567/1077] target/riscv: introduce KVM AccelCPUClass Add a KVM accelerator class like we did with TCG. The difference is that, at least for now, we won't be using a realize() implementation for this accelerator. We'll start by assiging kvm_riscv_cpu_add_kvm_properties(), renamed to kvm_cpu_instance_init(), as a 'cpu_instance_init' implementation. Change riscv_cpu_post_init() to invoke accel_cpu_instance_init(), which will go through the 'cpu_instance_init' impl of the current acceleration (if available) and execute it. The end result is that the KVM initial setup, i.e. starting registers and adding its specific properties, will be done via this hook. Add a 'tcg_enabled()' condition in riscv_cpu_post_init() to avoid calling riscv_cpu_add_user_properties() when running KVM. We'll remove this condition when the TCG accel class get its own 'cpu_instance_init' implementation. Signed-off-by: Daniel Henrique Barboza Reviewed-by: Andrew Jones Reviewed-by: LIU Zhiwei Reviewed-by: Alistair Francis Message-ID: <20230925175709.35696-12-dbarboza@ventanamicro.com> Signed-off-by: Alistair Francis --- target/riscv/cpu.c | 8 +++----- target/riscv/kvm.c | 26 ++++++++++++++++++++++++-- target/riscv/kvm_riscv.h | 1 - 3 files changed, 27 insertions(+), 8 deletions(-) diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c index 143fbc1fbc..648b9f7af7 100644 --- a/target/riscv/cpu.c +++ b/target/riscv/cpu.c @@ -1219,7 +1219,9 @@ static bool riscv_cpu_has_user_properties(Object *cpu_obj) static void riscv_cpu_post_init(Object *obj) { - if (riscv_cpu_has_user_properties(obj)) { + accel_cpu_instance_init(CPU(obj)); + + if (tcg_enabled() && riscv_cpu_has_user_properties(obj)) { riscv_cpu_add_user_properties(obj); } @@ -1585,10 +1587,6 @@ static void riscv_cpu_add_multiext_prop_array(Object *obj, static void riscv_cpu_add_user_properties(Object *obj) { #ifndef CONFIG_USER_ONLY - if (kvm_enabled()) { - kvm_riscv_cpu_add_kvm_properties(obj); - return; - } riscv_add_satp_mode_properties(obj); #endif diff --git a/target/riscv/kvm.c b/target/riscv/kvm.c index e5e957121f..606fdab223 100644 --- a/target/riscv/kvm.c +++ b/target/riscv/kvm.c @@ -31,6 +31,7 @@ #include "sysemu/kvm_int.h" #include "cpu.h" #include "trace.h" +#include "hw/core/accel-cpu.h" #include "hw/pci/pci.h" #include "exec/memattrs.h" #include "exec/address-spaces.h" @@ -1318,8 +1319,9 @@ void kvm_riscv_aia_create(MachineState *machine, uint64_t group_shift, kvm_msi_via_irqfd_allowed = kvm_irqfds_enabled(); } -void kvm_riscv_cpu_add_kvm_properties(Object *obj) +static void kvm_cpu_instance_init(CPUState *cs) { + Object *obj = OBJECT(RISCV_CPU(cs)); DeviceState *dev = DEVICE(obj); riscv_init_user_properties(obj); @@ -1331,7 +1333,7 @@ void kvm_riscv_cpu_add_kvm_properties(Object *obj) riscv_cpu_add_kvm_unavail_prop_array(obj, riscv_cpu_experimental_exts); for (Property *prop = riscv_cpu_options; prop && prop->name; prop++) { - /* Check if KVM created the property already */ + /* Check if we have a specific KVM handler for the option */ if (object_property_find(obj, prop->name)) { continue; } @@ -1339,6 +1341,26 @@ void kvm_riscv_cpu_add_kvm_properties(Object *obj) } } +static void kvm_cpu_accel_class_init(ObjectClass *oc, void *data) +{ + AccelCPUClass *acc = ACCEL_CPU_CLASS(oc); + + acc->cpu_instance_init = kvm_cpu_instance_init; +} + +static const TypeInfo kvm_cpu_accel_type_info = { + .name = ACCEL_CPU_NAME("kvm"), + + .parent = TYPE_ACCEL_CPU, + .class_init = kvm_cpu_accel_class_init, + .abstract = true, +}; +static void kvm_cpu_accel_register_types(void) +{ + type_register_static(&kvm_cpu_accel_type_info); +} +type_init(kvm_cpu_accel_register_types); + static void riscv_host_cpu_init(Object *obj) { CPURISCVState *env = &RISCV_CPU(obj)->env; diff --git a/target/riscv/kvm_riscv.h b/target/riscv/kvm_riscv.h index da9630c4af..8329cfab82 100644 --- a/target/riscv/kvm_riscv.h +++ b/target/riscv/kvm_riscv.h @@ -19,7 +19,6 @@ #ifndef QEMU_KVM_RISCV_H #define QEMU_KVM_RISCV_H -void kvm_riscv_cpu_add_kvm_properties(Object *obj); void kvm_riscv_reset_vcpu(RISCVCPU *cpu); void kvm_riscv_set_irq(RISCVCPU *cpu, int irq, int level); void kvm_riscv_aia_create(MachineState *machine, uint64_t group_shift, From fb80f33377df221728d6c3c298f19b0da7ba277a Mon Sep 17 00:00:00 2001 From: Daniel Henrique Barboza Date: Mon, 25 Sep 2023 14:57:02 -0300 Subject: [PATCH 0568/1077] target/riscv: move KVM only files to kvm subdir Move the files to a 'kvm' dir to promote more code separation between accelerators and making our lives easier supporting build options such as --disable-tcg. Rename kvm.c to kvm-cpu.c to keep it in line with its TCG counterpart. Signed-off-by: Daniel Henrique Barboza Reviewed-by: Andrew Jones Reviewed-by: LIU Zhiwei Reviewed-by: Alistair Francis Message-ID: <20230925175709.35696-13-dbarboza@ventanamicro.com> Signed-off-by: Alistair Francis --- hw/intc/riscv_aplic.c | 2 +- hw/riscv/virt.c | 2 +- target/riscv/cpu.c | 2 +- target/riscv/{kvm.c => kvm/kvm-cpu.c} | 0 target/riscv/{ => kvm}/kvm_riscv.h | 0 target/riscv/kvm/meson.build | 1 + target/riscv/meson.build | 2 +- 7 files changed, 5 insertions(+), 4 deletions(-) rename target/riscv/{kvm.c => kvm/kvm-cpu.c} (100%) rename target/riscv/{ => kvm}/kvm_riscv.h (100%) create mode 100644 target/riscv/kvm/meson.build diff --git a/hw/intc/riscv_aplic.c b/hw/intc/riscv_aplic.c index 99aae8ccbe..c677b5cfbb 100644 --- a/hw/intc/riscv_aplic.c +++ b/hw/intc/riscv_aplic.c @@ -32,7 +32,7 @@ #include "target/riscv/cpu.h" #include "sysemu/sysemu.h" #include "sysemu/kvm.h" -#include "kvm_riscv.h" +#include "kvm/kvm_riscv.h" #include "migration/vmstate.h" #define APLIC_MAX_IDC (1UL << 14) diff --git a/hw/riscv/virt.c b/hw/riscv/virt.c index 5edc1d98d2..9de578c756 100644 --- a/hw/riscv/virt.c +++ b/hw/riscv/virt.c @@ -35,7 +35,7 @@ #include "hw/riscv/virt.h" #include "hw/riscv/boot.h" #include "hw/riscv/numa.h" -#include "kvm_riscv.h" +#include "kvm/kvm_riscv.h" #include "hw/intc/riscv_aclint.h" #include "hw/intc/riscv_aplic.h" #include "hw/intc/riscv_imsic.h" diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c index 648b9f7af7..d8753240bf 100644 --- a/target/riscv/cpu.c +++ b/target/riscv/cpu.c @@ -33,7 +33,7 @@ #include "fpu/softfloat-helpers.h" #include "sysemu/kvm.h" #include "sysemu/tcg.h" -#include "kvm_riscv.h" +#include "kvm/kvm_riscv.h" #include "tcg/tcg.h" /* RISC-V CPU definitions */ diff --git a/target/riscv/kvm.c b/target/riscv/kvm/kvm-cpu.c similarity index 100% rename from target/riscv/kvm.c rename to target/riscv/kvm/kvm-cpu.c diff --git a/target/riscv/kvm_riscv.h b/target/riscv/kvm/kvm_riscv.h similarity index 100% rename from target/riscv/kvm_riscv.h rename to target/riscv/kvm/kvm_riscv.h diff --git a/target/riscv/kvm/meson.build b/target/riscv/kvm/meson.build new file mode 100644 index 0000000000..7e92415091 --- /dev/null +++ b/target/riscv/kvm/meson.build @@ -0,0 +1 @@ +riscv_ss.add(when: 'CONFIG_KVM', if_true: files('kvm-cpu.c')) diff --git a/target/riscv/meson.build b/target/riscv/meson.build index b30ebf5795..a5e0734e7f 100644 --- a/target/riscv/meson.build +++ b/target/riscv/meson.build @@ -24,7 +24,6 @@ riscv_ss.add(files( 'zce_helper.c', 'vcrypto_helper.c' )) -riscv_ss.add(when: 'CONFIG_KVM', if_true: files('kvm.c')) riscv_system_ss = ss.source_set() riscv_system_ss.add(files( @@ -39,6 +38,7 @@ riscv_system_ss.add(files( )) subdir('tcg') +subdir('kvm') target_arch += {'riscv': riscv_ss} target_system_arch += {'riscv': riscv_system_ss} From efa365b711075eee996a657ec4b399e27ec8fa4f Mon Sep 17 00:00:00 2001 From: Daniel Henrique Barboza Date: Mon, 25 Sep 2023 14:57:03 -0300 Subject: [PATCH 0569/1077] target/riscv/kvm: do not use riscv_cpu_add_misa_properties() riscv_cpu_add_misa_properties() is being used to fill the missing KVM MISA properties but it is a TCG helper that was adapted to do so. We'll move it to tcg-cpu.c in the next patches, meaning that KVM needs to fill the remaining MISA properties on its own. Do not use riscv_cpu_add_misa_properties(). Let's create a new array with all available MISA bits we support that can be read by KVM. The array is zero terminate to allow us to iterate through it without knowing its size. Then, inside kvm_riscv_add_cpu_user_properties(), we'll create all KVM MISA properties as usual and then use this array to add any missing MISA properties with the riscv_cpu_add_kvm_unavail_prop() helper. Note that we're creating misa_bits[], and not using the existing 'riscv_single_letter_exts[]', because the latter is tuned for riscv,isa related functions and it doesn't have all MISA bits we support. Commit 0e2c377023 ("target/riscv: misa to ISA string conversion fix") has the full context. While we're at it, move both satp and the multi-letter extension properties to kvm_riscv_add_cpu_user_properties() as well. Signed-off-by: Daniel Henrique Barboza Reviewed-by: Andrew Jones Reviewed-by: Alistair Francis Message-ID: <20230925175709.35696-14-dbarboza@ventanamicro.com> Signed-off-by: Alistair Francis --- target/riscv/cpu.c | 2 ++ target/riscv/cpu.h | 3 ++- target/riscv/kvm/kvm-cpu.c | 22 ++++++++++++++-------- 3 files changed, 18 insertions(+), 9 deletions(-) diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c index d8753240bf..cc439e5839 100644 --- a/target/riscv/cpu.c +++ b/target/riscv/cpu.c @@ -38,6 +38,8 @@ /* RISC-V CPU definitions */ static const char riscv_single_letter_exts[] = "IEMAFDQCPVH"; +const uint32_t misa_bits[] = {RVI, RVE, RVM, RVA, RVF, RVD, RVV, + RVC, RVS, RVU, RVH, RVJ, RVG, 0}; struct isa_ext_data { const char *name; diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h index d4b4ac3481..6f041d3333 100644 --- a/target/riscv/cpu.h +++ b/target/riscv/cpu.h @@ -43,7 +43,7 @@ #define RV(x) ((target_ulong)1 << (x - 'A')) /* - * Consider updating misa_ext_info_arr[] and misa_ext_cfgs[] + * Update misa_bits[], misa_ext_info_arr[] and misa_ext_cfgs[] * when adding new MISA bits here. */ #define RVI RV('I') @@ -60,6 +60,7 @@ #define RVJ RV('J') #define RVG RV('G') +extern const uint32_t misa_bits[]; const char *riscv_get_misa_ext_name(uint32_t bit); const char *riscv_get_misa_ext_description(uint32_t bit); diff --git a/target/riscv/kvm/kvm-cpu.c b/target/riscv/kvm/kvm-cpu.c index 606fdab223..c6615cb807 100644 --- a/target/riscv/kvm/kvm-cpu.c +++ b/target/riscv/kvm/kvm-cpu.c @@ -396,6 +396,8 @@ static void kvm_riscv_add_cpu_user_properties(Object *cpu_obj) { int i; + riscv_add_satp_mode_properties(cpu_obj); + for (i = 0; i < ARRAY_SIZE(kvm_misa_ext_cfgs); i++) { KVMCPUConfig *misa_cfg = &kvm_misa_ext_cfgs[i]; int bit = misa_cfg->offset; @@ -411,6 +413,11 @@ static void kvm_riscv_add_cpu_user_properties(Object *cpu_obj) misa_cfg->description); } + for (i = 0; misa_bits[i] != 0; i++) { + const char *ext_name = riscv_get_misa_ext_name(misa_bits[i]); + riscv_cpu_add_kvm_unavail_prop(cpu_obj, ext_name); + } + for (i = 0; i < ARRAY_SIZE(kvm_multi_ext_cfgs); i++) { KVMCPUConfig *multi_cfg = &kvm_multi_ext_cfgs[i]; @@ -427,6 +434,10 @@ static void kvm_riscv_add_cpu_user_properties(Object *cpu_obj) object_property_add(cpu_obj, "cboz_blocksize", "uint16", NULL, kvm_cpu_set_cbomz_blksize, NULL, &kvm_cboz_blocksize); + + riscv_cpu_add_kvm_unavail_prop_array(cpu_obj, riscv_cpu_extensions); + riscv_cpu_add_kvm_unavail_prop_array(cpu_obj, riscv_cpu_vendor_exts); + riscv_cpu_add_kvm_unavail_prop_array(cpu_obj, riscv_cpu_experimental_exts); } static int kvm_riscv_get_regs_core(CPUState *cs) @@ -801,7 +812,7 @@ static void kvm_riscv_init_multiext_cfg(RISCVCPU *cpu, KVMScratchCPU *kvmcpu) } } -static void riscv_init_user_properties(Object *cpu_obj) +static void riscv_init_kvm_registers(Object *cpu_obj) { RISCVCPU *cpu = RISCV_CPU(cpu_obj); KVMScratchCPU kvmcpu; @@ -810,7 +821,6 @@ static void riscv_init_user_properties(Object *cpu_obj) return; } - kvm_riscv_add_cpu_user_properties(cpu_obj); kvm_riscv_init_machine_ids(cpu, &kvmcpu); kvm_riscv_init_misa_ext_mask(cpu, &kvmcpu); kvm_riscv_init_multiext_cfg(cpu, &kvmcpu); @@ -1324,13 +1334,9 @@ static void kvm_cpu_instance_init(CPUState *cs) Object *obj = OBJECT(RISCV_CPU(cs)); DeviceState *dev = DEVICE(obj); - riscv_init_user_properties(obj); - riscv_add_satp_mode_properties(obj); - riscv_cpu_add_misa_properties(obj); + riscv_init_kvm_registers(obj); - riscv_cpu_add_kvm_unavail_prop_array(obj, riscv_cpu_extensions); - riscv_cpu_add_kvm_unavail_prop_array(obj, riscv_cpu_vendor_exts); - riscv_cpu_add_kvm_unavail_prop_array(obj, riscv_cpu_experimental_exts); + kvm_riscv_add_cpu_user_properties(obj); for (Property *prop = riscv_cpu_options; prop && prop->name; prop++) { /* Check if we have a specific KVM handler for the option */ From f51d03b01fac6cf2757d02efe1cc2679b1d133ac Mon Sep 17 00:00:00 2001 From: Daniel Henrique Barboza Date: Mon, 25 Sep 2023 14:57:04 -0300 Subject: [PATCH 0570/1077] target/riscv/cpu.c: export set_misa() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We'll move riscv_init_max_cpu_extensions() to tcg-cpu.c in the next patch and set_misa() needs to be usable from there. Rename it to riscv_cpu_set_misa() and make it public. Signed-off-by: Daniel Henrique Barboza Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Andrew Jones Reviewed-by: Alistair Francis Message-ID: <20230925175709.35696-15-dbarboza@ventanamicro.com> Signed-off-by: Alistair Francis --- target/riscv/cpu.c | 34 ++++++++++++++++++---------------- target/riscv/cpu.h | 1 + 2 files changed, 19 insertions(+), 16 deletions(-) diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c index cc439e5839..10846c2f4b 100644 --- a/target/riscv/cpu.c +++ b/target/riscv/cpu.c @@ -294,7 +294,7 @@ const char *riscv_cpu_get_trap_name(target_ulong cause, bool async) } } -static void set_misa(CPURISCVState *env, RISCVMXL mxl, uint32_t ext) +void riscv_cpu_set_misa(CPURISCVState *env, RISCVMXL mxl, uint32_t ext) { env->misa_mxl_max = env->misa_mxl = mxl; env->misa_ext_mask = env->misa_ext = ext; @@ -399,9 +399,9 @@ static void riscv_any_cpu_init(Object *obj) RISCVCPU *cpu = RISCV_CPU(obj); CPURISCVState *env = &cpu->env; #if defined(TARGET_RISCV32) - set_misa(env, MXL_RV32, RVI | RVM | RVA | RVF | RVD | RVC | RVU); + riscv_cpu_set_misa(env, MXL_RV32, RVI | RVM | RVA | RVF | RVD | RVC | RVU); #elif defined(TARGET_RISCV64) - set_misa(env, MXL_RV64, RVI | RVM | RVA | RVF | RVD | RVC | RVU); + riscv_cpu_set_misa(env, MXL_RV64, RVI | RVM | RVA | RVF | RVD | RVC | RVU); #endif #ifndef CONFIG_USER_ONLY @@ -428,7 +428,7 @@ static void riscv_max_cpu_init(Object *obj) #ifdef TARGET_RISCV32 mlx = MXL_RV32; #endif - set_misa(env, mlx, 0); + riscv_cpu_set_misa(env, mlx, 0); env->priv_ver = PRIV_VERSION_LATEST; #ifndef CONFIG_USER_ONLY set_satp_mode_max_supported(RISCV_CPU(obj), mlx == MXL_RV32 ? @@ -441,7 +441,7 @@ static void rv64_base_cpu_init(Object *obj) { CPURISCVState *env = &RISCV_CPU(obj)->env; /* We set this in the realise function */ - set_misa(env, MXL_RV64, 0); + riscv_cpu_set_misa(env, MXL_RV64, 0); /* Set latest version of privileged specification */ env->priv_ver = PRIV_VERSION_LATEST; #ifndef CONFIG_USER_ONLY @@ -453,7 +453,8 @@ static void rv64_sifive_u_cpu_init(Object *obj) { RISCVCPU *cpu = RISCV_CPU(obj); CPURISCVState *env = &cpu->env; - set_misa(env, MXL_RV64, RVI | RVM | RVA | RVF | RVD | RVC | RVS | RVU); + riscv_cpu_set_misa(env, MXL_RV64, + RVI | RVM | RVA | RVF | RVD | RVC | RVS | RVU); env->priv_ver = PRIV_VERSION_1_10_0; #ifndef CONFIG_USER_ONLY set_satp_mode_max_supported(RISCV_CPU(obj), VM_1_10_SV39); @@ -471,7 +472,7 @@ static void rv64_sifive_e_cpu_init(Object *obj) CPURISCVState *env = &RISCV_CPU(obj)->env; RISCVCPU *cpu = RISCV_CPU(obj); - set_misa(env, MXL_RV64, RVI | RVM | RVA | RVC | RVU); + riscv_cpu_set_misa(env, MXL_RV64, RVI | RVM | RVA | RVC | RVU); env->priv_ver = PRIV_VERSION_1_10_0; #ifndef CONFIG_USER_ONLY set_satp_mode_max_supported(cpu, VM_1_10_MBARE); @@ -488,7 +489,7 @@ static void rv64_thead_c906_cpu_init(Object *obj) CPURISCVState *env = &RISCV_CPU(obj)->env; RISCVCPU *cpu = RISCV_CPU(obj); - set_misa(env, MXL_RV64, RVG | RVC | RVS | RVU); + riscv_cpu_set_misa(env, MXL_RV64, RVG | RVC | RVS | RVU); env->priv_ver = PRIV_VERSION_1_11_0; cpu->cfg.ext_zfa = true; @@ -519,7 +520,7 @@ static void rv64_veyron_v1_cpu_init(Object *obj) CPURISCVState *env = &RISCV_CPU(obj)->env; RISCVCPU *cpu = RISCV_CPU(obj); - set_misa(env, MXL_RV64, RVG | RVC | RVS | RVU | RVH); + riscv_cpu_set_misa(env, MXL_RV64, RVG | RVC | RVS | RVU | RVH); env->priv_ver = PRIV_VERSION_1_12_0; /* Enable ISA extensions */ @@ -564,7 +565,7 @@ static void rv128_base_cpu_init(Object *obj) } CPURISCVState *env = &RISCV_CPU(obj)->env; /* We set this in the realise function */ - set_misa(env, MXL_RV128, 0); + riscv_cpu_set_misa(env, MXL_RV128, 0); /* Set latest version of privileged specification */ env->priv_ver = PRIV_VERSION_LATEST; #ifndef CONFIG_USER_ONLY @@ -576,7 +577,7 @@ static void rv32_base_cpu_init(Object *obj) { CPURISCVState *env = &RISCV_CPU(obj)->env; /* We set this in the realise function */ - set_misa(env, MXL_RV32, 0); + riscv_cpu_set_misa(env, MXL_RV32, 0); /* Set latest version of privileged specification */ env->priv_ver = PRIV_VERSION_LATEST; #ifndef CONFIG_USER_ONLY @@ -588,7 +589,8 @@ static void rv32_sifive_u_cpu_init(Object *obj) { RISCVCPU *cpu = RISCV_CPU(obj); CPURISCVState *env = &cpu->env; - set_misa(env, MXL_RV32, RVI | RVM | RVA | RVF | RVD | RVC | RVS | RVU); + riscv_cpu_set_misa(env, MXL_RV32, + RVI | RVM | RVA | RVF | RVD | RVC | RVS | RVU); env->priv_ver = PRIV_VERSION_1_10_0; #ifndef CONFIG_USER_ONLY set_satp_mode_max_supported(RISCV_CPU(obj), VM_1_10_SV32); @@ -606,7 +608,7 @@ static void rv32_sifive_e_cpu_init(Object *obj) CPURISCVState *env = &RISCV_CPU(obj)->env; RISCVCPU *cpu = RISCV_CPU(obj); - set_misa(env, MXL_RV32, RVI | RVM | RVA | RVC | RVU); + riscv_cpu_set_misa(env, MXL_RV32, RVI | RVM | RVA | RVC | RVU); env->priv_ver = PRIV_VERSION_1_10_0; #ifndef CONFIG_USER_ONLY set_satp_mode_max_supported(cpu, VM_1_10_MBARE); @@ -623,7 +625,7 @@ static void rv32_ibex_cpu_init(Object *obj) CPURISCVState *env = &RISCV_CPU(obj)->env; RISCVCPU *cpu = RISCV_CPU(obj); - set_misa(env, MXL_RV32, RVI | RVM | RVC | RVU); + riscv_cpu_set_misa(env, MXL_RV32, RVI | RVM | RVC | RVU); env->priv_ver = PRIV_VERSION_1_11_0; #ifndef CONFIG_USER_ONLY set_satp_mode_max_supported(cpu, VM_1_10_MBARE); @@ -641,7 +643,7 @@ static void rv32_imafcu_nommu_cpu_init(Object *obj) CPURISCVState *env = &RISCV_CPU(obj)->env; RISCVCPU *cpu = RISCV_CPU(obj); - set_misa(env, MXL_RV32, RVI | RVM | RVA | RVF | RVC | RVU); + riscv_cpu_set_misa(env, MXL_RV32, RVI | RVM | RVA | RVF | RVC | RVU); env->priv_ver = PRIV_VERSION_1_10_0; #ifndef CONFIG_USER_ONLY set_satp_mode_max_supported(cpu, VM_1_10_MBARE); @@ -1614,7 +1616,7 @@ static void riscv_init_max_cpu_extensions(Object *obj) const RISCVCPUMultiExtConfig *prop; /* Enable RVG, RVJ and RVV that are disabled by default */ - set_misa(env, env->misa_mxl, env->misa_ext | RVG | RVJ | RVV); + riscv_cpu_set_misa(env, env->misa_mxl, env->misa_ext | RVG | RVJ | RVV); for (prop = riscv_cpu_extensions; prop && prop->name; prop++) { isa_ext_update_enabled(cpu, prop->offset, true); diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h index 6f041d3333..7cc9f3d1fc 100644 --- a/target/riscv/cpu.h +++ b/target/riscv/cpu.h @@ -713,6 +713,7 @@ void isa_ext_update_enabled(RISCVCPU *cpu, uint32_t ext_offset, bool en); bool cpu_cfg_ext_is_user_set(uint32_t ext_offset); bool isa_ext_is_enabled(RISCVCPU *cpu, uint32_t ext_offset); int cpu_cfg_ext_get_min_version(uint32_t ext_offset); +void riscv_cpu_set_misa(CPURISCVState *env, RISCVMXL mxl, uint32_t ext); void riscv_cpu_disable_priv_spec_isa_exts(RISCVCPU *cpu); typedef struct RISCVCPUMultiExtConfig { From fce8bb5d088c655be18b1642e716489df608a0c4 Mon Sep 17 00:00:00 2001 From: Daniel Henrique Barboza Date: Mon, 25 Sep 2023 14:57:05 -0300 Subject: [PATCH 0571/1077] target/riscv/tcg: introduce tcg_cpu_instance_init() tcg_cpu_instance_init() will be the 'cpu_instance_init' impl for the TCG accelerator. It'll be called from within riscv_cpu_post_init(), via accel_cpu_instance_init(), similar to what happens with KVM. In fact, to preserve behavior, the implementation will be similar to what riscv_cpu_post_init() already does. In this patch we'll move riscv_cpu_add_user_properties() and riscv_init_max_cpu_extensions() and all their dependencies to tcg-cpu.c. All multi-extension properties code was moved. The 'multi_ext_user_opts' hash table was also moved to tcg-cpu.c since it's a TCG only structure, meaning that we won't have to worry about initializing a TCG hash table when running a KVM CPU anymore. riscv_cpu_add_user_properties() will remain in cpu.c for now due to how much code it requires to be moved at the same time. We'll do that in the next patch. Signed-off-by: Daniel Henrique Barboza Reviewed-by: Andrew Jones Reviewed-by: Alistair Francis Message-ID: <20230925175709.35696-16-dbarboza@ventanamicro.com> Signed-off-by: Alistair Francis --- target/riscv/cpu.c | 150 ------------------------------------- target/riscv/cpu.h | 1 - target/riscv/tcg/tcg-cpu.c | 149 ++++++++++++++++++++++++++++++++++++ 3 files changed, 149 insertions(+), 151 deletions(-) diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c index 10846c2f4b..40f9ad84f6 100644 --- a/target/riscv/cpu.c +++ b/target/riscv/cpu.c @@ -162,9 +162,6 @@ static const struct isa_ext_data isa_edata_arr[] = { ISA_EXT_DATA_ENTRY(xventanacondops, PRIV_VERSION_1_12_0, ext_XVentanaCondOps), }; -/* Hash that stores user set extensions */ -static GHashTable *multi_ext_user_opts; - bool isa_ext_is_enabled(RISCVCPU *cpu, uint32_t ext_offset) { bool *ext_enabled = (void *)&cpu->cfg + ext_offset; @@ -194,12 +191,6 @@ int cpu_cfg_ext_get_min_version(uint32_t ext_offset) g_assert_not_reached(); } -bool cpu_cfg_ext_is_user_set(uint32_t ext_offset) -{ - return g_hash_table_contains(multi_ext_user_opts, - GUINT_TO_POINTER(ext_offset)); -} - const char * const riscv_int_regnames[] = { "x0/zero", "x1/ra", "x2/sp", "x3/gp", "x4/tp", "x5/t0", "x6/t1", "x7/t2", "x8/s0", "x9/s1", "x10/a0", "x11/a1", "x12/a2", "x13/a3", @@ -280,9 +271,6 @@ static const char * const riscv_intr_names[] = { "reserved" }; -static void riscv_cpu_add_user_properties(Object *obj); -static void riscv_init_max_cpu_extensions(Object *obj); - const char *riscv_cpu_get_trap_name(target_ulong cause, bool async) { if (async) { @@ -1206,32 +1194,9 @@ static bool riscv_cpu_is_dynamic(Object *cpu_obj) return object_dynamic_cast(cpu_obj, TYPE_RISCV_DYNAMIC_CPU) != NULL; } -static bool riscv_cpu_has_max_extensions(Object *cpu_obj) -{ - return object_dynamic_cast(cpu_obj, TYPE_RISCV_CPU_MAX) != NULL; -} - -static bool riscv_cpu_has_user_properties(Object *cpu_obj) -{ - if (kvm_enabled() && - object_dynamic_cast(cpu_obj, TYPE_RISCV_CPU_HOST) != NULL) { - return true; - } - - return riscv_cpu_is_dynamic(cpu_obj); -} - static void riscv_cpu_post_init(Object *obj) { accel_cpu_instance_init(CPU(obj)); - - if (tcg_enabled() && riscv_cpu_has_user_properties(obj)) { - riscv_cpu_add_user_properties(obj); - } - - if (riscv_cpu_has_max_extensions(obj)) { - riscv_init_max_cpu_extensions(obj); - } } static void riscv_cpu_init(Object *obj) @@ -1240,8 +1205,6 @@ static void riscv_cpu_init(Object *obj) qdev_init_gpio_in(DEVICE(obj), riscv_cpu_set_irq, IRQ_LOCAL_MAX + IRQ_LOCAL_GUEST_MAX); #endif /* CONFIG_USER_ONLY */ - - multi_ext_user_opts = g_hash_table_new(NULL, g_direct_equal); } typedef struct RISCVCPUMisaExtConfig { @@ -1527,119 +1490,6 @@ Property riscv_cpu_options[] = { DEFINE_PROP_END_OF_LIST(), }; -static void cpu_set_multi_ext_cfg(Object *obj, Visitor *v, const char *name, - void *opaque, Error **errp) -{ - const RISCVCPUMultiExtConfig *multi_ext_cfg = opaque; - bool value; - - if (!visit_type_bool(v, name, &value, errp)) { - return; - } - - isa_ext_update_enabled(RISCV_CPU(obj), multi_ext_cfg->offset, value); - - g_hash_table_insert(multi_ext_user_opts, - GUINT_TO_POINTER(multi_ext_cfg->offset), - (gpointer)value); -} - -static void cpu_get_multi_ext_cfg(Object *obj, Visitor *v, const char *name, - void *opaque, Error **errp) -{ - const RISCVCPUMultiExtConfig *multi_ext_cfg = opaque; - bool value = isa_ext_is_enabled(RISCV_CPU(obj), multi_ext_cfg->offset); - - visit_type_bool(v, name, &value, errp); -} - -static void cpu_add_multi_ext_prop(Object *cpu_obj, - const RISCVCPUMultiExtConfig *multi_cfg) -{ - object_property_add(cpu_obj, multi_cfg->name, "bool", - cpu_get_multi_ext_cfg, - cpu_set_multi_ext_cfg, - NULL, (void *)multi_cfg); - - /* - * Set def val directly instead of using - * object_property_set_bool() to save the set() - * callback hash for user inputs. - */ - isa_ext_update_enabled(RISCV_CPU(cpu_obj), multi_cfg->offset, - multi_cfg->enabled); -} - -static void riscv_cpu_add_multiext_prop_array(Object *obj, - const RISCVCPUMultiExtConfig *array) -{ - const RISCVCPUMultiExtConfig *prop; - - g_assert(array); - - for (prop = array; prop && prop->name; prop++) { - cpu_add_multi_ext_prop(obj, prop); - } -} - -/* - * Add CPU properties with user-facing flags. - * - * This will overwrite existing env->misa_ext values with the - * defaults set via riscv_cpu_add_misa_properties(). - */ -static void riscv_cpu_add_user_properties(Object *obj) -{ -#ifndef CONFIG_USER_ONLY - riscv_add_satp_mode_properties(obj); -#endif - - riscv_cpu_add_misa_properties(obj); - - riscv_cpu_add_multiext_prop_array(obj, riscv_cpu_extensions); - riscv_cpu_add_multiext_prop_array(obj, riscv_cpu_vendor_exts); - riscv_cpu_add_multiext_prop_array(obj, riscv_cpu_experimental_exts); - - for (Property *prop = riscv_cpu_options; prop && prop->name; prop++) { - qdev_property_add_static(DEVICE(obj), prop); - } -} - -/* - * The 'max' type CPU will have all possible ratified - * non-vendor extensions enabled. - */ -static void riscv_init_max_cpu_extensions(Object *obj) -{ - RISCVCPU *cpu = RISCV_CPU(obj); - CPURISCVState *env = &cpu->env; - const RISCVCPUMultiExtConfig *prop; - - /* Enable RVG, RVJ and RVV that are disabled by default */ - riscv_cpu_set_misa(env, env->misa_mxl, env->misa_ext | RVG | RVJ | RVV); - - for (prop = riscv_cpu_extensions; prop && prop->name; prop++) { - isa_ext_update_enabled(cpu, prop->offset, true); - } - - /* set vector version */ - env->vext_ver = VEXT_VERSION_1_00_0; - - /* Zfinx is not compatible with F. Disable it */ - isa_ext_update_enabled(cpu, CPU_CFG_OFFSET(ext_zfinx), false); - isa_ext_update_enabled(cpu, CPU_CFG_OFFSET(ext_zdinx), false); - isa_ext_update_enabled(cpu, CPU_CFG_OFFSET(ext_zhinx), false); - isa_ext_update_enabled(cpu, CPU_CFG_OFFSET(ext_zhinxmin), false); - - isa_ext_update_enabled(cpu, CPU_CFG_OFFSET(ext_zce), false); - isa_ext_update_enabled(cpu, CPU_CFG_OFFSET(ext_zcmp), false); - isa_ext_update_enabled(cpu, CPU_CFG_OFFSET(ext_zcmt), false); - - if (env->misa_mxl != MXL_RV32) { - isa_ext_update_enabled(cpu, CPU_CFG_OFFSET(ext_zcf), false); - } -} - static Property riscv_cpu_properties[] = { DEFINE_PROP_BOOL("debug", RISCVCPU, cfg.debug, true), diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h index 7cc9f3d1fc..9d41beafec 100644 --- a/target/riscv/cpu.h +++ b/target/riscv/cpu.h @@ -710,7 +710,6 @@ enum riscv_pmu_event_idx { /* used by tcg/tcg-cpu.c*/ void isa_ext_update_enabled(RISCVCPU *cpu, uint32_t ext_offset, bool en); -bool cpu_cfg_ext_is_user_set(uint32_t ext_offset); bool isa_ext_is_enabled(RISCVCPU *cpu, uint32_t ext_offset); int cpu_cfg_ext_get_min_version(uint32_t ext_offset); void riscv_cpu_set_misa(CPURISCVState *env, RISCVMXL mxl, uint32_t ext); diff --git a/target/riscv/tcg/tcg-cpu.c b/target/riscv/tcg/tcg-cpu.c index c92dfc20cb..30740ba030 100644 --- a/target/riscv/tcg/tcg-cpu.c +++ b/target/riscv/tcg/tcg-cpu.c @@ -24,6 +24,7 @@ #include "pmu.h" #include "time_helper.h" #include "qapi/error.h" +#include "qapi/visitor.h" #include "qemu/accel.h" #include "qemu/error-report.h" #include "qemu/log.h" @@ -31,6 +32,15 @@ #include "hw/core/tcg-cpu-ops.h" #include "tcg/tcg.h" +/* Hash that stores user set extensions */ +static GHashTable *multi_ext_user_opts; + +static bool cpu_cfg_ext_is_user_set(uint32_t ext_offset) +{ + return g_hash_table_contains(multi_ext_user_opts, + GUINT_TO_POINTER(ext_offset)); +} + static void riscv_cpu_synchronize_from_tb(CPUState *cs, const TranslationBlock *tb) { @@ -570,6 +580,144 @@ static bool tcg_cpu_realize(CPUState *cs, Error **errp) return true; } +static void cpu_set_multi_ext_cfg(Object *obj, Visitor *v, const char *name, + void *opaque, Error **errp) +{ + const RISCVCPUMultiExtConfig *multi_ext_cfg = opaque; + bool value; + + if (!visit_type_bool(v, name, &value, errp)) { + return; + } + + isa_ext_update_enabled(RISCV_CPU(obj), multi_ext_cfg->offset, value); + + g_hash_table_insert(multi_ext_user_opts, + GUINT_TO_POINTER(multi_ext_cfg->offset), + (gpointer)value); +} + +static void cpu_get_multi_ext_cfg(Object *obj, Visitor *v, const char *name, + void *opaque, Error **errp) +{ + const RISCVCPUMultiExtConfig *multi_ext_cfg = opaque; + bool value = isa_ext_is_enabled(RISCV_CPU(obj), multi_ext_cfg->offset); + + visit_type_bool(v, name, &value, errp); +} + +static void cpu_add_multi_ext_prop(Object *cpu_obj, + const RISCVCPUMultiExtConfig *multi_cfg) +{ + object_property_add(cpu_obj, multi_cfg->name, "bool", + cpu_get_multi_ext_cfg, + cpu_set_multi_ext_cfg, + NULL, (void *)multi_cfg); + + /* + * Set def val directly instead of using + * object_property_set_bool() to save the set() + * callback hash for user inputs. + */ + isa_ext_update_enabled(RISCV_CPU(cpu_obj), multi_cfg->offset, + multi_cfg->enabled); +} + +static void riscv_cpu_add_multiext_prop_array(Object *obj, + const RISCVCPUMultiExtConfig *array) +{ + const RISCVCPUMultiExtConfig *prop; + + g_assert(array); + + for (prop = array; prop && prop->name; prop++) { + cpu_add_multi_ext_prop(obj, prop); + } +} + +/* + * Add CPU properties with user-facing flags. + * + * This will overwrite existing env->misa_ext values with the + * defaults set via riscv_cpu_add_misa_properties(). + */ +static void riscv_cpu_add_user_properties(Object *obj) +{ +#ifndef CONFIG_USER_ONLY + riscv_add_satp_mode_properties(obj); +#endif + + riscv_cpu_add_misa_properties(obj); + + riscv_cpu_add_multiext_prop_array(obj, riscv_cpu_extensions); + riscv_cpu_add_multiext_prop_array(obj, riscv_cpu_vendor_exts); + riscv_cpu_add_multiext_prop_array(obj, riscv_cpu_experimental_exts); + + for (Property *prop = riscv_cpu_options; prop && prop->name; prop++) { + qdev_property_add_static(DEVICE(obj), prop); + } +} + +/* + * The 'max' type CPU will have all possible ratified + * non-vendor extensions enabled. + */ +static void riscv_init_max_cpu_extensions(Object *obj) +{ + RISCVCPU *cpu = RISCV_CPU(obj); + CPURISCVState *env = &cpu->env; + const RISCVCPUMultiExtConfig *prop; + + /* Enable RVG, RVJ and RVV that are disabled by default */ + riscv_cpu_set_misa(env, env->misa_mxl, env->misa_ext | RVG | RVJ | RVV); + + for (prop = riscv_cpu_extensions; prop && prop->name; prop++) { + isa_ext_update_enabled(cpu, prop->offset, true); + } + + /* set vector version */ + env->vext_ver = VEXT_VERSION_1_00_0; + + /* Zfinx is not compatible with F. Disable it */ + isa_ext_update_enabled(cpu, CPU_CFG_OFFSET(ext_zfinx), false); + isa_ext_update_enabled(cpu, CPU_CFG_OFFSET(ext_zdinx), false); + isa_ext_update_enabled(cpu, CPU_CFG_OFFSET(ext_zhinx), false); + isa_ext_update_enabled(cpu, CPU_CFG_OFFSET(ext_zhinxmin), false); + + isa_ext_update_enabled(cpu, CPU_CFG_OFFSET(ext_zce), false); + isa_ext_update_enabled(cpu, CPU_CFG_OFFSET(ext_zcmp), false); + isa_ext_update_enabled(cpu, CPU_CFG_OFFSET(ext_zcmt), false); + + if (env->misa_mxl != MXL_RV32) { + isa_ext_update_enabled(cpu, CPU_CFG_OFFSET(ext_zcf), false); + } +} + +static bool riscv_cpu_has_max_extensions(Object *cpu_obj) +{ + return object_dynamic_cast(cpu_obj, TYPE_RISCV_CPU_MAX) != NULL; +} + +static bool riscv_cpu_has_user_properties(Object *cpu_obj) +{ + return object_dynamic_cast(cpu_obj, TYPE_RISCV_DYNAMIC_CPU) != NULL; +} + +static void tcg_cpu_instance_init(CPUState *cs) +{ + RISCVCPU *cpu = RISCV_CPU(cs); + Object *obj = OBJECT(cpu); + + if (riscv_cpu_has_user_properties(obj)) { + multi_ext_user_opts = g_hash_table_new(NULL, g_direct_equal); + riscv_cpu_add_user_properties(obj); + } + + if (riscv_cpu_has_max_extensions(obj)) { + riscv_init_max_cpu_extensions(obj); + } +} + static void tcg_cpu_init_ops(AccelCPUClass *accel_cpu, CPUClass *cc) { /* @@ -588,6 +736,7 @@ static void tcg_cpu_accel_class_init(ObjectClass *oc, void *data) AccelCPUClass *acc = ACCEL_CPU_CLASS(oc); acc->cpu_class_init = tcg_cpu_class_init; + acc->cpu_instance_init = tcg_cpu_instance_init; acc->cpu_target_realize = tcg_cpu_realize; } From 1dbb6104ffb428f3a559855a49c28b91c8d3b401 Mon Sep 17 00:00:00 2001 From: Daniel Henrique Barboza Date: Mon, 25 Sep 2023 14:57:06 -0300 Subject: [PATCH 0572/1077] target/riscv/cpu.c: make misa_ext_cfgs[] 'const' The array isn't marked as 'const' because we're initializing their elements in riscv_cpu_add_misa_properties(), 'name' and 'description' fields. In a closer look we can see that we're not using these 2 fields after creating the MISA properties. And we can create the properties by using riscv_get_misa_ext_name() and riscv_get_misa_ext_description() directly. Remove the 'name' and 'description' fields from RISCVCPUMisaExtConfig and make misa_ext_cfgs[] a const array. Signed-off-by: Daniel Henrique Barboza Reviewed-by: Andrew Jones Reviewed-by: Alistair Francis Message-ID: <20230925175709.35696-17-dbarboza@ventanamicro.com> Signed-off-by: Alistair Francis --- target/riscv/cpu.c | 21 ++++++++------------- 1 file changed, 8 insertions(+), 13 deletions(-) diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c index 40f9ad84f6..1c42e2590e 100644 --- a/target/riscv/cpu.c +++ b/target/riscv/cpu.c @@ -1208,8 +1208,6 @@ static void riscv_cpu_init(Object *obj) } typedef struct RISCVCPUMisaExtConfig { - const char *name; - const char *description; target_ulong misa_bit; bool enabled; } RISCVCPUMisaExtConfig; @@ -1313,7 +1311,7 @@ const char *riscv_get_misa_ext_description(uint32_t bit) #define MISA_CFG(_bit, _enabled) \ {.misa_bit = _bit, .enabled = _enabled} -static RISCVCPUMisaExtConfig misa_ext_cfgs[] = { +static const RISCVCPUMisaExtConfig misa_ext_cfgs[] = { MISA_CFG(RVA, true), MISA_CFG(RVC, true), MISA_CFG(RVD, true), @@ -1340,25 +1338,22 @@ void riscv_cpu_add_misa_properties(Object *cpu_obj) int i; for (i = 0; i < ARRAY_SIZE(misa_ext_cfgs); i++) { - RISCVCPUMisaExtConfig *misa_cfg = &misa_ext_cfgs[i]; + const RISCVCPUMisaExtConfig *misa_cfg = &misa_ext_cfgs[i]; int bit = misa_cfg->misa_bit; - - misa_cfg->name = riscv_get_misa_ext_name(bit); - misa_cfg->description = riscv_get_misa_ext_description(bit); + const char *name = riscv_get_misa_ext_name(bit); + const char *desc = riscv_get_misa_ext_description(bit); /* Check if KVM already created the property */ - if (object_property_find(cpu_obj, misa_cfg->name)) { + if (object_property_find(cpu_obj, name)) { continue; } - object_property_add(cpu_obj, misa_cfg->name, "bool", + object_property_add(cpu_obj, name, "bool", cpu_get_misa_ext_cfg, cpu_set_misa_ext_cfg, NULL, (void *)misa_cfg); - object_property_set_description(cpu_obj, misa_cfg->name, - misa_cfg->description); - object_property_set_bool(cpu_obj, misa_cfg->name, - misa_cfg->enabled, NULL); + object_property_set_description(cpu_obj, name, desc); + object_property_set_bool(cpu_obj, name, misa_cfg->enabled, NULL); } } From 4de9151b20ad0b33ea975e84b437bc15a804375d Mon Sep 17 00:00:00 2001 From: Daniel Henrique Barboza Date: Mon, 25 Sep 2023 14:57:07 -0300 Subject: [PATCH 0573/1077] target/riscv/tcg: move riscv_cpu_add_misa_properties() to tcg-cpu.c All code related to MISA TCG properties is also moved. At this point, all TCG properties handling is done in tcg-cpu.c, all KVM properties handling is done in kvm-cpu.c. Signed-off-by: Daniel Henrique Barboza Reviewed-by: Andrew Jones Reviewed-by: Alistair Francis Message-ID: <20230925175709.35696-18-dbarboza@ventanamicro.com> Signed-off-by: Alistair Francis --- target/riscv/cpu.c | 90 -------------------------------------- target/riscv/cpu.h | 1 - target/riscv/tcg/tcg-cpu.c | 90 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 90 insertions(+), 91 deletions(-) diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c index 1c42e2590e..d758d61ff8 100644 --- a/target/riscv/cpu.c +++ b/target/riscv/cpu.c @@ -1207,47 +1207,6 @@ static void riscv_cpu_init(Object *obj) #endif /* CONFIG_USER_ONLY */ } -typedef struct RISCVCPUMisaExtConfig { - target_ulong misa_bit; - bool enabled; -} RISCVCPUMisaExtConfig; - -static void cpu_set_misa_ext_cfg(Object *obj, Visitor *v, const char *name, - void *opaque, Error **errp) -{ - const RISCVCPUMisaExtConfig *misa_ext_cfg = opaque; - target_ulong misa_bit = misa_ext_cfg->misa_bit; - RISCVCPU *cpu = RISCV_CPU(obj); - CPURISCVState *env = &cpu->env; - bool value; - - if (!visit_type_bool(v, name, &value, errp)) { - return; - } - - if (value) { - env->misa_ext |= misa_bit; - env->misa_ext_mask |= misa_bit; - } else { - env->misa_ext &= ~misa_bit; - env->misa_ext_mask &= ~misa_bit; - } -} - -static void cpu_get_misa_ext_cfg(Object *obj, Visitor *v, const char *name, - void *opaque, Error **errp) -{ - const RISCVCPUMisaExtConfig *misa_ext_cfg = opaque; - target_ulong misa_bit = misa_ext_cfg->misa_bit; - RISCVCPU *cpu = RISCV_CPU(obj); - CPURISCVState *env = &cpu->env; - bool value; - - value = env->misa_ext & misa_bit; - - visit_type_bool(v, name, &value, errp); -} - typedef struct misa_ext_info { const char *name; const char *description; @@ -1308,55 +1267,6 @@ const char *riscv_get_misa_ext_description(uint32_t bit) return val; } -#define MISA_CFG(_bit, _enabled) \ - {.misa_bit = _bit, .enabled = _enabled} - -static const RISCVCPUMisaExtConfig misa_ext_cfgs[] = { - MISA_CFG(RVA, true), - MISA_CFG(RVC, true), - MISA_CFG(RVD, true), - MISA_CFG(RVF, true), - MISA_CFG(RVI, true), - MISA_CFG(RVE, false), - MISA_CFG(RVM, true), - MISA_CFG(RVS, true), - MISA_CFG(RVU, true), - MISA_CFG(RVH, true), - MISA_CFG(RVJ, false), - MISA_CFG(RVV, false), - MISA_CFG(RVG, false), -}; - -/* - * We do not support user choice tracking for MISA - * extensions yet because, so far, we do not silently - * change MISA bits during realize() (RVG enables MISA - * bits but the user is warned about it). - */ -void riscv_cpu_add_misa_properties(Object *cpu_obj) -{ - int i; - - for (i = 0; i < ARRAY_SIZE(misa_ext_cfgs); i++) { - const RISCVCPUMisaExtConfig *misa_cfg = &misa_ext_cfgs[i]; - int bit = misa_cfg->misa_bit; - const char *name = riscv_get_misa_ext_name(bit); - const char *desc = riscv_get_misa_ext_description(bit); - - /* Check if KVM already created the property */ - if (object_property_find(cpu_obj, name)) { - continue; - } - - object_property_add(cpu_obj, name, "bool", - cpu_get_misa_ext_cfg, - cpu_set_misa_ext_cfg, - NULL, (void *)misa_cfg); - object_property_set_description(cpu_obj, name, desc); - object_property_set_bool(cpu_obj, name, misa_cfg->enabled, NULL); - } -} - #define MULTI_EXT_CFG_BOOL(_name, _prop, _defval) \ {.name = _name, .offset = CPU_CFG_OFFSET(_prop), \ .enabled = _defval} diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h index 9d41beafec..089c7e6d95 100644 --- a/target/riscv/cpu.h +++ b/target/riscv/cpu.h @@ -726,7 +726,6 @@ extern const RISCVCPUMultiExtConfig riscv_cpu_vendor_exts[]; extern const RISCVCPUMultiExtConfig riscv_cpu_experimental_exts[]; extern Property riscv_cpu_options[]; -void riscv_cpu_add_misa_properties(Object *cpu_obj); void riscv_add_satp_mode_properties(Object *obj); /* CSR function table */ diff --git a/target/riscv/tcg/tcg-cpu.c b/target/riscv/tcg/tcg-cpu.c index 30740ba030..ef981ad0ce 100644 --- a/target/riscv/tcg/tcg-cpu.c +++ b/target/riscv/tcg/tcg-cpu.c @@ -580,6 +580,96 @@ static bool tcg_cpu_realize(CPUState *cs, Error **errp) return true; } +typedef struct RISCVCPUMisaExtConfig { + target_ulong misa_bit; + bool enabled; +} RISCVCPUMisaExtConfig; + +static void cpu_set_misa_ext_cfg(Object *obj, Visitor *v, const char *name, + void *opaque, Error **errp) +{ + const RISCVCPUMisaExtConfig *misa_ext_cfg = opaque; + target_ulong misa_bit = misa_ext_cfg->misa_bit; + RISCVCPU *cpu = RISCV_CPU(obj); + CPURISCVState *env = &cpu->env; + bool value; + + if (!visit_type_bool(v, name, &value, errp)) { + return; + } + + if (value) { + env->misa_ext |= misa_bit; + env->misa_ext_mask |= misa_bit; + } else { + env->misa_ext &= ~misa_bit; + env->misa_ext_mask &= ~misa_bit; + } +} + +static void cpu_get_misa_ext_cfg(Object *obj, Visitor *v, const char *name, + void *opaque, Error **errp) +{ + const RISCVCPUMisaExtConfig *misa_ext_cfg = opaque; + target_ulong misa_bit = misa_ext_cfg->misa_bit; + RISCVCPU *cpu = RISCV_CPU(obj); + CPURISCVState *env = &cpu->env; + bool value; + + value = env->misa_ext & misa_bit; + + visit_type_bool(v, name, &value, errp); +} + +#define MISA_CFG(_bit, _enabled) \ + {.misa_bit = _bit, .enabled = _enabled} + +static const RISCVCPUMisaExtConfig misa_ext_cfgs[] = { + MISA_CFG(RVA, true), + MISA_CFG(RVC, true), + MISA_CFG(RVD, true), + MISA_CFG(RVF, true), + MISA_CFG(RVI, true), + MISA_CFG(RVE, false), + MISA_CFG(RVM, true), + MISA_CFG(RVS, true), + MISA_CFG(RVU, true), + MISA_CFG(RVH, true), + MISA_CFG(RVJ, false), + MISA_CFG(RVV, false), + MISA_CFG(RVG, false), +}; + +/* + * We do not support user choice tracking for MISA + * extensions yet because, so far, we do not silently + * change MISA bits during realize() (RVG enables MISA + * bits but the user is warned about it). + */ +static void riscv_cpu_add_misa_properties(Object *cpu_obj) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(misa_ext_cfgs); i++) { + const RISCVCPUMisaExtConfig *misa_cfg = &misa_ext_cfgs[i]; + int bit = misa_cfg->misa_bit; + const char *name = riscv_get_misa_ext_name(bit); + const char *desc = riscv_get_misa_ext_description(bit); + + /* Check if KVM already created the property */ + if (object_property_find(cpu_obj, name)) { + continue; + } + + object_property_add(cpu_obj, name, "bool", + cpu_get_misa_ext_cfg, + cpu_set_misa_ext_cfg, + NULL, (void *)misa_cfg); + object_property_set_description(cpu_obj, name, desc); + object_property_set_bool(cpu_obj, name, misa_cfg->enabled, NULL); + } +} + static void cpu_set_multi_ext_cfg(Object *obj, Visitor *v, const char *name, void *opaque, Error **errp) { From 7935e2c49c1ecb7b106d62bd91791cc02eea71ef Mon Sep 17 00:00:00 2001 From: Daniel Henrique Barboza Date: Mon, 25 Sep 2023 14:57:08 -0300 Subject: [PATCH 0574/1077] target/riscv/cpu.c: export isa_edata_arr[] This array will be read by the TCG accel class, allowing it to handle priv spec verifications on its own. The array will remain here in cpu.c because it's also used by the riscv,isa string function. To export it we'll finish it with an empty element since ARRAY_SIZE() won't work outside of cpu.c. Get rid of its ARRAY_SIZE() usage now to alleviate the changes for the next patch. Signed-off-by: Daniel Henrique Barboza Reviewed-by: Andrew Jones Reviewed-by: Alistair Francis Message-ID: <20230925175709.35696-19-dbarboza@ventanamicro.com> Signed-off-by: Alistair Francis --- target/riscv/cpu.c | 47 +++++++++++++++++++++------------------------- target/riscv/cpu.h | 7 +++++++ 2 files changed, 28 insertions(+), 26 deletions(-) diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c index d758d61ff8..989610ff90 100644 --- a/target/riscv/cpu.c +++ b/target/riscv/cpu.c @@ -41,15 +41,6 @@ static const char riscv_single_letter_exts[] = "IEMAFDQCPVH"; const uint32_t misa_bits[] = {RVI, RVE, RVM, RVA, RVF, RVD, RVV, RVC, RVS, RVU, RVH, RVJ, RVG, 0}; -struct isa_ext_data { - const char *name; - int min_version; - int ext_enable_offset; -}; - -#define ISA_EXT_DATA_ENTRY(_name, _min_ver, _prop) \ - {#_name, _min_ver, CPU_CFG_OFFSET(_prop)} - /* * From vector_helper.c * Note that vector data is stored in host-endian 64-bit chunks, @@ -61,6 +52,9 @@ struct isa_ext_data { #define BYTE(x) (x) #endif +#define ISA_EXT_DATA_ENTRY(_name, _min_ver, _prop) \ + {#_name, _min_ver, CPU_CFG_OFFSET(_prop)} + /* * Here are the ordering rules of extension naming defined by RISC-V * specification : @@ -81,7 +75,7 @@ struct isa_ext_data { * Single letter extensions are checked in riscv_cpu_validate_misa_priv() * instead. */ -static const struct isa_ext_data isa_edata_arr[] = { +const RISCVIsaExtData isa_edata_arr[] = { ISA_EXT_DATA_ENTRY(zicbom, PRIV_VERSION_1_12_0, ext_icbom), ISA_EXT_DATA_ENTRY(zicboz, PRIV_VERSION_1_12_0, ext_icboz), ISA_EXT_DATA_ENTRY(zicond, PRIV_VERSION_1_12_0, ext_zicond), @@ -160,6 +154,8 @@ static const struct isa_ext_data isa_edata_arr[] = { ISA_EXT_DATA_ENTRY(xtheadmempair, PRIV_VERSION_1_11_0, ext_xtheadmempair), ISA_EXT_DATA_ENTRY(xtheadsync, PRIV_VERSION_1_11_0, ext_xtheadsync), ISA_EXT_DATA_ENTRY(xventanacondops, PRIV_VERSION_1_12_0, ext_XVentanaCondOps), + + DEFINE_PROP_END_OF_LIST(), }; bool isa_ext_is_enabled(RISCVCPU *cpu, uint32_t ext_offset) @@ -178,14 +174,14 @@ void isa_ext_update_enabled(RISCVCPU *cpu, uint32_t ext_offset, bool en) int cpu_cfg_ext_get_min_version(uint32_t ext_offset) { - int i; + const RISCVIsaExtData *edata; - for (i = 0; i < ARRAY_SIZE(isa_edata_arr); i++) { - if (isa_edata_arr[i].ext_enable_offset != ext_offset) { + for (edata = isa_edata_arr; edata && edata->name; edata++) { + if (edata->ext_enable_offset != ext_offset) { continue; } - return isa_edata_arr[i].min_version; + return edata->min_version; } g_assert_not_reached(); @@ -932,22 +928,21 @@ static void riscv_cpu_disas_set_info(CPUState *s, disassemble_info *info) void riscv_cpu_disable_priv_spec_isa_exts(RISCVCPU *cpu) { CPURISCVState *env = &cpu->env; - int i; + const RISCVIsaExtData *edata; /* Force disable extensions if priv spec version does not match */ - for (i = 0; i < ARRAY_SIZE(isa_edata_arr); i++) { - if (isa_ext_is_enabled(cpu, isa_edata_arr[i].ext_enable_offset) && - (env->priv_ver < isa_edata_arr[i].min_version)) { - isa_ext_update_enabled(cpu, isa_edata_arr[i].ext_enable_offset, - false); + for (edata = isa_edata_arr; edata && edata->name; edata++) { + if (isa_ext_is_enabled(cpu, edata->ext_enable_offset) && + (env->priv_ver < edata->min_version)) { + isa_ext_update_enabled(cpu, edata->ext_enable_offset, false); #ifndef CONFIG_USER_ONLY warn_report("disabling %s extension for hart 0x" TARGET_FMT_lx " because privilege spec version does not match", - isa_edata_arr[i].name, env->mhartid); + edata->name, env->mhartid); #else warn_report("disabling %s extension because " "privilege spec version does not match", - isa_edata_arr[i].name); + edata->name); #endif } } @@ -1615,13 +1610,13 @@ static void riscv_cpu_class_init(ObjectClass *c, void *data) static void riscv_isa_string_ext(RISCVCPU *cpu, char **isa_str, int max_str_len) { + const RISCVIsaExtData *edata; char *old = *isa_str; char *new = *isa_str; - int i; - for (i = 0; i < ARRAY_SIZE(isa_edata_arr); i++) { - if (isa_ext_is_enabled(cpu, isa_edata_arr[i].ext_enable_offset)) { - new = g_strconcat(old, "_", isa_edata_arr[i].name, NULL); + for (edata = isa_edata_arr; edata && edata->name; edata++) { + if (isa_ext_is_enabled(cpu, edata->ext_enable_offset)) { + new = g_strconcat(old, "_", edata->name, NULL); g_free(old); old = new; } diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h index 089c7e6d95..6eef1f697e 100644 --- a/target/riscv/cpu.h +++ b/target/riscv/cpu.h @@ -726,6 +726,13 @@ extern const RISCVCPUMultiExtConfig riscv_cpu_vendor_exts[]; extern const RISCVCPUMultiExtConfig riscv_cpu_experimental_exts[]; extern Property riscv_cpu_options[]; +typedef struct isa_ext_data { + const char *name; + int min_version; + int ext_enable_offset; +} RISCVIsaExtData; +extern const RISCVIsaExtData isa_edata_arr[]; + void riscv_add_satp_mode_properties(Object *obj); /* CSR function table */ From 31778448f2c39565062014ae89ca8c2f82522fe5 Mon Sep 17 00:00:00 2001 From: Daniel Henrique Barboza Date: Mon, 25 Sep 2023 14:57:09 -0300 Subject: [PATCH 0575/1077] target/riscv/cpu: move priv spec functions to tcg-cpu.c MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Priv spec validation is TCG specific. Move it to the TCG accel class. Signed-off-by: Daniel Henrique Barboza Reviewed-by: Andrew Jones Reviewed-by: Alistair Francis Reviewed-by: Philippe Mathieu-Daudé Message-ID: <20230925175709.35696-20-dbarboza@ventanamicro.com> Signed-off-by: Alistair Francis --- target/riscv/cpu.c | 38 -------------------------------------- target/riscv/cpu.h | 2 -- target/riscv/tcg/tcg-cpu.c | 38 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 38 insertions(+), 40 deletions(-) diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c index 989610ff90..a7cc7aa6e2 100644 --- a/target/riscv/cpu.c +++ b/target/riscv/cpu.c @@ -172,21 +172,6 @@ void isa_ext_update_enabled(RISCVCPU *cpu, uint32_t ext_offset, bool en) *ext_enabled = en; } -int cpu_cfg_ext_get_min_version(uint32_t ext_offset) -{ - const RISCVIsaExtData *edata; - - for (edata = isa_edata_arr; edata && edata->name; edata++) { - if (edata->ext_enable_offset != ext_offset) { - continue; - } - - return edata->min_version; - } - - g_assert_not_reached(); -} - const char * const riscv_int_regnames[] = { "x0/zero", "x1/ra", "x2/sp", "x3/gp", "x4/tp", "x5/t0", "x6/t1", "x7/t2", "x8/s0", "x9/s1", "x10/a0", "x11/a1", "x12/a2", "x13/a3", @@ -925,29 +910,6 @@ static void riscv_cpu_disas_set_info(CPUState *s, disassemble_info *info) } } -void riscv_cpu_disable_priv_spec_isa_exts(RISCVCPU *cpu) -{ - CPURISCVState *env = &cpu->env; - const RISCVIsaExtData *edata; - - /* Force disable extensions if priv spec version does not match */ - for (edata = isa_edata_arr; edata && edata->name; edata++) { - if (isa_ext_is_enabled(cpu, edata->ext_enable_offset) && - (env->priv_ver < edata->min_version)) { - isa_ext_update_enabled(cpu, edata->ext_enable_offset, false); -#ifndef CONFIG_USER_ONLY - warn_report("disabling %s extension for hart 0x" TARGET_FMT_lx - " because privilege spec version does not match", - edata->name, env->mhartid); -#else - warn_report("disabling %s extension because " - "privilege spec version does not match", - edata->name); -#endif - } - } -} - #ifndef CONFIG_USER_ONLY static void riscv_cpu_satp_mode_finalize(RISCVCPU *cpu, Error **errp) { diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h index 6eef1f697e..7291b84756 100644 --- a/target/riscv/cpu.h +++ b/target/riscv/cpu.h @@ -711,9 +711,7 @@ enum riscv_pmu_event_idx { /* used by tcg/tcg-cpu.c*/ void isa_ext_update_enabled(RISCVCPU *cpu, uint32_t ext_offset, bool en); bool isa_ext_is_enabled(RISCVCPU *cpu, uint32_t ext_offset); -int cpu_cfg_ext_get_min_version(uint32_t ext_offset); void riscv_cpu_set_misa(CPURISCVState *env, RISCVMXL mxl, uint32_t ext); -void riscv_cpu_disable_priv_spec_isa_exts(RISCVCPU *cpu); typedef struct RISCVCPUMultiExtConfig { const char *name; diff --git a/target/riscv/tcg/tcg-cpu.c b/target/riscv/tcg/tcg-cpu.c index ef981ad0ce..a021ec833d 100644 --- a/target/riscv/tcg/tcg-cpu.c +++ b/target/riscv/tcg/tcg-cpu.c @@ -99,6 +99,21 @@ static const struct TCGCPUOps riscv_tcg_ops = { #endif /* !CONFIG_USER_ONLY */ }; +static int cpu_cfg_ext_get_min_version(uint32_t ext_offset) +{ + const RISCVIsaExtData *edata; + + for (edata = isa_edata_arr; edata && edata->name; edata++) { + if (edata->ext_enable_offset != ext_offset) { + continue; + } + + return edata->min_version; + } + + g_assert_not_reached(); +} + static void cpu_cfg_ext_auto_update(RISCVCPU *cpu, uint32_t ext_offset, bool value) { @@ -226,6 +241,29 @@ static void riscv_cpu_validate_v(CPURISCVState *env, RISCVCPUConfig *cfg, } } +static void riscv_cpu_disable_priv_spec_isa_exts(RISCVCPU *cpu) +{ + CPURISCVState *env = &cpu->env; + const RISCVIsaExtData *edata; + + /* Force disable extensions if priv spec version does not match */ + for (edata = isa_edata_arr; edata && edata->name; edata++) { + if (isa_ext_is_enabled(cpu, edata->ext_enable_offset) && + (env->priv_ver < edata->min_version)) { + isa_ext_update_enabled(cpu, edata->ext_enable_offset, false); +#ifndef CONFIG_USER_ONLY + warn_report("disabling %s extension for hart 0x" TARGET_FMT_lx + " because privilege spec version does not match", + edata->name, env->mhartid); +#else + warn_report("disabling %s extension because " + "privilege spec version does not match", + edata->name); +#endif + } + } +} + /* * Check consistency between chosen extensions while setting * cpu->cfg accordingly. From b933720be22442e6847629fe0dcf24b95cef3d56 Mon Sep 17 00:00:00 2001 From: Daniel Henrique Barboza Date: Tue, 26 Sep 2023 15:31:08 -0300 Subject: [PATCH 0576/1077] target/riscv: add riscv_cpu_get_name() We'll introduce generic errors that will output a CPU type name via its RISCVCPU pointer. Create a helper for that. Use the helper in tcg_cpu_realizefn() instead of hardcoding the 'host' CPU name. Signed-off-by: Daniel Henrique Barboza Reviewed-by: Alistair Francis Message-ID: <20230926183109.165878-2-dbarboza@ventanamicro.com> Signed-off-by: Alistair Francis --- target/riscv/cpu.c | 11 +++++++++++ target/riscv/cpu.h | 1 + target/riscv/tcg/tcg-cpu.c | 4 +++- 3 files changed, 15 insertions(+), 1 deletion(-) diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c index a7cc7aa6e2..cdeb24cb5e 100644 --- a/target/riscv/cpu.c +++ b/target/riscv/cpu.c @@ -643,6 +643,17 @@ static ObjectClass *riscv_cpu_class_by_name(const char *cpu_model) return oc; } +char *riscv_cpu_get_name(RISCVCPU *cpu) +{ + RISCVCPUClass *rcc = RISCV_CPU_GET_CLASS(cpu); + const char *typename = object_class_get_name(OBJECT_CLASS(rcc)); + + g_assert(g_str_has_suffix(typename, RISCV_CPU_TYPE_SUFFIX)); + + return g_strndup(typename, + strlen(typename) - strlen(RISCV_CPU_TYPE_SUFFIX)); +} + static void riscv_cpu_dump_state(CPUState *cs, FILE *f, int flags) { RISCVCPU *cpu = RISCV_CPU(cs); diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h index 7291b84756..8298f8bf63 100644 --- a/target/riscv/cpu.h +++ b/target/riscv/cpu.h @@ -730,6 +730,7 @@ typedef struct isa_ext_data { int ext_enable_offset; } RISCVIsaExtData; extern const RISCVIsaExtData isa_edata_arr[]; +char *riscv_cpu_get_name(RISCVCPU *cpu); void riscv_add_satp_mode_properties(Object *obj); diff --git a/target/riscv/tcg/tcg-cpu.c b/target/riscv/tcg/tcg-cpu.c index a021ec833d..104e91846a 100644 --- a/target/riscv/tcg/tcg-cpu.c +++ b/target/riscv/tcg/tcg-cpu.c @@ -563,7 +563,9 @@ static bool tcg_cpu_realize(CPUState *cs, Error **errp) Error *local_err = NULL; if (object_dynamic_cast(OBJECT(cpu), TYPE_RISCV_CPU_HOST)) { - error_setg(errp, "'host' CPU is not compatible with TCG acceleration"); + g_autofree char *name = riscv_cpu_get_name(cpu); + error_setg(errp, "'%s' CPU is not compatible with TCG acceleration", + name); return false; } From eb992b609159212c55ed26971dde7743c956cb7a Mon Sep 17 00:00:00 2001 From: Daniel Henrique Barboza Date: Tue, 26 Sep 2023 15:31:09 -0300 Subject: [PATCH 0577/1077] target/riscv/tcg-cpu.c: add extension properties for all cpus At this moment we do not expose extension properties for vendor CPUs because that would allow users to change them via command line. The drawback is that if we were to add an API that shows all CPU properties, e.g. qmp-query-cpu-model-expansion, we won't be able to show extensions state of vendor CPUs. We have the required machinery to create extension properties for vendor CPUs while not allowing users to enable extensions. Disabling existing extensions is allowed since it can be useful for debugging. Change the set() callback cpu_set_multi_ext_cfg() to allow enabling extensions only for generic CPUs. In cpu_add_multi_ext_prop() let's not set the default values for the properties if we're not dealing with generic CPUs, otherwise the values set in cpu_init() of vendor CPUs will be overwritten. And finally, in tcg_cpu_instance_init(), add cpu user properties for all CPUs. For the veyron-v1 CPU, we're now able to disable existing extensions like smstateen: $ ./build/qemu-system-riscv64 --nographic -M virt \ -cpu veyron-v1,smstateen=false But setting extensions that the CPU didn't set during cpu_init(), like V, is not allowed: $ ./build/qemu-system-riscv64 --nographic -M virt \ -cpu veyron-v1,v=true qemu-system-riscv64: can't apply global veyron-v1-riscv-cpu.v=true: 'veyron-v1' CPU does not allow enabling extensions Signed-off-by: Daniel Henrique Barboza Reviewed-by: Alistair Francis Message-ID: <20230926183109.165878-3-dbarboza@ventanamicro.com> Signed-off-by: Alistair Francis --- target/riscv/tcg/tcg-cpu.c | 64 +++++++++++++++++++++++++++++--------- 1 file changed, 50 insertions(+), 14 deletions(-) diff --git a/target/riscv/tcg/tcg-cpu.c b/target/riscv/tcg/tcg-cpu.c index 104e91846a..2e462e7d11 100644 --- a/target/riscv/tcg/tcg-cpu.c +++ b/target/riscv/tcg/tcg-cpu.c @@ -549,6 +549,11 @@ void riscv_cpu_validate_set_extensions(RISCVCPU *cpu, Error **errp) riscv_cpu_disable_priv_spec_isa_exts(cpu); } +static bool riscv_cpu_is_generic(Object *cpu_obj) +{ + return object_dynamic_cast(cpu_obj, TYPE_RISCV_DYNAMIC_CPU) != NULL; +} + /* * We'll get here via the following path: * @@ -632,13 +637,27 @@ static void cpu_set_misa_ext_cfg(Object *obj, Visitor *v, const char *name, target_ulong misa_bit = misa_ext_cfg->misa_bit; RISCVCPU *cpu = RISCV_CPU(obj); CPURISCVState *env = &cpu->env; - bool value; + bool generic_cpu = riscv_cpu_is_generic(obj); + bool prev_val, value; if (!visit_type_bool(v, name, &value, errp)) { return; } + prev_val = env->misa_ext & misa_bit; + + if (value == prev_val) { + return; + } + if (value) { + if (!generic_cpu) { + g_autofree char *cpuname = riscv_cpu_get_name(cpu); + error_setg(errp, "'%s' CPU does not allow enabling extensions", + cpuname); + return; + } + env->misa_ext |= misa_bit; env->misa_ext_mask |= misa_bit; } else { @@ -688,6 +707,7 @@ static const RISCVCPUMisaExtConfig misa_ext_cfgs[] = { */ static void riscv_cpu_add_misa_properties(Object *cpu_obj) { + bool use_def_vals = riscv_cpu_is_generic(cpu_obj); int i; for (i = 0; i < ARRAY_SIZE(misa_ext_cfgs); i++) { @@ -706,7 +726,9 @@ static void riscv_cpu_add_misa_properties(Object *cpu_obj) cpu_set_misa_ext_cfg, NULL, (void *)misa_cfg); object_property_set_description(cpu_obj, name, desc); - object_property_set_bool(cpu_obj, name, misa_cfg->enabled, NULL); + if (use_def_vals) { + object_property_set_bool(cpu_obj, name, misa_cfg->enabled, NULL); + } } } @@ -714,17 +736,32 @@ static void cpu_set_multi_ext_cfg(Object *obj, Visitor *v, const char *name, void *opaque, Error **errp) { const RISCVCPUMultiExtConfig *multi_ext_cfg = opaque; - bool value; + RISCVCPU *cpu = RISCV_CPU(obj); + bool generic_cpu = riscv_cpu_is_generic(obj); + bool prev_val, value; if (!visit_type_bool(v, name, &value, errp)) { return; } - isa_ext_update_enabled(RISCV_CPU(obj), multi_ext_cfg->offset, value); - g_hash_table_insert(multi_ext_user_opts, GUINT_TO_POINTER(multi_ext_cfg->offset), (gpointer)value); + + prev_val = isa_ext_is_enabled(cpu, multi_ext_cfg->offset); + + if (value == prev_val) { + return; + } + + if (value && !generic_cpu) { + g_autofree char *cpuname = riscv_cpu_get_name(cpu); + error_setg(errp, "'%s' CPU does not allow enabling extensions", + cpuname); + return; + } + + isa_ext_update_enabled(cpu, multi_ext_cfg->offset, value); } static void cpu_get_multi_ext_cfg(Object *obj, Visitor *v, const char *name, @@ -739,11 +776,17 @@ static void cpu_get_multi_ext_cfg(Object *obj, Visitor *v, const char *name, static void cpu_add_multi_ext_prop(Object *cpu_obj, const RISCVCPUMultiExtConfig *multi_cfg) { + bool generic_cpu = riscv_cpu_is_generic(cpu_obj); + object_property_add(cpu_obj, multi_cfg->name, "bool", cpu_get_multi_ext_cfg, cpu_set_multi_ext_cfg, NULL, (void *)multi_cfg); + if (!generic_cpu) { + return; + } + /* * Set def val directly instead of using * object_property_set_bool() to save the set() @@ -828,20 +871,13 @@ static bool riscv_cpu_has_max_extensions(Object *cpu_obj) return object_dynamic_cast(cpu_obj, TYPE_RISCV_CPU_MAX) != NULL; } -static bool riscv_cpu_has_user_properties(Object *cpu_obj) -{ - return object_dynamic_cast(cpu_obj, TYPE_RISCV_DYNAMIC_CPU) != NULL; -} - static void tcg_cpu_instance_init(CPUState *cs) { RISCVCPU *cpu = RISCV_CPU(cs); Object *obj = OBJECT(cpu); - if (riscv_cpu_has_user_properties(obj)) { - multi_ext_user_opts = g_hash_table_new(NULL, g_direct_equal); - riscv_cpu_add_user_properties(obj); - } + multi_ext_user_opts = g_hash_table_new(NULL, g_direct_equal); + riscv_cpu_add_user_properties(obj); if (riscv_cpu_has_max_extensions(obj)) { riscv_init_max_cpu_extensions(obj); From 0386f39b46a28da87647075f0fc20da4ba1f6478 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Chigot?= Date: Tue, 3 Oct 2023 09:14:23 +0200 Subject: [PATCH 0578/1077] softmmu: add means to pass an exit code when requesting a shutdown MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit As of now, the exit code was either EXIT_FAILURE when a panic shutdown was requested or EXIT_SUCCESS otherwise. However, some hardware could want to pass more complex exit codes. Thus, introduce a new shutdown request function allowing that. Signed-off-by: Clément Chigot Reviewed-by: Alistair Francis Message-ID: <20231003071427.188697-2-chigot@adacore.com> Signed-off-by: Alistair Francis --- include/sysemu/runstate.h | 2 ++ system/runstate.c | 12 +++++++++++- 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/include/sysemu/runstate.h b/include/sysemu/runstate.h index 08afb97695..c8c2bd8a61 100644 --- a/include/sysemu/runstate.h +++ b/include/sysemu/runstate.h @@ -68,6 +68,8 @@ void qemu_system_wakeup_request(WakeupReason reason, Error **errp); void qemu_system_wakeup_enable(WakeupReason reason, bool enabled); void qemu_register_wakeup_notifier(Notifier *notifier); void qemu_register_wakeup_support(void); +void qemu_system_shutdown_request_with_code(ShutdownCause reason, + int exit_code); void qemu_system_shutdown_request(ShutdownCause reason); void qemu_system_powerdown_request(void); void qemu_register_powerdown_notifier(Notifier *notifier); diff --git a/system/runstate.c b/system/runstate.c index 1652ed0439..363a5ea8dd 100644 --- a/system/runstate.c +++ b/system/runstate.c @@ -385,6 +385,7 @@ void vm_state_notify(bool running, RunState state) static ShutdownCause reset_requested; static ShutdownCause shutdown_requested; +static int shutdown_exit_code = EXIT_SUCCESS; static int shutdown_signal; static pid_t shutdown_pid; static int powerdown_requested; @@ -664,6 +665,13 @@ void qemu_system_killed(int signal, pid_t pid) qemu_notify_event(); } +void qemu_system_shutdown_request_with_code(ShutdownCause reason, + int exit_code) +{ + shutdown_exit_code = exit_code; + qemu_system_shutdown_request(reason); +} + void qemu_system_shutdown_request(ShutdownCause reason) { trace_qemu_system_shutdown_request(reason); @@ -725,7 +733,9 @@ static bool main_loop_should_exit(int *status) if (shutdown_action == SHUTDOWN_ACTION_PAUSE) { vm_stop(RUN_STATE_SHUTDOWN); } else { - if (request == SHUTDOWN_CAUSE_GUEST_PANIC && + if (shutdown_exit_code != EXIT_SUCCESS) { + *status = shutdown_exit_code; + } else if (request == SHUTDOWN_CAUSE_GUEST_PANIC && panic_action == PANIC_ACTION_EXIT_FAILURE) { *status = EXIT_FAILURE; } From 66bbe3e9b46112ec2fe35a7d6e79d8a9bb39d14a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Chigot?= Date: Tue, 3 Oct 2023 09:14:24 +0200 Subject: [PATCH 0579/1077] softmmu: pass the main loop status to gdb "Wxx" packet MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit gdb_exit function aims to close gdb sessions and sends the exit code of the current execution. It's being called by qemu_cleanup once the main loop is over. Until now, the exit code sent was always 0. Now that hardware can shutdown this main loop with custom exit codes, these codes must be transfered to gdb as well. Signed-off-by: Clément Chigot Reviewed-by: Alistair Francis Message-ID: <20231003071427.188697-3-chigot@adacore.com> Signed-off-by: Alistair Francis --- include/sysemu/sysemu.h | 2 +- system/main.c | 2 +- system/runstate.c | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/include/sysemu/sysemu.h b/include/sysemu/sysemu.h index 25be2a692e..73a37949c2 100644 --- a/include/sysemu/sysemu.h +++ b/include/sysemu/sysemu.h @@ -101,7 +101,7 @@ bool defaults_enabled(void); void qemu_init(int argc, char **argv); int qemu_main_loop(void); -void qemu_cleanup(void); +void qemu_cleanup(int); extern QemuOptsList qemu_legacy_drive_opts; extern QemuOptsList qemu_common_drive_opts; diff --git a/system/main.c b/system/main.c index 694388bd7f..9b91d21ea8 100644 --- a/system/main.c +++ b/system/main.c @@ -35,7 +35,7 @@ int qemu_default_main(void) int status; status = qemu_main_loop(); - qemu_cleanup(); + qemu_cleanup(status); return status; } diff --git a/system/runstate.c b/system/runstate.c index 363a5ea8dd..ea9d6c2a32 100644 --- a/system/runstate.c +++ b/system/runstate.c @@ -834,9 +834,9 @@ void qemu_init_subsystems(void) } -void qemu_cleanup(void) +void qemu_cleanup(int status) { - gdb_exit(0); + gdb_exit(status); /* * cleaning up the migration object cancels any existing migration From 215128e44bd3095b254e2f3d8ff067eadf166a1d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Chigot?= Date: Tue, 3 Oct 2023 09:14:25 +0200 Subject: [PATCH 0580/1077] hw/misc/sifive_test.c: replace exit calls with proper shutdown MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This replaces the exit calls by shutdown requests, ensuring a proper cleanup of Qemu. Otherwise, some connections like gdb could be broken before its final packet ("Wxx") is being sent. This part, being done inside qemu_cleanup function, can be reached only when the main loop exits after a shutdown request. Signed-off-by: Clément Chigot Reviewed-by: Alistair Francis Message-ID: <20231003071427.188697-4-chigot@adacore.com> Signed-off-by: Alistair Francis --- hw/misc/sifive_test.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/hw/misc/sifive_test.c b/hw/misc/sifive_test.c index 56df45bfe5..ad688079c4 100644 --- a/hw/misc/sifive_test.c +++ b/hw/misc/sifive_test.c @@ -25,6 +25,7 @@ #include "qemu/module.h" #include "sysemu/runstate.h" #include "hw/misc/sifive_test.h" +#include "sysemu/sysemu.h" static uint64_t sifive_test_read(void *opaque, hwaddr addr, unsigned int size) { @@ -39,9 +40,13 @@ static void sifive_test_write(void *opaque, hwaddr addr, int code = (val64 >> 16) & 0xffff; switch (status) { case FINISHER_FAIL: - exit(code); + qemu_system_shutdown_request_with_code( + SHUTDOWN_CAUSE_GUEST_PANIC, code); + return; case FINISHER_PASS: - exit(0); + qemu_system_shutdown_request_with_code( + SHUTDOWN_CAUSE_GUEST_SHUTDOWN, code); + return; case FINISHER_RESET: qemu_system_reset_request(SHUTDOWN_CAUSE_GUEST_RESET); return; From 354c96069c4b6af176c03b046087e971ac621177 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Chigot?= Date: Tue, 3 Oct 2023 09:14:26 +0200 Subject: [PATCH 0581/1077] hw/char: riscv_htif: replace exit calls with proper shutdown MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This replaces the exit calls by shutdown requests, ensuring a proper cleanup of Qemu. Otherwise, some connections like gdb could be broken before its final packet ("Wxx") is being sent. This part, being done inside qemu_cleanup function, can be reached only when the main loop exits after a shutdown request. Signed-off-by: Clément Chigot Reviewed-by: Alistair Francis Message-ID: <20231003071427.188697-5-chigot@adacore.com> Signed-off-by: Alistair Francis --- hw/char/riscv_htif.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/hw/char/riscv_htif.c b/hw/char/riscv_htif.c index 40de6b8b77..9bef60def1 100644 --- a/hw/char/riscv_htif.c +++ b/hw/char/riscv_htif.c @@ -32,6 +32,7 @@ #include "exec/address-spaces.h" #include "exec/tswap.h" #include "sysemu/dma.h" +#include "sysemu/runstate.h" #define RISCV_DEBUG_HTIF 0 #define HTIF_DEBUG(fmt, ...) \ @@ -206,7 +207,9 @@ static void htif_handle_tohost_write(HTIFState *s, uint64_t val_written) g_free(sig_data); } - exit(exit_code); + qemu_system_shutdown_request_with_code( + SHUTDOWN_CAUSE_GUEST_SHUTDOWN, exit_code); + return; } else { uint64_t syscall[8]; cpu_physical_memory_read(payload, syscall, sizeof(syscall)); From e216256ae9fc3d1988e3f1af3f644b4dafb79838 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Chigot?= Date: Tue, 3 Oct 2023 09:14:27 +0200 Subject: [PATCH 0582/1077] gdbstub: replace exit calls with proper shutdown for softmmu MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This replaces the exit calls by shutdown requests, ensuring a proper cleanup of Qemu. Features like net/vhost-vdpa.c are expecting qemu_cleanup to be called to remove their last residuals. Signed-off-by: Clément Chigot Reviewed-by: Alistair Francis Message-ID: <20231003071427.188697-6-chigot@adacore.com> Signed-off-by: Alistair Francis --- gdbstub/gdbstub.c | 5 +++-- gdbstub/system.c | 6 ++++++ gdbstub/user.c | 6 ++++++ include/gdbstub/syscalls.h | 9 +++++++++ 4 files changed, 24 insertions(+), 2 deletions(-) diff --git a/gdbstub/gdbstub.c b/gdbstub/gdbstub.c index b1532118d1..1e96a71c0c 100644 --- a/gdbstub/gdbstub.c +++ b/gdbstub/gdbstub.c @@ -1324,7 +1324,7 @@ static void handle_v_kill(GArray *params, void *user_ctx) gdb_put_packet("OK"); error_report("QEMU: Terminated via GDBstub"); gdb_exit(0); - exit(0); + gdb_qemu_exit(0); } static const GdbCmdParseEntry gdb_v_commands_table[] = { @@ -1843,7 +1843,8 @@ static int gdb_handle_packet(const char *line_buf) /* Kill the target */ error_report("QEMU: Terminated via GDBstub"); gdb_exit(0); - exit(0); + gdb_qemu_exit(0); + break; case 'D': { static const GdbCmdParseEntry detach_cmd_desc = { diff --git a/gdbstub/system.c b/gdbstub/system.c index 48976873d2..783ac140b9 100644 --- a/gdbstub/system.c +++ b/gdbstub/system.c @@ -435,6 +435,12 @@ void gdb_exit(int code) qemu_chr_fe_deinit(&gdbserver_system_state.chr, true); } +void gdb_qemu_exit(int code) +{ + qemu_system_shutdown_request_with_code(SHUTDOWN_CAUSE_GUEST_SHUTDOWN, + code); +} + /* * Memory access */ diff --git a/gdbstub/user.c b/gdbstub/user.c index 7ab6e5d975..dbe1d9b887 100644 --- a/gdbstub/user.c +++ b/gdbstub/user.c @@ -113,6 +113,12 @@ void gdb_exit(int code) gdb_put_packet(buf); gdbserver_state.allow_stop_reply = false; } + +} + +void gdb_qemu_exit(int code) +{ + exit(code); } int gdb_handlesig(CPUState *cpu, int sig) diff --git a/include/gdbstub/syscalls.h b/include/gdbstub/syscalls.h index 243eaf8ce4..54ff7245a1 100644 --- a/include/gdbstub/syscalls.h +++ b/include/gdbstub/syscalls.h @@ -110,4 +110,13 @@ int use_gdb_syscalls(void); */ void gdb_exit(int code); +/** + * gdb_qemu_exit: ask qemu to exit + * @code: exit code reported + * + * This requests qemu to exit. This function is allowed to return as + * the exit request might be processed asynchronously by qemu backend. + */ +void gdb_qemu_exit(int code); + #endif /* _SYSCALLS_H_ */ From 082e9e4a58ba80ec056220a2f762a1c6b9a3a96c Mon Sep 17 00:00:00 2001 From: Daniel Henrique Barboza Date: Tue, 3 Oct 2023 10:21:47 -0300 Subject: [PATCH 0583/1077] target/riscv/kvm: improve 'init_multiext_cfg' error msg MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Our error message is returning the value of 'ret', which will be always -1 in case of error, and will not be that useful: qemu-system-riscv64: Unable to read ISA_EXT KVM register ssaia, error -1 Improve the error message by outputting 'errno' instead of 'ret'. Use strerrorname_np() to output the error name instead of the error code. This will give us what we need to know right away: qemu-system-riscv64: Unable to read ISA_EXT KVM register ssaia, error code: ENOENT Given that we're going to exit(1) in this condition instead of attempting to recover, remove the 'kvm_riscv_destroy_scratch_vcpu()' call. Signed-off-by: Daniel Henrique Barboza Reviewed-by: Alistair Francis Reviewed-by: Andrew Jones Reviewed-by: Philippe Mathieu-Daudé Message-ID: <20231003132148.797921-2-dbarboza@ventanamicro.com> Signed-off-by: Alistair Francis --- target/riscv/kvm/kvm-cpu.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/target/riscv/kvm/kvm-cpu.c b/target/riscv/kvm/kvm-cpu.c index c6615cb807..c3daf74fe9 100644 --- a/target/riscv/kvm/kvm-cpu.c +++ b/target/riscv/kvm/kvm-cpu.c @@ -792,8 +792,8 @@ static void kvm_riscv_init_multiext_cfg(RISCVCPU *cpu, KVMScratchCPU *kvmcpu) val = false; } else { error_report("Unable to read ISA_EXT KVM register %s, " - "error %d", multi_ext_cfg->name, ret); - kvm_riscv_destroy_scratch_vcpu(kvmcpu); + "error code: %s", multi_ext_cfg->name, + strerrorname_np(errno)); exit(EXIT_FAILURE); } } else { From 608bdebb6075b757e5505f6bbc60c45a54a1390b Mon Sep 17 00:00:00 2001 From: Daniel Henrique Barboza Date: Tue, 3 Oct 2023 10:21:48 -0300 Subject: [PATCH 0584/1077] target/riscv/kvm: support KVM_GET_REG_LIST KVM for RISC-V started supporting KVM_GET_REG_LIST in Linux 6.6. It consists of a KVM ioctl() that retrieves a list of all available regs for get_one_reg/set_one_reg. Regs that aren't present in the list aren't supported in the host. This simplifies our lives when initing the KVM regs since we don't have to always attempt a KVM_GET_ONE_REG for all regs QEMU knows. We'll only attempt a get_one_reg() if we're sure the reg is supported, i.e. it was retrieved by KVM_GET_REG_LIST. Any error in get_one_reg() will then always considered fatal, instead of having to handle special error codes that might indicate a non-fatal failure. Start by moving the current kvm_riscv_init_multiext_cfg() logic into a new kvm_riscv_read_multiext_legacy() helper. We'll prioritize using KVM_GET_REG_LIST, so check if we have it available and, in case we don't, use the legacy() logic. Otherwise, retrieve the available reg list and use it to check if the host supports our known KVM regs, doing the usual get_one_reg() for the supported regs and setting cpu->cfg accordingly. Signed-off-by: Daniel Henrique Barboza Acked-by: Alistair Francis Reviewed-by: Andrew Jones Message-ID: <20231003132148.797921-3-dbarboza@ventanamicro.com> Signed-off-by: Alistair Francis --- target/riscv/kvm/kvm-cpu.c | 96 +++++++++++++++++++++++++++++++++++++- 1 file changed, 95 insertions(+), 1 deletion(-) diff --git a/target/riscv/kvm/kvm-cpu.c b/target/riscv/kvm/kvm-cpu.c index c3daf74fe9..090d617627 100644 --- a/target/riscv/kvm/kvm-cpu.c +++ b/target/riscv/kvm/kvm-cpu.c @@ -771,7 +771,8 @@ static void kvm_riscv_read_cbomz_blksize(RISCVCPU *cpu, KVMScratchCPU *kvmcpu, } } -static void kvm_riscv_init_multiext_cfg(RISCVCPU *cpu, KVMScratchCPU *kvmcpu) +static void kvm_riscv_read_multiext_legacy(RISCVCPU *cpu, + KVMScratchCPU *kvmcpu) { CPURISCVState *env = &cpu->env; uint64_t val; @@ -812,6 +813,99 @@ static void kvm_riscv_init_multiext_cfg(RISCVCPU *cpu, KVMScratchCPU *kvmcpu) } } +static int uint64_cmp(const void *a, const void *b) +{ + uint64_t val1 = *(const uint64_t *)a; + uint64_t val2 = *(const uint64_t *)b; + + if (val1 < val2) { + return -1; + } + + if (val1 > val2) { + return 1; + } + + return 0; +} + +static void kvm_riscv_init_multiext_cfg(RISCVCPU *cpu, KVMScratchCPU *kvmcpu) +{ + KVMCPUConfig *multi_ext_cfg; + struct kvm_one_reg reg; + struct kvm_reg_list rl_struct; + struct kvm_reg_list *reglist; + uint64_t val, reg_id, *reg_search; + int i, ret; + + rl_struct.n = 0; + ret = ioctl(kvmcpu->cpufd, KVM_GET_REG_LIST, &rl_struct); + + /* + * If KVM_GET_REG_LIST isn't supported we'll get errno 22 + * (EINVAL). Use read_legacy() in this case. + */ + if (errno == EINVAL) { + return kvm_riscv_read_multiext_legacy(cpu, kvmcpu); + } else if (errno != E2BIG) { + /* + * E2BIG is an expected error message for the API since we + * don't know the number of registers. The right amount will + * be written in rl_struct.n. + * + * Error out if we get any other errno. + */ + error_report("Error when accessing get-reg-list, code: %s", + strerrorname_np(errno)); + exit(EXIT_FAILURE); + } + + reglist = g_malloc(sizeof(struct kvm_reg_list) + + rl_struct.n * sizeof(uint64_t)); + reglist->n = rl_struct.n; + ret = ioctl(kvmcpu->cpufd, KVM_GET_REG_LIST, reglist); + if (ret) { + error_report("Error when reading KVM_GET_REG_LIST, code %s ", + strerrorname_np(errno)); + exit(EXIT_FAILURE); + } + + /* sort reglist to use bsearch() */ + qsort(®list->reg, reglist->n, sizeof(uint64_t), uint64_cmp); + + for (i = 0; i < ARRAY_SIZE(kvm_multi_ext_cfgs); i++) { + multi_ext_cfg = &kvm_multi_ext_cfgs[i]; + reg_id = kvm_riscv_reg_id(&cpu->env, KVM_REG_RISCV_ISA_EXT, + multi_ext_cfg->kvm_reg_id); + reg_search = bsearch(®_id, reglist->reg, reglist->n, + sizeof(uint64_t), uint64_cmp); + if (!reg_search) { + continue; + } + + reg.id = reg_id; + reg.addr = (uint64_t)&val; + ret = ioctl(kvmcpu->cpufd, KVM_GET_ONE_REG, ®); + if (ret != 0) { + error_report("Unable to read ISA_EXT KVM register %s, " + "error code: %s", multi_ext_cfg->name, + strerrorname_np(errno)); + exit(EXIT_FAILURE); + } + + multi_ext_cfg->supported = true; + kvm_cpu_cfg_set(cpu, multi_ext_cfg, val); + } + + if (cpu->cfg.ext_icbom) { + kvm_riscv_read_cbomz_blksize(cpu, kvmcpu, &kvm_cbom_blocksize); + } + + if (cpu->cfg.ext_icboz) { + kvm_riscv_read_cbomz_blksize(cpu, kvmcpu, &kvm_cboz_blocksize); + } +} + static void riscv_init_kvm_registers(Object *cpu_obj) { RISCVCPU *cpu = RISCV_CPU(cpu_obj); From 9b9741c38f2a92eb99c74f2bf387fc7a12d7f8e2 Mon Sep 17 00:00:00 2001 From: Daniel Henrique Barboza Date: Tue, 3 Oct 2023 09:25:39 -0300 Subject: [PATCH 0585/1077] target/riscv/tcg: remove RVG warning Vendor CPUs that set RVG are displaying user warnings about other extensions that RVG must enable, one warning per CPU. E.g.: $ ./build/qemu-system-riscv64 -smp 8 -M virt -cpu veyron-v1 -nographic qemu-system-riscv64: warning: Setting G will also set IMAFD_Zicsr_Zifencei qemu-system-riscv64: warning: Setting G will also set IMAFD_Zicsr_Zifencei qemu-system-riscv64: warning: Setting G will also set IMAFD_Zicsr_Zifencei qemu-system-riscv64: warning: Setting G will also set IMAFD_Zicsr_Zifencei qemu-system-riscv64: warning: Setting G will also set IMAFD_Zicsr_Zifencei qemu-system-riscv64: warning: Setting G will also set IMAFD_Zicsr_Zifencei qemu-system-riscv64: warning: Setting G will also set IMAFD_Zicsr_Zifencei qemu-system-riscv64: warning: Setting G will also set IMAFD_Zicsr_Zifencei This happens because we decided a while ago that, for simplicity, vendor CPUs could set RVG instead of setting each G extension individually in their cpu_init(). Our warning isn't taking that into account, and we're bugging users with a warning that we're causing ourselves. In a closer look we conclude that this warning is not warranted in any other circumstance since we're just following the ISA [1], which states in chapter 24: "One goal of the RISC-V project is that it be used as a stable software development target. For this purpose, we define a combination of a base ISA (RV32I or RV64I) plus selected standard extensions (IMAFD, Zicsr, Zifencei) as a 'general-purpose' ISA, and we use the abbreviation G for the IMAFDZicsr Zifencei combination of instruction-set extensions." With this in mind, enabling IMAFD_Zicsr_Zifencei if the user explicitly enables 'G' is an expected behavior and the warning is unneeded. Any user caught by surprise should refer to the ISA. Remove the warning when handling RVG. [1] https://github.com/riscv/riscv-isa-manual/releases/download/Ratified-IMAFDQC/riscv-spec-20191213.pdf Reported-by: Paul A. Clarke Suggested-by: Andrew Jones Signed-off-by: Daniel Henrique Barboza Reviewed-by: Alistair Francis Reviewed-by: Andrew Jones Message-ID: <20231003122539.775932-1-dbarboza@ventanamicro.com> Signed-off-by: Alistair Francis --- target/riscv/tcg/tcg-cpu.c | 1 - 1 file changed, 1 deletion(-) diff --git a/target/riscv/tcg/tcg-cpu.c b/target/riscv/tcg/tcg-cpu.c index 2e462e7d11..a042bb6cda 100644 --- a/target/riscv/tcg/tcg-cpu.c +++ b/target/riscv/tcg/tcg-cpu.c @@ -293,7 +293,6 @@ void riscv_cpu_validate_set_extensions(RISCVCPU *cpu, Error **errp) return; } - warn_report("Setting G will also set IMAFD_Zicsr_Zifencei"); cpu_cfg_ext_auto_update(cpu, CPU_CFG_OFFSET(ext_icsr), true); cpu_cfg_ext_auto_update(cpu, CPU_CFG_OFFSET(ext_ifencei), true); From 614c9466a238641480332b707a7a20a3593bdfb7 Mon Sep 17 00:00:00 2001 From: "Richard W.M. Jones" Date: Mon, 9 Oct 2023 13:48:25 +0100 Subject: [PATCH 0586/1077] target/riscv: Use env_archcpu for better performance MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit RISCV_CPU(cs) uses a checked cast. When QOM cast debugging is enabled this adds about 5% total overhead when emulating RV64 on x86-64 host. Using a RISC-V guest with 16 vCPUs, 16 GB of guest RAM, virtio-blk disk. The guest has a copy of the qemu source tree. The test involves compiling the qemu source tree with 'make clean; time make -j16'. Before making this change the compile step took 449 & 447 seconds over two consecutive runs. After making this change: 428 & 421 seconds. The saving is over 5%. Thanks: Paolo Bonzini Thanks: Philippe Mathieu-Daudé Signed-off-by: Richard W.M. Jones Reviewed-by: Alistair Francis Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Richard Henderson Message-ID: <20231009124859.3373696-2-rjones@redhat.com> Signed-off-by: Alistair Francis --- target/riscv/cpu_helper.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/target/riscv/cpu_helper.c b/target/riscv/cpu_helper.c index 3a02079290..8c28241c18 100644 --- a/target/riscv/cpu_helper.c +++ b/target/riscv/cpu_helper.c @@ -65,8 +65,7 @@ int riscv_cpu_mmu_index(CPURISCVState *env, bool ifetch) void cpu_get_tb_cpu_state(CPURISCVState *env, vaddr *pc, uint64_t *cs_base, uint32_t *pflags) { - CPUState *cs = env_cpu(env); - RISCVCPU *cpu = RISCV_CPU(cs); + RISCVCPU *cpu = env_archcpu(env); RISCVExtStatus fs, vs; uint32_t flags = 0; From 8043effd9b0368c626192cde36c8b83389a617f6 Mon Sep 17 00:00:00 2001 From: Daniel Henrique Barboza Date: Mon, 9 Oct 2023 08:28:17 -0300 Subject: [PATCH 0587/1077] target/riscv: deprecate capital 'Z' CPU properties At this moment there are eleven CPU extension properties that starts with capital 'Z': Zifencei, Zicsr, Zihintntl, Zihintpause, Zawrs, Zfa, Zfh, Zfhmin, Zve32f, Zve64f and Zve64d. All other extensions are named with lower-case letters. We want all properties to be named with lower-case letters since it's consistent with the riscv-isa string that we create in the FDT. Having these 11 properties to be exceptions can be confusing. Deprecate all of them. Create their lower-case counterpart to be used as maintained CPU properties. When trying to use any deprecated property a warning message will be displayed, recommending users to switch to the lower-case variant: ./build/qemu-system-riscv64 -M virt -cpu rv64,Zifencei=true --nographic qemu-system-riscv64: warning: CPU property 'Zifencei' is deprecated. Please use 'zifencei' instead This will give users some time to change their scripts before we remove the capital 'Z' properties entirely. Signed-off-by: Daniel Henrique Barboza Reviewed-by: Alistair Francis Reviewed-by: Andrew Jones Message-ID: <20231009112817.8896-2-dbarboza@ventanamicro.com> Signed-off-by: Alistair Francis --- docs/about/deprecated.rst | 23 ++++++++++++++++++++++ target/riscv/cpu.c | 39 +++++++++++++++++++++++++++----------- target/riscv/cpu.h | 1 + target/riscv/tcg/tcg-cpu.c | 31 +++++++++++++++++++++++++++++- 4 files changed, 82 insertions(+), 12 deletions(-) diff --git a/docs/about/deprecated.rst b/docs/about/deprecated.rst index 5e3965a674..1c4d7f36f0 100644 --- a/docs/about/deprecated.rst +++ b/docs/about/deprecated.rst @@ -340,6 +340,29 @@ of generic CPUs: rv32 and rv64 as default CPUs and 'max' as a feature complete CPU for both 32 and 64 bit builds. Users are then discouraged to use the 'any' CPU type starting in 8.2. +RISC-V CPU properties which start with capital 'Z' (since 8.2) +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +All RISC-V CPU properties which start with capital 'Z' are being deprecated +starting in 8.2. The reason is that they were wrongly added with capital 'Z' +in the past. CPU properties were later added with lower-case names, which +is the format we want to use from now on. + +Users which try to use these deprecated properties will receive a warning +recommending to switch to their stable counterparts: + +- "Zifencei" should be replaced with "zifencei" +- "Zicsr" should be replaced with "zicsr" +- "Zihintntl" should be replaced with "zihintntl" +- "Zihintpause" should be replaced with "zihintpause" +- "Zawrs" should be replaced with "zawrs" +- "Zfa" should be replaced with "zfa" +- "Zfh" should be replaced with "zfh" +- "Zfhmin" should be replaced with "zfhmin" +- "Zve32f" should be replaced with "zve32f" +- "Zve64f" should be replaced with "zve64f" +- "Zve64d" should be replaced with "zve64d" + Block device options '''''''''''''''''''' diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c index cdeb24cb5e..ac4a6c7eec 100644 --- a/target/riscv/cpu.c +++ b/target/riscv/cpu.c @@ -1242,17 +1242,17 @@ const char *riscv_get_misa_ext_description(uint32_t bit) const RISCVCPUMultiExtConfig riscv_cpu_extensions[] = { /* Defaults for standard extensions */ MULTI_EXT_CFG_BOOL("sscofpmf", ext_sscofpmf, false), - MULTI_EXT_CFG_BOOL("Zifencei", ext_ifencei, true), - MULTI_EXT_CFG_BOOL("Zicsr", ext_icsr, true), - MULTI_EXT_CFG_BOOL("Zihintntl", ext_zihintntl, true), - MULTI_EXT_CFG_BOOL("Zihintpause", ext_zihintpause, true), - MULTI_EXT_CFG_BOOL("Zawrs", ext_zawrs, true), - MULTI_EXT_CFG_BOOL("Zfa", ext_zfa, true), - MULTI_EXT_CFG_BOOL("Zfh", ext_zfh, false), - MULTI_EXT_CFG_BOOL("Zfhmin", ext_zfhmin, false), - MULTI_EXT_CFG_BOOL("Zve32f", ext_zve32f, false), - MULTI_EXT_CFG_BOOL("Zve64f", ext_zve64f, false), - MULTI_EXT_CFG_BOOL("Zve64d", ext_zve64d, false), + MULTI_EXT_CFG_BOOL("zifencei", ext_ifencei, true), + MULTI_EXT_CFG_BOOL("zicsr", ext_icsr, true), + MULTI_EXT_CFG_BOOL("zihintntl", ext_zihintntl, true), + MULTI_EXT_CFG_BOOL("zihintpause", ext_zihintpause, true), + MULTI_EXT_CFG_BOOL("zawrs", ext_zawrs, true), + MULTI_EXT_CFG_BOOL("zfa", ext_zfa, true), + MULTI_EXT_CFG_BOOL("zfh", ext_zfh, false), + MULTI_EXT_CFG_BOOL("zfhmin", ext_zfhmin, false), + MULTI_EXT_CFG_BOOL("zve32f", ext_zve32f, false), + MULTI_EXT_CFG_BOOL("zve64f", ext_zve64f, false), + MULTI_EXT_CFG_BOOL("zve64d", ext_zve64d, false), MULTI_EXT_CFG_BOOL("sstc", ext_sstc, true), MULTI_EXT_CFG_BOOL("smstateen", ext_smstateen, false), @@ -1345,6 +1345,23 @@ const RISCVCPUMultiExtConfig riscv_cpu_experimental_exts[] = { DEFINE_PROP_END_OF_LIST(), }; +/* Deprecated entries marked for future removal */ +const RISCVCPUMultiExtConfig riscv_cpu_deprecated_exts[] = { + MULTI_EXT_CFG_BOOL("Zifencei", ext_ifencei, true), + MULTI_EXT_CFG_BOOL("Zicsr", ext_icsr, true), + MULTI_EXT_CFG_BOOL("Zihintntl", ext_zihintntl, true), + MULTI_EXT_CFG_BOOL("Zihintpause", ext_zihintpause, true), + MULTI_EXT_CFG_BOOL("Zawrs", ext_zawrs, true), + MULTI_EXT_CFG_BOOL("Zfa", ext_zfa, true), + MULTI_EXT_CFG_BOOL("Zfh", ext_zfh, false), + MULTI_EXT_CFG_BOOL("Zfhmin", ext_zfhmin, false), + MULTI_EXT_CFG_BOOL("Zve32f", ext_zve32f, false), + MULTI_EXT_CFG_BOOL("Zve64f", ext_zve64f, false), + MULTI_EXT_CFG_BOOL("Zve64d", ext_zve64d, false), + + DEFINE_PROP_END_OF_LIST(), +}; + Property riscv_cpu_options[] = { DEFINE_PROP_UINT8("pmu-num", RISCVCPU, cfg.pmu_num, 16), diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h index 8298f8bf63..f8ffa5ee38 100644 --- a/target/riscv/cpu.h +++ b/target/riscv/cpu.h @@ -722,6 +722,7 @@ typedef struct RISCVCPUMultiExtConfig { extern const RISCVCPUMultiExtConfig riscv_cpu_extensions[]; extern const RISCVCPUMultiExtConfig riscv_cpu_vendor_exts[]; extern const RISCVCPUMultiExtConfig riscv_cpu_experimental_exts[]; +extern const RISCVCPUMultiExtConfig riscv_cpu_deprecated_exts[]; extern Property riscv_cpu_options[]; typedef struct isa_ext_data { diff --git a/target/riscv/tcg/tcg-cpu.c b/target/riscv/tcg/tcg-cpu.c index a042bb6cda..a28918ab30 100644 --- a/target/riscv/tcg/tcg-cpu.c +++ b/target/riscv/tcg/tcg-cpu.c @@ -731,6 +731,25 @@ static void riscv_cpu_add_misa_properties(Object *cpu_obj) } } +static bool cpu_ext_is_deprecated(const char *ext_name) +{ + return isupper(ext_name[0]); +} + +/* + * String will be allocated in the heap. Caller is responsible + * for freeing it. + */ +static char *cpu_ext_to_lower(const char *ext_name) +{ + char *ret = g_malloc0(strlen(ext_name) + 1); + + strcpy(ret, ext_name); + ret[0] = tolower(ret[0]); + + return ret; +} + static void cpu_set_multi_ext_cfg(Object *obj, Visitor *v, const char *name, void *opaque, Error **errp) { @@ -743,6 +762,13 @@ static void cpu_set_multi_ext_cfg(Object *obj, Visitor *v, const char *name, return; } + if (cpu_ext_is_deprecated(multi_ext_cfg->name)) { + g_autofree char *lower = cpu_ext_to_lower(multi_ext_cfg->name); + + warn_report("CPU property '%s' is deprecated. Please use '%s' instead", + multi_ext_cfg->name, lower); + } + g_hash_table_insert(multi_ext_user_opts, GUINT_TO_POINTER(multi_ext_cfg->offset), (gpointer)value); @@ -776,13 +802,14 @@ static void cpu_add_multi_ext_prop(Object *cpu_obj, const RISCVCPUMultiExtConfig *multi_cfg) { bool generic_cpu = riscv_cpu_is_generic(cpu_obj); + bool deprecated_ext = cpu_ext_is_deprecated(multi_cfg->name); object_property_add(cpu_obj, multi_cfg->name, "bool", cpu_get_multi_ext_cfg, cpu_set_multi_ext_cfg, NULL, (void *)multi_cfg); - if (!generic_cpu) { + if (!generic_cpu || deprecated_ext) { return; } @@ -825,6 +852,8 @@ static void riscv_cpu_add_user_properties(Object *obj) riscv_cpu_add_multiext_prop_array(obj, riscv_cpu_vendor_exts); riscv_cpu_add_multiext_prop_array(obj, riscv_cpu_experimental_exts); + riscv_cpu_add_multiext_prop_array(obj, riscv_cpu_deprecated_exts); + for (Property *prop = riscv_cpu_options; prop && prop->name; prop++) { qdev_property_add_static(DEVICE(obj), prop); } From 837570cef237b634eb4c245363470deebea7089d Mon Sep 17 00:00:00 2001 From: Max Chou Date: Thu, 5 Oct 2023 17:57:32 +0800 Subject: [PATCH 0588/1077] target/riscv: Fix vfwmaccbf16.vf MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The operator (fwmacc16) of vfwmaccbf16.vf helper function should be replaced by fwmaccbf16. Fixes: adf772b0f7 ("target/riscv: Add support for Zvfbfwma extension") Signed-off-by: Max Chou Reviewed-by: LIU Zhiwei Reviewed-by: Philippe Mathieu-Daudé Message-ID: <20231005095734.567575-1-max.chou@sifive.com> Signed-off-by: Alistair Francis --- target/riscv/vector_helper.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/target/riscv/vector_helper.c b/target/riscv/vector_helper.c index c9b39fb67f..c1c3a4d1ea 100644 --- a/target/riscv/vector_helper.c +++ b/target/riscv/vector_helper.c @@ -3361,7 +3361,7 @@ static uint32_t fwmaccbf16(uint16_t a, uint16_t b, uint32_t d, float_status *s) RVVCALL(OPFVV3, vfwmaccbf16_vv, WOP_UUU_H, H4, H2, H2, fwmaccbf16) GEN_VEXT_VV_ENV(vfwmaccbf16_vv, 4) -RVVCALL(OPFVF3, vfwmaccbf16_vf, WOP_UUU_H, H4, H2, fwmacc16) +RVVCALL(OPFVF3, vfwmaccbf16_vf, WOP_UUU_H, H4, H2, fwmaccbf16) GEN_VEXT_VF(vfwmaccbf16_vf, 4) static uint32_t fwnmacc16(uint16_t a, uint16_t b, uint32_t d, float_status *s) From 3cc72cdbb2235b1001bab760712ef6bf543752c3 Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Fri, 6 Oct 2023 14:08:19 +0200 Subject: [PATCH 0589/1077] libvduse: Fix compiler warning with -Wshadow=local No need to declare a new variable with the same name here, we can simple re-use the one from the top of the function. With this change, the file now compiles fine with -Wshadow=local. Signed-off-by: Thomas Huth Message-ID: <20231006120819.480792-1-thuth@redhat.com> Reviewed-by: Xie Yongji Signed-off-by: Markus Armbruster --- subprojects/libvduse/libvduse.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/subprojects/libvduse/libvduse.c b/subprojects/libvduse/libvduse.c index 377959a0b4..21ffbb5b8d 100644 --- a/subprojects/libvduse/libvduse.c +++ b/subprojects/libvduse/libvduse.c @@ -1031,7 +1031,7 @@ int vduse_dev_handler(VduseDev *dev) /* The iova will be updated by iova_to_va() later, so just remove it */ vduse_iova_remove_region(dev, req.iova.start, req.iova.last); for (i = 0; i < dev->num_queues; i++) { - VduseVirtq *vq = &dev->vqs[i]; + vq = &dev->vqs[i]; if (vq->ready) { if (vduse_queue_update_vring(vq, vq->vring.desc_addr, vq->vring.avail_addr, From 61499d87f4eb7594fb3fcbbbcbf5bf8b05fdd1be Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Fri, 6 Oct 2023 14:11:29 +0200 Subject: [PATCH 0590/1077] libvhost-user: Fix compiler warning with -Wshadow=local Rename shadowing variables to make this code compilable with -Wshadow=local. Signed-off-by: Thomas Huth Message-ID: <20231006121129.487251-1-thuth@redhat.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Markus Armbruster --- subprojects/libvhost-user/libvhost-user.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/subprojects/libvhost-user/libvhost-user.c b/subprojects/libvhost-user/libvhost-user.c index 051a611da3..ea2822a44c 100644 --- a/subprojects/libvhost-user/libvhost-user.c +++ b/subprojects/libvhost-user/libvhost-user.c @@ -870,10 +870,10 @@ vu_rem_mem_reg(VuDev *dev, VhostUserMsg *vmsg) { for (i = 0; i < dev->nregions; i++) { if (reg_equal(&dev->regions[i], msg_region)) { VuDevRegion *r = &dev->regions[i]; - void *m = (void *) (uintptr_t) r->mmap_addr; + void *ma = (void *) (uintptr_t) r->mmap_addr; - if (m) { - munmap(m, r->size + r->mmap_offset); + if (ma) { + munmap(ma, r->size + r->mmap_offset); } /* @@ -1005,10 +1005,10 @@ vu_set_mem_table_exec(VuDev *dev, VhostUserMsg *vmsg) for (i = 0; i < dev->nregions; i++) { VuDevRegion *r = &dev->regions[i]; - void *m = (void *) (uintptr_t) r->mmap_addr; + void *ma = (void *) (uintptr_t) r->mmap_addr; - if (m) { - munmap(m, r->size + r->mmap_offset); + if (ma) { + munmap(ma, r->size + r->mmap_offset); } } dev->nregions = memory->nregions; From 9e7d33941f2070d00090395addf476fd1b0a3d6f Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Mon, 9 Oct 2023 10:45:59 +0200 Subject: [PATCH 0591/1077] hw/virtio/virtio-gpu: Fix compiler warning when compiling with -Wshadow MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Avoid using trivial variable names in macros, otherwise we get the following compiler warning when compiling with -Wshadow=local: In file included from ../../qemu/hw/display/virtio-gpu-virgl.c:19: ../../home/thuth/devel/qemu/hw/display/virtio-gpu-virgl.c: In function ‘virgl_cmd_submit_3d’: ../../qemu/include/hw/virtio/virtio-gpu.h:228:16: error: declaration of ‘s’ shadows a previous local [-Werror=shadow=compatible-local] 228 | size_t s; | ^ ../../qemu/hw/display/virtio-gpu-virgl.c:215:5: note: in expansion of macro ‘VIRTIO_GPU_FILL_CMD’ 215 | VIRTIO_GPU_FILL_CMD(cs); | ^~~~~~~~~~~~~~~~~~~ ../../qemu/hw/display/virtio-gpu-virgl.c:213:12: note: shadowed declaration is here 213 | size_t s; | ^ cc1: all warnings being treated as errors Signed-off-by: Thomas Huth Message-ID: <20231009084559.41427-1-thuth@redhat.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Markus Armbruster --- include/hw/virtio/virtio-gpu.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/include/hw/virtio/virtio-gpu.h b/include/hw/virtio/virtio-gpu.h index 390c4642b8..4739fa4689 100644 --- a/include/hw/virtio/virtio-gpu.h +++ b/include/hw/virtio/virtio-gpu.h @@ -225,13 +225,13 @@ struct VhostUserGPU { }; #define VIRTIO_GPU_FILL_CMD(out) do { \ - size_t s; \ - s = iov_to_buf(cmd->elem.out_sg, cmd->elem.out_num, 0, \ + size_t virtiogpufillcmd_s_ = \ + iov_to_buf(cmd->elem.out_sg, cmd->elem.out_num, 0, \ &out, sizeof(out)); \ - if (s != sizeof(out)) { \ + if (virtiogpufillcmd_s_ != sizeof(out)) { \ qemu_log_mask(LOG_GUEST_ERROR, \ "%s: command size incorrect %zu vs %zu\n", \ - __func__, s, sizeof(out)); \ + __func__, virtiogpufillcmd_s_, sizeof(out)); \ return; \ } \ } while (0) From 85fc35afa93c7320d1641d344d0c5dfbe341d087 Mon Sep 17 00:00:00 2001 From: Yuval Shaia Date: Wed, 1 Mar 2023 16:29:26 +0200 Subject: [PATCH 0592/1077] hw/pvrdma: Protect against buggy or malicious guest driver Guest driver allocates and initialize page tables to be used as a ring of descriptors for CQ and async events. The page table that represents the ring, along with the number of pages in the page table is passed to the device. Currently our device supports only one page table for a ring. Let's make sure that the number of page table entries the driver reports, do not exceeds the one page table size. Reported-by: Soul Chen Signed-off-by: Yuval Shaia Fixes: CVE-2023-1544 Message-ID: <20230301142926.18686-1-yuval.shaia.ml@gmail.com> Signed-off-by: Thomas Huth --- hw/rdma/vmw/pvrdma_main.c | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/hw/rdma/vmw/pvrdma_main.c b/hw/rdma/vmw/pvrdma_main.c index 4fc6712025..55b338046e 100644 --- a/hw/rdma/vmw/pvrdma_main.c +++ b/hw/rdma/vmw/pvrdma_main.c @@ -91,19 +91,33 @@ static int init_dev_ring(PvrdmaRing *ring, PvrdmaRingState **ring_state, dma_addr_t dir_addr, uint32_t num_pages) { uint64_t *dir, *tbl; - int rc = 0; + int max_pages, rc = 0; if (!num_pages) { rdma_error_report("Ring pages count must be strictly positive"); return -EINVAL; } + /* + * Make sure we can satisfy the requested number of pages in a single + * TARGET_PAGE_SIZE sized page table (taking into account that first entry + * is reserved for ring-state) + */ + max_pages = TARGET_PAGE_SIZE / sizeof(dma_addr_t) - 1; + if (num_pages > max_pages) { + rdma_error_report("Maximum pages on a single directory must not exceed %d\n", + max_pages); + return -EINVAL; + } + dir = rdma_pci_dma_map(pci_dev, dir_addr, TARGET_PAGE_SIZE); if (!dir) { rdma_error_report("Failed to map to page directory (ring %s)", name); rc = -ENOMEM; goto out; } + + /* We support only one page table for a ring */ tbl = rdma_pci_dma_map(pci_dev, dir[0], TARGET_PAGE_SIZE); if (!tbl) { rdma_error_report("Failed to map to page table (ring %s)", name); From e9a54265f533f4df957ee9ced3304df8c3ef2bea Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Wed, 27 Sep 2023 15:30:19 +0200 Subject: [PATCH 0593/1077] hw/rdma: Deprecate the pvrdma device and the rdma subsystem MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This subsystem is said to be in a bad shape (see e.g. [1], [2] and [3]), and nobody seems to feel responsible to pick up patches for this and send them via a pull request. For example there is a patch for a CVE-worthy bug posted more than half a year ago [4] which has never been merged. Thus let's mark it as deprecated and finally remove it unless somebody steps up and improves the code quality and adds proper regression tests. [1] https://lore.kernel.org/qemu-devel/20230918144206.560120-1-armbru@redhat.com/ [2] https://lore.kernel.org/qemu-devel/ZQnojJOqoFu73995@redhat.com/ [3] https://lore.kernel.org/qemu-devel/1054981c-e8ae-c676-3b04-eeb030e11f65@tls.msk.ru/ [4] https://lore.kernel.org/qemu-devel/20230301142926.18686-1-yuval.shaia.ml@gmail.com/ Message-ID: <20230927133019.228495-1-thuth@redhat.com> Acked-by: Juan Quintela Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Thomas Huth --- MAINTAINERS | 2 +- docs/about/deprecated.rst | 8 ++++++++ hw/rdma/vmw/pvrdma_main.c | 2 ++ 3 files changed, 11 insertions(+), 1 deletion(-) diff --git a/MAINTAINERS b/MAINTAINERS index c3cc12dc29..1c9b49c00f 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -3843,7 +3843,7 @@ F: docs/block-replication.txt PVRDMA M: Yuval Shaia M: Marcel Apfelbaum -S: Maintained +S: Odd Fixes F: hw/rdma/* F: hw/rdma/vmw/* F: docs/pvrdma.txt diff --git a/docs/about/deprecated.rst b/docs/about/deprecated.rst index 8b136320e2..ffd0a8c896 100644 --- a/docs/about/deprecated.rst +++ b/docs/about/deprecated.rst @@ -327,6 +327,14 @@ QEMU's ``vhost`` feature, which would eliminate the high latency costs under which the 9p ``proxy`` backend currently suffers. However as of to date nobody has indicated plans for such kind of reimplementation unfortunately. +``-device pvrdma`` and the rdma subsystem (since 8.2) +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +The pvrdma device and the whole rdma subsystem are in a bad shape and +without active maintenance. The QEMU project intends to remove this +device and subsystem from the code base in a future release without +replacement unless somebody steps up and improves the situation. + Block device options '''''''''''''''''''' diff --git a/hw/rdma/vmw/pvrdma_main.c b/hw/rdma/vmw/pvrdma_main.c index 55b338046e..e735ff97eb 100644 --- a/hw/rdma/vmw/pvrdma_main.c +++ b/hw/rdma/vmw/pvrdma_main.c @@ -615,6 +615,8 @@ static void pvrdma_realize(PCIDevice *pdev, Error **errp) bool ram_shared = false; PCIDevice *func0; + warn_report_once("pvrdma is deprecated and will be removed in a future release"); + rdma_info_report("Initializing device %s %x.%x", pdev->name, PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn)); From d0353b6e7b3f9ba6132f0fa9b3605e4d4275af0c Mon Sep 17 00:00:00 2001 From: Chris Rauer Date: Fri, 29 Sep 2023 00:08:31 +0000 Subject: [PATCH 0594/1077] tests/qtest: Fix npcm7xx_timer-test.c flaky test npcm7xx_timer-test occasionally fails due to the state of the timers from the previous test iteration. Advancing the clock step after the reset resolves this issue. Fixes: https://gitlab.com/qemu-project/qemu/-/issues/1897 Signed-off-by: Chris Rauer Message-ID: <20230929000831.691559-1-crauer@google.com> Signed-off-by: Thomas Huth --- tests/qtest/npcm7xx_timer-test.c | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/qtest/npcm7xx_timer-test.c b/tests/qtest/npcm7xx_timer-test.c index 43711049ca..58f58c2f71 100644 --- a/tests/qtest/npcm7xx_timer-test.c +++ b/tests/qtest/npcm7xx_timer-test.c @@ -465,6 +465,7 @@ static void test_periodic_interrupt(gconstpointer test_data) int i; tim_reset(td); + clock_step_next(); tim_write_ticr(td, count); tim_write_tcsr(td, CEN | IE | MODE_PERIODIC | PRESCALE(ps)); From f912f1bdb6b4237515e01a4ba646b2a7daefebed Mon Sep 17 00:00:00 2001 From: Klaus Jensen Date: Wed, 23 Aug 2023 10:14:41 +0200 Subject: [PATCH 0595/1077] hw/misc/i2c-echo: add copyright/license note Add missing copyright and license notice. Also add a short description of the device. Signed-off-by: Klaus Jensen Message-ID: <20230823-i2c-echo-fixes-v1-1-ccc05a6028f0@samsung.com> Signed-off-by: Thomas Huth --- hw/misc/i2c-echo.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/hw/misc/i2c-echo.c b/hw/misc/i2c-echo.c index 5705ab5d73..5ae3d0817e 100644 --- a/hw/misc/i2c-echo.c +++ b/hw/misc/i2c-echo.c @@ -1,3 +1,13 @@ +/* + * Example I2C device using asynchronous I2C send. + * + * Copyright (C) 2023 Samsung Electronics Co., Ltd. All Rights Reserved. + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + * + */ + #include "qemu/osdep.h" #include "qemu/timer.h" #include "qemu/main-loop.h" From a8500f804313ec7be233b329195cc8476e4190eb Mon Sep 17 00:00:00 2001 From: Klaus Jensen Date: Wed, 23 Aug 2023 10:14:42 +0200 Subject: [PATCH 0596/1077] hw/misc/Kconfig: add switch for i2c-echo MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Associate i2c-echo with TEST_DEVICES and add a dependency on I2C. Signed-off-by: Klaus Jensen Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Thomas Huth Message-ID: <20230823-i2c-echo-fixes-v1-2-ccc05a6028f0@samsung.com> Signed-off-by: Thomas Huth --- hw/misc/Kconfig | 5 +++++ hw/misc/meson.build | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/hw/misc/Kconfig b/hw/misc/Kconfig index 858277bb60..dba41afe67 100644 --- a/hw/misc/Kconfig +++ b/hw/misc/Kconfig @@ -34,6 +34,11 @@ config PCA9552 bool depends on I2C +config I2C_ECHO + bool + default y if TEST_DEVICES + depends on I2C + config PL310 bool diff --git a/hw/misc/meson.build b/hw/misc/meson.build index 33659313b4..f60de33f9a 100644 --- a/hw/misc/meson.build +++ b/hw/misc/meson.build @@ -138,7 +138,7 @@ system_ss.add(when: 'CONFIG_NRF51_SOC', if_true: files('nrf51_rng.c')) system_ss.add(when: 'CONFIG_GRLIB', if_true: files('grlib_ahb_apb_pnp.c')) -system_ss.add(when: 'CONFIG_I2C', if_true: files('i2c-echo.c')) +system_ss.add(when: 'CONFIG_I2C_ECHO', if_true: files('i2c-echo.c')) specific_ss.add(when: 'CONFIG_AVR_POWER', if_true: files('avr_power.c')) From abf8c47f44f7a9b6c66214e9a0c59336e8728074 Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Thu, 12 Oct 2023 13:14:01 +0200 Subject: [PATCH 0597/1077] MAINTAINERS: Add include/sysemu/qtest.h to the qtest section MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We already list system/qtest.c in the qtest section, so the corresponding header file should be listed here, too. Message-ID: <20231012111401.871711-1-thuth@redhat.com> Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Thomas Huth --- MAINTAINERS | 1 + 1 file changed, 1 insertion(+) diff --git a/MAINTAINERS b/MAINTAINERS index 1c9b49c00f..3f449bfe58 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -3128,6 +3128,7 @@ M: Laurent Vivier R: Paolo Bonzini S: Maintained F: system/qtest.c +F: include/sysemu/qtest.h F: accel/qtest/ F: tests/qtest/ F: docs/devel/qgraph.rst From 552b25229cf7c65d31ac9a60b1d9202672dd9c61 Mon Sep 17 00:00:00 2001 From: David Hildenbrand Date: Tue, 26 Sep 2023 20:57:21 +0200 Subject: [PATCH 0598/1077] vhost: Rework memslot filtering and fix "used_memslot" tracking Having multiple vhost devices, some filtering out fd-less memslots and some not, can mess up the "used_memslot" accounting. Consequently our "free memslot" checks become unreliable and we might run out of free memslots at runtime later. An example sequence which can trigger a potential issue that involves different vhost backends (vhost-kernel and vhost-user) and hotplugged memory devices can be found at [1]. Let's make the filtering mechanism less generic and distinguish between backends that support private memslots (without a fd) and ones that only support shared memslots (with a fd). Track the used_memslots for both cases separately and use the corresponding value when required. Note: Most probably we should filter out MAP_PRIVATE fd-based RAM regions (for example, via memory-backend-memfd,...,shared=off or as default with memory-backend-file) as well. When not using MAP_SHARED, it might not work as expected. Add a TODO for now. [1] https://lkml.kernel.org/r/fad9136f-08d3-3fd9-71a1-502069c000cf@redhat.com Message-ID: <20230926185738.277351-2-david@redhat.com> Fixes: 988a27754bbb ("vhost: allow backends to filter memory sections") Cc: Tiwei Bie Acked-by: Igor Mammedov Reviewed-by: Peter Xu Reviewed-by: Michael S. Tsirkin Signed-off-by: David Hildenbrand --- hw/virtio/vhost-user.c | 7 ++-- hw/virtio/vhost.c | 56 ++++++++++++++++++++++++++----- include/hw/virtio/vhost-backend.h | 5 ++- 3 files changed, 52 insertions(+), 16 deletions(-) diff --git a/hw/virtio/vhost-user.c b/hw/virtio/vhost-user.c index 3766b415f8..85e99061d3 100644 --- a/hw/virtio/vhost-user.c +++ b/hw/virtio/vhost-user.c @@ -2622,10 +2622,9 @@ vhost_user_crypto_close_session(struct vhost_dev *dev, uint64_t session_id) return 0; } -static bool vhost_user_mem_section_filter(struct vhost_dev *dev, - MemoryRegionSection *section) +static bool vhost_user_no_private_memslots(struct vhost_dev *dev) { - return memory_region_get_fd(section->mr) >= 0; + return true; } static int vhost_user_get_inflight_fd(struct vhost_dev *dev, @@ -2868,6 +2867,7 @@ const VhostOps user_ops = { .vhost_backend_init = vhost_user_backend_init, .vhost_backend_cleanup = vhost_user_backend_cleanup, .vhost_backend_memslots_limit = vhost_user_memslots_limit, + .vhost_backend_no_private_memslots = vhost_user_no_private_memslots, .vhost_set_log_base = vhost_user_set_log_base, .vhost_set_mem_table = vhost_user_set_mem_table, .vhost_set_vring_addr = vhost_user_set_vring_addr, @@ -2894,7 +2894,6 @@ const VhostOps user_ops = { .vhost_set_config = vhost_user_set_config, .vhost_crypto_create_session = vhost_user_crypto_create_session, .vhost_crypto_close_session = vhost_user_crypto_close_session, - .vhost_backend_mem_section_filter = vhost_user_mem_section_filter, .vhost_get_inflight_fd = vhost_user_get_inflight_fd, .vhost_set_inflight_fd = vhost_user_set_inflight_fd, .vhost_dev_start = vhost_user_dev_start, diff --git a/hw/virtio/vhost.c b/hw/virtio/vhost.c index 9cfac40fde..0edd31a7e8 100644 --- a/hw/virtio/vhost.c +++ b/hw/virtio/vhost.c @@ -45,20 +45,33 @@ static struct vhost_log *vhost_log; static struct vhost_log *vhost_log_shm; +/* Memslots used by backends that support private memslots (without an fd). */ static unsigned int used_memslots; + +/* Memslots used by backends that only support shared memslots (with an fd). */ +static unsigned int used_shared_memslots; + static QLIST_HEAD(, vhost_dev) vhost_devices = QLIST_HEAD_INITIALIZER(vhost_devices); bool vhost_has_free_slot(void) { - unsigned int slots_limit = ~0U; + unsigned int free = UINT_MAX; struct vhost_dev *hdev; QLIST_FOREACH(hdev, &vhost_devices, entry) { unsigned int r = hdev->vhost_ops->vhost_backend_memslots_limit(hdev); - slots_limit = MIN(slots_limit, r); + unsigned int cur_free; + + if (hdev->vhost_ops->vhost_backend_no_private_memslots && + hdev->vhost_ops->vhost_backend_no_private_memslots(hdev)) { + cur_free = r - used_shared_memslots; + } else { + cur_free = r - used_memslots; + } + free = MIN(free, cur_free); } - return slots_limit > used_memslots; + return free > 0; } static void vhost_dev_sync_region(struct vhost_dev *dev, @@ -474,8 +487,7 @@ static int vhost_verify_ring_mappings(struct vhost_dev *dev, * vhost_section: identify sections needed for vhost access * * We only care about RAM sections here (where virtqueue and guest - * internals accessed by virtio might live). If we find one we still - * allow the backend to potentially filter it out of our list. + * internals accessed by virtio might live). */ static bool vhost_section(struct vhost_dev *dev, MemoryRegionSection *section) { @@ -502,8 +514,16 @@ static bool vhost_section(struct vhost_dev *dev, MemoryRegionSection *section) return false; } - if (dev->vhost_ops->vhost_backend_mem_section_filter && - !dev->vhost_ops->vhost_backend_mem_section_filter(dev, section)) { + /* + * Some backends (like vhost-user) can only handle memory regions + * that have an fd (can be mapped into a different process). Filter + * the ones without an fd out, if requested. + * + * TODO: we might have to limit to MAP_SHARED as well. + */ + if (memory_region_get_fd(section->mr) < 0 && + dev->vhost_ops->vhost_backend_no_private_memslots && + dev->vhost_ops->vhost_backend_no_private_memslots(dev)) { trace_vhost_reject_section(mr->name, 2); return false; } @@ -568,7 +588,14 @@ static void vhost_commit(MemoryListener *listener) dev->n_mem_sections * sizeof dev->mem->regions[0]; dev->mem = g_realloc(dev->mem, regions_size); dev->mem->nregions = dev->n_mem_sections; - used_memslots = dev->mem->nregions; + + if (dev->vhost_ops->vhost_backend_no_private_memslots && + dev->vhost_ops->vhost_backend_no_private_memslots(dev)) { + used_shared_memslots = dev->mem->nregions; + } else { + used_memslots = dev->mem->nregions; + } + for (i = 0; i < dev->n_mem_sections; i++) { struct vhost_memory_region *cur_vmr = dev->mem->regions + i; struct MemoryRegionSection *mrs = dev->mem_sections + i; @@ -1400,6 +1427,7 @@ int vhost_dev_init(struct vhost_dev *hdev, void *opaque, VhostBackendType backend_type, uint32_t busyloop_timeout, Error **errp) { + unsigned int used; uint64_t features; int i, r, n_initialized_vqs = 0; @@ -1495,7 +1523,17 @@ int vhost_dev_init(struct vhost_dev *hdev, void *opaque, memory_listener_register(&hdev->memory_listener, &address_space_memory); QLIST_INSERT_HEAD(&vhost_devices, hdev, entry); - if (used_memslots > hdev->vhost_ops->vhost_backend_memslots_limit(hdev)) { + /* + * The listener we registered properly updated the corresponding counter. + * So we can trust that these values are accurate. + */ + if (hdev->vhost_ops->vhost_backend_no_private_memslots && + hdev->vhost_ops->vhost_backend_no_private_memslots(hdev)) { + used = used_shared_memslots; + } else { + used = used_memslots; + } + if (used > hdev->vhost_ops->vhost_backend_memslots_limit(hdev)) { error_setg(errp, "vhost backend memory slots limit is less" " than current number of present memory slots"); r = -EINVAL; diff --git a/include/hw/virtio/vhost-backend.h b/include/hw/virtio/vhost-backend.h index 1860b541d8..d4aa635153 100644 --- a/include/hw/virtio/vhost-backend.h +++ b/include/hw/virtio/vhost-backend.h @@ -108,8 +108,7 @@ typedef int (*vhost_crypto_create_session_op)(struct vhost_dev *dev, typedef int (*vhost_crypto_close_session_op)(struct vhost_dev *dev, uint64_t session_id); -typedef bool (*vhost_backend_mem_section_filter_op)(struct vhost_dev *dev, - MemoryRegionSection *section); +typedef bool (*vhost_backend_no_private_memslots_op)(struct vhost_dev *dev); typedef int (*vhost_get_inflight_fd_op)(struct vhost_dev *dev, uint16_t queue_size, @@ -138,6 +137,7 @@ typedef struct VhostOps { vhost_backend_init vhost_backend_init; vhost_backend_cleanup vhost_backend_cleanup; vhost_backend_memslots_limit vhost_backend_memslots_limit; + vhost_backend_no_private_memslots_op vhost_backend_no_private_memslots; vhost_net_set_backend_op vhost_net_set_backend; vhost_net_set_mtu_op vhost_net_set_mtu; vhost_scsi_set_endpoint_op vhost_scsi_set_endpoint; @@ -172,7 +172,6 @@ typedef struct VhostOps { vhost_set_config_op vhost_set_config; vhost_crypto_create_session_op vhost_crypto_create_session; vhost_crypto_close_session_op vhost_crypto_close_session; - vhost_backend_mem_section_filter_op vhost_backend_mem_section_filter; vhost_get_inflight_fd_op vhost_get_inflight_fd; vhost_set_inflight_fd_op vhost_set_inflight_fd; vhost_dev_start_op vhost_dev_start; From 309ebfa691eb73648e77fc5a775986c12951df67 Mon Sep 17 00:00:00 2001 From: David Hildenbrand Date: Tue, 26 Sep 2023 20:57:22 +0200 Subject: [PATCH 0599/1077] vhost: Remove vhost_backend_can_merge() callback Checking whether the memory regions are equal is sufficient: if they are equal, then most certainly the contained fd is equal. The whole vhost-user memslot handling is suboptimal and overly complicated. We shouldn't have to lookup a RAM memory regions we got notified about in vhost_user_get_mr_data() using a host pointer. But that requires a bigger rework -- especially an alternative vhost_set_mem_table() backend call that simply consumes MemoryRegionSections. For now, let's just drop vhost_backend_can_merge(). Message-ID: <20230926185738.277351-3-david@redhat.com> Acked-by: Stefan Hajnoczi Reviewed-by: Igor Mammedov Acked-by: Igor Mammedov Reviewed-by: Peter Xu Reviewed-by: Michael S. Tsirkin Signed-off-by: David Hildenbrand --- hw/virtio/vhost-user.c | 14 -------------- hw/virtio/vhost-vdpa.c | 1 - hw/virtio/vhost.c | 6 +----- include/hw/virtio/vhost-backend.h | 4 ---- 4 files changed, 1 insertion(+), 24 deletions(-) diff --git a/hw/virtio/vhost-user.c b/hw/virtio/vhost-user.c index 85e99061d3..68eb1f0c99 100644 --- a/hw/virtio/vhost-user.c +++ b/hw/virtio/vhost-user.c @@ -2327,19 +2327,6 @@ static int vhost_user_migration_done(struct vhost_dev *dev, char* mac_addr) return -ENOTSUP; } -static bool vhost_user_can_merge(struct vhost_dev *dev, - uint64_t start1, uint64_t size1, - uint64_t start2, uint64_t size2) -{ - ram_addr_t offset; - int mfd, rfd; - - (void)vhost_user_get_mr_data(start1, &offset, &mfd); - (void)vhost_user_get_mr_data(start2, &offset, &rfd); - - return mfd == rfd; -} - static int vhost_user_net_set_mtu(struct vhost_dev *dev, uint16_t mtu) { VhostUserMsg msg; @@ -2886,7 +2873,6 @@ const VhostOps user_ops = { .vhost_set_vring_enable = vhost_user_set_vring_enable, .vhost_requires_shm_log = vhost_user_requires_shm_log, .vhost_migration_done = vhost_user_migration_done, - .vhost_backend_can_merge = vhost_user_can_merge, .vhost_net_set_mtu = vhost_user_net_set_mtu, .vhost_set_iotlb_callback = vhost_user_set_iotlb_callback, .vhost_send_device_iotlb_msg = vhost_user_send_device_iotlb_msg, diff --git a/hw/virtio/vhost-vdpa.c b/hw/virtio/vhost-vdpa.c index 89ff02a999..819b2d811a 100644 --- a/hw/virtio/vhost-vdpa.c +++ b/hw/virtio/vhost-vdpa.c @@ -1512,7 +1512,6 @@ const VhostOps vdpa_ops = { .vhost_set_config = vhost_vdpa_set_config, .vhost_requires_shm_log = NULL, .vhost_migration_done = NULL, - .vhost_backend_can_merge = NULL, .vhost_net_set_mtu = NULL, .vhost_set_iotlb_callback = NULL, .vhost_send_device_iotlb_msg = NULL, diff --git a/hw/virtio/vhost.c b/hw/virtio/vhost.c index 0edd31a7e8..530a65c1b4 100644 --- a/hw/virtio/vhost.c +++ b/hw/virtio/vhost.c @@ -728,11 +728,7 @@ static void vhost_region_add_section(struct vhost_dev *dev, size_t offset = mrs_gpa - prev_gpa_start; if (prev_host_start + offset == mrs_host && - section->mr == prev_sec->mr && - (!dev->vhost_ops->vhost_backend_can_merge || - dev->vhost_ops->vhost_backend_can_merge(dev, - mrs_host, mrs_size, - prev_host_start, prev_size))) { + section->mr == prev_sec->mr) { uint64_t max_end = MAX(prev_host_end, mrs_host + mrs_size); need_add = false; prev_sec->offset_within_address_space = diff --git a/include/hw/virtio/vhost-backend.h b/include/hw/virtio/vhost-backend.h index d4aa635153..96ccc18cd3 100644 --- a/include/hw/virtio/vhost-backend.h +++ b/include/hw/virtio/vhost-backend.h @@ -86,9 +86,6 @@ typedef int (*vhost_set_vring_enable_op)(struct vhost_dev *dev, typedef bool (*vhost_requires_shm_log_op)(struct vhost_dev *dev); typedef int (*vhost_migration_done_op)(struct vhost_dev *dev, char *mac_addr); -typedef bool (*vhost_backend_can_merge_op)(struct vhost_dev *dev, - uint64_t start1, uint64_t size1, - uint64_t start2, uint64_t size2); typedef int (*vhost_vsock_set_guest_cid_op)(struct vhost_dev *dev, uint64_t guest_cid); typedef int (*vhost_vsock_set_running_op)(struct vhost_dev *dev, int start); @@ -163,7 +160,6 @@ typedef struct VhostOps { vhost_set_vring_enable_op vhost_set_vring_enable; vhost_requires_shm_log_op vhost_requires_shm_log; vhost_migration_done_op vhost_migration_done; - vhost_backend_can_merge_op vhost_backend_can_merge; vhost_vsock_set_guest_cid_op vhost_vsock_set_guest_cid; vhost_vsock_set_running_op vhost_vsock_set_running; vhost_set_iotlb_callback_op vhost_set_iotlb_callback; From 022f033bd77a54a395f9df50a3201f059b80a2d9 Mon Sep 17 00:00:00 2001 From: David Hildenbrand Date: Tue, 26 Sep 2023 20:57:23 +0200 Subject: [PATCH 0600/1077] softmmu/physmem: Fixup qemu_ram_block_from_host() documentation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Let's fixup the documentation (e.g., removing traces of the ram_addr parameter that no longer exists) and move it to the header file while at it. Message-ID: <20230926185738.277351-4-david@redhat.com> Suggested-by: Igor Mammedov Acked-by: Igor Mammedov Reviewed-by: Peter Xu Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Michael S. Tsirkin Signed-off-by: David Hildenbrand --- include/exec/cpu-common.h | 15 +++++++++++++++ system/physmem.c | 17 ----------------- 2 files changed, 15 insertions(+), 17 deletions(-) diff --git a/include/exec/cpu-common.h b/include/exec/cpu-common.h index 605b160a7e..30c376a4de 100644 --- a/include/exec/cpu-common.h +++ b/include/exec/cpu-common.h @@ -83,6 +83,21 @@ void qemu_ram_remap(ram_addr_t addr, ram_addr_t length); ram_addr_t qemu_ram_addr_from_host(void *ptr); ram_addr_t qemu_ram_addr_from_host_nofail(void *ptr); RAMBlock *qemu_ram_block_by_name(const char *name); + +/* + * Translates a host ptr back to a RAMBlock and an offset in that RAMBlock. + * + * @ptr: The host pointer to translate. + * @round_offset: Whether to round the result offset down to a target page + * @offset: Will be set to the offset within the returned RAMBlock. + * + * Returns: RAMBlock (or NULL if not found) + * + * By the time this function returns, the returned pointer is not protected + * by RCU anymore. If the caller is not within an RCU critical section and + * does not hold the iothread lock, it must have other means of protecting the + * pointer, such as a reference to the memory region that owns the RAMBlock. + */ RAMBlock *qemu_ram_block_from_host(void *ptr, bool round_offset, ram_addr_t *offset); ram_addr_t qemu_ram_block_host_offset(RAMBlock *rb, void *host); diff --git a/system/physmem.c b/system/physmem.c index edc3ed8ab9..fc2b0fee01 100644 --- a/system/physmem.c +++ b/system/physmem.c @@ -2221,23 +2221,6 @@ ram_addr_t qemu_ram_block_host_offset(RAMBlock *rb, void *host) return res; } -/* - * Translates a host ptr back to a RAMBlock, a ram_addr and an offset - * in that RAMBlock. - * - * ptr: Host pointer to look up - * round_offset: If true round the result offset down to a page boundary - * *ram_addr: set to result ram_addr - * *offset: set to result offset within the RAMBlock - * - * Returns: RAMBlock (or NULL if not found) - * - * By the time this function returns, the returned pointer is not protected - * by RCU anymore. If the caller is not within an RCU critical section and - * does not hold the iothread lock, it must have other means of protecting the - * pointer, such as a reference to the region that includes the incoming - * ram_addr_t. - */ RAMBlock *qemu_ram_block_from_host(void *ptr, bool round_offset, ram_addr_t *offset) { From 5b23186a954a88ecabb2696cd846e0e67a9e349c Mon Sep 17 00:00:00 2001 From: David Hildenbrand Date: Tue, 26 Sep 2023 20:57:24 +0200 Subject: [PATCH 0601/1077] kvm: Return number of free memslots MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Let's return the number of free slots instead of only checking if there is a free slot. While at it, check all address spaces, which will also consider SMM under x86 correctly. This is a preparation for memory devices that consume multiple memslots. Message-ID: <20230926185738.277351-5-david@redhat.com> Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Maciej S. Szmigiero Reviewed-by: Michael S. Tsirkin Signed-off-by: David Hildenbrand --- accel/kvm/kvm-all.c | 33 ++++++++++++++++++++------------- accel/stubs/kvm-stub.c | 4 ++-- hw/mem/memory-device.c | 2 +- include/sysemu/kvm.h | 2 +- include/sysemu/kvm_int.h | 1 + 5 files changed, 25 insertions(+), 17 deletions(-) diff --git a/accel/kvm/kvm-all.c b/accel/kvm/kvm-all.c index 72e1d1141c..5937e46e12 100644 --- a/accel/kvm/kvm-all.c +++ b/accel/kvm/kvm-all.c @@ -181,6 +181,24 @@ int kvm_get_max_memslots(void) return s->nr_slots; } +unsigned int kvm_get_free_memslots(void) +{ + unsigned int used_slots = 0; + KVMState *s = kvm_state; + int i; + + kvm_slots_lock(); + for (i = 0; i < s->nr_as; i++) { + if (!s->as[i].ml) { + continue; + } + used_slots = MAX(used_slots, s->as[i].ml->nr_used_slots); + } + kvm_slots_unlock(); + + return s->nr_slots - used_slots; +} + /* Called with KVMMemoryListener.slots_lock held */ static KVMSlot *kvm_get_free_slot(KVMMemoryListener *kml) { @@ -196,19 +214,6 @@ static KVMSlot *kvm_get_free_slot(KVMMemoryListener *kml) return NULL; } -bool kvm_has_free_slot(MachineState *ms) -{ - KVMState *s = KVM_STATE(ms->accelerator); - bool result; - KVMMemoryListener *kml = &s->memory_listener; - - kvm_slots_lock(); - result = !!kvm_get_free_slot(kml); - kvm_slots_unlock(); - - return result; -} - /* Called with KVMMemoryListener.slots_lock held */ static KVMSlot *kvm_alloc_slot(KVMMemoryListener *kml) { @@ -1387,6 +1392,7 @@ static void kvm_set_phys_mem(KVMMemoryListener *kml, } start_addr += slot_size; size -= slot_size; + kml->nr_used_slots--; } while (size); return; } @@ -1412,6 +1418,7 @@ static void kvm_set_phys_mem(KVMMemoryListener *kml, ram_start_offset += slot_size; ram += slot_size; size -= slot_size; + kml->nr_used_slots++; } while (size); } diff --git a/accel/stubs/kvm-stub.c b/accel/stubs/kvm-stub.c index 235dc661bc..a5d4442d8f 100644 --- a/accel/stubs/kvm-stub.c +++ b/accel/stubs/kvm-stub.c @@ -109,9 +109,9 @@ int kvm_irqchip_remove_irqfd_notifier_gsi(KVMState *s, EventNotifier *n, return -ENOSYS; } -bool kvm_has_free_slot(MachineState *ms) +unsigned int kvm_get_free_memslots(void) { - return false; + return 0; } void kvm_init_cpu_signals(CPUState *cpu) diff --git a/hw/mem/memory-device.c b/hw/mem/memory-device.c index 667d56bd29..98e355c960 100644 --- a/hw/mem/memory-device.c +++ b/hw/mem/memory-device.c @@ -59,7 +59,7 @@ static void memory_device_check_addable(MachineState *ms, MemoryRegion *mr, const uint64_t size = memory_region_size(mr); /* we will need a new memory slot for kvm and vhost */ - if (kvm_enabled() && !kvm_has_free_slot(ms)) { + if (kvm_enabled() && !kvm_get_free_memslots()) { error_setg(errp, "hypervisor has no free memory slots left"); return; } diff --git a/include/sysemu/kvm.h b/include/sysemu/kvm.h index ee9025f8e9..c3d831baef 100644 --- a/include/sysemu/kvm.h +++ b/include/sysemu/kvm.h @@ -215,7 +215,7 @@ typedef struct KVMRouteChange { /* external API */ -bool kvm_has_free_slot(MachineState *ms); +unsigned int kvm_get_free_memslots(void); bool kvm_has_sync_mmu(void); int kvm_has_vcpu_events(void); int kvm_has_robust_singlestep(void); diff --git a/include/sysemu/kvm_int.h b/include/sysemu/kvm_int.h index a5b9122cb8..075939a3c4 100644 --- a/include/sysemu/kvm_int.h +++ b/include/sysemu/kvm_int.h @@ -40,6 +40,7 @@ typedef struct KVMMemoryUpdate { typedef struct KVMMemoryListener { MemoryListener listener; KVMSlot *slots; + unsigned int nr_used_slots; int as_id; QSIMPLEQ_HEAD(, KVMMemoryUpdate) transaction_add; QSIMPLEQ_HEAD(, KVMMemoryUpdate) transaction_del; From 8c49951c4ad9798cbe19f74f7645393ee625c180 Mon Sep 17 00:00:00 2001 From: David Hildenbrand Date: Tue, 26 Sep 2023 20:57:25 +0200 Subject: [PATCH 0602/1077] vhost: Return number of free memslots Let's return the number of free slots instead of only checking if there is a free slot. Required to support memory devices that consume multiple memslots. This is a preparation for memory devices that consume multiple memslots. Message-ID: <20230926185738.277351-6-david@redhat.com> Reviewed-by: Maciej S. Szmigiero Reviewed-by: Michael S. Tsirkin Signed-off-by: David Hildenbrand --- hw/mem/memory-device.c | 2 +- hw/virtio/vhost-stub.c | 4 ++-- hw/virtio/vhost.c | 4 ++-- include/hw/virtio/vhost.h | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/hw/mem/memory-device.c b/hw/mem/memory-device.c index 98e355c960..e09960744d 100644 --- a/hw/mem/memory-device.c +++ b/hw/mem/memory-device.c @@ -63,7 +63,7 @@ static void memory_device_check_addable(MachineState *ms, MemoryRegion *mr, error_setg(errp, "hypervisor has no free memory slots left"); return; } - if (!vhost_has_free_slot()) { + if (!vhost_get_free_memslots()) { error_setg(errp, "a used vhost backend has no free memory slots left"); return; } diff --git a/hw/virtio/vhost-stub.c b/hw/virtio/vhost-stub.c index aa858ef3fb..d53dd9d288 100644 --- a/hw/virtio/vhost-stub.c +++ b/hw/virtio/vhost-stub.c @@ -2,9 +2,9 @@ #include "hw/virtio/vhost.h" #include "hw/virtio/vhost-user.h" -bool vhost_has_free_slot(void) +unsigned int vhost_get_free_memslots(void) { - return true; + return UINT_MAX; } bool vhost_user_init(VhostUserState *user, CharBackend *chr, Error **errp) diff --git a/hw/virtio/vhost.c b/hw/virtio/vhost.c index 530a65c1b4..82c3d20521 100644 --- a/hw/virtio/vhost.c +++ b/hw/virtio/vhost.c @@ -54,7 +54,7 @@ static unsigned int used_shared_memslots; static QLIST_HEAD(, vhost_dev) vhost_devices = QLIST_HEAD_INITIALIZER(vhost_devices); -bool vhost_has_free_slot(void) +unsigned int vhost_get_free_memslots(void) { unsigned int free = UINT_MAX; struct vhost_dev *hdev; @@ -71,7 +71,7 @@ bool vhost_has_free_slot(void) } free = MIN(free, cur_free); } - return free > 0; + return free; } static void vhost_dev_sync_region(struct vhost_dev *dev, diff --git a/include/hw/virtio/vhost.h b/include/hw/virtio/vhost.h index 6a173cb9fa..603bf834be 100644 --- a/include/hw/virtio/vhost.h +++ b/include/hw/virtio/vhost.h @@ -315,7 +315,7 @@ uint64_t vhost_get_features(struct vhost_dev *hdev, const int *feature_bits, */ void vhost_ack_features(struct vhost_dev *hdev, const int *feature_bits, uint64_t features); -bool vhost_has_free_slot(void); +unsigned int vhost_get_free_memslots(void); int vhost_net_set_backend(struct vhost_dev *hdev, struct vhost_vring_file *file); From 7975feece9053b73a2b7b015840f85e9f6ad25db Mon Sep 17 00:00:00 2001 From: David Hildenbrand Date: Tue, 26 Sep 2023 20:57:26 +0200 Subject: [PATCH 0603/1077] memory-device: Support memory devices with multiple memslots We want to support memory devices that have a memory region container as device memory region that maps multiple RAM memory regions. Let's start by supporting memory devices that statically map multiple RAM memory regions and, thereby, consume multiple memslots. We already have one device that uses a container as device memory region: NVDIMMs. However, a NVDIMM always ends up consuming exactly one memslot. Let's add support for that by asking the memory device via a new callback how many memslots it requires. Message-ID: <20230926185738.277351-7-david@redhat.com> Reviewed-by: Maciej S. Szmigiero Reviewed-by: Michael S. Tsirkin Signed-off-by: David Hildenbrand --- hw/mem/memory-device.c | 27 +++++++++++++++++++-------- include/hw/mem/memory-device.h | 18 ++++++++++++++++++ 2 files changed, 37 insertions(+), 8 deletions(-) diff --git a/hw/mem/memory-device.c b/hw/mem/memory-device.c index e09960744d..0eec0872a9 100644 --- a/hw/mem/memory-device.c +++ b/hw/mem/memory-device.c @@ -52,19 +52,30 @@ static int memory_device_build_list(Object *obj, void *opaque) return 0; } -static void memory_device_check_addable(MachineState *ms, MemoryRegion *mr, - Error **errp) +static unsigned int memory_device_get_memslots(MemoryDeviceState *md) +{ + const MemoryDeviceClass *mdc = MEMORY_DEVICE_GET_CLASS(md); + + if (mdc->get_memslots) { + return mdc->get_memslots(md); + } + return 1; +} + +static void memory_device_check_addable(MachineState *ms, MemoryDeviceState *md, + MemoryRegion *mr, Error **errp) { const uint64_t used_region_size = ms->device_memory->used_region_size; const uint64_t size = memory_region_size(mr); + const unsigned int required_memslots = memory_device_get_memslots(md); - /* we will need a new memory slot for kvm and vhost */ - if (kvm_enabled() && !kvm_get_free_memslots()) { - error_setg(errp, "hypervisor has no free memory slots left"); + /* we will need memory slots for kvm and vhost */ + if (kvm_enabled() && kvm_get_free_memslots() < required_memslots) { + error_setg(errp, "hypervisor has not enough free memory slots left"); return; } - if (!vhost_get_free_memslots()) { - error_setg(errp, "a used vhost backend has no free memory slots left"); + if (vhost_get_free_memslots() < required_memslots) { + error_setg(errp, "a used vhost backend has not enough free memory slots left"); return; } @@ -233,7 +244,7 @@ void memory_device_pre_plug(MemoryDeviceState *md, MachineState *ms, goto out; } - memory_device_check_addable(ms, mr, &local_err); + memory_device_check_addable(ms, md, mr, &local_err); if (local_err) { goto out; } diff --git a/include/hw/mem/memory-device.h b/include/hw/mem/memory-device.h index 48d2611fc5..b51a579fb9 100644 --- a/include/hw/mem/memory-device.h +++ b/include/hw/mem/memory-device.h @@ -41,6 +41,11 @@ typedef struct MemoryDeviceState MemoryDeviceState; * successive memory regions are used, a covering memory region has to * be provided. Scattered memory regions are not supported for single * devices. + * + * The device memory region returned via @get_memory_region may either be a + * single RAM memory region or a memory region container with subregions + * that are RAM memory regions or aliases to RAM memory regions. Other + * memory regions or subregions are not supported. */ struct MemoryDeviceClass { /* private */ @@ -88,6 +93,19 @@ struct MemoryDeviceClass { */ MemoryRegion *(*get_memory_region)(MemoryDeviceState *md, Error **errp); + /* + * Optional for memory devices that require only a single memslot, + * required for all other memory devices: Return the number of memslots + * (distinct RAM memory regions in the device memory region) that are + * required by the device. + * + * If this function is not implemented, the assumption is "1". + * + * Called when (un)plugging the memory device, to check if the requirements + * can be satisfied, and to do proper accounting. + */ + unsigned int (*get_memslots)(MemoryDeviceState *md); + /* * Optional: Return the desired minimum alignment of the device in guest * physical address space. The final alignment is computed based on this From 759bac673a8de9d6db50b0f96caa7b70cf0d1694 Mon Sep 17 00:00:00 2001 From: David Hildenbrand Date: Tue, 26 Sep 2023 20:57:27 +0200 Subject: [PATCH 0604/1077] stubs: Rename qmp_memory_device.c to memory_device.c We want to place non-qmp stubs in there, so let's rename it. While at it, put it into the MAINTAINERS file under "Memory devices". Message-ID: <20230926185738.277351-8-david@redhat.com> Reviewed-by: Maciej S. Szmigiero Reviewed-by: Michael S. Tsirkin Signed-off-by: David Hildenbrand --- MAINTAINERS | 1 + stubs/{qmp_memory_device.c => memory_device.c} | 0 stubs/meson.build | 2 +- 3 files changed, 2 insertions(+), 1 deletion(-) rename stubs/{qmp_memory_device.c => memory_device.c} (100%) diff --git a/MAINTAINERS b/MAINTAINERS index c3cc12dc29..0c585d093f 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -2876,6 +2876,7 @@ F: hw/mem/pc-dimm.c F: include/hw/mem/memory-device.h F: include/hw/mem/nvdimm.h F: include/hw/mem/pc-dimm.h +F: stubs/memory_device.c F: docs/nvdimm.txt SPICE diff --git a/stubs/qmp_memory_device.c b/stubs/memory_device.c similarity index 100% rename from stubs/qmp_memory_device.c rename to stubs/memory_device.c diff --git a/stubs/meson.build b/stubs/meson.build index ef6e39a64d..cde44972bf 100644 --- a/stubs/meson.build +++ b/stubs/meson.build @@ -32,7 +32,7 @@ stub_ss.add(files('monitor.c')) stub_ss.add(files('monitor-core.c')) stub_ss.add(files('physmem.c')) stub_ss.add(files('qemu-timer-notify-cb.c')) -stub_ss.add(files('qmp_memory_device.c')) +stub_ss.add(files('memory_device.c')) stub_ss.add(files('qmp-command-available.c')) stub_ss.add(files('qmp-quit.c')) stub_ss.add(files('qtest.c')) From f9716f4b0d6eaee5d0b1ccf428a102e0c148fa30 Mon Sep 17 00:00:00 2001 From: David Hildenbrand Date: Tue, 26 Sep 2023 20:57:28 +0200 Subject: [PATCH 0605/1077] memory-device: Track required and actually used memslots in DeviceMemoryState Let's track how many memslots are required by plugged memory devices and how many are currently actually getting used by plugged memory devices. "required - used" is the number of reserved memslots. For now, the number of used and required memslots is always equal, and there are no reservations. This is a preparation for memory devices that want to dynamically consume memslots after initially specifying how many they require -- where we'll end up with reserved memslots. To track the number of used memslots, create a new address space for our device memory and register a memory listener (add/remove) for that address space. Message-ID: <20230926185738.277351-9-david@redhat.com> Reviewed-by: Maciej S. Szmigiero Reviewed-by: Michael S. Tsirkin Signed-off-by: David Hildenbrand --- hw/mem/memory-device.c | 54 ++++++++++++++++++++++++++++++++++++++++++ include/hw/boards.h | 10 +++++++- 2 files changed, 63 insertions(+), 1 deletion(-) diff --git a/hw/mem/memory-device.c b/hw/mem/memory-device.c index 0eec0872a9..d37cfbd65d 100644 --- a/hw/mem/memory-device.c +++ b/hw/mem/memory-device.c @@ -286,6 +286,7 @@ void memory_device_plug(MemoryDeviceState *md, MachineState *ms) g_assert(ms->device_memory); ms->device_memory->used_region_size += memory_region_size(mr); + ms->device_memory->required_memslots += memory_device_get_memslots(md); memory_region_add_subregion(&ms->device_memory->mr, addr - ms->device_memory->base, mr); trace_memory_device_plug(DEVICE(md)->id ? DEVICE(md)->id : "", addr); @@ -305,6 +306,7 @@ void memory_device_unplug(MemoryDeviceState *md, MachineState *ms) memory_region_del_subregion(&ms->device_memory->mr, mr); ms->device_memory->used_region_size -= memory_region_size(mr); + ms->device_memory->required_memslots -= memory_device_get_memslots(md); trace_memory_device_unplug(DEVICE(md)->id ? DEVICE(md)->id : "", mdc->get_addr(md)); } @@ -324,6 +326,50 @@ uint64_t memory_device_get_region_size(const MemoryDeviceState *md, return memory_region_size(mr); } +static void memory_devices_region_mod(MemoryListener *listener, + MemoryRegionSection *mrs, bool add) +{ + DeviceMemoryState *dms = container_of(listener, DeviceMemoryState, + listener); + + if (!memory_region_is_ram(mrs->mr)) { + warn_report("Unexpected memory region mapped into device memory region."); + return; + } + + /* + * The expectation is that each distinct RAM memory region section in + * our region for memory devices consumes exactly one memslot in KVM + * and in vhost. For vhost, this is true, except: + * * ROM memory regions don't consume a memslot. These get used very + * rarely for memory devices (R/O NVDIMMs). + * * Memslots without a fd (memory-backend-ram) don't necessarily + * consume a memslot. Such setups are quite rare and possibly bogus: + * the memory would be inaccessible by such vhost devices. + * + * So for vhost, in corner cases we might over-estimate the number of + * memslots that are currently used or that might still be reserved + * (required - used). + */ + dms->used_memslots += add ? 1 : -1; + + if (dms->used_memslots > dms->required_memslots) { + warn_report("Memory devices use more memory slots than indicated as required."); + } +} + +static void memory_devices_region_add(MemoryListener *listener, + MemoryRegionSection *mrs) +{ + return memory_devices_region_mod(listener, mrs, true); +} + +static void memory_devices_region_del(MemoryListener *listener, + MemoryRegionSection *mrs) +{ + return memory_devices_region_mod(listener, mrs, false); +} + void machine_memory_devices_init(MachineState *ms, hwaddr base, uint64_t size) { g_assert(size); @@ -333,8 +379,16 @@ void machine_memory_devices_init(MachineState *ms, hwaddr base, uint64_t size) memory_region_init(&ms->device_memory->mr, OBJECT(ms), "device-memory", size); + address_space_init(&ms->device_memory->as, &ms->device_memory->mr, + "device-memory"); memory_region_add_subregion(get_system_memory(), ms->device_memory->base, &ms->device_memory->mr); + + /* Track the number of memslots used by memory devices. */ + ms->device_memory->listener.region_add = memory_devices_region_add; + ms->device_memory->listener.region_del = memory_devices_region_del; + memory_listener_register(&ms->device_memory->listener, + &ms->device_memory->as); } static const TypeInfo memory_device_info = { diff --git a/include/hw/boards.h b/include/hw/boards.h index 55a64a13fd..01bddb258f 100644 --- a/include/hw/boards.h +++ b/include/hw/boards.h @@ -297,15 +297,23 @@ struct MachineClass { * DeviceMemoryState: * @base: address in guest physical address space where the memory * address space for memory devices starts - * @mr: address space container for memory devices + * @mr: memory region container for memory devices + * @as: address space for memory devices + * @listener: memory listener used to track used memslots in the address space * @dimm_size: the sum of plugged DIMMs' sizes * @used_region_size: the part of @mr already used by memory devices + * @required_memslots: the number of memslots required by memory devices + * @used_memslots: the number of memslots currently used by memory devices */ typedef struct DeviceMemoryState { hwaddr base; MemoryRegion mr; + AddressSpace as; + MemoryListener listener; uint64_t dimm_size; uint64_t used_region_size; + unsigned int required_memslots; + unsigned int used_memslots; } DeviceMemoryState; /** From 766aa0a654d887ad8fed2f116c84a89e20102c14 Mon Sep 17 00:00:00 2001 From: David Hildenbrand Date: Tue, 26 Sep 2023 20:57:29 +0200 Subject: [PATCH 0606/1077] memory-device,vhost: Support memory devices that dynamically consume memslots We want to support memory devices that have a dynamically managed memory region container as device memory region. This device memory region maps multiple RAM memory subregions (e.g., aliases to the same RAM memory region), whereby these subregions can be (un)mapped on demand. Each RAM subregion will consume a memslot in KVM and vhost, resulting in such a new device consuming memslots dynamically, and initially usually 0. We already track the number of used vs. required memslots for all memslots. From that, we can derive the number of reserved memslots that must not be used otherwise. The target use case is virtio-mem and the hyper-v balloon, which will dynamically map aliases to RAM memory region into their device memory region container. Properly document what's supported and what's not and extend the vhost memslot check accordingly. Message-ID: <20230926185738.277351-10-david@redhat.com> Reviewed-by: Maciej S. Szmigiero Reviewed-by: Michael S. Tsirkin Signed-off-by: David Hildenbrand --- hw/mem/memory-device.c | 29 +++++++++++++++++++++++++++-- hw/virtio/vhost.c | 18 ++++++++++++++---- include/hw/mem/memory-device.h | 7 +++++++ stubs/memory_device.c | 5 +++++ 4 files changed, 53 insertions(+), 6 deletions(-) diff --git a/hw/mem/memory-device.c b/hw/mem/memory-device.c index d37cfbd65d..1b14ba5661 100644 --- a/hw/mem/memory-device.c +++ b/hw/mem/memory-device.c @@ -62,19 +62,44 @@ static unsigned int memory_device_get_memslots(MemoryDeviceState *md) return 1; } +/* + * Memslots that are reserved by memory devices (required but still reported + * as free from KVM / vhost). + */ +static unsigned int get_reserved_memslots(MachineState *ms) +{ + if (ms->device_memory->used_memslots > + ms->device_memory->required_memslots) { + /* This is unexpected, and we warned already in the memory notifier. */ + return 0; + } + return ms->device_memory->required_memslots - + ms->device_memory->used_memslots; +} + +unsigned int memory_devices_get_reserved_memslots(void) +{ + if (!current_machine->device_memory) { + return 0; + } + return get_reserved_memslots(current_machine); +} + static void memory_device_check_addable(MachineState *ms, MemoryDeviceState *md, MemoryRegion *mr, Error **errp) { const uint64_t used_region_size = ms->device_memory->used_region_size; const uint64_t size = memory_region_size(mr); const unsigned int required_memslots = memory_device_get_memslots(md); + const unsigned int reserved_memslots = get_reserved_memslots(ms); /* we will need memory slots for kvm and vhost */ - if (kvm_enabled() && kvm_get_free_memslots() < required_memslots) { + if (kvm_enabled() && + kvm_get_free_memslots() < required_memslots + reserved_memslots) { error_setg(errp, "hypervisor has not enough free memory slots left"); return; } - if (vhost_get_free_memslots() < required_memslots) { + if (vhost_get_free_memslots() < required_memslots + reserved_memslots) { error_setg(errp, "a used vhost backend has not enough free memory slots left"); return; } diff --git a/hw/virtio/vhost.c b/hw/virtio/vhost.c index 82c3d20521..041a05d5f1 100644 --- a/hw/virtio/vhost.c +++ b/hw/virtio/vhost.c @@ -23,6 +23,7 @@ #include "qemu/log.h" #include "standard-headers/linux/vhost_types.h" #include "hw/virtio/virtio-bus.h" +#include "hw/mem/memory-device.h" #include "migration/blocker.h" #include "migration/qemu-file-types.h" #include "sysemu/dma.h" @@ -1423,7 +1424,7 @@ int vhost_dev_init(struct vhost_dev *hdev, void *opaque, VhostBackendType backend_type, uint32_t busyloop_timeout, Error **errp) { - unsigned int used; + unsigned int used, reserved, limit; uint64_t features; int i, r, n_initialized_vqs = 0; @@ -1529,9 +1530,18 @@ int vhost_dev_init(struct vhost_dev *hdev, void *opaque, } else { used = used_memslots; } - if (used > hdev->vhost_ops->vhost_backend_memslots_limit(hdev)) { - error_setg(errp, "vhost backend memory slots limit is less" - " than current number of present memory slots"); + /* + * We assume that all reserved memslots actually require a real memslot + * in our vhost backend. This might not be true, for example, if the + * memslot would be ROM. If ever relevant, we can optimize for that -- + * but we'll need additional information about the reservations. + */ + reserved = memory_devices_get_reserved_memslots(); + limit = hdev->vhost_ops->vhost_backend_memslots_limit(hdev); + if (used + reserved > limit) { + error_setg(errp, "vhost backend memory slots limit (%d) is less" + " than current number of used (%d) and reserved (%d)" + " memory slots for memory devices.", limit, used, reserved); r = -EINVAL; goto fail_busyloop; } diff --git a/include/hw/mem/memory-device.h b/include/hw/mem/memory-device.h index b51a579fb9..c7b624da6a 100644 --- a/include/hw/mem/memory-device.h +++ b/include/hw/mem/memory-device.h @@ -46,6 +46,12 @@ typedef struct MemoryDeviceState MemoryDeviceState; * single RAM memory region or a memory region container with subregions * that are RAM memory regions or aliases to RAM memory regions. Other * memory regions or subregions are not supported. + * + * If the device memory region returned via @get_memory_region is a + * memory region container, it's supported to dynamically (un)map subregions + * as long as the number of memslots returned by @get_memslots() won't + * be exceeded and as long as all memory regions are of the same kind (e.g., + * all RAM or all ROM). */ struct MemoryDeviceClass { /* private */ @@ -125,6 +131,7 @@ struct MemoryDeviceClass { MemoryDeviceInfoList *qmp_memory_device_list(void); uint64_t get_plugged_memory_size(void); +unsigned int memory_devices_get_reserved_memslots(void); void memory_device_pre_plug(MemoryDeviceState *md, MachineState *ms, const uint64_t *legacy_align, Error **errp); void memory_device_plug(MemoryDeviceState *md, MachineState *ms); diff --git a/stubs/memory_device.c b/stubs/memory_device.c index e75cac62dc..318a5d4187 100644 --- a/stubs/memory_device.c +++ b/stubs/memory_device.c @@ -10,3 +10,8 @@ uint64_t get_plugged_memory_size(void) { return (uint64_t)-1; } + +unsigned int memory_devices_get_reserved_memslots(void) +{ + return 0; +} From 16ab2eda57233787c2145bc5eaeabcc2852bc4c3 Mon Sep 17 00:00:00 2001 From: David Hildenbrand Date: Tue, 26 Sep 2023 20:57:30 +0200 Subject: [PATCH 0607/1077] kvm: Add stub for kvm_get_max_memslots() We'll need the stub soon from memory device context. While at it, use "unsigned int" as return value and place the declaration next to kvm_get_free_memslots(). Message-ID: <20230926185738.277351-11-david@redhat.com> Reviewed-by: Maciej S. Szmigiero Reviewed-by: Michael S. Tsirkin Signed-off-by: David Hildenbrand --- accel/kvm/kvm-all.c | 2 +- accel/stubs/kvm-stub.c | 5 +++++ include/sysemu/kvm.h | 2 +- 3 files changed, 7 insertions(+), 2 deletions(-) diff --git a/accel/kvm/kvm-all.c b/accel/kvm/kvm-all.c index 5937e46e12..3f7eafe08c 100644 --- a/accel/kvm/kvm-all.c +++ b/accel/kvm/kvm-all.c @@ -174,7 +174,7 @@ void kvm_resample_fd_notify(int gsi) } } -int kvm_get_max_memslots(void) +unsigned int kvm_get_max_memslots(void) { KVMState *s = KVM_STATE(current_accel()); diff --git a/accel/stubs/kvm-stub.c b/accel/stubs/kvm-stub.c index a5d4442d8f..51f522e52e 100644 --- a/accel/stubs/kvm-stub.c +++ b/accel/stubs/kvm-stub.c @@ -109,6 +109,11 @@ int kvm_irqchip_remove_irqfd_notifier_gsi(KVMState *s, EventNotifier *n, return -ENOSYS; } +unsigned int kvm_get_max_memslots(void) +{ + return 0; +} + unsigned int kvm_get_free_memslots(void) { return 0; diff --git a/include/sysemu/kvm.h b/include/sysemu/kvm.h index c3d831baef..97a8a4f201 100644 --- a/include/sysemu/kvm.h +++ b/include/sysemu/kvm.h @@ -215,6 +215,7 @@ typedef struct KVMRouteChange { /* external API */ +unsigned int kvm_get_max_memslots(void); unsigned int kvm_get_free_memslots(void); bool kvm_has_sync_mmu(void); int kvm_has_vcpu_events(void); @@ -552,7 +553,6 @@ int kvm_set_one_reg(CPUState *cs, uint64_t id, void *source); */ int kvm_get_one_reg(CPUState *cs, uint64_t id, void *target); struct ppc_radix_page_info *kvm_get_radix_page_info(void); -int kvm_get_max_memslots(void); /* Notify resamplefd for EOI of specific interrupts. */ void kvm_resample_fd_notify(int gsi); From cd89c065b06d49691ecb1f3707849472acdf3ea5 Mon Sep 17 00:00:00 2001 From: David Hildenbrand Date: Tue, 26 Sep 2023 20:57:31 +0200 Subject: [PATCH 0608/1077] vhost: Add vhost_get_max_memslots() Let's add vhost_get_max_memslots(). Message-ID: <20230926185738.277351-12-david@redhat.com> Reviewed-by: Maciej S. Szmigiero Reviewed-by: Michael S. Tsirkin Signed-off-by: David Hildenbrand --- hw/virtio/vhost-stub.c | 5 +++++ hw/virtio/vhost.c | 11 +++++++++++ include/hw/virtio/vhost.h | 1 + 3 files changed, 17 insertions(+) diff --git a/hw/virtio/vhost-stub.c b/hw/virtio/vhost-stub.c index d53dd9d288..52d42adab2 100644 --- a/hw/virtio/vhost-stub.c +++ b/hw/virtio/vhost-stub.c @@ -2,6 +2,11 @@ #include "hw/virtio/vhost.h" #include "hw/virtio/vhost-user.h" +unsigned int vhost_get_max_memslots(void) +{ + return UINT_MAX; +} + unsigned int vhost_get_free_memslots(void) { return UINT_MAX; diff --git a/hw/virtio/vhost.c b/hw/virtio/vhost.c index 041a05d5f1..2bdb4fb231 100644 --- a/hw/virtio/vhost.c +++ b/hw/virtio/vhost.c @@ -55,6 +55,17 @@ static unsigned int used_shared_memslots; static QLIST_HEAD(, vhost_dev) vhost_devices = QLIST_HEAD_INITIALIZER(vhost_devices); +unsigned int vhost_get_max_memslots(void) +{ + unsigned int max = UINT_MAX; + struct vhost_dev *hdev; + + QLIST_FOREACH(hdev, &vhost_devices, entry) { + max = MIN(max, hdev->vhost_ops->vhost_backend_memslots_limit(hdev)); + } + return max; +} + unsigned int vhost_get_free_memslots(void) { unsigned int free = UINT_MAX; diff --git a/include/hw/virtio/vhost.h b/include/hw/virtio/vhost.h index 603bf834be..c7e5467693 100644 --- a/include/hw/virtio/vhost.h +++ b/include/hw/virtio/vhost.h @@ -315,6 +315,7 @@ uint64_t vhost_get_features(struct vhost_dev *hdev, const int *feature_bits, */ void vhost_ack_features(struct vhost_dev *hdev, const int *feature_bits, uint64_t features); +unsigned int vhost_get_max_memslots(void); unsigned int vhost_get_free_memslots(void); int vhost_net_set_backend(struct vhost_dev *hdev, From a2335113aeda1cddad3dc4a76f2ace47a00d7ac9 Mon Sep 17 00:00:00 2001 From: David Hildenbrand Date: Tue, 26 Sep 2023 20:57:32 +0200 Subject: [PATCH 0609/1077] memory-device,vhost: Support automatic decision on the number of memslots We want to support memory devices that can automatically decide how many memslots they will use. In the worst case, they have to use a single memslot. The target use cases are virtio-mem and the hyper-v balloon. Let's calculate a reasonable limit such a memory device may use, and instruct the device to make a decision based on that limit. Use a simple heuristic that considers: * A memslot soft-limit for all memory devices of 256; also, to not consume too many memslots -- which could harm performance. * Actually still free and unreserved memslots * The percentage of the remaining device memory region that memory device will occupy. Further, while we properly check before plugging a memory device whether there still is are free memslots, we have other memslot consumers (such as boot memory, PCI BARs) that don't perform any checks and might dynamically consume memslots without any prior reservation. So we might succeed in plugging a memory device, but once we dynamically map a PCI BAR we would be in trouble. Doing accounting / reservation / checks for all such users is problematic (e.g., sometimes we might temporarily split boot memory into two memslots, triggered by the BIOS). We use the historic magic memslot number of 509 as orientation to when supporting 256 memory devices -> memslots (leaving 253 for boot memory and other devices) has been proven to work reliable. We'll fallback to suggesting a single memslot if we don't have at least 509 total memslots. Plugging vhost devices with less than 509 memslots available while we have memory devices plugged that consume multiple memslots due to automatic decisions can be problematic. Most configurations might just fail due to "limit < used + reserved", however, it can also happen that these memory devices would suddenly consume memslots that would actually be required by other memslot consumers (boot, PCI BARs) later. Note that this has always been sketchy with vhost devices that support only a small number of memslots; but we don't want to make it any worse.So let's keep it simple and simply reject plugging such vhost devices in such a configuration. Eventually, all vhost devices that want to be fully compatible with such memory devices should support a decent number of memslots (>= 509). Message-ID: <20230926185738.277351-13-david@redhat.com> Reviewed-by: Maciej S. Szmigiero Reviewed-by: Michael S. Tsirkin Signed-off-by: David Hildenbrand --- hw/mem/memory-device.c | 96 ++++++++++++++++++++++++++++++++-- hw/virtio/vhost.c | 14 ++++- include/hw/boards.h | 4 ++ include/hw/mem/memory-device.h | 32 ++++++++++++ stubs/memory_device.c | 5 ++ 5 files changed, 147 insertions(+), 4 deletions(-) diff --git a/hw/mem/memory-device.c b/hw/mem/memory-device.c index 1b14ba5661..ae38f48f16 100644 --- a/hw/mem/memory-device.c +++ b/hw/mem/memory-device.c @@ -85,13 +85,93 @@ unsigned int memory_devices_get_reserved_memslots(void) return get_reserved_memslots(current_machine); } +bool memory_devices_memslot_auto_decision_active(void) +{ + if (!current_machine->device_memory) { + return false; + } + + return current_machine->device_memory->memslot_auto_decision_active; +} + +static unsigned int memory_device_memslot_decision_limit(MachineState *ms, + MemoryRegion *mr) +{ + const unsigned int reserved = get_reserved_memslots(ms); + const uint64_t size = memory_region_size(mr); + unsigned int max = vhost_get_max_memslots(); + unsigned int free = vhost_get_free_memslots(); + uint64_t available_space; + unsigned int memslots; + + if (kvm_enabled()) { + max = MIN(max, kvm_get_max_memslots()); + free = MIN(free, kvm_get_free_memslots()); + } + + /* + * If we only have less overall memslots than what we consider reasonable, + * just keep it to a minimum. + */ + if (max < MEMORY_DEVICES_SAFE_MAX_MEMSLOTS) { + return 1; + } + + /* + * Consider our soft-limit across all memory devices. We don't really + * expect to exceed this limit in reasonable configurations. + */ + if (MEMORY_DEVICES_SOFT_MEMSLOT_LIMIT <= + ms->device_memory->required_memslots) { + return 1; + } + memslots = MEMORY_DEVICES_SOFT_MEMSLOT_LIMIT - + ms->device_memory->required_memslots; + + /* + * Consider the actually still free memslots. This is only relevant if + * other memslot consumers would consume *significantly* more memslots than + * what we prepared for (> 253). Unlikely, but let's just handle it + * cleanly. + */ + memslots = MIN(memslots, free - reserved); + if (memslots < 1 || unlikely(free < reserved)) { + return 1; + } + + /* We cannot have any other memory devices? So give all to this device. */ + if (size == ms->maxram_size - ms->ram_size) { + return memslots; + } + + /* + * Simple heuristic: equally distribute the memslots over the space + * still available for memory devices. + */ + available_space = ms->maxram_size - ms->ram_size - + ms->device_memory->used_region_size; + memslots = (double)memslots * size / available_space; + return memslots < 1 ? 1 : memslots; +} + static void memory_device_check_addable(MachineState *ms, MemoryDeviceState *md, MemoryRegion *mr, Error **errp) { + const MemoryDeviceClass *mdc = MEMORY_DEVICE_GET_CLASS(md); const uint64_t used_region_size = ms->device_memory->used_region_size; const uint64_t size = memory_region_size(mr); - const unsigned int required_memslots = memory_device_get_memslots(md); const unsigned int reserved_memslots = get_reserved_memslots(ms); + unsigned int required_memslots, memslot_limit; + + /* + * Instruct the device to decide how many memslots to use, if applicable, + * before we query the number of required memslots the first time. + */ + if (mdc->decide_memslots) { + memslot_limit = memory_device_memslot_decision_limit(ms, mr); + mdc->decide_memslots(md, memslot_limit); + } + required_memslots = memory_device_get_memslots(md); /* we will need memory slots for kvm and vhost */ if (kvm_enabled() && @@ -300,6 +380,7 @@ out: void memory_device_plug(MemoryDeviceState *md, MachineState *ms) { const MemoryDeviceClass *mdc = MEMORY_DEVICE_GET_CLASS(md); + const unsigned int memslots = memory_device_get_memslots(md); const uint64_t addr = mdc->get_addr(md); MemoryRegion *mr; @@ -311,7 +392,11 @@ void memory_device_plug(MemoryDeviceState *md, MachineState *ms) g_assert(ms->device_memory); ms->device_memory->used_region_size += memory_region_size(mr); - ms->device_memory->required_memslots += memory_device_get_memslots(md); + ms->device_memory->required_memslots += memslots; + if (mdc->decide_memslots && memslots > 1) { + ms->device_memory->memslot_auto_decision_active++; + } + memory_region_add_subregion(&ms->device_memory->mr, addr - ms->device_memory->base, mr); trace_memory_device_plug(DEVICE(md)->id ? DEVICE(md)->id : "", addr); @@ -320,6 +405,7 @@ void memory_device_plug(MemoryDeviceState *md, MachineState *ms) void memory_device_unplug(MemoryDeviceState *md, MachineState *ms) { const MemoryDeviceClass *mdc = MEMORY_DEVICE_GET_CLASS(md); + const unsigned int memslots = memory_device_get_memslots(md); MemoryRegion *mr; /* @@ -330,8 +416,12 @@ void memory_device_unplug(MemoryDeviceState *md, MachineState *ms) g_assert(ms->device_memory); memory_region_del_subregion(&ms->device_memory->mr, mr); + + if (mdc->decide_memslots && memslots > 1) { + ms->device_memory->memslot_auto_decision_active--; + } ms->device_memory->used_region_size -= memory_region_size(mr); - ms->device_memory->required_memslots -= memory_device_get_memslots(md); + ms->device_memory->required_memslots -= memslots; trace_memory_device_unplug(DEVICE(md)->id ? DEVICE(md)->id : "", mdc->get_addr(md)); } diff --git a/hw/virtio/vhost.c b/hw/virtio/vhost.c index 2bdb4fb231..a546a585da 100644 --- a/hw/virtio/vhost.c +++ b/hw/virtio/vhost.c @@ -1462,6 +1462,19 @@ int vhost_dev_init(struct vhost_dev *hdev, void *opaque, goto fail; } + limit = hdev->vhost_ops->vhost_backend_memslots_limit(hdev); + if (limit < MEMORY_DEVICES_SAFE_MAX_MEMSLOTS && + memory_devices_memslot_auto_decision_active()) { + error_setg(errp, "some memory device (like virtio-mem)" + " decided how many memory slots to use based on the overall" + " number of memory slots; this vhost backend would further" + " restricts the overall number of memory slots"); + error_append_hint(errp, "Try plugging this vhost backend before" + " plugging such memory devices.\n"); + r = -EINVAL; + goto fail; + } + for (i = 0; i < hdev->nvqs; ++i, ++n_initialized_vqs) { r = vhost_virtqueue_init(hdev, hdev->vqs + i, hdev->vq_index + i); if (r < 0) { @@ -1548,7 +1561,6 @@ int vhost_dev_init(struct vhost_dev *hdev, void *opaque, * but we'll need additional information about the reservations. */ reserved = memory_devices_get_reserved_memslots(); - limit = hdev->vhost_ops->vhost_backend_memslots_limit(hdev); if (used + reserved > limit) { error_setg(errp, "vhost backend memory slots limit (%d) is less" " than current number of used (%d) and reserved (%d)" diff --git a/include/hw/boards.h b/include/hw/boards.h index 01bddb258f..43a56dc51e 100644 --- a/include/hw/boards.h +++ b/include/hw/boards.h @@ -304,6 +304,9 @@ struct MachineClass { * @used_region_size: the part of @mr already used by memory devices * @required_memslots: the number of memslots required by memory devices * @used_memslots: the number of memslots currently used by memory devices + * @memslot_auto_decision_active: whether any plugged memory device + * automatically decided to use more than + * one memslot */ typedef struct DeviceMemoryState { hwaddr base; @@ -314,6 +317,7 @@ typedef struct DeviceMemoryState { uint64_t used_region_size; unsigned int required_memslots; unsigned int used_memslots; + unsigned int memslot_auto_decision_active; } DeviceMemoryState; /** diff --git a/include/hw/mem/memory-device.h b/include/hw/mem/memory-device.h index c7b624da6a..3354d6c166 100644 --- a/include/hw/mem/memory-device.h +++ b/include/hw/mem/memory-device.h @@ -14,6 +14,7 @@ #define MEMORY_DEVICE_H #include "hw/qdev-core.h" +#include "qemu/typedefs.h" #include "qapi/qapi-types-machine.h" #include "qom/object.h" @@ -99,6 +100,15 @@ struct MemoryDeviceClass { */ MemoryRegion *(*get_memory_region)(MemoryDeviceState *md, Error **errp); + /* + * Optional: Instruct the memory device to decide how many memory slots + * it requires, not exceeding the given limit. + * + * Called exactly once when pre-plugging the memory device, before + * querying the number of memslots using @get_memslots the first time. + */ + void (*decide_memslots)(MemoryDeviceState *md, unsigned int limit); + /* * Optional for memory devices that require only a single memslot, * required for all other memory devices: Return the number of memslots @@ -129,9 +139,31 @@ struct MemoryDeviceClass { MemoryDeviceInfo *info); }; +/* + * Traditionally, KVM/vhost in many setups supported 509 memslots, whereby + * 253 memslots were "reserved" for boot memory and other devices (such + * as PCI BARs, which can get mapped dynamically) and 256 memslots were + * dedicated for DIMMs. These magic numbers worked reliably in the past. + * + * Further, using many memslots can negatively affect performance, so setting + * the soft-limit of memslots used by memory devices to the traditional + * DIMM limit of 256 sounds reasonable. + * + * If we have less than 509 memslots, we will instruct memory devices that + * support automatically deciding how many memslots to use to only use a single + * one. + * + * Hotplugging vhost devices with at least 509 memslots is not expected to + * cause problems, not even when devices automatically decided how many memslots + * to use. + */ +#define MEMORY_DEVICES_SOFT_MEMSLOT_LIMIT 256 +#define MEMORY_DEVICES_SAFE_MAX_MEMSLOTS 509 + MemoryDeviceInfoList *qmp_memory_device_list(void); uint64_t get_plugged_memory_size(void); unsigned int memory_devices_get_reserved_memslots(void); +bool memory_devices_memslot_auto_decision_active(void); void memory_device_pre_plug(MemoryDeviceState *md, MachineState *ms, const uint64_t *legacy_align, Error **errp); void memory_device_plug(MemoryDeviceState *md, MachineState *ms); diff --git a/stubs/memory_device.c b/stubs/memory_device.c index 318a5d4187..15fd93ff67 100644 --- a/stubs/memory_device.c +++ b/stubs/memory_device.c @@ -15,3 +15,8 @@ unsigned int memory_devices_get_reserved_memslots(void) { return 0; } + +bool memory_devices_memslot_auto_decision_active(void) +{ + return false; +} From aa5317ef7cbf3a322b423a7b63625959b82b1a62 Mon Sep 17 00:00:00 2001 From: David Hildenbrand Date: Tue, 26 Sep 2023 20:57:33 +0200 Subject: [PATCH 0610/1077] memory: Clarify mapping requirements for RamDiscardManager We really only care about the RAM memory region not being mapped into an address space yet as long as we're still setting up the RamDiscardManager. Once mapped into an address space, memory notifiers would get notified about such a region and any attempts to modify the RamDiscardManager would be wrong. While "mapped into an address space" is easy to check for RAM regions that are mapped directly (following the ->container links), it's harder to check when such regions are mapped indirectly via aliases. For now, we can only detect that a region is mapped through an alias (->mapped_via_alias), but we don't have a handle on these aliases to follow all their ->container links to test if they are eventually mapped into an address space. So relax the assertion in memory_region_set_ram_discard_manager(), remove the check in memory_region_get_ram_discard_manager() and clarify the doc. Message-ID: <20230926185738.277351-14-david@redhat.com> Reviewed-by: Maciej S. Szmigiero Reviewed-by: Michael S. Tsirkin Signed-off-by: David Hildenbrand --- include/exec/memory.h | 5 +++-- system/memory.c | 4 ++-- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/include/exec/memory.h b/include/exec/memory.h index c99842d2fc..cf7c7dde91 100644 --- a/include/exec/memory.h +++ b/include/exec/memory.h @@ -599,8 +599,9 @@ typedef void (*ReplayRamDiscard)(MemoryRegionSection *section, void *opaque); * populated (consuming memory), to be used/accessed by the VM. * * A #RamDiscardManager can only be set for a RAM #MemoryRegion while the - * #MemoryRegion isn't mapped yet; it cannot change while the #MemoryRegion is - * mapped. + * #MemoryRegion isn't mapped into an address space yet (either directly + * or via an alias); it cannot change while the #MemoryRegion is + * mapped into an address space. * * The #RamDiscardManager is intended to be used by technologies that are * incompatible with discarding of RAM (e.g., VFIO, which may pin all diff --git a/system/memory.c b/system/memory.c index fa1c99f9ba..e11bce5991 100644 --- a/system/memory.c +++ b/system/memory.c @@ -2085,7 +2085,7 @@ int memory_region_iommu_num_indexes(IOMMUMemoryRegion *iommu_mr) RamDiscardManager *memory_region_get_ram_discard_manager(MemoryRegion *mr) { - if (!memory_region_is_mapped(mr) || !memory_region_is_ram(mr)) { + if (!memory_region_is_ram(mr)) { return NULL; } return mr->rdm; @@ -2094,7 +2094,7 @@ RamDiscardManager *memory_region_get_ram_discard_manager(MemoryRegion *mr) void memory_region_set_ram_discard_manager(MemoryRegion *mr, RamDiscardManager *rdm) { - g_assert(memory_region_is_ram(mr) && !memory_region_is_mapped(mr)); + g_assert(memory_region_is_ram(mr)); g_assert(!rdm || !mr->rdm); mr->rdm = rdm; } From a45171dba74a376354746e0c83dc15616b42614f Mon Sep 17 00:00:00 2001 From: David Hildenbrand Date: Tue, 26 Sep 2023 20:57:34 +0200 Subject: [PATCH 0611/1077] virtio-mem: Pass non-const VirtIOMEM via virtio_mem_range_cb Let's prepare for a user that has to modify the VirtIOMEM device state. Message-ID: <20230926185738.277351-15-david@redhat.com> Reviewed-by: Maciej S. Szmigiero Reviewed-by: Michael S. Tsirkin Signed-off-by: David Hildenbrand --- hw/virtio/virtio-mem.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/hw/virtio/virtio-mem.c b/hw/virtio/virtio-mem.c index da5b09cefc..0b0e6c5090 100644 --- a/hw/virtio/virtio-mem.c +++ b/hw/virtio/virtio-mem.c @@ -177,10 +177,10 @@ static bool virtio_mem_is_busy(void) return migration_in_incoming_postcopy() || !migration_is_idle(); } -typedef int (*virtio_mem_range_cb)(const VirtIOMEM *vmem, void *arg, +typedef int (*virtio_mem_range_cb)(VirtIOMEM *vmem, void *arg, uint64_t offset, uint64_t size); -static int virtio_mem_for_each_unplugged_range(const VirtIOMEM *vmem, void *arg, +static int virtio_mem_for_each_unplugged_range(VirtIOMEM *vmem, void *arg, virtio_mem_range_cb cb) { unsigned long first_zero_bit, last_zero_bit; @@ -204,7 +204,7 @@ static int virtio_mem_for_each_unplugged_range(const VirtIOMEM *vmem, void *arg, return ret; } -static int virtio_mem_for_each_plugged_range(const VirtIOMEM *vmem, void *arg, +static int virtio_mem_for_each_plugged_range(VirtIOMEM *vmem, void *arg, virtio_mem_range_cb cb) { unsigned long first_bit, last_bit; @@ -969,7 +969,7 @@ static void virtio_mem_device_unrealize(DeviceState *dev) ram_block_coordinated_discard_require(false); } -static int virtio_mem_discard_range_cb(const VirtIOMEM *vmem, void *arg, +static int virtio_mem_discard_range_cb(VirtIOMEM *vmem, void *arg, uint64_t offset, uint64_t size) { RAMBlock *rb = vmem->memdev->mr.ram_block; @@ -1021,7 +1021,7 @@ static int virtio_mem_post_load(void *opaque, int version_id) return virtio_mem_restore_unplugged(vmem); } -static int virtio_mem_prealloc_range_cb(const VirtIOMEM *vmem, void *arg, +static int virtio_mem_prealloc_range_cb(VirtIOMEM *vmem, void *arg, uint64_t offset, uint64_t size) { void *area = memory_region_get_ram_ptr(&vmem->memdev->mr) + offset; From 884a0c20e624275e2dc946c4b8abba9ccbaf4167 Mon Sep 17 00:00:00 2001 From: David Hildenbrand Date: Tue, 26 Sep 2023 20:57:35 +0200 Subject: [PATCH 0612/1077] virtio-mem: Update state to match bitmap as soon as it's been migrated It's cleaner and future-proof to just have other state that depends on the bitmap state to be updated as soon as possible when restoring the bitmap. So factor out informing RamDiscardListener into a functon and call it in case of early migration right after we restored the bitmap. Message-ID: <20230926185738.277351-16-david@redhat.com> Reviewed-by: Maciej S. Szmigiero Reviewed-by: Michael S. Tsirkin Signed-off-by: David Hildenbrand --- hw/virtio/virtio-mem.c | 26 +++++++++++++++++++++----- 1 file changed, 21 insertions(+), 5 deletions(-) diff --git a/hw/virtio/virtio-mem.c b/hw/virtio/virtio-mem.c index 0b0e6c5090..0cf47df9cf 100644 --- a/hw/virtio/virtio-mem.c +++ b/hw/virtio/virtio-mem.c @@ -984,9 +984,8 @@ static int virtio_mem_restore_unplugged(VirtIOMEM *vmem) virtio_mem_discard_range_cb); } -static int virtio_mem_post_load(void *opaque, int version_id) +static int virtio_mem_post_load_bitmap(VirtIOMEM *vmem) { - VirtIOMEM *vmem = VIRTIO_MEM(opaque); RamDiscardListener *rdl; int ret; @@ -1001,6 +1000,20 @@ static int virtio_mem_post_load(void *opaque, int version_id) return ret; } } + return 0; +} + +static int virtio_mem_post_load(void *opaque, int version_id) +{ + VirtIOMEM *vmem = VIRTIO_MEM(opaque); + int ret; + + if (!vmem->early_migration) { + ret = virtio_mem_post_load_bitmap(vmem); + if (ret) { + return ret; + } + } /* * If shared RAM is migrated using the file content and not using QEMU, @@ -1043,7 +1056,7 @@ static int virtio_mem_post_load_early(void *opaque, int version_id) int ret; if (!vmem->prealloc) { - return 0; + goto post_load_bitmap; } /* @@ -1051,7 +1064,7 @@ static int virtio_mem_post_load_early(void *opaque, int version_id) * don't mess with preallocation and postcopy. */ if (migrate_ram_is_ignored(rb)) { - return 0; + goto post_load_bitmap; } /* @@ -1084,7 +1097,10 @@ static int virtio_mem_post_load_early(void *opaque, int version_id) return -EBUSY; } } - return 0; + +post_load_bitmap: + /* Finally, update any other state to be consistent with the new bitmap. */ + return virtio_mem_post_load_bitmap(vmem); } typedef struct VirtIOMEMMigSanityChecks { From 177f9b1ee4643626faa0caac20f06d77ae443fe8 Mon Sep 17 00:00:00 2001 From: David Hildenbrand Date: Tue, 26 Sep 2023 20:57:36 +0200 Subject: [PATCH 0613/1077] virtio-mem: Expose device memory dynamically via multiple memslots if enabled Having large virtio-mem devices that only expose little memory to a VM is currently a problem: we map the whole sparse memory region into the guest using a single memslot, resulting in one gigantic memslot in KVM. KVM allocates metadata for the whole memslot, which can result in quite some memory waste. Assuming we have a 1 TiB virtio-mem device and only expose little (e.g., 1 GiB) memory, we would create a single 1 TiB memslot and KVM has to allocate metadata for that 1 TiB memslot: on x86, this implies allocating a significant amount of memory for metadata: (1) RMAP: 8 bytes per 4 KiB, 8 bytes per 2 MiB, 8 bytes per 1 GiB -> For 1 TiB: 2147483648 + 4194304 + 8192 = ~ 2 GiB (0.2 %) With the TDP MMU (cat /sys/module/kvm/parameters/tdp_mmu) this gets allocated lazily when required for nested VMs (2) gfn_track: 2 bytes per 4 KiB -> For 1 TiB: 536870912 = ~512 MiB (0.05 %) (3) lpage_info: 4 bytes per 2 MiB, 4 bytes per 1 GiB -> For 1 TiB: 2097152 + 4096 = ~2 MiB (0.0002 %) (4) 2x dirty bitmaps for tracking: 2x 1 bit per 4 KiB page -> For 1 TiB: 536870912 = 64 MiB (0.006 %) So we primarily care about (1) and (2). The bad thing is, that the memory consumption *doubles* once SMM is enabled, because we create the memslot once for !SMM and once for SMM. Having a 1 TiB memslot without the TDP MMU consumes around: * With SMM: 5 GiB * Without SMM: 2.5 GiB Having a 1 TiB memslot with the TDP MMU consumes around: * With SMM: 1 GiB * Without SMM: 512 MiB ... and that's really something we want to optimize, to be able to just start a VM with small boot memory (e.g., 4 GiB) and a virtio-mem device that can grow very large (e.g., 1 TiB). Consequently, using multiple memslots and only mapping the memslots we really need can significantly reduce memory waste and speed up memslot-related operations. Let's expose the sparse RAM memory region using multiple memslots, mapping only the memslots we currently need into our device memory region container. The feature can be enabled using "dynamic-memslots=on" and requires "unplugged-inaccessible=on", which is nowadays the default. Once enabled, we'll auto-detect the number of memslots to use based on the memslot limit provided by the core. We'll use at most 1 memslot per gigabyte. Note that our global limit of memslots accross all memory devices is currently set to 256: even with multiple large virtio-mem devices, we'd still have a sane limit on the number of memslots used. The default is to not dynamically map memslot for now ("dynamic-memslots=off"). The optimization must be enabled manually, because some vhost setups (e.g., hotplug of vhost-user devices) might be problematic until we support more memslots especially in vhost-user backends. Note that "dynamic-memslots=on" is just a hint that multiple memslots *may* be used for internal optimizations, not that multiple memslots *must* be used. The actual number of memslots that are used is an internal detail: for example, once memslot metadata is no longer an issue, we could simply stop optimizing for that. Migration source and destination can differ on the setting of "dynamic-memslots". Message-ID: <20230926185738.277351-17-david@redhat.com> Reviewed-by: Maciej S. Szmigiero Reviewed-by: Michael S. Tsirkin Signed-off-by: David Hildenbrand --- hw/virtio/virtio-mem-pci.c | 21 +++ hw/virtio/virtio-mem.c | 288 +++++++++++++++++++++++++++++++++ include/hw/virtio/virtio-mem.h | 32 +++- 3 files changed, 340 insertions(+), 1 deletion(-) diff --git a/hw/virtio/virtio-mem-pci.c b/hw/virtio/virtio-mem-pci.c index c4597e029e..1b4e9a3284 100644 --- a/hw/virtio/virtio-mem-pci.c +++ b/hw/virtio/virtio-mem-pci.c @@ -48,6 +48,25 @@ static MemoryRegion *virtio_mem_pci_get_memory_region(MemoryDeviceState *md, return vmc->get_memory_region(vmem, errp); } +static void virtio_mem_pci_decide_memslots(MemoryDeviceState *md, + unsigned int limit) +{ + VirtIOMEMPCI *pci_mem = VIRTIO_MEM_PCI(md); + VirtIOMEM *vmem = VIRTIO_MEM(&pci_mem->vdev); + VirtIOMEMClass *vmc = VIRTIO_MEM_GET_CLASS(vmem); + + vmc->decide_memslots(vmem, limit); +} + +static unsigned int virtio_mem_pci_get_memslots(MemoryDeviceState *md) +{ + VirtIOMEMPCI *pci_mem = VIRTIO_MEM_PCI(md); + VirtIOMEM *vmem = VIRTIO_MEM(&pci_mem->vdev); + VirtIOMEMClass *vmc = VIRTIO_MEM_GET_CLASS(vmem); + + return vmc->get_memslots(vmem); +} + static uint64_t virtio_mem_pci_get_plugged_size(const MemoryDeviceState *md, Error **errp) { @@ -150,6 +169,8 @@ static void virtio_mem_pci_class_init(ObjectClass *klass, void *data) mdc->set_addr = virtio_mem_pci_set_addr; mdc->get_plugged_size = virtio_mem_pci_get_plugged_size; mdc->get_memory_region = virtio_mem_pci_get_memory_region; + mdc->decide_memslots = virtio_mem_pci_decide_memslots; + mdc->get_memslots = virtio_mem_pci_get_memslots; mdc->fill_device_info = virtio_mem_pci_fill_device_info; mdc->get_min_alignment = virtio_mem_pci_get_min_alignment; diff --git a/hw/virtio/virtio-mem.c b/hw/virtio/virtio-mem.c index 0cf47df9cf..e1e4250e69 100644 --- a/hw/virtio/virtio-mem.c +++ b/hw/virtio/virtio-mem.c @@ -66,6 +66,13 @@ static uint32_t virtio_mem_default_thp_size(void) return default_thp_size; } +/* + * The minimum memslot size depends on this setting ("sane default"), the + * device block size, and the memory backend page size. The last (or single) + * memslot might be smaller than this constant. + */ +#define VIRTIO_MEM_MIN_MEMSLOT_SIZE (1 * GiB) + /* * We want to have a reasonable default block size such that * 1. We avoid splitting THPs when unplugging memory, which degrades @@ -483,6 +490,96 @@ static bool virtio_mem_valid_range(const VirtIOMEM *vmem, uint64_t gpa, return true; } +static void virtio_mem_activate_memslot(VirtIOMEM *vmem, unsigned int idx) +{ + const uint64_t memslot_offset = idx * vmem->memslot_size; + + assert(vmem->memslots); + + /* + * Instead of enabling/disabling memslots, we add/remove them. This should + * make address space updates faster, because we don't have to loop over + * many disabled subregions. + */ + if (memory_region_is_mapped(&vmem->memslots[idx])) { + return; + } + memory_region_add_subregion(vmem->mr, memslot_offset, &vmem->memslots[idx]); +} + +static void virtio_mem_deactivate_memslot(VirtIOMEM *vmem, unsigned int idx) +{ + assert(vmem->memslots); + + if (!memory_region_is_mapped(&vmem->memslots[idx])) { + return; + } + memory_region_del_subregion(vmem->mr, &vmem->memslots[idx]); +} + +static void virtio_mem_activate_memslots_to_plug(VirtIOMEM *vmem, + uint64_t offset, uint64_t size) +{ + const unsigned int start_idx = offset / vmem->memslot_size; + const unsigned int end_idx = (offset + size + vmem->memslot_size - 1) / + vmem->memslot_size; + unsigned int idx; + + if (!vmem->dynamic_memslots) { + return; + } + + /* Activate all involved memslots in a single transaction. */ + memory_region_transaction_begin(); + for (idx = start_idx; idx < end_idx; idx++) { + virtio_mem_activate_memslot(vmem, idx); + } + memory_region_transaction_commit(); +} + +static void virtio_mem_deactivate_unplugged_memslots(VirtIOMEM *vmem, + uint64_t offset, + uint64_t size) +{ + const uint64_t region_size = memory_region_size(&vmem->memdev->mr); + const unsigned int start_idx = offset / vmem->memslot_size; + const unsigned int end_idx = (offset + size + vmem->memslot_size - 1) / + vmem->memslot_size; + unsigned int idx; + + if (!vmem->dynamic_memslots) { + return; + } + + /* Deactivate all memslots with unplugged blocks in a single transaction. */ + memory_region_transaction_begin(); + for (idx = start_idx; idx < end_idx; idx++) { + const uint64_t memslot_offset = idx * vmem->memslot_size; + uint64_t memslot_size = vmem->memslot_size; + + /* The size of the last memslot might be smaller. */ + if (idx == vmem->nb_memslots - 1) { + memslot_size = region_size - memslot_offset; + } + + /* + * Partially covered memslots might still have some blocks plugged and + * have to remain active if that's the case. + */ + if (offset > memslot_offset || + offset + size < memslot_offset + memslot_size) { + const uint64_t gpa = vmem->addr + memslot_offset; + + if (!virtio_mem_is_range_unplugged(vmem, gpa, memslot_size)) { + continue; + } + } + + virtio_mem_deactivate_memslot(vmem, idx); + } + memory_region_transaction_commit(); +} + static int virtio_mem_set_block_state(VirtIOMEM *vmem, uint64_t start_gpa, uint64_t size, bool plug) { @@ -500,6 +597,8 @@ static int virtio_mem_set_block_state(VirtIOMEM *vmem, uint64_t start_gpa, } virtio_mem_notify_unplug(vmem, offset, size); virtio_mem_set_range_unplugged(vmem, start_gpa, size); + /* Deactivate completely unplugged memslots after updating the state. */ + virtio_mem_deactivate_unplugged_memslots(vmem, offset, size); return 0; } @@ -527,7 +626,20 @@ static int virtio_mem_set_block_state(VirtIOMEM *vmem, uint64_t start_gpa, } if (!ret) { + /* + * Activate before notifying and rollback in case of any errors. + * + * When activating a yet inactive memslot, memory notifiers will get + * notified about the added memory region and can register with the + * RamDiscardManager; this will traverse all plugged blocks and skip the + * blocks we are plugging here. The following notification will inform + * registered listeners about the blocks we're plugging. + */ + virtio_mem_activate_memslots_to_plug(vmem, offset, size); ret = virtio_mem_notify_plug(vmem, offset, size); + if (ret) { + virtio_mem_deactivate_unplugged_memslots(vmem, offset, size); + } } if (ret) { /* Could be preallocation or a notifier populated memory. */ @@ -620,6 +732,7 @@ static void virtio_mem_resize_usable_region(VirtIOMEM *vmem, static int virtio_mem_unplug_all(VirtIOMEM *vmem) { + const uint64_t region_size = memory_region_size(&vmem->memdev->mr); RAMBlock *rb = vmem->memdev->mr.ram_block; if (vmem->size) { @@ -634,6 +747,9 @@ static int virtio_mem_unplug_all(VirtIOMEM *vmem) bitmap_clear(vmem->bitmap, 0, vmem->bitmap_size); vmem->size = 0; notifier_list_notify(&vmem->size_change_notifiers, &vmem->size); + + /* Deactivate all memslots after updating the state. */ + virtio_mem_deactivate_unplugged_memslots(vmem, 0, region_size); } trace_virtio_mem_unplugged_all(); @@ -790,6 +906,43 @@ static void virtio_mem_system_reset(void *opaque) virtio_mem_unplug_all(vmem); } +static void virtio_mem_prepare_mr(VirtIOMEM *vmem) +{ + const uint64_t region_size = memory_region_size(&vmem->memdev->mr); + + assert(!vmem->mr && vmem->dynamic_memslots); + vmem->mr = g_new0(MemoryRegion, 1); + memory_region_init(vmem->mr, OBJECT(vmem), "virtio-mem", + region_size); + vmem->mr->align = memory_region_get_alignment(&vmem->memdev->mr); +} + +static void virtio_mem_prepare_memslots(VirtIOMEM *vmem) +{ + const uint64_t region_size = memory_region_size(&vmem->memdev->mr); + unsigned int idx; + + g_assert(!vmem->memslots && vmem->nb_memslots && vmem->dynamic_memslots); + vmem->memslots = g_new0(MemoryRegion, vmem->nb_memslots); + + /* Initialize our memslots, but don't map them yet. */ + for (idx = 0; idx < vmem->nb_memslots; idx++) { + const uint64_t memslot_offset = idx * vmem->memslot_size; + uint64_t memslot_size = vmem->memslot_size; + char name[20]; + + /* The size of the last memslot might be smaller. */ + if (idx == vmem->nb_memslots - 1) { + memslot_size = region_size - memslot_offset; + } + + snprintf(name, sizeof(name), "memslot-%u", idx); + memory_region_init_alias(&vmem->memslots[idx], OBJECT(vmem), name, + &vmem->memdev->mr, memslot_offset, + memslot_size); + } +} + static void virtio_mem_device_realize(DeviceState *dev, Error **errp) { MachineState *ms = MACHINE(qdev_get_machine()); @@ -861,6 +1014,14 @@ static void virtio_mem_device_realize(DeviceState *dev, Error **errp) vmem->unplugged_inaccessible = ON_OFF_AUTO_ON; #endif /* VIRTIO_MEM_HAS_LEGACY_GUESTS */ + if (vmem->dynamic_memslots && + vmem->unplugged_inaccessible != ON_OFF_AUTO_ON) { + error_setg(errp, "'%s' property set to 'on' requires '%s' to be 'on'", + VIRTIO_MEM_DYNAMIC_MEMSLOTS_PROP, + VIRTIO_MEM_UNPLUGGED_INACCESSIBLE_PROP); + return; + } + /* * If the block size wasn't configured by the user, use a sane default. This * allows using hugetlbfs backends of any page size without manual @@ -930,6 +1091,25 @@ static void virtio_mem_device_realize(DeviceState *dev, Error **errp) virtio_init(vdev, VIRTIO_ID_MEM, sizeof(struct virtio_mem_config)); vmem->vq = virtio_add_queue(vdev, 128, virtio_mem_handle_request); + /* + * With "dynamic-memslots=off" (old behavior) we always map the whole + * RAM memory region directly. + */ + if (vmem->dynamic_memslots) { + if (!vmem->mr) { + virtio_mem_prepare_mr(vmem); + } + if (vmem->nb_memslots <= 1) { + vmem->nb_memslots = 1; + vmem->memslot_size = memory_region_size(&vmem->memdev->mr); + } + if (!vmem->memslots) { + virtio_mem_prepare_memslots(vmem); + } + } else { + assert(!vmem->mr && !vmem->nb_memslots && !vmem->memslots); + } + host_memory_backend_set_mapped(vmem->memdev, true); vmstate_register_ram(&vmem->memdev->mr, DEVICE(vmem)); if (vmem->early_migration) { @@ -984,11 +1164,31 @@ static int virtio_mem_restore_unplugged(VirtIOMEM *vmem) virtio_mem_discard_range_cb); } +static int virtio_mem_activate_memslot_range_cb(VirtIOMEM *vmem, void *arg, + uint64_t offset, uint64_t size) +{ + virtio_mem_activate_memslots_to_plug(vmem, offset, size); + return 0; +} + static int virtio_mem_post_load_bitmap(VirtIOMEM *vmem) { RamDiscardListener *rdl; int ret; + /* + * We restored the bitmap and updated the requested size; activate all + * memslots (so listeners register) before notifying about plugged blocks. + */ + if (vmem->dynamic_memslots) { + /* + * We don't expect any active memslots at this point to deactivate: no + * memory was plugged on the migration destination. + */ + virtio_mem_for_each_plugged_range(vmem, NULL, + virtio_mem_activate_memslot_range_cb); + } + /* * We started out with all memory discarded and our memory region is mapped * into an address space. Replay, now that we updated the bitmap. @@ -1251,11 +1451,79 @@ static MemoryRegion *virtio_mem_get_memory_region(VirtIOMEM *vmem, Error **errp) if (!vmem->memdev) { error_setg(errp, "'%s' property must be set", VIRTIO_MEM_MEMDEV_PROP); return NULL; + } else if (vmem->dynamic_memslots) { + if (!vmem->mr) { + virtio_mem_prepare_mr(vmem); + } + return vmem->mr; } return &vmem->memdev->mr; } +static void virtio_mem_decide_memslots(VirtIOMEM *vmem, unsigned int limit) +{ + uint64_t region_size, memslot_size, min_memslot_size; + unsigned int memslots; + RAMBlock *rb; + + if (!vmem->dynamic_memslots) { + return; + } + + /* We're called exactly once, before realizing the device. */ + assert(!vmem->nb_memslots); + + /* If realizing the device will fail, just assume a single memslot. */ + if (limit <= 1 || !vmem->memdev || !vmem->memdev->mr.ram_block) { + vmem->nb_memslots = 1; + return; + } + + rb = vmem->memdev->mr.ram_block; + region_size = memory_region_size(&vmem->memdev->mr); + + /* + * Determine the default block size now, to determine the minimum memslot + * size. We want the minimum slot size to be at least the device block size. + */ + if (!vmem->block_size) { + vmem->block_size = virtio_mem_default_block_size(rb); + } + /* If realizing the device will fail, just assume a single memslot. */ + if (vmem->block_size < qemu_ram_pagesize(rb) || + !QEMU_IS_ALIGNED(region_size, vmem->block_size)) { + vmem->nb_memslots = 1; + return; + } + + /* + * All memslots except the last one have a reasonable minimum size, and + * and all memslot sizes are aligned to the device block size. + */ + memslot_size = QEMU_ALIGN_UP(region_size / limit, vmem->block_size); + min_memslot_size = MAX(vmem->block_size, VIRTIO_MEM_MIN_MEMSLOT_SIZE); + memslot_size = MAX(memslot_size, min_memslot_size); + + memslots = QEMU_ALIGN_UP(region_size, memslot_size) / memslot_size; + if (memslots != 1) { + vmem->memslot_size = memslot_size; + } + vmem->nb_memslots = memslots; +} + +static unsigned int virtio_mem_get_memslots(VirtIOMEM *vmem) +{ + if (!vmem->dynamic_memslots) { + /* Exactly one static RAM memory region. */ + return 1; + } + + /* We're called after instructed to make a decision. */ + g_assert(vmem->nb_memslots); + return vmem->nb_memslots; +} + static void virtio_mem_add_size_change_notifier(VirtIOMEM *vmem, Notifier *notifier) { @@ -1393,6 +1661,21 @@ static void virtio_mem_instance_init(Object *obj) NULL, NULL); } +static void virtio_mem_instance_finalize(Object *obj) +{ + VirtIOMEM *vmem = VIRTIO_MEM(obj); + + /* + * Note: the core already dropped the references on all memory regions + * (it's passed as the owner to memory_region_init_*()) and finalized + * these objects. We can simply free the memory. + */ + g_free(vmem->memslots); + vmem->memslots = NULL; + g_free(vmem->mr); + vmem->mr = NULL; +} + static Property virtio_mem_properties[] = { DEFINE_PROP_UINT64(VIRTIO_MEM_ADDR_PROP, VirtIOMEM, addr, 0), DEFINE_PROP_UINT32(VIRTIO_MEM_NODE_PROP, VirtIOMEM, node, 0), @@ -1405,6 +1688,8 @@ static Property virtio_mem_properties[] = { #endif DEFINE_PROP_BOOL(VIRTIO_MEM_EARLY_MIGRATION_PROP, VirtIOMEM, early_migration, true), + DEFINE_PROP_BOOL(VIRTIO_MEM_DYNAMIC_MEMSLOTS_PROP, VirtIOMEM, + dynamic_memslots, false), DEFINE_PROP_END_OF_LIST(), }; @@ -1572,6 +1857,8 @@ static void virtio_mem_class_init(ObjectClass *klass, void *data) vmc->fill_device_info = virtio_mem_fill_device_info; vmc->get_memory_region = virtio_mem_get_memory_region; + vmc->decide_memslots = virtio_mem_decide_memslots; + vmc->get_memslots = virtio_mem_get_memslots; vmc->add_size_change_notifier = virtio_mem_add_size_change_notifier; vmc->remove_size_change_notifier = virtio_mem_remove_size_change_notifier; vmc->unplug_request_check = virtio_mem_unplug_request_check; @@ -1589,6 +1876,7 @@ static const TypeInfo virtio_mem_info = { .parent = TYPE_VIRTIO_DEVICE, .instance_size = sizeof(VirtIOMEM), .instance_init = virtio_mem_instance_init, + .instance_finalize = virtio_mem_instance_finalize, .class_init = virtio_mem_class_init, .class_size = sizeof(VirtIOMEMClass), .interfaces = (InterfaceInfo[]) { diff --git a/include/hw/virtio/virtio-mem.h b/include/hw/virtio/virtio-mem.h index ab0fe2b4f2..5f5b02b8f9 100644 --- a/include/hw/virtio/virtio-mem.h +++ b/include/hw/virtio/virtio-mem.h @@ -33,6 +33,7 @@ OBJECT_DECLARE_TYPE(VirtIOMEM, VirtIOMEMClass, #define VIRTIO_MEM_UNPLUGGED_INACCESSIBLE_PROP "unplugged-inaccessible" #define VIRTIO_MEM_EARLY_MIGRATION_PROP "x-early-migration" #define VIRTIO_MEM_PREALLOC_PROP "prealloc" +#define VIRTIO_MEM_DYNAMIC_MEMSLOTS_PROP "dynamic-memslots" struct VirtIOMEM { VirtIODevice parent_obj; @@ -44,7 +45,28 @@ struct VirtIOMEM { int32_t bitmap_size; unsigned long *bitmap; - /* assigned memory backend and memory region */ + /* + * With "dynamic-memslots=on": Device memory region in which we dynamically + * map the memslots. + */ + MemoryRegion *mr; + + /* + * With "dynamic-memslots=on": The individual memslots (aliases into the + * memory backend). + */ + MemoryRegion *memslots; + + /* With "dynamic-memslots=on": The total number of memslots. */ + uint16_t nb_memslots; + + /* + * With "dynamic-memslots=on": Size of one memslot (the size of the + * last one can differ). + */ + uint64_t memslot_size; + + /* Assigned memory backend with the RAM memory region. */ HostMemoryBackend *memdev; /* NUMA node */ @@ -82,6 +104,12 @@ struct VirtIOMEM { */ bool early_migration; + /* + * Whether we dynamically map (multiple, if possible) memslots instead of + * statically mapping the whole RAM memory region. + */ + bool dynamic_memslots; + /* notifiers to notify when "size" changes */ NotifierList size_change_notifiers; @@ -96,6 +124,8 @@ struct VirtIOMEMClass { /* public */ void (*fill_device_info)(const VirtIOMEM *vmen, VirtioMEMDeviceInfo *vi); MemoryRegion *(*get_memory_region)(VirtIOMEM *vmem, Error **errp); + void (*decide_memslots)(VirtIOMEM *vmem, unsigned int limit); + unsigned int (*get_memslots)(VirtIOMEM *vmem); void (*add_size_change_notifier)(VirtIOMEM *vmem, Notifier *notifier); void (*remove_size_change_notifier)(VirtIOMEM *vmem, Notifier *notifier); void (*unplug_request_check)(VirtIOMEM *vmem, Error **errp); From 533f5d667909177f2890fca0bd64ad67297d7ba6 Mon Sep 17 00:00:00 2001 From: David Hildenbrand Date: Tue, 26 Sep 2023 20:57:37 +0200 Subject: [PATCH 0614/1077] memory,vhost: Allow for marking memory device memory regions unmergeable MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Let's allow for marking memory regions unmergeable, to teach flatview code and vhost to not merge adjacent aliases to the same memory region into a larger memory section; instead, we want separate aliases to stay separate such that we can atomically map/unmap aliases without affecting other aliases. This is desired for virtio-mem mapping device memory located on a RAM memory region via multiple aliases into a memory region container, resulting in separate memslots that can get (un)mapped atomically. As an example with virtio-mem, the layout would look something like this: [...] 0000000240000000-00000020bfffffff (prio 0, i/o): device-memory 0000000240000000-000000043fffffff (prio 0, i/o): virtio-mem 0000000240000000-000000027fffffff (prio 0, ram): alias memslot-0 @mem2 0000000000000000-000000003fffffff 0000000280000000-00000002bfffffff (prio 0, ram): alias memslot-1 @mem2 0000000040000000-000000007fffffff 00000002c0000000-00000002ffffffff (prio 0, ram): alias memslot-2 @mem2 0000000080000000-00000000bfffffff [...] Without unmergable memory regions, all three memslots would get merged into a single memory section. For example, when mapping another alias (e.g., virtio-mem-memslot-3) or when unmapping any of the mapped aliases, memory listeners will first get notified about the removal of the big memory section to then get notified about re-adding of the new (differently merged) memory section(s). In an ideal world, memory listeners would be able to deal with that atomically, like KVM nowadays does. However, (a) supporting this for other memory listeners (vhost-user, vfio) is fairly hard: temporary removal can result in all kinds of issues on concurrent access to guest memory; and (b) this handling is undesired, because temporarily removing+readding can consume quite some time on bigger memslots and is not efficient (e.g., vfio unpinning and repinning pages ...). Let's allow for marking a memory region unmergeable, such that we can atomically (un)map aliases to the same memory region, similar to (un)mapping individual DIMMs. Similarly, teach vhost code to not redo what flatview core stopped doing: don't merge such sections. Merging in vhost code is really only relevant for handling random holes in boot memory where; without this merging, the vhost-user backend wouldn't be able to mmap() some boot memory backed on hugetlb. We'll use this for virtio-mem next. Message-ID: <20230926185738.277351-18-david@redhat.com> Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Michael S. Tsirkin Signed-off-by: David Hildenbrand --- hw/virtio/vhost.c | 4 ++-- include/exec/memory.h | 22 ++++++++++++++++++++++ system/memory.c | 31 +++++++++++++++++++++++++------ 3 files changed, 49 insertions(+), 8 deletions(-) diff --git a/hw/virtio/vhost.c b/hw/virtio/vhost.c index a546a585da..9f37206ba0 100644 --- a/hw/virtio/vhost.c +++ b/hw/virtio/vhost.c @@ -707,7 +707,7 @@ static void vhost_region_add_section(struct vhost_dev *dev, mrs_size, mrs_host); } - if (dev->n_tmp_sections) { + if (dev->n_tmp_sections && !section->unmergeable) { /* Since we already have at least one section, lets see if * this extends it; since we're scanning in order, we only * have to look at the last one, and the FlatView that calls @@ -740,7 +740,7 @@ static void vhost_region_add_section(struct vhost_dev *dev, size_t offset = mrs_gpa - prev_gpa_start; if (prev_host_start + offset == mrs_host && - section->mr == prev_sec->mr) { + section->mr == prev_sec->mr && !prev_sec->unmergeable) { uint64_t max_end = MAX(prev_host_end, mrs_host + mrs_size); need_add = false; prev_sec->offset_within_address_space = diff --git a/include/exec/memory.h b/include/exec/memory.h index cf7c7dde91..653a32ea10 100644 --- a/include/exec/memory.h +++ b/include/exec/memory.h @@ -95,6 +95,7 @@ struct ReservedRegion { * relative to the region's address space * @readonly: writes to this section are ignored * @nonvolatile: this section is non-volatile + * @unmergeable: this section should not get merged with adjacent sections */ struct MemoryRegionSection { Int128 size; @@ -104,6 +105,7 @@ struct MemoryRegionSection { hwaddr offset_within_address_space; bool readonly; bool nonvolatile; + bool unmergeable; }; typedef struct IOMMUTLBEntry IOMMUTLBEntry; @@ -773,6 +775,7 @@ struct MemoryRegion { bool nonvolatile; bool rom_device; bool flush_coalesced_mmio; + bool unmergeable; uint8_t dirty_log_mask; bool is_iommu; RAMBlock *ram_block; @@ -2351,6 +2354,25 @@ void memory_region_set_size(MemoryRegion *mr, uint64_t size); void memory_region_set_alias_offset(MemoryRegion *mr, hwaddr offset); +/* + * memory_region_set_unmergeable: Set a memory region unmergeable + * + * Mark a memory region unmergeable, resulting in the memory region (or + * everything contained in a memory region container) not getting merged when + * simplifying the address space and notifying memory listeners. Consequently, + * memory listeners will never get notified about ranges that are larger than + * the original memory regions. + * + * This is primarily useful when multiple aliases to a RAM memory region are + * mapped into a memory region container, and updates (e.g., enable/disable or + * map/unmap) of individual memory region aliases are not supposed to affect + * other memory regions in the same container. + * + * @mr: the #MemoryRegion to be updated + * @unmergeable: whether to mark the #MemoryRegion unmergeable + */ +void memory_region_set_unmergeable(MemoryRegion *mr, bool unmergeable); + /** * memory_region_present: checks if an address relative to a @container * translates into #MemoryRegion within @container diff --git a/system/memory.c b/system/memory.c index e11bce5991..a800fbc9e5 100644 --- a/system/memory.c +++ b/system/memory.c @@ -224,6 +224,7 @@ struct FlatRange { bool romd_mode; bool readonly; bool nonvolatile; + bool unmergeable; }; #define FOR_EACH_FLAT_RANGE(var, view) \ @@ -240,6 +241,7 @@ section_from_flat_range(FlatRange *fr, FlatView *fv) .offset_within_address_space = int128_get64(fr->addr.start), .readonly = fr->readonly, .nonvolatile = fr->nonvolatile, + .unmergeable = fr->unmergeable, }; } @@ -250,7 +252,8 @@ static bool flatrange_equal(FlatRange *a, FlatRange *b) && a->offset_in_region == b->offset_in_region && a->romd_mode == b->romd_mode && a->readonly == b->readonly - && a->nonvolatile == b->nonvolatile; + && a->nonvolatile == b->nonvolatile + && a->unmergeable == b->unmergeable; } static FlatView *flatview_new(MemoryRegion *mr_root) @@ -323,7 +326,8 @@ static bool can_merge(FlatRange *r1, FlatRange *r2) && r1->dirty_log_mask == r2->dirty_log_mask && r1->romd_mode == r2->romd_mode && r1->readonly == r2->readonly - && r1->nonvolatile == r2->nonvolatile; + && r1->nonvolatile == r2->nonvolatile + && !r1->unmergeable && !r2->unmergeable; } /* Attempt to simplify a view by merging adjacent ranges */ @@ -599,7 +603,8 @@ static void render_memory_region(FlatView *view, Int128 base, AddrRange clip, bool readonly, - bool nonvolatile) + bool nonvolatile, + bool unmergeable) { MemoryRegion *subregion; unsigned i; @@ -616,6 +621,7 @@ static void render_memory_region(FlatView *view, int128_addto(&base, int128_make64(mr->addr)); readonly |= mr->readonly; nonvolatile |= mr->nonvolatile; + unmergeable |= mr->unmergeable; tmp = addrrange_make(base, mr->size); @@ -629,14 +635,14 @@ static void render_memory_region(FlatView *view, int128_subfrom(&base, int128_make64(mr->alias->addr)); int128_subfrom(&base, int128_make64(mr->alias_offset)); render_memory_region(view, mr->alias, base, clip, - readonly, nonvolatile); + readonly, nonvolatile, unmergeable); return; } /* Render subregions in priority order. */ QTAILQ_FOREACH(subregion, &mr->subregions, subregions_link) { render_memory_region(view, subregion, base, clip, - readonly, nonvolatile); + readonly, nonvolatile, unmergeable); } if (!mr->terminates) { @@ -652,6 +658,7 @@ static void render_memory_region(FlatView *view, fr.romd_mode = mr->romd_mode; fr.readonly = readonly; fr.nonvolatile = nonvolatile; + fr.unmergeable = unmergeable; /* Render the region itself into any gaps left by the current view. */ for (i = 0; i < view->nr && int128_nz(remain); ++i) { @@ -753,7 +760,7 @@ static FlatView *generate_memory_topology(MemoryRegion *mr) if (mr) { render_memory_region(view, mr, int128_zero(), addrrange_make(int128_zero(), int128_2_64()), - false, false); + false, false, false); } flatview_simplify(view); @@ -2755,6 +2762,18 @@ void memory_region_set_alias_offset(MemoryRegion *mr, hwaddr offset) memory_region_transaction_commit(); } +void memory_region_set_unmergeable(MemoryRegion *mr, bool unmergeable) +{ + if (unmergeable == mr->unmergeable) { + return; + } + + memory_region_transaction_begin(); + mr->unmergeable = unmergeable; + memory_region_update_pending |= mr->enabled; + memory_region_transaction_commit(); +} + uint64_t memory_region_get_alignment(const MemoryRegion *mr) { return mr->align; From ee6398d862c108f8136a26d93d26680f3d222a3a Mon Sep 17 00:00:00 2001 From: David Hildenbrand Date: Tue, 26 Sep 2023 20:57:38 +0200 Subject: [PATCH 0615/1077] virtio-mem: Mark memslot alias memory regions unmergeable MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Let's mark the memslot alias memory regions as unmergable, such that flatview and vhost won't merge adjacent memory region aliases and we can atomically map/unmap individual aliases without affecting adjacent alias memory regions. This handles vhost and vfio in multiple-memslot mode correctly (which do not support atomic memslot updates) and avoids the temporary removal of large memslots, which can be an expensive operation. For example, vfio might have to unpin + repin a lot of memory, which is undesired. Message-ID: <20230926185738.277351-19-david@redhat.com> Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Michael S. Tsirkin Signed-off-by: David Hildenbrand --- hw/virtio/virtio-mem.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/hw/virtio/virtio-mem.c b/hw/virtio/virtio-mem.c index e1e4250e69..9dc3c61b5a 100644 --- a/hw/virtio/virtio-mem.c +++ b/hw/virtio/virtio-mem.c @@ -940,6 +940,12 @@ static void virtio_mem_prepare_memslots(VirtIOMEM *vmem) memory_region_init_alias(&vmem->memslots[idx], OBJECT(vmem), name, &vmem->memdev->mr, memslot_offset, memslot_size); + /* + * We want to be able to atomically and efficiently activate/deactivate + * individual memslots without affecting adjacent memslots in memory + * notifiers. + */ + memory_region_set_unmergeable(&vmem->memslots[idx], true); } } From f51f90c65ed7706c3c4f7a889ce3d6b7ab75ef6a Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Wed, 11 Oct 2023 08:20:31 +0200 Subject: [PATCH 0616/1077] gitlab-ci: Disable the riscv64-debian-cross-container by default This job is failing since weeks. Let's mark it as manual until it gets fixed. Message-Id: <82aa015a-ca94-49ce-beec-679cc175b726@redhat.com> Acked-by: Michael Tokarev Signed-off-by: Thomas Huth --- .gitlab-ci.d/container-cross.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitlab-ci.d/container-cross.yml b/.gitlab-ci.d/container-cross.yml index e0d75d5824..2848166ba3 100644 --- a/.gitlab-ci.d/container-cross.yml +++ b/.gitlab-ci.d/container-cross.yml @@ -95,6 +95,7 @@ riscv64-debian-cross-container: allow_failure: true variables: NAME: debian-riscv64-cross + QEMU_JOB_OPTIONAL: 1 # we can however build TCG tests using a non-sid base riscv64-debian-test-cross-container: From b170e92982665e69fcca9f2c63cd079450091603 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Mon, 4 Sep 2023 12:03:03 +0200 Subject: [PATCH 0617/1077] block: rename the bdrv_co_block_status static function bdrv_block_status exists as a wrapper for bdrv_block_status_above, but the name of the (hypothetical) coroutine version, bdrv_co_block_status, is squatted by a random static function. Rename it to bdrv_co_do_block_status. Signed-off-by: Paolo Bonzini Message-ID: <20230904100306.156197-2-pbonzini@redhat.com> Reviewed-by: Kevin Wolf Signed-off-by: Kevin Wolf --- block/io.c | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/block/io.c b/block/io.c index e7f9448d5a..2ff4ffda1c 100644 --- a/block/io.c +++ b/block/io.c @@ -2383,9 +2383,9 @@ int bdrv_flush_all(void) * set to the host mapping and BDS corresponding to the guest offset. */ static int coroutine_fn GRAPH_RDLOCK -bdrv_co_block_status(BlockDriverState *bs, bool want_zero, - int64_t offset, int64_t bytes, - int64_t *pnum, int64_t *map, BlockDriverState **file) +bdrv_co_do_block_status(BlockDriverState *bs, bool want_zero, + int64_t offset, int64_t bytes, + int64_t *pnum, int64_t *map, BlockDriverState **file) { int64_t total_size; int64_t n; /* bytes */ @@ -2544,8 +2544,8 @@ bdrv_co_block_status(BlockDriverState *bs, bool want_zero, if (ret & BDRV_BLOCK_RAW) { assert(ret & BDRV_BLOCK_OFFSET_VALID && local_file); - ret = bdrv_co_block_status(local_file, want_zero, local_map, - *pnum, pnum, &local_map, &local_file); + ret = bdrv_co_do_block_status(local_file, want_zero, local_map, + *pnum, pnum, &local_map, &local_file); goto out; } @@ -2572,8 +2572,8 @@ bdrv_co_block_status(BlockDriverState *bs, bool want_zero, int64_t file_pnum; int ret2; - ret2 = bdrv_co_block_status(local_file, want_zero, local_map, - *pnum, &file_pnum, NULL, NULL); + ret2 = bdrv_co_do_block_status(local_file, want_zero, local_map, + *pnum, &file_pnum, NULL, NULL); if (ret2 >= 0) { /* Ignore errors. This is just providing extra information, it * is useful but not necessary. @@ -2640,7 +2640,8 @@ bdrv_co_common_block_status_above(BlockDriverState *bs, return 0; } - ret = bdrv_co_block_status(bs, want_zero, offset, bytes, pnum, map, file); + ret = bdrv_co_do_block_status(bs, want_zero, offset, bytes, pnum, + map, file); ++*depth; if (ret < 0 || *pnum == 0 || ret & BDRV_BLOCK_ALLOCATED || bs == base) { return ret; @@ -2656,8 +2657,8 @@ bdrv_co_common_block_status_above(BlockDriverState *bs, for (p = bdrv_filter_or_cow_bs(bs); include_base || p != base; p = bdrv_filter_or_cow_bs(p)) { - ret = bdrv_co_block_status(p, want_zero, offset, bytes, pnum, map, - file); + ret = bdrv_co_do_block_status(p, want_zero, offset, bytes, pnum, + map, file); ++*depth; if (ret < 0) { return ret; From 1b88457eaae483d34d7ec40d2fcd9cf771982910 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Mon, 4 Sep 2023 12:03:04 +0200 Subject: [PATCH 0618/1077] block: complete public block status API Include both coroutine and non-coroutine versions, the latter being co_wrapper_mixed_bdrv_rdlock of the former. Reviewed-by: Eric Blake Signed-off-by: Paolo Bonzini Message-ID: <20230904100306.156197-3-pbonzini@redhat.com> Reviewed-by: Kevin Wolf Signed-off-by: Kevin Wolf --- block/io.c | 18 +++++------------- include/block/block-io.h | 17 +++++++++++------ 2 files changed, 16 insertions(+), 19 deletions(-) diff --git a/block/io.c b/block/io.c index 2ff4ffda1c..4ecc21c562 100644 --- a/block/io.c +++ b/block/io.c @@ -2724,21 +2724,13 @@ int coroutine_fn bdrv_co_block_status_above(BlockDriverState *bs, bytes, pnum, map, file, NULL); } -int bdrv_block_status_above(BlockDriverState *bs, BlockDriverState *base, - int64_t offset, int64_t bytes, int64_t *pnum, - int64_t *map, BlockDriverState **file) +int coroutine_fn bdrv_co_block_status(BlockDriverState *bs, int64_t offset, + int64_t bytes, int64_t *pnum, + int64_t *map, BlockDriverState **file) { IO_CODE(); - return bdrv_common_block_status_above(bs, base, false, true, offset, bytes, - pnum, map, file, NULL); -} - -int bdrv_block_status(BlockDriverState *bs, int64_t offset, int64_t bytes, - int64_t *pnum, int64_t *map, BlockDriverState **file) -{ - IO_CODE(); - return bdrv_block_status_above(bs, bdrv_filter_or_cow_bs(bs), - offset, bytes, pnum, map, file); + return bdrv_co_block_status_above(bs, bdrv_filter_or_cow_bs(bs), + offset, bytes, pnum, map, file); } /* diff --git a/include/block/block-io.h b/include/block/block-io.h index f1c796a1ce..41f78f2fc5 100644 --- a/include/block/block-io.h +++ b/include/block/block-io.h @@ -127,17 +127,22 @@ int coroutine_fn GRAPH_RDLOCK bdrv_co_zone_append(BlockDriverState *bs, BdrvRequestFlags flags); bool bdrv_can_write_zeroes_with_unmap(BlockDriverState *bs); -int bdrv_block_status(BlockDriverState *bs, int64_t offset, - int64_t bytes, int64_t *pnum, int64_t *map, - BlockDriverState **file); + +int coroutine_fn GRAPH_RDLOCK +bdrv_co_block_status(BlockDriverState *bs, int64_t offset, int64_t bytes, + int64_t *pnum, int64_t *map, BlockDriverState **file); +int co_wrapper_mixed_bdrv_rdlock +bdrv_block_status(BlockDriverState *bs, int64_t offset, int64_t bytes, + int64_t *pnum, int64_t *map, BlockDriverState **file); int coroutine_fn GRAPH_RDLOCK bdrv_co_block_status_above(BlockDriverState *bs, BlockDriverState *base, int64_t offset, int64_t bytes, int64_t *pnum, int64_t *map, BlockDriverState **file); -int bdrv_block_status_above(BlockDriverState *bs, BlockDriverState *base, - int64_t offset, int64_t bytes, int64_t *pnum, - int64_t *map, BlockDriverState **file); +int co_wrapper_mixed_bdrv_rdlock +bdrv_block_status_above(BlockDriverState *bs, BlockDriverState *base, + int64_t offset, int64_t bytes, int64_t *pnum, + int64_t *map, BlockDriverState **file); int coroutine_fn GRAPH_RDLOCK bdrv_co_is_allocated(BlockDriverState *bs, int64_t offset, int64_t bytes, From 578ffa9ffb13d9a40790de2a3dda8730d4d43efc Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Mon, 4 Sep 2023 12:03:05 +0200 Subject: [PATCH 0619/1077] block: switch to co_wrapper for bdrv_is_allocated_* Reviewed-by: Eric Blake Signed-off-by: Paolo Bonzini Message-ID: <20230904100306.156197-4-pbonzini@redhat.com> Reviewed-by: Kevin Wolf Signed-off-by: Kevin Wolf --- block/io.c | 53 ++++++---------------------------------- include/block/block-io.h | 12 +++++---- 2 files changed, 14 insertions(+), 51 deletions(-) diff --git a/block/io.c b/block/io.c index 4ecc21c562..b15a1ea880 100644 --- a/block/io.c +++ b/block/io.c @@ -2777,45 +2777,6 @@ int coroutine_fn bdrv_co_is_allocated(BlockDriverState *bs, int64_t offset, return !!(ret & BDRV_BLOCK_ALLOCATED); } -int bdrv_is_allocated(BlockDriverState *bs, int64_t offset, int64_t bytes, - int64_t *pnum) -{ - int ret; - int64_t dummy; - IO_CODE(); - - ret = bdrv_common_block_status_above(bs, bs, true, false, offset, - bytes, pnum ? pnum : &dummy, NULL, - NULL, NULL); - if (ret < 0) { - return ret; - } - return !!(ret & BDRV_BLOCK_ALLOCATED); -} - -/* See bdrv_is_allocated_above for documentation */ -int coroutine_fn bdrv_co_is_allocated_above(BlockDriverState *top, - BlockDriverState *base, - bool include_base, int64_t offset, - int64_t bytes, int64_t *pnum) -{ - int depth; - int ret; - IO_CODE(); - - ret = bdrv_co_common_block_status_above(top, base, include_base, false, - offset, bytes, pnum, NULL, NULL, - &depth); - if (ret < 0) { - return ret; - } - - if (ret & BDRV_BLOCK_ALLOCATED) { - return depth; - } - return 0; -} - /* * Given an image chain: ... -> [BASE] -> [INTER1] -> [INTER2] -> [TOP] * @@ -2833,18 +2794,18 @@ int coroutine_fn bdrv_co_is_allocated_above(BlockDriverState *top, * words, the result is not necessarily the maximum possible range); * but 'pnum' will only be 0 when end of file is reached. */ -int bdrv_is_allocated_above(BlockDriverState *top, - BlockDriverState *base, - bool include_base, int64_t offset, - int64_t bytes, int64_t *pnum) +int coroutine_fn bdrv_co_is_allocated_above(BlockDriverState *bs, + BlockDriverState *base, + bool include_base, int64_t offset, + int64_t bytes, int64_t *pnum) { int depth; int ret; IO_CODE(); - ret = bdrv_common_block_status_above(top, base, include_base, false, - offset, bytes, pnum, NULL, NULL, - &depth); + ret = bdrv_co_common_block_status_above(bs, base, include_base, false, + offset, bytes, pnum, NULL, NULL, + &depth); if (ret < 0) { return ret; } diff --git a/include/block/block-io.h b/include/block/block-io.h index 41f78f2fc5..6485b194a4 100644 --- a/include/block/block-io.h +++ b/include/block/block-io.h @@ -147,16 +147,18 @@ bdrv_block_status_above(BlockDriverState *bs, BlockDriverState *base, int coroutine_fn GRAPH_RDLOCK bdrv_co_is_allocated(BlockDriverState *bs, int64_t offset, int64_t bytes, int64_t *pnum); -int bdrv_is_allocated(BlockDriverState *bs, int64_t offset, int64_t bytes, - int64_t *pnum); +int co_wrapper_mixed_bdrv_rdlock +bdrv_is_allocated(BlockDriverState *bs, int64_t offset, + int64_t bytes, int64_t *pnum); int coroutine_fn GRAPH_RDLOCK bdrv_co_is_allocated_above(BlockDriverState *top, BlockDriverState *base, bool include_base, int64_t offset, int64_t bytes, int64_t *pnum); -int bdrv_is_allocated_above(BlockDriverState *top, BlockDriverState *base, - bool include_base, int64_t offset, int64_t bytes, - int64_t *pnum); +int co_wrapper_mixed_bdrv_rdlock +bdrv_is_allocated_above(BlockDriverState *bs, BlockDriverState *base, + bool include_base, int64_t offset, + int64_t bytes, int64_t *pnum); int coroutine_fn GRAPH_RDLOCK bdrv_co_is_zero_fast(BlockDriverState *bs, int64_t offset, int64_t bytes); From cc323997731bb1c2a9896fcca668b57d82d62153 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Mon, 4 Sep 2023 12:03:06 +0200 Subject: [PATCH 0620/1077] block: convert more bdrv_is_allocated* and bdrv_block_status* calls to coroutine versions Reviewed-by: Eric Blake Signed-off-by: Paolo Bonzini Message-ID: <20230904100306.156197-5-pbonzini@redhat.com> Reviewed-by: Kevin Wolf Signed-off-by: Kevin Wolf --- block/copy-before-write.c | 2 +- block/copy-on-read.c | 8 ++++---- block/io.c | 6 +++--- block/mirror.c | 10 +++++----- block/qcow2.c | 5 +++-- block/replication.c | 8 ++++---- block/stream.c | 8 ++++---- block/vvfat.c | 18 +++++++++--------- 8 files changed, 33 insertions(+), 32 deletions(-) diff --git a/block/copy-before-write.c b/block/copy-before-write.c index aeaff3bb82..4ffabc5ca2 100644 --- a/block/copy-before-write.c +++ b/block/copy-before-write.c @@ -305,7 +305,7 @@ cbw_co_snapshot_block_status(BlockDriverState *bs, return -EACCES; } - ret = bdrv_block_status(child->bs, offset, cur_bytes, pnum, map, file); + ret = bdrv_co_block_status(child->bs, offset, cur_bytes, pnum, map, file); if (child == s->target) { /* * We refer to s->target only for areas that we've written to it. diff --git a/block/copy-on-read.c b/block/copy-on-read.c index b4d6b7efc3..5149fcf63a 100644 --- a/block/copy-on-read.c +++ b/block/copy-on-read.c @@ -146,11 +146,11 @@ cor_co_preadv_part(BlockDriverState *bs, int64_t offset, int64_t bytes, local_flags = flags; /* In case of failure, try to copy-on-read anyway */ - ret = bdrv_is_allocated(bs->file->bs, offset, bytes, &n); + ret = bdrv_co_is_allocated(bs->file->bs, offset, bytes, &n); if (ret <= 0) { - ret = bdrv_is_allocated_above(bdrv_backing_chain_next(bs->file->bs), - state->bottom_bs, true, offset, - n, &n); + ret = bdrv_co_is_allocated_above(bdrv_backing_chain_next(bs->file->bs), + state->bottom_bs, true, offset, + n, &n); if (ret > 0 || ret < 0) { local_flags |= BDRV_REQ_COPY_ON_READ; } diff --git a/block/io.c b/block/io.c index b15a1ea880..9e170929a7 100644 --- a/block/io.c +++ b/block/io.c @@ -1223,8 +1223,8 @@ bdrv_co_do_copy_on_readv(BdrvChild *child, int64_t offset, int64_t bytes, ret = 1; /* "already allocated", so nothing will be copied */ pnum = MIN(align_bytes, max_transfer); } else { - ret = bdrv_is_allocated(bs, align_offset, - MIN(align_bytes, max_transfer), &pnum); + ret = bdrv_co_is_allocated(bs, align_offset, + MIN(align_bytes, max_transfer), &pnum); if (ret < 0) { /* * Safe to treat errors in querying allocation as if @@ -1371,7 +1371,7 @@ bdrv_aligned_preadv(BdrvChild *child, BdrvTrackedRequest *req, /* The flag BDRV_REQ_COPY_ON_READ has reached its addressee */ flags &= ~BDRV_REQ_COPY_ON_READ; - ret = bdrv_is_allocated(bs, offset, bytes, &pnum); + ret = bdrv_co_is_allocated(bs, offset, bytes, &pnum); if (ret < 0) { goto out; } diff --git a/block/mirror.c b/block/mirror.c index 3cc0757a03..dcd88de2e3 100644 --- a/block/mirror.c +++ b/block/mirror.c @@ -559,9 +559,9 @@ static void coroutine_fn mirror_iteration(MirrorBlockJob *s) assert(!(offset % s->granularity)); WITH_GRAPH_RDLOCK_GUARD() { - ret = bdrv_block_status_above(source, NULL, offset, - nb_chunks * s->granularity, - &io_bytes, NULL, NULL); + ret = bdrv_co_block_status_above(source, NULL, offset, + nb_chunks * s->granularity, + &io_bytes, NULL, NULL); } if (ret < 0) { io_bytes = MIN(nb_chunks * s->granularity, max_io_bytes); @@ -879,8 +879,8 @@ static int coroutine_fn mirror_dirty_init(MirrorBlockJob *s) } WITH_GRAPH_RDLOCK_GUARD() { - ret = bdrv_is_allocated_above(bs, s->base_overlay, true, offset, - bytes, &count); + ret = bdrv_co_is_allocated_above(bs, s->base_overlay, true, offset, + bytes, &count); } if (ret < 0) { return ret; diff --git a/block/qcow2.c b/block/qcow2.c index 5a3c537f14..6e9c731bac 100644 --- a/block/qcow2.c +++ b/block/qcow2.c @@ -3991,7 +3991,8 @@ finish: } -static bool is_zero(BlockDriverState *bs, int64_t offset, int64_t bytes) +static bool coroutine_fn GRAPH_RDLOCK +is_zero(BlockDriverState *bs, int64_t offset, int64_t bytes) { int64_t nr; int res; @@ -4012,7 +4013,7 @@ static bool is_zero(BlockDriverState *bs, int64_t offset, int64_t bytes) * backing file. So, we need a loop. */ do { - res = bdrv_block_status_above(bs, NULL, offset, bytes, &nr, NULL, NULL); + res = bdrv_co_block_status_above(bs, NULL, offset, bytes, &nr, NULL, NULL); offset += nr; bytes -= nr; } while (res >= 0 && (res & BDRV_BLOCK_ZERO) && nr && bytes); diff --git a/block/replication.c b/block/replication.c index dd166d2d82..4ad3dd5115 100644 --- a/block/replication.c +++ b/block/replication.c @@ -276,10 +276,10 @@ replication_co_writev(BlockDriverState *bs, int64_t sector_num, while (remaining_sectors > 0) { int64_t count; - ret = bdrv_is_allocated_above(top->bs, base->bs, false, - sector_num * BDRV_SECTOR_SIZE, - remaining_sectors * BDRV_SECTOR_SIZE, - &count); + ret = bdrv_co_is_allocated_above(top->bs, base->bs, false, + sector_num * BDRV_SECTOR_SIZE, + remaining_sectors * BDRV_SECTOR_SIZE, + &count); if (ret < 0) { goto out1; } diff --git a/block/stream.c b/block/stream.c index 133cb72fb4..ddaab7dbbd 100644 --- a/block/stream.c +++ b/block/stream.c @@ -172,7 +172,7 @@ static int coroutine_fn stream_run(Job *job, Error **errp) copy = false; WITH_GRAPH_RDLOCK_GUARD() { - ret = bdrv_is_allocated(unfiltered_bs, offset, STREAM_CHUNK, &n); + ret = bdrv_co_is_allocated(unfiltered_bs, offset, STREAM_CHUNK, &n); if (ret == 1) { /* Allocated in the top, no need to copy. */ } else if (ret >= 0) { @@ -180,9 +180,9 @@ static int coroutine_fn stream_run(Job *job, Error **errp) * Copy if allocated in the intermediate images. Limit to the * known-unallocated area [offset, offset+n*BDRV_SECTOR_SIZE). */ - ret = bdrv_is_allocated_above(bdrv_cow_bs(unfiltered_bs), - s->base_overlay, true, - offset, n, &n); + ret = bdrv_co_is_allocated_above(bdrv_cow_bs(unfiltered_bs), + s->base_overlay, true, + offset, n, &n); /* Finish early if end of backing file has been reached */ if (ret == 0 && n == 0) { n = len - offset; diff --git a/block/vvfat.c b/block/vvfat.c index 856b479c91..1a3a64c713 100644 --- a/block/vvfat.c +++ b/block/vvfat.c @@ -1480,8 +1480,8 @@ vvfat_read(BlockDriverState *bs, int64_t sector_num, uint8_t *buf, int nb_sector if (s->qcow) { int64_t n; int ret; - ret = bdrv_is_allocated(s->qcow->bs, sector_num * BDRV_SECTOR_SIZE, - (nb_sectors - i) * BDRV_SECTOR_SIZE, &n); + ret = bdrv_co_is_allocated(s->qcow->bs, sector_num * BDRV_SECTOR_SIZE, + (nb_sectors - i) * BDRV_SECTOR_SIZE, &n); if (ret < 0) { return ret; } @@ -1806,10 +1806,10 @@ cluster_was_modified(BDRVVVFATState *s, uint32_t cluster_num) } for (i = 0; !was_modified && i < s->sectors_per_cluster; i++) { - was_modified = bdrv_is_allocated(s->qcow->bs, - (cluster2sector(s, cluster_num) + - i) * BDRV_SECTOR_SIZE, - BDRV_SECTOR_SIZE, NULL); + was_modified = bdrv_co_is_allocated(s->qcow->bs, + (cluster2sector(s, cluster_num) + + i) * BDRV_SECTOR_SIZE, + BDRV_SECTOR_SIZE, NULL); } /* @@ -1967,9 +1967,9 @@ get_cluster_count_for_direntry(BDRVVVFATState* s, direntry_t* direntry, const ch for (i = 0; i < s->sectors_per_cluster; i++) { int res; - res = bdrv_is_allocated(s->qcow->bs, - (offs + i) * BDRV_SECTOR_SIZE, - BDRV_SECTOR_SIZE, NULL); + res = bdrv_co_is_allocated(s->qcow->bs, + (offs + i) * BDRV_SECTOR_SIZE, + BDRV_SECTOR_SIZE, NULL); if (res < 0) { return -1; } From 903df115aaa5b9455ffde2894002f3f4820868bd Mon Sep 17 00:00:00 2001 From: Kevin Wolf Date: Fri, 29 Sep 2023 16:51:36 +0200 Subject: [PATCH 0621/1077] test-bdrv-drain: Don't call bdrv_graph_wrlock() in coroutine context AIO callbacks are effectively coroutine_mixed_fn. If AIO requests don't return immediately, their callback is called from the request coroutine. This means that in AIO callbacks, we can't call no_coroutine_fns such as bdrv_graph_wrlock(). Unfortunately test-bdrv-drain does so. Change the test to use a BH to drop out of coroutine context, and add coroutine_mixed_fn and no_coroutine_fn markers to clarify the context each function runs in. Signed-off-by: Kevin Wolf Message-ID: <20230929145157.45443-2-kwolf@redhat.com> Reviewed-by: Stefan Hajnoczi Signed-off-by: Kevin Wolf --- tests/unit/test-bdrv-drain.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/tests/unit/test-bdrv-drain.c b/tests/unit/test-bdrv-drain.c index 0b603e7c57..bdd3757615 100644 --- a/tests/unit/test-bdrv-drain.c +++ b/tests/unit/test-bdrv-drain.c @@ -1168,7 +1168,7 @@ struct detach_by_parent_data { }; static struct detach_by_parent_data detach_by_parent_data; -static void detach_indirect_bh(void *opaque) +static void no_coroutine_fn detach_indirect_bh(void *opaque) { struct detach_by_parent_data *data = opaque; @@ -1184,14 +1184,15 @@ static void detach_indirect_bh(void *opaque) bdrv_graph_wrunlock(); } -static void detach_by_parent_aio_cb(void *opaque, int ret) +static void coroutine_mixed_fn detach_by_parent_aio_cb(void *opaque, int ret) { struct detach_by_parent_data *data = &detach_by_parent_data; g_assert_cmpint(ret, ==, 0); if (data->by_parent_cb) { bdrv_inc_in_flight(data->child_b->bs); - detach_indirect_bh(data); + aio_bh_schedule_oneshot(qemu_get_current_aio_context(), + detach_indirect_bh, &detach_by_parent_data); } } From e84c07bc73f63cd0251d9fd2c582ad051e27fb39 Mon Sep 17 00:00:00 2001 From: Kevin Wolf Date: Fri, 29 Sep 2023 16:51:37 +0200 Subject: [PATCH 0622/1077] block-coroutine-wrapper: Add no_co_wrapper_bdrv_rdlock functions Add a new wrapper type for GRAPH_RDLOCK functions that should be called from coroutine context. Signed-off-by: Kevin Wolf Message-ID: <20230929145157.45443-3-kwolf@redhat.com> Reviewed-by: Stefan Hajnoczi Signed-off-by: Kevin Wolf --- include/block/block-common.h | 7 +++++-- scripts/block-coroutine-wrapper.py | 10 +++++++--- 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/include/block/block-common.h b/include/block/block-common.h index 2d2af7230d..d7599564db 100644 --- a/include/block/block-common.h +++ b/include/block/block-common.h @@ -66,13 +66,16 @@ * function. The coroutine yields after scheduling the BH and is reentered when * the wrapped function returns. * - * A no_co_wrapper_bdrv_wrlock function is a no_co_wrapper function that - * automatically takes the graph wrlock when calling the wrapped function. + * A no_co_wrapper_bdrv_rdlock function is a no_co_wrapper function that + * automatically takes the graph rdlock when calling the wrapped function. In + * the same way, no_co_wrapper_bdrv_wrlock functions automatically take the + * graph wrlock. * * If the first parameter of the function is a BlockDriverState, BdrvChild or * BlockBackend pointer, the AioContext lock for it is taken in the wrapper. */ #define no_co_wrapper +#define no_co_wrapper_bdrv_rdlock #define no_co_wrapper_bdrv_wrlock #include "block/blockjob.h" diff --git a/scripts/block-coroutine-wrapper.py b/scripts/block-coroutine-wrapper.py index 685d0b4ed4..a601c3c672 100644 --- a/scripts/block-coroutine-wrapper.py +++ b/scripts/block-coroutine-wrapper.py @@ -87,8 +87,9 @@ class FuncDecl: raise ValueError(f"Invalid no_co function name: {self.name}") if not self.create_only_co: raise ValueError(f"no_co function can't be mixed: {self.name}") - if self.graph_rdlock: - raise ValueError(f"no_co function can't be rdlock: {self.name}") + if self.graph_rdlock and self.graph_wrlock: + raise ValueError("function can't be both rdlock and wrlock: " + f"{self.name}") self.target_name = f'{subsystem}_{subname}' self.ctx = self.gen_ctx() @@ -256,7 +257,10 @@ def gen_no_co_wrapper(func: FuncDecl) -> str: graph_lock='' graph_unlock='' - if func.graph_wrlock: + if func.graph_rdlock: + graph_lock=' bdrv_graph_rdlock_main_loop();' + graph_unlock=' bdrv_graph_rdunlock_main_loop();' + elif func.graph_wrlock: graph_lock=' bdrv_graph_wrlock(NULL);' graph_unlock=' bdrv_graph_wrunlock();' From 0e6bad1f2171385ec3ab7b9721dacfdb7dda70d7 Mon Sep 17 00:00:00 2001 From: Kevin Wolf Date: Fri, 29 Sep 2023 16:51:38 +0200 Subject: [PATCH 0623/1077] block: Take graph rdlock in bdrv_inactivate_all() The function reads the parents list, so it needs to hold the graph lock. Signed-off-by: Kevin Wolf Message-ID: <20230929145157.45443-4-kwolf@redhat.com> Reviewed-by: Stefan Hajnoczi Signed-off-by: Kevin Wolf --- block.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/block.c b/block.c index af04c8ac6f..b62f6f3841 100644 --- a/block.c +++ b/block.c @@ -6976,7 +6976,8 @@ void bdrv_activate_all(Error **errp) } } -static bool bdrv_has_bds_parent(BlockDriverState *bs, bool only_active) +static bool GRAPH_RDLOCK +bdrv_has_bds_parent(BlockDriverState *bs, bool only_active) { BdrvChild *parent; GLOBAL_STATE_CODE(); @@ -6993,14 +6994,13 @@ static bool bdrv_has_bds_parent(BlockDriverState *bs, bool only_active) return false; } -static int bdrv_inactivate_recurse(BlockDriverState *bs) +static int GRAPH_RDLOCK bdrv_inactivate_recurse(BlockDriverState *bs) { BdrvChild *child, *parent; int ret; uint64_t cumulative_perms, cumulative_shared_perms; GLOBAL_STATE_CODE(); - GRAPH_RDLOCK_GUARD_MAINLOOP(); if (!bs->drv) { return -ENOMEDIUM; @@ -7066,6 +7066,7 @@ int bdrv_inactivate_all(void) GSList *aio_ctxs = NULL, *ctx; GLOBAL_STATE_CODE(); + GRAPH_RDLOCK_GUARD_MAINLOOP(); for (bs = bdrv_first(&it); bs; bs = bdrv_next(&it)) { AioContext *aio_context = bdrv_get_aio_context(bs); From 2b3912f1350971fbc2c04d986a1d0c60ae757c78 Mon Sep 17 00:00:00 2001 From: Kevin Wolf Date: Fri, 29 Sep 2023 16:51:39 +0200 Subject: [PATCH 0624/1077] block: Mark bdrv_first_blk() and bdrv_is_root_node() GRAPH_RDLOCK This adds GRAPH_RDLOCK annotations to declare that callers of bdrv_first_blk() and bdrv_is_root_node() need to hold a reader lock for the graph. These functions are the only functions in block-backend.c that access the parent list of a node. Signed-off-by: Kevin Wolf Message-ID: <20230929145157.45443-5-kwolf@redhat.com> Reviewed-by: Stefan Hajnoczi Signed-off-by: Kevin Wolf --- block.c | 1 + block/block-backend.c | 6 +++++- block/export/export.c | 4 ++++ block/io.c | 1 + block/monitor/block-hmp-cmds.c | 2 ++ block/qapi-sysemu.c | 2 ++ block/replication.c | 10 ++++++++-- block/snapshot.c | 15 +++++++++++---- blockdev.c | 5 +++++ include/block/block-global-state.h | 9 +++++---- include/sysemu/block-backend-global-state.h | 4 ++-- migration/block.c | 2 ++ migration/migration-hmp-cmds.c | 2 ++ tests/unit/test-block-iothread.c | 3 +++ 14 files changed, 53 insertions(+), 13 deletions(-) diff --git a/block.c b/block.c index b62f6f3841..701f77fe2f 100644 --- a/block.c +++ b/block.c @@ -6961,6 +6961,7 @@ void bdrv_activate_all(Error **errp) BdrvNextIterator it; GLOBAL_STATE_CODE(); + GRAPH_RDLOCK_GUARD_MAINLOOP(); for (bs = bdrv_first(&it); bs; bs = bdrv_next(&it)) { AioContext *aio_context = bdrv_get_aio_context(bs); diff --git a/block/block-backend.c b/block/block-backend.c index efe2e7cbf8..39b5f90a11 100644 --- a/block/block-backend.c +++ b/block/block-backend.c @@ -780,11 +780,12 @@ BlockDriverState *blk_bs(BlockBackend *blk) return blk->root ? blk->root->bs : NULL; } -static BlockBackend *bdrv_first_blk(BlockDriverState *bs) +static BlockBackend * GRAPH_RDLOCK bdrv_first_blk(BlockDriverState *bs) { BdrvChild *child; GLOBAL_STATE_CODE(); + assert_bdrv_graph_readable(); QLIST_FOREACH(child, &bs->parents, next_parent) { if (child->klass == &child_root) { @@ -812,6 +813,8 @@ bool bdrv_is_root_node(BlockDriverState *bs) BdrvChild *c; GLOBAL_STATE_CODE(); + assert_bdrv_graph_readable(); + QLIST_FOREACH(c, &bs->parents, next_parent) { if (c->klass != &child_root) { return false; @@ -2259,6 +2262,7 @@ void blk_activate(BlockBackend *blk, Error **errp) if (qemu_in_coroutine()) { bdrv_co_activate(bs, errp); } else { + GRAPH_RDLOCK_GUARD_MAINLOOP(); bdrv_activate(bs, errp); } } diff --git a/block/export/export.c b/block/export/export.c index 10316b43c5..a8f274e526 100644 --- a/block/export/export.c +++ b/block/export/export.c @@ -83,6 +83,8 @@ BlockExport *blk_exp_add(BlockExportOptions *export, Error **errp) uint64_t perm; int ret; + GLOBAL_STATE_CODE(); + if (!id_wellformed(export->id)) { error_setg(errp, "Invalid block export id"); return NULL; @@ -145,7 +147,9 @@ BlockExport *blk_exp_add(BlockExportOptions *export, Error **errp) * access since the export could be available before migration handover. * ctx was acquired in the caller. */ + bdrv_graph_rdlock_main_loop(); bdrv_activate(bs, NULL); + bdrv_graph_rdunlock_main_loop(); perm = BLK_PERM_CONSISTENT_READ; if (export->writable) { diff --git a/block/io.c b/block/io.c index 9e170929a7..5821a4d1f5 100644 --- a/block/io.c +++ b/block/io.c @@ -2330,6 +2330,7 @@ int bdrv_flush_all(void) int result = 0; GLOBAL_STATE_CODE(); + GRAPH_RDLOCK_GUARD_MAINLOOP(); /* * bdrv queue is managed by record/replay, diff --git a/block/monitor/block-hmp-cmds.c b/block/monitor/block-hmp-cmds.c index ca2599de44..6b7d7dd072 100644 --- a/block/monitor/block-hmp-cmds.c +++ b/block/monitor/block-hmp-cmds.c @@ -896,6 +896,8 @@ void hmp_info_snapshots(Monitor *mon, const QDict *qdict) SnapshotEntry *snapshot_entry; Error *err = NULL; + GRAPH_RDLOCK_GUARD_MAINLOOP(); + bs = bdrv_all_find_vmstate_bs(NULL, false, NULL, &err); if (!bs) { error_report_err(err); diff --git a/block/qapi-sysemu.c b/block/qapi-sysemu.c index ef07151892..e885a64c32 100644 --- a/block/qapi-sysemu.c +++ b/block/qapi-sysemu.c @@ -279,6 +279,8 @@ static void blockdev_insert_medium(const char *device, const char *id, BlockBackend *blk; BlockDriverState *bs; + GRAPH_RDLOCK_GUARD_MAINLOOP(); + blk = qmp_get_blk(device, id, errp); if (!blk) { return; diff --git a/block/replication.c b/block/replication.c index 4ad3dd5115..107445d0ce 100644 --- a/block/replication.c +++ b/block/replication.c @@ -458,6 +458,8 @@ static void replication_start(ReplicationState *rs, ReplicationMode mode, Error *local_err = NULL; BackupPerf perf = { .use_copy_range = true, .max_workers = 1 }; + GLOBAL_STATE_CODE(); + aio_context = bdrv_get_aio_context(bs); aio_context_acquire(aio_context); s = bs->opaque; @@ -504,12 +506,15 @@ static void replication_start(ReplicationState *rs, ReplicationMode mode, return; } + bdrv_graph_rdlock_main_loop(); secondary_disk = hidden_disk->bs->backing; if (!secondary_disk->bs || !bdrv_has_blk(secondary_disk->bs)) { error_setg(errp, "The secondary disk doesn't have block backend"); + bdrv_graph_rdunlock_main_loop(); aio_context_release(aio_context); return; } + bdrv_graph_rdunlock_main_loop(); /* verify the length */ active_length = bdrv_getlength(active_disk->bs); @@ -566,8 +571,6 @@ static void replication_start(ReplicationState *rs, ReplicationMode mode, return; } - bdrv_graph_wrunlock(); - /* start backup job now */ error_setg(&s->blocker, "Block device is in use by internal backup job"); @@ -576,6 +579,7 @@ static void replication_start(ReplicationState *rs, ReplicationMode mode, if (!top_bs || !bdrv_is_root_node(top_bs) || !check_top_bs(top_bs, bs)) { error_setg(errp, "No top_bs or it is invalid"); + bdrv_graph_wrunlock(); reopen_backing_file(bs, false, NULL); aio_context_release(aio_context); return; @@ -583,6 +587,8 @@ static void replication_start(ReplicationState *rs, ReplicationMode mode, bdrv_op_block_all(top_bs, s->blocker); bdrv_op_unblock(top_bs, BLOCK_OP_TYPE_DATAPLANE, s->blocker); + bdrv_graph_wrunlock(); + s->backup_job = backup_job_create( NULL, s->secondary_disk->bs, s->hidden_disk->bs, 0, MIRROR_SYNC_MODE_NONE, NULL, 0, false, NULL, diff --git a/block/snapshot.c b/block/snapshot.c index b86b5b24ad..633391e8a9 100644 --- a/block/snapshot.c +++ b/block/snapshot.c @@ -462,9 +462,9 @@ int bdrv_snapshot_load_tmp_by_id_or_name(BlockDriverState *bs, } -static int bdrv_all_get_snapshot_devices(bool has_devices, strList *devices, - GList **all_bdrvs, - Error **errp) +static int GRAPH_RDLOCK +bdrv_all_get_snapshot_devices(bool has_devices, strList *devices, + GList **all_bdrvs, Error **errp) { g_autoptr(GList) bdrvs = NULL; @@ -496,7 +496,7 @@ static int bdrv_all_get_snapshot_devices(bool has_devices, strList *devices, } -static bool bdrv_all_snapshots_includes_bs(BlockDriverState *bs) +static bool GRAPH_RDLOCK bdrv_all_snapshots_includes_bs(BlockDriverState *bs) { if (!bdrv_is_inserted(bs) || bdrv_is_read_only(bs)) { return false; @@ -518,6 +518,7 @@ bool bdrv_all_can_snapshot(bool has_devices, strList *devices, GList *iterbdrvs; GLOBAL_STATE_CODE(); + GRAPH_RDLOCK_GUARD_MAINLOOP(); if (bdrv_all_get_snapshot_devices(has_devices, devices, &bdrvs, errp) < 0) { return false; @@ -554,6 +555,7 @@ int bdrv_all_delete_snapshot(const char *name, GList *iterbdrvs; GLOBAL_STATE_CODE(); + GRAPH_RDLOCK_GUARD_MAINLOOP(); if (bdrv_all_get_snapshot_devices(has_devices, devices, &bdrvs, errp) < 0) { return -1; @@ -595,6 +597,7 @@ int bdrv_all_goto_snapshot(const char *name, GList *iterbdrvs; GLOBAL_STATE_CODE(); + GRAPH_RDLOCK_GUARD_MAINLOOP(); if (bdrv_all_get_snapshot_devices(has_devices, devices, &bdrvs, errp) < 0) { return -1; @@ -631,6 +634,7 @@ int bdrv_all_has_snapshot(const char *name, GList *iterbdrvs; GLOBAL_STATE_CODE(); + GRAPH_RDLOCK_GUARD_MAINLOOP(); if (bdrv_all_get_snapshot_devices(has_devices, devices, &bdrvs, errp) < 0) { return -1; @@ -673,7 +677,9 @@ int bdrv_all_create_snapshot(QEMUSnapshotInfo *sn, { g_autoptr(GList) bdrvs = NULL; GList *iterbdrvs; + GLOBAL_STATE_CODE(); + GRAPH_RDLOCK_GUARD_MAINLOOP(); if (bdrv_all_get_snapshot_devices(has_devices, devices, &bdrvs, errp) < 0) { return -1; @@ -715,6 +721,7 @@ BlockDriverState *bdrv_all_find_vmstate_bs(const char *vmstate_bs, GList *iterbdrvs; GLOBAL_STATE_CODE(); + GRAPH_RDLOCK_GUARD_MAINLOOP(); if (bdrv_all_get_snapshot_devices(has_devices, devices, &bdrvs, errp) < 0) { return NULL; diff --git a/blockdev.c b/blockdev.c index 325b7a3bef..b6b7c44288 100644 --- a/blockdev.c +++ b/blockdev.c @@ -1041,6 +1041,8 @@ static BlockDriverState *qmp_get_root_bs(const char *name, Error **errp) BlockDriverState *bs; AioContext *aio_context; + GRAPH_RDLOCK_GUARD_MAINLOOP(); + bs = bdrv_lookup_bs(name, name, errp); if (bs == NULL) { return NULL; @@ -3509,6 +3511,7 @@ void qmp_blockdev_del(const char *node_name, Error **errp) BlockDriverState *bs; GLOBAL_STATE_CODE(); + GRAPH_RDLOCK_GUARD_MAINLOOP(); bs = bdrv_find_node(node_name); if (!bs) { @@ -3636,6 +3639,8 @@ void qmp_x_blockdev_set_iothread(const char *node_name, StrOrNull *iothread, AioContext *new_context; BlockDriverState *bs; + GRAPH_RDLOCK_GUARD_MAINLOOP(); + bs = bdrv_find_node(node_name); if (!bs) { error_setg(errp, "Failed to find node with node-name='%s'", node_name); diff --git a/include/block/block-global-state.h b/include/block/block-global-state.h index 6061220a6c..505a0d0c11 100644 --- a/include/block/block-global-state.h +++ b/include/block/block-global-state.h @@ -170,9 +170,10 @@ BlockDriverState * GRAPH_RDLOCK check_to_replace_node(BlockDriverState *parent_bs, const char *node_name, Error **errp); -int no_coroutine_fn bdrv_activate(BlockDriverState *bs, Error **errp); +int no_coroutine_fn GRAPH_RDLOCK +bdrv_activate(BlockDriverState *bs, Error **errp); -int coroutine_fn no_co_wrapper +int coroutine_fn no_co_wrapper_bdrv_rdlock bdrv_co_activate(BlockDriverState *bs, Error **errp); void bdrv_activate_all(Error **errp); @@ -208,8 +209,8 @@ typedef struct BdrvNextIterator { BlockDriverState *bs; } BdrvNextIterator; -BlockDriverState *bdrv_first(BdrvNextIterator *it); -BlockDriverState *bdrv_next(BdrvNextIterator *it); +BlockDriverState * GRAPH_RDLOCK bdrv_first(BdrvNextIterator *it); +BlockDriverState * GRAPH_RDLOCK bdrv_next(BdrvNextIterator *it); void bdrv_next_cleanup(BdrvNextIterator *it); BlockDriverState *bdrv_next_monitor_owned(BlockDriverState *bs); diff --git a/include/sysemu/block-backend-global-state.h b/include/sysemu/block-backend-global-state.h index d5f675493a..49c12b0fa9 100644 --- a/include/sysemu/block-backend-global-state.h +++ b/include/sysemu/block-backend-global-state.h @@ -59,8 +59,8 @@ BlockBackend *blk_by_public(BlockBackendPublic *public); void blk_remove_bs(BlockBackend *blk); int blk_insert_bs(BlockBackend *blk, BlockDriverState *bs, Error **errp); int blk_replace_bs(BlockBackend *blk, BlockDriverState *new_bs, Error **errp); -bool bdrv_has_blk(BlockDriverState *bs); -bool bdrv_is_root_node(BlockDriverState *bs); +bool GRAPH_RDLOCK bdrv_has_blk(BlockDriverState *bs); +bool GRAPH_RDLOCK bdrv_is_root_node(BlockDriverState *bs); int GRAPH_UNLOCKED blk_set_perm(BlockBackend *blk, uint64_t perm, uint64_t shared_perm, Error **errp); void blk_get_perm(BlockBackend *blk, uint64_t *perm, uint64_t *shared_perm); diff --git a/migration/block.c b/migration/block.c index 5f930870a5..d115e1cfa5 100644 --- a/migration/block.c +++ b/migration/block.c @@ -388,6 +388,8 @@ static int init_blk_migration(QEMUFile *f) Error *local_err = NULL; int ret; + GRAPH_RDLOCK_GUARD_MAINLOOP(); + block_mig_state.submitted = 0; block_mig_state.read_done = 0; block_mig_state.transferred = 0; diff --git a/migration/migration-hmp-cmds.c b/migration/migration-hmp-cmds.c index c115ef2d23..5b25ba24f7 100644 --- a/migration/migration-hmp-cmds.c +++ b/migration/migration-hmp-cmds.c @@ -794,6 +794,8 @@ static void vm_completion(ReadLineState *rs, const char *str) BlockDriverState *bs; BdrvNextIterator it; + GRAPH_RDLOCK_GUARD_MAINLOOP(); + len = strlen(str); readline_set_completion_index(rs, len); diff --git a/tests/unit/test-block-iothread.c b/tests/unit/test-block-iothread.c index 9155547313..151049bda5 100644 --- a/tests/unit/test-block-iothread.c +++ b/tests/unit/test-block-iothread.c @@ -383,6 +383,9 @@ static void test_sync_op_check(BdrvChild *c) static void test_sync_op_activate(BdrvChild *c) { + GLOBAL_STATE_CODE(); + GRAPH_RDLOCK_GUARD_MAINLOOP(); + /* Early success: Image is not inactive */ bdrv_activate(c->bs, NULL); } From d05ab380db649d882396653f9830b67d84bffbe1 Mon Sep 17 00:00:00 2001 From: Emanuele Giuseppe Esposito Date: Fri, 29 Sep 2023 16:51:40 +0200 Subject: [PATCH 0625/1077] block: Mark drain related functions GRAPH_RDLOCK Draining recursively traverses the graph, therefore we need to make sure that also such accesses to the graph are protected by the graph rdlock. There are 3 different drain callers to consider: 1. drain in the main loop: no issue at all, rdlock is nop. 2. drain in an iothread: rdlock only works in main loop or coroutines, so disallow it. 3. drain in a coroutine (regardless of AioContext): the drain mechanism takes care of scheduling a BH in the bs->aio_context that will then take care of perform the actual draining. This is wrong, because as pointed in (2) if bs->aio_context is an iothread then rdlock won't work. Therefore change bdrv_co_yield_to_drain to schedule the BH in the main loop. Caller (2) also implies that we need to modify test-bdrv-drain.c to disallow draining in the iothreads. For some places, we know that they will hold the lock, but we don't have the GRAPH_RDLOCK annotations yet. In this case, add assume_graph_lock() with a FIXME comment. These places will be removed once everything is properly annotated. Signed-off-by: Emanuele Giuseppe Esposito Signed-off-by: Kevin Wolf Message-ID: <20230929145157.45443-6-kwolf@redhat.com> Reviewed-by: Stefan Hajnoczi Signed-off-by: Kevin Wolf --- block.c | 6 +++--- block/io.c | 32 ++++++++++++++++++++++++++++---- include/block/block-io.h | 23 ++++++++++++++++++----- include/block/block_int-common.h | 6 +++--- tests/unit/test-bdrv-drain.c | 4 ++-- 5 files changed, 54 insertions(+), 17 deletions(-) diff --git a/block.c b/block.c index 701f77fe2f..6cc4115510 100644 --- a/block.c +++ b/block.c @@ -1192,19 +1192,19 @@ static char *bdrv_child_get_parent_desc(BdrvChild *c) return g_strdup_printf("node '%s'", bdrv_get_node_name(parent)); } -static void bdrv_child_cb_drained_begin(BdrvChild *child) +static void GRAPH_RDLOCK bdrv_child_cb_drained_begin(BdrvChild *child) { BlockDriverState *bs = child->opaque; bdrv_do_drained_begin_quiesce(bs, NULL); } -static bool bdrv_child_cb_drained_poll(BdrvChild *child) +static bool GRAPH_RDLOCK bdrv_child_cb_drained_poll(BdrvChild *child) { BlockDriverState *bs = child->opaque; return bdrv_drain_poll(bs, NULL, false); } -static void bdrv_child_cb_drained_end(BdrvChild *child) +static void GRAPH_RDLOCK bdrv_child_cb_drained_end(BdrvChild *child) { BlockDriverState *bs = child->opaque; bdrv_drained_end(bs); diff --git a/block/io.c b/block/io.c index 5821a4d1f5..e2e846d37d 100644 --- a/block/io.c +++ b/block/io.c @@ -46,9 +46,12 @@ static void bdrv_parent_cb_resize(BlockDriverState *bs); static int coroutine_fn bdrv_co_do_pwrite_zeroes(BlockDriverState *bs, int64_t offset, int64_t bytes, BdrvRequestFlags flags); -static void bdrv_parent_drained_begin(BlockDriverState *bs, BdrvChild *ignore) +static void GRAPH_RDLOCK +bdrv_parent_drained_begin(BlockDriverState *bs, BdrvChild *ignore) { BdrvChild *c, *next; + IO_OR_GS_CODE(); + assert_bdrv_graph_readable(); QLIST_FOREACH_SAFE(c, &bs->parents, next_parent, next) { if (c == ignore) { @@ -70,9 +73,12 @@ void bdrv_parent_drained_end_single(BdrvChild *c) } } -static void bdrv_parent_drained_end(BlockDriverState *bs, BdrvChild *ignore) +static void GRAPH_RDLOCK +bdrv_parent_drained_end(BlockDriverState *bs, BdrvChild *ignore) { BdrvChild *c; + IO_OR_GS_CODE(); + assert_bdrv_graph_readable(); QLIST_FOREACH(c, &bs->parents, next_parent) { if (c == ignore) { @@ -84,17 +90,22 @@ static void bdrv_parent_drained_end(BlockDriverState *bs, BdrvChild *ignore) bool bdrv_parent_drained_poll_single(BdrvChild *c) { + IO_OR_GS_CODE(); + if (c->klass->drained_poll) { return c->klass->drained_poll(c); } return false; } -static bool bdrv_parent_drained_poll(BlockDriverState *bs, BdrvChild *ignore, - bool ignore_bds_parents) +static bool GRAPH_RDLOCK +bdrv_parent_drained_poll(BlockDriverState *bs, BdrvChild *ignore, + bool ignore_bds_parents) { BdrvChild *c, *next; bool busy = false; + IO_OR_GS_CODE(); + assert_bdrv_graph_readable(); QLIST_FOREACH_SAFE(c, &bs->parents, next_parent, next) { if (c == ignore || (ignore_bds_parents && c->klass->parent_is_bds)) { @@ -114,6 +125,7 @@ void bdrv_parent_drained_begin_single(BdrvChild *c) c->quiesced_parent = true; if (c->klass->drained_begin) { + /* called with rdlock taken, but it doesn't really need it. */ c->klass->drained_begin(c); } } @@ -263,6 +275,9 @@ bool bdrv_drain_poll(BlockDriverState *bs, BdrvChild *ignore_parent, static bool bdrv_drain_poll_top_level(BlockDriverState *bs, BdrvChild *ignore_parent) { + GLOBAL_STATE_CODE(); + GRAPH_RDLOCK_GUARD_MAINLOOP(); + return bdrv_drain_poll(bs, ignore_parent, false); } @@ -362,6 +377,7 @@ static void bdrv_do_drained_begin(BlockDriverState *bs, BdrvChild *parent, /* Stop things in parent-to-child order */ if (qatomic_fetch_inc(&bs->quiesce_counter) == 0) { + GRAPH_RDLOCK_GUARD_MAINLOOP(); bdrv_parent_drained_begin(bs, parent); if (bs->drv && bs->drv->bdrv_drain_begin) { bs->drv->bdrv_drain_begin(bs); @@ -408,12 +424,16 @@ static void bdrv_do_drained_end(BlockDriverState *bs, BdrvChild *parent) bdrv_co_yield_to_drain(bs, false, parent, false); return; } + + /* At this point, we should be always running in the main loop. */ + GLOBAL_STATE_CODE(); assert(bs->quiesce_counter > 0); GLOBAL_STATE_CODE(); /* Re-enable things in child-to-parent order */ old_quiesce_counter = qatomic_fetch_dec(&bs->quiesce_counter); if (old_quiesce_counter == 1) { + GRAPH_RDLOCK_GUARD_MAINLOOP(); if (bs->drv && bs->drv->bdrv_drain_end) { bs->drv->bdrv_drain_end(bs); } @@ -437,6 +457,8 @@ void bdrv_drain(BlockDriverState *bs) static void bdrv_drain_assert_idle(BlockDriverState *bs) { BdrvChild *child, *next; + GLOBAL_STATE_CODE(); + GRAPH_RDLOCK_GUARD_MAINLOOP(); assert(qatomic_read(&bs->in_flight) == 0); QLIST_FOREACH_SAFE(child, &bs->children, next, next) { @@ -450,7 +472,9 @@ static bool bdrv_drain_all_poll(void) { BlockDriverState *bs = NULL; bool result = false; + GLOBAL_STATE_CODE(); + GRAPH_RDLOCK_GUARD_MAINLOOP(); /* bdrv_drain_poll() can't make changes to the graph and we are holding the * main AioContext lock, so iterating bdrv_next_all_states() is safe. */ diff --git a/include/block/block-io.h b/include/block/block-io.h index 6485b194a4..9707eb3eff 100644 --- a/include/block/block-io.h +++ b/include/block/block-io.h @@ -370,7 +370,7 @@ bdrv_writev_vmstate(BlockDriverState *bs, QEMUIOVector *qiov, int64_t pos); * * Begin a quiesced section for the parent of @c. */ -void bdrv_parent_drained_begin_single(BdrvChild *c); +void GRAPH_RDLOCK bdrv_parent_drained_begin_single(BdrvChild *c); /** * bdrv_parent_drained_poll_single: @@ -378,14 +378,14 @@ void bdrv_parent_drained_begin_single(BdrvChild *c); * Returns true if there is any pending activity to cease before @c can be * called quiesced, false otherwise. */ -bool bdrv_parent_drained_poll_single(BdrvChild *c); +bool GRAPH_RDLOCK bdrv_parent_drained_poll_single(BdrvChild *c); /** * bdrv_parent_drained_end_single: * * End a quiesced section for the parent of @c. */ -void bdrv_parent_drained_end_single(BdrvChild *c); +void GRAPH_RDLOCK bdrv_parent_drained_end_single(BdrvChild *c); /** * bdrv_drain_poll: @@ -398,8 +398,9 @@ void bdrv_parent_drained_end_single(BdrvChild *c); * * This is part of bdrv_drained_begin. */ -bool bdrv_drain_poll(BlockDriverState *bs, BdrvChild *ignore_parent, - bool ignore_bds_parents); +bool GRAPH_RDLOCK +bdrv_drain_poll(BlockDriverState *bs, BdrvChild *ignore_parent, + bool ignore_bds_parents); /** * bdrv_drained_begin: @@ -407,6 +408,12 @@ bool bdrv_drain_poll(BlockDriverState *bs, BdrvChild *ignore_parent, * Begin a quiesced section for exclusive access to the BDS, by disabling * external request sources including NBD server, block jobs, and device model. * + * This function can only be invoked by the main loop or a coroutine + * (regardless of the AioContext where it is running). + * If the coroutine is running in an Iothread AioContext, this function will + * just schedule a BH to run in the main loop. + * However, it cannot be directly called by an Iothread. + * * This function can be recursive. */ void bdrv_drained_begin(BlockDriverState *bs); @@ -423,6 +430,12 @@ void bdrv_do_drained_begin_quiesce(BlockDriverState *bs, BdrvChild *parent); * bdrv_drained_end: * * End a quiescent section started by bdrv_drained_begin(). + * + * This function can only be invoked by the main loop or a coroutine + * (regardless of the AioContext where it is running). + * If the coroutine is running in an Iothread AioContext, this function will + * just schedule a BH to run in the main loop. + * However, it cannot be directly called by an Iothread. */ void bdrv_drained_end(BlockDriverState *bs); diff --git a/include/block/block_int-common.h b/include/block/block_int-common.h index 2ca3758cb8..8ef68176a5 100644 --- a/include/block/block_int-common.h +++ b/include/block/block_int-common.h @@ -963,15 +963,15 @@ struct BdrvChildClass { * Note that this can be nested. If drained_begin() was called twice, new * I/O is allowed only after drained_end() was called twice, too. */ - void (*drained_begin)(BdrvChild *child); - void (*drained_end)(BdrvChild *child); + void GRAPH_RDLOCK_PTR (*drained_begin)(BdrvChild *child); + void GRAPH_RDLOCK_PTR (*drained_end)(BdrvChild *child); /* * Returns whether the parent has pending requests for the child. This * callback is polled after .drained_begin() has been called until all * activity on the child has stopped. */ - bool (*drained_poll)(BdrvChild *child); + bool GRAPH_RDLOCK_PTR (*drained_poll)(BdrvChild *child); /* * Notifies the parent that the filename of its child has changed (e.g. diff --git a/tests/unit/test-bdrv-drain.c b/tests/unit/test-bdrv-drain.c index bdd3757615..d734829778 100644 --- a/tests/unit/test-bdrv-drain.c +++ b/tests/unit/test-bdrv-drain.c @@ -1196,7 +1196,7 @@ static void coroutine_mixed_fn detach_by_parent_aio_cb(void *opaque, int ret) } } -static void detach_by_driver_cb_drained_begin(BdrvChild *child) +static void GRAPH_RDLOCK detach_by_driver_cb_drained_begin(BdrvChild *child) { struct detach_by_parent_data *data = &detach_by_parent_data; @@ -1233,7 +1233,7 @@ static BdrvChildClass detach_by_driver_cb_class; * state is messed up, but if it is only polled in the single * BDRV_POLL_WHILE() at the end of the drain, this should work fine. */ -static void test_detach_indirect(bool by_parent_cb) +static void TSA_NO_TSA test_detach_indirect(bool by_parent_cb) { BlockBackend *blk; BlockDriverState *parent_a, *parent_b, *a, *b, *c; From 7859c45a4662284fde4d6b5548263197e8aa4f24 Mon Sep 17 00:00:00 2001 From: Kevin Wolf Date: Fri, 29 Sep 2023 16:51:41 +0200 Subject: [PATCH 0626/1077] block: Mark bdrv_parent_cb_resize() and callers GRAPH_RDLOCK This adds GRAPH_RDLOCK annotations to declare that callers of bdrv_parent_cb_resize() need to hold a reader lock for the graph. Signed-off-by: Kevin Wolf Message-ID: <20230929145157.45443-7-kwolf@redhat.com> Reviewed-by: Stefan Hajnoczi Signed-off-by: Kevin Wolf --- block/io.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/block/io.c b/block/io.c index e2e846d37d..527a1de04e 100644 --- a/block/io.c +++ b/block/io.c @@ -42,7 +42,9 @@ /* Maximum bounce buffer for copy-on-read and write zeroes, in bytes */ #define MAX_BOUNCE_BUFFER (32768 << BDRV_SECTOR_BITS) -static void bdrv_parent_cb_resize(BlockDriverState *bs); +static void coroutine_fn GRAPH_RDLOCK +bdrv_parent_cb_resize(BlockDriverState *bs); + static int coroutine_fn bdrv_co_do_pwrite_zeroes(BlockDriverState *bs, int64_t offset, int64_t bytes, BdrvRequestFlags flags); @@ -2027,7 +2029,7 @@ bdrv_co_write_req_prepare(BdrvChild *child, int64_t offset, int64_t bytes, } } -static inline void coroutine_fn +static inline void coroutine_fn GRAPH_RDLOCK bdrv_co_write_req_finish(BdrvChild *child, int64_t offset, int64_t bytes, BdrvTrackedRequest *req, int ret) { @@ -3530,9 +3532,13 @@ int coroutine_fn bdrv_co_copy_range(BdrvChild *src, int64_t src_offset, bytes, read_flags, write_flags); } -static void bdrv_parent_cb_resize(BlockDriverState *bs) +static void coroutine_fn GRAPH_RDLOCK +bdrv_parent_cb_resize(BlockDriverState *bs) { BdrvChild *c; + + assert_bdrv_graph_readable(); + QLIST_FOREACH(c, &bs->parents, next_parent) { if (c->klass->resize) { c->klass->resize(c); From a32e781838e7231f2239bde0ac2f105dc7072abb Mon Sep 17 00:00:00 2001 From: Kevin Wolf Date: Fri, 29 Sep 2023 16:51:42 +0200 Subject: [PATCH 0627/1077] block: Mark bdrv_snapshot_fallback() and callers GRAPH_RDLOCK This adds GRAPH_RDLOCK annotations to declare that callers of bdrv_snapshot_fallback() need to hold a reader lock for the graph because it accesses the children list of a node. Signed-off-by: Kevin Wolf Message-ID: <20230929145157.45443-8-kwolf@redhat.com> Reviewed-by: Stefan Hajnoczi Signed-off-by: Kevin Wolf --- block/snapshot.c | 35 ++++++++++++++++++++++++++------ blockdev.c | 9 ++++++++ include/block/block_int-common.h | 18 ++++++++-------- include/block/snapshot.h | 24 +++++++++++++--------- qemu-img.c | 5 +++++ 5 files changed, 67 insertions(+), 24 deletions(-) diff --git a/block/snapshot.c b/block/snapshot.c index 633391e8a9..554065578b 100644 --- a/block/snapshot.c +++ b/block/snapshot.c @@ -155,11 +155,15 @@ bool bdrv_snapshot_find_by_id_and_name(BlockDriverState *bs, * back if the given BDS does not support snapshots. * Return NULL if there is no BDS to (safely) fall back to. */ -static BdrvChild *bdrv_snapshot_fallback_child(BlockDriverState *bs) +static BdrvChild * GRAPH_RDLOCK +bdrv_snapshot_fallback_child(BlockDriverState *bs) { BdrvChild *fallback = bdrv_primary_child(bs); BdrvChild *child; + GLOBAL_STATE_CODE(); + assert_bdrv_graph_readable(); + /* We allow fallback only to primary child */ if (!fallback) { return NULL; @@ -182,8 +186,10 @@ static BdrvChild *bdrv_snapshot_fallback_child(BlockDriverState *bs) return fallback; } -static BlockDriverState *bdrv_snapshot_fallback(BlockDriverState *bs) +static BlockDriverState * GRAPH_RDLOCK +bdrv_snapshot_fallback(BlockDriverState *bs) { + GLOBAL_STATE_CODE(); return child_bs(bdrv_snapshot_fallback_child(bs)); } @@ -254,7 +260,10 @@ int bdrv_snapshot_goto(BlockDriverState *bs, return ret; } + bdrv_graph_rdlock_main_loop(); fallback = bdrv_snapshot_fallback_child(bs); + bdrv_graph_rdunlock_main_loop(); + if (fallback) { QDict *options; QDict *file_options; @@ -374,10 +383,12 @@ int bdrv_snapshot_delete(BlockDriverState *bs, int bdrv_snapshot_list(BlockDriverState *bs, QEMUSnapshotInfo **psn_info) { + GLOBAL_STATE_CODE(); + GRAPH_RDLOCK_GUARD_MAINLOOP(); + BlockDriver *drv = bs->drv; BlockDriverState *fallback_bs = bdrv_snapshot_fallback(bs); - GLOBAL_STATE_CODE(); if (!drv) { return -ENOMEDIUM; } @@ -498,6 +509,9 @@ bdrv_all_get_snapshot_devices(bool has_devices, strList *devices, static bool GRAPH_RDLOCK bdrv_all_snapshots_includes_bs(BlockDriverState *bs) { + GLOBAL_STATE_CODE(); + assert_bdrv_graph_readable(); + if (!bdrv_is_inserted(bs) || bdrv_is_read_only(bs)) { return false; } @@ -595,11 +609,15 @@ int bdrv_all_goto_snapshot(const char *name, { g_autoptr(GList) bdrvs = NULL; GList *iterbdrvs; + int ret; GLOBAL_STATE_CODE(); - GRAPH_RDLOCK_GUARD_MAINLOOP(); - if (bdrv_all_get_snapshot_devices(has_devices, devices, &bdrvs, errp) < 0) { + bdrv_graph_rdlock_main_loop(); + ret = bdrv_all_get_snapshot_devices(has_devices, devices, &bdrvs, errp); + bdrv_graph_rdunlock_main_loop(); + + if (ret < 0) { return -1; } @@ -608,9 +626,14 @@ int bdrv_all_goto_snapshot(const char *name, BlockDriverState *bs = iterbdrvs->data; AioContext *ctx = bdrv_get_aio_context(bs); int ret = 0; + bool all_snapshots_includes_bs; aio_context_acquire(ctx); - if (devices || bdrv_all_snapshots_includes_bs(bs)) { + bdrv_graph_rdlock_main_loop(); + all_snapshots_includes_bs = bdrv_all_snapshots_includes_bs(bs); + bdrv_graph_rdunlock_main_loop(); + + if (devices || all_snapshots_includes_bs) { ret = bdrv_snapshot_goto(bs, name, errp); } aio_context_release(ctx); diff --git a/blockdev.c b/blockdev.c index b6b7c44288..43e0c4ddf2 100644 --- a/blockdev.c +++ b/blockdev.c @@ -1138,6 +1138,9 @@ SnapshotInfo *qmp_blockdev_snapshot_delete_internal_sync(const char *device, SnapshotInfo *info = NULL; int ret; + GLOBAL_STATE_CODE(); + GRAPH_RDLOCK_GUARD_MAINLOOP(); + bs = qmp_get_root_bs(device, errp); if (!bs) { return NULL; @@ -1223,6 +1226,9 @@ static void internal_snapshot_action(BlockdevSnapshotInternal *internal, AioContext *aio_context; int ret1; + GLOBAL_STATE_CODE(); + GRAPH_RDLOCK_GUARD_MAINLOOP(); + tran_add(tran, &internal_snapshot_drv, state); device = internal->device; @@ -1311,6 +1317,9 @@ static void internal_snapshot_abort(void *opaque) AioContext *aio_context; Error *local_error = NULL; + GLOBAL_STATE_CODE(); + GRAPH_RDLOCK_GUARD_MAINLOOP(); + if (!state->created) { return; } diff --git a/include/block/block_int-common.h b/include/block/block_int-common.h index 8ef68176a5..29c5b8a3c5 100644 --- a/include/block/block_int-common.h +++ b/include/block/block_int-common.h @@ -313,14 +313,16 @@ struct BlockDriver { int GRAPH_RDLOCK_PTR (*bdrv_inactivate)(BlockDriverState *bs); - int (*bdrv_snapshot_create)(BlockDriverState *bs, - QEMUSnapshotInfo *sn_info); - int (*bdrv_snapshot_goto)(BlockDriverState *bs, - const char *snapshot_id); - int (*bdrv_snapshot_delete)(BlockDriverState *bs, - const char *snapshot_id, - const char *name, - Error **errp); + int GRAPH_RDLOCK_PTR (*bdrv_snapshot_create)( + BlockDriverState *bs, QEMUSnapshotInfo *sn_info); + + int GRAPH_UNLOCKED_PTR (*bdrv_snapshot_goto)( + BlockDriverState *bs, const char *snapshot_id); + + int GRAPH_RDLOCK_PTR (*bdrv_snapshot_delete)( + BlockDriverState *bs, const char *snapshot_id, const char *name, + Error **errp); + int (*bdrv_snapshot_list)(BlockDriverState *bs, QEMUSnapshotInfo **psn_info); int (*bdrv_snapshot_load_tmp)(BlockDriverState *bs, diff --git a/include/block/snapshot.h b/include/block/snapshot.h index 50ff924710..d49c5599d9 100644 --- a/include/block/snapshot.h +++ b/include/block/snapshot.h @@ -25,6 +25,7 @@ #ifndef SNAPSHOT_H #define SNAPSHOT_H +#include "block/graph-lock.h" #include "qapi/qapi-builtin-types.h" #define SNAPSHOT_OPT_BASE "snapshot." @@ -59,16 +60,19 @@ bool bdrv_snapshot_find_by_id_and_name(BlockDriverState *bs, const char *name, QEMUSnapshotInfo *sn_info, Error **errp); -int bdrv_can_snapshot(BlockDriverState *bs); -int bdrv_snapshot_create(BlockDriverState *bs, - QEMUSnapshotInfo *sn_info); -int bdrv_snapshot_goto(BlockDriverState *bs, - const char *snapshot_id, - Error **errp); -int bdrv_snapshot_delete(BlockDriverState *bs, - const char *snapshot_id, - const char *name, - Error **errp); + +int GRAPH_RDLOCK bdrv_can_snapshot(BlockDriverState *bs); + +int GRAPH_RDLOCK +bdrv_snapshot_create(BlockDriverState *bs, QEMUSnapshotInfo *sn_info); + +int GRAPH_UNLOCKED +bdrv_snapshot_goto(BlockDriverState *bs, const char *snapshot_id, Error **errp); + +int GRAPH_RDLOCK +bdrv_snapshot_delete(BlockDriverState *bs, const char *snapshot_id, + const char *name, Error **errp); + int bdrv_snapshot_list(BlockDriverState *bs, QEMUSnapshotInfo **psn_info); int bdrv_snapshot_load_tmp(BlockDriverState *bs, diff --git a/qemu-img.c b/qemu-img.c index 6068ab0d27..5a74e9b10e 100644 --- a/qemu-img.c +++ b/qemu-img.c @@ -3470,7 +3470,10 @@ static int img_snapshot(int argc, char **argv) sn.date_sec = rt / G_USEC_PER_SEC; sn.date_nsec = (rt % G_USEC_PER_SEC) * 1000; + bdrv_graph_rdlock_main_loop(); ret = bdrv_snapshot_create(bs, &sn); + bdrv_graph_rdunlock_main_loop(); + if (ret) { error_report("Could not create snapshot '%s': %s", snapshot_name, strerror(-ret)); @@ -3486,6 +3489,7 @@ static int img_snapshot(int argc, char **argv) break; case SNAPSHOT_DELETE: + bdrv_graph_rdlock_main_loop(); ret = bdrv_snapshot_find(bs, &sn, snapshot_name); if (ret < 0) { error_report("Could not delete snapshot '%s': snapshot not " @@ -3499,6 +3503,7 @@ static int img_snapshot(int argc, char **argv) ret = 1; } } + bdrv_graph_rdunlock_main_loop(); break; } From ce433d2942b78d38d31bdb7845dbf565c9dc1109 Mon Sep 17 00:00:00 2001 From: Kevin Wolf Date: Fri, 29 Sep 2023 16:51:43 +0200 Subject: [PATCH 0628/1077] block: Take graph rdlock in parts of reopen Reopen isn't easy with respect to locking because many of its functions need to iterate the graph, some change it, and then you get some drains in the middle where you can't hold any locks. Therefore just documents most of the functions to be unlocked, and take locks internally before accessing the graph. Signed-off-by: Kevin Wolf Message-ID: <20230929145157.45443-9-kwolf@redhat.com> Reviewed-by: Stefan Hajnoczi Signed-off-by: Kevin Wolf --- block.c | 57 ++++++++++++++++++++------------ include/block/block_int-common.h | 13 +++++--- 2 files changed, 43 insertions(+), 27 deletions(-) diff --git a/block.c b/block.c index 6cc4115510..084ff14509 100644 --- a/block.c +++ b/block.c @@ -4314,8 +4314,8 @@ static int bdrv_reset_options_allowed(BlockDriverState *bs, /* * Returns true if @child can be reached recursively from @bs */ -static bool bdrv_recurse_has_child(BlockDriverState *bs, - BlockDriverState *child) +static bool GRAPH_RDLOCK +bdrv_recurse_has_child(BlockDriverState *bs, BlockDriverState *child) { BdrvChild *c; @@ -4356,15 +4356,12 @@ static bool bdrv_recurse_has_child(BlockDriverState *bs, * * To be called with bs->aio_context locked. */ -static BlockReopenQueue *bdrv_reopen_queue_child(BlockReopenQueue *bs_queue, - BlockDriverState *bs, - QDict *options, - const BdrvChildClass *klass, - BdrvChildRole role, - bool parent_is_format, - QDict *parent_options, - int parent_flags, - bool keep_old_opts) +static BlockReopenQueue * GRAPH_RDLOCK +bdrv_reopen_queue_child(BlockReopenQueue *bs_queue, BlockDriverState *bs, + QDict *options, const BdrvChildClass *klass, + BdrvChildRole role, bool parent_is_format, + QDict *parent_options, int parent_flags, + bool keep_old_opts) { assert(bs != NULL); @@ -4376,6 +4373,11 @@ static BlockReopenQueue *bdrv_reopen_queue_child(BlockReopenQueue *bs_queue, GLOBAL_STATE_CODE(); + /* + * Strictly speaking, draining is illegal under GRAPH_RDLOCK. We know that + * we've been called with bdrv_graph_rdlock_main_loop(), though, so it's ok + * in practice. + */ bdrv_drained_begin(bs); if (bs_queue == NULL) { @@ -4517,6 +4519,7 @@ BlockReopenQueue *bdrv_reopen_queue(BlockReopenQueue *bs_queue, QDict *options, bool keep_old_opts) { GLOBAL_STATE_CODE(); + GRAPH_RDLOCK_GUARD_MAINLOOP(); return bdrv_reopen_queue_child(bs_queue, bs, options, NULL, 0, false, NULL, 0, keep_old_opts); @@ -4736,9 +4739,10 @@ int bdrv_reopen_set_read_only(BlockDriverState *bs, bool read_only, * Callers must make sure that their AioContext locking is still correct after * this. */ -static int bdrv_reopen_parse_file_or_backing(BDRVReopenState *reopen_state, - bool is_backing, Transaction *tran, - Error **errp) +static int GRAPH_UNLOCKED +bdrv_reopen_parse_file_or_backing(BDRVReopenState *reopen_state, + bool is_backing, Transaction *tran, + Error **errp) { BlockDriverState *bs = reopen_state->bs; BlockDriverState *new_child_bs; @@ -4748,6 +4752,7 @@ static int bdrv_reopen_parse_file_or_backing(BDRVReopenState *reopen_state, QObject *value; const char *str; AioContext *ctx, *old_ctx; + bool has_child; int ret; GLOBAL_STATE_CODE(); @@ -4767,7 +4772,13 @@ static int bdrv_reopen_parse_file_or_backing(BDRVReopenState *reopen_state, new_child_bs = bdrv_lookup_bs(NULL, str, errp); if (new_child_bs == NULL) { return -EINVAL; - } else if (bdrv_recurse_has_child(new_child_bs, bs)) { + } + + bdrv_graph_rdlock_main_loop(); + has_child = bdrv_recurse_has_child(new_child_bs, bs); + bdrv_graph_rdunlock_main_loop(); + + if (has_child) { error_setg(errp, "Making '%s' a %s child of '%s' would create a " "cycle", str, child_name, bs->node_name); return -EINVAL; @@ -4866,9 +4877,9 @@ static int bdrv_reopen_parse_file_or_backing(BDRVReopenState *reopen_state, * After calling this function, the transaction @change_child_tran may only be * completed while holding a writer lock for the graph. */ -static int bdrv_reopen_prepare(BDRVReopenState *reopen_state, - BlockReopenQueue *queue, - Transaction *change_child_tran, Error **errp) +static int GRAPH_UNLOCKED +bdrv_reopen_prepare(BDRVReopenState *reopen_state, BlockReopenQueue *queue, + Transaction *change_child_tran, Error **errp) { int ret = -1; int old_flags; @@ -5010,6 +5021,8 @@ static int bdrv_reopen_prepare(BDRVReopenState *reopen_state, if (qdict_size(reopen_state->options)) { const QDictEntry *entry = qdict_first(reopen_state->options); + GRAPH_RDLOCK_GUARD_MAINLOOP(); + do { QObject *new = entry->value; QObject *old = qdict_get(reopen_state->bs->options, entry->key); @@ -5083,7 +5096,7 @@ error: * makes them final by swapping the staging BlockDriverState contents into * the active BlockDriverState contents. */ -static void bdrv_reopen_commit(BDRVReopenState *reopen_state) +static void GRAPH_UNLOCKED bdrv_reopen_commit(BDRVReopenState *reopen_state) { BlockDriver *drv; BlockDriverState *bs; @@ -5100,6 +5113,8 @@ static void bdrv_reopen_commit(BDRVReopenState *reopen_state) drv->bdrv_reopen_commit(reopen_state); } + GRAPH_RDLOCK_GUARD_MAINLOOP(); + /* set BDS specific flags now */ qobject_unref(bs->explicit_options); qobject_unref(bs->options); @@ -5121,9 +5136,7 @@ static void bdrv_reopen_commit(BDRVReopenState *reopen_state) qdict_del(bs->explicit_options, "backing"); qdict_del(bs->options, "backing"); - bdrv_graph_rdlock_main_loop(); bdrv_refresh_limits(bs, NULL, NULL); - bdrv_graph_rdunlock_main_loop(); bdrv_refresh_total_sectors(bs, bs->total_sectors); } @@ -5131,7 +5144,7 @@ static void bdrv_reopen_commit(BDRVReopenState *reopen_state) * Abort the reopen, and delete and free the staged changes in * reopen_state */ -static void bdrv_reopen_abort(BDRVReopenState *reopen_state) +static void GRAPH_UNLOCKED bdrv_reopen_abort(BDRVReopenState *reopen_state) { BlockDriver *drv; diff --git a/include/block/block_int-common.h b/include/block/block_int-common.h index 29c5b8a3c5..0373cbed49 100644 --- a/include/block/block_int-common.h +++ b/include/block/block_int-common.h @@ -235,11 +235,14 @@ struct BlockDriver { Error **errp); /* For handling image reopen for split or non-split files. */ - int (*bdrv_reopen_prepare)(BDRVReopenState *reopen_state, - BlockReopenQueue *queue, Error **errp); - void (*bdrv_reopen_commit)(BDRVReopenState *reopen_state); - void (*bdrv_reopen_commit_post)(BDRVReopenState *reopen_state); - void (*bdrv_reopen_abort)(BDRVReopenState *reopen_state); + int GRAPH_UNLOCKED_PTR (*bdrv_reopen_prepare)( + BDRVReopenState *reopen_state, BlockReopenQueue *queue, Error **errp); + void GRAPH_UNLOCKED_PTR (*bdrv_reopen_commit)( + BDRVReopenState *reopen_state); + void GRAPH_UNLOCKED_PTR (*bdrv_reopen_commit_post)( + BDRVReopenState *reopen_state); + void GRAPH_UNLOCKED_PTR (*bdrv_reopen_abort)( + BDRVReopenState *reopen_state); void (*bdrv_join_options)(QDict *options, QDict *old_options); int GRAPH_UNLOCKED_PTR (*bdrv_open)( From 15f3f1fe57cd98ef0f45a25681b7a99dc3be0484 Mon Sep 17 00:00:00 2001 From: Kevin Wolf Date: Fri, 29 Sep 2023 16:51:44 +0200 Subject: [PATCH 0629/1077] block: Mark bdrv_get_xdbg_block_graph() and callers GRAPH_RDLOCK This adds GRAPH_RDLOCK annotations to declare that callers of bdrv_get_xdbg_block_graph() need to hold a reader lock for the graph because it accesses the children list of a node. Signed-off-by: Kevin Wolf Message-ID: <20230929145157.45443-10-kwolf@redhat.com> Reviewed-by: Stefan Hajnoczi Signed-off-by: Kevin Wolf --- blockdev.c | 2 ++ include/block/block-global-state.h | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/blockdev.c b/blockdev.c index 43e0c4ddf2..ff5ee9ff7b 100644 --- a/blockdev.c +++ b/blockdev.c @@ -2846,6 +2846,8 @@ BlockDeviceInfoList *qmp_query_named_block_nodes(bool has_flat, XDbgBlockGraph *qmp_x_debug_query_block_graph(Error **errp) { + GRAPH_RDLOCK_GUARD_MAINLOOP(); + return bdrv_get_xdbg_block_graph(errp); } diff --git a/include/block/block-global-state.h b/include/block/block-global-state.h index 505a0d0c11..4d80b3d554 100644 --- a/include/block/block-global-state.h +++ b/include/block/block-global-state.h @@ -192,7 +192,7 @@ int bdrv_has_zero_init_1(BlockDriverState *bs); int bdrv_has_zero_init(BlockDriverState *bs); BlockDriverState *bdrv_find_node(const char *node_name); BlockDeviceInfoList *bdrv_named_nodes_list(bool flat, Error **errp); -XDbgBlockGraph *bdrv_get_xdbg_block_graph(Error **errp); +XDbgBlockGraph * GRAPH_RDLOCK bdrv_get_xdbg_block_graph(Error **errp); BlockDriverState *bdrv_lookup_bs(const char *device, const char *node_name, Error **errp); From b7cfc7d58ec697a681a269036dc8f6444ffd495d Mon Sep 17 00:00:00 2001 From: Kevin Wolf Date: Fri, 29 Sep 2023 16:51:45 +0200 Subject: [PATCH 0630/1077] block: Mark bdrv_refresh_filename() and callers GRAPH_RDLOCK This adds GRAPH_RDLOCK annotations to declare that callers of bdrv_refresh_filename() need to hold a reader lock for the graph because it accesses the children list of a node. Signed-off-by: Kevin Wolf Message-ID: <20230929145157.45443-11-kwolf@redhat.com> Reviewed-by: Stefan Hajnoczi Signed-off-by: Kevin Wolf --- block.c | 23 +++++++++++--- block/nfs.c | 2 +- block/qapi.c | 11 ++++--- block/raw-format.c | 2 ++ block/vhdx.c | 4 +++ block/vhdx.h | 5 +-- block/vmdk.c | 51 +++++++++++++++++++----------- blockdev.c | 13 ++++++++ include/block/block-global-state.h | 9 ++++-- include/block/block_int-common.h | 8 ++--- include/block/qapi.h | 16 ++++------ qemu-img.c | 4 +++ 12 files changed, 101 insertions(+), 47 deletions(-) diff --git a/block.c b/block.c index 084ff14509..142e1d5e2b 100644 --- a/block.c +++ b/block.c @@ -371,8 +371,9 @@ char *bdrv_get_full_backing_filename_from_filename(const char *backed, * setting @errp. In all other cases, NULL will only be returned with * @errp set. */ -static char *bdrv_make_absolute_filename(BlockDriverState *relative_to, - const char *filename, Error **errp) +static char * GRAPH_RDLOCK +bdrv_make_absolute_filename(BlockDriverState *relative_to, + const char *filename, Error **errp) { char *dir, *full_name; @@ -1250,7 +1251,7 @@ static void bdrv_temp_snapshot_options(int *child_flags, QDict *child_options, *child_flags &= ~BDRV_O_NATIVE_AIO; } -static void bdrv_backing_attach(BdrvChild *c) +static void GRAPH_WRLOCK bdrv_backing_attach(BdrvChild *c) { BlockDriverState *parent = c->opaque; BlockDriverState *backing_hd = c->bs; @@ -1874,7 +1875,10 @@ static int bdrv_open_common(BlockDriverState *bs, BlockBackend *file, } if (file != NULL) { + bdrv_graph_rdlock_main_loop(); bdrv_refresh_filename(blk_bs(file)); + bdrv_graph_rdunlock_main_loop(); + filename = blk_bs(file)->filename; } else { /* @@ -3644,7 +3648,10 @@ int bdrv_open_backing_file(BlockDriverState *bs, QDict *parent_options, implicit_backing = !strcmp(bs->auto_backing_file, bs->backing_file); } + bdrv_graph_rdlock_main_loop(); backing_filename = bdrv_get_full_backing_filename(bs, &local_err); + bdrv_graph_rdunlock_main_loop(); + if (local_err) { ret = -EINVAL; error_propagate(errp, local_err); @@ -3675,7 +3682,9 @@ int bdrv_open_backing_file(BlockDriverState *bs, QDict *parent_options, } if (implicit_backing) { + bdrv_graph_rdlock_main_loop(); bdrv_refresh_filename(backing_hd); + bdrv_graph_rdunlock_main_loop(); pstrcpy(bs->auto_backing_file, sizeof(bs->auto_backing_file), backing_hd->filename); } @@ -4964,7 +4973,9 @@ bdrv_reopen_prepare(BDRVReopenState *reopen_state, BlockReopenQueue *queue, if (local_err != NULL) { error_propagate(errp, local_err); } else { + bdrv_graph_rdlock_main_loop(); bdrv_refresh_filename(reopen_state->bs); + bdrv_graph_rdunlock_main_loop(); error_setg(errp, "failed while preparing to reopen image '%s'", reopen_state->bs->filename); } @@ -5931,6 +5942,7 @@ int bdrv_drop_intermediate(BlockDriverState *top, BlockDriverState *base, bdrv_ref(top); bdrv_drained_begin(base); + bdrv_graph_rdlock_main_loop(); if (!top->drv || !base->drv) { goto exit; @@ -5955,11 +5967,9 @@ int bdrv_drop_intermediate(BlockDriverState *top, BlockDriverState *base, backing_file_str = base->filename; } - bdrv_graph_rdlock_main_loop(); QLIST_FOREACH(c, &top->parents, next_parent) { updated_children = g_slist_prepend(updated_children, c); } - bdrv_graph_rdunlock_main_loop(); /* * It seems correct to pass detach_subchain=true here, but it triggers @@ -6005,6 +6015,7 @@ int bdrv_drop_intermediate(BlockDriverState *top, BlockDriverState *base, ret = 0; exit: + bdrv_graph_rdunlock_main_loop(); bdrv_drained_end(base); bdrv_unref(top); return ret; @@ -6295,6 +6306,7 @@ BlockDeviceInfoList *bdrv_named_nodes_list(bool flat, BlockDriverState *bs; GLOBAL_STATE_CODE(); + GRAPH_RDLOCK_GUARD_MAINLOOP(); list = NULL; QTAILQ_FOREACH(bs, &graph_bdrv_states, node_list) { @@ -6763,6 +6775,7 @@ BlockDriverState *bdrv_find_backing_image(BlockDriverState *bs, BlockDriverState *bs_below; GLOBAL_STATE_CODE(); + GRAPH_RDLOCK_GUARD_MAINLOOP(); if (!bs || !bs->drv || !backing_file) { return NULL; diff --git a/block/nfs.c b/block/nfs.c index c24df49747..f737e19cd3 100644 --- a/block/nfs.c +++ b/block/nfs.c @@ -843,7 +843,7 @@ static void nfs_refresh_filename(BlockDriverState *bs) } } -static char *nfs_dirname(BlockDriverState *bs, Error **errp) +static char * GRAPH_RDLOCK nfs_dirname(BlockDriverState *bs, Error **errp) { NFSClient *client = bs->opaque; diff --git a/block/qapi.c b/block/qapi.c index 1cbb0935ff..82a30b38fe 100644 --- a/block/qapi.c +++ b/block/qapi.c @@ -225,9 +225,8 @@ int bdrv_query_snapshot_info_list(BlockDriverState *bs, * Helper function for other query info functions. Store information about @bs * in @info, setting @errp on error. */ -static void bdrv_do_query_node_info(BlockDriverState *bs, - BlockNodeInfo *info, - Error **errp) +static void GRAPH_RDLOCK +bdrv_do_query_node_info(BlockDriverState *bs, BlockNodeInfo *info, Error **errp) { int64_t size; const char *backing_filename; @@ -423,8 +422,8 @@ fail: } /* @p_info will be set only on success. */ -static void bdrv_query_info(BlockBackend *blk, BlockInfo **p_info, - Error **errp) +static void GRAPH_RDLOCK +bdrv_query_info(BlockBackend *blk, BlockInfo **p_info, Error **errp) { BlockInfo *info = g_malloc0(sizeof(*info)); BlockDriverState *bs = blk_bs(blk); @@ -672,6 +671,8 @@ BlockInfoList *qmp_query_block(Error **errp) BlockBackend *blk; Error *local_err = NULL; + GRAPH_RDLOCK_GUARD_MAINLOOP(); + for (blk = blk_all_next(NULL); blk; blk = blk_all_next(blk)) { BlockInfoList *info; diff --git a/block/raw-format.c b/block/raw-format.c index a8bdee5279..8ff03adfa4 100644 --- a/block/raw-format.c +++ b/block/raw-format.c @@ -505,7 +505,9 @@ static int raw_open(BlockDriverState *bs, QDict *options, int flags, BDRV_REQ_ZERO_WRITE; if (bs->probed && !bdrv_is_read_only(bs)) { + bdrv_graph_rdlock_main_loop(); bdrv_refresh_filename(bs->file->bs); + bdrv_graph_rdunlock_main_loop(); fprintf(stderr, "WARNING: Image format was not specified for '%s' and probing " "guessed raw.\n" diff --git a/block/vhdx.c b/block/vhdx.c index a67edcc03e..73cb214fb4 100644 --- a/block/vhdx.c +++ b/block/vhdx.c @@ -1001,11 +1001,15 @@ static int vhdx_open(BlockDriverState *bs, QDict *options, int flags, uint64_t signature; Error *local_err = NULL; + GLOBAL_STATE_CODE(); + ret = bdrv_open_file_child(NULL, options, "file", bs, errp); if (ret < 0) { return ret; } + GRAPH_RDLOCK_GUARD_MAINLOOP(); + s->bat = NULL; s->first_visible_write = true; diff --git a/block/vhdx.h b/block/vhdx.h index 455a627a46..85594a5380 100644 --- a/block/vhdx.h +++ b/block/vhdx.h @@ -410,8 +410,9 @@ uint32_t vhdx_checksum_calc(uint32_t crc, uint8_t *buf, size_t size, bool vhdx_checksum_is_valid(uint8_t *buf, size_t size, int crc_offset); -int vhdx_parse_log(BlockDriverState *bs, BDRVVHDXState *s, bool *flushed, - Error **errp); +int GRAPH_RDLOCK +vhdx_parse_log(BlockDriverState *bs, BDRVVHDXState *s, bool *flushed, + Error **errp); int coroutine_fn GRAPH_RDLOCK vhdx_log_write_and_flush(BlockDriverState *bs, BDRVVHDXState *s, diff --git a/block/vmdk.c b/block/vmdk.c index e90649c8bf..e50965bc37 100644 --- a/block/vmdk.c +++ b/block/vmdk.c @@ -578,8 +578,8 @@ static int vmdk_add_extent(BlockDriverState *bs, return 0; } -static int vmdk_init_tables(BlockDriverState *bs, VmdkExtent *extent, - Error **errp) +static int GRAPH_RDLOCK +vmdk_init_tables(BlockDriverState *bs, VmdkExtent *extent, Error **errp) { int ret; size_t l1_size; @@ -641,9 +641,9 @@ static int vmdk_init_tables(BlockDriverState *bs, VmdkExtent *extent, return ret; } -static int vmdk_open_vmfs_sparse(BlockDriverState *bs, - BdrvChild *file, - int flags, Error **errp) +static int GRAPH_RDLOCK +vmdk_open_vmfs_sparse(BlockDriverState *bs, BdrvChild *file, int flags, + Error **errp) { int ret; uint32_t magic; @@ -797,9 +797,9 @@ static int check_se_sparse_volatile_header(VMDKSESparseVolatileHeader *header, return 0; } -static int vmdk_open_se_sparse(BlockDriverState *bs, - BdrvChild *file, - int flags, Error **errp) +static int GRAPH_RDLOCK +vmdk_open_se_sparse(BlockDriverState *bs, BdrvChild *file, int flags, + Error **errp) { int ret; VMDKSESparseConstHeader const_header; @@ -913,9 +913,9 @@ static char *vmdk_read_desc(BdrvChild *file, uint64_t desc_offset, Error **errp) return buf; } -static int vmdk_open_vmdk4(BlockDriverState *bs, - BdrvChild *file, - int flags, QDict *options, Error **errp) +static int GRAPH_RDLOCK +vmdk_open_vmdk4(BlockDriverState *bs, BdrvChild *file, int flags, + QDict *options, Error **errp) { int ret; uint32_t magic; @@ -1095,8 +1095,9 @@ static int vmdk_parse_description(const char *desc, const char *opt_name, } /* Open an extent file and append to bs array */ -static int vmdk_open_sparse(BlockDriverState *bs, BdrvChild *file, int flags, - char *buf, QDict *options, Error **errp) +static int GRAPH_RDLOCK +vmdk_open_sparse(BlockDriverState *bs, BdrvChild *file, int flags, + char *buf, QDict *options, Error **errp) { uint32_t magic; @@ -1123,8 +1124,9 @@ static const char *next_line(const char *s) return s; } -static int vmdk_parse_extents(const char *desc, BlockDriverState *bs, - QDict *options, Error **errp) +static int GRAPH_RDLOCK +vmdk_parse_extents(const char *desc, BlockDriverState *bs, QDict *options, + Error **errp) { int ret; int matches; @@ -1143,6 +1145,8 @@ static int vmdk_parse_extents(const char *desc, BlockDriverState *bs, char extent_opt_prefix[32]; Error *local_err = NULL; + GLOBAL_STATE_CODE(); + for (p = desc; *p; p = next_line(p)) { /* parse extent line in one of below formats: * @@ -1223,9 +1227,11 @@ static int vmdk_parse_extents(const char *desc, BlockDriverState *bs, ret = vmdk_add_extent(bs, extent_file, true, sectors, 0, 0, 0, 0, 0, &extent, errp); if (ret < 0) { + bdrv_graph_rdunlock_main_loop(); bdrv_graph_wrlock(NULL); bdrv_unref_child(bs, extent_file); bdrv_graph_wrunlock(); + bdrv_graph_rdlock_main_loop(); goto out; } extent->flat_start_offset = flat_offset << 9; @@ -1240,26 +1246,32 @@ static int vmdk_parse_extents(const char *desc, BlockDriverState *bs, } g_free(buf); if (ret) { + bdrv_graph_rdunlock_main_loop(); bdrv_graph_wrlock(NULL); bdrv_unref_child(bs, extent_file); bdrv_graph_wrunlock(); + bdrv_graph_rdlock_main_loop(); goto out; } extent = &s->extents[s->num_extents - 1]; } else if (!strcmp(type, "SESPARSE")) { ret = vmdk_open_se_sparse(bs, extent_file, bs->open_flags, errp); if (ret) { + bdrv_graph_rdunlock_main_loop(); bdrv_graph_wrlock(NULL); bdrv_unref_child(bs, extent_file); bdrv_graph_wrunlock(); + bdrv_graph_rdlock_main_loop(); goto out; } extent = &s->extents[s->num_extents - 1]; } else { error_setg(errp, "Unsupported extent type '%s'", type); + bdrv_graph_rdunlock_main_loop(); bdrv_graph_wrlock(NULL); bdrv_unref_child(bs, extent_file); bdrv_graph_wrunlock(); + bdrv_graph_rdlock_main_loop(); ret = -ENOTSUP; goto out; } @@ -1283,8 +1295,9 @@ out: return ret; } -static int vmdk_open_desc_file(BlockDriverState *bs, int flags, char *buf, - QDict *options, Error **errp) +static int GRAPH_RDLOCK +vmdk_open_desc_file(BlockDriverState *bs, int flags, char *buf, QDict *options, + Error **errp) { int ret; char ct[128]; @@ -2900,7 +2913,7 @@ static int vmdk_has_zero_init(BlockDriverState *bs) return 1; } -static VmdkExtentInfo *vmdk_get_extent_info(VmdkExtent *extent) +static VmdkExtentInfo * GRAPH_RDLOCK vmdk_get_extent_info(VmdkExtent *extent) { VmdkExtentInfo *info = g_new0(VmdkExtentInfo, 1); @@ -2985,6 +2998,8 @@ static ImageInfoSpecific *vmdk_get_specific_info(BlockDriverState *bs, ImageInfoSpecific *spec_info = g_new0(ImageInfoSpecific, 1); VmdkExtentInfoList **tail; + assume_graph_lock(); /* FIXME */ + *spec_info = (ImageInfoSpecific){ .type = IMAGE_INFO_SPECIFIC_KIND_VMDK, .u = { diff --git a/blockdev.c b/blockdev.c index ff5ee9ff7b..51c58dd432 100644 --- a/blockdev.c +++ b/blockdev.c @@ -1665,6 +1665,8 @@ static void drive_backup_action(DriveBackup *backup, bool set_backing_hd = false; int ret; + GLOBAL_STATE_CODE(); + tran_add(tran, &drive_backup_drv, state); if (!backup->has_mode) { @@ -1735,7 +1737,10 @@ static void drive_backup_action(DriveBackup *backup, BlockDriverState *explicit_backing = bdrv_skip_implicit_filters(source); + bdrv_graph_rdlock_main_loop(); bdrv_refresh_filename(explicit_backing); + bdrv_graph_rdunlock_main_loop(); + bdrv_img_create(backup->target, format, explicit_backing->filename, explicit_backing->drv->format_name, NULL, @@ -2398,6 +2403,8 @@ void qmp_block_stream(const char *job_id, const char *device, Error *local_err = NULL; int job_flags = JOB_DEFAULT; + GLOBAL_STATE_CODE(); + if (base && base_node) { error_setg(errp, "'base' and 'base-node' cannot be specified " "at the same time"); @@ -2448,7 +2455,10 @@ void qmp_block_stream(const char *job_id, const char *device, goto out; } assert(bdrv_get_aio_context(base_bs) == aio_context); + + bdrv_graph_rdlock_main_loop(); bdrv_refresh_filename(base_bs); + bdrv_graph_rdunlock_main_loop(); } if (bottom) { @@ -3076,7 +3086,10 @@ void qmp_drive_mirror(DriveMirror *arg, Error **errp) break; case NEW_IMAGE_MODE_ABSOLUTE_PATHS: /* create new image with backing file */ + bdrv_graph_rdlock_main_loop(); bdrv_refresh_filename(explicit_backing); + bdrv_graph_rdunlock_main_loop(); + bdrv_img_create(arg->target, format, explicit_backing->filename, explicit_backing->drv->format_name, diff --git a/include/block/block-global-state.h b/include/block/block-global-state.h index 4d80b3d554..ec623ef3c9 100644 --- a/include/block/block-global-state.h +++ b/include/block/block-global-state.h @@ -132,7 +132,7 @@ int bdrv_reopen_set_read_only(BlockDriverState *bs, bool read_only, Error **errp); BlockDriverState *bdrv_find_backing_image(BlockDriverState *bs, const char *backing_file); -void bdrv_refresh_filename(BlockDriverState *bs); +void GRAPH_RDLOCK bdrv_refresh_filename(BlockDriverState *bs); void GRAPH_RDLOCK bdrv_refresh_limits(BlockDriverState *bs, Transaction *tran, Error **errp); @@ -216,8 +216,11 @@ void bdrv_next_cleanup(BdrvNextIterator *it); BlockDriverState *bdrv_next_monitor_owned(BlockDriverState *bs); void bdrv_iterate_format(void (*it)(void *opaque, const char *name), void *opaque, bool read_only); -char *bdrv_get_full_backing_filename(BlockDriverState *bs, Error **errp); -char *bdrv_dirname(BlockDriverState *bs, Error **errp); + +char * GRAPH_RDLOCK +bdrv_get_full_backing_filename(BlockDriverState *bs, Error **errp); + +char * GRAPH_RDLOCK bdrv_dirname(BlockDriverState *bs, Error **errp); void bdrv_img_create(const char *filename, const char *fmt, const char *base_filename, const char *base_fmt, diff --git a/include/block/block_int-common.h b/include/block/block_int-common.h index 0373cbed49..be80887898 100644 --- a/include/block/block_int-common.h +++ b/include/block/block_int-common.h @@ -272,7 +272,7 @@ struct BlockDriver { * Refreshes the bs->exact_filename field. If that is impossible, * bs->exact_filename has to be left empty. */ - void (*bdrv_refresh_filename)(BlockDriverState *bs); + void GRAPH_RDLOCK_PTR (*bdrv_refresh_filename)(BlockDriverState *bs); /* * Gathers the open options for all children into @target. @@ -295,15 +295,15 @@ struct BlockDriver { * block driver which implements it is probably doing something * shady regarding its runtime option structure. */ - void (*bdrv_gather_child_options)(BlockDriverState *bs, QDict *target, - bool backing_overridden); + void GRAPH_RDLOCK_PTR (*bdrv_gather_child_options)( + BlockDriverState *bs, QDict *target, bool backing_overridden); /* * Returns an allocated string which is the directory name of this BDS: It * will be used to make relative filenames absolute by prepending this * function's return value to them. */ - char *(*bdrv_dirname)(BlockDriverState *bs, Error **errp); + char * GRAPH_RDLOCK_PTR (*bdrv_dirname)(BlockDriverState *bs, Error **errp); /* * This informs the driver that we are no longer interested in the result diff --git a/include/block/qapi.h b/include/block/qapi.h index 8663971c58..887235653a 100644 --- a/include/block/qapi.h +++ b/include/block/qapi.h @@ -29,18 +29,16 @@ #include "block/snapshot.h" #include "qapi/qapi-types-block-core.h" -BlockDeviceInfo *bdrv_block_device_info(BlockBackend *blk, - BlockDriverState *bs, - bool flat, - Error **errp); +BlockDeviceInfo * GRAPH_RDLOCK +bdrv_block_device_info(BlockBackend *blk, BlockDriverState *bs, + bool flat, Error **errp); + int bdrv_query_snapshot_info_list(BlockDriverState *bs, SnapshotInfoList **p_list, Error **errp); -void bdrv_query_image_info(BlockDriverState *bs, - ImageInfo **p_info, - bool flat, - bool skip_implicit_filters, - Error **errp); +void GRAPH_RDLOCK +bdrv_query_image_info(BlockDriverState *bs, ImageInfo **p_info, bool flat, + bool skip_implicit_filters, Error **errp); void GRAPH_RDLOCK bdrv_query_block_graph_info(BlockDriverState *bs, BlockGraphInfo **p_info, Error **errp); diff --git a/qemu-img.c b/qemu-img.c index 5a74e9b10e..3ecbc375b0 100644 --- a/qemu-img.c +++ b/qemu-img.c @@ -3165,7 +3165,9 @@ static int get_block_status(BlockDriverState *bs, int64_t offset, has_offset = !!(ret & BDRV_BLOCK_OFFSET_VALID); if (file && has_offset) { + bdrv_graph_rdlock_main_loop(); bdrv_refresh_filename(file); + bdrv_graph_rdunlock_main_loop(); filename = file->filename; } @@ -3688,7 +3690,9 @@ static int img_rebase(int argc, char **argv) qdict_put_bool(options, BDRV_OPT_FORCE_SHARE, true); } + bdrv_graph_rdlock_main_loop(); bdrv_refresh_filename(bs); + bdrv_graph_rdunlock_main_loop(); overlay_filename = bs->exact_filename[0] ? bs->exact_filename : bs->filename; out_real_path = From c0fc5123ad33158f6f289a896b568b9adce7d1f2 Mon Sep 17 00:00:00 2001 From: Kevin Wolf Date: Fri, 29 Sep 2023 16:51:46 +0200 Subject: [PATCH 0631/1077] block: Mark bdrv_primary_child() and callers GRAPH_RDLOCK This adds GRAPH_RDLOCK annotations to declare that callers of bdrv_primary_child() need to hold a reader lock for the graph because it accesses the children list of a node. Signed-off-by: Kevin Wolf Message-ID: <20230929145157.45443-12-kwolf@redhat.com> Reviewed-by: Stefan Hajnoczi Signed-off-by: Kevin Wolf --- block.c | 11 ++++++++++- block/snapshot.c | 3 +++ include/block/block_int-io.h | 5 +++-- 3 files changed, 16 insertions(+), 3 deletions(-) diff --git a/block.c b/block.c index 142e1d5e2b..6ce3e2ad7a 100644 --- a/block.c +++ b/block.c @@ -6692,7 +6692,8 @@ void coroutine_fn bdrv_co_debug_event(BlockDriverState *bs, BlkdebugEvent event) bs->drv->bdrv_co_debug_event(bs, event); } -static BlockDriverState *bdrv_find_debug_node(BlockDriverState *bs) +static BlockDriverState * GRAPH_RDLOCK +bdrv_find_debug_node(BlockDriverState *bs) { GLOBAL_STATE_CODE(); while (bs && bs->drv && !bs->drv->bdrv_debug_breakpoint) { @@ -6711,6 +6712,8 @@ int bdrv_debug_breakpoint(BlockDriverState *bs, const char *event, const char *tag) { GLOBAL_STATE_CODE(); + GRAPH_RDLOCK_GUARD_MAINLOOP(); + bs = bdrv_find_debug_node(bs); if (bs) { return bs->drv->bdrv_debug_breakpoint(bs, event, tag); @@ -6722,6 +6725,8 @@ int bdrv_debug_breakpoint(BlockDriverState *bs, const char *event, int bdrv_debug_remove_breakpoint(BlockDriverState *bs, const char *tag) { GLOBAL_STATE_CODE(); + GRAPH_RDLOCK_GUARD_MAINLOOP(); + bs = bdrv_find_debug_node(bs); if (bs) { return bs->drv->bdrv_debug_remove_breakpoint(bs, tag); @@ -6733,6 +6738,8 @@ int bdrv_debug_remove_breakpoint(BlockDriverState *bs, const char *tag) int bdrv_debug_resume(BlockDriverState *bs, const char *tag) { GLOBAL_STATE_CODE(); + GRAPH_RDLOCK_GUARD_MAINLOOP(); + while (bs && (!bs->drv || !bs->drv->bdrv_debug_resume)) { bs = bdrv_primary_bs(bs); } @@ -6747,6 +6754,8 @@ int bdrv_debug_resume(BlockDriverState *bs, const char *tag) bool bdrv_debug_is_suspended(BlockDriverState *bs, const char *tag) { GLOBAL_STATE_CODE(); + GRAPH_RDLOCK_GUARD_MAINLOOP(); + while (bs && bs->drv && !bs->drv->bdrv_debug_is_suspended) { bs = bdrv_primary_bs(bs); } diff --git a/block/snapshot.c b/block/snapshot.c index 554065578b..ad2bf6e068 100644 --- a/block/snapshot.c +++ b/block/snapshot.c @@ -311,7 +311,10 @@ int bdrv_snapshot_goto(BlockDriverState *bs, * respective option (with the qdict_put_str() call above). * Assert that .bdrv_open() has attached the right BDS as primary child. */ + bdrv_graph_rdlock_main_loop(); assert(bdrv_primary_bs(bs) == fallback_bs); + bdrv_graph_rdunlock_main_loop(); + bdrv_unref(fallback_bs); return ret; } diff --git a/include/block/block_int-io.h b/include/block/block_int-io.h index eb0da7232e..2b6004ab93 100644 --- a/include/block/block_int-io.h +++ b/include/block/block_int-io.h @@ -133,7 +133,7 @@ bdrv_refresh_total_sectors(BlockDriverState *bs, int64_t hint); BdrvChild *bdrv_cow_child(BlockDriverState *bs); BdrvChild *bdrv_filter_child(BlockDriverState *bs); BdrvChild *bdrv_filter_or_cow_child(BlockDriverState *bs); -BdrvChild *bdrv_primary_child(BlockDriverState *bs); +BdrvChild * GRAPH_RDLOCK bdrv_primary_child(BlockDriverState *bs); BlockDriverState *bdrv_skip_filters(BlockDriverState *bs); BlockDriverState *bdrv_backing_chain_next(BlockDriverState *bs); @@ -155,7 +155,8 @@ static inline BlockDriverState *bdrv_filter_or_cow_bs(BlockDriverState *bs) return child_bs(bdrv_filter_or_cow_child(bs)); } -static inline BlockDriverState *bdrv_primary_bs(BlockDriverState *bs) +static inline BlockDriverState * GRAPH_RDLOCK +bdrv_primary_bs(BlockDriverState *bs) { IO_CODE(); return child_bs(bdrv_primary_child(bs)); From 4026f1c4f320aa072fa4cd299545cbc97315e246 Mon Sep 17 00:00:00 2001 From: Kevin Wolf Date: Fri, 29 Sep 2023 16:51:47 +0200 Subject: [PATCH 0632/1077] block: Mark bdrv_get_parent_name() and callers GRAPH_RDLOCK This adds GRAPH_RDLOCK annotations to declare that callers of bdrv_get_parent_name() need to hold a reader lock for the graph because it accesses the parents list of a node. For some places, we know that they will hold the lock, but we don't have the GRAPH_RDLOCK annotations yet. In this case, add assume_graph_lock() with a FIXME comment. These places will be removed once everything is properly annotated. Signed-off-by: Kevin Wolf Message-ID: <20230929145157.45443-13-kwolf@redhat.com> Reviewed-by: Stefan Hajnoczi Signed-off-by: Kevin Wolf --- block.c | 14 ++++++++++++-- block/backup.c | 1 + block/parallels.c | 3 +++ block/qcow.c | 3 +++ block/qcow2-bitmap.c | 2 ++ block/qcow2.c | 4 ++++ block/qcow2.h | 7 +++---- block/quorum.c | 4 ++-- block/rbd.c | 2 ++ block/snapshot.c | 3 +++ block/vdi.c | 3 +++ block/vpc.c | 3 +++ block/vvfat.c | 2 ++ blockjob.c | 1 + include/block/block-io.h | 8 ++++++-- include/block/block_int-io.h | 2 +- include/block/qapi.h | 7 ++++--- 17 files changed, 55 insertions(+), 14 deletions(-) diff --git a/block.c b/block.c index 6ce3e2ad7a..c932dc0a51 100644 --- a/block.c +++ b/block.c @@ -279,8 +279,9 @@ bool bdrv_is_read_only(BlockDriverState *bs) return !(bs->open_flags & BDRV_O_RDWR); } -static int bdrv_can_set_read_only(BlockDriverState *bs, bool read_only, - bool ignore_allow_rdw, Error **errp) +static int GRAPH_RDLOCK +bdrv_can_set_read_only(BlockDriverState *bs, bool read_only, + bool ignore_allow_rdw, Error **errp) { IO_CODE(); @@ -319,6 +320,8 @@ int bdrv_apply_auto_read_only(BlockDriverState *bs, const char *errmsg, int ret = 0; IO_CODE(); + assume_graph_lock(); /* FIXME */ + if (!(bs->open_flags & BDRV_O_RDWR)) { return 0; } @@ -4950,7 +4953,10 @@ bdrv_reopen_prepare(BDRVReopenState *reopen_state, BlockReopenQueue *queue, * to r/w. Attempting to set to r/w may fail if either BDRV_O_ALLOW_RDWR is * not set, or if the BDS still has copy_on_read enabled */ read_only = !(reopen_state->flags & BDRV_O_RDWR); + + bdrv_graph_rdlock_main_loop(); ret = bdrv_can_set_read_only(reopen_state->bs, read_only, true, &local_err); + bdrv_graph_rdunlock_main_loop(); if (local_err) { error_propagate(errp, local_err); goto error; @@ -4984,9 +4990,11 @@ bdrv_reopen_prepare(BDRVReopenState *reopen_state, BlockReopenQueue *queue, } else { /* It is currently mandatory to have a bdrv_reopen_prepare() * handler for each supported drv. */ + bdrv_graph_rdlock_main_loop(); error_setg(errp, "Block format '%s' used by node '%s' " "does not support reopening files", drv->format_name, bdrv_get_device_or_node_name(reopen_state->bs)); + bdrv_graph_rdunlock_main_loop(); ret = -1; goto error; } @@ -7242,6 +7250,8 @@ bool bdrv_op_is_blocked(BlockDriverState *bs, BlockOpType op, Error **errp) { BdrvOpBlocker *blocker; GLOBAL_STATE_CODE(); + GRAPH_RDLOCK_GUARD_MAINLOOP(); + assert((int) op >= 0 && op < BLOCK_OP_TYPE_MAX); if (!QLIST_EMPTY(&bs->op_blockers[op])) { blocker = QLIST_FIRST(&bs->op_blockers[op]); diff --git a/block/backup.c b/block/backup.c index db3791f4d1..9a3c4bdc82 100644 --- a/block/backup.c +++ b/block/backup.c @@ -374,6 +374,7 @@ BlockJob *backup_job_create(const char *job_id, BlockDriverState *bs, assert(bs); assert(target); GLOBAL_STATE_CODE(); + GRAPH_RDLOCK_GUARD_MAINLOOP(); /* QMP interface protects us from these cases */ assert(sync_mode != MIRROR_SYNC_MODE_INCREMENTAL); diff --git a/block/parallels.c b/block/parallels.c index d026ce9e2f..6b46623241 100644 --- a/block/parallels.c +++ b/block/parallels.c @@ -1363,9 +1363,12 @@ static int parallels_open(BlockDriverState *bs, QDict *options, int flags, bitmap_new(DIV_ROUND_UP(s->header_size, s->bat_dirty_block)); /* Disable migration until bdrv_activate method is added */ + bdrv_graph_rdlock_main_loop(); error_setg(&s->migration_blocker, "The Parallels format used by node '%s' " "does not support live migration", bdrv_get_device_or_node_name(bs)); + bdrv_graph_rdunlock_main_loop(); + ret = migrate_add_blocker(s->migration_blocker, errp); if (ret < 0) { error_setg(errp, "Migration blocker error"); diff --git a/block/qcow.c b/block/qcow.c index d56d24ab6d..38a16253b8 100644 --- a/block/qcow.c +++ b/block/qcow.c @@ -301,9 +301,12 @@ static int qcow_open(BlockDriverState *bs, QDict *options, int flags, } /* Disable migration when qcow images are used */ + bdrv_graph_rdlock_main_loop(); error_setg(&s->migration_blocker, "The qcow format used by node '%s' " "does not support live migration", bdrv_get_device_or_node_name(bs)); + bdrv_graph_rdunlock_main_loop(); + ret = migrate_add_blocker(s->migration_blocker, errp); if (ret < 0) { error_free(s->migration_blocker); diff --git a/block/qcow2-bitmap.c b/block/qcow2-bitmap.c index ffd5cd3b23..03dd91dfac 100644 --- a/block/qcow2-bitmap.c +++ b/block/qcow2-bitmap.c @@ -166,6 +166,8 @@ static int check_constraints_on_bitmap(BlockDriverState *bs, int64_t len = bdrv_getlength(bs); int64_t bitmap_bytes; + assume_graph_lock(); /* FIXME */ + assert(granularity > 0); assert((granularity & (granularity - 1)) == 0); diff --git a/block/qcow2.c b/block/qcow2.c index 6e9c731bac..4780cb9148 100644 --- a/block/qcow2.c +++ b/block/qcow2.c @@ -2737,6 +2737,8 @@ static int qcow2_inactivate(BlockDriverState *bs) int ret, result = 0; Error *local_err = NULL; + assume_graph_lock(); /* FIXME */ + qcow2_store_persistent_dirty_bitmaps(bs, true, &local_err); if (local_err != NULL) { result = -EINVAL; @@ -5945,6 +5947,8 @@ void qcow2_signal_corruption(BlockDriverState *bs, bool fatal, int64_t offset, char *message; va_list ap; + assume_graph_lock(); /* FIXME */ + fatal = fatal && bdrv_is_writable(bs); if (s->signaled_corruption && diff --git a/block/qcow2.h b/block/qcow2.h index f789ce3ae0..359bfca4aa 100644 --- a/block/qcow2.h +++ b/block/qcow2.h @@ -1003,10 +1003,9 @@ int coroutine_fn qcow2_truncate_bitmaps_check(BlockDriverState *bs, Error **errp bool qcow2_store_persistent_dirty_bitmaps(BlockDriverState *bs, bool release_stored, Error **errp); int qcow2_reopen_bitmaps_ro(BlockDriverState *bs, Error **errp); -bool coroutine_fn qcow2_co_can_store_new_dirty_bitmap(BlockDriverState *bs, - const char *name, - uint32_t granularity, - Error **errp); +bool coroutine_fn GRAPH_RDLOCK +qcow2_co_can_store_new_dirty_bitmap(BlockDriverState *bs, const char *name, + uint32_t granularity, Error **errp); int coroutine_fn qcow2_co_remove_persistent_dirty_bitmap(BlockDriverState *bs, const char *name, Error **errp); diff --git a/block/quorum.c b/block/quorum.c index 05220cab7f..d3ffc2ee33 100644 --- a/block/quorum.c +++ b/block/quorum.c @@ -206,7 +206,7 @@ static void quorum_report_bad(QuorumOpType type, uint64_t offset, end_sector - start_sector); } -static void quorum_report_failure(QuorumAIOCB *acb) +static void GRAPH_RDLOCK quorum_report_failure(QuorumAIOCB *acb) { const char *reference = bdrv_get_device_or_node_name(acb->bs); int64_t start_sector = acb->offset / BDRV_SECTOR_SIZE; @@ -219,7 +219,7 @@ static void quorum_report_failure(QuorumAIOCB *acb) static int quorum_vote_error(QuorumAIOCB *acb); -static bool quorum_has_too_much_io_failed(QuorumAIOCB *acb) +static bool GRAPH_RDLOCK quorum_has_too_much_io_failed(QuorumAIOCB *acb) { BDRVQuorumState *s = acb->bs->opaque; diff --git a/block/rbd.c b/block/rbd.c index 472ca05cba..073bc92e39 100644 --- a/block/rbd.c +++ b/block/rbd.c @@ -1208,6 +1208,8 @@ static int qemu_rbd_reopen_prepare(BDRVReopenState *state, BDRVRBDState *s = state->bs->opaque; int ret = 0; + GRAPH_RDLOCK_GUARD_MAINLOOP(); + if (s->snap && state->flags & BDRV_O_RDWR) { error_setg(errp, "Cannot change node '%s' to r/w when using RBD snapshot", diff --git a/block/snapshot.c b/block/snapshot.c index ad2bf6e068..6e16eb803a 100644 --- a/block/snapshot.c +++ b/block/snapshot.c @@ -432,6 +432,7 @@ int bdrv_snapshot_load_tmp(BlockDriverState *bs, BlockDriver *drv = bs->drv; GLOBAL_STATE_CODE(); + GRAPH_RDLOCK_GUARD_MAINLOOP(); if (!drv) { error_setg(errp, QERR_DEVICE_HAS_NO_MEDIUM, bdrv_get_device_name(bs)); @@ -641,8 +642,10 @@ int bdrv_all_goto_snapshot(const char *name, } aio_context_release(ctx); if (ret < 0) { + bdrv_graph_rdlock_main_loop(); error_prepend(errp, "Could not load snapshot '%s' on '%s': ", name, bdrv_get_device_or_node_name(bs)); + bdrv_graph_rdunlock_main_loop(); return -1; } diff --git a/block/vdi.c b/block/vdi.c index 934e1b849b..3ed43b6f35 100644 --- a/block/vdi.c +++ b/block/vdi.c @@ -492,9 +492,12 @@ static int vdi_open(BlockDriverState *bs, QDict *options, int flags, } /* Disable migration when vdi images are used */ + bdrv_graph_rdlock_main_loop(); error_setg(&s->migration_blocker, "The vdi format used by node '%s' " "does not support live migration", bdrv_get_device_or_node_name(bs)); + bdrv_graph_rdunlock_main_loop(); + ret = migrate_add_blocker(s->migration_blocker, errp); if (ret < 0) { error_free(s->migration_blocker); diff --git a/block/vpc.c b/block/vpc.c index ceb87dd3d8..945847fe4a 100644 --- a/block/vpc.c +++ b/block/vpc.c @@ -446,9 +446,12 @@ static int vpc_open(BlockDriverState *bs, QDict *options, int flags, } /* Disable migration when VHD images are used */ + bdrv_graph_rdlock_main_loop(); error_setg(&s->migration_blocker, "The vpc format used by node '%s' " "does not support live migration", bdrv_get_device_or_node_name(bs)); + bdrv_graph_rdunlock_main_loop(); + ret = migrate_add_blocker(s->migration_blocker, errp); if (ret < 0) { error_free(s->migration_blocker); diff --git a/block/vvfat.c b/block/vvfat.c index 1a3a64c713..b0415798c0 100644 --- a/block/vvfat.c +++ b/block/vvfat.c @@ -1144,6 +1144,8 @@ static int vvfat_open(BlockDriverState *bs, QDict *options, int flags, QemuOpts *opts; int ret; + GRAPH_RDLOCK_GUARD_MAINLOOP(); + #ifdef DEBUG vvv = s; #endif diff --git a/blockjob.c b/blockjob.c index 58c5d64539..807f992b59 100644 --- a/blockjob.c +++ b/blockjob.c @@ -485,6 +485,7 @@ void *block_job_create(const char *job_id, const BlockJobDriver *driver, BlockJob *job; int ret; GLOBAL_STATE_CODE(); + GRAPH_RDLOCK_GUARD_MAINLOOP(); if (job_id == NULL && !(flags & JOB_INTERNAL)) { job_id = bdrv_get_device_name(bs); diff --git a/include/block/block-io.h b/include/block/block-io.h index 9707eb3eff..2c0c7b1906 100644 --- a/include/block/block-io.h +++ b/include/block/block-io.h @@ -183,8 +183,12 @@ const char *bdrv_get_format_name(BlockDriverState *bs); bool bdrv_supports_compressed_writes(BlockDriverState *bs); const char *bdrv_get_node_name(const BlockDriverState *bs); -const char *bdrv_get_device_name(const BlockDriverState *bs); -const char *bdrv_get_device_or_node_name(const BlockDriverState *bs); + +const char * GRAPH_RDLOCK +bdrv_get_device_name(const BlockDriverState *bs); + +const char * GRAPH_RDLOCK +bdrv_get_device_or_node_name(const BlockDriverState *bs); int coroutine_fn GRAPH_RDLOCK bdrv_co_get_info(BlockDriverState *bs, BlockDriverInfo *bdi); diff --git a/include/block/block_int-io.h b/include/block/block_int-io.h index 2b6004ab93..34eac72d7a 100644 --- a/include/block/block_int-io.h +++ b/include/block/block_int-io.h @@ -99,7 +99,7 @@ BlockDriver *bdrv_probe_all(const uint8_t *buf, int buf_size, */ void bdrv_wakeup(BlockDriverState *bs); -const char *bdrv_get_parent_name(const BlockDriverState *bs); +const char * GRAPH_RDLOCK bdrv_get_parent_name(const BlockDriverState *bs); bool blk_dev_has_tray(BlockBackend *blk); bool blk_dev_is_tray_open(BlockBackend *blk); diff --git a/include/block/qapi.h b/include/block/qapi.h index 887235653a..54c48de26a 100644 --- a/include/block/qapi.h +++ b/include/block/qapi.h @@ -33,9 +33,10 @@ BlockDeviceInfo * GRAPH_RDLOCK bdrv_block_device_info(BlockBackend *blk, BlockDriverState *bs, bool flat, Error **errp); -int bdrv_query_snapshot_info_list(BlockDriverState *bs, - SnapshotInfoList **p_list, - Error **errp); +int GRAPH_RDLOCK +bdrv_query_snapshot_info_list(BlockDriverState *bs, + SnapshotInfoList **p_list, + Error **errp); void GRAPH_RDLOCK bdrv_query_image_info(BlockDriverState *bs, ImageInfo **p_info, bool flat, bool skip_implicit_filters, Error **errp); From bd131d6705b6996f2cdccee3db017af570ce91ad Mon Sep 17 00:00:00 2001 From: Kevin Wolf Date: Fri, 29 Sep 2023 16:51:48 +0200 Subject: [PATCH 0633/1077] block: Mark bdrv_amend_options() and callers GRAPH_RDLOCK This adds GRAPH_RDLOCK annotations to declare that callers of bdrv_amend_options() need to hold a reader lock for the graph. This removes an assume_graph_lock() call in crypto's implementation. Signed-off-by: Kevin Wolf Message-ID: <20230929145157.45443-14-kwolf@redhat.com> Reviewed-by: Stefan Hajnoczi Signed-off-by: Kevin Wolf --- block/crypto.c | 4 +--- include/block/block-global-state.h | 8 ++++---- include/block/block_int-common.h | 10 ++++------ qemu-img.c | 7 +++++++ 4 files changed, 16 insertions(+), 13 deletions(-) diff --git a/block/crypto.c b/block/crypto.c index c9c9a39fa3..b3f0233d53 100644 --- a/block/crypto.c +++ b/block/crypto.c @@ -828,7 +828,7 @@ block_crypto_amend_options_generic_luks(BlockDriverState *bs, errp); } -static int +static int GRAPH_RDLOCK block_crypto_amend_options_luks(BlockDriverState *bs, QemuOpts *opts, BlockDriverAmendStatusCB *status_cb, @@ -841,8 +841,6 @@ block_crypto_amend_options_luks(BlockDriverState *bs, QCryptoBlockAmendOptions *amend_options = NULL; int ret = -EINVAL; - assume_graph_lock(); /* FIXME */ - assert(crypto); assert(crypto->block); diff --git a/include/block/block-global-state.h b/include/block/block-global-state.h index ec623ef3c9..9dc35133a8 100644 --- a/include/block/block-global-state.h +++ b/include/block/block-global-state.h @@ -160,10 +160,10 @@ void bdrv_unfreeze_backing_chain(BlockDriverState *bs, BlockDriverState *base); */ typedef void BlockDriverAmendStatusCB(BlockDriverState *bs, int64_t offset, int64_t total_work_size, void *opaque); -int bdrv_amend_options(BlockDriverState *bs_new, QemuOpts *opts, - BlockDriverAmendStatusCB *status_cb, void *cb_opaque, - bool force, - Error **errp); +int GRAPH_RDLOCK +bdrv_amend_options(BlockDriverState *bs_new, QemuOpts *opts, + BlockDriverAmendStatusCB *status_cb, void *cb_opaque, + bool force, Error **errp); /* check if a named node can be replaced when doing drive-mirror */ BlockDriverState * GRAPH_RDLOCK diff --git a/include/block/block_int-common.h b/include/block/block_int-common.h index be80887898..c8661775f4 100644 --- a/include/block/block_int-common.h +++ b/include/block/block_int-common.h @@ -259,12 +259,10 @@ struct BlockDriver { int coroutine_fn GRAPH_UNLOCKED_PTR (*bdrv_co_create_opts)( BlockDriver *drv, const char *filename, QemuOpts *opts, Error **errp); - int (*bdrv_amend_options)(BlockDriverState *bs, - QemuOpts *opts, - BlockDriverAmendStatusCB *status_cb, - void *cb_opaque, - bool force, - Error **errp); + int GRAPH_RDLOCK_PTR (*bdrv_amend_options)( + BlockDriverState *bs, QemuOpts *opts, + BlockDriverAmendStatusCB *status_cb, void *cb_opaque, + bool force, Error **errp); int (*bdrv_make_empty)(BlockDriverState *bs); diff --git a/qemu-img.c b/qemu-img.c index 3ecbc375b0..585b65640f 100644 --- a/qemu-img.c +++ b/qemu-img.c @@ -4129,6 +4129,8 @@ static int print_amend_option_help(const char *format) { BlockDriver *drv; + GRAPH_RDLOCK_GUARD_MAINLOOP(); + /* Find driver and parse its options */ drv = bdrv_find_format(format); if (!drv) { @@ -4267,9 +4269,11 @@ static int img_amend(int argc, char **argv) goto out; } + bdrv_graph_rdlock_main_loop(); if (!bs->drv->bdrv_amend_options) { error_report("Format driver '%s' does not support option amendment", fmt); + bdrv_graph_rdunlock_main_loop(); ret = -1; goto out; } @@ -4289,6 +4293,7 @@ static int img_amend(int argc, char **argv) "This option is only supported for image creation\n"); } + bdrv_graph_rdunlock_main_loop(); error_report_err(err); ret = -1; goto out; @@ -4298,6 +4303,8 @@ static int img_amend(int argc, char **argv) qemu_progress_print(0.f, 0); ret = bdrv_amend_options(bs, opts, &amend_status_cb, NULL, force, &err); qemu_progress_print(100.f, 0); + bdrv_graph_rdunlock_main_loop(); + if (ret < 0) { error_report_err(err); goto out; From 0bb79c97fd8e355aca433f4331d7d45e7e72b4b6 Mon Sep 17 00:00:00 2001 From: Kevin Wolf Date: Fri, 29 Sep 2023 16:51:49 +0200 Subject: [PATCH 0634/1077] qcow2: Mark qcow2_signal_corruption() and callers GRAPH_RDLOCK This adds GRAPH_RDLOCK annotations to declare that callers of qcow2_signal_corruption() need to hold a reader lock for the graph because it calls bdrv_get_node_name(), which accesses the parents list of a node. For some places, we know that they will hold the lock, but we don't have the GRAPH_RDLOCK annotations yet. In this case, add assume_graph_lock() with a FIXME comment. These places will be removed once everything is properly annotated. Signed-off-by: Kevin Wolf Message-ID: <20230929145157.45443-15-kwolf@redhat.com> Reviewed-by: Stefan Hajnoczi Signed-off-by: Kevin Wolf --- block.c | 3 +- block/block-backend.c | 2 + block/qcow2-bitmap.c | 31 ++--- block/qcow2-cache.c | 11 +- block/qcow2-cluster.c | 62 +++++----- block/qcow2-refcount.c | 80 ++++++------- block/qcow2.c | 61 +++++----- block/qcow2.h | 178 +++++++++++++++++------------ block/replication.c | 8 +- include/block/block-global-state.h | 2 +- include/block/block_int-common.h | 2 +- 11 files changed, 249 insertions(+), 191 deletions(-) diff --git a/block.c b/block.c index c932dc0a51..d1a3466069 100644 --- a/block.c +++ b/block.c @@ -7250,7 +7250,8 @@ bool bdrv_op_is_blocked(BlockDriverState *bs, BlockOpType op, Error **errp) { BdrvOpBlocker *blocker; GLOBAL_STATE_CODE(); - GRAPH_RDLOCK_GUARD_MAINLOOP(); + + assume_graph_lock(); /* FIXME */ assert((int) op >= 0 && op < BLOCK_OP_TYPE_MAX); if (!QLIST_EMPTY(&bs->op_blockers[op])) { diff --git a/block/block-backend.c b/block/block-backend.c index 39b5f90a11..fd10fcc2d0 100644 --- a/block/block-backend.c +++ b/block/block-backend.c @@ -2905,6 +2905,8 @@ const BdrvChild *blk_root(BlockBackend *blk) int blk_make_empty(BlockBackend *blk, Error **errp) { GLOBAL_STATE_CODE(); + GRAPH_RDLOCK_GUARD_MAINLOOP(); + if (!blk_is_available(blk)) { error_setg(errp, "No medium inserted"); return -ENOMEDIUM; diff --git a/block/qcow2-bitmap.c b/block/qcow2-bitmap.c index 03dd91dfac..6996eab9e1 100644 --- a/block/qcow2-bitmap.c +++ b/block/qcow2-bitmap.c @@ -206,8 +206,9 @@ static int check_constraints_on_bitmap(BlockDriverState *bs, return 0; } -static void clear_bitmap_table(BlockDriverState *bs, uint64_t *bitmap_table, - uint32_t bitmap_table_size) +static void GRAPH_RDLOCK +clear_bitmap_table(BlockDriverState *bs, uint64_t *bitmap_table, + uint32_t bitmap_table_size) { BDRVQcow2State *s = bs->opaque; int i; @@ -261,7 +262,8 @@ fail: return ret; } -static int free_bitmap_clusters(BlockDriverState *bs, Qcow2BitmapTable *tb) +static int GRAPH_RDLOCK +free_bitmap_clusters(BlockDriverState *bs, Qcow2BitmapTable *tb) { int ret; uint64_t *bitmap_table; @@ -732,8 +734,9 @@ out: * Store bitmap list to qcow2 image as a bitmap directory. * Everything is checked. */ -static int bitmap_list_store(BlockDriverState *bs, Qcow2BitmapList *bm_list, - uint64_t *offset, uint64_t *size, bool in_place) +static int GRAPH_RDLOCK +bitmap_list_store(BlockDriverState *bs, Qcow2BitmapList *bm_list, + uint64_t *offset, uint64_t *size, bool in_place) { int ret; uint8_t *dir; @@ -831,8 +834,9 @@ fail: * Bitmap List end */ -static int update_ext_header_and_dir_in_place(BlockDriverState *bs, - Qcow2BitmapList *bm_list) +static int GRAPH_RDLOCK +update_ext_header_and_dir_in_place(BlockDriverState *bs, + Qcow2BitmapList *bm_list) { BDRVQcow2State *s = bs->opaque; int ret; @@ -879,8 +883,8 @@ static int update_ext_header_and_dir_in_place(BlockDriverState *bs, */ } -static int update_ext_header_and_dir(BlockDriverState *bs, - Qcow2BitmapList *bm_list) +static int GRAPH_RDLOCK +update_ext_header_and_dir(BlockDriverState *bs, Qcow2BitmapList *bm_list) { BDRVQcow2State *s = bs->opaque; int ret; @@ -1273,9 +1277,9 @@ out: /* store_bitmap_data() * Store bitmap to image, filling bitmap table accordingly. */ -static uint64_t *store_bitmap_data(BlockDriverState *bs, - BdrvDirtyBitmap *bitmap, - uint32_t *bitmap_table_size, Error **errp) +static uint64_t * GRAPH_RDLOCK +store_bitmap_data(BlockDriverState *bs, BdrvDirtyBitmap *bitmap, + uint32_t *bitmap_table_size, Error **errp) { int ret; BDRVQcow2State *s = bs->opaque; @@ -1372,7 +1376,8 @@ fail: * Store bm->dirty_bitmap to qcow2. * Set bm->table_offset and bm->table_size accordingly. */ -static int store_bitmap(BlockDriverState *bs, Qcow2Bitmap *bm, Error **errp) +static int GRAPH_RDLOCK +store_bitmap(BlockDriverState *bs, Qcow2Bitmap *bm, Error **errp) { int ret; uint64_t *tb; diff --git a/block/qcow2-cache.c b/block/qcow2-cache.c index 01c67bdddc..23d9588b08 100644 --- a/block/qcow2-cache.c +++ b/block/qcow2-cache.c @@ -163,7 +163,8 @@ int qcow2_cache_destroy(Qcow2Cache *c) return 0; } -static int qcow2_cache_flush_dependency(BlockDriverState *bs, Qcow2Cache *c) +static int GRAPH_RDLOCK +qcow2_cache_flush_dependency(BlockDriverState *bs, Qcow2Cache *c) { int ret; @@ -178,7 +179,8 @@ static int qcow2_cache_flush_dependency(BlockDriverState *bs, Qcow2Cache *c) return 0; } -static int qcow2_cache_entry_flush(BlockDriverState *bs, Qcow2Cache *c, int i) +static int GRAPH_RDLOCK +qcow2_cache_entry_flush(BlockDriverState *bs, Qcow2Cache *c, int i) { BDRVQcow2State *s = bs->opaque; int ret = 0; @@ -318,8 +320,9 @@ int qcow2_cache_empty(BlockDriverState *bs, Qcow2Cache *c) return 0; } -static int qcow2_cache_do_get(BlockDriverState *bs, Qcow2Cache *c, - uint64_t offset, void **table, bool read_from_disk) +static int GRAPH_RDLOCK +qcow2_cache_do_get(BlockDriverState *bs, Qcow2Cache *c, uint64_t offset, + void **table, bool read_from_disk) { BDRVQcow2State *s = bs->opaque; int i; diff --git a/block/qcow2-cluster.c b/block/qcow2-cluster.c index f4f6cd6ad0..904f00d1b3 100644 --- a/block/qcow2-cluster.c +++ b/block/qcow2-cluster.c @@ -207,8 +207,9 @@ int qcow2_grow_l1_table(BlockDriverState *bs, uint64_t min_size, * the cache is used; otherwise the L2 slice is loaded from the image * file. */ -static int l2_load(BlockDriverState *bs, uint64_t offset, - uint64_t l2_offset, uint64_t **l2_slice) +static int GRAPH_RDLOCK +l2_load(BlockDriverState *bs, uint64_t offset, + uint64_t l2_offset, uint64_t **l2_slice) { BDRVQcow2State *s = bs->opaque; int start_of_slice = l2_entry_size(s) * @@ -269,7 +270,7 @@ int qcow2_write_l1_entry(BlockDriverState *bs, int l1_index) * */ -static int l2_allocate(BlockDriverState *bs, int l1_index) +static int GRAPH_RDLOCK l2_allocate(BlockDriverState *bs, int l1_index) { BDRVQcow2State *s = bs->opaque; uint64_t old_l2_offset; @@ -751,9 +752,9 @@ fail: * * Returns 0 on success, -errno in failure case */ -static int get_cluster_table(BlockDriverState *bs, uint64_t offset, - uint64_t **new_l2_slice, - int *new_l2_index) +static int GRAPH_RDLOCK +get_cluster_table(BlockDriverState *bs, uint64_t offset, + uint64_t **new_l2_slice, int *new_l2_index) { BDRVQcow2State *s = bs->opaque; unsigned int l2_index; @@ -1155,11 +1156,10 @@ void coroutine_fn qcow2_alloc_cluster_abort(BlockDriverState *bs, QCowL2Meta *m) * * Returns 0 on success, -errno on failure. */ -static int coroutine_fn calculate_l2_meta(BlockDriverState *bs, - uint64_t host_cluster_offset, - uint64_t guest_offset, unsigned bytes, - uint64_t *l2_slice, QCowL2Meta **m, - bool keep_old) +static int coroutine_fn GRAPH_RDLOCK +calculate_l2_meta(BlockDriverState *bs, uint64_t host_cluster_offset, + uint64_t guest_offset, unsigned bytes, uint64_t *l2_slice, + QCowL2Meta **m, bool keep_old) { BDRVQcow2State *s = bs->opaque; int sc_index, l2_index = offset_to_l2_slice_index(s, guest_offset); @@ -1490,9 +1490,9 @@ static int coroutine_fn handle_dependencies(BlockDriverState *bs, * * -errno: in error cases */ -static int coroutine_fn handle_copied(BlockDriverState *bs, - uint64_t guest_offset, uint64_t *host_offset, uint64_t *bytes, - QCowL2Meta **m) +static int coroutine_fn GRAPH_RDLOCK +handle_copied(BlockDriverState *bs, uint64_t guest_offset, + uint64_t *host_offset, uint64_t *bytes, QCowL2Meta **m) { BDRVQcow2State *s = bs->opaque; int l2_index; @@ -1600,10 +1600,9 @@ out: * function has been waiting for another request and the allocation must be * restarted, but the whole request should not be failed. */ -static int coroutine_fn do_alloc_cluster_offset(BlockDriverState *bs, - uint64_t guest_offset, - uint64_t *host_offset, - uint64_t *nb_clusters) +static int coroutine_fn GRAPH_RDLOCK +do_alloc_cluster_offset(BlockDriverState *bs, uint64_t guest_offset, + uint64_t *host_offset, uint64_t *nb_clusters) { BDRVQcow2State *s = bs->opaque; @@ -1658,9 +1657,9 @@ static int coroutine_fn do_alloc_cluster_offset(BlockDriverState *bs, * * -errno: in error cases */ -static int coroutine_fn handle_alloc(BlockDriverState *bs, - uint64_t guest_offset, uint64_t *host_offset, uint64_t *bytes, - QCowL2Meta **m) +static int coroutine_fn GRAPH_RDLOCK +handle_alloc(BlockDriverState *bs, uint64_t guest_offset, + uint64_t *host_offset, uint64_t *bytes, QCowL2Meta **m) { BDRVQcow2State *s = bs->opaque; int l2_index; @@ -1898,9 +1897,9 @@ again: * all clusters in the same L2 slice) and returns the number of discarded * clusters. */ -static int discard_in_l2_slice(BlockDriverState *bs, uint64_t offset, - uint64_t nb_clusters, - enum qcow2_discard_type type, bool full_discard) +static int GRAPH_RDLOCK +discard_in_l2_slice(BlockDriverState *bs, uint64_t offset, uint64_t nb_clusters, + enum qcow2_discard_type type, bool full_discard) { BDRVQcow2State *s = bs->opaque; uint64_t *l2_slice; @@ -2037,7 +2036,7 @@ fail: * all clusters in the same L2 slice) and returns the number of zeroed * clusters. */ -static int coroutine_fn +static int coroutine_fn GRAPH_RDLOCK zero_in_l2_slice(BlockDriverState *bs, uint64_t offset, uint64_t nb_clusters, int flags) { @@ -2093,7 +2092,7 @@ zero_in_l2_slice(BlockDriverState *bs, uint64_t offset, return nb_clusters; } -static int coroutine_fn +static int coroutine_fn GRAPH_RDLOCK zero_l2_subclusters(BlockDriverState *bs, uint64_t offset, unsigned nb_subclusters) { @@ -2231,11 +2230,12 @@ fail: * status_cb(). l1_entries contains the total number of L1 entries and * *visited_l1_entries counts all visited L1 entries. */ -static int expand_zero_clusters_in_l1(BlockDriverState *bs, uint64_t *l1_table, - int l1_size, int64_t *visited_l1_entries, - int64_t l1_entries, - BlockDriverAmendStatusCB *status_cb, - void *cb_opaque) +static int GRAPH_RDLOCK +expand_zero_clusters_in_l1(BlockDriverState *bs, uint64_t *l1_table, + int l1_size, int64_t *visited_l1_entries, + int64_t l1_entries, + BlockDriverAmendStatusCB *status_cb, + void *cb_opaque) { BDRVQcow2State *s = bs->opaque; bool is_active_l1 = (l1_table == s->l1_table); diff --git a/block/qcow2-refcount.c b/block/qcow2-refcount.c index 996d1217d0..0266542cee 100644 --- a/block/qcow2-refcount.c +++ b/block/qcow2-refcount.c @@ -229,9 +229,9 @@ static void set_refcount_ro6(void *refcount_array, uint64_t index, } -static int load_refcount_block(BlockDriverState *bs, - int64_t refcount_block_offset, - void **refcount_block) +static int GRAPH_RDLOCK +load_refcount_block(BlockDriverState *bs, int64_t refcount_block_offset, + void **refcount_block) { BDRVQcow2State *s = bs->opaque; @@ -302,8 +302,9 @@ static int in_same_refcount_block(BDRVQcow2State *s, uint64_t offset_a, * * Returns 0 on success or -errno in error case */ -static int alloc_refcount_block(BlockDriverState *bs, - int64_t cluster_index, void **refcount_block) +static int GRAPH_RDLOCK +alloc_refcount_block(BlockDriverState *bs, int64_t cluster_index, + void **refcount_block) { BDRVQcow2State *s = bs->opaque; unsigned int refcount_table_index; @@ -806,12 +807,9 @@ found: /* XXX: cache several refcount block clusters ? */ /* @addend is the absolute value of the addend; if @decrease is set, @addend * will be subtracted from the current refcount, otherwise it will be added */ -static int update_refcount(BlockDriverState *bs, - int64_t offset, - int64_t length, - uint64_t addend, - bool decrease, - enum qcow2_discard_type type) +static int GRAPH_RDLOCK +update_refcount(BlockDriverState *bs, int64_t offset, int64_t length, + uint64_t addend, bool decrease, enum qcow2_discard_type type) { BDRVQcow2State *s = bs->opaque; int64_t start, last, cluster_offset; @@ -967,8 +965,8 @@ int qcow2_update_cluster_refcount(BlockDriverState *bs, /* return < 0 if error */ -static int64_t alloc_clusters_noref(BlockDriverState *bs, uint64_t size, - uint64_t max) +static int64_t GRAPH_RDLOCK +alloc_clusters_noref(BlockDriverState *bs, uint64_t size, uint64_t max) { BDRVQcow2State *s = bs->opaque; uint64_t i, nb_clusters, refcount; @@ -2302,7 +2300,7 @@ calculate_refcounts(BlockDriverState *bs, BdrvCheckResult *res, * Compares the actual reference count for each cluster in the image against the * refcount as reported by the refcount structures on-disk. */ -static void coroutine_fn +static void coroutine_fn GRAPH_RDLOCK compare_refcounts(BlockDriverState *bs, BdrvCheckResult *res, BdrvCheckMode fix, bool *rebuild, int64_t *highest_cluster, @@ -3103,20 +3101,22 @@ int qcow2_pre_write_overlap_check(BlockDriverState *bs, int ign, int64_t offset, * * @allocated should be set to true if a new cluster has been allocated. */ -typedef int (RefblockFinishOp)(BlockDriverState *bs, uint64_t **reftable, - uint64_t reftable_index, uint64_t *reftable_size, - void *refblock, bool refblock_empty, - bool *allocated, Error **errp); +typedef int /* GRAPH_RDLOCK_PTR */ + (RefblockFinishOp)(BlockDriverState *bs, uint64_t **reftable, + uint64_t reftable_index, uint64_t *reftable_size, + void *refblock, bool refblock_empty, + bool *allocated, Error **errp); /** * This "operation" for walk_over_reftable() allocates the refblock on disk (if * it is not empty) and inserts its offset into the new reftable. The size of * this new reftable is increased as required. */ -static int alloc_refblock(BlockDriverState *bs, uint64_t **reftable, - uint64_t reftable_index, uint64_t *reftable_size, - void *refblock, bool refblock_empty, bool *allocated, - Error **errp) +static int GRAPH_RDLOCK +alloc_refblock(BlockDriverState *bs, uint64_t **reftable, + uint64_t reftable_index, uint64_t *reftable_size, + void *refblock, bool refblock_empty, bool *allocated, + Error **errp) { BDRVQcow2State *s = bs->opaque; int64_t offset; @@ -3166,10 +3166,11 @@ static int alloc_refblock(BlockDriverState *bs, uint64_t **reftable, * offset specified by the new reftable's entry. It does not modify the new * reftable or change any refcounts. */ -static int flush_refblock(BlockDriverState *bs, uint64_t **reftable, - uint64_t reftable_index, uint64_t *reftable_size, - void *refblock, bool refblock_empty, bool *allocated, - Error **errp) +static int GRAPH_RDLOCK +flush_refblock(BlockDriverState *bs, uint64_t **reftable, + uint64_t reftable_index, uint64_t *reftable_size, + void *refblock, bool refblock_empty, bool *allocated, + Error **errp) { BDRVQcow2State *s = bs->opaque; int64_t offset; @@ -3210,16 +3211,17 @@ static int flush_refblock(BlockDriverState *bs, uint64_t **reftable, * * @allocated is set to true if a new cluster has been allocated. */ -static int walk_over_reftable(BlockDriverState *bs, uint64_t **new_reftable, - uint64_t *new_reftable_index, - uint64_t *new_reftable_size, - void *new_refblock, int new_refblock_size, - int new_refcount_bits, - RefblockFinishOp *operation, bool *allocated, - Qcow2SetRefcountFunc *new_set_refcount, - BlockDriverAmendStatusCB *status_cb, - void *cb_opaque, int index, int total, - Error **errp) +static int GRAPH_RDLOCK +walk_over_reftable(BlockDriverState *bs, uint64_t **new_reftable, + uint64_t *new_reftable_index, + uint64_t *new_reftable_size, + void *new_refblock, int new_refblock_size, + int new_refcount_bits, + RefblockFinishOp *operation, bool *allocated, + Qcow2SetRefcountFunc *new_set_refcount, + BlockDriverAmendStatusCB *status_cb, + void *cb_opaque, int index, int total, + Error **errp) { BDRVQcow2State *s = bs->opaque; uint64_t reftable_index; @@ -3545,8 +3547,8 @@ done: return ret; } -static int64_t coroutine_fn get_refblock_offset(BlockDriverState *bs, - uint64_t offset) +static int64_t coroutine_fn GRAPH_RDLOCK +get_refblock_offset(BlockDriverState *bs, uint64_t offset) { BDRVQcow2State *s = bs->opaque; uint32_t index = offset_to_reftable_index(s, offset); @@ -3565,7 +3567,7 @@ static int64_t coroutine_fn get_refblock_offset(BlockDriverState *bs, return covering_refblock_offset; } -static int coroutine_fn +static int coroutine_fn GRAPH_RDLOCK qcow2_discard_refcount_block(BlockDriverState *bs, uint64_t discard_block_offs) { BDRVQcow2State *s = bs->opaque; diff --git a/block/qcow2.c b/block/qcow2.c index 4780cb9148..137c036ea4 100644 --- a/block/qcow2.c +++ b/block/qcow2.c @@ -536,7 +536,7 @@ int qcow2_mark_dirty(BlockDriverState *bs) * function when there are no pending requests, it does not guard against * concurrent requests dirtying the image. */ -static int qcow2_mark_clean(BlockDriverState *bs) +static int GRAPH_RDLOCK qcow2_mark_clean(BlockDriverState *bs) { BDRVQcow2State *s = bs->opaque; @@ -570,7 +570,8 @@ int qcow2_mark_corrupt(BlockDriverState *bs) * Marks the image as consistent, i.e., unsets the corrupt bit, and flushes * before if necessary. */ -static int coroutine_fn qcow2_mark_consistent(BlockDriverState *bs) +static int coroutine_fn GRAPH_RDLOCK +qcow2_mark_consistent(BlockDriverState *bs) { BDRVQcow2State *s = bs->opaque; @@ -980,10 +981,9 @@ typedef struct Qcow2ReopenState { QCryptoBlockOpenOptions *crypto_opts; /* Disk encryption runtime options */ } Qcow2ReopenState; -static int qcow2_update_options_prepare(BlockDriverState *bs, - Qcow2ReopenState *r, - QDict *options, int flags, - Error **errp) +static int GRAPH_RDLOCK +qcow2_update_options_prepare(BlockDriverState *bs, Qcow2ReopenState *r, + QDict *options, int flags, Error **errp) { BDRVQcow2State *s = bs->opaque; QemuOpts *opts = NULL; @@ -1260,7 +1260,7 @@ static void qcow2_update_options_abort(BlockDriverState *bs, qapi_free_QCryptoBlockOpenOptions(r->crypto_opts); } -static int coroutine_fn +static int coroutine_fn GRAPH_RDLOCK qcow2_update_options(BlockDriverState *bs, QDict *options, int flags, Error **errp) { @@ -1969,13 +1969,17 @@ static void qcow2_refresh_limits(BlockDriverState *bs, Error **errp) bs->bl.pdiscard_alignment = s->cluster_size; } -static int qcow2_reopen_prepare(BDRVReopenState *state, - BlockReopenQueue *queue, Error **errp) +static int GRAPH_UNLOCKED +qcow2_reopen_prepare(BDRVReopenState *state,BlockReopenQueue *queue, + Error **errp) { BDRVQcow2State *s = state->bs->opaque; Qcow2ReopenState *r; int ret; + GLOBAL_STATE_CODE(); + GRAPH_RDLOCK_GUARD_MAINLOOP(); + r = g_new0(Qcow2ReopenState, 1); state->opaque = r; @@ -2038,6 +2042,8 @@ static void qcow2_reopen_commit(BDRVReopenState *state) static void qcow2_reopen_commit_post(BDRVReopenState *state) { + GRAPH_RDLOCK_GUARD_MAINLOOP(); + if (state->flags & BDRV_O_RDWR) { Error *local_err = NULL; @@ -4079,8 +4085,8 @@ qcow2_co_pwrite_zeroes(BlockDriverState *bs, int64_t offset, int64_t bytes, return ret; } -static coroutine_fn int qcow2_co_pdiscard(BlockDriverState *bs, - int64_t offset, int64_t bytes) +static int coroutine_fn GRAPH_RDLOCK +qcow2_co_pdiscard(BlockDriverState *bs, int64_t offset, int64_t bytes) { int ret; BDRVQcow2State *s = bs->opaque; @@ -4825,7 +4831,7 @@ fail: return ret; } -static int make_completely_empty(BlockDriverState *bs) +static int GRAPH_RDLOCK make_completely_empty(BlockDriverState *bs) { BDRVQcow2State *s = bs->opaque; Error *local_err = NULL; @@ -4976,7 +4982,7 @@ fail: return ret; } -static int qcow2_make_empty(BlockDriverState *bs) +static int GRAPH_RDLOCK qcow2_make_empty(BlockDriverState *bs) { BDRVQcow2State *s = bs->opaque; uint64_t offset, end_offset; @@ -5020,7 +5026,7 @@ static int qcow2_make_empty(BlockDriverState *bs) return ret; } -static coroutine_fn int qcow2_co_flush_to_os(BlockDriverState *bs) +static coroutine_fn GRAPH_RDLOCK int qcow2_co_flush_to_os(BlockDriverState *bs) { BDRVQcow2State *s = bs->opaque; int ret; @@ -5369,7 +5375,7 @@ qcow2_co_load_vmstate(BlockDriverState *bs, QEMUIOVector *qiov, int64_t pos) return bs->drv->bdrv_co_preadv_part(bs, offset, qiov->size, qiov, 0, 0); } -static int qcow2_has_compressed_clusters(BlockDriverState *bs) +static int GRAPH_RDLOCK qcow2_has_compressed_clusters(BlockDriverState *bs) { int64_t offset = 0; int64_t bytes = bdrv_getlength(bs); @@ -5405,9 +5411,10 @@ static int qcow2_has_compressed_clusters(BlockDriverState *bs) * Downgrades an image's version. To achieve this, any incompatible features * have to be removed. */ -static int qcow2_downgrade(BlockDriverState *bs, int target_version, - BlockDriverAmendStatusCB *status_cb, void *cb_opaque, - Error **errp) +static int GRAPH_RDLOCK +qcow2_downgrade(BlockDriverState *bs, int target_version, + BlockDriverAmendStatusCB *status_cb, void *cb_opaque, + Error **errp) { BDRVQcow2State *s = bs->opaque; int current_version = s->qcow_version; @@ -5515,9 +5522,10 @@ static int qcow2_downgrade(BlockDriverState *bs, int target_version, * features of older versions, some things may have to be presented * differently. */ -static int qcow2_upgrade(BlockDriverState *bs, int target_version, - BlockDriverAmendStatusCB *status_cb, void *cb_opaque, - Error **errp) +static int GRAPH_RDLOCK +qcow2_upgrade(BlockDriverState *bs, int target_version, + BlockDriverAmendStatusCB *status_cb, void *cb_opaque, + Error **errp) { BDRVQcow2State *s = bs->opaque; bool need_snapshot_update; @@ -5643,11 +5651,10 @@ static void qcow2_amend_helper_cb(BlockDriverState *bs, info->original_cb_opaque); } -static int qcow2_amend_options(BlockDriverState *bs, QemuOpts *opts, - BlockDriverAmendStatusCB *status_cb, - void *cb_opaque, - bool force, - Error **errp) +static int GRAPH_RDLOCK +qcow2_amend_options(BlockDriverState *bs, QemuOpts *opts, + BlockDriverAmendStatusCB *status_cb, void *cb_opaque, + bool force, Error **errp) { BDRVQcow2State *s = bs->opaque; int old_version = s->qcow_version, new_version = old_version; @@ -5947,8 +5954,6 @@ void qcow2_signal_corruption(BlockDriverState *bs, bool fatal, int64_t offset, char *message; va_list ap; - assume_graph_lock(); /* FIXME */ - fatal = fatal && bdrv_is_writable(bs); if (s->signaled_corruption && diff --git a/block/qcow2.h b/block/qcow2.h index 359bfca4aa..29958c512b 100644 --- a/block/qcow2.h +++ b/block/qcow2.h @@ -838,9 +838,10 @@ int qcow2_mark_dirty(BlockDriverState *bs); int qcow2_mark_corrupt(BlockDriverState *bs); int qcow2_update_header(BlockDriverState *bs); -void qcow2_signal_corruption(BlockDriverState *bs, bool fatal, int64_t offset, - int64_t size, const char *message_format, ...) - G_GNUC_PRINTF(5, 6); +void GRAPH_RDLOCK +qcow2_signal_corruption(BlockDriverState *bs, bool fatal, int64_t offset, + int64_t size, const char *message_format, ...) + G_GNUC_PRINTF(5, 6); int qcow2_validate_table(BlockDriverState *bs, uint64_t offset, uint64_t entries, size_t entry_len, @@ -851,33 +852,41 @@ int qcow2_validate_table(BlockDriverState *bs, uint64_t offset, int coroutine_fn GRAPH_RDLOCK qcow2_refcount_init(BlockDriverState *bs); void qcow2_refcount_close(BlockDriverState *bs); -int qcow2_get_refcount(BlockDriverState *bs, int64_t cluster_index, - uint64_t *refcount); +int GRAPH_RDLOCK qcow2_get_refcount(BlockDriverState *bs, int64_t cluster_index, + uint64_t *refcount); -int qcow2_update_cluster_refcount(BlockDriverState *bs, int64_t cluster_index, - uint64_t addend, bool decrease, - enum qcow2_discard_type type); +int GRAPH_RDLOCK +qcow2_update_cluster_refcount(BlockDriverState *bs, int64_t cluster_index, + uint64_t addend, bool decrease, + enum qcow2_discard_type type); -int64_t qcow2_refcount_area(BlockDriverState *bs, uint64_t offset, - uint64_t additional_clusters, bool exact_size, - int new_refblock_index, - uint64_t new_refblock_offset); +int64_t GRAPH_RDLOCK +qcow2_refcount_area(BlockDriverState *bs, uint64_t offset, + uint64_t additional_clusters, bool exact_size, + int new_refblock_index, + uint64_t new_refblock_offset); + +int64_t GRAPH_RDLOCK +qcow2_alloc_clusters(BlockDriverState *bs, uint64_t size); + +int64_t GRAPH_RDLOCK coroutine_fn +qcow2_alloc_clusters_at(BlockDriverState *bs, uint64_t offset, + int64_t nb_clusters); -int64_t qcow2_alloc_clusters(BlockDriverState *bs, uint64_t size); -int64_t coroutine_fn qcow2_alloc_clusters_at(BlockDriverState *bs, uint64_t offset, - int64_t nb_clusters); int64_t coroutine_fn GRAPH_RDLOCK qcow2_alloc_bytes(BlockDriverState *bs, int size); -void qcow2_free_clusters(BlockDriverState *bs, - int64_t offset, int64_t size, - enum qcow2_discard_type type); -void qcow2_free_any_cluster(BlockDriverState *bs, uint64_t l2_entry, - enum qcow2_discard_type type); +void GRAPH_RDLOCK qcow2_free_clusters(BlockDriverState *bs, + int64_t offset, int64_t size, + enum qcow2_discard_type type); +void GRAPH_RDLOCK +qcow2_free_any_cluster(BlockDriverState *bs, uint64_t l2_entry, + enum qcow2_discard_type type); -int qcow2_update_snapshot_refcount(BlockDriverState *bs, - int64_t l1_table_offset, int l1_size, int addend); +int GRAPH_RDLOCK +qcow2_update_snapshot_refcount(BlockDriverState *bs, int64_t l1_table_offset, + int l1_size, int addend); -int qcow2_flush_caches(BlockDriverState *bs); -int qcow2_write_caches(BlockDriverState *bs); +int GRAPH_RDLOCK qcow2_flush_caches(BlockDriverState *bs); +int GRAPH_RDLOCK qcow2_write_caches(BlockDriverState *bs); int coroutine_fn qcow2_check_refcounts(BlockDriverState *bs, BdrvCheckResult *res, BdrvCheckMode fix); @@ -885,39 +894,48 @@ void qcow2_process_discards(BlockDriverState *bs, int ret); int qcow2_check_metadata_overlap(BlockDriverState *bs, int ign, int64_t offset, int64_t size); -int qcow2_pre_write_overlap_check(BlockDriverState *bs, int ign, int64_t offset, - int64_t size, bool data_file); +int GRAPH_RDLOCK +qcow2_pre_write_overlap_check(BlockDriverState *bs, int ign, int64_t offset, + int64_t size, bool data_file); + int coroutine_fn qcow2_inc_refcounts_imrt(BlockDriverState *bs, BdrvCheckResult *res, void **refcount_table, int64_t *refcount_table_size, int64_t offset, int64_t size); -int qcow2_change_refcount_order(BlockDriverState *bs, int refcount_order, - BlockDriverAmendStatusCB *status_cb, - void *cb_opaque, Error **errp); +int GRAPH_RDLOCK +qcow2_change_refcount_order(BlockDriverState *bs, int refcount_order, + BlockDriverAmendStatusCB *status_cb, + void *cb_opaque, Error **errp); int coroutine_fn GRAPH_RDLOCK qcow2_shrink_reftable(BlockDriverState *bs); -int64_t coroutine_fn qcow2_get_last_cluster(BlockDriverState *bs, int64_t size); + +int64_t coroutine_fn GRAPH_RDLOCK +qcow2_get_last_cluster(BlockDriverState *bs, int64_t size); int coroutine_fn GRAPH_RDLOCK qcow2_detect_metadata_preallocation(BlockDriverState *bs); /* qcow2-cluster.c functions */ -int qcow2_grow_l1_table(BlockDriverState *bs, uint64_t min_size, - bool exact_size); +int GRAPH_RDLOCK +qcow2_grow_l1_table(BlockDriverState *bs, uint64_t min_size, bool exact_size); int coroutine_fn GRAPH_RDLOCK qcow2_shrink_l1_table(BlockDriverState *bs, uint64_t max_size); -int qcow2_write_l1_entry(BlockDriverState *bs, int l1_index); +int GRAPH_RDLOCK qcow2_write_l1_entry(BlockDriverState *bs, int l1_index); int qcow2_encrypt_sectors(BDRVQcow2State *s, int64_t sector_num, uint8_t *buf, int nb_sectors, bool enc, Error **errp); -int qcow2_get_host_offset(BlockDriverState *bs, uint64_t offset, - unsigned int *bytes, uint64_t *host_offset, - QCow2SubclusterType *subcluster_type); -int coroutine_fn qcow2_alloc_host_offset(BlockDriverState *bs, uint64_t offset, - unsigned int *bytes, - uint64_t *host_offset, QCowL2Meta **m); +int GRAPH_RDLOCK +qcow2_get_host_offset(BlockDriverState *bs, uint64_t offset, + unsigned int *bytes, uint64_t *host_offset, + QCow2SubclusterType *subcluster_type); + +int coroutine_fn GRAPH_RDLOCK +qcow2_alloc_host_offset(BlockDriverState *bs, uint64_t offset, + unsigned int *bytes, uint64_t *host_offset, + QCowL2Meta **m); + int coroutine_fn GRAPH_RDLOCK qcow2_alloc_compressed_cluster_offset(BlockDriverState *bs, uint64_t offset, int compressed_size, uint64_t *host_offset); @@ -927,26 +945,33 @@ void qcow2_parse_compressed_l2_entry(BlockDriverState *bs, uint64_t l2_entry, int coroutine_fn GRAPH_RDLOCK qcow2_alloc_cluster_link_l2(BlockDriverState *bs, QCowL2Meta *m); -void coroutine_fn qcow2_alloc_cluster_abort(BlockDriverState *bs, QCowL2Meta *m); -int qcow2_cluster_discard(BlockDriverState *bs, uint64_t offset, - uint64_t bytes, enum qcow2_discard_type type, - bool full_discard); +void coroutine_fn GRAPH_RDLOCK +qcow2_alloc_cluster_abort(BlockDriverState *bs, QCowL2Meta *m); + +int GRAPH_RDLOCK +qcow2_cluster_discard(BlockDriverState *bs, uint64_t offset, uint64_t bytes, + enum qcow2_discard_type type, bool full_discard); int coroutine_fn GRAPH_RDLOCK qcow2_subcluster_zeroize(BlockDriverState *bs, uint64_t offset, uint64_t bytes, int flags); -int qcow2_expand_zero_clusters(BlockDriverState *bs, - BlockDriverAmendStatusCB *status_cb, - void *cb_opaque); +int GRAPH_RDLOCK +qcow2_expand_zero_clusters(BlockDriverState *bs, + BlockDriverAmendStatusCB *status_cb, + void *cb_opaque); /* qcow2-snapshot.c functions */ -int qcow2_snapshot_create(BlockDriverState *bs, QEMUSnapshotInfo *sn_info); -int qcow2_snapshot_goto(BlockDriverState *bs, const char *snapshot_id); -int qcow2_snapshot_delete(BlockDriverState *bs, - const char *snapshot_id, - const char *name, - Error **errp); +int GRAPH_RDLOCK +qcow2_snapshot_create(BlockDriverState *bs, QEMUSnapshotInfo *sn_info); + +int GRAPH_RDLOCK +qcow2_snapshot_goto(BlockDriverState *bs, const char *snapshot_id); + +int GRAPH_RDLOCK +qcow2_snapshot_delete(BlockDriverState *bs, const char *snapshot_id, + const char *name, Error **errp); + int qcow2_snapshot_list(BlockDriverState *bs, QEMUSnapshotInfo **psn_tab); int qcow2_snapshot_load_tmp(BlockDriverState *bs, const char *snapshot_id, @@ -956,15 +981,15 @@ int qcow2_snapshot_load_tmp(BlockDriverState *bs, void qcow2_free_snapshots(BlockDriverState *bs); int coroutine_fn GRAPH_RDLOCK qcow2_read_snapshots(BlockDriverState *bs, Error **errp); -int qcow2_write_snapshots(BlockDriverState *bs); +int GRAPH_RDLOCK qcow2_write_snapshots(BlockDriverState *bs); int coroutine_fn GRAPH_RDLOCK qcow2_check_read_snapshot_table(BlockDriverState *bs, BdrvCheckResult *result, BdrvCheckMode fix); -int coroutine_fn qcow2_check_fix_snapshot_table(BlockDriverState *bs, - BdrvCheckResult *result, - BdrvCheckMode fix); +int coroutine_fn GRAPH_RDLOCK +qcow2_check_fix_snapshot_table(BlockDriverState *bs, BdrvCheckResult *result, + BdrvCheckMode fix); /* qcow2-cache.c functions */ Qcow2Cache *qcow2_cache_create(BlockDriverState *bs, int num_tables, @@ -972,19 +997,23 @@ Qcow2Cache *qcow2_cache_create(BlockDriverState *bs, int num_tables, int qcow2_cache_destroy(Qcow2Cache *c); void qcow2_cache_entry_mark_dirty(Qcow2Cache *c, void *table); -int qcow2_cache_flush(BlockDriverState *bs, Qcow2Cache *c); -int qcow2_cache_write(BlockDriverState *bs, Qcow2Cache *c); -int qcow2_cache_set_dependency(BlockDriverState *bs, Qcow2Cache *c, - Qcow2Cache *dependency); +int GRAPH_RDLOCK qcow2_cache_flush(BlockDriverState *bs, Qcow2Cache *c); +int GRAPH_RDLOCK qcow2_cache_write(BlockDriverState *bs, Qcow2Cache *c); +int GRAPH_RDLOCK qcow2_cache_set_dependency(BlockDriverState *bs, Qcow2Cache *c, + Qcow2Cache *dependency); void qcow2_cache_depends_on_flush(Qcow2Cache *c); void qcow2_cache_clean_unused(Qcow2Cache *c); -int qcow2_cache_empty(BlockDriverState *bs, Qcow2Cache *c); +int GRAPH_RDLOCK qcow2_cache_empty(BlockDriverState *bs, Qcow2Cache *c); + +int GRAPH_RDLOCK +qcow2_cache_get(BlockDriverState *bs, Qcow2Cache *c, uint64_t offset, + void **table); + +int GRAPH_RDLOCK +qcow2_cache_get_empty(BlockDriverState *bs, Qcow2Cache *c, uint64_t offset, + void **table); -int qcow2_cache_get(BlockDriverState *bs, Qcow2Cache *c, uint64_t offset, - void **table); -int qcow2_cache_get_empty(BlockDriverState *bs, Qcow2Cache *c, uint64_t offset, - void **table); void qcow2_cache_put(Qcow2Cache *c, void **table); void *qcow2_cache_is_table_offset(Qcow2Cache *c, uint64_t offset); void qcow2_cache_discard(Qcow2Cache *c, void *table); @@ -998,17 +1027,22 @@ bool coroutine_fn GRAPH_RDLOCK qcow2_load_dirty_bitmaps(BlockDriverState *bs, bool *header_updated, Error **errp); bool qcow2_get_bitmap_info_list(BlockDriverState *bs, Qcow2BitmapInfoList **info_list, Error **errp); -int qcow2_reopen_bitmaps_rw(BlockDriverState *bs, Error **errp); +int GRAPH_RDLOCK qcow2_reopen_bitmaps_rw(BlockDriverState *bs, Error **errp); +int GRAPH_RDLOCK qcow2_reopen_bitmaps_ro(BlockDriverState *bs, Error **errp); int coroutine_fn qcow2_truncate_bitmaps_check(BlockDriverState *bs, Error **errp); -bool qcow2_store_persistent_dirty_bitmaps(BlockDriverState *bs, - bool release_stored, Error **errp); -int qcow2_reopen_bitmaps_ro(BlockDriverState *bs, Error **errp); + +bool GRAPH_RDLOCK +qcow2_store_persistent_dirty_bitmaps(BlockDriverState *bs, bool release_stored, + Error **errp); + bool coroutine_fn GRAPH_RDLOCK qcow2_co_can_store_new_dirty_bitmap(BlockDriverState *bs, const char *name, uint32_t granularity, Error **errp); -int coroutine_fn qcow2_co_remove_persistent_dirty_bitmap(BlockDriverState *bs, - const char *name, - Error **errp); + +int coroutine_fn GRAPH_RDLOCK +qcow2_co_remove_persistent_dirty_bitmap(BlockDriverState *bs, const char *name, + Error **errp); + bool qcow2_supports_persistent_dirty_bitmap(BlockDriverState *bs); uint64_t qcow2_get_persistent_dirty_bitmap_size(BlockDriverState *bs, uint32_t cluster_size); diff --git a/block/replication.c b/block/replication.c index 107445d0ce..3459f50669 100644 --- a/block/replication.c +++ b/block/replication.c @@ -307,13 +307,16 @@ out: return ret; } -static void secondary_do_checkpoint(BlockDriverState *bs, Error **errp) +static void GRAPH_UNLOCKED +secondary_do_checkpoint(BlockDriverState *bs, Error **errp) { BDRVReplicationState *s = bs->opaque; BdrvChild *active_disk = bs->file; Error *local_err = NULL; int ret; + GRAPH_RDLOCK_GUARD_MAINLOOP(); + if (!s->backup_job) { error_setg(errp, "Backup job was cancelled unexpectedly"); return; @@ -531,13 +534,16 @@ static void replication_start(ReplicationState *rs, ReplicationMode mode, /* Must be true, or the bdrv_getlength() calls would have failed */ assert(active_disk->bs->drv && hidden_disk->bs->drv); + bdrv_graph_rdlock_main_loop(); if (!active_disk->bs->drv->bdrv_make_empty || !hidden_disk->bs->drv->bdrv_make_empty) { error_setg(errp, "Active disk or hidden disk doesn't support make_empty"); aio_context_release(aio_context); + bdrv_graph_rdunlock_main_loop(); return; } + bdrv_graph_rdunlock_main_loop(); /* reopen the backing file in r/w mode */ reopen_backing_file(bs, true, &local_err); diff --git a/include/block/block-global-state.h b/include/block/block-global-state.h index 9dc35133a8..794ef34ded 100644 --- a/include/block/block-global-state.h +++ b/include/block/block-global-state.h @@ -138,7 +138,7 @@ void GRAPH_RDLOCK bdrv_refresh_limits(BlockDriverState *bs, Transaction *tran, Error **errp); int bdrv_commit(BlockDriverState *bs); -int bdrv_make_empty(BdrvChild *c, Error **errp); +int GRAPH_RDLOCK bdrv_make_empty(BdrvChild *c, Error **errp); int bdrv_change_backing_file(BlockDriverState *bs, const char *backing_file, const char *backing_fmt, bool warn); void bdrv_register(BlockDriver *bdrv); diff --git a/include/block/block_int-common.h b/include/block/block_int-common.h index c8661775f4..d971d73f8f 100644 --- a/include/block/block_int-common.h +++ b/include/block/block_int-common.h @@ -264,7 +264,7 @@ struct BlockDriver { BlockDriverAmendStatusCB *status_cb, void *cb_opaque, bool force, Error **errp); - int (*bdrv_make_empty)(BlockDriverState *bs); + int GRAPH_RDLOCK_PTR (*bdrv_make_empty)(BlockDriverState *bs); /* * Refreshes the bs->exact_filename field. If that is impossible, From de4fed6f4ef7f2f1a1bce50a2cbbb7fdd397b7ec Mon Sep 17 00:00:00 2001 From: Kevin Wolf Date: Fri, 29 Sep 2023 16:51:50 +0200 Subject: [PATCH 0635/1077] qcow2: Mark qcow2_inactivate() and callers GRAPH_RDLOCK This adds GRAPH_RDLOCK annotations to declare that callers of qcow2_inactivate() need to hold a reader lock for the graph because it calls bdrv_get_device_or_node_name(), which accesses the parents list of a node. qcow2_do_close() is a bit strange because it is called from different contexts. If close_data_file = true, we know that we were called from non-coroutine main loop context (more specifically, we're coming from qcow2_close()) and can safely drop the reader lock temporarily with bdrv_graph_rdunlock_main_loop() and acquire the writer lock. Signed-off-by: Kevin Wolf Message-ID: <20230929145157.45443-16-kwolf@redhat.com> Reviewed-by: Stefan Hajnoczi Signed-off-by: Kevin Wolf --- block/qcow2.c | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/block/qcow2.c b/block/qcow2.c index 137c036ea4..aa01d9e7b5 100644 --- a/block/qcow2.c +++ b/block/qcow2.c @@ -2737,14 +2737,12 @@ fail_nometa: return ret; } -static int qcow2_inactivate(BlockDriverState *bs) +static int GRAPH_RDLOCK qcow2_inactivate(BlockDriverState *bs) { BDRVQcow2State *s = bs->opaque; int ret, result = 0; Error *local_err = NULL; - assume_graph_lock(); /* FIXME */ - qcow2_store_persistent_dirty_bitmaps(bs, true, &local_err); if (local_err != NULL) { result = -EINVAL; @@ -2774,7 +2772,8 @@ static int qcow2_inactivate(BlockDriverState *bs) return result; } -static void qcow2_do_close(BlockDriverState *bs, bool close_data_file) +static void coroutine_mixed_fn GRAPH_RDLOCK +qcow2_do_close(BlockDriverState *bs, bool close_data_file) { BDRVQcow2State *s = bs->opaque; qemu_vfree(s->l1_table); @@ -2801,18 +2800,24 @@ static void qcow2_do_close(BlockDriverState *bs, bool close_data_file) g_free(s->image_backing_format); if (close_data_file && has_data_file(bs)) { + GLOBAL_STATE_CODE(); + bdrv_graph_rdunlock_main_loop(); bdrv_graph_wrlock(NULL); bdrv_unref_child(bs, s->data_file); bdrv_graph_wrunlock(); s->data_file = NULL; + bdrv_graph_rdlock_main_loop(); } qcow2_refcount_close(bs); qcow2_free_snapshots(bs); } -static void qcow2_close(BlockDriverState *bs) +static void GRAPH_UNLOCKED qcow2_close(BlockDriverState *bs) { + GLOBAL_STATE_CODE(); + GRAPH_RDLOCK_GUARD_MAINLOOP(); + qcow2_do_close(bs, true); } From 5155853e90388d9c8c5370bcbe1b6484a92ee710 Mon Sep 17 00:00:00 2001 From: Kevin Wolf Date: Fri, 29 Sep 2023 16:51:51 +0200 Subject: [PATCH 0636/1077] qcow2: Mark check_constraints_on_bitmap() GRAPH_RDLOCK It still has an assume_graph_lock() call, but all of its callers are now properly annotated to hold the graph lock. Update the function to be GRAPH_RDLOCK as well and remove the assume_graph_lock(). Signed-off-by: Kevin Wolf Message-ID: <20230929145157.45443-17-kwolf@redhat.com> Reviewed-by: Stefan Hajnoczi Signed-off-by: Kevin Wolf --- block/qcow2-bitmap.c | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/block/qcow2-bitmap.c b/block/qcow2-bitmap.c index 6996eab9e1..3058309c47 100644 --- a/block/qcow2-bitmap.c +++ b/block/qcow2-bitmap.c @@ -156,18 +156,15 @@ static int64_t get_bitmap_bytes_needed(int64_t len, uint32_t granularity) return DIV_ROUND_UP(num_bits, 8); } -static int check_constraints_on_bitmap(BlockDriverState *bs, - const char *name, - uint32_t granularity, - Error **errp) +static int GRAPH_RDLOCK +check_constraints_on_bitmap(BlockDriverState *bs, const char *name, + uint32_t granularity, Error **errp) { BDRVQcow2State *s = bs->opaque; int granularity_bits = ctz32(granularity); int64_t len = bdrv_getlength(bs); int64_t bitmap_bytes; - assume_graph_lock(); /* FIXME */ - assert(granularity > 0); assert((granularity & (granularity - 1)) == 0); From 277f2007ce187a6ff467579cb016824f80a2be10 Mon Sep 17 00:00:00 2001 From: Kevin Wolf Date: Fri, 29 Sep 2023 16:51:52 +0200 Subject: [PATCH 0637/1077] block: Mark bdrv_op_is_blocked() and callers GRAPH_RDLOCK This adds GRAPH_RDLOCK annotations to declare that callers of bdrv_op_is_blocked() need to hold a reader lock for the graph because it calls bdrv_get_device_or_node_name(), which accesses the parents list of a node. Signed-off-by: Kevin Wolf Message-ID: <20230929145157.45443-18-kwolf@redhat.com> Reviewed-by: Stefan Hajnoczi Signed-off-by: Kevin Wolf --- block.c | 2 -- block/block-backend.c | 1 + block/commit.c | 1 + block/monitor/block-hmp-cmds.c | 3 +++ block/qapi-sysemu.c | 9 +++++++-- blockdev.c | 15 +++++++++++++++ include/block/block-global-state.h | 4 +++- 7 files changed, 30 insertions(+), 5 deletions(-) diff --git a/block.c b/block.c index d1a3466069..fd348f5069 100644 --- a/block.c +++ b/block.c @@ -7251,8 +7251,6 @@ bool bdrv_op_is_blocked(BlockDriverState *bs, BlockOpType op, Error **errp) BdrvOpBlocker *blocker; GLOBAL_STATE_CODE(); - assume_graph_lock(); /* FIXME */ - assert((int) op >= 0 && op < BLOCK_OP_TYPE_MAX); if (!QLIST_EMPTY(&bs->op_blockers[op])) { blocker = QLIST_FIRST(&bs->op_blockers[op]); diff --git a/block/block-backend.c b/block/block-backend.c index fd10fcc2d0..39aac1bbce 100644 --- a/block/block-backend.c +++ b/block/block-backend.c @@ -2388,6 +2388,7 @@ bool blk_op_is_blocked(BlockBackend *blk, BlockOpType op, Error **errp) { BlockDriverState *bs = blk_bs(blk); GLOBAL_STATE_CODE(); + GRAPH_RDLOCK_GUARD_MAINLOOP(); if (!bs) { return false; diff --git a/block/commit.c b/block/commit.c index aa45beb0f0..43d1de7577 100644 --- a/block/commit.c +++ b/block/commit.c @@ -434,6 +434,7 @@ int bdrv_commit(BlockDriverState *bs) Error *local_err = NULL; GLOBAL_STATE_CODE(); + GRAPH_RDLOCK_GUARD_MAINLOOP(); if (!drv) return -ENOMEDIUM; diff --git a/block/monitor/block-hmp-cmds.c b/block/monitor/block-hmp-cmds.c index 6b7d7dd072..7645c7e5fb 100644 --- a/block/monitor/block-hmp-cmds.c +++ b/block/monitor/block-hmp-cmds.c @@ -144,6 +144,9 @@ void hmp_drive_del(Monitor *mon, const QDict *qdict) AioContext *aio_context; Error *local_err = NULL; + GLOBAL_STATE_CODE(); + GRAPH_RDLOCK_GUARD_MAINLOOP(); + bs = bdrv_find_node(id); if (bs) { qmp_blockdev_del(id, &local_err); diff --git a/block/qapi-sysemu.c b/block/qapi-sysemu.c index e885a64c32..3f614cbc04 100644 --- a/block/qapi-sysemu.c +++ b/block/qapi-sysemu.c @@ -169,14 +169,16 @@ void qmp_blockdev_close_tray(const char *device, } } -static void blockdev_remove_medium(const char *device, const char *id, - Error **errp) +static void GRAPH_UNLOCKED +blockdev_remove_medium(const char *device, const char *id, Error **errp) { BlockBackend *blk; BlockDriverState *bs; AioContext *aio_context; bool has_attached_device; + GLOBAL_STATE_CODE(); + blk = qmp_get_blk(device, id, errp); if (!blk) { return; @@ -205,9 +207,12 @@ static void blockdev_remove_medium(const char *device, const char *id, aio_context = bdrv_get_aio_context(bs); aio_context_acquire(aio_context); + bdrv_graph_rdlock_main_loop(); if (bdrv_op_is_blocked(bs, BLOCK_OP_TYPE_EJECT, errp)) { + bdrv_graph_rdunlock_main_loop(); goto out; } + bdrv_graph_rdunlock_main_loop(); blk_remove_bs(blk); diff --git a/blockdev.c b/blockdev.c index 51c58dd432..a01c62596b 100644 --- a/blockdev.c +++ b/blockdev.c @@ -1696,9 +1696,12 @@ static void drive_backup_action(DriveBackup *backup, } /* Early check to avoid creating target */ + bdrv_graph_rdlock_main_loop(); if (bdrv_op_is_blocked(bs, BLOCK_OP_TYPE_BACKUP_SOURCE, errp)) { + bdrv_graph_rdunlock_main_loop(); goto out; } + bdrv_graph_rdunlock_main_loop(); flags = bs->open_flags | BDRV_O_RDWR; @@ -2360,10 +2363,13 @@ void coroutine_fn qmp_block_resize(const char *device, const char *node_name, return; } + bdrv_graph_co_rdlock(); if (bdrv_op_is_blocked(bs, BLOCK_OP_TYPE_RESIZE, NULL)) { error_setg(errp, QERR_DEVICE_IN_USE, device); + bdrv_graph_co_rdunlock(); return; } + bdrv_graph_co_rdunlock(); blk = blk_co_new_with_bs(bs, BLK_PERM_RESIZE, BLK_PERM_ALL, errp); if (!blk) { @@ -2487,13 +2493,16 @@ void qmp_block_stream(const char *job_id, const char *device, * Check for op blockers in the whole chain between bs and base (or bottom) */ iter_end = bottom ? bdrv_filter_or_cow_bs(bottom_bs) : base_bs; + bdrv_graph_rdlock_main_loop(); for (iter = bs; iter && iter != iter_end; iter = bdrv_filter_or_cow_bs(iter)) { if (bdrv_op_is_blocked(iter, BLOCK_OP_TYPE_STREAM, errp)) { + bdrv_graph_rdunlock_main_loop(); goto out; } } + bdrv_graph_rdunlock_main_loop(); /* if we are streaming the entire chain, the result will have no backing * file, and specifying one is therefore an error */ @@ -3021,9 +3030,12 @@ void qmp_drive_mirror(DriveMirror *arg, Error **errp) } /* Early check to avoid creating target */ + bdrv_graph_rdlock_main_loop(); if (bdrv_op_is_blocked(bs, BLOCK_OP_TYPE_MIRROR_SOURCE, errp)) { + bdrv_graph_rdunlock_main_loop(); return; } + bdrv_graph_rdunlock_main_loop(); aio_context = bdrv_get_aio_context(bs); aio_context_acquire(aio_context); @@ -3409,9 +3421,12 @@ void qmp_change_backing_file(const char *device, /* even though we are not necessarily operating on bs, we need it to * determine if block ops are currently prohibited on the chain */ + bdrv_graph_rdlock_main_loop(); if (bdrv_op_is_blocked(bs, BLOCK_OP_TYPE_CHANGE, errp)) { + bdrv_graph_rdunlock_main_loop(); goto out; } + bdrv_graph_rdunlock_main_loop(); /* final sanity check */ if (!bdrv_chain_contains(bs, image_bs)) { diff --git a/include/block/block-global-state.h b/include/block/block-global-state.h index 794ef34ded..6bfafe781d 100644 --- a/include/block/block-global-state.h +++ b/include/block/block-global-state.h @@ -246,7 +246,9 @@ bdrv_attach_child(BlockDriverState *parent_bs, BdrvChildRole child_role, Error **errp); -bool bdrv_op_is_blocked(BlockDriverState *bs, BlockOpType op, Error **errp); +bool GRAPH_RDLOCK +bdrv_op_is_blocked(BlockDriverState *bs, BlockOpType op, Error **errp); + void bdrv_op_block(BlockDriverState *bs, BlockOpType op, Error *reason); void bdrv_op_unblock(BlockDriverState *bs, BlockOpType op, Error *reason); void bdrv_op_block_all(BlockDriverState *bs, Error *reason); From 018f9dea9c905506c49f8f37c018470dddfc50f1 Mon Sep 17 00:00:00 2001 From: Kevin Wolf Date: Fri, 29 Sep 2023 16:51:53 +0200 Subject: [PATCH 0638/1077] block: Mark bdrv_apply_auto_read_only() and callers GRAPH_RDLOCK This adds GRAPH_RDLOCK annotations to declare that callers of bdrv_apply_auto_read_only() need to hold a reader lock for the graph because it calls bdrv_can_set_read_only(), which indirectly accesses the parents list of a node. Signed-off-by: Kevin Wolf Message-ID: <20230929145157.45443-19-kwolf@redhat.com> Reviewed-by: Stefan Hajnoczi Signed-off-by: Kevin Wolf --- block.c | 4 ++-- block/bochs.c | 2 ++ block/cloop.c | 2 ++ block/curl.c | 2 ++ block/dmg.c | 2 ++ block/gluster.c | 2 ++ block/iscsi.c | 2 ++ block/nbd.c | 3 ++- block/rbd.c | 2 ++ include/block/block-io.h | 6 ++++-- 10 files changed, 22 insertions(+), 5 deletions(-) diff --git a/block.c b/block.c index fd348f5069..2ac7406c77 100644 --- a/block.c +++ b/block.c @@ -320,8 +320,6 @@ int bdrv_apply_auto_read_only(BlockDriverState *bs, const char *errmsg, int ret = 0; IO_CODE(); - assume_graph_lock(); /* FIXME */ - if (!(bs->open_flags & BDRV_O_RDWR)) { return 0; } @@ -1908,7 +1906,9 @@ static int bdrv_open_common(BlockDriverState *bs, BlockBackend *file, if (use_bdrv_whitelist && !bdrv_is_whitelisted(drv, ro)) { if (!ro && bdrv_is_whitelisted(drv, true)) { + bdrv_graph_rdlock_main_loop(); ret = bdrv_apply_auto_read_only(bs, NULL, NULL); + bdrv_graph_rdunlock_main_loop(); } else { ret = -ENOTSUP; } diff --git a/block/bochs.c b/block/bochs.c index 66e7a58e5e..8c659fa9b9 100644 --- a/block/bochs.c +++ b/block/bochs.c @@ -106,7 +106,9 @@ static int bochs_open(BlockDriverState *bs, QDict *options, int flags, int ret; /* No write support yet */ + bdrv_graph_rdlock_main_loop(); ret = bdrv_apply_auto_read_only(bs, NULL, errp); + bdrv_graph_rdunlock_main_loop(); if (ret < 0) { return ret; } diff --git a/block/cloop.c b/block/cloop.c index 835a0fe3da..773d7918be 100644 --- a/block/cloop.c +++ b/block/cloop.c @@ -67,7 +67,9 @@ static int cloop_open(BlockDriverState *bs, QDict *options, int flags, uint32_t offsets_size, max_compressed_block_size = 1, i; int ret; + bdrv_graph_rdlock_main_loop(); ret = bdrv_apply_auto_read_only(bs, NULL, errp); + bdrv_graph_rdunlock_main_loop(); if (ret < 0) { return ret; } diff --git a/block/curl.c b/block/curl.c index 0fc42d03d7..419f7c89ef 100644 --- a/block/curl.c +++ b/block/curl.c @@ -696,8 +696,10 @@ static int curl_open(BlockDriverState *bs, QDict *options, int flags, const char *protocol_delimiter; int ret; + bdrv_graph_rdlock_main_loop(); ret = bdrv_apply_auto_read_only(bs, "curl driver does not support writes", errp); + bdrv_graph_rdunlock_main_loop(); if (ret < 0) { return ret; } diff --git a/block/dmg.c b/block/dmg.c index 06a0244a9c..38ee72bbe5 100644 --- a/block/dmg.c +++ b/block/dmg.c @@ -452,7 +452,9 @@ static int dmg_open(BlockDriverState *bs, QDict *options, int flags, int64_t offset; int ret; + bdrv_graph_rdlock_main_loop(); ret = bdrv_apply_auto_read_only(bs, NULL, errp); + bdrv_graph_rdunlock_main_loop(); if (ret < 0) { return ret; } diff --git a/block/gluster.c b/block/gluster.c index ad5fadbe79..cc74af06dc 100644 --- a/block/gluster.c +++ b/block/gluster.c @@ -863,11 +863,13 @@ static int qemu_gluster_open(BlockDriverState *bs, QDict *options, if (ret == -EACCES || ret == -EROFS) { /* Try to degrade to read-only, but if it doesn't work, still use the * normal error message. */ + bdrv_graph_rdlock_main_loop(); if (bdrv_apply_auto_read_only(bs, NULL, NULL) == 0) { open_flags = (open_flags & ~O_RDWR) | O_RDONLY; s->fd = glfs_open(s->glfs, gconf->path, open_flags); ret = s->fd ? 0 : -errno; } + bdrv_graph_rdunlock_main_loop(); } s->supports_seek_data = qemu_gluster_test_seek(s->fd); diff --git a/block/iscsi.c b/block/iscsi.c index 5640c8b565..2ff14b7472 100644 --- a/block/iscsi.c +++ b/block/iscsi.c @@ -1925,7 +1925,9 @@ static int iscsi_open(BlockDriverState *bs, QDict *options, int flags, /* Check the write protect flag of the LUN if we want to write */ if (iscsilun->type == TYPE_DISK && (flags & BDRV_O_RDWR) && iscsilun->write_protected) { + bdrv_graph_rdlock_main_loop(); ret = bdrv_apply_auto_read_only(bs, "LUN is write protected", errp); + bdrv_graph_rdunlock_main_loop(); if (ret < 0) { goto out; } diff --git a/block/nbd.c b/block/nbd.c index 52ebc8b2f5..b9d4f935e0 100644 --- a/block/nbd.c +++ b/block/nbd.c @@ -275,7 +275,8 @@ static bool nbd_client_will_reconnect(BDRVNBDState *s) * Return failure if the server's advertised options are incompatible with the * client's needs. */ -static int nbd_handle_updated_info(BlockDriverState *bs, Error **errp) +static int coroutine_fn GRAPH_RDLOCK +nbd_handle_updated_info(BlockDriverState *bs, Error **errp) { BDRVNBDState *s = (BDRVNBDState *)bs->opaque; int ret; diff --git a/block/rbd.c b/block/rbd.c index 073bc92e39..84bb2fa5d7 100644 --- a/block/rbd.c +++ b/block/rbd.c @@ -1168,7 +1168,9 @@ static int qemu_rbd_open(BlockDriverState *bs, QDict *options, int flags, /* If we are using an rbd snapshot, we must be r/o, otherwise * leave as-is */ if (s->snap != NULL) { + bdrv_graph_rdlock_main_loop(); r = bdrv_apply_auto_read_only(bs, "rbd snapshots are read-only", errp); + bdrv_graph_rdunlock_main_loop(); if (r < 0) { goto failed_post_open; } diff --git a/include/block/block-io.h b/include/block/block-io.h index 2c0c7b1906..e051e9bed6 100644 --- a/include/block/block-io.h +++ b/include/block/block-io.h @@ -163,8 +163,10 @@ bdrv_is_allocated_above(BlockDriverState *bs, BlockDriverState *base, int coroutine_fn GRAPH_RDLOCK bdrv_co_is_zero_fast(BlockDriverState *bs, int64_t offset, int64_t bytes); -int bdrv_apply_auto_read_only(BlockDriverState *bs, const char *errmsg, - Error **errp); +int GRAPH_RDLOCK +bdrv_apply_auto_read_only(BlockDriverState *bs, const char *errmsg, + Error **errp); + bool bdrv_is_read_only(BlockDriverState *bs); bool bdrv_is_writable(BlockDriverState *bs); bool bdrv_is_sg(BlockDriverState *bs); From 3574499a1e5e420c3e72d0e283cfb2b13bce672e Mon Sep 17 00:00:00 2001 From: Kevin Wolf Date: Fri, 29 Sep 2023 16:51:54 +0200 Subject: [PATCH 0639/1077] block: Mark bdrv_get_specific_info() and callers GRAPH_RDLOCK This adds GRAPH_RDLOCK annotations to declare that callers of bdrv_get_specific_info() need to hold a reader lock for the graph. This removes an assume_graph_lock() call in vmdk's implementation. Signed-off-by: Kevin Wolf Message-ID: <20230929145157.45443-20-kwolf@redhat.com> Reviewed-by: Stefan Hajnoczi Signed-off-by: Kevin Wolf --- block/vmdk.c | 6 ++---- include/block/block-io.h | 5 +++-- include/block/block_int-common.h | 4 ++-- qemu-io-cmds.c | 3 +++ 4 files changed, 10 insertions(+), 8 deletions(-) diff --git a/block/vmdk.c b/block/vmdk.c index e50965bc37..8a3b152798 100644 --- a/block/vmdk.c +++ b/block/vmdk.c @@ -2990,16 +2990,14 @@ vmdk_co_check(BlockDriverState *bs, BdrvCheckResult *result, BdrvCheckMode fix) return ret; } -static ImageInfoSpecific *vmdk_get_specific_info(BlockDriverState *bs, - Error **errp) +static ImageInfoSpecific * GRAPH_RDLOCK +vmdk_get_specific_info(BlockDriverState *bs, Error **errp) { int i; BDRVVmdkState *s = bs->opaque; ImageInfoSpecific *spec_info = g_new0(ImageInfoSpecific, 1); VmdkExtentInfoList **tail; - assume_graph_lock(); /* FIXME */ - *spec_info = (ImageInfoSpecific){ .type = IMAGE_INFO_SPECIFIC_KIND_VMDK, .u = { diff --git a/include/block/block-io.h b/include/block/block-io.h index e051e9bed6..ad270b6ad2 100644 --- a/include/block/block-io.h +++ b/include/block/block-io.h @@ -198,8 +198,9 @@ bdrv_co_get_info(BlockDriverState *bs, BlockDriverInfo *bdi); int co_wrapper_mixed_bdrv_rdlock bdrv_get_info(BlockDriverState *bs, BlockDriverInfo *bdi); -ImageInfoSpecific *bdrv_get_specific_info(BlockDriverState *bs, - Error **errp); +ImageInfoSpecific * GRAPH_RDLOCK +bdrv_get_specific_info(BlockDriverState *bs, Error **errp); + BlockStatsSpecific *bdrv_get_specific_stats(BlockDriverState *bs); void bdrv_round_to_subclusters(BlockDriverState *bs, int64_t offset, int64_t bytes, diff --git a/include/block/block_int-common.h b/include/block/block_int-common.h index d971d73f8f..024262b5a2 100644 --- a/include/block/block_int-common.h +++ b/include/block/block_int-common.h @@ -728,8 +728,8 @@ struct BlockDriver { int coroutine_fn GRAPH_RDLOCK_PTR (*bdrv_co_get_info)( BlockDriverState *bs, BlockDriverInfo *bdi); - ImageInfoSpecific *(*bdrv_get_specific_info)(BlockDriverState *bs, - Error **errp); + ImageInfoSpecific * GRAPH_RDLOCK_PTR (*bdrv_get_specific_info)( + BlockDriverState *bs, Error **errp); BlockStatsSpecific *(*bdrv_get_specific_stats)(BlockDriverState *bs); int coroutine_fn GRAPH_RDLOCK_PTR (*bdrv_co_save_vmstate)( diff --git a/qemu-io-cmds.c b/qemu-io-cmds.c index 3f75d2f5a6..f5d7202a13 100644 --- a/qemu-io-cmds.c +++ b/qemu-io-cmds.c @@ -2037,6 +2037,9 @@ static int info_f(BlockBackend *blk, int argc, char **argv) char s1[64], s2[64]; int ret; + GLOBAL_STATE_CODE(); + GRAPH_RDLOCK_GUARD_MAINLOOP(); + if (bs->drv && bs->drv->format_name) { printf("format name: %s\n", bs->drv->format_name); } From b59b466071391cb76b39584e1558be2d0797c054 Mon Sep 17 00:00:00 2001 From: Kevin Wolf Date: Fri, 29 Sep 2023 16:51:55 +0200 Subject: [PATCH 0640/1077] block: Protect bs->parents with graph_lock Almost all functions that access the parent link already take the graph lock now. Add locking to the remaining user in a test case and finally annotate the struct field itself as protected by the graph lock. Signed-off-by: Kevin Wolf Message-ID: <20230929145157.45443-21-kwolf@redhat.com> Reviewed-by: Stefan Hajnoczi Signed-off-by: Kevin Wolf --- include/block/block_int-common.h | 4 ++-- tests/unit/test-block-iothread.c | 5 +++++ 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/include/block/block_int-common.h b/include/block/block_int-common.h index 024262b5a2..0e37acd976 100644 --- a/include/block/block_int-common.h +++ b/include/block/block_int-common.h @@ -1043,7 +1043,7 @@ struct BdrvChild { bool quiesced_parent; QLIST_ENTRY(BdrvChild) next; - QLIST_ENTRY(BdrvChild) next_parent; + QLIST_ENTRY(BdrvChild GRAPH_RDLOCK_PTR) next_parent; }; /* @@ -1180,7 +1180,7 @@ struct BlockDriverState { BdrvChild *backing; BdrvChild *file; - QLIST_HEAD(, BdrvChild) parents; + QLIST_HEAD(, BdrvChild GRAPH_RDLOCK_PTR) parents; QDict *options; QDict *explicit_options; diff --git a/tests/unit/test-block-iothread.c b/tests/unit/test-block-iothread.c index 151049bda5..9b15d2768c 100644 --- a/tests/unit/test-block-iothread.c +++ b/tests/unit/test-block-iothread.c @@ -471,11 +471,16 @@ static void test_sync_op(const void *opaque) BlockDriverState *bs; BdrvChild *c; + GLOBAL_STATE_CODE(); + blk = blk_new(qemu_get_aio_context(), BLK_PERM_ALL, BLK_PERM_ALL); bs = bdrv_new_open_driver(&bdrv_test, "base", BDRV_O_RDWR, &error_abort); bs->total_sectors = 65536 / BDRV_SECTOR_SIZE; blk_insert_bs(blk, bs, &error_abort); + + bdrv_graph_rdlock_main_loop(); c = QLIST_FIRST(&bs->parents); + bdrv_graph_rdunlock_main_loop(); blk_set_aio_context(blk, ctx, &error_abort); aio_context_acquire(ctx); From 680e0cc40c5830ebcbfa0bce99bf932e1a4cf6c6 Mon Sep 17 00:00:00 2001 From: Kevin Wolf Date: Fri, 29 Sep 2023 16:51:56 +0200 Subject: [PATCH 0641/1077] block: Protect bs->children with graph_lock Almost all functions that access the child links already take the graph lock now. Add locking to the remaining users and finally annotate the struct field itself as protected by the graph lock. Signed-off-by: Kevin Wolf Message-ID: <20230929145157.45443-22-kwolf@redhat.com> Reviewed-by: Stefan Hajnoczi Signed-off-by: Kevin Wolf --- block.c | 2 ++ block/replication.c | 3 ++- include/block/block_int-common.h | 4 ++-- tests/unit/test-bdrv-drain.c | 4 ++++ 4 files changed, 10 insertions(+), 3 deletions(-) diff --git a/block.c b/block.c index 2ac7406c77..f9cf05ddcf 100644 --- a/block.c +++ b/block.c @@ -2973,6 +2973,8 @@ static void bdrv_child_free(BdrvChild *child) { assert(!child->bs); GLOBAL_STATE_CODE(); + GRAPH_RDLOCK_GUARD_MAINLOOP(); + assert(!child->next.le_prev); /* not in children list */ g_free(child->name); diff --git a/block/replication.c b/block/replication.c index 3459f50669..d522c7396f 100644 --- a/block/replication.c +++ b/block/replication.c @@ -430,7 +430,8 @@ static void backup_job_completed(void *opaque, int ret) backup_job_cleanup(bs); } -static bool check_top_bs(BlockDriverState *top_bs, BlockDriverState *bs) +static bool GRAPH_RDLOCK +check_top_bs(BlockDriverState *top_bs, BlockDriverState *bs) { BdrvChild *child; diff --git a/include/block/block_int-common.h b/include/block/block_int-common.h index 0e37acd976..b8d9d24f39 100644 --- a/include/block/block_int-common.h +++ b/include/block/block_int-common.h @@ -1042,7 +1042,7 @@ struct BdrvChild { */ bool quiesced_parent; - QLIST_ENTRY(BdrvChild) next; + QLIST_ENTRY(BdrvChild GRAPH_RDLOCK_PTR) next; QLIST_ENTRY(BdrvChild GRAPH_RDLOCK_PTR) next_parent; }; @@ -1176,7 +1176,7 @@ struct BlockDriverState { * See also comment in include/block/block.h, to learn how backing and file * are connected with BdrvChildRole. */ - QLIST_HEAD(, BdrvChild) children; + QLIST_HEAD(, BdrvChild GRAPH_RDLOCK_PTR) children; BdrvChild *backing; BdrvChild *file; diff --git a/tests/unit/test-bdrv-drain.c b/tests/unit/test-bdrv-drain.c index d734829778..f67e9df01c 100644 --- a/tests/unit/test-bdrv-drain.c +++ b/tests/unit/test-bdrv-drain.c @@ -1034,9 +1034,13 @@ static void coroutine_fn test_co_delete_by_drain(void *opaque) blk_co_unref(blk); } else { BdrvChild *c, *next_c; + bdrv_graph_co_rdlock(); QLIST_FOREACH_SAFE(c, &bs->children, next, next_c) { + bdrv_graph_co_rdunlock(); bdrv_co_unref_child(bs, c); + bdrv_graph_co_rdlock(); } + bdrv_graph_co_rdunlock(); } dbdd->done = true; From e6e964b8b021446c8d3d1f91c0208f653e9ec92c Mon Sep 17 00:00:00 2001 From: Kevin Wolf Date: Fri, 29 Sep 2023 16:51:57 +0200 Subject: [PATCH 0642/1077] block: Add assertion for bdrv_graph_wrlock() bdrv_graph_wrlock() can't run in a coroutine (because it polls) and requires holding the BQL. We already have GLOBAL_STATE_CODE() to assert the latter. Assert the former as well and add a no_coroutine_fn marker. Signed-off-by: Kevin Wolf Message-ID: <20230929145157.45443-23-kwolf@redhat.com> Reviewed-by: Stefan Hajnoczi Signed-off-by: Kevin Wolf --- block/graph-lock.c | 3 ++- include/block/graph-lock.h | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/block/graph-lock.c b/block/graph-lock.c index 58a799065f..e5525ee2db 100644 --- a/block/graph-lock.c +++ b/block/graph-lock.c @@ -106,12 +106,13 @@ static uint32_t reader_count(void) return rd; } -void bdrv_graph_wrlock(BlockDriverState *bs) +void no_coroutine_fn bdrv_graph_wrlock(BlockDriverState *bs) { AioContext *ctx = NULL; GLOBAL_STATE_CODE(); assert(!qatomic_read(&has_writer)); + assert(!qemu_in_coroutine()); /* * Release only non-mainloop AioContext. The mainloop often relies on the diff --git a/include/block/graph-lock.h b/include/block/graph-lock.h index 7e04f98ff0..6f1cd12745 100644 --- a/include/block/graph-lock.h +++ b/include/block/graph-lock.h @@ -116,7 +116,8 @@ void unregister_aiocontext(AioContext *ctx); * This function polls. Callers must not hold the lock of any AioContext other * than the current one and the one of @bs. */ -void bdrv_graph_wrlock(BlockDriverState *bs) TSA_ACQUIRE(graph_lock) TSA_NO_TSA; +void no_coroutine_fn TSA_ACQUIRE(graph_lock) TSA_NO_TSA +bdrv_graph_wrlock(BlockDriverState *bs); /* * bdrv_graph_wrunlock: From cc46a7ef3b05242896016cd2928a123ed711272f Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Mon, 9 Oct 2023 10:37:25 +0200 Subject: [PATCH 0643/1077] contrib/vhost-user-gpu: Fix compiler warning when compiling with -Wshadow Rename some variables to avoid compiler warnings when compiling with -Wshadow=local. Signed-off-by: Thomas Huth Message-ID: <20231009083726.30301-1-thuth@redhat.com> Signed-off-by: Markus Armbruster --- contrib/vhost-user-gpu/vhost-user-gpu.c | 6 +++--- contrib/vhost-user-gpu/vugpu.h | 8 ++++---- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/contrib/vhost-user-gpu/vhost-user-gpu.c b/contrib/vhost-user-gpu/vhost-user-gpu.c index aa304475a0..bb41758e34 100644 --- a/contrib/vhost-user-gpu/vhost-user-gpu.c +++ b/contrib/vhost-user-gpu/vhost-user-gpu.c @@ -834,7 +834,7 @@ vg_resource_flush(VuGpu *g, .width = width, .height = height, }; - pixman_image_t *i = + pixman_image_t *img = pixman_image_create_bits(pixman_image_get_format(res->image), msg->payload.update.width, msg->payload.update.height, @@ -842,11 +842,11 @@ vg_resource_flush(VuGpu *g, payload.update.data), width * bpp); pixman_image_composite(PIXMAN_OP_SRC, - res->image, NULL, i, + res->image, NULL, img, extents->x1, extents->y1, 0, 0, 0, 0, width, height); - pixman_image_unref(i); + pixman_image_unref(img); vg_send_msg(g, msg, -1); g_free(msg); } diff --git a/contrib/vhost-user-gpu/vugpu.h b/contrib/vhost-user-gpu/vugpu.h index 509b679f03..654c392fbb 100644 --- a/contrib/vhost-user-gpu/vugpu.h +++ b/contrib/vhost-user-gpu/vugpu.h @@ -164,12 +164,12 @@ struct virtio_gpu_ctrl_command { }; #define VUGPU_FILL_CMD(out) do { \ - size_t s; \ - s = iov_to_buf(cmd->elem.out_sg, cmd->elem.out_num, 0, \ + size_t vugpufillcmd_s_ = \ + iov_to_buf(cmd->elem.out_sg, cmd->elem.out_num, 0, \ &out, sizeof(out)); \ - if (s != sizeof(out)) { \ + if (vugpufillcmd_s_ != sizeof(out)) { \ g_critical("%s: command size incorrect %zu vs %zu", \ - __func__, s, sizeof(out)); \ + __func__, vugpufillcmd_s_, sizeof(out)); \ return; \ } \ } while (0) From c35b2fb1fdc7f6926653cc6df289e5bd77ecbad3 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Wed, 11 Oct 2023 15:53:50 +0200 Subject: [PATCH 0644/1077] target/i386: fix shadowed variable pasto MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Commit a908985971a ("target/i386/seg_helper: introduce tss_set_busy", 2023-09-26) failed to use the tss_selector argument of the new function, which was therefore unused. This shows up as a #GP fault when booting old versions of 32-bit Linux. Fixes: a908985971a ("target/i386/seg_helper: introduce tss_set_busy", 2023-09-26) Signed-off-by: Paolo Bonzini Message-ID: <20231011135350.438492-1-pbonzini@redhat.com> Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Markus Armbruster --- target/i386/tcg/seg_helper.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/target/i386/tcg/seg_helper.c b/target/i386/tcg/seg_helper.c index 2b92aee207..eb29a1fd4e 100644 --- a/target/i386/tcg/seg_helper.c +++ b/target/i386/tcg/seg_helper.c @@ -229,7 +229,7 @@ static void tss_load_seg(CPUX86State *env, X86Seg seg_reg, int selector, static void tss_set_busy(CPUX86State *env, int tss_selector, bool value, uintptr_t retaddr) { - target_ulong ptr = env->gdt.base + (env->tr.selector & ~7); + target_ulong ptr = env->gdt.base + (tss_selector & ~7); uint32_t e2 = cpu_ldl_kernel_ra(env, ptr + 4, retaddr); if (value) { From f187cfefd2993a4d3632aa41b86a08e01beb053f Mon Sep 17 00:00:00 2001 From: Vladimir Sementsov-Ogievskiy Date: Fri, 6 Oct 2023 18:41:11 +0300 Subject: [PATCH 0645/1077] python/qemu/qmp/legacy: cmd(): drop cmd_id unused argument The argument is unused, let's drop it for now, as we are going to refactor the interface and don't want to refactor unused things. Signed-off-by: Vladimir Sementsov-Ogievskiy Reviewed-by: Eric Blake Message-id: 20231006154125.1068348-2-vsementsov@yandex-team.ru Signed-off-by: John Snow --- python/qemu/qmp/legacy.py | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/python/qemu/qmp/legacy.py b/python/qemu/qmp/legacy.py index e1e9383978..fe115e301c 100644 --- a/python/qemu/qmp/legacy.py +++ b/python/qemu/qmp/legacy.py @@ -195,20 +195,16 @@ class QEMUMonitorProtocol: ) def cmd(self, name: str, - args: Optional[Dict[str, object]] = None, - cmd_id: Optional[object] = None) -> QMPMessage: + args: Optional[Dict[str, object]] = None) -> QMPMessage: """ Build a QMP command and send it to the QMP Monitor. :param name: command name (string) :param args: command arguments (dict) - :param cmd_id: command id (dict, list, string or int) """ qmp_cmd: QMPMessage = {'execute': name} if args: qmp_cmd['arguments'] = args - if cmd_id: - qmp_cmd['id'] = cmd_id return self.cmd_obj(qmp_cmd) def command(self, cmd: str, **kwds: object) -> QMPReturnValue: From 2cee9ca97d12fe8c6aac92485386fa62efed2409 Mon Sep 17 00:00:00 2001 From: Vladimir Sementsov-Ogievskiy Date: Fri, 6 Oct 2023 18:41:12 +0300 Subject: [PATCH 0646/1077] qmp_shell.py: _fill_completion() use .command() instead of .cmd() We just want to ignore failure, so we don't need low level .cmd(). This helps further renaming .command() to .cmd(). Signed-off-by: Vladimir Sementsov-Ogievskiy Reviewed-by: Eric Blake Message-id: 20231006154125.1068348-3-vsementsov@yandex-team.ru Signed-off-by: John Snow --- python/qemu/qmp/qmp_shell.py | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/python/qemu/qmp/qmp_shell.py b/python/qemu/qmp/qmp_shell.py index 619ab42ced..988d79c01b 100644 --- a/python/qemu/qmp/qmp_shell.py +++ b/python/qemu/qmp/qmp_shell.py @@ -91,14 +91,21 @@ from subprocess import Popen import sys from typing import ( IO, + Dict, Iterator, List, NoReturn, Optional, Sequence, + cast, ) -from qemu.qmp import ConnectError, QMPError, SocketAddrT +from qemu.qmp import ( + ConnectError, + ExecuteError, + QMPError, + SocketAddrT, +) from qemu.qmp.legacy import ( QEMUMonitorProtocol, QMPBadPortError, @@ -194,11 +201,12 @@ class QMPShell(QEMUMonitorProtocol): super().close() def _fill_completion(self) -> None: - cmds = self.cmd('query-commands') - if 'error' in cmds: - return - for cmd in cmds['return']: - self._completer.append(cmd['name']) + try: + cmds = cast(List[Dict[str, str]], self.command('query-commands')) + for cmd in cmds: + self._completer.append(cmd['name']) + except ExecuteError: + pass def _completer_setup(self) -> None: self._completer = QMPCompleter() From 7f521b023bc288ef6bf3ea76add140f1db25169a Mon Sep 17 00:00:00 2001 From: Vladimir Sementsov-Ogievskiy Date: Fri, 6 Oct 2023 18:41:13 +0300 Subject: [PATCH 0647/1077] scripts/cpu-x86-uarch-abi.py: use .command() instead of .cmd() Here we don't expect a failure. In case of failure we'll crash on trying to access ['return']. Better is to use .command() that clearly raises on failure. Signed-off-by: Vladimir Sementsov-Ogievskiy Reviewed-by: Eric Blake Message-id: 20231006154125.1068348-4-vsementsov@yandex-team.ru Signed-off-by: John Snow --- scripts/cpu-x86-uarch-abi.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/scripts/cpu-x86-uarch-abi.py b/scripts/cpu-x86-uarch-abi.py index 82ff07582f..893afd1b35 100644 --- a/scripts/cpu-x86-uarch-abi.py +++ b/scripts/cpu-x86-uarch-abi.py @@ -69,7 +69,7 @@ sock = sys.argv[1] shell = QEMUMonitorProtocol(sock) shell.connect() -models = shell.cmd("query-cpu-definitions") +models = shell.command("query-cpu-definitions") # These QMP props don't correspond to CPUID fatures # so ignore them @@ -85,7 +85,7 @@ skip = [ names = [] -for model in models["return"]: +for model in models: if "alias-of" in model: continue names.append(model["name"]) @@ -93,12 +93,12 @@ for model in models["return"]: models = {} for name in sorted(names): - cpu = shell.cmd("query-cpu-model-expansion", - { "type": "static", - "model": { "name": name }}) + cpu = shell.command("query-cpu-model-expansion", + { "type": "static", + "model": { "name": name }}) got = {} - for (feature, present) in cpu["return"]["model"]["props"].items(): + for (feature, present) in cpu["model"]["props"].items(): if present and feature not in skip: got[feature] = True From 37274707f6f3868fae7e0055d9a703006fc142d0 Mon Sep 17 00:00:00 2001 From: Vladimir Sementsov-Ogievskiy Date: Fri, 6 Oct 2023 18:41:14 +0300 Subject: [PATCH 0648/1077] python: rename QEMUMonitorProtocol.cmd() to cmd_raw() Having cmd() and command() methods in one class doesn't look good. Rename cmd() to cmd_raw(), to show its meaning better. We also want to rename command() to cmd() in future, so this commit is a necessary step. Signed-off-by: Vladimir Sementsov-Ogievskiy Reviewed-by: Eric Blake Message-id: 20231006154125.1068348-5-vsementsov@yandex-team.ru Signed-off-by: John Snow --- python/qemu/machine/machine.py | 2 +- python/qemu/qmp/legacy.py | 4 ++-- tests/qemu-iotests/iotests.py | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/python/qemu/machine/machine.py b/python/qemu/machine/machine.py index d539e91268..50bba33729 100644 --- a/python/qemu/machine/machine.py +++ b/python/qemu/machine/machine.py @@ -702,7 +702,7 @@ class QEMUMachine: conv_keys = True qmp_args = self._qmp_args(conv_keys, args) - ret = self._qmp.cmd(cmd, args=qmp_args) + ret = self._qmp.cmd_raw(cmd, args=qmp_args) if cmd == 'quit' and 'error' not in ret and 'return' in ret: self._quit_issued = True return ret diff --git a/python/qemu/qmp/legacy.py b/python/qemu/qmp/legacy.py index fe115e301c..e5fa1ce9c4 100644 --- a/python/qemu/qmp/legacy.py +++ b/python/qemu/qmp/legacy.py @@ -194,8 +194,8 @@ class QEMUMonitorProtocol: ) ) - def cmd(self, name: str, - args: Optional[Dict[str, object]] = None) -> QMPMessage: + def cmd_raw(self, name: str, + args: Optional[Dict[str, object]] = None) -> QMPMessage: """ Build a QMP command and send it to the QMP Monitor. diff --git a/tests/qemu-iotests/iotests.py b/tests/qemu-iotests/iotests.py index 145c682713..0c061d8986 100644 --- a/tests/qemu-iotests/iotests.py +++ b/tests/qemu-iotests/iotests.py @@ -460,7 +460,7 @@ class QemuStorageDaemon: def qmp(self, cmd: str, args: Optional[Dict[str, object]] = None) \ -> QMPMessage: assert self._qmp is not None - return self._qmp.cmd(cmd, args) + return self._qmp.cmd_raw(cmd, args) def get_qmp(self) -> QEMUMonitorProtocol: assert self._qmp is not None From 684750ab4f8a3ad69512b71532408be3ac2547d4 Mon Sep 17 00:00:00 2001 From: Vladimir Sementsov-Ogievskiy Date: Fri, 6 Oct 2023 18:41:15 +0300 Subject: [PATCH 0649/1077] python/qemu: rename command() to cmd() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use a shorter name. We are going to move in iotests from qmp() to command() where possible. But command() is longer than qmp() and don't look better. Let's rename. You can simply grep for '\.command(' and for 'def command(' to check that everything is updated (command() in tests/docker/docker.py is unrelated). Signed-off-by: Vladimir Sementsov-Ogievskiy Reviewed-by: Daniel P. Berrangé Reviewed-by: Eric Blake Reviewed-by: Cédric Le Goater Reviewed-by: Juan Quintela Message-id: 20231006154125.1068348-6-vsementsov@yandex-team.ru [vsementsov: also update three occurrences in tests/avocado/machine_aspeed.py and keep r-b] Signed-off-by: John Snow --- docs/devel/testing.rst | 10 +- python/qemu/machine/machine.py | 8 +- python/qemu/qmp/legacy.py | 2 +- python/qemu/qmp/qmp_shell.py | 2 +- python/qemu/utils/qemu_ga_client.py | 2 +- python/qemu/utils/qom.py | 8 +- python/qemu/utils/qom_common.py | 2 +- python/qemu/utils/qom_fuse.py | 6 +- scripts/cpu-x86-uarch-abi.py | 8 +- scripts/device-crash-test | 8 +- scripts/render_block_graph.py | 8 +- tests/avocado/avocado_qemu/__init__.py | 4 +- tests/avocado/cpu_queries.py | 5 +- tests/avocado/hotplug_cpu.py | 10 +- tests/avocado/info_usernet.py | 4 +- tests/avocado/machine_arm_integratorcp.py | 6 +- tests/avocado/machine_aspeed.py | 12 +- tests/avocado/machine_m68k_nextcube.py | 4 +- tests/avocado/machine_mips_malta.py | 6 +- tests/avocado/machine_s390_ccw_virtio.py | 28 ++--- tests/avocado/migration.py | 10 +- tests/avocado/pc_cpu_hotplug_props.py | 2 +- tests/avocado/version.py | 4 +- tests/avocado/virtio_check_params.py | 6 +- tests/avocado/virtio_version.py | 5 +- tests/avocado/x86_cpu_model_versions.py | 13 +- tests/migration/guestperf/engine.py | 144 +++++++++++----------- tests/qemu-iotests/256 | 34 ++--- tests/qemu-iotests/257 | 34 ++--- 29 files changed, 200 insertions(+), 195 deletions(-) diff --git a/docs/devel/testing.rst b/docs/devel/testing.rst index f3e2472189..b0680cbb22 100644 --- a/docs/devel/testing.rst +++ b/docs/devel/testing.rst @@ -1014,8 +1014,8 @@ class. Here's a simple usage example: """ def test_qmp_human_info_version(self): self.vm.launch() - res = self.vm.command('human-monitor-command', - command_line='info version') + res = self.vm.cmd('human-monitor-command', + command_line='info version') self.assertRegexpMatches(res, r'^(\d+\.\d+\.\d)') To execute your test, run: @@ -1065,15 +1065,15 @@ and hypothetical example follows: first_machine.launch() second_machine.launch() - first_res = first_machine.command( + first_res = first_machine.cmd( 'human-monitor-command', command_line='info version') - second_res = second_machine.command( + second_res = second_machine.cmd( 'human-monitor-command', command_line='info version') - third_res = self.get_vm(name='third_machine').command( + third_res = self.get_vm(name='third_machine').cmd( 'human-monitor-command', command_line='info version') diff --git a/python/qemu/machine/machine.py b/python/qemu/machine/machine.py index 50bba33729..eae193eb00 100644 --- a/python/qemu/machine/machine.py +++ b/python/qemu/machine/machine.py @@ -707,16 +707,16 @@ class QEMUMachine: self._quit_issued = True return ret - def command(self, cmd: str, - conv_keys: bool = True, - **args: Any) -> QMPReturnValue: + def cmd(self, cmd: str, + conv_keys: bool = True, + **args: Any) -> QMPReturnValue: """ Invoke a QMP command. On success return the response dict. On failure raise an exception. """ qmp_args = self._qmp_args(conv_keys, args) - ret = self._qmp.command(cmd, **qmp_args) + ret = self._qmp.cmd(cmd, **qmp_args) if cmd == 'quit': self._quit_issued = True return ret diff --git a/python/qemu/qmp/legacy.py b/python/qemu/qmp/legacy.py index e5fa1ce9c4..22a2b5616e 100644 --- a/python/qemu/qmp/legacy.py +++ b/python/qemu/qmp/legacy.py @@ -207,7 +207,7 @@ class QEMUMonitorProtocol: qmp_cmd['arguments'] = args return self.cmd_obj(qmp_cmd) - def command(self, cmd: str, **kwds: object) -> QMPReturnValue: + def cmd(self, cmd: str, **kwds: object) -> QMPReturnValue: """ Build and send a QMP command to the monitor, report errors if any """ diff --git a/python/qemu/qmp/qmp_shell.py b/python/qemu/qmp/qmp_shell.py index 988d79c01b..98e684e9e8 100644 --- a/python/qemu/qmp/qmp_shell.py +++ b/python/qemu/qmp/qmp_shell.py @@ -202,7 +202,7 @@ class QMPShell(QEMUMonitorProtocol): def _fill_completion(self) -> None: try: - cmds = cast(List[Dict[str, str]], self.command('query-commands')) + cmds = cast(List[Dict[str, str]], self.cmd('query-commands')) for cmd in cmds: self._completer.append(cmd['name']) except ExecuteError: diff --git a/python/qemu/utils/qemu_ga_client.py b/python/qemu/utils/qemu_ga_client.py index d8411bb2d0..9a665e6e99 100644 --- a/python/qemu/utils/qemu_ga_client.py +++ b/python/qemu/utils/qemu_ga_client.py @@ -64,7 +64,7 @@ from qemu.qmp.legacy import QEMUMonitorProtocol class QemuGuestAgent(QEMUMonitorProtocol): def __getattr__(self, name: str) -> Callable[..., Any]: def wrapper(**kwds: object) -> object: - return self.command('guest-' + name.replace('_', '-'), **kwds) + return self.cmd('guest-' + name.replace('_', '-'), **kwds) return wrapper diff --git a/python/qemu/utils/qom.py b/python/qemu/utils/qom.py index bcf192f477..426a0f245f 100644 --- a/python/qemu/utils/qom.py +++ b/python/qemu/utils/qom.py @@ -84,7 +84,7 @@ class QOMSet(QOMCommand): self.value = args.value def run(self) -> int: - rsp = self.qmp.command( + rsp = self.qmp.cmd( 'qom-set', path=self.path, property=self.prop, @@ -129,7 +129,7 @@ class QOMGet(QOMCommand): self.prop = tmp[1] def run(self) -> int: - rsp = self.qmp.command( + rsp = self.qmp.cmd( 'qom-get', path=self.path, property=self.prop @@ -231,8 +231,8 @@ class QOMTree(QOMCommand): if item.child: continue try: - rsp = self.qmp.command('qom-get', path=path, - property=item.name) + rsp = self.qmp.cmd('qom-get', path=path, + property=item.name) print(f" {item.name}: {rsp} ({item.type})") except ExecuteError as err: print(f" {item.name}: ({item.type})") diff --git a/python/qemu/utils/qom_common.py b/python/qemu/utils/qom_common.py index 80da1b2304..dd2c8b1908 100644 --- a/python/qemu/utils/qom_common.py +++ b/python/qemu/utils/qom_common.py @@ -140,7 +140,7 @@ class QOMCommand: """ :return: a strongly typed list from the 'qom-list' command. """ - rsp = self.qmp.command('qom-list', path=path) + rsp = self.qmp.cmd('qom-list', path=path) # qom-list returns List[ObjectPropertyInfo] assert isinstance(rsp, list) return [ObjectPropertyInfo.make(x) for x in rsp] diff --git a/python/qemu/utils/qom_fuse.py b/python/qemu/utils/qom_fuse.py index 8dcd59fcde..cf7e344bd5 100644 --- a/python/qemu/utils/qom_fuse.py +++ b/python/qemu/utils/qom_fuse.py @@ -137,7 +137,7 @@ class QOMFuse(QOMCommand, Operations): if path == '': path = '/' try: - data = str(self.qmp.command('qom-get', path=path, property=prop)) + data = str(self.qmp.cmd('qom-get', path=path, property=prop)) data += '\n' # make values shell friendly except ExecuteError as err: raise FuseOSError(EPERM) from err @@ -152,8 +152,8 @@ class QOMFuse(QOMCommand, Operations): return False path, prop = path.rsplit('/', 1) prefix = '/'.join(['..'] * (len(path.split('/')) - 1)) - return prefix + str(self.qmp.command('qom-get', path=path, - property=prop)) + return prefix + str(self.qmp.cmd('qom-get', path=path, + property=prop)) def getattr(self, path: str, fh: Optional[IO[bytes]] = None) -> Mapping[str, object]: diff --git a/scripts/cpu-x86-uarch-abi.py b/scripts/cpu-x86-uarch-abi.py index 893afd1b35..f6baeeff24 100644 --- a/scripts/cpu-x86-uarch-abi.py +++ b/scripts/cpu-x86-uarch-abi.py @@ -69,7 +69,7 @@ sock = sys.argv[1] shell = QEMUMonitorProtocol(sock) shell.connect() -models = shell.command("query-cpu-definitions") +models = shell.cmd("query-cpu-definitions") # These QMP props don't correspond to CPUID fatures # so ignore them @@ -93,9 +93,9 @@ for model in models: models = {} for name in sorted(names): - cpu = shell.command("query-cpu-model-expansion", - { "type": "static", - "model": { "name": name }}) + cpu = shell.cmd("query-cpu-model-expansion", + { "type": "static", + "model": { "name": name }}) got = {} for (feature, present) in cpu["model"]["props"].items(): diff --git a/scripts/device-crash-test b/scripts/device-crash-test index 353aa575d7..da8b56edd9 100755 --- a/scripts/device-crash-test +++ b/scripts/device-crash-test @@ -269,14 +269,14 @@ def formatTestCase(t): def qomListTypeNames(vm, **kwargs): """Run qom-list-types QMP command, return type names""" - types = vm.command('qom-list-types', **kwargs) + types = vm.cmd('qom-list-types', **kwargs) return [t['name'] for t in types] def infoQDM(vm): """Parse 'info qdm' output""" args = {'command-line': 'info qdm'} - devhelp = vm.command('human-monitor-command', **args) + devhelp = vm.cmd('human-monitor-command', **args) for l in devhelp.split('\n'): l = l.strip() if l == '' or l.endswith(':'): @@ -304,9 +304,9 @@ class QemuBinaryInfo(object): # there's no way to query DeviceClass::user_creatable using QMP, # so use 'info qdm': self.no_user_devs = set([d['name'] for d in infoQDM(vm, ) if d['no-user']]) - self.machines = list(m['name'] for m in vm.command('query-machines')) + self.machines = list(m['name'] for m in vm.cmd('query-machines')) self.user_devs = self.alldevs.difference(self.no_user_devs) - self.kvm_available = vm.command('query-kvm')['enabled'] + self.kvm_available = vm.cmd('query-kvm')['enabled'] finally: vm.shutdown() diff --git a/scripts/render_block_graph.py b/scripts/render_block_graph.py index 8f731a5cfe..3e1a2e3fa7 100755 --- a/scripts/render_block_graph.py +++ b/scripts/render_block_graph.py @@ -43,13 +43,13 @@ def render_block_graph(qmp, filename, format='png'): representation in @format into "@filename.@format" ''' - bds_nodes = qmp.command('query-named-block-nodes') + bds_nodes = qmp.cmd('query-named-block-nodes') bds_nodes = {n['node-name']: n for n in bds_nodes} - job_nodes = qmp.command('query-block-jobs') + job_nodes = qmp.cmd('query-block-jobs') job_nodes = {n['device']: n for n in job_nodes} - block_graph = qmp.command('x-debug-query-block-graph') + block_graph = qmp.cmd('x-debug-query-block-graph') graph = Digraph(comment='Block Nodes Graph') graph.format = format @@ -94,7 +94,7 @@ class LibvirtGuest(): def __init__(self, name): self.name = name - def command(self, cmd): + def cmd(self, cmd): # only supports qmp commands without parameters m = {'execute': cmd} ar = ['virsh', 'qemu-monitor-command', self.name, json.dumps(m)] diff --git a/tests/avocado/avocado_qemu/__init__.py b/tests/avocado/avocado_qemu/__init__.py index 0589534f28..d71e989db6 100644 --- a/tests/avocado/avocado_qemu/__init__.py +++ b/tests/avocado/avocado_qemu/__init__.py @@ -408,8 +408,8 @@ class LinuxSSHMixIn: def ssh_connect(self, username, credential, credential_is_key=True): self.ssh_logger = logging.getLogger('ssh') - res = self.vm.command('human-monitor-command', - command_line='info usernet') + res = self.vm.cmd('human-monitor-command', + command_line='info usernet') port = get_info_usernet_hostfwd_port(res) self.assertIsNotNone(port) self.assertGreater(port, 0) diff --git a/tests/avocado/cpu_queries.py b/tests/avocado/cpu_queries.py index cf69f69b11..86c2d5c92d 100644 --- a/tests/avocado/cpu_queries.py +++ b/tests/avocado/cpu_queries.py @@ -23,12 +23,13 @@ class QueryCPUModelExpansion(QemuSystemTest): self.vm.add_args('-S') self.vm.launch() - cpus = self.vm.command('query-cpu-definitions') + cpus = self.vm.cmd('query-cpu-definitions') for c in cpus: self.log.info("Checking CPU: %s", c) self.assertNotIn('', c['unavailable-features'], c['name']) for c in cpus: model = {'name': c['name']} - e = self.vm.command('query-cpu-model-expansion', model=model, type='full') + e = self.vm.cmd('query-cpu-model-expansion', model=model, + type='full') self.assertEquals(e['model']['name'], c['name']) diff --git a/tests/avocado/hotplug_cpu.py b/tests/avocado/hotplug_cpu.py index 6374bf1b54..292bb43e4d 100644 --- a/tests/avocado/hotplug_cpu.py +++ b/tests/avocado/hotplug_cpu.py @@ -29,9 +29,9 @@ class HotPlugCPU(LinuxTest): with self.assertRaises(AssertionError): self.ssh_command('test -e /sys/devices/system/cpu/cpu1') - self.vm.command('device_add', - driver='Haswell-x86_64-cpu', - socket_id=0, - core_id=1, - thread_id=0) + self.vm.cmd('device_add', + driver='Haswell-x86_64-cpu', + socket_id=0, + core_id=1, + thread_id=0) self.ssh_command('test -e /sys/devices/system/cpu/cpu1') diff --git a/tests/avocado/info_usernet.py b/tests/avocado/info_usernet.py index fdc4d90c42..e1aa7a6e0a 100644 --- a/tests/avocado/info_usernet.py +++ b/tests/avocado/info_usernet.py @@ -22,8 +22,8 @@ class InfoUsernet(QemuSystemTest): self.require_netdev('user') self.vm.add_args('-netdev', 'user,id=vnet,hostfwd=:127.0.0.1:0-:22') self.vm.launch() - res = self.vm.command('human-monitor-command', - command_line='info usernet') + res = self.vm.cmd('human-monitor-command', + command_line='info usernet') port = get_info_usernet_hostfwd_port(res) self.assertIsNotNone(port, ('"info usernet" output content does not seem to ' diff --git a/tests/avocado/machine_arm_integratorcp.py b/tests/avocado/machine_arm_integratorcp.py index 1ffe1073ef..87f5cf3953 100644 --- a/tests/avocado/machine_arm_integratorcp.py +++ b/tests/avocado/machine_arm_integratorcp.py @@ -81,9 +81,9 @@ class IntegratorMachine(QemuSystemTest): self.boot_integratorcp() framebuffer_ready = 'Console: switching to colour frame buffer device' wait_for_console_pattern(self, framebuffer_ready) - self.vm.command('human-monitor-command', command_line='stop') - self.vm.command('human-monitor-command', - command_line='screendump %s' % screendump_path) + self.vm.cmd('human-monitor-command', command_line='stop') + self.vm.cmd('human-monitor-command', + command_line='screendump %s' % screendump_path) logger = logging.getLogger('framebuffer') cpu_count = 1 diff --git a/tests/avocado/machine_aspeed.py b/tests/avocado/machine_aspeed.py index f691ee3fb8..df31b2a8a8 100644 --- a/tests/avocado/machine_aspeed.py +++ b/tests/avocado/machine_aspeed.py @@ -181,8 +181,8 @@ class AST2x00Machine(QemuSystemTest): 'i2c i2c-3: new_device: Instantiated device lm75 at 0x4d'); exec_command_and_wait_for_pattern(self, 'cat /sys/class/hwmon/hwmon1/temp1_input', '0') - self.vm.command('qom-set', path='/machine/peripheral/tmp-test', - property='temperature', value=18000); + self.vm.cmd('qom-set', path='/machine/peripheral/tmp-test', + property='temperature', value=18000); exec_command_and_wait_for_pattern(self, 'cat /sys/class/hwmon/hwmon1/temp1_input', '18000') @@ -213,8 +213,8 @@ class AST2x00Machine(QemuSystemTest): 'i2c i2c-3: new_device: Instantiated device lm75 at 0x4d'); exec_command_and_wait_for_pattern(self, 'cat /sys/class/hwmon/hwmon0/temp1_input', '0') - self.vm.command('qom-set', path='/machine/peripheral/tmp-test', - property='temperature', value=18000); + self.vm.cmd('qom-set', path='/machine/peripheral/tmp-test', + property='temperature', value=18000); exec_command_and_wait_for_pattern(self, 'cat /sys/class/hwmon/hwmon0/temp1_input', '18000') @@ -360,8 +360,8 @@ class AST2x00MachineSDK(QemuSystemTest, LinuxSSHMixIn): 'i2c i2c-5: new_device: Instantiated device lm75 at 0x4d'); self.ssh_command_output_contains( 'cat /sys/class/hwmon/hwmon19/temp1_input', '0') - self.vm.command('qom-set', path='/machine/peripheral/tmp-test', - property='temperature', value=18000); + self.vm.cmd('qom-set', path='/machine/peripheral/tmp-test', + property='temperature', value=18000); self.ssh_command_output_contains( 'cat /sys/class/hwmon/hwmon19/temp1_input', '18000') diff --git a/tests/avocado/machine_m68k_nextcube.py b/tests/avocado/machine_m68k_nextcube.py index 6790e7d9cd..d6da2fbb01 100644 --- a/tests/avocado/machine_m68k_nextcube.py +++ b/tests/avocado/machine_m68k_nextcube.py @@ -43,8 +43,8 @@ class NextCubeMachine(QemuSystemTest): # 'displaysurface_create 1120x832' trace-event. time.sleep(2) - self.vm.command('human-monitor-command', - command_line='screendump %s' % screenshot_path) + self.vm.cmd('human-monitor-command', + command_line='screendump %s' % screenshot_path) @skipUnless(PIL_AVAILABLE, 'Python PIL not installed') def test_bootrom_framebuffer_size(self): diff --git a/tests/avocado/machine_mips_malta.py b/tests/avocado/machine_mips_malta.py index 92233451c5..9bd54518bf 100644 --- a/tests/avocado/machine_mips_malta.py +++ b/tests/avocado/machine_mips_malta.py @@ -71,9 +71,9 @@ class MaltaMachineFramebuffer(QemuSystemTest): framebuffer_ready = 'Console: switching to colour frame buffer device' wait_for_console_pattern(self, framebuffer_ready, failure_message='Kernel panic - not syncing') - self.vm.command('human-monitor-command', command_line='stop') - self.vm.command('human-monitor-command', - command_line='screendump %s' % screendump_path) + self.vm.cmd('human-monitor-command', command_line='stop') + self.vm.cmd('human-monitor-command', + command_line='screendump %s' % screendump_path) logger = logging.getLogger('framebuffer') match_threshold = 0.95 diff --git a/tests/avocado/machine_s390_ccw_virtio.py b/tests/avocado/machine_s390_ccw_virtio.py index e7a2a20ba6..e1f493bc44 100644 --- a/tests/avocado/machine_s390_ccw_virtio.py +++ b/tests/avocado/machine_s390_ccw_virtio.py @@ -107,10 +107,10 @@ class S390CCWVirtioMachine(QemuSystemTest): 'dd if=/dev/hwrng of=/dev/null bs=1k count=10', '10+0 records out') self.clear_guest_dmesg() - self.vm.command('device_del', id='rn1') + self.vm.cmd('device_del', id='rn1') self.wait_for_crw_reports() self.clear_guest_dmesg() - self.vm.command('device_del', id='rn2') + self.vm.cmd('device_del', id='rn2') self.wait_for_crw_reports() exec_command_and_wait_for_pattern(self, 'dd if=/dev/hwrng of=/dev/null bs=1k count=10', @@ -132,8 +132,8 @@ class S390CCWVirtioMachine(QemuSystemTest): '0x0000000c') # add another device self.clear_guest_dmesg() - self.vm.command('device_add', driver='virtio-net-ccw', - devno='fe.0.4711', id='net_4711') + self.vm.cmd('device_add', driver='virtio-net-ccw', + devno='fe.0.4711', id='net_4711') self.wait_for_crw_reports() exec_command_and_wait_for_pattern(self, 'for i in 1 2 3 4 5 6 7 ; do ' 'if [ -e /sys/bus/ccw/devices/*4711 ]; then break; fi ;' @@ -141,7 +141,7 @@ class S390CCWVirtioMachine(QemuSystemTest): '0.0.4711') # and detach it again self.clear_guest_dmesg() - self.vm.command('device_del', id='net_4711') + self.vm.cmd('device_del', id='net_4711') self.vm.event_wait(name='DEVICE_DELETED', match={'data': {'device': 'net_4711'}}) self.wait_for_crw_reports() @@ -151,10 +151,10 @@ class S390CCWVirtioMachine(QemuSystemTest): # test the virtio-balloon device exec_command_and_wait_for_pattern(self, 'head -n 1 /proc/meminfo', 'MemTotal: 115640 kB') - self.vm.command('human-monitor-command', command_line='balloon 96') + self.vm.cmd('human-monitor-command', command_line='balloon 96') exec_command_and_wait_for_pattern(self, 'head -n 1 /proc/meminfo', 'MemTotal: 82872 kB') - self.vm.command('human-monitor-command', command_line='balloon 128') + self.vm.cmd('human-monitor-command', command_line='balloon 128') exec_command_and_wait_for_pattern(self, 'head -n 1 /proc/meminfo', 'MemTotal: 115640 kB') @@ -245,7 +245,7 @@ class S390CCWVirtioMachine(QemuSystemTest): '12+0 records out') with tempfile.NamedTemporaryFile(suffix='.ppm', prefix='qemu-scrdump-') as ppmfile: - self.vm.command('screendump', filename=ppmfile.name) + self.vm.cmd('screendump', filename=ppmfile.name) ppmfile.seek(0) line = ppmfile.readline() self.assertEqual(line, b"P6\n") @@ -261,16 +261,16 @@ class S390CCWVirtioMachine(QemuSystemTest): # Hot-plug a virtio-crypto device and see whether it gets accepted self.log.info("Test hot-plug virtio-crypto device") self.clear_guest_dmesg() - self.vm.command('object-add', qom_type='cryptodev-backend-builtin', - id='cbe0') - self.vm.command('device_add', driver='virtio-crypto-ccw', id='crypdev0', - cryptodev='cbe0', devno='fe.0.2342') + self.vm.cmd('object-add', qom_type='cryptodev-backend-builtin', + id='cbe0') + self.vm.cmd('device_add', driver='virtio-crypto-ccw', id='crypdev0', + cryptodev='cbe0', devno='fe.0.2342') exec_command_and_wait_for_pattern(self, 'while ! (dmesg -c | grep Accelerator.device) ; do' ' sleep 1 ; done', 'Accelerator device is ready') exec_command_and_wait_for_pattern(self, 'lscss', '0.0.2342') - self.vm.command('device_del', id='crypdev0') - self.vm.command('object-del', id='cbe0') + self.vm.cmd('device_del', id='crypdev0') + self.vm.cmd('object-del', id='cbe0') exec_command_and_wait_for_pattern(self, 'while ! (dmesg -c | grep Start.virtcrypto_remove) ; do' ' sleep 1 ; done', 'Start virtcrypto_remove.') diff --git a/tests/avocado/migration.py b/tests/avocado/migration.py index fdc1d234fb..09b62f813e 100644 --- a/tests/avocado/migration.py +++ b/tests/avocado/migration.py @@ -30,7 +30,7 @@ class MigrationTest(QemuSystemTest): @staticmethod def migration_finished(vm): - return vm.command('query-migrate')['status'] in ('completed', 'failed') + return vm.cmd('query-migrate')['status'] in ('completed', 'failed') def assert_migration(self, src_vm, dst_vm): wait.wait_for(self.migration_finished, @@ -41,10 +41,10 @@ class MigrationTest(QemuSystemTest): timeout=self.timeout, step=0.1, args=(dst_vm,)) - self.assertEqual(src_vm.command('query-migrate')['status'], 'completed') - self.assertEqual(dst_vm.command('query-migrate')['status'], 'completed') - self.assertEqual(dst_vm.command('query-status')['status'], 'running') - self.assertEqual(src_vm.command('query-status')['status'],'postmigrate') + self.assertEqual(src_vm.cmd('query-migrate')['status'], 'completed') + self.assertEqual(dst_vm.cmd('query-migrate')['status'], 'completed') + self.assertEqual(dst_vm.cmd('query-status')['status'], 'running') + self.assertEqual(src_vm.cmd('query-status')['status'],'postmigrate') def do_migrate(self, dest_uri, src_uri=None): dest_vm = self.get_vm('-incoming', dest_uri) diff --git a/tests/avocado/pc_cpu_hotplug_props.py b/tests/avocado/pc_cpu_hotplug_props.py index 52b878188e..b56f51d02a 100644 --- a/tests/avocado/pc_cpu_hotplug_props.py +++ b/tests/avocado/pc_cpu_hotplug_props.py @@ -32,4 +32,4 @@ class OmittedCPUProps(QemuSystemTest): self.vm.add_args('-smp', '1,sockets=2,cores=2,threads=2,maxcpus=8') self.vm.add_args('-device', 'qemu64-x86_64-cpu,socket-id=1,core-id=0,thread-id=0') self.vm.launch() - self.assertEquals(len(self.vm.command('query-cpus-fast')), 2) + self.assertEquals(len(self.vm.cmd('query-cpus-fast')), 2) diff --git a/tests/avocado/version.py b/tests/avocado/version.py index dd775955eb..93ffdf3d97 100644 --- a/tests/avocado/version.py +++ b/tests/avocado/version.py @@ -20,6 +20,6 @@ class Version(QemuSystemTest): def test_qmp_human_info_version(self): self.vm.add_args('-nodefaults') self.vm.launch() - res = self.vm.command('human-monitor-command', - command_line='info version') + res = self.vm.cmd('human-monitor-command', + command_line='info version') self.assertRegexpMatches(res, r'^(\d+\.\d+\.\d)') diff --git a/tests/avocado/virtio_check_params.py b/tests/avocado/virtio_check_params.py index 4093da8a67..f4314ef824 100644 --- a/tests/avocado/virtio_check_params.py +++ b/tests/avocado/virtio_check_params.py @@ -51,8 +51,8 @@ class VirtioMaxSegSettingsCheck(QemuSystemTest): error = None props = None - output = vm.command('human-monitor-command', - command_line = 'info qtree') + output = vm.cmd('human-monitor-command', + command_line = 'info qtree') props_list = DEV_TYPES[dev_type_name].values(); pattern = self.make_pattern(props_list) res = re.findall(pattern, output) @@ -121,7 +121,7 @@ class VirtioMaxSegSettingsCheck(QemuSystemTest): # collect all machine types except 'none', 'isapc', 'microvm' with QEMUMachine(self.qemu_bin) as vm: vm.launch() - machines = [m['name'] for m in vm.command('query-machines')] + machines = [m['name'] for m in vm.cmd('query-machines')] vm.shutdown() machines.remove('none') machines.remove('isapc') diff --git a/tests/avocado/virtio_version.py b/tests/avocado/virtio_version.py index c84e48813a..afe5e828b5 100644 --- a/tests/avocado/virtio_version.py +++ b/tests/avocado/virtio_version.py @@ -48,7 +48,8 @@ def pci_modern_device_id(virtio_devid): return virtio_devid + 0x1040 def devtype_implements(vm, devtype, implements): - return devtype in [d['name'] for d in vm.command('qom-list-types', implements=implements)] + return devtype in [d['name'] for d in + vm.cmd('qom-list-types', implements=implements)] def get_pci_interfaces(vm, devtype): interfaces = ('pci-express-device', 'conventional-pci-device') @@ -78,7 +79,7 @@ class VirtioVersionCheck(QemuSystemTest): vm.add_args('-S') vm.launch() - pcibuses = vm.command('query-pci') + pcibuses = vm.cmd('query-pci') alldevs = [dev for bus in pcibuses for dev in bus['devices']] devfortest = [dev for dev in alldevs if dev['qdev_id'] == 'devfortest'] diff --git a/tests/avocado/x86_cpu_model_versions.py b/tests/avocado/x86_cpu_model_versions.py index a6edf74c1c..9e07b8a55d 100644 --- a/tests/avocado/x86_cpu_model_versions.py +++ b/tests/avocado/x86_cpu_model_versions.py @@ -84,7 +84,8 @@ class X86CPUModelAliases(avocado_qemu.QemuSystemTest): # with older QEMU versions that didn't have the versioned CPU model self.vm.add_args('-S') self.vm.launch() - cpus = dict((m['name'], m) for m in self.vm.command('query-cpu-definitions')) + cpus = dict((m['name'], m) for m in + self.vm.cmd('query-cpu-definitions')) self.assertFalse(cpus['Cascadelake-Server']['static'], 'unversioned Cascadelake-Server CPU model must not be static') @@ -115,7 +116,8 @@ class X86CPUModelAliases(avocado_qemu.QemuSystemTest): self.vm.add_args('-S') self.vm.launch() - cpus = dict((m['name'], m) for m in self.vm.command('query-cpu-definitions')) + cpus = dict((m['name'], m) for m in + self.vm.cmd('query-cpu-definitions')) self.assertFalse(cpus['Cascadelake-Server']['static'], 'unversioned Cascadelake-Server CPU model must not be static') @@ -220,7 +222,8 @@ class X86CPUModelAliases(avocado_qemu.QemuSystemTest): self.vm.add_args('-S') self.vm.launch() - cpus = dict((m['name'], m) for m in self.vm.command('query-cpu-definitions')) + cpus = dict((m['name'], m) for m in + self.vm.cmd('query-cpu-definitions')) self.assertFalse(cpus['Cascadelake-Server']['static'], 'unversioned Cascadelake-Server CPU model must not be static') @@ -246,8 +249,8 @@ class CascadelakeArchCapabilities(avocado_qemu.QemuSystemTest): :avocado: tags=arch:x86_64 """ def get_cpu_prop(self, prop): - cpu_path = self.vm.command('query-cpus-fast')[0].get('qom-path') - return self.vm.command('qom-get', path=cpu_path, property=prop) + cpu_path = self.vm.cmd('query-cpus-fast')[0].get('qom-path') + return self.vm.cmd('qom-get', path=cpu_path, property=prop) def test_4_1(self): """ diff --git a/tests/migration/guestperf/engine.py b/tests/migration/guestperf/engine.py index e69d16a62c..da96ca034a 100644 --- a/tests/migration/guestperf/engine.py +++ b/tests/migration/guestperf/engine.py @@ -77,7 +77,7 @@ class Engine(object): return TimingRecord(pid, now, 1000 * (stime + utime) / jiffies_per_sec) def _migrate_progress(self, vm): - info = vm.command("query-migrate") + info = vm.cmd("query-migrate") if "ram" not in info: info["ram"] = {} @@ -109,7 +109,7 @@ class Engine(object): src_vcpu_time = [] src_pid = src.get_pid() - vcpus = src.command("query-cpus-fast") + vcpus = src.cmd("query-cpus-fast") src_threads = [] for vcpu in vcpus: src_threads.append(vcpu["thread-id"]) @@ -128,82 +128,82 @@ class Engine(object): if self._verbose: print("Starting migration") if scenario._auto_converge: - resp = src.command("migrate-set-capabilities", - capabilities = [ - { "capability": "auto-converge", - "state": True } - ]) - resp = src.command("migrate-set-parameters", - cpu_throttle_increment=scenario._auto_converge_step) + resp = src.cmd("migrate-set-capabilities", + capabilities = [ + { "capability": "auto-converge", + "state": True } + ]) + resp = src.cmd("migrate-set-parameters", + cpu_throttle_increment=scenario._auto_converge_step) if scenario._post_copy: - resp = src.command("migrate-set-capabilities", - capabilities = [ - { "capability": "postcopy-ram", - "state": True } - ]) - resp = dst.command("migrate-set-capabilities", - capabilities = [ - { "capability": "postcopy-ram", - "state": True } - ]) + resp = src.cmd("migrate-set-capabilities", + capabilities = [ + { "capability": "postcopy-ram", + "state": True } + ]) + resp = dst.cmd("migrate-set-capabilities", + capabilities = [ + { "capability": "postcopy-ram", + "state": True } + ]) - resp = src.command("migrate-set-parameters", - max_bandwidth=scenario._bandwidth * 1024 * 1024) + resp = src.cmd("migrate-set-parameters", + max_bandwidth=scenario._bandwidth * 1024 * 1024) - resp = src.command("migrate-set-parameters", - downtime_limit=scenario._downtime) + resp = src.cmd("migrate-set-parameters", + downtime_limit=scenario._downtime) if scenario._compression_mt: - resp = src.command("migrate-set-capabilities", - capabilities = [ - { "capability": "compress", - "state": True } - ]) - resp = src.command("migrate-set-parameters", - compress_threads=scenario._compression_mt_threads) - resp = dst.command("migrate-set-capabilities", - capabilities = [ - { "capability": "compress", - "state": True } - ]) - resp = dst.command("migrate-set-parameters", - decompress_threads=scenario._compression_mt_threads) + resp = src.cmd("migrate-set-capabilities", + capabilities = [ + { "capability": "compress", + "state": True } + ]) + resp = src.cmd("migrate-set-parameters", + compress_threads=scenario._compression_mt_threads) + resp = dst.cmd("migrate-set-capabilities", + capabilities = [ + { "capability": "compress", + "state": True } + ]) + resp = dst.cmd("migrate-set-parameters", + decompress_threads=scenario._compression_mt_threads) if scenario._compression_xbzrle: - resp = src.command("migrate-set-capabilities", - capabilities = [ - { "capability": "xbzrle", - "state": True } - ]) - resp = dst.command("migrate-set-capabilities", - capabilities = [ - { "capability": "xbzrle", - "state": True } - ]) - resp = src.command("migrate-set-parameters", - xbzrle_cache_size=( - hardware._mem * - 1024 * 1024 * 1024 / 100 * - scenario._compression_xbzrle_cache)) + resp = src.cmd("migrate-set-capabilities", + capabilities = [ + { "capability": "xbzrle", + "state": True } + ]) + resp = dst.cmd("migrate-set-capabilities", + capabilities = [ + { "capability": "xbzrle", + "state": True } + ]) + resp = src.cmd("migrate-set-parameters", + xbzrle_cache_size=( + hardware._mem * + 1024 * 1024 * 1024 / 100 * + scenario._compression_xbzrle_cache)) if scenario._multifd: - resp = src.command("migrate-set-capabilities", - capabilities = [ - { "capability": "multifd", - "state": True } - ]) - resp = src.command("migrate-set-parameters", - multifd_channels=scenario._multifd_channels) - resp = dst.command("migrate-set-capabilities", - capabilities = [ - { "capability": "multifd", - "state": True } - ]) - resp = dst.command("migrate-set-parameters", - multifd_channels=scenario._multifd_channels) + resp = src.cmd("migrate-set-capabilities", + capabilities = [ + { "capability": "multifd", + "state": True } + ]) + resp = src.cmd("migrate-set-parameters", + multifd_channels=scenario._multifd_channels) + resp = dst.cmd("migrate-set-capabilities", + capabilities = [ + { "capability": "multifd", + "state": True } + ]) + resp = dst.cmd("migrate-set-parameters", + multifd_channels=scenario._multifd_channels) - resp = src.command("migrate", uri=connect_uri) + resp = src.cmd("migrate", uri=connect_uri) post_copy = False paused = False @@ -228,7 +228,7 @@ class Engine(object): if progress._status in ("completed", "failed", "cancelled"): if progress._status == "completed" and paused: - dst.command("cont") + dst.cmd("cont") if progress_history[-1] != progress: progress_history.append(progress) @@ -256,13 +256,13 @@ class Engine(object): if progress._ram._iterations > scenario._max_iters: if self._verbose: print("No completion after %d iterations over RAM" % scenario._max_iters) - src.command("migrate_cancel") + src.cmd("migrate_cancel") continue if time.time() > (start + scenario._max_time): if self._verbose: print("No completion after %d seconds" % scenario._max_time) - src.command("migrate_cancel") + src.cmd("migrate_cancel") continue if (scenario._post_copy and @@ -270,7 +270,7 @@ class Engine(object): not post_copy): if self._verbose: print("Switching to post-copy after %d iterations" % scenario._post_copy_iters) - resp = src.command("migrate-start-postcopy") + resp = src.cmd("migrate-start-postcopy") post_copy = True if (scenario._pause and @@ -278,7 +278,7 @@ class Engine(object): not paused): if self._verbose: print("Pausing VM after %d iterations" % scenario._pause_iters) - resp = src.command("stop") + resp = src.cmd("stop") paused = True def _is_ppc64le(self): diff --git a/tests/qemu-iotests/256 b/tests/qemu-iotests/256 index d7e67f4a05..f34af6cef7 100755 --- a/tests/qemu-iotests/256 +++ b/tests/qemu-iotests/256 @@ -40,25 +40,25 @@ with iotests.FilePath('img0') as img0_path, \ def create_target(filepath, name, size): basename = os.path.basename(filepath) nodename = "file_{}".format(basename) - log(vm.command('blockdev-create', job_id='job1', - options={ - 'driver': 'file', - 'filename': filepath, - 'size': 0, - })) + log(vm.cmd('blockdev-create', job_id='job1', + options={ + 'driver': 'file', + 'filename': filepath, + 'size': 0, + })) vm.run_job('job1') - log(vm.command('blockdev-add', driver='file', - node_name=nodename, filename=filepath)) - log(vm.command('blockdev-create', job_id='job2', - options={ - 'driver': iotests.imgfmt, - 'file': nodename, - 'size': size, - })) + log(vm.cmd('blockdev-add', driver='file', + node_name=nodename, filename=filepath)) + log(vm.cmd('blockdev-create', job_id='job2', + options={ + 'driver': iotests.imgfmt, + 'file': nodename, + 'size': size, + })) vm.run_job('job2') - log(vm.command('blockdev-add', driver=iotests.imgfmt, - node_name=name, - file=nodename)) + log(vm.cmd('blockdev-add', driver=iotests.imgfmt, + node_name=name, + file=nodename)) log('--- Preparing images & VM ---\n') vm.add_object('iothread,id=iothread0') diff --git a/tests/qemu-iotests/257 b/tests/qemu-iotests/257 index e7e7a2317e..7d3720b8e5 100755 --- a/tests/qemu-iotests/257 +++ b/tests/qemu-iotests/257 @@ -160,26 +160,26 @@ class Drive: file_node_name = "file_{}".format(basename) vm = self.vm - log(vm.command('blockdev-create', job_id='bdc-file-job', - options={ - 'driver': 'file', - 'filename': self.path, - 'size': 0, - })) + log(vm.cmd('blockdev-create', job_id='bdc-file-job', + options={ + 'driver': 'file', + 'filename': self.path, + 'size': 0, + })) vm.run_job('bdc-file-job') - log(vm.command('blockdev-add', driver='file', - node_name=file_node_name, filename=self.path)) + log(vm.cmd('blockdev-add', driver='file', + node_name=file_node_name, filename=self.path)) - log(vm.command('blockdev-create', job_id='bdc-fmt-job', - options={ - 'driver': fmt, - 'file': file_node_name, - 'size': size, - })) + log(vm.cmd('blockdev-create', job_id='bdc-fmt-job', + options={ + 'driver': fmt, + 'file': file_node_name, + 'size': size, + })) vm.run_job('bdc-fmt-job') - log(vm.command('blockdev-add', driver=fmt, - node_name=name, - file=file_node_name)) + log(vm.cmd('blockdev-add', driver=fmt, + node_name=name, + file=file_node_name)) self.fmt = fmt self.size = size self.node = name From 4e620ff48f31493d61c98c6770595b5b242b837d Mon Sep 17 00:00:00 2001 From: Vladimir Sementsov-Ogievskiy Date: Fri, 6 Oct 2023 18:41:16 +0300 Subject: [PATCH 0650/1077] python/machine.py: upgrade vm.cmd() method The method is not popular in iotests, we prefer use vm.qmp() and then check success by hand. But that's not optimal. To simplify movement to vm.cmd() let's support same interface improvements like in vm.qmp(). Signed-off-by: Vladimir Sementsov-Ogievskiy Reviewed-by: Eric Blake Message-id: 20231006154125.1068348-7-vsementsov@yandex-team.ru Signed-off-by: John Snow --- python/qemu/machine/machine.py | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/python/qemu/machine/machine.py b/python/qemu/machine/machine.py index eae193eb00..31cb9d617d 100644 --- a/python/qemu/machine/machine.py +++ b/python/qemu/machine/machine.py @@ -708,13 +708,23 @@ class QEMUMachine: return ret def cmd(self, cmd: str, - conv_keys: bool = True, + args_dict: Optional[Dict[str, object]] = None, + conv_keys: Optional[bool] = None, **args: Any) -> QMPReturnValue: """ Invoke a QMP command. On success return the response dict. On failure raise an exception. """ + if args_dict is not None: + assert not args + assert conv_keys is None + args = args_dict + conv_keys = False + + if conv_keys is None: + conv_keys = True + qmp_args = self._qmp_args(conv_keys, args) ret = self._qmp.cmd(cmd, **qmp_args) if cmd == 'quit': From 3a8736cf1e069c2b93c194d71062f911ff2571e7 Mon Sep 17 00:00:00 2001 From: Vladimir Sementsov-Ogievskiy Date: Fri, 6 Oct 2023 18:41:17 +0300 Subject: [PATCH 0651/1077] iotests: QemuStorageDaemon: add cmd() method like in QEMUMachine. Add similar method for consistency. Signed-off-by: Vladimir Sementsov-Ogievskiy Reviewed-by: Eric Blake Message-id: 20231006154125.1068348-8-vsementsov@yandex-team.ru Signed-off-by: John Snow --- tests/qemu-iotests/iotests.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/tests/qemu-iotests/iotests.py b/tests/qemu-iotests/iotests.py index 0c061d8986..ee7b6ddeff 100644 --- a/tests/qemu-iotests/iotests.py +++ b/tests/qemu-iotests/iotests.py @@ -38,7 +38,7 @@ import unittest from contextlib import contextmanager from qemu.machine import qtest -from qemu.qmp.legacy import QMPMessage, QEMUMonitorProtocol +from qemu.qmp.legacy import QMPMessage, QMPReturnValue, QEMUMonitorProtocol from qemu.utils import VerboseProcessError # Use this logger for logging messages directly from the iotests module @@ -466,6 +466,11 @@ class QemuStorageDaemon: assert self._qmp is not None return self._qmp + def cmd(self, cmd: str, args: Optional[Dict[str, object]] = None) \ + -> QMPReturnValue: + assert self._qmp is not None + return self._qmp.cmd(cmd, **(args or {})) + def stop(self, kill_signal=15): self._p.send_signal(kill_signal) self._p.wait() From f7ccc3295b3d7c49d4a7a3d42242cd5b50111e35 Mon Sep 17 00:00:00 2001 From: Vladimir Sementsov-Ogievskiy Date: Fri, 6 Oct 2023 18:41:18 +0300 Subject: [PATCH 0652/1077] iotests: add some missed checks of qmp result Signed-off-by: Vladimir Sementsov-Ogievskiy Reviewed-by: Eric Blake Message-id: 20231006154125.1068348-9-vsementsov@yandex-team.ru Signed-off-by: John Snow --- tests/qemu-iotests/041 | 1 + tests/qemu-iotests/151 | 1 + tests/qemu-iotests/152 | 2 ++ tests/qemu-iotests/tests/migrate-bitmaps-test | 2 ++ 4 files changed, 6 insertions(+) diff --git a/tests/qemu-iotests/041 b/tests/qemu-iotests/041 index 8429958bf0..4d7a829b65 100755 --- a/tests/qemu-iotests/041 +++ b/tests/qemu-iotests/041 @@ -1087,6 +1087,7 @@ class TestRepairQuorum(iotests.QMPTestCase): result = self.vm.qmp('blockdev-snapshot-sync', node_name='img1', snapshot_file=quorum_snapshot_file, snapshot_node_name="snap1"); + self.assert_qmp(result, 'return', {}) result = self.vm.qmp('drive-mirror', job_id='job0', device='quorum0', sync='full', node_name='repair0', replaces="img1", diff --git a/tests/qemu-iotests/151 b/tests/qemu-iotests/151 index b4d1bc2553..668d0c1e9c 100755 --- a/tests/qemu-iotests/151 +++ b/tests/qemu-iotests/151 @@ -159,6 +159,7 @@ class TestActiveMirror(iotests.QMPTestCase): sync='full', copy_mode='write-blocking', speed=1) + self.assert_qmp(result, 'return', {}) self.vm.hmp_qemu_io('source', 'break write_aio A') self.vm.hmp_qemu_io('source', 'aio_write 0 1M') # 1 diff --git a/tests/qemu-iotests/152 b/tests/qemu-iotests/152 index 4e179c340f..b73a0d08a2 100755 --- a/tests/qemu-iotests/152 +++ b/tests/qemu-iotests/152 @@ -43,6 +43,7 @@ class TestUnaligned(iotests.QMPTestCase): def test_unaligned(self): result = self.vm.qmp('drive-mirror', device='drive0', sync='full', granularity=65536, target=target_img) + self.assert_qmp(result, 'return', {}) self.complete_and_wait() self.vm.shutdown() self.assertEqual(iotests.image_size(test_img), iotests.image_size(target_img), @@ -51,6 +52,7 @@ class TestUnaligned(iotests.QMPTestCase): def test_unaligned_with_update(self): result = self.vm.qmp('drive-mirror', device='drive0', sync='full', granularity=65536, target=target_img) + self.assert_qmp(result, 'return', {}) self.wait_ready() self.vm.hmp_qemu_io('drive0', 'write 0 512') self.complete_and_wait(wait_ready=False) diff --git a/tests/qemu-iotests/tests/migrate-bitmaps-test b/tests/qemu-iotests/tests/migrate-bitmaps-test index 59f3357580..8668caae1e 100755 --- a/tests/qemu-iotests/tests/migrate-bitmaps-test +++ b/tests/qemu-iotests/tests/migrate-bitmaps-test @@ -101,6 +101,7 @@ class TestDirtyBitmapMigration(iotests.QMPTestCase): sha256 = get_bitmap_hash(self.vm_a) result = self.vm_a.qmp('migrate', uri=mig_cmd) + self.assert_qmp(result, 'return', {}) while True: event = self.vm_a.event_wait('MIGRATION') if event['data']['status'] == 'completed': @@ -176,6 +177,7 @@ class TestDirtyBitmapMigration(iotests.QMPTestCase): self.assert_qmp(result, 'return', {}) result = self.vm_a.qmp('migrate', uri=mig_cmd) + self.assert_qmp(result, 'return', {}) while True: event = self.vm_a.event_wait('MIGRATION') if event['data']['status'] == 'completed': From d24eb059faf321fb552cf96a2a1e88e5651347c1 Mon Sep 17 00:00:00 2001 From: Vladimir Sementsov-Ogievskiy Date: Fri, 6 Oct 2023 18:41:19 +0300 Subject: [PATCH 0653/1077] iotests: refactor some common qmp result checks into generic pattern To simplify further conversion. Signed-off-by: Vladimir Sementsov-Ogievskiy Reviewed-by: Eric Blake Message-id: 20231006154125.1068348-10-vsementsov@yandex-team.ru Signed-off-by: John Snow --- tests/qemu-iotests/040 | 3 ++- tests/qemu-iotests/147 | 3 ++- tests/qemu-iotests/155 | 4 ++-- tests/qemu-iotests/218 | 4 ++-- tests/qemu-iotests/296 | 3 ++- 5 files changed, 10 insertions(+), 7 deletions(-) diff --git a/tests/qemu-iotests/040 b/tests/qemu-iotests/040 index 5601a4873c..e61e7f2433 100755 --- a/tests/qemu-iotests/040 +++ b/tests/qemu-iotests/040 @@ -62,9 +62,10 @@ class ImageCommitTestCase(iotests.QMPTestCase): self.assert_no_active_block_jobs() if node_names: result = self.vm.qmp('block-commit', device='drive0', top_node=top, base_node=base) + self.assert_qmp(result, 'return', {}) else: result = self.vm.qmp('block-commit', device='drive0', top=top, base=base) - self.assert_qmp(result, 'return', {}) + self.assert_qmp(result, 'return', {}) self.wait_for_complete(need_ready) def run_default_commit_test(self): diff --git a/tests/qemu-iotests/147 b/tests/qemu-iotests/147 index 47dfa62e6b..770b73e2f4 100755 --- a/tests/qemu-iotests/147 +++ b/tests/qemu-iotests/147 @@ -159,10 +159,11 @@ class BuiltinNBD(NBDBlockdevAddBase): if export_name is None: result = self.server.qmp('nbd-server-add', device='nbd-export') + self.assert_qmp(result, 'return', {}) else: result = self.server.qmp('nbd-server-add', device='nbd-export', name=export_name) - self.assert_qmp(result, 'return', {}) + self.assert_qmp(result, 'return', {}) if export_name2 is not None: result = self.server.qmp('nbd-server-add', device='nbd-export', diff --git a/tests/qemu-iotests/155 b/tests/qemu-iotests/155 index eadda52615..d3e1b7401e 100755 --- a/tests/qemu-iotests/155 +++ b/tests/qemu-iotests/155 @@ -181,6 +181,7 @@ class MirrorBaseClass(BaseClass): result = self.vm.qmp(self.cmd, job_id='mirror-job', device='source', sync=sync, target='target', auto_finalize=False) + self.assert_qmp(result, 'return', {}) else: if self.existing: mode = 'existing' @@ -190,8 +191,7 @@ class MirrorBaseClass(BaseClass): sync=sync, target=target_img, format=iotests.imgfmt, mode=mode, node_name='target', auto_finalize=False) - - self.assert_qmp(result, 'return', {}) + self.assert_qmp(result, 'return', {}) self.vm.run_job('mirror-job', auto_finalize=False, pre_finalize=self.openBacking, auto_dismiss=True) diff --git a/tests/qemu-iotests/218 b/tests/qemu-iotests/218 index 6320c4cb56..5e74c55b6a 100755 --- a/tests/qemu-iotests/218 +++ b/tests/qemu-iotests/218 @@ -61,14 +61,14 @@ def start_mirror(vm, speed=None, buf_size=None): sync='full', speed=speed, buf_size=buf_size) + assert ret['return'] == {} else: ret = vm.qmp('blockdev-mirror', job_id='mirror', device='source', target='target', sync='full') - - assert ret['return'] == {} + assert ret['return'] == {} log('') diff --git a/tests/qemu-iotests/296 b/tests/qemu-iotests/296 index 0d21b740a7..19a674c5ae 100755 --- a/tests/qemu-iotests/296 +++ b/tests/qemu-iotests/296 @@ -133,9 +133,10 @@ class EncryptionSetupTestCase(iotests.QMPTestCase): if reOpen: result = vm.qmp(command, options=[opts]) + self.assert_qmp(result, 'return', {}) else: result = vm.qmp(command, **opts) - self.assert_qmp(result, 'return', {}) + self.assert_qmp(result, 'return', {}) ########################################################################### From 1ada73fbea540c9b397b08da6f1110fced1c0840 Mon Sep 17 00:00:00 2001 From: Vladimir Sementsov-Ogievskiy Date: Fri, 6 Oct 2023 18:41:20 +0300 Subject: [PATCH 0654/1077] iotests: drop some extra semicolons Signed-off-by: Vladimir Sementsov-Ogievskiy Reviewed-by: Eric Blake Message-id: 20231006154125.1068348-11-vsementsov@yandex-team.ru Signed-off-by: John Snow --- tests/qemu-iotests/041 | 2 +- tests/qemu-iotests/196 | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/qemu-iotests/041 b/tests/qemu-iotests/041 index 4d7a829b65..550e4dc391 100755 --- a/tests/qemu-iotests/041 +++ b/tests/qemu-iotests/041 @@ -1086,7 +1086,7 @@ class TestRepairQuorum(iotests.QMPTestCase): def test_after_a_quorum_snapshot(self): result = self.vm.qmp('blockdev-snapshot-sync', node_name='img1', snapshot_file=quorum_snapshot_file, - snapshot_node_name="snap1"); + snapshot_node_name="snap1") self.assert_qmp(result, 'return', {}) result = self.vm.qmp('drive-mirror', job_id='job0', device='quorum0', diff --git a/tests/qemu-iotests/196 b/tests/qemu-iotests/196 index 76509a5ad1..27c1629be3 100755 --- a/tests/qemu-iotests/196 +++ b/tests/qemu-iotests/196 @@ -46,7 +46,7 @@ class TestInvalidateAutoclear(iotests.QMPTestCase): def test_migration(self): result = self.vm_a.qmp('migrate', uri='exec:cat>' + migfile) - self.assert_qmp(result, 'return', {}); + self.assert_qmp(result, 'return', {}) self.assertNotEqual(self.vm_a.event_wait("STOP"), None) with open(disk, 'r+b') as f: From c5339030e64781bf8f0d80ab7c5044b5547df79b Mon Sep 17 00:00:00 2001 From: Vladimir Sementsov-Ogievskiy Date: Fri, 6 Oct 2023 18:41:21 +0300 Subject: [PATCH 0655/1077] iotests: drop some extra ** in qmp() call qmp() method supports passing dict (if it doesn't need substituting '_' to '-' in keys). So, drop some extra '**' operators. Signed-off-by: Vladimir Sementsov-Ogievskiy Reviewed-by: Eric Blake Message-id: 20231006154125.1068348-12-vsementsov@yandex-team.ru Signed-off-by: John Snow --- tests/qemu-iotests/040 | 4 +- tests/qemu-iotests/041 | 14 +++--- tests/qemu-iotests/129 | 2 +- tests/qemu-iotests/147 | 2 +- tests/qemu-iotests/155 | 2 +- tests/qemu-iotests/264 | 12 ++--- tests/qemu-iotests/295 | 5 +- tests/qemu-iotests/296 | 15 +++--- tests/qemu-iotests/tests/migrate-bitmaps-test | 4 +- .../tests/mirror-ready-cancel-error | 50 +++++++++---------- 10 files changed, 54 insertions(+), 56 deletions(-) diff --git a/tests/qemu-iotests/040 b/tests/qemu-iotests/040 index e61e7f2433..4b8bf09a5d 100755 --- a/tests/qemu-iotests/040 +++ b/tests/qemu-iotests/040 @@ -774,7 +774,7 @@ class TestCommitWithFilters(iotests.QMPTestCase): result = self.vm.qmp('object-add', qom_type='throttle-group', id='tg') self.assert_qmp(result, 'return', {}) - result = self.vm.qmp('blockdev-add', **{ + result = self.vm.qmp('blockdev-add', { 'node-name': 'top-filter', 'driver': 'throttle', 'throttle-group': 'tg', @@ -935,7 +935,7 @@ class TestCommitWithOverriddenBacking(iotests.QMPTestCase): self.vm.launch() # Use base_b instead of base_a as the backing of top - result = self.vm.qmp('blockdev-add', **{ + result = self.vm.qmp('blockdev-add', { 'node-name': 'top', 'driver': iotests.imgfmt, 'file': { diff --git a/tests/qemu-iotests/041 b/tests/qemu-iotests/041 index 550e4dc391..3aef42aec8 100755 --- a/tests/qemu-iotests/041 +++ b/tests/qemu-iotests/041 @@ -236,7 +236,7 @@ class TestSingleBlockdev(TestSingleDrive): args = {'driver': iotests.imgfmt, 'node-name': self.qmp_target, 'file': { 'filename': target_img, 'driver': 'file' } } - result = self.vm.qmp("blockdev-add", **args) + result = self.vm.qmp("blockdev-add", args) self.assert_qmp(result, 'return', {}) def test_mirror_to_self(self): @@ -963,7 +963,7 @@ class TestRepairQuorum(iotests.QMPTestCase): #assemble the quorum block device from the individual files args = { "driver": "quorum", "node-name": "quorum0", "vote-threshold": 2, "children": [ "img0", "img1", "img2" ] } - result = self.vm.qmp("blockdev-add", **args) + result = self.vm.qmp("blockdev-add", args) self.assert_qmp(result, 'return', {}) @@ -1278,7 +1278,7 @@ class TestReplaces(iotests.QMPTestCase): """ Check that we can replace filter nodes. """ - result = self.vm.qmp('blockdev-add', **{ + result = self.vm.qmp('blockdev-add', { 'driver': 'copy-on-read', 'node-name': 'filter0', 'file': { @@ -1319,7 +1319,7 @@ class TestFilters(iotests.QMPTestCase): self.vm = iotests.VM().add_device('virtio-scsi,id=vio-scsi') self.vm.launch() - result = self.vm.qmp('blockdev-add', **{ + result = self.vm.qmp('blockdev-add', { 'node-name': 'target', 'driver': iotests.imgfmt, 'file': { @@ -1355,7 +1355,7 @@ class TestFilters(iotests.QMPTestCase): os.remove(backing_img) def test_cor(self): - result = self.vm.qmp('blockdev-add', **{ + result = self.vm.qmp('blockdev-add', { 'node-name': 'filter', 'driver': 'copy-on-read', 'file': self.filterless_chain @@ -1384,7 +1384,7 @@ class TestFilters(iotests.QMPTestCase): assert target_map[1]['depth'] == 0 def test_implicit_mirror_filter(self): - result = self.vm.qmp('blockdev-add', **self.filterless_chain) + result = self.vm.qmp('blockdev-add', self.filterless_chain) self.assert_qmp(result, 'return', {}) # We need this so we can query from above the mirror node @@ -1418,7 +1418,7 @@ class TestFilters(iotests.QMPTestCase): def test_explicit_mirror_filter(self): # Same test as above, but this time we give the mirror filter # a node-name so it will not be invisible - result = self.vm.qmp('blockdev-add', **self.filterless_chain) + result = self.vm.qmp('blockdev-add', self.filterless_chain) self.assert_qmp(result, 'return', {}) # We need this so we can query from above the mirror node diff --git a/tests/qemu-iotests/129 b/tests/qemu-iotests/129 index c75ec62ecf..e1536ee3c3 100755 --- a/tests/qemu-iotests/129 +++ b/tests/qemu-iotests/129 @@ -87,7 +87,7 @@ class TestStopWithBlockJob(iotests.QMPTestCase): iotests.qemu_img('create', '-f', iotests.imgfmt, self.overlay_img, '1G') - result = self.vm.qmp('blockdev-add', **{ + result = self.vm.qmp('blockdev-add', { 'node-name': 'overlay', 'driver': iotests.imgfmt, 'file': { diff --git a/tests/qemu-iotests/147 b/tests/qemu-iotests/147 index 770b73e2f4..08111c5108 100755 --- a/tests/qemu-iotests/147 +++ b/tests/qemu-iotests/147 @@ -58,7 +58,7 @@ class NBDBlockdevAddBase(iotests.QMPTestCase): def client_test(self, filename, address, export=None, node_name='nbd-blockdev', delete=True): bao = self.blockdev_add_options(address, export, node_name) - result = self.vm.qmp('blockdev-add', **bao) + result = self.vm.qmp('blockdev-add', bao) self.assert_qmp(result, 'return', {}) found = False diff --git a/tests/qemu-iotests/155 b/tests/qemu-iotests/155 index d3e1b7401e..0c073fd61b 100755 --- a/tests/qemu-iotests/155 +++ b/tests/qemu-iotests/155 @@ -110,7 +110,7 @@ class BaseClass(iotests.QMPTestCase): elif self.target_blockdev_backing: options['backing'] = self.target_blockdev_backing - result = self.vm.qmp('blockdev-add', **options) + result = self.vm.qmp('blockdev-add', options) self.assert_qmp(result, 'return', {}) def tearDown(self): diff --git a/tests/qemu-iotests/264 b/tests/qemu-iotests/264 index 289381e315..d44deb673a 100755 --- a/tests/qemu-iotests/264 +++ b/tests/qemu-iotests/264 @@ -49,12 +49,12 @@ class TestNbdReconnect(iotests.QMPTestCase): assert job in ('blockdev-backup', 'blockdev-mirror') with qemu_nbd_popen('-k', nbd_sock, '-f', iotests.imgfmt, disk_b): result = self.vm.qmp('blockdev-add', - **{'node_name': 'backup0', - 'driver': 'raw', - 'file': {'driver': 'nbd', - 'server': {'type': 'unix', - 'path': nbd_sock}, - 'reconnect-delay': 10}}) + {'node-name': 'backup0', + 'driver': 'raw', + 'file': {'driver': 'nbd', + 'server': {'type': 'unix', + 'path': nbd_sock}, + 'reconnect-delay': 10}}) self.assert_qmp(result, 'return', {}) result = self.vm.qmp(job, device='drive0', sync='full', target='backup0', diff --git a/tests/qemu-iotests/295 b/tests/qemu-iotests/295 index 270ad3999f..8ebe31054c 100755 --- a/tests/qemu-iotests/295 +++ b/tests/qemu-iotests/295 @@ -102,8 +102,7 @@ class EncryptionSetupTestCase(iotests.QMPTestCase): } } - result = self.vm.qmp('blockdev-add', ** - { + result = self.vm.qmp('blockdev-add', { 'driver': iotests.imgfmt, 'node-name': id, 'read-only': read_only, @@ -120,7 +119,7 @@ class EncryptionSetupTestCase(iotests.QMPTestCase): # close the encrypted block device def closeImageQmp(self, id): - result = self.vm.qmp('blockdev-del', **{ 'node-name': id }) + result = self.vm.qmp('blockdev-del', {'node-name': id}) self.assert_qmp(result, 'return', {}) ########################################################################### diff --git a/tests/qemu-iotests/296 b/tests/qemu-iotests/296 index 19a674c5ae..47d2526b72 100755 --- a/tests/qemu-iotests/296 +++ b/tests/qemu-iotests/296 @@ -42,7 +42,7 @@ class Secret: return [ "secret,id=" + self._id + ",data=" + self._secret] def to_qmp_object(self): - return { "qom_type" : "secret", "id": self.id(), + return { "qom-type" : "secret", "id": self.id(), "data": self.secret() } ################################################################################ @@ -61,9 +61,9 @@ class EncryptionSetupTestCase(iotests.QMPTestCase): # create the secrets and load 'em into the VMs self.secrets = [ Secret(i) for i in range(0, 4) ] for secret in self.secrets: - result = self.vm1.qmp("object-add", **secret.to_qmp_object()) + result = self.vm1.qmp("object-add", secret.to_qmp_object()) self.assert_qmp(result, 'return', {}) - result = self.vm2.qmp("object-add", **secret.to_qmp_object()) + result = self.vm2.qmp("object-add", secret.to_qmp_object()) self.assert_qmp(result, 'return', {}) # test case shutdown @@ -135,15 +135,14 @@ class EncryptionSetupTestCase(iotests.QMPTestCase): result = vm.qmp(command, options=[opts]) self.assert_qmp(result, 'return', {}) else: - result = vm.qmp(command, **opts) + result = vm.qmp(command, opts) self.assert_qmp(result, 'return', {}) ########################################################################### # add virtio-blk consumer for a block device def addImageUser(self, vm, id, disk_id, share_rw=False): - result = vm.qmp('device_add', ** - { + result = vm.qmp('device_add', { 'driver': 'virtio-blk', 'id': id, 'drive': disk_id, @@ -155,7 +154,7 @@ class EncryptionSetupTestCase(iotests.QMPTestCase): # close the encrypted block device def closeImageQmp(self, vm, id): - result = vm.qmp('blockdev-del', **{ 'node-name': id }) + result = vm.qmp('blockdev-del', {'node-name': id}) self.assert_qmp(result, 'return', {}) ########################################################################### @@ -174,7 +173,7 @@ class EncryptionSetupTestCase(iotests.QMPTestCase): }, } - result = vm.qmp('x-blockdev-amend', **args) + result = vm.qmp('x-blockdev-amend', args) iotests.log(result) # Run the job only if it was created event = ('JOB_STATUS_CHANGE', diff --git a/tests/qemu-iotests/tests/migrate-bitmaps-test b/tests/qemu-iotests/tests/migrate-bitmaps-test index 8668caae1e..eebb256485 100755 --- a/tests/qemu-iotests/tests/migrate-bitmaps-test +++ b/tests/qemu-iotests/tests/migrate-bitmaps-test @@ -67,7 +67,7 @@ class TestDirtyBitmapMigration(iotests.QMPTestCase): if persistent: params['persistent'] = True - result = vm.qmp('block-dirty-bitmap-add', **params) + result = vm.qmp('block-dirty-bitmap-add', params) self.assert_qmp(result, 'return', {}) def check_bitmap(self, vm, sha256): @@ -256,7 +256,7 @@ class TestDirtyBitmapBackingMigration(iotests.QMPTestCase): self.vm = iotests.VM() self.vm.launch() - result = self.vm.qmp('blockdev-add', **blockdev) + result = self.vm.qmp('blockdev-add', blockdev) self.assert_qmp(result, 'return', {}) # Check that the bitmaps are there diff --git a/tests/qemu-iotests/tests/mirror-ready-cancel-error b/tests/qemu-iotests/tests/mirror-ready-cancel-error index 01217459b9..a59e245659 100755 --- a/tests/qemu-iotests/tests/mirror-ready-cancel-error +++ b/tests/qemu-iotests/tests/mirror-ready-cancel-error @@ -49,12 +49,12 @@ class TestMirrorReadyCancelError(iotests.QMPTestCase): def add_blockdevs(self, once: bool) -> None: res = self.vm.qmp('blockdev-add', - **{'node-name': 'source', - 'driver': iotests.imgfmt, - 'file': { - 'driver': 'file', - 'filename': source - }}) + {'node-name': 'source', + 'driver': iotests.imgfmt, + 'file': { + 'driver': 'file', + 'filename': source + }}) self.assert_qmp(res, 'return', {}) # blkdebug notes: @@ -63,25 +63,25 @@ class TestMirrorReadyCancelError(iotests.QMPTestCase): # when the job is about to complete, and we want that one to # fail. res = self.vm.qmp('blockdev-add', - **{'node-name': 'target', - 'driver': iotests.imgfmt, - 'file': { - 'driver': 'blkdebug', - 'image': { - 'driver': 'file', - 'filename': target - }, - 'set-state': [{ - 'event': 'flush_to_disk', - 'state': 1, - 'new_state': 2 - }], - 'inject-error': [{ - 'event': 'flush_to_disk', - 'once': once, - 'immediately': True, - 'state': 2 - }]}}) + {'node-name': 'target', + 'driver': iotests.imgfmt, + 'file': { + 'driver': 'blkdebug', + 'image': { + 'driver': 'file', + 'filename': target + }, + 'set-state': [{ + 'event': 'flush_to_disk', + 'state': 1, + 'new_state': 2 + }], + 'inject-error': [{ + 'event': 'flush_to_disk', + 'once': once, + 'immediately': True, + 'state': 2 + }]}}) self.assert_qmp(res, 'return', {}) def start_mirror(self) -> None: From 39995e21261d19e44db00e0ebce2c5616703b29a Mon Sep 17 00:00:00 2001 From: Vladimir Sementsov-Ogievskiy Date: Fri, 6 Oct 2023 18:41:22 +0300 Subject: [PATCH 0656/1077] iotests.py: pause_job(): drop return value The returned value is unused. It's simple to check by command git grep -B 3 '\.pause_job(' Signed-off-by: Vladimir Sementsov-Ogievskiy Reviewed-by: Eric Blake Message-id: 20231006154125.1068348-13-vsementsov@yandex-team.ru Signed-off-by: John Snow --- tests/qemu-iotests/iotests.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/tests/qemu-iotests/iotests.py b/tests/qemu-iotests/iotests.py index ee7b6ddeff..f43814e802 100644 --- a/tests/qemu-iotests/iotests.py +++ b/tests/qemu-iotests/iotests.py @@ -1338,8 +1338,7 @@ class QMPTestCase(unittest.TestCase): result = self.vm.qmp('block-job-pause', device=job_id) self.assert_qmp(result, 'return', {}) if wait: - return self.pause_wait(job_id) - return result + self.pause_wait(job_id) def case_skip(self, reason): '''Skip this test case''' From 9acd49e29e5a3e388c0de0501e1308b507fd1fc4 Mon Sep 17 00:00:00 2001 From: Vladimir Sementsov-Ogievskiy Date: Fri, 6 Oct 2023 18:41:23 +0300 Subject: [PATCH 0657/1077] tests/vm/basevm.py: use cmd() instead of qmp() We don't expect failure here and need 'result' object. cmd() is better in this case. Signed-off-by: Vladimir Sementsov-Ogievskiy Reviewed-by: Eric Blake Message-id: 20231006154125.1068348-14-vsementsov@yandex-team.ru Signed-off-by: John Snow --- tests/vm/basevm.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/vm/basevm.py b/tests/vm/basevm.py index a97e23b0ce..8aef4cff96 100644 --- a/tests/vm/basevm.py +++ b/tests/vm/basevm.py @@ -312,8 +312,8 @@ class BaseVM(object): self._guest = guest # Init console so we can start consuming the chars. self.console_init() - usernet_info = guest.qmp("human-monitor-command", - command_line="info usernet").get("return") + usernet_info = guest.cmd("human-monitor-command", + command_line="info usernet") self.ssh_port = get_info_usernet_hostfwd_port(usernet_info) if not self.ssh_port: raise Exception("Cannot find ssh port from 'info usernet':\n%s" % \ From 25ad2cf6500db3b7f2d88de448791183d7614097 Mon Sep 17 00:00:00 2001 From: Vladimir Sementsov-Ogievskiy Date: Fri, 6 Oct 2023 18:41:24 +0300 Subject: [PATCH 0658/1077] scripts: add python_qmp_updater.py A script, to update the pattern result = self.vm.qmp(...) self.assert_qmp(result, 'return', {}) (and some similar ones) into self.vm.cmd(...) Used in the next commit "python: use vm.cmd() instead of vm.qmp() where appropriate" Signed-off-by: Vladimir Sementsov-Ogievskiy Reviewed-by: Eric Blake Message-id: 20231006154125.1068348-15-vsementsov@yandex-team.ru Signed-off-by: John Snow --- scripts/python_qmp_updater.py | 136 ++++++++++++++++++++++++++++++++++ 1 file changed, 136 insertions(+) create mode 100755 scripts/python_qmp_updater.py diff --git a/scripts/python_qmp_updater.py b/scripts/python_qmp_updater.py new file mode 100755 index 0000000000..494a169812 --- /dev/null +++ b/scripts/python_qmp_updater.py @@ -0,0 +1,136 @@ +#!/usr/bin/env python3 +# +# Intended usage: +# +# git grep -l '\.qmp(' | xargs ./scripts/python_qmp_updater.py +# + +import re +import sys +from typing import Optional + +start_reg = re.compile(r'^(?P *)(?P\w+) = (?P.*).qmp\(', + flags=re.MULTILINE) + +success_reg_templ = re.sub('\n *', '', r""" + (\n*{padding}(?P\#.*$))? + \n*{padding} + ( + self.assert_qmp\({res},\ 'return',\ {{}}\) + | + assert\ {res}\['return'\]\ ==\ {{}} + | + assert\ {res}\ ==\ {{'return':\ {{}}}} + | + self.assertEqual\({res}\['return'\],\ {{}}\) + )""") + +some_check_templ = re.sub('\n *', '', r""" + (\n*{padding}(?P\#.*$))? + \s*self.assert_qmp\({res},""") + + +def tmatch(template: str, text: str, + padding: str, res: str) -> Optional[re.Match[str]]: + return re.match(template.format(padding=padding, res=res), text, + flags=re.MULTILINE) + + +def find_closing_brace(text: str, start: int) -> int: + """ + Having '(' at text[start] search for pairing ')' and return its index. + """ + assert text[start] == '(' + + height = 1 + + for i in range(start + 1, len(text)): + if text[i] == '(': + height += 1 + elif text[i] == ')': + height -= 1 + if height == 0: + return i + + raise ValueError + + +def update(text: str) -> str: + result = '' + + while True: + m = start_reg.search(text) + if m is None: + result += text + break + + result += text[:m.start()] + + args_ind = m.end() + args_end = find_closing_brace(text, args_ind - 1) + + all_args = text[args_ind:args_end].split(',', 1) + + name = all_args[0] + args = None if len(all_args) == 1 else all_args[1] + + unchanged_call = text[m.start():args_end+1] + text = text[args_end+1:] + + padding, res, vm = m.group('padding', 'res', 'vm') + + m = tmatch(success_reg_templ, text, padding, res) + + if m is None: + result += unchanged_call + + if ('query-' not in name and + 'x-debug-block-dirty-bitmap-sha256' not in name and + not tmatch(some_check_templ, text, padding, res)): + print(unchanged_call + text[:200] + '...\n\n') + + continue + + if m.group('comment'): + result += f'{padding}{m.group("comment")}\n' + + result += f'{padding}{vm}.cmd({name}' + + if args: + result += ',' + + if '\n' in args: + m_args = re.search('(?P *).*$', args) + assert m_args is not None + + cur_padding = len(m_args.group('pad')) + expected = len(f'{padding}{res} = {vm}.qmp(') + drop = len(f'{res} = ') + if cur_padding == expected - 1: + # tolerate this bad style + drop -= 1 + elif cur_padding < expected - 1: + # assume nothing to do + drop = 0 + + if drop: + args = re.sub('\n' + ' ' * drop, '\n', args) + + result += args + + result += ')' + + text = text[m.end():] + + return result + + +for fname in sys.argv[1:]: + print(fname) + with open(fname) as f: + t = f.read() + + t = update(t) + + with open(fname, 'w') as f: + f.write(t) From b6aed193e5ecca32bb07e062f58f0daca06e7009 Mon Sep 17 00:00:00 2001 From: Vladimir Sementsov-Ogievskiy Date: Fri, 6 Oct 2023 18:41:25 +0300 Subject: [PATCH 0659/1077] python: use vm.cmd() instead of vm.qmp() where appropriate In many cases we just want an effect of qmp command and want to raise on failure. Use vm.cmd() method which does exactly this. The commit is generated by command git grep -l '\.qmp(' | xargs ./scripts/python_qmp_updater.py And then, fix self.assertRaises to expect ExecuteError exception in tests/qemu-iotests/124 Signed-off-by: Vladimir Sementsov-Ogievskiy Reviewed-by: Eric Blake Message-id: 20231006154125.1068348-16-vsementsov@yandex-team.ru Signed-off-by: John Snow --- tests/avocado/vnc.py | 16 +- tests/qemu-iotests/030 | 168 +++---- tests/qemu-iotests/040 | 172 +++---- tests/qemu-iotests/041 | 471 ++++++++---------- tests/qemu-iotests/045 | 15 +- tests/qemu-iotests/055 | 62 +-- tests/qemu-iotests/056 | 77 ++- tests/qemu-iotests/093 | 42 +- tests/qemu-iotests/118 | 223 ++++----- tests/qemu-iotests/124 | 102 ++-- tests/qemu-iotests/129 | 14 +- tests/qemu-iotests/132 | 5 +- tests/qemu-iotests/139 | 45 +- tests/qemu-iotests/147 | 31 +- tests/qemu-iotests/151 | 104 ++-- tests/qemu-iotests/152 | 10 +- tests/qemu-iotests/155 | 55 +- tests/qemu-iotests/165 | 8 +- tests/qemu-iotests/196 | 3 +- tests/qemu-iotests/205 | 6 +- tests/qemu-iotests/218 | 95 ++-- tests/qemu-iotests/245 | 245 ++++----- tests/qemu-iotests/264 | 31 +- tests/qemu-iotests/281 | 21 +- tests/qemu-iotests/295 | 15 +- tests/qemu-iotests/296 | 15 +- tests/qemu-iotests/298 | 13 +- tests/qemu-iotests/300 | 54 +- tests/qemu-iotests/iotests.py | 9 +- .../tests/backing-file-invalidation | 11 +- tests/qemu-iotests/tests/copy-before-write | 15 +- .../tests/export-incoming-iothread | 6 +- .../qemu-iotests/tests/graph-changes-while-io | 18 +- tests/qemu-iotests/tests/image-fleecing | 3 +- .../tests/migrate-bitmaps-postcopy-test | 31 +- tests/qemu-iotests/tests/migrate-bitmaps-test | 47 +- .../qemu-iotests/tests/migrate-during-backup | 37 +- .../qemu-iotests/tests/migration-permissions | 9 +- .../tests/mirror-ready-cancel-error | 74 ++- tests/qemu-iotests/tests/mirror-top-perms | 16 +- tests/qemu-iotests/tests/nbd-multiconn | 12 +- tests/qemu-iotests/tests/reopen-file | 3 +- .../qemu-iotests/tests/stream-error-on-reset | 6 +- .../qemu-iotests/tests/stream-under-throttle | 7 +- 44 files changed, 974 insertions(+), 1448 deletions(-) diff --git a/tests/avocado/vnc.py b/tests/avocado/vnc.py index aeeefc70be..862c8996a8 100644 --- a/tests/avocado/vnc.py +++ b/tests/avocado/vnc.py @@ -88,9 +88,8 @@ class Vnc(QemuSystemTest): self.vm.add_args('-nodefaults', '-S', '-vnc', ':0,password=on') self.vm.launch() self.assertTrue(self.vm.qmp('query-vnc')['return']['enabled']) - set_password_response = self.vm.qmp('change-vnc-password', - password='new_password') - self.assertEqual(set_password_response['return'], {}) + self.vm.cmd('change-vnc-password', + password='new_password') def test_change_listen(self): a, b, c = find_free_ports(3) @@ -105,12 +104,11 @@ class Vnc(QemuSystemTest): self.assertFalse(check_connect(b)) self.assertFalse(check_connect(c)) - res = self.vm.qmp('display-update', type='vnc', - addresses=[{'type': 'inet', 'host': VNC_ADDR, - 'port': str(b)}, - {'type': 'inet', 'host': VNC_ADDR, - 'port': str(c)}]) - self.assertEqual(res['return'], {}) + self.vm.cmd('display-update', type='vnc', + addresses=[{'type': 'inet', 'host': VNC_ADDR, + 'port': str(b)}, + {'type': 'inet', 'host': VNC_ADDR, + 'port': str(c)}]) self.assertEqual(self.vm.qmp('query-vnc')['return']['service'], str(b)) self.assertFalse(check_connect(a)) self.assertTrue(check_connect(b)) diff --git a/tests/qemu-iotests/030 b/tests/qemu-iotests/030 index 98595d47fe..0e6a39d103 100755 --- a/tests/qemu-iotests/030 +++ b/tests/qemu-iotests/030 @@ -56,8 +56,7 @@ class TestSingleDrive(iotests.QMPTestCase): def test_stream(self): self.assert_no_active_block_jobs() - result = self.vm.qmp('block-stream', device='drive0') - self.assert_qmp(result, 'return', {}) + self.vm.cmd('block-stream', device='drive0') self.wait_until_completed() @@ -77,8 +76,7 @@ class TestSingleDrive(iotests.QMPTestCase): qemu_io('-f', iotests.imgfmt, '-rU', '-c', 'map', mid_img).stdout, 'image file map matches backing file before streaming') - result = self.vm.qmp('block-stream', device='mid', job_id='stream-mid') - self.assert_qmp(result, 'return', {}) + self.vm.cmd('block-stream', device='mid', job_id='stream-mid') self.wait_until_completed(drive='stream-mid') @@ -94,8 +92,7 @@ class TestSingleDrive(iotests.QMPTestCase): self.assert_no_active_block_jobs() self.vm.pause_drive('drive0') - result = self.vm.qmp('block-stream', device='drive0') - self.assert_qmp(result, 'return', {}) + self.vm.cmd('block-stream', device='drive0') self.pause_job('drive0', wait=False) self.vm.resume_drive('drive0') @@ -108,8 +105,7 @@ class TestSingleDrive(iotests.QMPTestCase): result = self.vm.qmp('query-block-jobs') self.assert_qmp(result, 'return[0]/offset', offset) - result = self.vm.qmp('block-job-resume', device='drive0') - self.assert_qmp(result, 'return', {}) + self.vm.cmd('block-job-resume', device='drive0') self.wait_until_completed() @@ -129,8 +125,7 @@ class TestSingleDrive(iotests.QMPTestCase): '-f', iotests.imgfmt, '-rU', '-c', 'map', test_img).stdout # This is a no-op: no data should ever be copied from the base image - result = self.vm.qmp('block-stream', device='drive0', base=mid_img) - self.assert_qmp(result, 'return', {}) + self.vm.cmd('block-stream', device='drive0', base=mid_img) self.wait_until_completed() @@ -144,8 +139,7 @@ class TestSingleDrive(iotests.QMPTestCase): def test_stream_partial(self): self.assert_no_active_block_jobs() - result = self.vm.qmp('block-stream', device='drive0', base=backing_img) - self.assert_qmp(result, 'return', {}) + self.vm.cmd('block-stream', device='drive0', base=backing_img) self.wait_until_completed() @@ -172,24 +166,22 @@ class TestSingleDrive(iotests.QMPTestCase): qemu_img('create', '-f', iotests.imgfmt, ro_top_path, str(self.image_len)) - result = self.vm.qmp('blockdev-add', - node_name='ro-top', - driver=iotests.imgfmt, - read_only=True, - file={ - 'driver': 'file', - 'filename': ro_top_path, - 'read-only': True - }, - backing='mid') - self.assert_qmp(result, 'return', {}) + self.vm.cmd('blockdev-add', + node_name='ro-top', + driver=iotests.imgfmt, + read_only=True, + file={ + 'driver': 'file', + 'filename': ro_top_path, + 'read-only': True + }, + backing='mid') result = self.vm.qmp('block-stream', job_id='stream', device='ro-top', base_node='base') self.assert_qmp(result, 'error/desc', 'Block node is read-only') - result = self.vm.qmp('blockdev-del', node_name='ro-top') - self.assert_qmp(result, 'return', {}) + self.vm.cmd('blockdev-del', node_name='ro-top') class TestParallelOps(iotests.QMPTestCase): @@ -254,10 +246,9 @@ class TestParallelOps(iotests.QMPTestCase): node_name = 'node%d' % i job_id = 'stream-%s' % node_name pending_jobs.append(job_id) - result = self.vm.qmp('block-stream', device=node_name, - job_id=job_id, bottom=f'node{i-1}', - speed=1024) - self.assert_qmp(result, 'return', {}) + self.vm.cmd('block-stream', device=node_name, + job_id=job_id, bottom=f'node{i-1}', + speed=1024) # Do this in reverse: After unthrottling them, some jobs may finish # before we have unthrottled all of them. This will drain their @@ -269,8 +260,7 @@ class TestParallelOps(iotests.QMPTestCase): # Starting from the top (i.e. in reverse) does not have this problem: # When a job finishes, the ones below it are not advanced. for job in reversed(pending_jobs): - result = self.vm.qmp('block-job-set-speed', device=job, speed=0) - self.assert_qmp(result, 'return', {}) + self.vm.cmd('block-job-set-speed', device=job, speed=0) # Wait for all jobs to be finished. while len(pending_jobs) > 0: @@ -297,10 +287,9 @@ class TestParallelOps(iotests.QMPTestCase): self.assert_no_active_block_jobs() # Set a speed limit to make sure that this job blocks the rest - result = self.vm.qmp('block-stream', device='node4', - job_id='stream-node4', base=self.imgs[1], - filter_node_name='stream-filter', speed=1024*1024) - self.assert_qmp(result, 'return', {}) + self.vm.cmd('block-stream', device='node4', + job_id='stream-node4', base=self.imgs[1], + filter_node_name='stream-filter', speed=1024*1024) result = self.vm.qmp('block-stream', device='node5', job_id='stream-node5', base=self.imgs[2]) self.assert_qmp(result, 'error/desc', @@ -328,8 +317,7 @@ class TestParallelOps(iotests.QMPTestCase): self.assert_qmp(result, 'error/desc', "Node 'node2' is busy: block device is in use by block job: stream") - result = self.vm.qmp('block-job-set-speed', device='stream-node4', speed=0) - self.assert_qmp(result, 'return', {}) + self.vm.cmd('block-job-set-speed', device='stream-node4', speed=0) self.wait_until_completed(drive='stream-node4') self.assert_no_active_block_jobs() @@ -341,8 +329,7 @@ class TestParallelOps(iotests.QMPTestCase): self.assert_no_active_block_jobs() # Set a speed limit to make sure that this job blocks the rest - result = self.vm.qmp('block-commit', device='drive0', top=self.imgs[5], base=self.imgs[3], job_id='commit-node3', speed=1024*1024) - self.assert_qmp(result, 'return', {}) + self.vm.cmd('block-commit', device='drive0', top=self.imgs[5], base=self.imgs[3], job_id='commit-node3', speed=1024*1024) result = self.vm.qmp('block-stream', device='node3', job_id='stream-node3') self.assert_qmp(result, 'error/desc', @@ -365,8 +352,7 @@ class TestParallelOps(iotests.QMPTestCase): self.assert_qmp(result, 'error/desc', "Node 'drive0' is busy: block device is in use by block job: commit") - result = self.vm.qmp('block-job-set-speed', device='commit-node3', speed=0) - self.assert_qmp(result, 'return', {}) + self.vm.cmd('block-job-set-speed', device='commit-node3', speed=0) self.wait_until_completed(drive='commit-node3') @@ -377,23 +363,20 @@ class TestParallelOps(iotests.QMPTestCase): self.assert_no_active_block_jobs() # Set a speed limit to make sure that this job blocks the rest - result = self.vm.qmp('block-commit', device='drive0', base=self.imgs[3], job_id='commit-drive0', speed=1024*1024) - self.assert_qmp(result, 'return', {}) + self.vm.cmd('block-commit', device='drive0', base=self.imgs[3], job_id='commit-drive0', speed=1024*1024) result = self.vm.qmp('block-stream', device='node5', base=self.imgs[3], job_id='stream-node6') self.assert_qmp(result, 'error/desc', "Node 'node5' is busy: block device is in use by block job: commit") - result = self.vm.qmp('block-job-set-speed', device='commit-drive0', speed=0) - self.assert_qmp(result, 'return', {}) + self.vm.cmd('block-job-set-speed', device='commit-drive0', speed=0) event = self.vm.event_wait(name='BLOCK_JOB_READY') self.assert_qmp(event, 'data/device', 'commit-drive0') self.assert_qmp(event, 'data/type', 'commit') self.assert_qmp_absent(event, 'data/error') - result = self.vm.qmp('block-job-complete', device='commit-drive0') - self.assert_qmp(result, 'return', {}) + self.vm.cmd('block-job-complete', device='commit-drive0') self.wait_until_completed(drive='commit-drive0') @@ -404,18 +387,16 @@ class TestParallelOps(iotests.QMPTestCase): self.assert_no_active_block_jobs() # Commit from node2 into node0 - result = self.vm.qmp('block-commit', device='drive0', - top=self.imgs[2], base=self.imgs[0], - filter_node_name='commit-filter', speed=1024*1024) - self.assert_qmp(result, 'return', {}) + self.vm.cmd('block-commit', device='drive0', + top=self.imgs[2], base=self.imgs[0], + filter_node_name='commit-filter', speed=1024*1024) # Stream from node2 into node4 result = self.vm.qmp('block-stream', device='node4', base_node='node2', job_id='node4') self.assert_qmp(result, 'error/desc', "Cannot freeze 'backing' link to 'commit-filter'") - result = self.vm.qmp('block-job-set-speed', device='drive0', speed=0) - self.assert_qmp(result, 'return', {}) + self.vm.cmd('block-job-set-speed', device='drive0', speed=0) self.wait_until_completed() self.assert_no_active_block_jobs() @@ -428,18 +409,15 @@ class TestParallelOps(iotests.QMPTestCase): self.assert_no_active_block_jobs() # Commit from node2 into node0 - result = self.vm.qmp('block-commit', device='drive0', - top_node='node2', base_node='node0', - filter_node_name='commit-filter', speed=1024*1024) - self.assert_qmp(result, 'return', {}) + self.vm.cmd('block-commit', device='drive0', + top_node='node2', base_node='node0', + filter_node_name='commit-filter', speed=1024*1024) # Stream from node2 into node4 - result = self.vm.qmp('block-stream', device='node4', - base_node='commit-filter', job_id='node4') - self.assert_qmp(result, 'return', {}) + self.vm.cmd('block-stream', device='node4', + base_node='commit-filter', job_id='node4') - result = self.vm.qmp('block-job-set-speed', device='drive0', speed=0) - self.assert_qmp(result, 'return', {}) + self.vm.cmd('block-job-set-speed', device='drive0', speed=0) self.vm.run_job(job='drive0', auto_dismiss=True) self.vm.run_job(job='node4', auto_dismiss=True) @@ -458,12 +436,10 @@ class TestParallelOps(iotests.QMPTestCase): self.assert_no_active_block_jobs() # Stream from node0 into node2 - result = self.vm.qmp('block-stream', device='node2', base_node='node0', job_id='node2') - self.assert_qmp(result, 'return', {}) + self.vm.cmd('block-stream', device='node2', base_node='node0', job_id='node2') # Commit from the active layer into node3 - result = self.vm.qmp('block-commit', device='drive0', base=self.imgs[3]) - self.assert_qmp(result, 'return', {}) + self.vm.cmd('block-commit', device='drive0', base=self.imgs[3]) # Wait for all jobs to be finished. pending_jobs = ['node2', 'drive0'] @@ -490,16 +466,13 @@ class TestParallelOps(iotests.QMPTestCase): self.assert_no_active_block_jobs() # Stream from node0 into node4 - result = self.vm.qmp('block-stream', device='node4', base_node='node0', job_id='node4', speed=1024*1024) - self.assert_qmp(result, 'return', {}) + self.vm.cmd('block-stream', device='node4', base_node='node0', job_id='node4', speed=1024*1024) # Commit from the active layer into node5 - result = self.vm.qmp('block-commit', device='drive0', base=self.imgs[5], speed=1024*1024) - self.assert_qmp(result, 'return', {}) + self.vm.cmd('block-commit', device='drive0', base=self.imgs[5], speed=1024*1024) for job in ['drive0', 'node4']: - result = self.vm.qmp('block-job-set-speed', device=job, speed=0) - self.assert_qmp(result, 'return', {}) + self.vm.cmd('block-job-set-speed', device=job, speed=0) # Wait for all jobs to be finished. pending_jobs = ['node4', 'drive0'] @@ -549,8 +522,7 @@ class TestParallelOps(iotests.QMPTestCase): "'base' and 'base-node' cannot be specified at the same time") # Success: the base node is a backing file of the top node - result = self.vm.qmp('block-stream', device='node4', base_node='node2', job_id='stream') - self.assert_qmp(result, 'return', {}) + self.vm.cmd('block-stream', device='node4', base_node='node2', job_id='stream') self.wait_until_completed(drive='stream') @@ -606,8 +578,7 @@ class TestQuorum(iotests.QMPTestCase): self.assert_no_active_block_jobs() - result = self.vm.qmp('block-stream', device='node0', job_id='stream-node0') - self.assert_qmp(result, 'return', {}) + self.vm.cmd('block-stream', device='node0', job_id='stream-node0') self.wait_until_completed(drive='stream-node0') @@ -636,8 +607,7 @@ class TestSmallerBackingFile(iotests.QMPTestCase): def test_stream(self): self.assert_no_active_block_jobs() - result = self.vm.qmp('block-stream', device='drive0') - self.assert_qmp(result, 'return', {}) + self.vm.cmd('block-stream', device='drive0') self.wait_until_completed() @@ -694,8 +664,7 @@ class TestEIO(TestErrors): def test_report(self): self.assert_no_active_block_jobs() - result = self.vm.qmp('block-stream', device='drive0') - self.assert_qmp(result, 'return', {}) + self.vm.cmd('block-stream', device='drive0') completed = False error = False @@ -722,8 +691,7 @@ class TestEIO(TestErrors): def test_ignore(self): self.assert_no_active_block_jobs() - result = self.vm.qmp('block-stream', device='drive0', on_error='ignore') - self.assert_qmp(result, 'return', {}) + self.vm.cmd('block-stream', device='drive0', on_error='ignore') error = False completed = False @@ -756,8 +724,7 @@ class TestEIO(TestErrors): def test_stop(self): self.assert_no_active_block_jobs() - result = self.vm.qmp('block-stream', device='drive0', on_error='stop') - self.assert_qmp(result, 'return', {}) + self.vm.cmd('block-stream', device='drive0', on_error='stop') error = False completed = False @@ -779,8 +746,7 @@ class TestEIO(TestErrors): self.assert_qmp(result, 'return[0]/offset', self.STREAM_BUFFER_SIZE) self.assert_qmp(result, 'return[0]/io-status', 'failed') - result = self.vm.qmp('block-job-resume', device='drive0') - self.assert_qmp(result, 'return', {}) + self.vm.cmd('block-job-resume', device='drive0') result = self.vm.qmp('query-block-jobs') if result == {'return': []}: @@ -806,8 +772,7 @@ class TestEIO(TestErrors): def test_enospc(self): self.assert_no_active_block_jobs() - result = self.vm.qmp('block-stream', device='drive0', on_error='enospc') - self.assert_qmp(result, 'return', {}) + self.vm.cmd('block-stream', device='drive0', on_error='enospc') completed = False error = False @@ -852,8 +817,7 @@ class TestENOSPC(TestErrors): def test_enospc(self): self.assert_no_active_block_jobs() - result = self.vm.qmp('block-stream', device='drive0', on_error='enospc') - self.assert_qmp(result, 'return', {}) + self.vm.cmd('block-stream', device='drive0', on_error='enospc') error = False completed = False @@ -875,8 +839,7 @@ class TestENOSPC(TestErrors): self.assert_qmp(result, 'return[0]/offset', self.STREAM_BUFFER_SIZE) self.assert_qmp(result, 'return[0]/io-status', 'nospace') - result = self.vm.qmp('block-job-resume', device='drive0') - self.assert_qmp(result, 'return', {}) + self.vm.cmd('block-job-resume', device='drive0') result = self.vm.qmp('query-block-jobs') if result == {'return': []}: @@ -921,8 +884,7 @@ class TestStreamStop(iotests.QMPTestCase): self.assert_no_active_block_jobs() self.vm.pause_drive('drive0') - result = self.vm.qmp('block-stream', device='drive0') - self.assert_qmp(result, 'return', {}) + self.vm.cmd('block-stream', device='drive0') time.sleep(0.1) events = self.vm.get_qmp_events(wait=False) @@ -955,11 +917,9 @@ class TestSetSpeed(iotests.QMPTestCase): def perf_test_throughput(self): self.assert_no_active_block_jobs() - result = self.vm.qmp('block-stream', device='drive0') - self.assert_qmp(result, 'return', {}) + self.vm.cmd('block-stream', device='drive0') - result = self.vm.qmp('block-job-set-speed', device='drive0', speed=8 * 1024 * 1024) - self.assert_qmp(result, 'return', {}) + self.vm.cmd('block-job-set-speed', device='drive0', speed=8 * 1024 * 1024) self.wait_until_completed() @@ -969,16 +929,14 @@ class TestSetSpeed(iotests.QMPTestCase): self.assert_no_active_block_jobs() self.vm.pause_drive('drive0') - result = self.vm.qmp('block-stream', device='drive0') - self.assert_qmp(result, 'return', {}) + self.vm.cmd('block-stream', device='drive0') # Default speed is 0 result = self.vm.qmp('query-block-jobs') self.assert_qmp(result, 'return[0]/device', 'drive0') self.assert_qmp(result, 'return[0]/speed', 0) - result = self.vm.qmp('block-job-set-speed', device='drive0', speed=8 * 1024 * 1024) - self.assert_qmp(result, 'return', {}) + self.vm.cmd('block-job-set-speed', device='drive0', speed=8 * 1024 * 1024) # Ensure the speed we set was accepted result = self.vm.qmp('query-block-jobs') @@ -989,8 +947,7 @@ class TestSetSpeed(iotests.QMPTestCase): self.vm.pause_drive('drive0') # Check setting speed in block-stream works - result = self.vm.qmp('block-stream', device='drive0', speed=4 * 1024 * 1024) - self.assert_qmp(result, 'return', {}) + self.vm.cmd('block-stream', device='drive0', speed=4 * 1024 * 1024) result = self.vm.qmp('query-block-jobs') self.assert_qmp(result, 'return[0]/device', 'drive0') @@ -1007,8 +964,7 @@ class TestSetSpeed(iotests.QMPTestCase): self.assert_no_active_block_jobs() self.vm.pause_drive('drive0') - result = self.vm.qmp('block-stream', device='drive0') - self.assert_qmp(result, 'return', {}) + self.vm.cmd('block-stream', device='drive0') result = self.vm.qmp('block-job-set-speed', device='drive0', speed=-1) self.assert_qmp(result, 'error/desc', "Parameter 'speed' expects a non-negative value") diff --git a/tests/qemu-iotests/040 b/tests/qemu-iotests/040 index 4b8bf09a5d..5c18e413ec 100755 --- a/tests/qemu-iotests/040 +++ b/tests/qemu-iotests/040 @@ -61,17 +61,14 @@ class ImageCommitTestCase(iotests.QMPTestCase): def run_commit_test(self, top, base, need_ready=False, node_names=False): self.assert_no_active_block_jobs() if node_names: - result = self.vm.qmp('block-commit', device='drive0', top_node=top, base_node=base) - self.assert_qmp(result, 'return', {}) + self.vm.cmd('block-commit', device='drive0', top_node=top, base_node=base) else: - result = self.vm.qmp('block-commit', device='drive0', top=top, base=base) - self.assert_qmp(result, 'return', {}) + self.vm.cmd('block-commit', device='drive0', top=top, base=base) self.wait_for_complete(need_ready) def run_default_commit_test(self): self.assert_no_active_block_jobs() - result = self.vm.qmp('block-commit', device='drive0') - self.assert_qmp(result, 'return', {}) + self.vm.cmd('block-commit', device='drive0') self.wait_for_complete() class TestSingleDrive(ImageCommitTestCase): @@ -118,38 +115,30 @@ class TestSingleDrive(ImageCommitTestCase): @iotests.skip_if_unsupported(['throttle']) def test_commit_with_filter_and_quit(self): - result = self.vm.qmp('object-add', qom_type='throttle-group', id='tg') - self.assert_qmp(result, 'return', {}) + self.vm.cmd('object-add', qom_type='throttle-group', id='tg') # Add a filter outside of the backing chain - result = self.vm.qmp('blockdev-add', driver='throttle', node_name='filter', throttle_group='tg', file='mid') - self.assert_qmp(result, 'return', {}) + self.vm.cmd('blockdev-add', driver='throttle', node_name='filter', throttle_group='tg', file='mid') - result = self.vm.qmp('block-commit', device='drive0') - self.assert_qmp(result, 'return', {}) + self.vm.cmd('block-commit', device='drive0') # Quit immediately, thus forcing a simultaneous cancel of the # block job and a bdrv_drain_all() - result = self.vm.qmp('quit') - self.assert_qmp(result, 'return', {}) + self.vm.cmd('quit') # Same as above, but this time we add the filter after starting the job @iotests.skip_if_unsupported(['throttle']) def test_commit_plus_filter_and_quit(self): - result = self.vm.qmp('object-add', qom_type='throttle-group', id='tg') - self.assert_qmp(result, 'return', {}) + self.vm.cmd('object-add', qom_type='throttle-group', id='tg') - result = self.vm.qmp('block-commit', device='drive0') - self.assert_qmp(result, 'return', {}) + self.vm.cmd('block-commit', device='drive0') # Add a filter outside of the backing chain - result = self.vm.qmp('blockdev-add', driver='throttle', node_name='filter', throttle_group='tg', file='mid') - self.assert_qmp(result, 'return', {}) + self.vm.cmd('blockdev-add', driver='throttle', node_name='filter', throttle_group='tg', file='mid') # Quit immediately, thus forcing a simultaneous cancel of the # block job and a bdrv_drain_all() - result = self.vm.qmp('quit') - self.assert_qmp(result, 'return', {}) + self.vm.cmd('quit') def test_device_not_found(self): result = self.vm.qmp('block-commit', device='nonexistent', top='%s' % mid_img) @@ -226,8 +215,7 @@ class TestSingleDrive(ImageCommitTestCase): def test_top_node_in_wrong_chain(self): self.assert_no_active_block_jobs() - result = self.vm.qmp('blockdev-add', driver='null-co', node_name='null') - self.assert_qmp(result, 'return', {}) + self.vm.cmd('blockdev-add', driver='null-co', node_name='null') result = self.vm.qmp('block-commit', device='drive0', top_node='null', base_node='base') self.assert_qmp(result, 'error/class', 'GenericError') @@ -240,11 +228,9 @@ class TestSingleDrive(ImageCommitTestCase): return self.assert_no_active_block_jobs() - result = self.vm.qmp('block-commit', device='drive0', top=mid_img, - base=backing_img, speed=(self.image_len // 4)) - self.assert_qmp(result, 'return', {}) - result = self.vm.qmp('device_del', id='scsi0') - self.assert_qmp(result, 'return', {}) + self.vm.cmd('block-commit', device='drive0', top=mid_img, + base=backing_img, speed=(self.image_len // 4)) + self.vm.cmd('device_del', id='scsi0') cancelled = False deleted = False @@ -270,9 +256,8 @@ class TestSingleDrive(ImageCommitTestCase): return self.assert_no_active_block_jobs() - result = self.vm.qmp('block-commit', device='drive0', top=mid_img, - base=backing_img, speed=(self.image_len // 4)) - self.assert_qmp(result, 'return', {}) + self.vm.cmd('block-commit', device='drive0', top=mid_img, + base=backing_img, speed=(self.image_len // 4)) result = self.vm.qmp('query-block') self.assert_qmp(result, 'return[0]/inserted/file', test_img) @@ -407,8 +392,7 @@ class TestSetSpeed(ImageCommitTestCase): self.assert_no_active_block_jobs() self.vm.pause_drive('drive0') - result = self.vm.qmp('block-commit', device='drive0', top=mid_img, speed=1024 * 1024) - self.assert_qmp(result, 'return', {}) + self.vm.cmd('block-commit', device='drive0', top=mid_img, speed=1024 * 1024) # Ensure the speed we set was accepted result = self.vm.qmp('query-block-jobs') @@ -481,8 +465,7 @@ class TestErrorHandling(iotests.QMPTestCase): os.remove(backing_img) def blockdev_add(self, **kwargs): - result = self.vm.qmp('blockdev-add', **kwargs) - self.assert_qmp(result, 'return', {}) + self.vm.cmd('blockdev-add', **kwargs) def add_block_nodes(self, base_debug=None, mid_debug=None, top_debug=None): self.blockdev_add(node_name='base-file', driver='file', @@ -528,11 +511,9 @@ class TestErrorHandling(iotests.QMPTestCase): completed = True elif ev['event'] == 'BLOCK_JOB_ERROR': if error_pauses_job: - result = self.vm.qmp('block-job-resume', device='job0') - self.assert_qmp(result, 'return', {}) + self.vm.cmd('block-job-resume', device='job0') elif ev['event'] == 'BLOCK_JOB_READY': - result = self.vm.qmp('block-job-complete', device='job0') - self.assert_qmp(result, 'return', {}) + self.vm.cmd('block-job-complete', device='job0') else: self.fail("Unexpected event: %s" % ev) log.append(iotests.filter_qmp_event(ev)) @@ -595,11 +576,10 @@ class TestErrorHandling(iotests.QMPTestCase): self.add_block_nodes(top_debug=top_debug, mid_debug=mid_debug, base_debug=base_debug) - result = self.vm.qmp('block-commit', job_id='job0', device='top-fmt', - top_node='top-fmt' if active else 'mid-fmt', - base_node='mid-fmt' if active else 'base-fmt', - on_error=on_error) - self.assert_qmp(result, 'return', {}) + self.vm.cmd('block-commit', job_id='job0', device='top-fmt', + top_node='top-fmt' if active else 'mid-fmt', + base_node='mid-fmt' if active else 'base-fmt', + on_error=on_error) def testActiveReadErrorReport(self): self.prepare_and_start_job('report', top_event='read_aio') @@ -771,10 +751,9 @@ class TestCommitWithFilters(iotests.QMPTestCase): self.vm = iotests.VM().add_device('virtio-scsi,id=vio-scsi') self.vm.launch() - result = self.vm.qmp('object-add', qom_type='throttle-group', id='tg') - self.assert_qmp(result, 'return', {}) + self.vm.cmd('object-add', qom_type='throttle-group', id='tg') - result = self.vm.qmp('blockdev-add', { + self.vm.cmd('blockdev-add', { 'node-name': 'top-filter', 'driver': 'throttle', 'throttle-group': 'tg', @@ -816,7 +795,6 @@ class TestCommitWithFilters(iotests.QMPTestCase): } } }) - self.assert_qmp(result, 'return', {}) def tearDown(self): self.vm.shutdown() @@ -833,13 +811,12 @@ class TestCommitWithFilters(iotests.QMPTestCase): return self.vm.node_info(node)['image']['filename'] def test_filterless_commit(self): - result = self.vm.qmp('block-commit', - job_id='commit', - device='top-filter', - top_node='cow-2', - base_node='cow-1', - backing_file=self.img1) - self.assert_qmp(result, 'return', {}) + self.vm.cmd('block-commit', + job_id='commit', + device='top-filter', + top_node='cow-2', + base_node='cow-1', + backing_file=self.img1) self.wait_until_completed(drive='commit') self.assertIsNotNone(self.vm.node_info('cow-3')) @@ -850,13 +827,12 @@ class TestCommitWithFilters(iotests.QMPTestCase): self.pattern_files[2] = self.img1 def test_commit_through_filter(self): - result = self.vm.qmp('block-commit', - job_id='commit', - device='top-filter', - top_node='cow-1', - base_node='cow-0', - backing_file=self.img0) - self.assert_qmp(result, 'return', {}) + self.vm.cmd('block-commit', + job_id='commit', + device='top-filter', + top_node='cow-1', + base_node='cow-0', + backing_file=self.img0) self.wait_until_completed(drive='commit') self.assertIsNotNone(self.vm.node_info('cow-2')) @@ -871,9 +847,8 @@ class TestCommitWithFilters(iotests.QMPTestCase): # Add a device, so the commit job finds a parent it can change # to point to the base node (so we can test that top-filter is # dropped from the graph) - result = self.vm.qmp('device_add', id='drv0', driver='scsi-hd', - bus='vio-scsi.0', drive='top-filter') - self.assert_qmp(result, 'return', {}) + self.vm.cmd('device_add', id='drv0', driver='scsi-hd', + bus='vio-scsi.0', drive='top-filter') # Try to release our reference to top-filter; that should not # work because drv0 uses it @@ -881,16 +856,14 @@ class TestCommitWithFilters(iotests.QMPTestCase): self.assert_qmp(result, 'error/class', 'GenericError') self.assert_qmp(result, 'error/desc', 'Node top-filter is in use') - result = self.vm.qmp('block-commit', - job_id='commit', - device='top-filter', - base_node='cow-2') - self.assert_qmp(result, 'return', {}) + self.vm.cmd('block-commit', + job_id='commit', + device='top-filter', + base_node='cow-2') self.complete_and_wait(drive='commit') # Try to release our reference to top-filter again - result = self.vm.qmp('blockdev-del', node_name='top-filter') - self.assert_qmp(result, 'return', {}) + self.vm.cmd('blockdev-del', node_name='top-filter') self.assertIsNone(self.vm.node_info('top-filter')) self.assertIsNone(self.vm.node_info('cow-3')) @@ -905,12 +878,11 @@ class TestCommitWithFilters(iotests.QMPTestCase): self.pattern_files[3] = self.img2 def test_filtered_active_commit_without_filter(self): - result = self.vm.qmp('block-commit', - job_id='commit', - device='top-filter', - top_node='cow-3', - base_node='cow-2') - self.assert_qmp(result, 'return', {}) + self.vm.cmd('block-commit', + job_id='commit', + device='top-filter', + top_node='cow-3', + base_node='cow-2') self.complete_and_wait(drive='commit') self.assertIsNotNone(self.vm.node_info('top-filter')) @@ -935,23 +907,22 @@ class TestCommitWithOverriddenBacking(iotests.QMPTestCase): self.vm.launch() # Use base_b instead of base_a as the backing of top - result = self.vm.qmp('blockdev-add', { - 'node-name': 'top', - 'driver': iotests.imgfmt, - 'file': { - 'driver': 'file', - 'filename': self.img_top - }, - 'backing': { - 'node-name': 'base', - 'driver': iotests.imgfmt, - 'file': { - 'driver': 'file', - 'filename': self.img_base_b - } - } - }) - self.assert_qmp(result, 'return', {}) + self.vm.cmd('blockdev-add', { + 'node-name': 'top', + 'driver': iotests.imgfmt, + 'file': { + 'driver': 'file', + 'filename': self.img_top + }, + 'backing': { + 'node-name': 'base', + 'driver': iotests.imgfmt, + 'file': { + 'driver': 'file', + 'filename': self.img_base_b + } + } + }) def tearDown(self): self.vm.shutdown() @@ -971,11 +942,10 @@ class TestCommitWithOverriddenBacking(iotests.QMPTestCase): def test_commit_to_b(self): # Try committing to base_b (which should work, since that is # actually top's backing image) - result = self.vm.qmp('block-commit', - job_id='commit', - device='top', - base=self.img_base_b) - self.assert_qmp(result, 'return', {}) + self.vm.cmd('block-commit', + job_id='commit', + device='top', + base=self.img_base_b) self.vm.event_wait('BLOCK_JOB_READY') self.vm.qmp('block-job-complete', device='commit') diff --git a/tests/qemu-iotests/041 b/tests/qemu-iotests/041 index 3aef42aec8..98d17b1388 100755 --- a/tests/qemu-iotests/041 +++ b/tests/qemu-iotests/041 @@ -65,9 +65,8 @@ class TestSingleDrive(iotests.QMPTestCase): def test_complete(self): self.assert_no_active_block_jobs() - result = self.vm.qmp(self.qmp_cmd, device='drive0', sync='full', - target=self.qmp_target) - self.assert_qmp(result, 'return', {}) + self.vm.cmd(self.qmp_cmd, device='drive0', sync='full', + target=self.qmp_target) self.complete_and_wait() result = self.vm.qmp('query-block') @@ -79,9 +78,8 @@ class TestSingleDrive(iotests.QMPTestCase): def test_cancel(self): self.assert_no_active_block_jobs() - result = self.vm.qmp(self.qmp_cmd, device='drive0', sync='full', - target=self.qmp_target) - self.assert_qmp(result, 'return', {}) + self.vm.cmd(self.qmp_cmd, device='drive0', sync='full', + target=self.qmp_target) self.cancel_and_wait(force=True) result = self.vm.qmp('query-block') @@ -90,9 +88,8 @@ class TestSingleDrive(iotests.QMPTestCase): def test_cancel_after_ready(self): self.assert_no_active_block_jobs() - result = self.vm.qmp(self.qmp_cmd, device='drive0', sync='full', - target=self.qmp_target) - self.assert_qmp(result, 'return', {}) + self.vm.cmd(self.qmp_cmd, device='drive0', sync='full', + target=self.qmp_target) self.wait_ready_and_cancel() result = self.vm.qmp('query-block') @@ -104,9 +101,8 @@ class TestSingleDrive(iotests.QMPTestCase): def test_pause(self): self.assert_no_active_block_jobs() - result = self.vm.qmp(self.qmp_cmd, device='drive0', sync='full', - target=self.qmp_target) - self.assert_qmp(result, 'return', {}) + self.vm.cmd(self.qmp_cmd, device='drive0', sync='full', + target=self.qmp_target) self.pause_job('drive0') @@ -117,8 +113,7 @@ class TestSingleDrive(iotests.QMPTestCase): result = self.vm.qmp('query-block-jobs') self.assert_qmp(result, 'return[0]/offset', offset) - result = self.vm.qmp('block-job-resume', device='drive0') - self.assert_qmp(result, 'return', {}) + self.vm.cmd('block-job-resume', device='drive0') self.complete_and_wait() self.vm.shutdown() @@ -129,9 +124,8 @@ class TestSingleDrive(iotests.QMPTestCase): self.assert_no_active_block_jobs() # A small buffer is rounded up automatically - result = self.vm.qmp(self.qmp_cmd, device='drive0', sync='full', - buf_size=4096, target=self.qmp_target) - self.assert_qmp(result, 'return', {}) + self.vm.cmd(self.qmp_cmd, device='drive0', sync='full', + buf_size=4096, target=self.qmp_target) self.complete_and_wait() result = self.vm.qmp('query-block') @@ -145,9 +139,8 @@ class TestSingleDrive(iotests.QMPTestCase): qemu_img('create', '-f', iotests.imgfmt, '-o', 'cluster_size=%d,size=%d' % (self.image_len, self.image_len), target_img) - result = self.vm.qmp(self.qmp_cmd, device='drive0', sync='full', - buf_size=65536, mode='existing', target=self.qmp_target) - self.assert_qmp(result, 'return', {}) + self.vm.cmd(self.qmp_cmd, device='drive0', sync='full', + buf_size=65536, mode='existing', target=self.qmp_target) self.complete_and_wait() result = self.vm.qmp('query-block') @@ -162,9 +155,8 @@ class TestSingleDrive(iotests.QMPTestCase): qemu_img('create', '-f', iotests.imgfmt, '-o', 'cluster_size=%d,backing_file=%s' % (self.image_len, backing_img), '-F', 'raw', target_img) - result = self.vm.qmp(self.qmp_cmd, device='drive0', sync='full', - mode='existing', target=self.qmp_target) - self.assert_qmp(result, 'return', {}) + self.vm.cmd(self.qmp_cmd, device='drive0', sync='full', + mode='existing', target=self.qmp_target) self.complete_and_wait() result = self.vm.qmp('query-block') @@ -178,9 +170,8 @@ class TestSingleDrive(iotests.QMPTestCase): def test_implicit_node(self): self.assert_no_active_block_jobs() - result = self.vm.qmp(self.qmp_cmd, device='drive0', sync='full', - target=self.qmp_target) - self.assert_qmp(result, 'return', {}) + self.vm.cmd(self.qmp_cmd, device='drive0', sync='full', + target=self.qmp_target) result = self.vm.qmp('query-block') self.assert_qmp(result, 'return[0]/inserted/file', test_img) @@ -236,8 +227,7 @@ class TestSingleBlockdev(TestSingleDrive): args = {'driver': iotests.imgfmt, 'node-name': self.qmp_target, 'file': { 'filename': target_img, 'driver': 'file' } } - result = self.vm.qmp("blockdev-add", args) - self.assert_qmp(result, 'return', {}) + self.vm.cmd("blockdev-add", args) def test_mirror_to_self(self): result = self.vm.qmp(self.qmp_cmd, job_id='job0', @@ -254,10 +244,9 @@ class TestSingleBlockdev(TestSingleDrive): result = self.vm.qmp('block_resize', node_name=node, size=65536) self.assert_qmp(result, 'error/class', 'GenericError') - result = self.vm.qmp(self.qmp_cmd, job_id='job0', device='drive0', - sync='full', target=self.qmp_target, - auto_finalize=False, auto_dismiss=False) - self.assert_qmp(result, 'return', {}) + self.vm.cmd(self.qmp_cmd, job_id='job0', device='drive0', + sync='full', target=self.qmp_target, + auto_finalize=False, auto_dismiss=False) result = self.vm.run_job('job0', auto_finalize=False, pre_finalize=pre_finalize) @@ -270,14 +259,12 @@ class TestSingleBlockdev(TestSingleDrive): self.do_test_resize(None, self.qmp_target) def do_test_target_size(self, size): - result = self.vm.qmp('block_resize', node_name=self.qmp_target, - size=size) - self.assert_qmp(result, 'return', {}) + self.vm.cmd('block_resize', node_name=self.qmp_target, + size=size) - result = self.vm.qmp(self.qmp_cmd, job_id='job0', - device='drive0', sync='full', auto_dismiss=False, - target=self.qmp_target) - self.assert_qmp(result, 'return', {}) + self.vm.cmd(self.qmp_cmd, job_id='job0', + device='drive0', sync='full', auto_dismiss=False, + target=self.qmp_target) result = self.vm.run_job('job0') self.assertEqual(result, 'Source and target image have different sizes') @@ -337,9 +324,8 @@ class TestMirrorNoBacking(iotests.QMPTestCase): qemu_img('create', '-f', iotests.imgfmt, '-o', 'backing_file=%s' % backing_img, '-F', 'raw', target_img) - result = self.vm.qmp('drive-mirror', device='drive0', sync='full', - mode='existing', target=target_img) - self.assert_qmp(result, 'return', {}) + self.vm.cmd('drive-mirror', device='drive0', sync='full', + mode='existing', target=target_img) self.complete_and_wait() result = self.vm.qmp('query-block') @@ -353,9 +339,8 @@ class TestMirrorNoBacking(iotests.QMPTestCase): qemu_img('create', '-f', iotests.imgfmt, '-o', 'backing_file=%s' % backing_img, '-F', 'raw', target_img) - result = self.vm.qmp('drive-mirror', device='drive0', sync='full', - mode='existing', target=target_img) - self.assert_qmp(result, 'return', {}) + self.vm.cmd('drive-mirror', device='drive0', sync='full', + mode='existing', target=target_img) self.wait_ready_and_cancel() result = self.vm.qmp('query-block') @@ -374,9 +359,8 @@ class TestMirrorNoBacking(iotests.QMPTestCase): % (TestMirrorNoBacking.image_len, target_backing_img), '-F', iotests.imgfmt, target_img) - result = self.vm.qmp('drive-mirror', device='drive0', sync='full', - mode='existing', target=target_img) - self.assert_qmp(result, 'return', {}) + self.vm.cmd('drive-mirror', device='drive0', sync='full', + mode='existing', target=target_img) self.complete_and_wait() result = self.vm.qmp('query-block') @@ -409,9 +393,8 @@ class TestMirrorResized(iotests.QMPTestCase): def test_complete_top(self): self.assert_no_active_block_jobs() - result = self.vm.qmp('drive-mirror', device='drive0', sync='top', - target=target_img) - self.assert_qmp(result, 'return', {}) + self.vm.cmd('drive-mirror', device='drive0', sync='top', + target=target_img) self.complete_and_wait() result = self.vm.qmp('query-block') @@ -423,9 +406,8 @@ class TestMirrorResized(iotests.QMPTestCase): def test_complete_full(self): self.assert_no_active_block_jobs() - result = self.vm.qmp('drive-mirror', device='drive0', sync='full', - target=target_img) - self.assert_qmp(result, 'return', {}) + self.vm.cmd('drive-mirror', device='drive0', sync='full', + target=target_img) self.complete_and_wait() result = self.vm.qmp('query-block') @@ -488,9 +470,8 @@ new_state = "1" def test_report_read(self): self.assert_no_active_block_jobs() - result = self.vm.qmp('drive-mirror', device='drive0', sync='full', - target=target_img) - self.assert_qmp(result, 'return', {}) + self.vm.cmd('drive-mirror', device='drive0', sync='full', + target=target_img) completed = False error = False @@ -516,9 +497,8 @@ new_state = "1" def test_ignore_read(self): self.assert_no_active_block_jobs() - result = self.vm.qmp('drive-mirror', device='drive0', sync='full', - target=target_img, on_source_error='ignore') - self.assert_qmp(result, 'return', {}) + self.vm.cmd('drive-mirror', device='drive0', sync='full', + target=target_img, on_source_error='ignore') event = self.vm.get_qmp_event(wait=True) while event['event'] == 'JOB_STATUS_CHANGE': @@ -541,10 +521,9 @@ new_state = "1" qemu_img('create', '-f', iotests.imgfmt, '-ocluster_size=131072,backing_file=%s' %(backing_img), '-F', 'raw', target_img) - result = self.vm.qmp('drive-mirror', device='drive0', sync='top', - on_source_error='ignore', - mode='existing', target=target_img) - self.assert_qmp(result, 'return', {}) + self.vm.cmd('drive-mirror', device='drive0', sync='top', + on_source_error='ignore', + mode='existing', target=target_img) event = self.vm.get_qmp_event(wait=True) while event['event'] == 'JOB_STATUS_CHANGE': @@ -568,9 +547,8 @@ new_state = "1" def test_stop_read(self): self.assert_no_active_block_jobs() - result = self.vm.qmp('drive-mirror', device='drive0', sync='full', - target=target_img, on_source_error='stop') - self.assert_qmp(result, 'return', {}) + self.vm.cmd('drive-mirror', device='drive0', sync='full', + target=target_img, on_source_error='stop') error = False ready = False @@ -590,8 +568,7 @@ new_state = "1" self.assert_qmp(result, 'return[0]/status', 'paused') self.assert_qmp(result, 'return[0]/io-status', 'failed') - result = self.vm.qmp('block-job-resume', device='drive0') - self.assert_qmp(result, 'return', {}) + self.vm.cmd('block-job-resume', device='drive0') error = True elif event['event'] == 'BLOCK_JOB_READY': self.assertTrue(error, 'job completed unexpectedly') @@ -656,9 +633,8 @@ new_state = "1" def test_report_write(self): self.assert_no_active_block_jobs() - result = self.vm.qmp('drive-mirror', device='drive0', sync='full', - mode='existing', target=self.target_img) - self.assert_qmp(result, 'return', {}) + self.vm.cmd('drive-mirror', device='drive0', sync='full', + mode='existing', target=self.target_img) completed = False error = False @@ -682,10 +658,9 @@ new_state = "1" def test_ignore_write(self): self.assert_no_active_block_jobs() - result = self.vm.qmp('drive-mirror', device='drive0', sync='full', - mode='existing', target=self.target_img, - on_target_error='ignore') - self.assert_qmp(result, 'return', {}) + self.vm.cmd('drive-mirror', device='drive0', sync='full', + mode='existing', target=self.target_img, + on_target_error='ignore') event = self.vm.event_wait(name='BLOCK_JOB_ERROR') self.assertEqual(event['event'], 'BLOCK_JOB_ERROR') @@ -698,10 +673,9 @@ new_state = "1" def test_stop_write(self): self.assert_no_active_block_jobs() - result = self.vm.qmp('drive-mirror', device='drive0', sync='full', - mode='existing', target=self.target_img, - on_target_error='stop') - self.assert_qmp(result, 'return', {}) + self.vm.cmd('drive-mirror', device='drive0', sync='full', + mode='existing', target=self.target_img, + on_target_error='stop') error = False ready = False @@ -721,8 +695,7 @@ new_state = "1" self.assert_qmp(result, 'return[0]/status', 'paused') self.assert_qmp(result, 'return[0]/io-status', 'failed') - result = self.vm.qmp('block-job-resume', device='drive0') - self.assert_qmp(result, 'return', {}) + self.vm.cmd('block-job-resume', device='drive0') result = self.vm.qmp('query-block-jobs') self.assertIn(result['return'][0]['status'], ['running', 'ready']) @@ -755,17 +728,15 @@ class TestSetSpeed(iotests.QMPTestCase): def test_set_speed(self): self.assert_no_active_block_jobs() - result = self.vm.qmp('drive-mirror', device='drive0', sync='full', - target=target_img) - self.assert_qmp(result, 'return', {}) + self.vm.cmd('drive-mirror', device='drive0', sync='full', + target=target_img) # Default speed is 0 result = self.vm.qmp('query-block-jobs') self.assert_qmp(result, 'return[0]/device', 'drive0') self.assert_qmp(result, 'return[0]/speed', 0) - result = self.vm.qmp('block-job-set-speed', device='drive0', speed=8 * 1024 * 1024) - self.assert_qmp(result, 'return', {}) + self.vm.cmd('block-job-set-speed', device='drive0', speed=8 * 1024 * 1024) # Ensure the speed we set was accepted result = self.vm.qmp('query-block-jobs') @@ -775,9 +746,8 @@ class TestSetSpeed(iotests.QMPTestCase): self.wait_ready_and_cancel() # Check setting speed in drive-mirror works - result = self.vm.qmp('drive-mirror', device='drive0', sync='full', - target=target_img, speed=4*1024*1024) - self.assert_qmp(result, 'return', {}) + self.vm.cmd('drive-mirror', device='drive0', sync='full', + target=target_img, speed=4*1024*1024) result = self.vm.qmp('query-block-jobs') self.assert_qmp(result, 'return[0]/device', 'drive0') @@ -794,9 +764,8 @@ class TestSetSpeed(iotests.QMPTestCase): self.assert_no_active_block_jobs() - result = self.vm.qmp('drive-mirror', device='drive0', sync='full', - target=target_img) - self.assert_qmp(result, 'return', {}) + self.vm.cmd('drive-mirror', device='drive0', sync='full', + target=target_img) result = self.vm.qmp('block-job-set-speed', device='drive0', speed=-1) self.assert_qmp(result, 'error/class', 'GenericError') @@ -811,13 +780,12 @@ class TestUnbackedSource(iotests.QMPTestCase): str(TestUnbackedSource.image_len)) self.vm = iotests.VM() self.vm.launch() - result = self.vm.qmp('blockdev-add', node_name='drive0', - driver=iotests.imgfmt, - file={ - 'driver': 'file', - 'filename': test_img, - }) - self.assert_qmp(result, 'return', {}) + self.vm.cmd('blockdev-add', node_name='drive0', + driver=iotests.imgfmt, + file={ + 'driver': 'file', + 'filename': test_img, + }) def tearDown(self): self.vm.shutdown() @@ -826,28 +794,25 @@ class TestUnbackedSource(iotests.QMPTestCase): def test_absolute_paths_full(self): self.assert_no_active_block_jobs() - result = self.vm.qmp('drive-mirror', job_id='drive0', device='drive0', - sync='full', target=target_img, - mode='absolute-paths') - self.assert_qmp(result, 'return', {}) + self.vm.cmd('drive-mirror', job_id='drive0', device='drive0', + sync='full', target=target_img, + mode='absolute-paths') self.complete_and_wait() self.assert_no_active_block_jobs() def test_absolute_paths_top(self): self.assert_no_active_block_jobs() - result = self.vm.qmp('drive-mirror', job_id='drive0', device='drive0', - sync='top', target=target_img, - mode='absolute-paths') - self.assert_qmp(result, 'return', {}) + self.vm.cmd('drive-mirror', job_id='drive0', device='drive0', + sync='top', target=target_img, + mode='absolute-paths') self.complete_and_wait() self.assert_no_active_block_jobs() def test_absolute_paths_none(self): self.assert_no_active_block_jobs() - result = self.vm.qmp('drive-mirror', job_id='drive0', device='drive0', - sync='none', target=target_img, - mode='absolute-paths') - self.assert_qmp(result, 'return', {}) + self.vm.cmd('drive-mirror', job_id='drive0', device='drive0', + sync='none', target=target_img, + mode='absolute-paths') self.complete_and_wait() self.assert_no_active_block_jobs() @@ -857,14 +822,12 @@ class TestUnbackedSource(iotests.QMPTestCase): qemu_io('-c', 'write -P 42 0 64k', target_img) self.assert_no_active_block_jobs() - result = self.vm.qmp('drive-mirror', job_id='drive0', device='drive0', - sync='full', target=target_img, mode='existing') - self.assert_qmp(result, 'return', {}) + self.vm.cmd('drive-mirror', job_id='drive0', device='drive0', + sync='full', target=target_img, mode='existing') self.complete_and_wait() self.assert_no_active_block_jobs() - result = self.vm.qmp('blockdev-del', node_name='drive0') - self.assert_qmp(result, 'return', {}) + self.vm.cmd('blockdev-del', node_name='drive0') self.assertTrue(iotests.compare_images(test_img, target_img), 'target image does not match source after mirroring') @@ -874,26 +837,22 @@ class TestUnbackedSource(iotests.QMPTestCase): str(self.image_len)) qemu_io('-c', 'write -P 42 0 64k', target_img) - result = self.vm.qmp('blockdev-add', node_name='target', - driver=iotests.imgfmt, - file={ - 'driver': 'file', - 'filename': target_img, - }) - self.assert_qmp(result, 'return', {}) + self.vm.cmd('blockdev-add', node_name='target', + driver=iotests.imgfmt, + file={ + 'driver': 'file', + 'filename': target_img, + }) self.assert_no_active_block_jobs() - result = self.vm.qmp('blockdev-mirror', job_id='drive0', device='drive0', - sync='full', target='target') - self.assert_qmp(result, 'return', {}) + self.vm.cmd('blockdev-mirror', job_id='drive0', device='drive0', + sync='full', target='target') self.complete_and_wait() self.assert_no_active_block_jobs() - result = self.vm.qmp('blockdev-del', node_name='drive0') - self.assert_qmp(result, 'return', {}) + self.vm.cmd('blockdev-del', node_name='drive0') - result = self.vm.qmp('blockdev-del', node_name='target') - self.assert_qmp(result, 'return', {}) + self.vm.cmd('blockdev-del', node_name='target') self.assertTrue(iotests.compare_images(test_img, target_img), 'target image does not match source after mirroring') @@ -918,10 +877,9 @@ class TestGranularity(iotests.QMPTestCase): def test_granularity(self): self.assert_no_active_block_jobs() - result = self.vm.qmp('drive-mirror', device='drive0', - sync='full', target=target_img, - mode='absolute-paths', granularity=8192) - self.assert_qmp(result, 'return', {}) + self.vm.cmd('drive-mirror', device='drive0', + sync='full', target=target_img, + mode='absolute-paths', granularity=8192) event = self.vm.get_qmp_event(wait=60.0) while event['event'] == 'JOB_STATUS_CHANGE': @@ -963,8 +921,7 @@ class TestRepairQuorum(iotests.QMPTestCase): #assemble the quorum block device from the individual files args = { "driver": "quorum", "node-name": "quorum0", "vote-threshold": 2, "children": [ "img0", "img1", "img2" ] } - result = self.vm.qmp("blockdev-add", args) - self.assert_qmp(result, 'return', {}) + self.vm.cmd("blockdev-add", args) def tearDown(self): @@ -978,10 +935,9 @@ class TestRepairQuorum(iotests.QMPTestCase): pass def test_complete(self): - result = self.vm.qmp('drive-mirror', job_id='job0', device='quorum0', - sync='full', node_name="repair0", replaces="img1", - target=quorum_repair_img, format=iotests.imgfmt) - self.assert_qmp(result, 'return', {}) + self.vm.cmd('drive-mirror', job_id='job0', device='quorum0', + sync='full', node_name="repair0", replaces="img1", + target=quorum_repair_img, format=iotests.imgfmt) self.complete_and_wait(drive="job0") self.assert_has_block_node("repair0", quorum_repair_img) @@ -991,10 +947,9 @@ class TestRepairQuorum(iotests.QMPTestCase): 'target image does not match source after mirroring') def test_cancel(self): - result = self.vm.qmp('drive-mirror', job_id='job0', device='quorum0', - sync='full', node_name="repair0", replaces="img1", - target=quorum_repair_img, format=iotests.imgfmt) - self.assert_qmp(result, 'return', {}) + self.vm.cmd('drive-mirror', job_id='job0', device='quorum0', + sync='full', node_name="repair0", replaces="img1", + target=quorum_repair_img, format=iotests.imgfmt) self.cancel_and_wait(drive="job0", force=True) # here we check that the last registered quorum file has not been @@ -1002,10 +957,9 @@ class TestRepairQuorum(iotests.QMPTestCase): self.assert_has_block_node(None, quorum_img3) def test_cancel_after_ready(self): - result = self.vm.qmp('drive-mirror', job_id='job0', device='quorum0', - sync='full', node_name="repair0", replaces="img1", - target=quorum_repair_img, format=iotests.imgfmt) - self.assert_qmp(result, 'return', {}) + self.vm.cmd('drive-mirror', job_id='job0', device='quorum0', + sync='full', node_name="repair0", replaces="img1", + target=quorum_repair_img, format=iotests.imgfmt) self.wait_ready_and_cancel(drive="job0") # here we check that the last registered quorum file has not been @@ -1016,10 +970,9 @@ class TestRepairQuorum(iotests.QMPTestCase): 'target image does not match source after mirroring') def test_pause(self): - result = self.vm.qmp('drive-mirror', job_id='job0', device='quorum0', - sync='full', node_name="repair0", replaces="img1", - target=quorum_repair_img, format=iotests.imgfmt) - self.assert_qmp(result, 'return', {}) + self.vm.cmd('drive-mirror', job_id='job0', device='quorum0', + sync='full', node_name="repair0", replaces="img1", + target=quorum_repair_img, format=iotests.imgfmt) self.pause_job('job0') @@ -1030,8 +983,7 @@ class TestRepairQuorum(iotests.QMPTestCase): result = self.vm.qmp('query-block-jobs') self.assert_qmp(result, 'return[0]/offset', offset) - result = self.vm.qmp('block-job-resume', device='job0') - self.assert_qmp(result, 'return', {}) + self.vm.cmd('block-job-resume', device='job0') self.complete_and_wait(drive="job0") self.vm.shutdown() @@ -1084,20 +1036,18 @@ class TestRepairQuorum(iotests.QMPTestCase): self.assert_qmp(result, 'error/class', 'GenericError') def test_after_a_quorum_snapshot(self): - result = self.vm.qmp('blockdev-snapshot-sync', node_name='img1', - snapshot_file=quorum_snapshot_file, - snapshot_node_name="snap1") - self.assert_qmp(result, 'return', {}) + self.vm.cmd('blockdev-snapshot-sync', node_name='img1', + snapshot_file=quorum_snapshot_file, + snapshot_node_name="snap1") result = self.vm.qmp('drive-mirror', job_id='job0', device='quorum0', sync='full', node_name='repair0', replaces="img1", target=quorum_repair_img, format=iotests.imgfmt) self.assert_qmp(result, 'error/class', 'GenericError') - result = self.vm.qmp('drive-mirror', job_id='job0', device='quorum0', - sync='full', node_name='repair0', replaces="snap1", - target=quorum_repair_img, format=iotests.imgfmt) - self.assert_qmp(result, 'return', {}) + self.vm.cmd('drive-mirror', job_id='job0', device='quorum0', + sync='full', node_name='repair0', replaces="snap1", + target=quorum_repair_img, format=iotests.imgfmt) self.complete_and_wait('job0') self.assert_has_block_node("repair0", quorum_repair_img) @@ -1108,15 +1058,13 @@ class TestRepairQuorum(iotests.QMPTestCase): Check that we cannot replace a Quorum child when it has other parents. """ - result = self.vm.qmp('nbd-server-start', - addr={ - 'type': 'unix', - 'data': {'path': nbd_sock_path} - }) - self.assert_qmp(result, 'return', {}) + self.vm.cmd('nbd-server-start', + addr={ + 'type': 'unix', + 'data': {'path': nbd_sock_path} + }) - result = self.vm.qmp('nbd-server-add', device='img1') - self.assert_qmp(result, 'return', {}) + self.vm.cmd('nbd-server-add', device='img1') result = self.vm.qmp('drive-mirror', job_id='mirror', device='quorum0', sync='full', node_name='repair0', replaces='img1', @@ -1131,20 +1079,17 @@ class TestRepairQuorum(iotests.QMPTestCase): The same as test_with_other_parent(), but add the NBD server only when the mirror job is already running. """ - result = self.vm.qmp('nbd-server-start', - addr={ - 'type': 'unix', - 'data': {'path': nbd_sock_path} - }) - self.assert_qmp(result, 'return', {}) + self.vm.cmd('nbd-server-start', + addr={ + 'type': 'unix', + 'data': {'path': nbd_sock_path} + }) - result = self.vm.qmp('drive-mirror', job_id='mirror', device='quorum0', - sync='full', node_name='repair0', replaces='img1', - target=quorum_repair_img, format=iotests.imgfmt) - self.assert_qmp(result, 'return', {}) + self.vm.cmd('drive-mirror', job_id='mirror', device='quorum0', + sync='full', node_name='repair0', replaces='img1', + target=quorum_repair_img, format=iotests.imgfmt) - result = self.vm.qmp('nbd-server-add', device='img1') - self.assert_qmp(result, 'return', {}) + self.vm.cmd('nbd-server-add', device='img1') # The full error message goes to stderr, we will check it later self.complete_and_wait('mirror', @@ -1200,9 +1145,8 @@ class TestOrphanedSource(iotests.QMPTestCase): def test_success(self): self.assert_no_active_block_jobs() - result = self.vm.qmp('blockdev-mirror', job_id='job', device='src', - sync='full', target='dest') - self.assert_qmp(result, 'return', {}) + self.vm.cmd('blockdev-mirror', job_id='job', device='src', + sync='full', target='dest') self.complete_and_wait('job') @@ -1218,27 +1162,24 @@ class TestOrphanedSource(iotests.QMPTestCase): # Unshare consistent-read on the target # (The mirror job does not care) - result = self.vm.qmp('blockdev-add', - driver='blkdebug', - node_name='dest-perm', - image='dest', - unshare_child_perms=['consistent-read']) - self.assert_qmp(result, 'return', {}) + self.vm.cmd('blockdev-add', + driver='blkdebug', + node_name='dest-perm', + image='dest', + unshare_child_perms=['consistent-read']) - result = self.vm.qmp('blockdev-mirror', job_id='job', device='src', - sync='full', target='dest', - filter_node_name='mirror-filter') - self.assert_qmp(result, 'return', {}) + self.vm.cmd('blockdev-mirror', job_id='job', device='src', + sync='full', target='dest', + filter_node_name='mirror-filter') # Require consistent-read on the source # (We can only add this node once the job has started, or it # will complain that it does not want to run on non-root nodes) - result = self.vm.qmp('blockdev-add', - driver='blkdebug', - node_name='src-perm', - image='src', - take_child_perms=['consistent-read']) - self.assert_qmp(result, 'return', {}) + self.vm.cmd('blockdev-add', + driver='blkdebug', + node_name='src-perm', + image='src', + take_child_perms=['consistent-read']) # While completing, mirror will attempt to replace src by # dest, which must fail because src-perm requires @@ -1278,26 +1219,23 @@ class TestReplaces(iotests.QMPTestCase): """ Check that we can replace filter nodes. """ - result = self.vm.qmp('blockdev-add', { - 'driver': 'copy-on-read', - 'node-name': 'filter0', - 'file': { - 'driver': 'copy-on-read', - 'node-name': 'filter1', - 'file': { - 'driver': 'null-co' - } - } - }) - self.assert_qmp(result, 'return', {}) + self.vm.cmd('blockdev-add', { + 'driver': 'copy-on-read', + 'node-name': 'filter0', + 'file': { + 'driver': 'copy-on-read', + 'node-name': 'filter1', + 'file': { + 'driver': 'null-co' + } + } + }) - result = self.vm.qmp('blockdev-add', - node_name='target', driver='null-co') - self.assert_qmp(result, 'return', {}) + self.vm.cmd('blockdev-add', + node_name='target', driver='null-co') - result = self.vm.qmp('blockdev-mirror', job_id='mirror', device='filter0', - target='target', sync='full', replaces='filter1') - self.assert_qmp(result, 'return', {}) + self.vm.cmd('blockdev-mirror', job_id='mirror', device='filter0', + target='target', sync='full', replaces='filter1') self.complete_and_wait('mirror') @@ -1319,16 +1257,15 @@ class TestFilters(iotests.QMPTestCase): self.vm = iotests.VM().add_device('virtio-scsi,id=vio-scsi') self.vm.launch() - result = self.vm.qmp('blockdev-add', { - 'node-name': 'target', - 'driver': iotests.imgfmt, - 'file': { - 'driver': 'file', - 'filename': target_img - }, - 'backing': None - }) - self.assert_qmp(result, 'return', {}) + self.vm.cmd('blockdev-add', { + 'node-name': 'target', + 'driver': iotests.imgfmt, + 'file': { + 'driver': 'file', + 'filename': target_img + }, + 'backing': None + }) self.filterless_chain = { 'node-name': 'source', @@ -1355,19 +1292,17 @@ class TestFilters(iotests.QMPTestCase): os.remove(backing_img) def test_cor(self): - result = self.vm.qmp('blockdev-add', { - 'node-name': 'filter', - 'driver': 'copy-on-read', - 'file': self.filterless_chain - }) - self.assert_qmp(result, 'return', {}) + self.vm.cmd('blockdev-add', { + 'node-name': 'filter', + 'driver': 'copy-on-read', + 'file': self.filterless_chain + }) - result = self.vm.qmp('blockdev-mirror', - job_id='mirror', - device='filter', - target='target', - sync='top') - self.assert_qmp(result, 'return', {}) + self.vm.cmd('blockdev-mirror', + job_id='mirror', + device='filter', + target='target', + sync='top') self.complete_and_wait('mirror') @@ -1384,23 +1319,20 @@ class TestFilters(iotests.QMPTestCase): assert target_map[1]['depth'] == 0 def test_implicit_mirror_filter(self): - result = self.vm.qmp('blockdev-add', self.filterless_chain) - self.assert_qmp(result, 'return', {}) + self.vm.cmd('blockdev-add', self.filterless_chain) # We need this so we can query from above the mirror node - result = self.vm.qmp('device_add', - driver='scsi-hd', - id='virtio', - bus='vio-scsi.0', - drive='source') - self.assert_qmp(result, 'return', {}) + self.vm.cmd('device_add', + driver='scsi-hd', + id='virtio', + bus='vio-scsi.0', + drive='source') - result = self.vm.qmp('blockdev-mirror', - job_id='mirror', - device='source', - target='target', - sync='top') - self.assert_qmp(result, 'return', {}) + self.vm.cmd('blockdev-mirror', + job_id='mirror', + device='source', + target='target', + sync='top') # The mirror filter is now an implicit node, so it should be # invisible when querying the backing chain @@ -1418,24 +1350,21 @@ class TestFilters(iotests.QMPTestCase): def test_explicit_mirror_filter(self): # Same test as above, but this time we give the mirror filter # a node-name so it will not be invisible - result = self.vm.qmp('blockdev-add', self.filterless_chain) - self.assert_qmp(result, 'return', {}) + self.vm.cmd('blockdev-add', self.filterless_chain) # We need this so we can query from above the mirror node - result = self.vm.qmp('device_add', - driver='scsi-hd', - id='virtio', - bus='vio-scsi.0', - drive='source') - self.assert_qmp(result, 'return', {}) + self.vm.cmd('device_add', + driver='scsi-hd', + id='virtio', + bus='vio-scsi.0', + drive='source') - result = self.vm.qmp('blockdev-mirror', - job_id='mirror', - device='source', - target='target', - sync='top', - filter_node_name='mirror-filter') - self.assert_qmp(result, 'return', {}) + self.vm.cmd('blockdev-mirror', + job_id='mirror', + device='source', + target='target', + sync='top', + filter_node_name='mirror-filter') # With a node-name given to it, the mirror filter should now # be visible diff --git a/tests/qemu-iotests/045 b/tests/qemu-iotests/045 index 45eb239baa..a341f21cd7 100755 --- a/tests/qemu-iotests/045 +++ b/tests/qemu-iotests/045 @@ -77,8 +77,7 @@ class TestFdSets(iotests.QMPTestCase): self.vm.shutdown() def test_remove_fdset(self): - result = self.vm.qmp('remove-fd', fdset_id=2) - self.assert_qmp(result, 'return', {}) + self.vm.cmd('remove-fd', fdset_id=2) result = self.vm.qmp('query-fdsets') self.assert_qmp(result, 'return[0]/fdset-id', 1) self.assert_qmp(result, 'return[1]/fdset-id', 0) @@ -90,8 +89,7 @@ class TestFdSets(iotests.QMPTestCase): def test_remove_fd(self): result = self.vm.qmp('query-fdsets') fd_image3 = result['return'][0]['fds'][0]['fd'] - result = self.vm.qmp('remove-fd', fdset_id=2, fd=fd_image3) - self.assert_qmp(result, 'return', {}) + self.vm.cmd('remove-fd', fdset_id=2, fd=fd_image3) result = self.vm.qmp('query-fdsets') self.assert_qmp(result, 'return[0]/fdset-id', 2) self.assert_qmp(result, 'return[1]/fdset-id', 1) @@ -151,8 +149,7 @@ class TestSCMFd(iotests.QMPTestCase): def test_getfd(self): self._send_fd_by_SCM() - result = self.vm.qmp('getfd', fdname='image0:r') - self.assert_qmp(result, 'return', {}) + self.vm.cmd('getfd', fdname='image0:r') def test_getfd_invalid_fdname(self): self._send_fd_by_SCM() @@ -163,10 +160,8 @@ class TestSCMFd(iotests.QMPTestCase): def test_closefd(self): self._send_fd_by_SCM() - result = self.vm.qmp('getfd', fdname='image0:r') - self.assert_qmp(result, 'return', {}) - result = self.vm.qmp('closefd', fdname='image0:r') - self.assert_qmp(result, 'return', {}) + self.vm.cmd('getfd', fdname='image0:r') + self.vm.cmd('closefd', fdname='image0:r') def test_closefd_fd_not_found(self): fdname = 'image0:r' diff --git a/tests/qemu-iotests/055 b/tests/qemu-iotests/055 index 5d6b607051..d8372b5598 100755 --- a/tests/qemu-iotests/055 +++ b/tests/qemu-iotests/055 @@ -69,8 +69,7 @@ class TestSingleDrive(iotests.QMPTestCase): self.assert_no_active_block_jobs() self.vm.pause_drive('drive0') - result = self.vm.qmp(cmd, device='drive0', target=target, sync='full') - self.assert_qmp(result, 'return', {}) + self.vm.cmd(cmd, device='drive0', target=target, sync='full') event = self.cancel_and_wait(resume=True) self.assert_qmp(event, 'data/type', 'backup') @@ -85,9 +84,8 @@ class TestSingleDrive(iotests.QMPTestCase): self.assert_no_active_block_jobs() self.vm.pause_drive('drive0') - result = self.vm.qmp(cmd, device='drive0', - target=target, sync='full') - self.assert_qmp(result, 'return', {}) + self.vm.cmd(cmd, device='drive0', + target=target, sync='full') self.pause_job('drive0', wait=False) self.vm.resume_drive('drive0') @@ -100,8 +98,7 @@ class TestSingleDrive(iotests.QMPTestCase): result = self.vm.qmp('query-block-jobs') self.assert_qmp(result, 'return[0]/offset', offset) - result = self.vm.qmp('block-job-resume', device='drive0') - self.assert_qmp(result, 'return', {}) + self.vm.cmd('block-job-resume', device='drive0') self.wait_until_completed() @@ -123,10 +120,9 @@ class TestSingleDrive(iotests.QMPTestCase): result = self.vm.qmp('block_resize', node_name=node, size=65536) self.assert_qmp(result, 'error/class', 'GenericError') - result = self.vm.qmp('blockdev-backup', job_id='job0', device='drive0', - target='drive1', sync='full', auto_finalize=False, - auto_dismiss=False) - self.assert_qmp(result, 'return', {}) + self.vm.cmd('blockdev-backup', job_id='job0', device='drive0', + target='drive1', sync='full', auto_finalize=False, + auto_dismiss=False) self.vm.run_job('job0', auto_finalize=False, pre_finalize=pre_finalize) @@ -137,8 +133,7 @@ class TestSingleDrive(iotests.QMPTestCase): self.do_test_resize_blockdev_backup('drive1', 'target') def do_test_target_size(self, size): - result = self.vm.qmp('block_resize', device='drive1', size=size) - self.assert_qmp(result, 'return', {}) + self.vm.cmd('block_resize', device='drive1', size=size) result = self.vm.qmp('blockdev-backup', job_id='job0', device='drive0', target='drive1', sync='full') @@ -219,16 +214,14 @@ class TestSetSpeed(iotests.QMPTestCase): self.assert_no_active_block_jobs() self.vm.pause_drive('drive0') - result = self.vm.qmp(cmd, device='drive0', target=target, sync='full') - self.assert_qmp(result, 'return', {}) + self.vm.cmd(cmd, device='drive0', target=target, sync='full') # Default speed is 0 result = self.vm.qmp('query-block-jobs') self.assert_qmp(result, 'return[0]/device', 'drive0') self.assert_qmp(result, 'return[0]/speed', 0) - result = self.vm.qmp('block-job-set-speed', device='drive0', speed=8 * 1024 * 1024) - self.assert_qmp(result, 'return', {}) + self.vm.cmd('block-job-set-speed', device='drive0', speed=8 * 1024 * 1024) # Ensure the speed we set was accepted result = self.vm.qmp('query-block-jobs') @@ -240,9 +233,8 @@ class TestSetSpeed(iotests.QMPTestCase): # Check setting speed option works self.vm.pause_drive('drive0') - result = self.vm.qmp(cmd, device='drive0', - target=target, sync='full', speed=4*1024*1024) - self.assert_qmp(result, 'return', {}) + self.vm.cmd(cmd, device='drive0', + target=target, sync='full', speed=4*1024*1024) result = self.vm.qmp('query-block-jobs') self.assert_qmp(result, 'return[0]/device', 'drive0') @@ -267,9 +259,8 @@ class TestSetSpeed(iotests.QMPTestCase): self.assert_no_active_block_jobs() self.vm.pause_drive('drive0') - result = self.vm.qmp(cmd, device='drive0', - target=target, sync='full') - self.assert_qmp(result, 'return', {}) + self.vm.cmd(cmd, device='drive0', + target=target, sync='full') result = self.vm.qmp('block-job-set-speed', device='drive0', speed=-1) self.assert_qmp(result, 'error/class', 'GenericError') @@ -306,7 +297,7 @@ class TestSingleTransaction(iotests.QMPTestCase): def do_test_cancel(self, cmd, target): self.assert_no_active_block_jobs() - result = self.vm.qmp('transaction', actions=[{ + self.vm.cmd('transaction', actions=[{ 'type': cmd, 'data': { 'device': 'drive0', 'target': target, @@ -315,8 +306,6 @@ class TestSingleTransaction(iotests.QMPTestCase): } ]) - self.assert_qmp(result, 'return', {}) - event = self.cancel_and_wait() self.assert_qmp(event, 'data/type', 'backup') @@ -329,7 +318,7 @@ class TestSingleTransaction(iotests.QMPTestCase): def do_test_pause(self, cmd, target, image): self.assert_no_active_block_jobs() - result = self.vm.qmp('transaction', actions=[{ + self.vm.cmd('transaction', actions=[{ 'type': cmd, 'data': { 'device': 'drive0', 'target': target, @@ -337,12 +326,10 @@ class TestSingleTransaction(iotests.QMPTestCase): 'speed': 64 * 1024 }, } ]) - self.assert_qmp(result, 'return', {}) self.pause_job('drive0', wait=False) - result = self.vm.qmp('block-job-set-speed', device='drive0', speed=0) - self.assert_qmp(result, 'return', {}) + self.vm.cmd('block-job-set-speed', device='drive0', speed=0) self.pause_wait('drive0') @@ -353,8 +340,7 @@ class TestSingleTransaction(iotests.QMPTestCase): result = self.vm.qmp('query-block-jobs') self.assert_qmp(result, 'return[0]/offset', offset) - result = self.vm.qmp('block-job-resume', device='drive0') - self.assert_qmp(result, 'return', {}) + self.vm.cmd('block-job-resume', device='drive0') self.wait_until_completed() @@ -519,8 +505,7 @@ class TestCompressedToQcow2(iotests.QMPTestCase): self.assert_no_active_block_jobs() - result = self.vm.qmp(cmd, device='drive0', sync='full', compress=True, **args) - self.assert_qmp(result, 'return', {}) + self.vm.cmd(cmd, device='drive0', sync='full', compress=True, **args) self.wait_until_completed() @@ -545,8 +530,7 @@ class TestCompressedToQcow2(iotests.QMPTestCase): self.assert_no_active_block_jobs() self.vm.pause_drive('drive0') - result = self.vm.qmp(cmd, device='drive0', sync='full', compress=True, **args) - self.assert_qmp(result, 'return', {}) + self.vm.cmd(cmd, device='drive0', sync='full', compress=True, **args) event = self.cancel_and_wait(resume=True) self.assert_qmp(event, 'data/type', 'backup') @@ -568,8 +552,7 @@ class TestCompressedToQcow2(iotests.QMPTestCase): self.assert_no_active_block_jobs() self.vm.pause_drive('drive0') - result = self.vm.qmp(cmd, device='drive0', sync='full', compress=True, **args) - self.assert_qmp(result, 'return', {}) + self.vm.cmd(cmd, device='drive0', sync='full', compress=True, **args) self.pause_job('drive0', wait=False) self.vm.resume_drive('drive0') @@ -582,8 +565,7 @@ class TestCompressedToQcow2(iotests.QMPTestCase): result = self.vm.qmp('query-block-jobs') self.assert_qmp(result, 'return[0]/offset', offset) - result = self.vm.qmp('block-job-resume', device='drive0') - self.assert_qmp(result, 'return', {}) + self.vm.cmd('block-job-resume', device='drive0') self.wait_until_completed() diff --git a/tests/qemu-iotests/056 b/tests/qemu-iotests/056 index bef865eec4..808ea6b48a 100755 --- a/tests/qemu-iotests/056 +++ b/tests/qemu-iotests/056 @@ -75,9 +75,8 @@ class TestSyncModesNoneAndTop(iotests.QMPTestCase): def test_complete_top(self): self.assert_no_active_block_jobs() - result = self.vm.qmp('drive-backup', device='drive0', sync='top', - format=iotests.imgfmt, target=target_img) - self.assert_qmp(result, 'return', {}) + self.vm.cmd('drive-backup', device='drive0', sync='top', + format=iotests.imgfmt, target=target_img) self.wait_until_completed(check_offset=False) @@ -89,9 +88,8 @@ class TestSyncModesNoneAndTop(iotests.QMPTestCase): def test_cancel_sync_none(self): self.assert_no_active_block_jobs() - result = self.vm.qmp('drive-backup', device='drive0', - sync='none', target=target_img) - self.assert_qmp(result, 'return', {}) + self.vm.cmd('drive-backup', device='drive0', + sync='none', target=target_img) time.sleep(1) self.vm.hmp_qemu_io('drive0', 'write -P0x5e 0 512') self.vm.hmp_qemu_io('drive0', 'aio_flush') @@ -115,18 +113,15 @@ class TestBeforeWriteNotifier(iotests.QMPTestCase): def test_before_write_notifier(self): self.vm.pause_drive("drive0") - result = self.vm.qmp('drive-backup', device='drive0', - sync='full', target=target_img, - format="file", speed=1) - self.assert_qmp(result, 'return', {}) - result = self.vm.qmp('block-job-pause', device="drive0") - self.assert_qmp(result, 'return', {}) + self.vm.cmd('drive-backup', device='drive0', + sync='full', target=target_img, + format="file", speed=1) + self.vm.cmd('block-job-pause', device="drive0") # Speed is low enough that this must be an uncopied range, which will # trigger the before write notifier self.vm.hmp_qemu_io('drive0', 'aio_write -P 1 512512 512') self.vm.resume_drive("drive0") - result = self.vm.qmp('block-job-resume', device="drive0") - self.assert_qmp(result, 'return', {}) + self.vm.cmd('block-job-resume', device="drive0") event = self.cancel_and_wait() self.assert_qmp(event, 'data/type', 'backup') @@ -191,8 +186,7 @@ class BackupTest(iotests.QMPTestCase): self.qmp_backup_and_wait(device='drive0', format=iotests.imgfmt, sync='full', target=self.ref_img, auto_dismiss=False) - res = self.vm.qmp('block-job-dismiss', id='drive0') - self.assert_qmp(res, 'return', {}) + self.vm.cmd('block-job-dismiss', id='drive0') # Now to the test backup: We simulate the following guest # writes: @@ -211,11 +205,9 @@ class BackupTest(iotests.QMPTestCase): ('66', '1M', '1M')]) # Let the job complete - res = self.vm.qmp('block-job-set-speed', device='drive0', speed=0) - self.assert_qmp(res, 'return', {}) + self.vm.cmd('block-job-set-speed', device='drive0', speed=0) self.qmp_backup_wait('drive0') - res = self.vm.qmp('block-job-dismiss', id='drive0') - self.assert_qmp(res, 'return', {}) + self.vm.cmd('block-job-dismiss', id='drive0') self.assertTrue(iotests.compare_images(self.ref_img, self.dest_img), 'target image does not match reference image') @@ -237,8 +229,7 @@ class BackupTest(iotests.QMPTestCase): auto_dismiss=False) res = self.vm.qmp('query-block-jobs') self.assert_qmp(res, 'return[0]/status', 'concluded') - res = self.vm.qmp('block-job-dismiss', id='drive0') - self.assert_qmp(res, 'return', {}) + self.vm.cmd('block-job-dismiss', id='drive0') res = self.vm.qmp('query-block-jobs') self.assert_qmp(res, 'return', []) @@ -263,8 +254,7 @@ class BackupTest(iotests.QMPTestCase): auto_dismiss=False) self.assertEqual(res, False) # OK, dismiss the zombie. - res = self.vm.qmp('block-job-dismiss', id='drive0') - self.assert_qmp(res, 'return', {}) + self.vm.cmd('block-job-dismiss', id='drive0') res = self.vm.qmp('query-block-jobs') self.assert_qmp(res, 'return', []) # Ensure it's really gone. @@ -281,23 +271,22 @@ class BackupTest(iotests.QMPTestCase): ('0x55', '8M', '352k'), ('0x78', '15872k', '1M'))) # Add destination node via blkdebug - res = self.vm.qmp('blockdev-add', - node_name='target0', - driver=iotests.imgfmt, - file={ - 'driver': 'blkdebug', - 'image': { - 'driver': 'file', - 'filename': self.dest_img - }, - 'inject-error': [{ - 'event': 'write_aio', - 'errno': 5, - 'immediately': False, - 'once': True - }], - }) - self.assert_qmp(res, 'return', {}) + self.vm.cmd('blockdev-add', + node_name='target0', + driver=iotests.imgfmt, + file={ + 'driver': 'blkdebug', + 'image': { + 'driver': 'file', + 'filename': self.dest_img + }, + 'inject-error': [{ + 'event': 'write_aio', + 'errno': 5, + 'immediately': False, + 'once': True + }], + }) res = self.qmp_backup(cmd='blockdev-backup', device='drive0', target='target0', @@ -323,8 +312,7 @@ class BackupTest(iotests.QMPTestCase): res = self.vm.qmp('query-block-jobs') self.assert_qmp(res, 'return[0]/status', 'paused') # OK, unstick job and move forward. - res = self.vm.qmp('block-job-resume', device='drive0') - self.assert_qmp(res, 'return', {}) + self.vm.cmd('block-job-resume', device='drive0') # And now we need to wait for it to conclude; res = self.qmp_backup_wait(device='drive0') self.assertTrue(res) @@ -332,8 +320,7 @@ class BackupTest(iotests.QMPTestCase): # Job should now be languishing: res = self.vm.qmp('query-block-jobs') self.assert_qmp(res, 'return[0]/status', 'concluded') - res = self.vm.qmp('block-job-dismiss', id='drive0') - self.assert_qmp(res, 'return', {}) + self.vm.cmd('block-job-dismiss', id='drive0') res = self.vm.qmp('query-block-jobs') self.assert_qmp(res, 'return', []) diff --git a/tests/qemu-iotests/093 b/tests/qemu-iotests/093 index 93274dc8cb..4f9e224e8a 100755 --- a/tests/qemu-iotests/093 +++ b/tests/qemu-iotests/093 @@ -55,8 +55,7 @@ class ThrottleTestCase(iotests.QMPTestCase): # Set the I/O throttling parameters to all drives for i in range(0, ndrives): params['device'] = 'drive%d' % i - result = self.vm.qmp("block_set_io_throttle", conv_keys=False, **params) - self.assert_qmp(result, 'return', {}) + self.vm.cmd("block_set_io_throttle", conv_keys=False, **params) def do_test_throttle(self, ndrives, seconds, params, first_drive = 0): def check_limit(limit, num): @@ -253,8 +252,7 @@ class ThrottleTestCase(iotests.QMPTestCase): # drive1 remains in the group with a throttled request. params['bps_rd'] = 0 params['device'] = 'drive0' - result = self.vm.qmp("block_set_io_throttle", conv_keys=False, **params) - self.assert_qmp(result, 'return', {}) + self.vm.cmd("block_set_io_throttle", conv_keys=False, **params) # Removing the I/O limits from drive0 drains its two pending requests. # The read request in drive1 is still throttled. @@ -286,8 +284,7 @@ class ThrottleTestGroupNames(iotests.QMPTestCase): def set_io_throttle(self, device, params): params["device"] = device - result = self.vm.qmp("block_set_io_throttle", conv_keys=False, **params) - self.assert_qmp(result, 'return', {}) + self.vm.cmd("block_set_io_throttle", conv_keys=False, **params) def verify_name(self, device, name): result = self.vm.qmp("query-block") @@ -379,23 +376,19 @@ class ThrottleTestRemovableMedia(iotests.QMPTestCase): def test_removable_media(self): # Add a couple of dummy nodes named cd0 and cd1 - result = self.vm.qmp("blockdev-add", driver="null-co", - read_zeroes=True, node_name="cd0") - self.assert_qmp(result, 'return', {}) - result = self.vm.qmp("blockdev-add", driver="null-co", - read_zeroes=True, node_name="cd1") - self.assert_qmp(result, 'return', {}) + self.vm.cmd("blockdev-add", driver="null-co", + read_zeroes=True, node_name="cd0") + self.vm.cmd("blockdev-add", driver="null-co", + read_zeroes=True, node_name="cd1") # Attach a CD drive with cd0 inserted - result = self.vm.qmp("device_add", driver="scsi-cd", - id="dev0", drive="cd0") - self.assert_qmp(result, 'return', {}) + self.vm.cmd("device_add", driver="scsi-cd", + id="dev0", drive="cd0") # Set I/O limits args = { "id": "dev0", "iops": 100, "iops_rd": 0, "iops_wr": 0, "bps": 50, "bps_rd": 0, "bps_wr": 0 } - result = self.vm.qmp("block_set_io_throttle", conv_keys=False, **args) - self.assert_qmp(result, 'return', {}) + self.vm.cmd("block_set_io_throttle", conv_keys=False, **args) # Check that the I/O limits have been set result = self.vm.qmp("query-block") @@ -403,12 +396,9 @@ class ThrottleTestRemovableMedia(iotests.QMPTestCase): self.assert_qmp(result, 'return[0]/inserted/bps', 50) # Now eject cd0 and insert cd1 - result = self.vm.qmp("blockdev-open-tray", id='dev0') - self.assert_qmp(result, 'return', {}) - result = self.vm.qmp("blockdev-remove-medium", id='dev0') - self.assert_qmp(result, 'return', {}) - result = self.vm.qmp("blockdev-insert-medium", id='dev0', node_name='cd1') - self.assert_qmp(result, 'return', {}) + self.vm.cmd("blockdev-open-tray", id='dev0') + self.vm.cmd("blockdev-remove-medium", id='dev0') + self.vm.cmd("blockdev-insert-medium", id='dev0', node_name='cd1') # Check that the I/O limits are still the same result = self.vm.qmp("query-block") @@ -416,16 +406,14 @@ class ThrottleTestRemovableMedia(iotests.QMPTestCase): self.assert_qmp(result, 'return[0]/inserted/bps', 50) # Eject cd1 - result = self.vm.qmp("blockdev-remove-medium", id='dev0') - self.assert_qmp(result, 'return', {}) + self.vm.cmd("blockdev-remove-medium", id='dev0') # Check that we can't set limits if the device has no medium result = self.vm.qmp("block_set_io_throttle", conv_keys=False, **args) self.assert_qmp(result, 'error/class', 'GenericError') # Remove the CD drive - result = self.vm.qmp("device_del", id='dev0') - self.assert_qmp(result, 'return', {}) + self.vm.cmd("device_del", id='dev0') if __name__ == '__main__': diff --git a/tests/qemu-iotests/118 b/tests/qemu-iotests/118 index cae52ffa5e..10dc47459f 100755 --- a/tests/qemu-iotests/118 +++ b/tests/qemu-iotests/118 @@ -74,11 +74,9 @@ class ChangeBaseClass(iotests.QMPTestCase): class GeneralChangeTestsBaseClass(ChangeBaseClass): def test_blockdev_change_medium(self): - result = self.vm.qmp('blockdev-change-medium', - id=self.device_name, filename=new_img, - format=iotests.imgfmt) - - self.assert_qmp(result, 'return', {}) + self.vm.cmd('blockdev-change-medium', + id=self.device_name, filename=new_img, + format=iotests.imgfmt) self.wait_for_open() self.wait_for_close() @@ -89,8 +87,7 @@ class GeneralChangeTestsBaseClass(ChangeBaseClass): self.assert_qmp(result, 'return[0]/inserted/image/filename', new_img) def test_eject(self): - result = self.vm.qmp('eject', id=self.device_name, force=True) - self.assert_qmp(result, 'return', {}) + self.vm.cmd('eject', id=self.device_name, force=True) self.wait_for_open() @@ -100,8 +97,7 @@ class GeneralChangeTestsBaseClass(ChangeBaseClass): self.assert_qmp_absent(result, 'return[0]/inserted') def test_tray_eject_change(self): - result = self.vm.qmp('eject', id=self.device_name, force=True) - self.assert_qmp(result, 'return', {}) + self.vm.cmd('eject', id=self.device_name, force=True) self.wait_for_open() @@ -110,9 +106,8 @@ class GeneralChangeTestsBaseClass(ChangeBaseClass): self.assert_qmp(result, 'return[0]/tray_open', True) self.assert_qmp_absent(result, 'return[0]/inserted') - result = self.vm.qmp('blockdev-change-medium', id=self.device_name, - filename=new_img, format=iotests.imgfmt) - self.assert_qmp(result, 'return', {}) + self.vm.cmd('blockdev-change-medium', id=self.device_name, + filename=new_img, format=iotests.imgfmt) self.wait_for_close() @@ -122,9 +117,8 @@ class GeneralChangeTestsBaseClass(ChangeBaseClass): self.assert_qmp(result, 'return[0]/inserted/image/filename', new_img) def test_tray_open_close(self): - result = self.vm.qmp('blockdev-open-tray', - id=self.device_name, force=True) - self.assert_qmp(result, 'return', {}) + self.vm.cmd('blockdev-open-tray', + id=self.device_name, force=True) self.wait_for_open() @@ -136,8 +130,7 @@ class GeneralChangeTestsBaseClass(ChangeBaseClass): else: self.assert_qmp(result, 'return[0]/inserted/image/filename', old_img) - result = self.vm.qmp('blockdev-close-tray', id=self.device_name) - self.assert_qmp(result, 'return', {}) + self.vm.cmd('blockdev-close-tray', id=self.device_name) if self.has_real_tray or not self.was_empty: self.wait_for_close() @@ -151,8 +144,7 @@ class GeneralChangeTestsBaseClass(ChangeBaseClass): self.assert_qmp(result, 'return[0]/inserted/image/filename', old_img) def test_tray_eject_close(self): - result = self.vm.qmp('eject', id=self.device_name, force=True) - self.assert_qmp(result, 'return', {}) + self.vm.cmd('eject', id=self.device_name, force=True) self.wait_for_open() @@ -161,8 +153,7 @@ class GeneralChangeTestsBaseClass(ChangeBaseClass): self.assert_qmp(result, 'return[0]/tray_open', True) self.assert_qmp_absent(result, 'return[0]/inserted') - result = self.vm.qmp('blockdev-close-tray', id=self.device_name) - self.assert_qmp(result, 'return', {}) + self.vm.cmd('blockdev-close-tray', id=self.device_name) self.wait_for_close() @@ -172,9 +163,8 @@ class GeneralChangeTestsBaseClass(ChangeBaseClass): self.assert_qmp_absent(result, 'return[0]/inserted') def test_tray_open_change(self): - result = self.vm.qmp('blockdev-open-tray', id=self.device_name, - force=True) - self.assert_qmp(result, 'return', {}) + self.vm.cmd('blockdev-open-tray', id=self.device_name, + force=True) self.wait_for_open() @@ -186,10 +176,9 @@ class GeneralChangeTestsBaseClass(ChangeBaseClass): else: self.assert_qmp(result, 'return[0]/inserted/image/filename', old_img) - result = self.vm.qmp('blockdev-change-medium', id=self.device_name, - filename=new_img, - format=iotests.imgfmt) - self.assert_qmp(result, 'return', {}) + self.vm.cmd('blockdev-change-medium', id=self.device_name, + filename=new_img, + format=iotests.imgfmt) self.wait_for_close() @@ -199,17 +188,15 @@ class GeneralChangeTestsBaseClass(ChangeBaseClass): self.assert_qmp(result, 'return[0]/inserted/image/filename', new_img) def test_cycle(self, read_only_node=False): - result = self.vm.qmp('blockdev-add', - node_name='new', - driver=iotests.imgfmt, - read_only=read_only_node, - file={'filename': new_img, - 'driver': 'file'}) - self.assert_qmp(result, 'return', {}) + self.vm.cmd('blockdev-add', + node_name='new', + driver=iotests.imgfmt, + read_only=read_only_node, + file={'filename': new_img, + 'driver': 'file'}) - result = self.vm.qmp('blockdev-open-tray', - id=self.device_name, force=True) - self.assert_qmp(result, 'return', {}) + self.vm.cmd('blockdev-open-tray', + id=self.device_name, force=True) self.wait_for_open() @@ -221,26 +208,23 @@ class GeneralChangeTestsBaseClass(ChangeBaseClass): else: self.assert_qmp(result, 'return[0]/inserted/image/filename', old_img) - result = self.vm.qmp('blockdev-remove-medium', - id=self.device_name) - self.assert_qmp(result, 'return', {}) + self.vm.cmd('blockdev-remove-medium', + id=self.device_name) result = self.vm.qmp('query-block') if self.has_real_tray: self.assert_qmp(result, 'return[0]/tray_open', True) self.assert_qmp_absent(result, 'return[0]/inserted') - result = self.vm.qmp('blockdev-insert-medium', - id=self.device_name, node_name='new') - self.assert_qmp(result, 'return', {}) + self.vm.cmd('blockdev-insert-medium', + id=self.device_name, node_name='new') result = self.vm.qmp('query-block') if self.has_real_tray: self.assert_qmp(result, 'return[0]/tray_open', True) self.assert_qmp(result, 'return[0]/inserted/image/filename', new_img) - result = self.vm.qmp('blockdev-close-tray', id=self.device_name) - self.assert_qmp(result, 'return', {}) + self.vm.cmd('blockdev-close-tray', id=self.device_name) self.wait_for_close() @@ -253,9 +237,8 @@ class GeneralChangeTestsBaseClass(ChangeBaseClass): self.test_cycle(True) def test_close_on_closed(self): - result = self.vm.qmp('blockdev-close-tray', id=self.device_name) # Should be a no-op - self.assert_qmp(result, 'return', {}) + self.vm.cmd('blockdev-close-tray', id=self.device_name) self.assertEqual(self.vm.get_qmp_events(wait=False), []) def test_remove_on_closed(self): @@ -269,12 +252,11 @@ class GeneralChangeTestsBaseClass(ChangeBaseClass): if not self.has_real_tray: return - result = self.vm.qmp('blockdev-add', - node_name='new', - driver=iotests.imgfmt, - file={'filename': new_img, - 'driver': 'file'}) - self.assert_qmp(result, 'return', {}) + self.vm.cmd('blockdev-add', + node_name='new', + driver=iotests.imgfmt, + file={'filename': new_img, + 'driver': 'file'}) result = self.vm.qmp('blockdev-insert-medium', id=self.device_name, node_name='new') @@ -307,15 +289,13 @@ class TestInitiallyFilled(GeneralChangeTestsBaseClass): os.remove(new_img) def test_insert_on_filled(self): - result = self.vm.qmp('blockdev-add', - node_name='new', - driver=iotests.imgfmt, - file={'filename': new_img, - 'driver': 'file'}) - self.assert_qmp(result, 'return', {}) + self.vm.cmd('blockdev-add', + node_name='new', + driver=iotests.imgfmt, + file={'filename': new_img, + 'driver': 'file'}) - result = self.vm.qmp('blockdev-open-tray', id=self.device_name) - self.assert_qmp(result, 'return', {}) + self.vm.cmd('blockdev-open-tray', id=self.device_name) self.wait_for_open() @@ -344,14 +324,12 @@ class TestInitiallyEmpty(GeneralChangeTestsBaseClass): os.remove(new_img) def test_remove_on_empty(self): - result = self.vm.qmp('blockdev-open-tray', id=self.device_name) - self.assert_qmp(result, 'return', {}) + self.vm.cmd('blockdev-open-tray', id=self.device_name) self.wait_for_open() - result = self.vm.qmp('blockdev-remove-medium', id=self.device_name) # Should be a no-op - self.assert_qmp(result, 'return', {}) + self.vm.cmd('blockdev-remove-medium', id=self.device_name) # Do this in a function to avoid leaking variables like case into the global # name space (otherwise tests would be run for the abstract base classes) @@ -399,11 +377,10 @@ class TestChangeReadOnly(ChangeBaseClass): self.assert_qmp(result, 'return[0]/inserted/ro', True) self.assert_qmp(result, 'return[0]/inserted/image/filename', old_img) - result = self.vm.qmp('blockdev-change-medium', id=self.device_name, - filename=new_img, - format=iotests.imgfmt, - read_only_mode='retain') - self.assert_qmp(result, 'return', {}) + self.vm.cmd('blockdev-change-medium', id=self.device_name, + filename=new_img, + format=iotests.imgfmt, + read_only_mode='retain') result = self.vm.qmp('query-block') self.assert_qmp(result, 'return[0]/inserted/ro', True) @@ -419,11 +396,10 @@ class TestChangeReadOnly(ChangeBaseClass): self.assert_qmp(result, 'return[0]/inserted/ro', True) self.assert_qmp(result, 'return[0]/inserted/image/filename', old_img) - result = self.vm.qmp('blockdev-change-medium', id=self.device_name, - filename=new_img, - format=iotests.imgfmt, - read_only_mode='retain') - self.assert_qmp(result, 'return', {}) + self.vm.cmd('blockdev-change-medium', id=self.device_name, + filename=new_img, + format=iotests.imgfmt, + read_only_mode='retain') result = self.vm.qmp('query-block') self.assert_qmp(result, 'return[0]/inserted/ro', True) @@ -462,12 +438,11 @@ class TestChangeReadOnly(ChangeBaseClass): self.assert_qmp(result, 'return[0]/inserted/ro', True) self.assert_qmp(result, 'return[0]/inserted/image/filename', old_img) - result = self.vm.qmp('blockdev-change-medium', - id=self.device_name, - filename=new_img, - format=iotests.imgfmt, - read_only_mode='read-write') - self.assert_qmp(result, 'return', {}) + self.vm.cmd('blockdev-change-medium', + id=self.device_name, + filename=new_img, + format=iotests.imgfmt, + read_only_mode='read-write') result = self.vm.qmp('query-block') self.assert_qmp(result, 'return[0]/inserted/ro', False) @@ -483,12 +458,11 @@ class TestChangeReadOnly(ChangeBaseClass): self.assert_qmp(result, 'return[0]/inserted/ro', False) self.assert_qmp(result, 'return[0]/inserted/image/filename', old_img) - result = self.vm.qmp('blockdev-change-medium', - id=self.device_name, - filename=new_img, - format=iotests.imgfmt, - read_only_mode='read-only') - self.assert_qmp(result, 'return', {}) + self.vm.cmd('blockdev-change-medium', + id=self.device_name, + filename=new_img, + format=iotests.imgfmt, + read_only_mode='read-only') result = self.vm.qmp('query-block') self.assert_qmp(result, 'return[0]/inserted/ro', True) @@ -503,12 +477,11 @@ class TestChangeReadOnly(ChangeBaseClass): self.assert_qmp(result, 'return[0]/inserted/ro', False) self.assert_qmp(result, 'return[0]/inserted/image/filename', old_img) - result = self.vm.qmp('blockdev-change-medium', - id=self.device_name, - filename=new_img, - format=iotests.imgfmt, - read_only_mode='read-only') - self.assert_qmp(result, 'return', {}) + self.vm.cmd('blockdev-change-medium', + id=self.device_name, + filename=new_img, + format=iotests.imgfmt, + read_only_mode='read-only') result = self.vm.qmp('query-block') self.assert_qmp(result, 'return[0]/inserted/ro', True) @@ -546,11 +519,10 @@ class TestChangeReadOnly(ChangeBaseClass): self.assert_qmp(result, 'return[0]/inserted/ro', True) self.assert_qmp(result, 'return[0]/inserted/image/filename', old_img) - result = self.vm.qmp('blockdev-change-medium', id=self.device_name, - filename=new_img, - format=iotests.imgfmt, - read_only_mode='retain') - self.assert_qmp(result, 'return', {}) + self.vm.cmd('blockdev-change-medium', id=self.device_name, + filename=new_img, + format=iotests.imgfmt, + read_only_mode='retain') result = self.vm.qmp('query-block') self.assert_qmp(result, 'return[0]/inserted/ro', True) @@ -587,27 +559,24 @@ class TestChangeReadOnly(ChangeBaseClass): self.assert_qmp(result, 'return[0]/inserted/ro', False) self.assert_qmp(result, 'return[0]/inserted/image/filename', old_img) - result = self.vm.qmp('blockdev-add', - node_name='new', - driver=iotests.imgfmt, - read_only=True, - file={'filename': new_img, - 'driver': 'file'}) - self.assert_qmp(result, 'return', {}) + self.vm.cmd('blockdev-add', + node_name='new', + driver=iotests.imgfmt, + read_only=True, + file={'filename': new_img, + 'driver': 'file'}) result = self.vm.qmp('query-block') self.assert_qmp(result, 'return[0]/inserted/ro', False) self.assert_qmp(result, 'return[0]/inserted/image/filename', old_img) - result = self.vm.qmp('blockdev-remove-medium', id=self.device_name) - self.assert_qmp(result, 'return', {}) + self.vm.cmd('blockdev-remove-medium', id=self.device_name) result = self.vm.qmp('query-block') self.assert_qmp_absent(result, 'return[0]/inserted') - result = self.vm.qmp('blockdev-insert-medium', id=self.device_name, - node_name='new') - self.assert_qmp(result, 'return', {}) + self.vm.cmd('blockdev-insert-medium', id=self.device_name, + node_name='new') result = self.vm.qmp('query-block') self.assert_qmp(result, 'return[0]/inserted/ro', True) @@ -638,22 +607,19 @@ class TestBlockJobsAfterCycle(ChangeBaseClass): # For device-less BBs, calling blockdev-open-tray or blockdev-close-tray # is not necessary - result = self.vm.qmp('blockdev-remove-medium', id=self.device_name) - self.assert_qmp(result, 'return', {}) + self.vm.cmd('blockdev-remove-medium', id=self.device_name) result = self.vm.qmp('query-block') self.assert_qmp_absent(result, 'return[0]/inserted') - result = self.vm.qmp('blockdev-add', - node_name='node0', - driver=iotests.imgfmt, - file={'filename': old_img, - 'driver': 'file'}) - self.assert_qmp(result, 'return', {}) + self.vm.cmd('blockdev-add', + node_name='node0', + driver=iotests.imgfmt, + file={'filename': old_img, + 'driver': 'file'}) - result = self.vm.qmp('blockdev-insert-medium', id=self.device_name, - node_name='node0') - self.assert_qmp(result, 'return', {}) + self.vm.cmd('blockdev-insert-medium', id=self.device_name, + node_name='node0') result = self.vm.qmp('query-block') self.assert_qmp(result, 'return[0]/inserted/image/filename', old_img) @@ -670,10 +636,9 @@ class TestBlockJobsAfterCycle(ChangeBaseClass): @iotests.skip_for_formats(('vpc', 'parallels', 'qcow', 'vdi', 'vmdk', 'raw', 'vhdx')) def test_snapshot_and_commit(self): - result = self.vm.qmp('blockdev-snapshot-sync', device='drive0', - snapshot_file=new_img, - format=iotests.imgfmt) - self.assert_qmp(result, 'return', {}) + self.vm.cmd('blockdev-snapshot-sync', device='drive0', + snapshot_file=new_img, + format=iotests.imgfmt) result = self.vm.qmp('query-block') self.assert_qmp(result, 'return[0]/inserted/image/filename', new_img) @@ -681,16 +646,14 @@ class TestBlockJobsAfterCycle(ChangeBaseClass): 'return[0]/inserted/image/backing-image/filename', old_img) - result = self.vm.qmp('block-commit', device='drive0') - self.assert_qmp(result, 'return', {}) + self.vm.cmd('block-commit', device='drive0') self.vm.event_wait(name='BLOCK_JOB_READY') result = self.vm.qmp('query-block-jobs') self.assert_qmp(result, 'return[0]/device', 'drive0') - result = self.vm.qmp('block-job-complete', device='drive0') - self.assert_qmp(result, 'return', {}) + self.vm.cmd('block-job-complete', device='drive0') self.vm.event_wait(name='BLOCK_JOB_COMPLETED') diff --git a/tests/qemu-iotests/124 b/tests/qemu-iotests/124 index 845ab5303c..b2f4328e34 100755 --- a/tests/qemu-iotests/124 +++ b/tests/qemu-iotests/124 @@ -24,6 +24,7 @@ import os import iotests from iotests import try_remove +from qemu.qmp.qmp_client import ExecuteError def io_write_patterns(img, patterns): @@ -141,8 +142,7 @@ class TestIncrementalBackupBase(iotests.QMPTestCase): def do_qmp_backup(self, error='Input/output error', **kwargs): - res = self.vm.qmp('drive-backup', **kwargs) - self.assert_qmp(res, 'return', {}) + self.vm.cmd('drive-backup', **kwargs) return self.wait_qmp_backup(kwargs['device'], error) @@ -201,9 +201,8 @@ class TestIncrementalBackupBase(iotests.QMPTestCase): def add_bitmap(self, name, drive, **kwargs): bitmap = Bitmap(name, drive) self.bitmaps.append(bitmap) - result = self.vm.qmp('block-dirty-bitmap-add', node=drive['id'], - name=bitmap.name, **kwargs) - self.assert_qmp(result, 'return', {}) + self.vm.cmd('block-dirty-bitmap-add', node=drive['id'], + name=bitmap.name, **kwargs) return bitmap @@ -388,13 +387,12 @@ class TestIncrementalBackup(TestIncrementalBackupBase): ('0x64', '32736k', '64k'))) bitmap1 = self.add_bitmap('bitmap1', drive0) - result = self.vm.qmp('transaction', actions=[ + self.vm.cmd('transaction', actions=[ transaction_bitmap_clear(bitmap0.drive['id'], bitmap0.name), transaction_bitmap_clear(bitmap1.drive['id'], bitmap1.name), transaction_drive_backup(drive0['id'], drive0['backup'], sync='full', format=drive0['fmt']) ]) - self.assert_qmp(result, 'return', {}) self.wait_until_completed(drive0['id']) self.files.append(drive0['backup']) @@ -417,7 +415,7 @@ class TestIncrementalBackup(TestIncrementalBackupBase): ('0xcd', '32M', '124k'))) # Create a blkdebug interface to this img as 'drive1' - result = self.vm.qmp('blockdev-add', + self.vm.cmd('blockdev-add', node_name=drive1['id'], driver=drive1['fmt'], file={ @@ -440,7 +438,6 @@ class TestIncrementalBackup(TestIncrementalBackupBase): }], } ) - self.assert_qmp(result, 'return', {}) # Create bitmaps and full backups for both drives drive0 = self.drives[0] @@ -475,9 +472,8 @@ class TestIncrementalBackup(TestIncrementalBackupBase): format=drive1['fmt'], mode='existing', bitmap=dr1bm0.name) ] - result = self.vm.qmp('transaction', actions=transaction, - properties={'completion-mode': 'grouped'} ) - self.assert_qmp(result, 'return', {}) + self.vm.cmd('transaction', actions=transaction, + properties={'completion-mode': 'grouped'} ) # Observe that drive0's backup is cancelled and drive1 completes with # an error. @@ -504,9 +500,8 @@ class TestIncrementalBackup(TestIncrementalBackupBase): target1 = self.prepare_backup(dr1bm0) # Re-run the exact same transaction. - result = self.vm.qmp('transaction', actions=transaction, - properties={'completion-mode':'grouped'}) - self.assert_qmp(result, 'return', {}) + self.vm.cmd('transaction', actions=transaction, + properties={'completion-mode':'grouped'}) # Both should complete successfully this time. self.assertTrue(self.wait_qmp_backup(drive0['id'])) @@ -567,7 +562,7 @@ class TestIncrementalBackup(TestIncrementalBackupBase): The granularity must always be a power of 2. ''' self.assert_no_active_block_jobs() - self.assertRaises(AssertionError, self.add_bitmap, + self.assertRaises(ExecuteError, self.add_bitmap, 'bitmap0', self.drives[0], granularity=64000) @@ -585,9 +580,8 @@ class TestIncrementalBackup(TestIncrementalBackupBase): self.add_bitmap('bitmap0', self.drives[0]) - res = self.vm.qmp('block_resize', device=self.drives[0]['id'], - size=(65 * 1048576)) - self.assert_qmp(res, 'return', {}) + self.vm.cmd('block_resize', device=self.drives[0]['id'], + size=(65 * 1048576)) # Dirty the image past the old end self.vm.hmp_qemu_io(self.drives[0]['id'], 'write 64M 64k') @@ -617,7 +611,7 @@ class TestIncrementalBackupBlkdebug(TestIncrementalBackupBase): ''' drive0 = self.drives[0] - result = self.vm.qmp('blockdev-add', + self.vm.cmd('blockdev-add', node_name=drive0['id'], driver=drive0['fmt'], file={ @@ -640,7 +634,6 @@ class TestIncrementalBackupBlkdebug(TestIncrementalBackupBase): }], } ) - self.assert_qmp(result, 'return', {}) self.create_anchor_backup(drive0) self.add_bitmap('bitmap0', drive0) @@ -668,29 +661,28 @@ class TestIncrementalBackupBlkdebug(TestIncrementalBackupBase): drive0 = self.drives[0] # NB: The blkdebug script here looks for a "flush, read" pattern. # The flush occurs in hmp_io_writes, and the read during the block job. - result = self.vm.qmp('blockdev-add', - node_name=drive0['id'], - driver=drive0['fmt'], - file={ - 'driver': 'blkdebug', - 'image': { - 'driver': 'file', - 'filename': drive0['file'] - }, - 'set-state': [{ - 'event': 'flush_to_disk', - 'state': 1, - 'new_state': 2 - }], - 'inject-error': [{ - 'event': 'read_aio', - 'errno': 5, - 'state': 2, - 'immediately': False, - 'once': True - }], - }) - self.assert_qmp(result, 'return', {}) + self.vm.cmd('blockdev-add', + node_name=drive0['id'], + driver=drive0['fmt'], + file={ + 'driver': 'blkdebug', + 'image': { + 'driver': 'file', + 'filename': drive0['file'] + }, + 'set-state': [{ + 'event': 'flush_to_disk', + 'state': 1, + 'new_state': 2 + }], + 'inject-error': [{ + 'event': 'read_aio', + 'errno': 5, + 'state': 2, + 'immediately': False, + 'once': True + }], + }) self.create_anchor_backup(drive0) bitmap = self.add_bitmap('bitmap0', drive0) @@ -711,16 +703,15 @@ class TestIncrementalBackupBlkdebug(TestIncrementalBackupBase): # Start backup parent, _ = bitmap.last_target() target = self.prepare_backup(bitmap, parent) - res = self.vm.qmp('drive-backup', - job_id=bitmap.drive['id'], - device=bitmap.drive['id'], - sync='incremental', - bitmap=bitmap.name, - format=bitmap.drive['fmt'], - target=target, - mode='existing', - on_source_error='stop') - self.assert_qmp(res, 'return', {}) + self.vm.cmd('drive-backup', + job_id=bitmap.drive['id'], + device=bitmap.drive['id'], + sync='incremental', + bitmap=bitmap.name, + format=bitmap.drive['fmt'], + target=target, + mode='existing', + on_source_error='stop') # Wait for the error event = self.vm.event_wait(name="BLOCK_JOB_ERROR", @@ -739,8 +730,7 @@ class TestIncrementalBackupBlkdebug(TestIncrementalBackupBase): })) # Resume and check incremental backup for consistency - res = self.vm.qmp('block-job-resume', device=bitmap.drive['id']) - self.assert_qmp(res, 'return', {}) + self.vm.cmd('block-job-resume', device=bitmap.drive['id']) self.wait_qmp_backup(bitmap.drive['id']) # Bitmap Status Check diff --git a/tests/qemu-iotests/129 b/tests/qemu-iotests/129 index e1536ee3c3..97773cd96d 100755 --- a/tests/qemu-iotests/129 +++ b/tests/qemu-iotests/129 @@ -55,11 +55,9 @@ class TestStopWithBlockJob(iotests.QMPTestCase): def do_test_stop(self, cmd, **args): """Test 'stop' while block job is running on a throttled drive. The 'stop' command shouldn't drain the job""" - result = self.vm.qmp(cmd, **args) - self.assert_qmp(result, 'return', {}) + self.vm.cmd(cmd, **args) - result = self.vm.qmp("stop") - self.assert_qmp(result, 'return', {}) + self.vm.cmd("stop") result = self.vm.qmp("query-block-jobs") self.assert_qmp(result, 'return[0]/status', 'running') @@ -87,7 +85,7 @@ class TestStopWithBlockJob(iotests.QMPTestCase): iotests.qemu_img('create', '-f', iotests.imgfmt, self.overlay_img, '1G') - result = self.vm.qmp('blockdev-add', { + self.vm.cmd('blockdev-add', { 'node-name': 'overlay', 'driver': iotests.imgfmt, 'file': { @@ -95,11 +93,9 @@ class TestStopWithBlockJob(iotests.QMPTestCase): 'filename': self.overlay_img } }) - self.assert_qmp(result, 'return', {}) - result = self.vm.qmp('blockdev-snapshot', - node='source', overlay='overlay') - self.assert_qmp(result, 'return', {}) + self.vm.cmd('blockdev-snapshot', + node='source', overlay='overlay') self.do_test_stop('block-commit', device='drive0', top_node='source') diff --git a/tests/qemu-iotests/132 b/tests/qemu-iotests/132 index 367ea08036..12a64b3d95 100755 --- a/tests/qemu-iotests/132 +++ b/tests/qemu-iotests/132 @@ -47,9 +47,8 @@ class TestSingleDrive(iotests.QMPTestCase): pass def test_mirror_discard(self): - result = self.vm.qmp('drive-mirror', device='drive0', sync='full', - target=target_img) - self.assert_qmp(result, 'return', {}) + self.vm.cmd('drive-mirror', device='drive0', sync='full', + target=target_img) self.vm.hmp_qemu_io('drive0', 'discard 0 64k') self.complete_and_wait('drive0') self.vm.shutdown() diff --git a/tests/qemu-iotests/139 b/tests/qemu-iotests/139 index 178b1ee230..ebb4cd62b6 100755 --- a/tests/qemu-iotests/139 +++ b/tests/qemu-iotests/139 @@ -58,8 +58,7 @@ class TestBlockdevDel(iotests.QMPTestCase): 'file': {'driver': 'file', 'node-name': file_node, 'filename': base_img}} - result = self.vm.qmp('blockdev-add', conv_keys = False, **opts) - self.assert_qmp(result, 'return', {}) + self.vm.cmd('blockdev-add', conv_keys = False, **opts) self.checkBlockDriverState(node) self.checkBlockDriverState(file_node) @@ -73,8 +72,7 @@ class TestBlockdevDel(iotests.QMPTestCase): 'backing': None, 'file': {'driver': 'file', 'filename': new_img}} - result = self.vm.qmp('blockdev-add', conv_keys = False, **opts) - self.assert_qmp(result, 'return', {}) + self.vm.cmd('blockdev-add', conv_keys = False, **opts) self.checkBlockDriverState(node) # Delete a BlockDriverState @@ -89,17 +87,14 @@ class TestBlockdevDel(iotests.QMPTestCase): # Add a device model def addDeviceModel(self, device, backend, driver = 'virtio-blk'): - result = self.vm.qmp('device_add', id = device, - driver = driver, drive = backend) - self.assert_qmp(result, 'return', {}) + self.vm.cmd('device_add', id = device, + driver = driver, drive = backend) # Delete a device model def delDeviceModel(self, device, is_virtio_blk = True): - result = self.vm.qmp('device_del', id = device) - self.assert_qmp(result, 'return', {}) + self.vm.cmd('device_del', id = device) - result = self.vm.qmp('system_reset') - self.assert_qmp(result, 'return', {}) + self.vm.cmd('system_reset') if is_virtio_blk: device_path = '/machine/peripheral/%s/virtio-backend' % device @@ -126,9 +121,8 @@ class TestBlockdevDel(iotests.QMPTestCase): # Insert a BlockDriverState def insertDrive(self, device, node): self.checkBlockDriverState(node) - result = self.vm.qmp('blockdev-insert-medium', - id = device, node_name = node) - self.assert_qmp(result, 'return', {}) + self.vm.cmd('blockdev-insert-medium', + id = device, node_name = node) self.checkBlockDriverState(node) # Create a snapshot using 'blockdev-snapshot-sync' @@ -139,8 +133,7 @@ class TestBlockdevDel(iotests.QMPTestCase): 'snapshot-file': new_img, 'snapshot-node-name': overlay, 'format': iotests.imgfmt} - result = self.vm.qmp('blockdev-snapshot-sync', conv_keys=False, **opts) - self.assert_qmp(result, 'return', {}) + self.vm.cmd('blockdev-snapshot-sync', conv_keys=False, **opts) self.checkBlockDriverState(node) self.checkBlockDriverState(overlay) @@ -148,9 +141,8 @@ class TestBlockdevDel(iotests.QMPTestCase): def createSnapshot(self, node, overlay): self.checkBlockDriverState(node) self.checkBlockDriverState(overlay) - result = self.vm.qmp('blockdev-snapshot', - node = node, overlay = overlay) - self.assert_qmp(result, 'return', {}) + self.vm.cmd('blockdev-snapshot', + node = node, overlay = overlay) self.checkBlockDriverState(node) self.checkBlockDriverState(overlay) @@ -163,14 +155,12 @@ class TestBlockdevDel(iotests.QMPTestCase): 'node-name': new_node, 'sync': 'top', 'format': iotests.imgfmt} - result = self.vm.qmp('drive-mirror', conv_keys=False, **opts) - self.assert_qmp(result, 'return', {}) + self.vm.cmd('drive-mirror', conv_keys=False, **opts) self.checkBlockDriverState(new_node) # Complete an existing block job def completeBlockJob(self, id, node_before, node_after): - result = self.vm.qmp('block-job-complete', device=id) - self.assert_qmp(result, 'return', {}) + self.vm.cmd('block-job-complete', device=id) self.wait_until_completed(id) # Add a BlkDebug node @@ -186,8 +176,7 @@ class TestBlockdevDel(iotests.QMPTestCase): opts = {'driver': 'blkdebug', 'node-name': debug, 'image': image} - result = self.vm.qmp('blockdev-add', conv_keys = False, **opts) - self.assert_qmp(result, 'return', {}) + self.vm.cmd('blockdev-add', conv_keys = False, **opts) self.checkBlockDriverState(node) self.checkBlockDriverState(debug) @@ -211,8 +200,7 @@ class TestBlockdevDel(iotests.QMPTestCase): 'node-name': blkverify, 'test': node_0, 'raw': node_1} - result = self.vm.qmp('blockdev-add', conv_keys = False, **opts) - self.assert_qmp(result, 'return', {}) + self.vm.cmd('blockdev-add', conv_keys = False, **opts) self.checkBlockDriverState(test) self.checkBlockDriverState(raw) self.checkBlockDriverState(blkverify) @@ -235,8 +223,7 @@ class TestBlockdevDel(iotests.QMPTestCase): 'node-name': quorum, 'vote-threshold': 1, 'children': [ child_0, child_1 ]} - result = self.vm.qmp('blockdev-add', conv_keys = False, **opts) - self.assert_qmp(result, 'return', {}) + self.vm.cmd('blockdev-add', conv_keys = False, **opts) self.checkBlockDriverState(child0) self.checkBlockDriverState(child1) self.checkBlockDriverState(quorum) diff --git a/tests/qemu-iotests/147 b/tests/qemu-iotests/147 index 08111c5108..6d6f077a14 100755 --- a/tests/qemu-iotests/147 +++ b/tests/qemu-iotests/147 @@ -58,8 +58,7 @@ class NBDBlockdevAddBase(iotests.QMPTestCase): def client_test(self, filename, address, export=None, node_name='nbd-blockdev', delete=True): bao = self.blockdev_add_options(address, export, node_name) - result = self.vm.qmp('blockdev-add', bao) - self.assert_qmp(result, 'return', {}) + self.vm.cmd('blockdev-add', bao) found = False result = self.vm.qmp('query-named-block-nodes') @@ -75,8 +74,7 @@ class NBDBlockdevAddBase(iotests.QMPTestCase): self.assertTrue(found) if delete: - result = self.vm.qmp('blockdev-del', node_name=node_name) - self.assert_qmp(result, 'return', {}) + self.vm.cmd('blockdev-del', node_name=node_name) class QemuNBD(NBDBlockdevAddBase): @@ -158,17 +156,14 @@ class BuiltinNBD(NBDBlockdevAddBase): self.assert_qmp(result, 'return', {}) if export_name is None: - result = self.server.qmp('nbd-server-add', device='nbd-export') - self.assert_qmp(result, 'return', {}) + self.server.cmd('nbd-server-add', device='nbd-export') else: - result = self.server.qmp('nbd-server-add', device='nbd-export', - name=export_name) - self.assert_qmp(result, 'return', {}) + self.server.cmd('nbd-server-add', device='nbd-export', + name=export_name) if export_name2 is not None: - result = self.server.qmp('nbd-server-add', device='nbd-export', - name=export_name2) - self.assert_qmp(result, 'return', {}) + self.server.cmd('nbd-server-add', device='nbd-export', + name=export_name2) return True @@ -176,8 +171,7 @@ class BuiltinNBD(NBDBlockdevAddBase): self.assertTrue(self._try_server_up(address, export_name, export_name2)) def _server_down(self): - result = self.server.qmp('nbd-server-stop') - self.assert_qmp(result, 'return', {}) + self.server.cmd('nbd-server-stop') def do_test_inet(self, export_name=None): while True: @@ -219,10 +213,8 @@ class BuiltinNBD(NBDBlockdevAddBase): flatten_sock_addr(address), 'exp1', 'node1', False) self.client_test('nbd://localhost:%i/%s' % (nbd_port, 'exp2'), flatten_sock_addr(address), 'exp2', 'node2', False) - result = self.vm.qmp('blockdev-del', node_name='node1') - self.assert_qmp(result, 'return', {}) - result = self.vm.qmp('blockdev-del', node_name='node2') - self.assert_qmp(result, 'return', {}) + self.vm.cmd('blockdev-del', node_name='node1') + self.vm.cmd('blockdev-del', node_name='node2') self._server_down() def test_inet6(self): @@ -273,8 +265,7 @@ class BuiltinNBD(NBDBlockdevAddBase): result = self.vm.send_fd_scm(fd=sockfd.fileno()) self.assertEqual(result, 0, 'Failed to send socket FD') - result = self.vm.qmp('getfd', fdname='nbd-fifo') - self.assert_qmp(result, 'return', {}) + self.vm.cmd('getfd', fdname='nbd-fifo') address = { 'type': 'fd', 'data': { 'str': 'nbd-fifo' } } diff --git a/tests/qemu-iotests/151 b/tests/qemu-iotests/151 index 668d0c1e9c..f2ff9c5dac 100755 --- a/tests/qemu-iotests/151 +++ b/tests/qemu-iotests/151 @@ -79,14 +79,13 @@ class TestActiveMirror(iotests.QMPTestCase): self.vm.hmp_qemu_io('source', 'aio_write -z %i 1M' % offset) # Start the block job - result = self.vm.qmp('blockdev-mirror', - job_id='mirror', - filter_node_name='mirror-node', - device='source-node', - target='target-node', - sync='full', - copy_mode='write-blocking') - self.assert_qmp(result, 'return', {}) + self.vm.cmd('blockdev-mirror', + job_id='mirror', + filter_node_name='mirror-node', + device='source-node', + target='target-node', + sync='full', + copy_mode='write-blocking') # Start some more requests for offset in range(3 * self.image_len // 8, 5 * self.image_len // 8, 1024 * 1024): @@ -125,23 +124,21 @@ class TestActiveMirror(iotests.QMPTestCase): result = self.vm.hmp_qemu_io('source', 'write -P 1 0 2M') # Start the block job (very slowly) - result = self.vm.qmp('blockdev-mirror', - job_id='mirror', - filter_node_name='mirror-node', - device='source-node', - target='target-node', - sync='full', - copy_mode='write-blocking', - buf_size=(1048576 // 4), - speed=1) - self.assert_qmp(result, 'return', {}) + self.vm.cmd('blockdev-mirror', + job_id='mirror', + filter_node_name='mirror-node', + device='source-node', + target='target-node', + sync='full', + copy_mode='write-blocking', + buf_size=(1048576 // 4), + speed=1) # Start an unaligned request to a dirty area result = self.vm.hmp_qemu_io('source', 'write -P 2 %i 1' % (1048576 + 42)) # Let the job finish - result = self.vm.qmp('block-job-set-speed', device='mirror', speed=0) - self.assert_qmp(result, 'return', {}) + self.vm.cmd('block-job-set-speed', device='mirror', speed=0) self.complete_and_wait(drive='mirror') self.potential_writes_in_flight = False @@ -151,15 +148,14 @@ class TestActiveMirror(iotests.QMPTestCase): result = self.vm.hmp_qemu_io('source', 'write -P 1 0 2M') # Start the block job (very slowly) - result = self.vm.qmp('blockdev-mirror', - job_id='mirror', - filter_node_name='mirror-node', - device='source-node', - target='target-node', - sync='full', - copy_mode='write-blocking', - speed=1) - self.assert_qmp(result, 'return', {}) + self.vm.cmd('blockdev-mirror', + job_id='mirror', + filter_node_name='mirror-node', + device='source-node', + target='target-node', + sync='full', + copy_mode='write-blocking', + speed=1) self.vm.hmp_qemu_io('source', 'break write_aio A') self.vm.hmp_qemu_io('source', 'aio_write 0 1M') # 1 @@ -190,8 +186,7 @@ class TestActiveMirror(iotests.QMPTestCase): # After resuming 4, one of 2 and 3 goes first and set in_flight_bitmap, # so the other will wait for it. - result = self.vm.qmp('block-job-set-speed', device='mirror', speed=0) - self.assert_qmp(result, 'return', {}) + self.vm.cmd('block-job-set-speed', device='mirror', speed=0) self.complete_and_wait(drive='mirror') self.potential_writes_in_flight = False @@ -212,7 +207,7 @@ class TestThrottledWithNbdExportBase(iotests.QMPTestCase): self.vm = iotests.VM() self.vm.launch() - result = self.vm.qmp('object-add', **{ + self.vm.cmd('object-add', **{ 'qom-type': 'throttle-group', 'id': 'thrgr', 'limits': { @@ -220,9 +215,8 @@ class TestThrottledWithNbdExportBase(iotests.QMPTestCase): 'iops-total-max': self.iops } }) - self.assert_qmp(result, 'return', {}) - result = self.vm.qmp('blockdev-add', **{ + self.vm.cmd('blockdev-add', **{ 'node-name': 'source-node', 'driver': 'throttle', 'throttle-group': 'thrgr', @@ -234,9 +228,8 @@ class TestThrottledWithNbdExportBase(iotests.QMPTestCase): } } }) - self.assert_qmp(result, 'return', {}) - result = self.vm.qmp('blockdev-add', **{ + self.vm.cmd('blockdev-add', **{ 'node-name': 'target-node', 'driver': iotests.imgfmt, 'file': { @@ -244,23 +237,20 @@ class TestThrottledWithNbdExportBase(iotests.QMPTestCase): 'filename': target_img } }) - self.assert_qmp(result, 'return', {}) self.nbd_sock = iotests.file_path('nbd.sock', base_dir=iotests.sock_dir) self.nbd_url = f'nbd+unix:///source-node?socket={self.nbd_sock}' - result = self.vm.qmp('nbd-server-start', addr={ + self.vm.cmd('nbd-server-start', addr={ 'type': 'unix', 'data': { 'path': self.nbd_sock } }) - self.assert_qmp(result, 'return', {}) - result = self.vm.qmp('block-export-add', id='exp0', type='nbd', - node_name='source-node', writable=True) - self.assert_qmp(result, 'return', {}) + self.vm.cmd('block-export-add', id='exp0', type='nbd', + node_name='source-node', writable=True) def tearDown(self): # Wait for background requests to settle @@ -313,15 +303,14 @@ class TestLowThrottledWithNbdExport(TestThrottledWithNbdExportBase): # Launch the mirror job mirror_buf_size = 65536 - result = self.vm.qmp('blockdev-mirror', - job_id='mirror', - filter_node_name='mirror-node', - device='source-node', - target='target-node', - sync='full', - copy_mode='write-blocking', - buf_size=mirror_buf_size) - self.assert_qmp(result, 'return', {}) + self.vm.cmd('blockdev-mirror', + job_id='mirror', + filter_node_name='mirror-node', + device='source-node', + target='target-node', + sync='full', + copy_mode='write-blocking', + buf_size=mirror_buf_size) # We create the external requests via qemu-io processes on the NBD # server. Have their offset start in the middle of the image so they @@ -409,13 +398,12 @@ class TestHighThrottledWithNbdExport(TestThrottledWithNbdExportBase): # start blockdev-mirror self.vm.qtest(f'clock_step {1 * 1000 * 1000 * 1000}') - result = self.vm.qmp('blockdev-mirror', - job_id='mirror', - device='source-node', - target='target-node', - sync='full', - copy_mode='write-blocking') - self.assert_qmp(result, 'return', {}) + self.vm.cmd('blockdev-mirror', + job_id='mirror', + device='source-node', + target='target-node', + sync='full', + copy_mode='write-blocking') if __name__ == '__main__': diff --git a/tests/qemu-iotests/152 b/tests/qemu-iotests/152 index b73a0d08a2..197bea9e77 100755 --- a/tests/qemu-iotests/152 +++ b/tests/qemu-iotests/152 @@ -41,18 +41,16 @@ class TestUnaligned(iotests.QMPTestCase): pass def test_unaligned(self): - result = self.vm.qmp('drive-mirror', device='drive0', sync='full', - granularity=65536, target=target_img) - self.assert_qmp(result, 'return', {}) + self.vm.cmd('drive-mirror', device='drive0', sync='full', + granularity=65536, target=target_img) self.complete_and_wait() self.vm.shutdown() self.assertEqual(iotests.image_size(test_img), iotests.image_size(target_img), "Target size doesn't match source when granularity when unaligend") def test_unaligned_with_update(self): - result = self.vm.qmp('drive-mirror', device='drive0', sync='full', - granularity=65536, target=target_img) - self.assert_qmp(result, 'return', {}) + self.vm.cmd('drive-mirror', device='drive0', sync='full', + granularity=65536, target=target_img) self.wait_ready() self.vm.hmp_qemu_io('drive0', 'write 0 512') self.complete_and_wait(wait_ready=False) diff --git a/tests/qemu-iotests/155 b/tests/qemu-iotests/155 index 0c073fd61b..38eacb4127 100755 --- a/tests/qemu-iotests/155 +++ b/tests/qemu-iotests/155 @@ -110,8 +110,7 @@ class BaseClass(iotests.QMPTestCase): elif self.target_blockdev_backing: options['backing'] = self.target_blockdev_backing - result = self.vm.qmp('blockdev-add', options) - self.assert_qmp(result, 'return', {}) + self.vm.cmd('blockdev-add', options) def tearDown(self): self.vm.shutdown() @@ -178,20 +177,18 @@ class MirrorBaseClass(BaseClass): def runMirror(self, sync): if self.cmd == 'blockdev-mirror': - result = self.vm.qmp(self.cmd, job_id='mirror-job', device='source', - sync=sync, target='target', - auto_finalize=False) - self.assert_qmp(result, 'return', {}) + self.vm.cmd(self.cmd, job_id='mirror-job', device='source', + sync=sync, target='target', + auto_finalize=False) else: if self.existing: mode = 'existing' else: mode = 'absolute-paths' - result = self.vm.qmp(self.cmd, job_id='mirror-job', device='source', - sync=sync, target=target_img, - format=iotests.imgfmt, mode=mode, - node_name='target', auto_finalize=False) - self.assert_qmp(result, 'return', {}) + self.vm.cmd(self.cmd, job_id='mirror-job', device='source', + sync=sync, target=target_img, + format=iotests.imgfmt, mode=mode, + node_name='target', auto_finalize=False) self.vm.run_job('mirror-job', auto_finalize=False, pre_finalize=self.openBacking, auto_dismiss=True) @@ -258,16 +255,14 @@ class TestBlockdevMirrorReopen(MirrorBaseClass): def openBacking(self): if not self.target_open_with_backing: - result = self.vm.qmp('blockdev-add', node_name="backing", - driver="null-co") - self.assert_qmp(result, 'return', {}) - result = self.vm.qmp('blockdev-reopen', options=[{ - 'node-name': "target", - 'driver': iotests.imgfmt, - 'file': "target-file", - 'backing': "backing" - }]) - self.assert_qmp(result, 'return', {}) + self.vm.cmd('blockdev-add', node_name="backing", + driver="null-co") + self.vm.cmd('blockdev-reopen', options=[{ + 'node-name': "target", + 'driver': iotests.imgfmt, + 'file': "target-file", + 'backing': "backing" + }]) class TestBlockdevMirrorReopenIothread(TestBlockdevMirrorReopen): use_iothread = True @@ -281,12 +276,10 @@ class TestBlockdevMirrorSnapshot(MirrorBaseClass): def openBacking(self): if not self.target_open_with_backing: - result = self.vm.qmp('blockdev-add', node_name="backing", - driver="null-co") - self.assert_qmp(result, 'return', {}) - result = self.vm.qmp('blockdev-snapshot', node="backing", - overlay="target") - self.assert_qmp(result, 'return', {}) + self.vm.cmd('blockdev-add', node_name="backing", + driver="null-co") + self.vm.cmd('blockdev-snapshot', node="backing", + overlay="target") class TestBlockdevMirrorSnapshotIothread(TestBlockdevMirrorSnapshot): use_iothread = True @@ -295,14 +288,12 @@ class TestCommit(BaseClass): existing = False def testCommit(self): - result = self.vm.qmp('block-commit', job_id='commit-job', - device='source', base=back1_img) - self.assert_qmp(result, 'return', {}) + self.vm.cmd('block-commit', job_id='commit-job', + device='source', base=back1_img) self.vm.event_wait('BLOCK_JOB_READY') - result = self.vm.qmp('block-job-complete', device='commit-job') - self.assert_qmp(result, 'return', {}) + self.vm.cmd('block-job-complete', device='commit-job') self.vm.event_wait('BLOCK_JOB_COMPLETED') diff --git a/tests/qemu-iotests/165 b/tests/qemu-iotests/165 index e3ef28e2ee..b24907a62f 100755 --- a/tests/qemu-iotests/165 +++ b/tests/qemu-iotests/165 @@ -116,9 +116,8 @@ class TestPersistentDirtyBitmap(iotests.QMPTestCase): sha256_2 = self.getSha256() assert sha256_1 != sha256_2 # Otherwise, it's not very interesting. - result = self.vm.qmp('block-dirty-bitmap-clear', node='drive0', - name='bitmap0') - self.assert_qmp(result, 'return', {}) + self.vm.cmd('block-dirty-bitmap-clear', node='drive0', + name='bitmap0') # Start with regions1 @@ -137,7 +136,7 @@ class TestPersistentDirtyBitmap(iotests.QMPTestCase): assert sha256_1 == self.getSha256() # Reopen to RW - result = self.vm.qmp('blockdev-reopen', options=[{ + self.vm.cmd('blockdev-reopen', options=[{ 'node-name': 'node0', 'driver': iotests.imgfmt, 'file': { @@ -146,7 +145,6 @@ class TestPersistentDirtyBitmap(iotests.QMPTestCase): }, 'read-only': False }]) - self.assert_qmp(result, 'return', {}) # Check that bitmap is reopened to RW and we can write to it. self.writeRegions(regions2) diff --git a/tests/qemu-iotests/196 b/tests/qemu-iotests/196 index 27c1629be3..e5105b1354 100755 --- a/tests/qemu-iotests/196 +++ b/tests/qemu-iotests/196 @@ -45,8 +45,7 @@ class TestInvalidateAutoclear(iotests.QMPTestCase): self.vm_b.add_incoming("exec: cat '" + migfile + "'") def test_migration(self): - result = self.vm_a.qmp('migrate', uri='exec:cat>' + migfile) - self.assert_qmp(result, 'return', {}) + self.vm_a.cmd('migrate', uri='exec:cat>' + migfile) self.assertNotEqual(self.vm_a.event_wait("STOP"), None) with open(disk, 'r+b') as f: diff --git a/tests/qemu-iotests/205 b/tests/qemu-iotests/205 index 15f798288a..2370e1a138 100755 --- a/tests/qemu-iotests/205 +++ b/tests/qemu-iotests/205 @@ -44,10 +44,8 @@ class TestNbdServerRemove(iotests.QMPTestCase): } } - result = self.vm.qmp('nbd-server-start', addr=address) - self.assert_qmp(result, 'return', {}) - result = self.vm.qmp('nbd-server-add', device='drive0', name='exp') - self.assert_qmp(result, 'return', {}) + self.vm.cmd('nbd-server-start', addr=address) + self.vm.cmd('nbd-server-add', device='drive0', name='exp') def tearDown(self): self.vm.shutdown() diff --git a/tests/qemu-iotests/218 b/tests/qemu-iotests/218 index 5e74c55b6a..81aa68806f 100755 --- a/tests/qemu-iotests/218 +++ b/tests/qemu-iotests/218 @@ -41,34 +41,30 @@ iotests.script_initialize(supported_fmts=['qcow2', 'raw']) def start_mirror(vm, speed=None, buf_size=None): vm.launch() - ret = vm.qmp('blockdev-add', - node_name='source', - driver='null-co', - size=1048576) - assert ret['return'] == {} + vm.cmd('blockdev-add', + node_name='source', + driver='null-co', + size=1048576) - ret = vm.qmp('blockdev-add', - node_name='target', - driver='null-co', - size=1048576) - assert ret['return'] == {} + vm.cmd('blockdev-add', + node_name='target', + driver='null-co', + size=1048576) if speed is not None: - ret = vm.qmp('blockdev-mirror', - job_id='mirror', - device='source', - target='target', - sync='full', - speed=speed, - buf_size=buf_size) - assert ret['return'] == {} + vm.cmd('blockdev-mirror', + job_id='mirror', + device='source', + target='target', + sync='full', + speed=speed, + buf_size=buf_size) else: - ret = vm.qmp('blockdev-mirror', - job_id='mirror', - device='source', - target='target', - sync='full') - assert ret['return'] == {} + vm.cmd('blockdev-mirror', + job_id='mirror', + device='source', + target='target', + sync='full') log('') @@ -150,38 +146,33 @@ with iotests.VM() as vm, \ vm.launch() - ret = vm.qmp('object-add', qom_type='throttle-group', id='tg', - limits={'bps-read': 4096}) - assert ret['return'] == {} + vm.cmd('object-add', qom_type='throttle-group', id='tg', + limits={'bps-read': 4096}) - ret = vm.qmp('blockdev-add', - node_name='source', - driver=iotests.imgfmt, - file={ - 'driver': 'file', - 'filename': src_img_path - }) - assert ret['return'] == {} + vm.cmd('blockdev-add', + node_name='source', + driver=iotests.imgfmt, + file={ + 'driver': 'file', + 'filename': src_img_path + }) - ret = vm.qmp('blockdev-add', - node_name='throttled-source', - driver='throttle', - throttle_group='tg', - file='source') - assert ret['return'] == {} + vm.cmd('blockdev-add', + node_name='throttled-source', + driver='throttle', + throttle_group='tg', + file='source') - ret = vm.qmp('blockdev-add', - node_name='target', - driver='null-co', - size=(64 * 1048576)) - assert ret['return'] == {} + vm.cmd('blockdev-add', + node_name='target', + driver='null-co', + size=(64 * 1048576)) - ret = vm.qmp('blockdev-mirror', - job_id='mirror', - device='throttled-source', - target='target', - sync='full') - assert ret['return'] == {} + vm.cmd('blockdev-mirror', + job_id='mirror', + device='throttled-source', + target='target', + sync='full') log(vm.qmp('quit')) diff --git a/tests/qemu-iotests/245 b/tests/qemu-iotests/245 index 92b28c79be..a934c9d1e6 100755 --- a/tests/qemu-iotests/245 +++ b/tests/qemu-iotests/245 @@ -136,8 +136,7 @@ class TestBlockdevReopen(iotests.QMPTestCase): def test_incorrect_parameters_single_file(self): # Open 'hd0' only (no backing files) opts = hd_opts(0) - result = self.vm.qmp('blockdev-add', conv_keys = False, **opts) - self.assert_qmp(result, 'return', {}) + self.vm.cmd('blockdev-add', conv_keys = False, **opts) original_graph = self.vm.qmp('query-named-block-nodes') # We can reopen the image passing the same options @@ -171,8 +170,7 @@ class TestBlockdevReopen(iotests.QMPTestCase): self.check_node_graph(original_graph) # Remove the node - result = self.vm.qmp('blockdev-del', conv_keys = True, node_name = 'hd0') - self.assert_qmp(result, 'return', {}) + self.vm.cmd('blockdev-del', conv_keys = True, node_name = 'hd0') # This test opens an image with a backing file and tries to reopen # it with illegal / incorrect parameters. @@ -180,8 +178,7 @@ class TestBlockdevReopen(iotests.QMPTestCase): # Open hd1 omitting the backing options (hd0 will be opened # with the default options) opts = hd_opts(1) - result = self.vm.qmp('blockdev-add', conv_keys = False, **opts) - self.assert_qmp(result, 'return', {}) + self.vm.cmd('blockdev-add', conv_keys = False, **opts) original_graph = self.vm.qmp('query-named-block-nodes') # We can't reopen the image passing the same options, 'backing' is mandatory @@ -213,8 +210,7 @@ class TestBlockdevReopen(iotests.QMPTestCase): self.check_node_graph(original_graph) # Remove the node - result = self.vm.qmp('blockdev-del', conv_keys = True, node_name = 'hd1') - self.assert_qmp(result, 'return', {}) + self.vm.cmd('blockdev-del', conv_keys = True, node_name = 'hd1') # Reopen an image several times changing some of its options def test_reopen(self): @@ -230,8 +226,7 @@ class TestBlockdevReopen(iotests.QMPTestCase): # Open the hd1 image passing all backing options opts = hd_opts(1) opts['backing'] = hd_opts(0) - result = self.vm.qmp('blockdev-add', conv_keys = False, **opts) - self.assert_qmp(result, 'return', {}) + self.vm.cmd('blockdev-add', conv_keys = False, **opts) original_graph = self.vm.qmp('query-named-block-nodes') # We can reopen the image passing the same options @@ -306,8 +301,7 @@ class TestBlockdevReopen(iotests.QMPTestCase): self.assert_qmp_absent(self.get_node('hd1'), 'image/backing-image') # Open the 'hd0' image - result = self.vm.qmp('blockdev-add', conv_keys = False, **hd_opts(0)) - self.assert_qmp(result, 'return', {}) + self.vm.cmd('blockdev-add', conv_keys = False, **hd_opts(0)) # Reopen the hd1 image setting 'hd0' as its backing image self.reopen(opts, {'backing': 'hd0'}) @@ -326,10 +320,8 @@ class TestBlockdevReopen(iotests.QMPTestCase): self.assert_qmp(result, 'error/desc', "Node 'hd0' is busy: node is used as backing hd of 'hd1'") # But we can remove both nodes if done in the proper order - result = self.vm.qmp('blockdev-del', conv_keys = True, node_name = 'hd1') - self.assert_qmp(result, 'return', {}) - result = self.vm.qmp('blockdev-del', conv_keys = True, node_name = 'hd0') - self.assert_qmp(result, 'return', {}) + self.vm.cmd('blockdev-del', conv_keys = True, node_name = 'hd1') + self.vm.cmd('blockdev-del', conv_keys = True, node_name = 'hd0') # Reopen a raw image and see the effect of changing the 'offset' option def test_reopen_raw(self): @@ -345,8 +337,7 @@ class TestBlockdevReopen(iotests.QMPTestCase): qemu_io('-f', 'raw', '-c', 'write -P 0xa1 1M 1M', hd_path[0]) # Open the raw file with QEMU - result = self.vm.qmp('blockdev-add', conv_keys = False, **opts) - self.assert_qmp(result, 'return', {}) + self.vm.cmd('blockdev-add', conv_keys = False, **opts) # Read 1MB from offset 0 self.run_qemu_io("hd0", "read -P 0xa0 0 1M") @@ -362,8 +353,7 @@ class TestBlockdevReopen(iotests.QMPTestCase): self.run_qemu_io("hd0", "read -P 0xa0 0 1M") # Remove the block device - result = self.vm.qmp('blockdev-del', conv_keys = True, node_name = 'hd0') - self.assert_qmp(result, 'return', {}) + self.vm.cmd('blockdev-del', conv_keys = True, node_name = 'hd0') # Omitting an option should reset it to the default value, but if # an option cannot be changed it shouldn't be possible to reset it @@ -377,8 +367,7 @@ class TestBlockdevReopen(iotests.QMPTestCase): 'node-name': 'hd0-file' } } # Open the file with QEMU - result = self.vm.qmp('blockdev-add', conv_keys = False, **opts) - self.assert_qmp(result, 'return', {}) + self.vm.cmd('blockdev-add', conv_keys = False, **opts) # file.x-check-cache-dropped can be changed... self.reopen(opts, { 'file.x-check-cache-dropped': False }) @@ -394,8 +383,7 @@ class TestBlockdevReopen(iotests.QMPTestCase): self.reopen(opts, { 'file.locking': 'off' }) # Remove the block device - result = self.vm.qmp('blockdev-del', conv_keys = True, node_name = 'hd0') - self.assert_qmp(result, 'return', {}) + self.vm.cmd('blockdev-del', conv_keys = True, node_name = 'hd0') # This test modifies the node graph a few times by changing the # 'backing' option on reopen and verifies that the guest data that @@ -407,8 +395,7 @@ class TestBlockdevReopen(iotests.QMPTestCase): for i in range(3): opts.append(hd_opts(i)) opts[i]['backing'] = None - result = self.vm.qmp('blockdev-add', conv_keys = False, **opts[i]) - self.assert_qmp(result, 'return', {}) + self.vm.cmd('blockdev-add', conv_keys = False, **opts[i]) # hd0 self.run_qemu_io("hd0", "read -P 0xa0 0 1M") @@ -499,8 +486,7 @@ class TestBlockdevReopen(iotests.QMPTestCase): for i in range(3): opts.append(hd_opts(i)) opts[i]['backing'] = None - result = self.vm.qmp('blockdev-add', conv_keys = False, **opts[i]) - self.assert_qmp(result, 'return', {}) + self.vm.cmd('blockdev-add', conv_keys = False, **opts[i]) # hd1 <- hd0, hd1 <- hd2 self.reopen(opts[0], {'backing': 'hd1'}) @@ -532,8 +518,7 @@ class TestBlockdevReopen(iotests.QMPTestCase): 'node-name': 'bv', 'test': 'hd0', 'raw': 'hd1'} - result = self.vm.qmp('blockdev-add', conv_keys = False, **bvopts) - self.assert_qmp(result, 'return', {}) + self.vm.cmd('blockdev-add', conv_keys = False, **bvopts) # blkverify doesn't currently allow reopening. TODO: implement this self.reopen(bvopts, {}, "Block format 'blkverify' used by node 'bv'" + @@ -544,8 +529,7 @@ class TestBlockdevReopen(iotests.QMPTestCase): "Making 'bv' a backing child of 'hd0' would create a cycle") # Delete the blkverify node - result = self.vm.qmp('blockdev-del', conv_keys = True, node_name = 'bv') - self.assert_qmp(result, 'return', {}) + self.vm.cmd('blockdev-del', conv_keys = True, node_name = 'bv') # Replace the protocol layer ('file' parameter) of a disk image def test_replace_file(self): @@ -556,16 +540,13 @@ class TestBlockdevReopen(iotests.QMPTestCase): hd0_opts = {'driver': 'file', 'node-name': 'hd0-file', 'filename': hd_path[0] } hd1_opts = {'driver': 'file', 'node-name': 'hd1-file', 'filename': hd_path[1] } - result = self.vm.qmp('blockdev-add', conv_keys = False, **hd0_opts) - self.assert_qmp(result, 'return', {}) - result = self.vm.qmp('blockdev-add', conv_keys = False, **hd1_opts) - self.assert_qmp(result, 'return', {}) + self.vm.cmd('blockdev-add', conv_keys = False, **hd0_opts) + self.vm.cmd('blockdev-add', conv_keys = False, **hd1_opts) # Add a raw format layer that uses hd0-file as its protocol layer opts = {'driver': 'raw', 'node-name': 'hd', 'file': 'hd0-file'} - result = self.vm.qmp('blockdev-add', conv_keys = False, **opts) - self.assert_qmp(result, 'return', {}) + self.vm.cmd('blockdev-add', conv_keys = False, **opts) # Fill the image with data self.run_qemu_io("hd", "read -P 0 0 10k") @@ -588,21 +569,18 @@ class TestBlockdevReopen(iotests.QMPTestCase): def test_insert_throttle_filter(self): # Add an image to the VM hd0_opts = hd_opts(0) - result = self.vm.qmp('blockdev-add', conv_keys = False, **hd0_opts) - self.assert_qmp(result, 'return', {}) + self.vm.cmd('blockdev-add', conv_keys = False, **hd0_opts) # Create a throttle-group object opts = { 'qom-type': 'throttle-group', 'id': 'group0', 'limits': { 'iops-total': 1000 } } - result = self.vm.qmp('object-add', conv_keys = False, **opts) - self.assert_qmp(result, 'return', {}) + self.vm.cmd('object-add', conv_keys = False, **opts) # Add a throttle filter with the group that we just created. # The filter is not used by anyone yet opts = { 'driver': 'throttle', 'node-name': 'throttle0', 'throttle-group': 'group0', 'file': 'hd0-file' } - result = self.vm.qmp('blockdev-add', conv_keys = False, **opts) - self.assert_qmp(result, 'return', {}) + self.vm.cmd('blockdev-add', conv_keys = False, **opts) # Insert the throttle filter between hd0 and hd0-file self.reopen(hd0_opts, {'file': 'throttle0'}) @@ -615,15 +593,13 @@ class TestBlockdevReopen(iotests.QMPTestCase): def test_insert_compress_filter(self): # Add an image to the VM: hd (raw) -> hd0 (qcow2) -> hd0-file (file) opts = {'driver': 'raw', 'node-name': 'hd', 'file': hd_opts(0)} - result = self.vm.qmp('blockdev-add', conv_keys = False, **opts) - self.assert_qmp(result, 'return', {}) + self.vm.cmd('blockdev-add', conv_keys = False, **opts) # Add a 'compress' filter filter_opts = {'driver': 'compress', 'node-name': 'compress0', 'file': 'hd0'} - result = self.vm.qmp('blockdev-add', conv_keys = False, **filter_opts) - self.assert_qmp(result, 'return', {}) + self.vm.cmd('blockdev-add', conv_keys = False, **filter_opts) # Unmap the beginning of the image (we cannot write compressed # data to an allocated cluster) @@ -659,12 +635,10 @@ class TestBlockdevReopen(iotests.QMPTestCase): def test_swap_files(self): # Add hd0 and hd2 (none of them with backing files) opts0 = hd_opts(0) - result = self.vm.qmp('blockdev-add', conv_keys = False, **opts0) - self.assert_qmp(result, 'return', {}) + self.vm.cmd('blockdev-add', conv_keys = False, **opts0) opts2 = hd_opts(2) - result = self.vm.qmp('blockdev-add', conv_keys = False, **opts2) - self.assert_qmp(result, 'return', {}) + self.vm.cmd('blockdev-add', conv_keys = False, **opts2) # Write different data to both block devices self.run_qemu_io("hd0", "write -P 0xa0 0 1k") @@ -712,15 +686,13 @@ class TestBlockdevReopen(iotests.QMPTestCase): opts = hd_opts(i) # Open all three images without backing file opts['backing'] = None - result = self.vm.qmp('blockdev-add', conv_keys = False, **opts) - self.assert_qmp(result, 'return', {}) + self.vm.cmd('blockdev-add', conv_keys = False, **opts) opts = {'driver': 'quorum', 'node-name': 'quorum0', 'children': ['hd0', 'hd1', 'hd2'], 'vote-threshold': 2} - result = self.vm.qmp('blockdev-add', conv_keys = False, **opts) - self.assert_qmp(result, 'return', {}) + self.vm.cmd('blockdev-add', conv_keys = False, **opts) # Quorum doesn't currently allow reopening. TODO: implement this self.reopen(opts, {}, "Block format 'quorum' used by node 'quorum0'" + @@ -732,14 +704,12 @@ class TestBlockdevReopen(iotests.QMPTestCase): "Making 'quorum0' a backing child of 'hd0' would create a cycle") # Delete quorum0 - result = self.vm.qmp('blockdev-del', conv_keys = True, node_name = 'quorum0') - self.assert_qmp(result, 'return', {}) + self.vm.cmd('blockdev-del', conv_keys = True, node_name = 'quorum0') # Delete hd0, hd1 and hd2 for i in range(3): - result = self.vm.qmp('blockdev-del', conv_keys = True, - node_name = 'hd%d' % i) - self.assert_qmp(result, 'return', {}) + self.vm.cmd('blockdev-del', conv_keys = True, + node_name = 'hd%d' % i) ###################### ###### blkdebug ###### @@ -748,8 +718,7 @@ class TestBlockdevReopen(iotests.QMPTestCase): 'node-name': 'bd', 'config': '/dev/null', 'image': hd_opts(0)} - result = self.vm.qmp('blockdev-add', conv_keys = False, **opts) - self.assert_qmp(result, 'return', {}) + self.vm.cmd('blockdev-add', conv_keys = False, **opts) # blkdebug allows reopening if we keep the same options self.reopen(opts) @@ -762,16 +731,14 @@ class TestBlockdevReopen(iotests.QMPTestCase): self.reopen(opts, {}, "Option 'config' cannot be reset to its default value") # Delete the blkdebug node - result = self.vm.qmp('blockdev-del', conv_keys = True, node_name = 'bd') - self.assert_qmp(result, 'return', {}) + self.vm.cmd('blockdev-del', conv_keys = True, node_name = 'bd') ################## ###### null ###### ################## opts = {'driver': 'null-co', 'node-name': 'root', 'size': 1024} - result = self.vm.qmp('blockdev-add', conv_keys = False, **opts) - self.assert_qmp(result, 'return', {}) + self.vm.cmd('blockdev-add', conv_keys = False, **opts) # 1 << 30 is the default value, but we cannot change it explicitly self.reopen(opts, {'size': (1 << 30)}, "Cannot change the option 'size'") @@ -780,16 +747,14 @@ class TestBlockdevReopen(iotests.QMPTestCase): del opts['size'] self.reopen(opts, {}, "Option 'size' cannot be reset to its default value") - result = self.vm.qmp('blockdev-del', conv_keys = True, node_name = 'root') - self.assert_qmp(result, 'return', {}) + self.vm.cmd('blockdev-del', conv_keys = True, node_name = 'root') ################## ###### file ###### ################## opts = hd_opts(0) opts['file']['locking'] = 'on' - result = self.vm.qmp('blockdev-add', conv_keys = False, **opts) - self.assert_qmp(result, 'return', {}) + self.vm.cmd('blockdev-add', conv_keys = False, **opts) # 'locking' cannot be changed del opts['file']['locking'] @@ -803,27 +768,23 @@ class TestBlockdevReopen(iotests.QMPTestCase): self.reopen(opts, {'locking': 'off'}, "Cannot change the option 'locking'") self.reopen(opts, {}, "Option 'locking' cannot be reset to its default value") - result = self.vm.qmp('blockdev-del', conv_keys = True, node_name = 'hd0') - self.assert_qmp(result, 'return', {}) + self.vm.cmd('blockdev-del', conv_keys = True, node_name = 'hd0') ###################### ###### throttle ###### ###################### opts = { 'qom-type': 'throttle-group', 'id': 'group0', 'limits': { 'iops-total': 1000 } } - result = self.vm.qmp('object-add', conv_keys = False, **opts) - self.assert_qmp(result, 'return', {}) + self.vm.cmd('object-add', conv_keys = False, **opts) opts = { 'qom-type': 'throttle-group', 'id': 'group1', 'limits': { 'iops-total': 2000 } } - result = self.vm.qmp('object-add', conv_keys = False, **opts) - self.assert_qmp(result, 'return', {}) + self.vm.cmd('object-add', conv_keys = False, **opts) # Add a throttle filter with group = group0 opts = { 'driver': 'throttle', 'node-name': 'throttle0', 'throttle-group': 'group0', 'file': hd_opts(0) } - result = self.vm.qmp('blockdev-add', conv_keys = False, **opts) - self.assert_qmp(result, 'return', {}) + self.vm.cmd('blockdev-add', conv_keys = False, **opts) # We can reopen it if we keep the same options self.reopen(opts) @@ -851,16 +812,13 @@ class TestBlockdevReopen(iotests.QMPTestCase): self.assert_qmp(result, 'error/desc', "object 'group0' is in use, can not be deleted") # But group1 is free this time, and it can be deleted - result = self.vm.qmp('object-del', id = 'group1') - self.assert_qmp(result, 'return', {}) + self.vm.cmd('object-del', id = 'group1') # Let's delete the filter node - result = self.vm.qmp('blockdev-del', conv_keys = True, node_name = 'throttle0') - self.assert_qmp(result, 'return', {}) + self.vm.cmd('blockdev-del', conv_keys = True, node_name = 'throttle0') # And we can finally get rid of group0 - result = self.vm.qmp('object-del', id = 'group0') - self.assert_qmp(result, 'return', {}) + self.vm.cmd('object-del', id = 'group0') # If an image has a backing file then the 'backing' option must be # passed on reopen. We don't allow leaving the option out in this @@ -868,13 +826,11 @@ class TestBlockdevReopen(iotests.QMPTestCase): def test_missing_backing_options_1(self): # hd2 opts = hd_opts(2) - result = self.vm.qmp('blockdev-add', conv_keys = False, **opts) - self.assert_qmp(result, 'return', {}) + self.vm.cmd('blockdev-add', conv_keys = False, **opts) # hd0 opts = hd_opts(0) - result = self.vm.qmp('blockdev-add', conv_keys = False, **opts) - self.assert_qmp(result, 'return', {}) + self.vm.cmd('blockdev-add', conv_keys = False, **opts) # hd0 has no backing file: we can omit the 'backing' option self.reopen(opts) @@ -897,11 +853,9 @@ class TestBlockdevReopen(iotests.QMPTestCase): self.reopen(opts) # Remove both hd0 and hd2 - result = self.vm.qmp('blockdev-del', conv_keys = True, node_name = 'hd0') - self.assert_qmp(result, 'return', {}) + self.vm.cmd('blockdev-del', conv_keys = True, node_name = 'hd0') - result = self.vm.qmp('blockdev-del', conv_keys = True, node_name = 'hd2') - self.assert_qmp(result, 'return', {}) + self.vm.cmd('blockdev-del', conv_keys = True, node_name = 'hd2') # If an image has default backing file (as part of its metadata) # then the 'backing' option must be passed on reopen. We don't @@ -911,8 +865,7 @@ class TestBlockdevReopen(iotests.QMPTestCase): # hd0 <- hd1 # (hd0 is hd1's default backing file) opts = hd_opts(1) - result = self.vm.qmp('blockdev-add', conv_keys = False, **opts) - self.assert_qmp(result, 'return', {}) + self.vm.cmd('blockdev-add', conv_keys = False, **opts) # hd1 has a backing file: we can't omit the 'backing' option self.reopen(opts, {}, "backing is missing for 'hd1'") @@ -923,8 +876,7 @@ class TestBlockdevReopen(iotests.QMPTestCase): # No backing file attached to hd1 now, but we still can't omit the 'backing' option self.reopen(opts, {}, "backing is missing for 'hd1'") - result = self.vm.qmp('blockdev-del', conv_keys = True, node_name = 'hd1') - self.assert_qmp(result, 'return', {}) + self.vm.cmd('blockdev-del', conv_keys = True, node_name = 'hd1') # Test that making 'backing' a reference to an existing child # keeps its current options @@ -937,8 +889,7 @@ class TestBlockdevReopen(iotests.QMPTestCase): opts['detect-zeroes'] = 'on' opts['backing']['detect-zeroes'] = 'on' opts['backing']['backing']['detect-zeroes'] = 'on' - result = self.vm.qmp('blockdev-add', conv_keys = False, **opts) - self.assert_qmp(result, 'return', {}) + self.vm.cmd('blockdev-add', conv_keys = False, **opts) # Reopen the chain passing the minimum amount of required options. # By making 'backing' a reference to hd1 (instead of a sub-dict) @@ -961,12 +912,10 @@ class TestBlockdevReopen(iotests.QMPTestCase): opts = hd_opts(0) opts['backing'] = hd_opts(1) opts['backing']['backing'] = None - result = self.vm.qmp('blockdev-add', conv_keys = False, **opts) - self.assert_qmp(result, 'return', {}) + self.vm.cmd('blockdev-add', conv_keys = False, **opts) # Stream hd1 into hd0 and wait until it's done - result = self.vm.qmp('block-stream', conv_keys = True, job_id = 'stream0', device = 'hd0') - self.assert_qmp(result, 'return', {}) + self.vm.cmd('block-stream', conv_keys = True, job_id = 'stream0', device = 'hd0') self.wait_until_completed(drive = 'stream0') # Now we have only hd0 @@ -982,8 +931,7 @@ class TestBlockdevReopen(iotests.QMPTestCase): # We can also reopen hd0 if we set 'backing' to null self.reopen(opts, {'backing': None}) - result = self.vm.qmp('blockdev-del', conv_keys = True, node_name = 'hd0') - self.assert_qmp(result, 'return', {}) + self.vm.cmd('blockdev-del', conv_keys = True, node_name = 'hd0') # Another block_stream test def test_block_stream_2(self): @@ -991,13 +939,11 @@ class TestBlockdevReopen(iotests.QMPTestCase): opts = hd_opts(0) opts['backing'] = hd_opts(1) opts['backing']['backing'] = hd_opts(2) - result = self.vm.qmp('blockdev-add', conv_keys = False, **opts) - self.assert_qmp(result, 'return', {}) + self.vm.cmd('blockdev-add', conv_keys = False, **opts) # Stream hd1 into hd0 and wait until it's done - result = self.vm.qmp('block-stream', conv_keys = True, job_id = 'stream0', - device = 'hd0', base_node = 'hd2') - self.assert_qmp(result, 'return', {}) + self.vm.cmd('block-stream', conv_keys = True, job_id = 'stream0', + device = 'hd0', base_node = 'hd2') self.wait_until_completed(drive = 'stream0') # The chain is hd2 <- hd0 now. hd1 is missing @@ -1019,8 +965,7 @@ class TestBlockdevReopen(iotests.QMPTestCase): self.reopen(opts, {}, "backing is missing for 'hd0'") # Now we can delete hd0 (and hd2) - result = self.vm.qmp('blockdev-del', conv_keys = True, node_name = 'hd0') - self.assert_qmp(result, 'return', {}) + self.vm.cmd('blockdev-del', conv_keys = True, node_name = 'hd0') self.assertEqual(self.get_node('hd2'), None) # Reopen the chain during a block-stream job (from hd1 to hd0) @@ -1029,14 +974,12 @@ class TestBlockdevReopen(iotests.QMPTestCase): opts = hd_opts(0) opts['backing'] = hd_opts(1) opts['backing']['backing'] = hd_opts(2) - result = self.vm.qmp('blockdev-add', conv_keys = False, **opts) - self.assert_qmp(result, 'return', {}) + self.vm.cmd('blockdev-add', conv_keys = False, **opts) # hd2 <- hd0 - result = self.vm.qmp('block-stream', conv_keys = True, job_id = 'stream0', - device = 'hd0', base_node = 'hd2', - auto_finalize = False) - self.assert_qmp(result, 'return', {}) + self.vm.cmd('block-stream', conv_keys = True, job_id = 'stream0', + device = 'hd0', base_node = 'hd2', + auto_finalize = False) # We can remove hd2 while the stream job is ongoing opts['backing']['backing'] = None @@ -1054,14 +997,12 @@ class TestBlockdevReopen(iotests.QMPTestCase): opts = hd_opts(0) opts['backing'] = hd_opts(1) opts['backing']['backing'] = hd_opts(2) - result = self.vm.qmp('blockdev-add', conv_keys = False, **opts) - self.assert_qmp(result, 'return', {}) + self.vm.cmd('blockdev-add', conv_keys = False, **opts) # hd1 <- hd0 - result = self.vm.qmp('block-stream', conv_keys = True, job_id = 'stream0', - device = 'hd1', filter_node_name='cor', - auto_finalize = False) - self.assert_qmp(result, 'return', {}) + self.vm.cmd('block-stream', conv_keys = True, job_id = 'stream0', + device = 'hd1', filter_node_name='cor', + auto_finalize = False) # We can't reopen with the original options because there is a filter # inserted by stream job above hd1. @@ -1090,12 +1031,10 @@ class TestBlockdevReopen(iotests.QMPTestCase): opts = hd_opts(0) opts['backing'] = hd_opts(1) opts['backing']['backing'] = hd_opts(2) - result = self.vm.qmp('blockdev-add', conv_keys = False, **opts) - self.assert_qmp(result, 'return', {}) + self.vm.cmd('blockdev-add', conv_keys = False, **opts) - result = self.vm.qmp('block-commit', conv_keys = True, job_id = 'commit0', - device = 'hd0') - self.assert_qmp(result, 'return', {}) + self.vm.cmd('block-commit', conv_keys = True, job_id = 'commit0', + device = 'hd0') # We can't remove hd2 while the commit job is ongoing opts['backing']['backing'] = None @@ -1110,8 +1049,7 @@ class TestBlockdevReopen(iotests.QMPTestCase): self.assert_qmp(event, 'data/type', 'commit') self.assert_qmp_absent(event, 'data/error') - result = self.vm.qmp('block-job-complete', device='commit0') - self.assert_qmp(result, 'return', {}) + self.vm.cmd('block-job-complete', device='commit0') self.wait_until_completed(drive = 'commit0') @@ -1121,13 +1059,11 @@ class TestBlockdevReopen(iotests.QMPTestCase): opts = hd_opts(0) opts['backing'] = hd_opts(1) opts['backing']['backing'] = hd_opts(2) - result = self.vm.qmp('blockdev-add', conv_keys = False, **opts) - self.assert_qmp(result, 'return', {}) + self.vm.cmd('blockdev-add', conv_keys = False, **opts) - result = self.vm.qmp('block-commit', conv_keys = True, job_id = 'commit0', - device = 'hd0', top_node = 'hd1', - auto_finalize = False) - self.assert_qmp(result, 'return', {}) + self.vm.cmd('block-commit', conv_keys = True, job_id = 'commit0', + device = 'hd0', top_node = 'hd1', + auto_finalize = False) # We can't remove hd2 while the commit job is ongoing opts['backing']['backing'] = None @@ -1147,36 +1083,28 @@ class TestBlockdevReopen(iotests.QMPTestCase): def run_test_iothreads(self, iothread_a, iothread_b, errmsg = None, opts_a = None, opts_b = None): opts = opts_a or hd_opts(0) - result = self.vm.qmp('blockdev-add', conv_keys = False, **opts) - self.assert_qmp(result, 'return', {}) + self.vm.cmd('blockdev-add', conv_keys = False, **opts) opts2 = opts_b or hd_opts(2) - result = self.vm.qmp('blockdev-add', conv_keys = False, **opts2) - self.assert_qmp(result, 'return', {}) + self.vm.cmd('blockdev-add', conv_keys = False, **opts2) - result = self.vm.qmp('object-add', qom_type='iothread', id='iothread0') - self.assert_qmp(result, 'return', {}) + self.vm.cmd('object-add', qom_type='iothread', id='iothread0') - result = self.vm.qmp('object-add', qom_type='iothread', id='iothread1') - self.assert_qmp(result, 'return', {}) + self.vm.cmd('object-add', qom_type='iothread', id='iothread1') - result = self.vm.qmp('device_add', driver='virtio-scsi', id='scsi0', - iothread=iothread_a) - self.assert_qmp(result, 'return', {}) + self.vm.cmd('device_add', driver='virtio-scsi', id='scsi0', + iothread=iothread_a) - result = self.vm.qmp('device_add', driver='virtio-scsi', id='scsi1', - iothread=iothread_b) - self.assert_qmp(result, 'return', {}) + self.vm.cmd('device_add', driver='virtio-scsi', id='scsi1', + iothread=iothread_b) if iothread_a: - result = self.vm.qmp('device_add', driver='scsi-hd', drive='hd0', - share_rw=True, bus="scsi0.0") - self.assert_qmp(result, 'return', {}) + self.vm.cmd('device_add', driver='scsi-hd', drive='hd0', + share_rw=True, bus="scsi0.0") if iothread_b: - result = self.vm.qmp('device_add', driver='scsi-hd', drive='hd2', - share_rw=True, bus="scsi1.0") - self.assert_qmp(result, 'return', {}) + self.vm.cmd('device_add', driver='scsi-hd', drive='hd2', + share_rw=True, bus="scsi1.0") # Attaching the backing file may or may not work self.reopen(opts, {'backing': 'hd2'}, errmsg) @@ -1205,8 +1133,7 @@ class TestBlockdevReopen(iotests.QMPTestCase): # Create a throttle-group object opts = { 'qom-type': 'throttle-group', 'id': 'group0', 'limits': { 'iops-total': 1000 } } - result = self.vm.qmp('object-add', conv_keys = False, **opts) - self.assert_qmp(result, 'return', {}) + self.vm.cmd('object-add', conv_keys = False, **opts) # Options with a throttle filter between format and protocol opts = [ diff --git a/tests/qemu-iotests/264 b/tests/qemu-iotests/264 index d44deb673a..c532ccd809 100755 --- a/tests/qemu-iotests/264 +++ b/tests/qemu-iotests/264 @@ -48,18 +48,16 @@ class TestNbdReconnect(iotests.QMPTestCase): """Stat job with nbd target and kill the server""" assert job in ('blockdev-backup', 'blockdev-mirror') with qemu_nbd_popen('-k', nbd_sock, '-f', iotests.imgfmt, disk_b): - result = self.vm.qmp('blockdev-add', - {'node-name': 'backup0', - 'driver': 'raw', - 'file': {'driver': 'nbd', - 'server': {'type': 'unix', - 'path': nbd_sock}, - 'reconnect-delay': 10}}) - self.assert_qmp(result, 'return', {}) - result = self.vm.qmp(job, device='drive0', - sync='full', target='backup0', - speed=(1 * 1024 * 1024)) - self.assert_qmp(result, 'return', {}) + self.vm.cmd('blockdev-add', + {'node-name': 'backup0', + 'driver': 'raw', + 'file': {'driver': 'nbd', + 'server': {'type': 'unix', + 'path': nbd_sock}, + 'reconnect-delay': 10}}) + self.vm.cmd(job, device='drive0', + sync='full', target='backup0', + speed=(1 * 1024 * 1024)) # Wait for some progress t = 0.0 @@ -77,8 +75,7 @@ class TestNbdReconnect(iotests.QMPTestCase): self.assertTrue(jobs) self.assertTrue(jobs[0]['offset'] < jobs[0]['len']) - result = self.vm.qmp('block-job-set-speed', device='drive0', speed=0) - self.assert_qmp(result, 'return', {}) + self.vm.cmd('block-job-set-speed', device='drive0', speed=0) # Emulate server down time for 1 second time.sleep(1) @@ -91,12 +88,10 @@ class TestNbdReconnect(iotests.QMPTestCase): with qemu_nbd_popen('-k', nbd_sock, '-f', iotests.imgfmt, disk_b): e = self.vm.event_wait('BLOCK_JOB_COMPLETED') self.assertEqual(e['data']['offset'], size) - result = self.vm.qmp('blockdev-del', node_name='backup0') - self.assert_qmp(result, 'return', {}) + self.vm.cmd('blockdev-del', node_name='backup0') def cancel_job(self): - result = self.vm.qmp('block-job-cancel', device='drive0', force=True) - self.assert_qmp(result, 'return', {}) + self.vm.cmd('block-job-cancel', device='drive0', force=True) start_t = time.time() self.vm.event_wait('BLOCK_JOB_CANCELLED') diff --git a/tests/qemu-iotests/281 b/tests/qemu-iotests/281 index 5e1339bd75..f6746a12e8 100755 --- a/tests/qemu-iotests/281 +++ b/tests/qemu-iotests/281 @@ -56,15 +56,13 @@ class TestDirtyBitmapIOThread(iotests.QMPTestCase): os.remove(self.images[name]) def test_add_dirty_bitmap(self): - result = self.vm.qmp( + self.vm.cmd( 'block-dirty-bitmap-add', node='drive0', name='bitmap1', persistent=True, ) - self.assert_qmp(result, 'return', {}) - # Test for RHBZ#1746217 & RHBZ#1773517 class TestNBDMirrorIOThread(iotests.QMPTestCase): @@ -105,23 +103,21 @@ class TestNBDMirrorIOThread(iotests.QMPTestCase): os.remove(self.images[name]) def test_nbd_mirror(self): - result = self.vm_tgt.qmp( + self.vm_tgt.cmd( 'nbd-server-start', addr={ 'type': 'unix', 'data': { 'path': self.nbd_sock } } ) - self.assert_qmp(result, 'return', {}) - result = self.vm_tgt.qmp( + self.vm_tgt.cmd( 'nbd-server-add', device='drive0', writable=True ) - self.assert_qmp(result, 'return', {}) - result = self.vm_src.qmp( + self.vm_src.cmd( 'drive-mirror', device='drive0', target='nbd+unix:///drive0?socket=' + self.nbd_sock, @@ -130,7 +126,6 @@ class TestNBDMirrorIOThread(iotests.QMPTestCase): speed=64*1024*1024, job_id='j1' ) - self.assert_qmp(result, 'return', {}) self.vm_src.event_wait(name="BLOCK_JOB_READY") @@ -290,8 +285,7 @@ class TestYieldingAndTimers(iotests.QMPTestCase): # they will remain active, fire later, and then access freed data. # (Or, with "block/nbd: Assert there are no timers when closed" # applied, the assertions added in that patch will fail.) - result = self.vm.qmp('blockdev-del', node_name='nbd') - self.assert_qmp(result, 'return', {}) + self.vm.cmd('blockdev-del', node_name='nbd') # Give the timers some time to fire (both have a timeout of 1 s). # (Sleeping in an iotest may ring some alarm bells, but note that if @@ -303,9 +297,8 @@ class TestYieldingAndTimers(iotests.QMPTestCase): def test_yield_in_iothread(self): # Move the NBD node to the I/O thread; the NBD block driver should # attach the connection's QIOChannel to that thread's AioContext, too - result = self.vm.qmp('x-blockdev-set-iothread', - node_name='nbd', iothread='iothr') - self.assert_qmp(result, 'return', {}) + self.vm.cmd('x-blockdev-set-iothread', + node_name='nbd', iothread='iothr') # Do some I/O that will be throttled by the QSD, so that the network # connection hopefully will yield here. When it is resumed, it must diff --git a/tests/qemu-iotests/295 b/tests/qemu-iotests/295 index 8ebe31054c..04818af264 100755 --- a/tests/qemu-iotests/295 +++ b/tests/qemu-iotests/295 @@ -57,8 +57,7 @@ class EncryptionSetupTestCase(iotests.QMPTestCase): # create the secrets and load 'em into the VM self.secrets = [ Secret(i) for i in range(0, 6) ] for secret in self.secrets: - result = self.vm.qmp("object-add", **secret.to_qmp_object()) - self.assert_qmp(result, 'return', {}) + self.vm.cmd("object-add", **secret.to_qmp_object()) if iotests.imgfmt == "qcow2": self.pfx = "encrypt." @@ -102,7 +101,7 @@ class EncryptionSetupTestCase(iotests.QMPTestCase): } } - result = self.vm.qmp('blockdev-add', { + self.vm.cmd('blockdev-add', { 'driver': iotests.imgfmt, 'node-name': id, 'read-only': read_only, @@ -115,12 +114,10 @@ class EncryptionSetupTestCase(iotests.QMPTestCase): } } ) - self.assert_qmp(result, 'return', {}) # close the encrypted block device def closeImageQmp(self, id): - result = self.vm.qmp('blockdev-del', {'node-name': id}) - self.assert_qmp(result, 'return', {}) + self.vm.cmd('blockdev-del', {'node-name': id}) ########################################################################### # add a key to an encrypted block device @@ -159,8 +156,7 @@ class EncryptionSetupTestCase(iotests.QMPTestCase): args['force'] = True #TODO: check what jobs return - result = self.vm.qmp('x-blockdev-amend', **args) - assert result['return'] == {} + self.vm.cmd('x-blockdev-amend', **args) self.vm.run_job('job_add_key') # erase a key from an encrypted block device @@ -193,8 +189,7 @@ class EncryptionSetupTestCase(iotests.QMPTestCase): if force == True: args['force'] = True - result = self.vm.qmp('x-blockdev-amend', **args) - assert result['return'] == {} + self.vm.cmd('x-blockdev-amend', **args) self.vm.run_job('job_erase_key') ########################################################################### diff --git a/tests/qemu-iotests/296 b/tests/qemu-iotests/296 index 47d2526b72..2b63cefff0 100755 --- a/tests/qemu-iotests/296 +++ b/tests/qemu-iotests/296 @@ -61,10 +61,8 @@ class EncryptionSetupTestCase(iotests.QMPTestCase): # create the secrets and load 'em into the VMs self.secrets = [ Secret(i) for i in range(0, 4) ] for secret in self.secrets: - result = self.vm1.qmp("object-add", secret.to_qmp_object()) - self.assert_qmp(result, 'return', {}) - result = self.vm2.qmp("object-add", secret.to_qmp_object()) - self.assert_qmp(result, 'return', {}) + self.vm1.cmd("object-add", secret.to_qmp_object()) + self.vm2.cmd("object-add", secret.to_qmp_object()) # test case shutdown def tearDown(self): @@ -132,11 +130,9 @@ class EncryptionSetupTestCase(iotests.QMPTestCase): } if reOpen: - result = vm.qmp(command, options=[opts]) - self.assert_qmp(result, 'return', {}) + vm.cmd(command, options=[opts]) else: - result = vm.qmp(command, opts) - self.assert_qmp(result, 'return', {}) + vm.cmd(command, opts) ########################################################################### @@ -154,8 +150,7 @@ class EncryptionSetupTestCase(iotests.QMPTestCase): # close the encrypted block device def closeImageQmp(self, vm, id): - result = vm.qmp('blockdev-del', {'node-name': id}) - self.assert_qmp(result, 'return', {}) + vm.cmd('blockdev-del', {'node-name': id}) ########################################################################### diff --git a/tests/qemu-iotests/298 b/tests/qemu-iotests/298 index 9e75ac6975..09c9290711 100755 --- a/tests/qemu-iotests/298 +++ b/tests/qemu-iotests/298 @@ -80,25 +80,23 @@ class TestPreallocateFilter(TestPreallocateBase): def test_external_snapshot(self): self.test_prealloc() - result = self.vm.qmp('blockdev-snapshot-sync', node_name='disk', - snapshot_file=overlay, - snapshot_node_name='overlay') - self.assert_qmp(result, 'return', {}) + self.vm.cmd('blockdev-snapshot-sync', node_name='disk', + snapshot_file=overlay, + snapshot_node_name='overlay') # on reopen to r-o base preallocation should be dropped self.check_small() self.vm.hmp_qemu_io('drive0', 'write 1M 1M') - result = self.vm.qmp('block-commit', device='overlay') - self.assert_qmp(result, 'return', {}) + self.vm.cmd('block-commit', device='overlay') self.complete_and_wait() # commit of new megabyte should trigger preallocation self.check_big() def test_reopen_opts(self): - result = self.vm.qmp('blockdev-reopen', options=[{ + self.vm.cmd('blockdev-reopen', options=[{ 'node-name': 'disk', 'driver': iotests.imgfmt, 'file': { @@ -113,7 +111,6 @@ class TestPreallocateFilter(TestPreallocateBase): } } }]) - self.assert_qmp(result, 'return', {}) self.vm.hmp_qemu_io('drive0', 'write 0 1M') self.assertTrue(os.path.getsize(disk) == 25 * MiB) diff --git a/tests/qemu-iotests/300 b/tests/qemu-iotests/300 index dbd28384ec..e46616d7b1 100755 --- a/tests/qemu-iotests/300 +++ b/tests/qemu-iotests/300 @@ -50,10 +50,9 @@ class TestDirtyBitmapMigration(iotests.QMPTestCase): self.vm_b.add_incoming(f'unix:{mig_sock}') self.vm_b.launch() - result = self.vm_a.qmp('block-dirty-bitmap-add', - node=self.src_node_name, - name=self.src_bmap_name) - self.assert_qmp(result, 'return', {}) + self.vm_a.cmd('block-dirty-bitmap-add', + node=self.src_node_name, + name=self.src_bmap_name) # Dirty some random megabytes for _ in range(9): @@ -69,8 +68,7 @@ class TestDirtyBitmapMigration(iotests.QMPTestCase): for name in ('dirty-bitmaps', 'events')] for vm in (self.vm_a, self.vm_b): - result = vm.qmp('migrate-set-capabilities', capabilities=caps) - self.assert_qmp(result, 'return', {}) + vm.cmd('migrate-set-capabilities', capabilities=caps) def tearDown(self) -> None: self.vm_a.shutdown() @@ -93,8 +91,7 @@ class TestDirtyBitmapMigration(iotests.QMPTestCase): def migrate(self, bitmap_name_valid: bool = True, migration_success: bool = True) -> None: - result = self.vm_a.qmp('migrate', uri=f'unix:{mig_sock}') - self.assert_qmp(result, 'return', {}) + self.vm_a.cmd('migrate', uri=f'unix:{mig_sock}') with iotests.Timeout(5, 'Timeout waiting for migration to complete'): self.assertEqual(self.vm_a.wait_migration('postmigrate'), @@ -442,10 +439,9 @@ class TestBlockBitmapMappingErrors(TestDirtyBitmapMigration): def test_bitmap_name_too_long(self) -> None: name = 'a' * 256 - result = self.vm_a.qmp('block-dirty-bitmap-add', - node=self.src_node_name, - name=name) - self.assert_qmp(result, 'return', {}) + self.vm_a.cmd('block-dirty-bitmap-add', + node=self.src_node_name, + name=name) self.migrate(False, False) @@ -517,22 +513,19 @@ class TestCrossAliasMigration(TestDirtyBitmapMigration): TestDirtyBitmapMigration.setUp(self) # Now create another block device and let both have two bitmaps each - result = self.vm_a.qmp('blockdev-add', - node_name='node-b', driver='null-co') - self.assert_qmp(result, 'return', {}) + self.vm_a.cmd('blockdev-add', + node_name='node-b', driver='null-co') - result = self.vm_b.qmp('blockdev-add', - node_name='node-a', driver='null-co') - self.assert_qmp(result, 'return', {}) + self.vm_b.cmd('blockdev-add', + node_name='node-a', driver='null-co') bmaps_to_add = (('node-a', 'bmap-b'), ('node-b', 'bmap-a'), ('node-b', 'bmap-b')) for (node, bmap) in bmaps_to_add: - result = self.vm_a.qmp('block-dirty-bitmap-add', - node=node, name=bmap) - self.assert_qmp(result, 'return', {}) + self.vm_a.cmd('block-dirty-bitmap-add', + node=node, name=bmap) @staticmethod def cross_mapping() -> BlockBitmapMapping: @@ -611,24 +604,21 @@ class TestAliasTransformMigration(TestDirtyBitmapMigration): TestDirtyBitmapMigration.setUp(self) # Now create another block device and let both have two bitmaps each - result = self.vm_a.qmp('blockdev-add', - node_name='node-b', driver='null-co', - read_zeroes=False) - self.assert_qmp(result, 'return', {}) + self.vm_a.cmd('blockdev-add', + node_name='node-b', driver='null-co', + read_zeroes=False) - result = self.vm_b.qmp('blockdev-add', - node_name='node-a', driver='null-co', - read_zeroes=False) - self.assert_qmp(result, 'return', {}) + self.vm_b.cmd('blockdev-add', + node_name='node-a', driver='null-co', + read_zeroes=False) bmaps_to_add = (('node-a', 'bmap-b'), ('node-b', 'bmap-a'), ('node-b', 'bmap-b')) for (node, bmap) in bmaps_to_add: - result = self.vm_a.qmp('block-dirty-bitmap-add', - node=node, name=bmap) - self.assert_qmp(result, 'return', {}) + self.vm_a.cmd('block-dirty-bitmap-add', + node=node, name=bmap) @staticmethod def transform_mapping() -> BlockBitmapMapping: diff --git a/tests/qemu-iotests/iotests.py b/tests/qemu-iotests/iotests.py index f43814e802..e5c5798c71 100644 --- a/tests/qemu-iotests/iotests.py +++ b/tests/qemu-iotests/iotests.py @@ -1252,8 +1252,7 @@ class QMPTestCase(unittest.TestCase): def cancel_and_wait(self, drive='drive0', force=False, resume=False, wait=60.0): '''Cancel a block job and wait for it to finish, returning the event''' - result = self.vm.qmp('block-job-cancel', device=drive, force=force) - self.assert_qmp(result, 'return', {}) + self.vm.cmd('block-job-cancel', device=drive, force=force) if resume: self.vm.resume_drive(drive) @@ -1315,8 +1314,7 @@ class QMPTestCase(unittest.TestCase): if wait_ready: self.wait_ready(drive=drive) - result = self.vm.qmp('block-job-complete', device=drive) - self.assert_qmp(result, 'return', {}) + self.vm.cmd('block-job-complete', device=drive) event = self.wait_until_completed(drive=drive, error=completion_error) self.assertTrue(event['data']['type'] in ['mirror', 'commit']) @@ -1335,8 +1333,7 @@ class QMPTestCase(unittest.TestCase): assert found def pause_job(self, job_id='job0', wait=True): - result = self.vm.qmp('block-job-pause', device=job_id) - self.assert_qmp(result, 'return', {}) + self.vm.cmd('block-job-pause', device=job_id) if wait: self.pause_wait(job_id) diff --git a/tests/qemu-iotests/tests/backing-file-invalidation b/tests/qemu-iotests/tests/backing-file-invalidation index 4eccc80153..b0e19839db 100755 --- a/tests/qemu-iotests/tests/backing-file-invalidation +++ b/tests/qemu-iotests/tests/backing-file-invalidation @@ -129,12 +129,11 @@ class TestPostMigrateFilename(iotests.QMPTestCase): # For good measure, try creating an overlay and check its backing # chain below. This is how the issue was originally found. - result = self.vm_d.qmp('blockdev-snapshot-sync', - format=iotests.imgfmt, - snapshot_file=imgs[3], - node_name='node0', - snapshot_node_name='node0-overlay') - self.assert_qmp(result, 'return', {}) + self.vm_d.cmd('blockdev-snapshot-sync', + format=iotests.imgfmt, + snapshot_file=imgs[3], + node_name='node0', + snapshot_node_name='node0-overlay') self.vm_d.shutdown() self.vm_d = None diff --git a/tests/qemu-iotests/tests/copy-before-write b/tests/qemu-iotests/tests/copy-before-write index d3987db942..d33bea577d 100755 --- a/tests/qemu-iotests/tests/copy-before-write +++ b/tests/qemu-iotests/tests/copy-before-write @@ -48,7 +48,7 @@ class TestCbwError(iotests.QMPTestCase): self.vm.launch() def do_cbw_error(self, on_cbw_error): - result = self.vm.qmp('blockdev-add', { + self.vm.cmd('blockdev-add', { 'node-name': 'cbw', 'driver': 'copy-before-write', 'on-cbw-error': on_cbw_error, @@ -78,14 +78,12 @@ class TestCbwError(iotests.QMPTestCase): } } }) - self.assert_qmp(result, 'return', {}) - result = self.vm.qmp('blockdev-add', { + self.vm.cmd('blockdev-add', { 'node-name': 'access', 'driver': 'snapshot-access', 'file': 'cbw' }) - self.assert_qmp(result, 'return', {}) result = self.vm.qmp('human-monitor-command', command_line='qemu-io cbw "write 0 1M"') @@ -129,14 +127,13 @@ read 1048576/1048576 bytes at offset 0 """) def do_cbw_timeout(self, on_cbw_error): - result = self.vm.qmp('object-add', { + self.vm.cmd('object-add', { 'qom-type': 'throttle-group', 'id': 'group0', 'limits': {'bps-write': 300 * 1024} }) - self.assert_qmp(result, 'return', {}) - result = self.vm.qmp('blockdev-add', { + self.vm.cmd('blockdev-add', { 'node-name': 'cbw', 'driver': 'copy-before-write', 'on-cbw-error': on_cbw_error, @@ -160,14 +157,12 @@ read 1048576/1048576 bytes at offset 0 } } }) - self.assert_qmp(result, 'return', {}) - result = self.vm.qmp('blockdev-add', { + self.vm.cmd('blockdev-add', { 'node-name': 'access', 'driver': 'snapshot-access', 'file': 'cbw' }) - self.assert_qmp(result, 'return', {}) result = self.vm.qmp('human-monitor-command', command_line='qemu-io cbw "write 0 512K"') diff --git a/tests/qemu-iotests/tests/export-incoming-iothread b/tests/qemu-iotests/tests/export-incoming-iothread index 7679e49103..d36d6194e0 100755 --- a/tests/qemu-iotests/tests/export-incoming-iothread +++ b/tests/qemu-iotests/tests/export-incoming-iothread @@ -55,7 +55,7 @@ class TestExportIncomingIothread(iotests.QMPTestCase): os.remove(test_img) def test_export_add(self): - result = self.vm.qmp('nbd-server-start', { + self.vm.cmd('nbd-server-start', { 'addr': { 'type': 'unix', 'data': { @@ -63,16 +63,14 @@ class TestExportIncomingIothread(iotests.QMPTestCase): } } }) - self.assert_qmp(result, 'return', {}) # Regression test for issue 945: This should not fail an assertion - result = self.vm.qmp('block-export-add', { + self.vm.cmd('block-export-add', { 'type': 'nbd', 'id': 'exp0', 'node-name': node_name, 'iothread': iothread_id }) - self.assert_qmp(result, 'return', {}) if __name__ == '__main__': diff --git a/tests/qemu-iotests/tests/graph-changes-while-io b/tests/qemu-iotests/tests/graph-changes-while-io index 750e7d4d38..194fda500e 100755 --- a/tests/qemu-iotests/tests/graph-changes-while-io +++ b/tests/qemu-iotests/tests/graph-changes-while-io @@ -66,7 +66,7 @@ class TestGraphChangesWhileIO(QMPTestCase): # While qemu-img bench is running, repeatedly add and remove an # overlay to/from node0 while bench_thr.is_alive(): - result = self.qsd.qmp('blockdev-add', { + self.qsd.cmd('blockdev-add', { 'driver': imgfmt, 'node-name': 'overlay', 'backing': 'node0', @@ -75,12 +75,10 @@ class TestGraphChangesWhileIO(QMPTestCase): 'filename': top } }) - self.assert_qmp(result, 'return', {}) - result = self.qsd.qmp('blockdev-del', { + self.qsd.cmd('blockdev-del', { 'node-name': 'overlay' }) - self.assert_qmp(result, 'return', {}) bench_thr.join() @@ -92,7 +90,7 @@ class TestGraphChangesWhileIO(QMPTestCase): qemu_io('-c', 'write 0 64k', top) qemu_io('-c', 'write 128k 64k', top) - result = self.qsd.qmp('blockdev-add', { + self.qsd.cmd('blockdev-add', { 'driver': imgfmt, 'node-name': 'overlay', 'backing': None, @@ -101,26 +99,22 @@ class TestGraphChangesWhileIO(QMPTestCase): 'filename': top } }) - self.assert_qmp(result, 'return', {}) - result = self.qsd.qmp('blockdev-snapshot', { + self.qsd.cmd('blockdev-snapshot', { 'node': 'node0', 'overlay': 'overlay', }) - self.assert_qmp(result, 'return', {}) # While qemu-img bench is running, repeatedly commit overlay to node0 while bench_thr.is_alive(): - result = self.qsd.qmp('block-commit', { + self.qsd.cmd('block-commit', { 'job-id': 'job0', 'device': 'overlay', }) - self.assert_qmp(result, 'return', {}) - result = self.qsd.qmp('block-job-cancel', { + self.qsd.cmd('block-job-cancel', { 'device': 'job0', }) - self.assert_qmp(result, 'return', {}) cancelled = False while not cancelled: diff --git a/tests/qemu-iotests/tests/image-fleecing b/tests/qemu-iotests/tests/image-fleecing index f6e449d071..5e3b2c7e46 100755 --- a/tests/qemu-iotests/tests/image-fleecing +++ b/tests/qemu-iotests/tests/image-fleecing @@ -213,8 +213,7 @@ def do_test(vm, use_cbw, use_snapshot_access_filter, base_img_path, result = vm.qmp('query-block-jobs') assert len(result['return']) == 1 - result = vm.qmp('block-job-set-speed', device='push-backup', speed=0) - assert result == {'return': {}} + vm.cmd('block-job-set-speed', device='push-backup', speed=0) log(vm.event_wait(name='BLOCK_JOB_COMPLETED', match={'data': {'device': 'push-backup'}}), diff --git a/tests/qemu-iotests/tests/migrate-bitmaps-postcopy-test b/tests/qemu-iotests/tests/migrate-bitmaps-postcopy-test index dda55fad28..c519e6db8c 100755 --- a/tests/qemu-iotests/tests/migrate-bitmaps-postcopy-test +++ b/tests/qemu-iotests/tests/migrate-bitmaps-postcopy-test @@ -118,11 +118,10 @@ class TestDirtyBitmapPostcopyMigration(iotests.QMPTestCase): def start_postcopy(self): """ Run migration until RESUME event on target. Return this event. """ for i in range(nb_bitmaps): - result = self.vm_a.qmp('block-dirty-bitmap-add', node='drive0', - name='bitmap{}'.format(i), - granularity=granularity, - persistent=True) - self.assert_qmp(result, 'return', {}) + self.vm_a.cmd('block-dirty-bitmap-add', node='drive0', + name='bitmap{}'.format(i), + granularity=granularity, + persistent=True) result = self.vm_a.qmp('x-debug-block-dirty-bitmap-sha256', node='drive0', name='bitmap0') @@ -140,9 +139,8 @@ class TestDirtyBitmapPostcopyMigration(iotests.QMPTestCase): # We want to calculate resulting sha256. Do it in bitmap0, so, disable # other bitmaps for i in range(1, nb_bitmaps): - result = self.vm_a.qmp('block-dirty-bitmap-disable', node='drive0', - name='bitmap{}'.format(i)) - self.assert_qmp(result, 'return', {}) + self.vm_a.cmd('block-dirty-bitmap-disable', node='drive0', + name='bitmap{}'.format(i)) apply_discards(self.vm_a, discards2) @@ -152,24 +150,19 @@ class TestDirtyBitmapPostcopyMigration(iotests.QMPTestCase): # Now, enable some bitmaps, to be updated during migration for i in range(2, nb_bitmaps, 2): - result = self.vm_a.qmp('block-dirty-bitmap-enable', node='drive0', - name='bitmap{}'.format(i)) - self.assert_qmp(result, 'return', {}) + self.vm_a.cmd('block-dirty-bitmap-enable', node='drive0', + name='bitmap{}'.format(i)) caps = [{'capability': 'dirty-bitmaps', 'state': True}, {'capability': 'events', 'state': True}] - result = self.vm_a.qmp('migrate-set-capabilities', capabilities=caps) - self.assert_qmp(result, 'return', {}) + self.vm_a.cmd('migrate-set-capabilities', capabilities=caps) - result = self.vm_b.qmp('migrate-set-capabilities', capabilities=caps) - self.assert_qmp(result, 'return', {}) + self.vm_b.cmd('migrate-set-capabilities', capabilities=caps) - result = self.vm_a.qmp('migrate', uri='exec:cat>' + fifo) - self.assert_qmp(result, 'return', {}) + self.vm_a.cmd('migrate', uri='exec:cat>' + fifo) - result = self.vm_a.qmp('migrate-start-postcopy') - self.assert_qmp(result, 'return', {}) + self.vm_a.cmd('migrate-start-postcopy') event_resume = self.vm_b.event_wait('RESUME') self.vm_b_events.append(event_resume) diff --git a/tests/qemu-iotests/tests/migrate-bitmaps-test b/tests/qemu-iotests/tests/migrate-bitmaps-test index eebb256485..f98e721e97 100755 --- a/tests/qemu-iotests/tests/migrate-bitmaps-test +++ b/tests/qemu-iotests/tests/migrate-bitmaps-test @@ -67,8 +67,7 @@ class TestDirtyBitmapMigration(iotests.QMPTestCase): if persistent: params['persistent'] = True - result = vm.qmp('block-dirty-bitmap-add', params) - self.assert_qmp(result, 'return', {}) + vm.cmd('block-dirty-bitmap-add', params) def check_bitmap(self, vm, sha256): result = vm.qmp('x-debug-block-dirty-bitmap-sha256', @@ -91,17 +90,15 @@ class TestDirtyBitmapMigration(iotests.QMPTestCase): if migrate_bitmaps: mig_caps.append({'capability': 'dirty-bitmaps', 'state': True}) - result = self.vm_a.qmp('migrate-set-capabilities', - capabilities=mig_caps) - self.assert_qmp(result, 'return', {}) + self.vm_a.cmd('migrate-set-capabilities', + capabilities=mig_caps) self.add_bitmap(self.vm_a, granularity, persistent) for r in regions: self.vm_a.hmp_qemu_io('drive0', 'write %d %d' % r) sha256 = get_bitmap_hash(self.vm_a) - result = self.vm_a.qmp('migrate', uri=mig_cmd) - self.assert_qmp(result, 'return', {}) + self.vm_a.cmd('migrate', uri=mig_cmd) while True: event = self.vm_a.event_wait('MIGRATION') if event['data']['status'] == 'completed': @@ -115,8 +112,7 @@ class TestDirtyBitmapMigration(iotests.QMPTestCase): removed = (not migrate_bitmaps) and persistent self.check_bitmap(self.vm_a, False if removed else sha256) - result = self.vm_a.qmp('cont') - self.assert_qmp(result, 'return', {}) + self.vm_a.cmd('cont') # test that bitmap is still here after invalidation self.check_bitmap(self.vm_a, sha256) @@ -159,9 +155,8 @@ class TestDirtyBitmapMigration(iotests.QMPTestCase): if online: os.mkfifo(mig_file) self.vm_b.launch() - result = self.vm_b.qmp('migrate-set-capabilities', - capabilities=mig_caps) - self.assert_qmp(result, 'return', {}) + self.vm_b.cmd('migrate-set-capabilities', + capabilities=mig_caps) self.add_bitmap(self.vm_a, granularity, persistent) for r in regions: @@ -172,12 +167,10 @@ class TestDirtyBitmapMigration(iotests.QMPTestCase): self.vm_a.shutdown() self.vm_a.launch() - result = self.vm_a.qmp('migrate-set-capabilities', - capabilities=mig_caps) - self.assert_qmp(result, 'return', {}) + self.vm_a.cmd('migrate-set-capabilities', + capabilities=mig_caps) - result = self.vm_a.qmp('migrate', uri=mig_cmd) - self.assert_qmp(result, 'return', {}) + self.vm_a.cmd('migrate', uri=mig_cmd) while True: event = self.vm_a.event_wait('MIGRATION') if event['data']['status'] == 'completed': @@ -186,11 +179,9 @@ class TestDirtyBitmapMigration(iotests.QMPTestCase): if not online: self.vm_a.shutdown() self.vm_b.launch() - result = self.vm_b.qmp('migrate-set-capabilities', - capabilities=mig_caps) - self.assert_qmp(result, 'return', {}) - result = self.vm_b.qmp('migrate-incoming', uri=incoming_cmd) - self.assert_qmp(result, 'return', {}) + self.vm_b.cmd('migrate-set-capabilities', + capabilities=mig_caps) + self.vm_b.cmd('migrate-incoming', uri=incoming_cmd) while True: event = self.vm_b.event_wait('MIGRATION') @@ -256,8 +247,7 @@ class TestDirtyBitmapBackingMigration(iotests.QMPTestCase): self.vm = iotests.VM() self.vm.launch() - result = self.vm.qmp('blockdev-add', blockdev) - self.assert_qmp(result, 'return', {}) + self.vm.cmd('blockdev-add', blockdev) # Check that the bitmaps are there nodes = self.vm.qmp('query-named-block-nodes', flat=True)['return'] @@ -266,8 +256,7 @@ class TestDirtyBitmapBackingMigration(iotests.QMPTestCase): self.assert_qmp(node, 'dirty-bitmaps[0]/name', 'bmap0') caps = [{'capability': 'events', 'state': True}] - result = self.vm.qmp('migrate-set-capabilities', capabilities=caps) - self.assert_qmp(result, 'return', {}) + self.vm.cmd('migrate-set-capabilities', capabilities=caps) def tearDown(self): self.vm.shutdown() @@ -278,14 +267,12 @@ class TestDirtyBitmapBackingMigration(iotests.QMPTestCase): """ Continue the source after migration. """ - result = self.vm.qmp('migrate', uri='exec: cat > /dev/null') - self.assert_qmp(result, 'return', {}) + self.vm.cmd('migrate', uri='exec: cat > /dev/null') with Timeout(10, 'Migration timeout'): self.vm.wait_migration('postmigrate') - result = self.vm.qmp('cont') - self.assert_qmp(result, 'return', {}) + self.vm.cmd('cont') def main() -> None: diff --git a/tests/qemu-iotests/tests/migrate-during-backup b/tests/qemu-iotests/tests/migrate-during-backup index 34103229ee..afb2277896 100755 --- a/tests/qemu-iotests/tests/migrate-during-backup +++ b/tests/qemu-iotests/tests/migrate-during-backup @@ -43,7 +43,7 @@ class TestMigrateDuringBackup(iotests.QMPTestCase): self.vm = iotests.VM().add_drive(disk_a) self.vm.launch() - result = self.vm.qmp('blockdev-add', { + self.vm.cmd('blockdev-add', { 'node-name': 'target', 'driver': iotests.imgfmt, 'file': { @@ -51,26 +51,21 @@ class TestMigrateDuringBackup(iotests.QMPTestCase): 'filename': disk_b } }) - self.assert_qmp(result, 'return', {}) def test_migrate(self): - result = self.vm.qmp('blockdev-backup', device='drive0', - target='target', sync='full', - speed=1, x_perf={ - 'max-workers': 1, - 'max-chunk': 64 * 1024 - }) - self.assert_qmp(result, 'return', {}) + self.vm.cmd('blockdev-backup', device='drive0', + target='target', sync='full', + speed=1, x_perf={ + 'max-workers': 1, + 'max-chunk': 64 * 1024 + }) - result = self.vm.qmp('job-pause', id='drive0') - self.assert_qmp(result, 'return', {}) + self.vm.cmd('job-pause', id='drive0') - result = self.vm.qmp('migrate-set-capabilities', - capabilities=[{'capability': 'events', - 'state': True}]) - self.assert_qmp(result, 'return', {}) - result = self.vm.qmp('migrate', uri=mig_cmd) - self.assert_qmp(result, 'return', {}) + self.vm.cmd('migrate-set-capabilities', + capabilities=[{'capability': 'events', + 'state': True}]) + self.vm.cmd('migrate', uri=mig_cmd) e = self.vm.events_wait((('MIGRATION', {'data': {'status': 'completed'}}), @@ -80,11 +75,9 @@ class TestMigrateDuringBackup(iotests.QMPTestCase): # Don't assert that e is 'failed' now: this way we'll miss # possible crash when backup continues :) - result = self.vm.qmp('block-job-set-speed', device='drive0', - speed=0) - self.assert_qmp(result, 'return', {}) - result = self.vm.qmp('job-resume', id='drive0') - self.assert_qmp(result, 'return', {}) + self.vm.cmd('block-job-set-speed', device='drive0', + speed=0) + self.vm.cmd('job-resume', id='drive0') # For future: if something changes so that both migration # and backup pass, let's not miss that moment, as it may diff --git a/tests/qemu-iotests/tests/migration-permissions b/tests/qemu-iotests/tests/migration-permissions index 4e1da369c9..0deaad2d3a 100755 --- a/tests/qemu-iotests/tests/migration-permissions +++ b/tests/qemu-iotests/tests/migration-permissions @@ -47,11 +47,10 @@ class TestMigrationPermissions(iotests.QMPTestCase): vms[i].launch() - result = vms[i].qmp('migrate-set-capabilities', - capabilities=[ - {'capability': 'events', 'state': True} - ]) - self.assert_qmp(result, 'return', {}) + vms[i].cmd('migrate-set-capabilities', + capabilities=[ + {'capability': 'events', 'state': True} + ]) self.vm_s = vms[0] self.vm_d = vms[1] diff --git a/tests/qemu-iotests/tests/mirror-ready-cancel-error b/tests/qemu-iotests/tests/mirror-ready-cancel-error index a59e245659..ed2e46447e 100755 --- a/tests/qemu-iotests/tests/mirror-ready-cancel-error +++ b/tests/qemu-iotests/tests/mirror-ready-cancel-error @@ -48,51 +48,48 @@ class TestMirrorReadyCancelError(iotests.QMPTestCase): os.remove(target) def add_blockdevs(self, once: bool) -> None: - res = self.vm.qmp('blockdev-add', - {'node-name': 'source', - 'driver': iotests.imgfmt, - 'file': { - 'driver': 'file', - 'filename': source - }}) - self.assert_qmp(res, 'return', {}) + self.vm.cmd('blockdev-add', + {'node-name': 'source', + 'driver': iotests.imgfmt, + 'file': { + 'driver': 'file', + 'filename': source + }}) # blkdebug notes: # Enter state 2 on the first flush, which happens before the # job enters the READY state. The second flush will happen # when the job is about to complete, and we want that one to # fail. - res = self.vm.qmp('blockdev-add', - {'node-name': 'target', - 'driver': iotests.imgfmt, - 'file': { - 'driver': 'blkdebug', - 'image': { - 'driver': 'file', - 'filename': target - }, - 'set-state': [{ - 'event': 'flush_to_disk', - 'state': 1, - 'new_state': 2 - }], - 'inject-error': [{ - 'event': 'flush_to_disk', - 'once': once, - 'immediately': True, - 'state': 2 - }]}}) - self.assert_qmp(res, 'return', {}) + self.vm.cmd('blockdev-add', + {'node-name': 'target', + 'driver': iotests.imgfmt, + 'file': { + 'driver': 'blkdebug', + 'image': { + 'driver': 'file', + 'filename': target + }, + 'set-state': [{ + 'event': 'flush_to_disk', + 'state': 1, + 'new_state': 2 + }], + 'inject-error': [{ + 'event': 'flush_to_disk', + 'once': once, + 'immediately': True, + 'state': 2 + }]}}) def start_mirror(self) -> None: - res = self.vm.qmp('blockdev-mirror', - job_id='mirror', - device='source', - target='target', - filter_node_name='mirror-top', - sync='full', - on_target_error='stop') - self.assert_qmp(res, 'return', {}) + self.vm.cmd('blockdev-mirror', + job_id='mirror', + device='source', + target='target', + filter_node_name='mirror-top', + sync='full', + on_target_error='stop') def cancel_mirror_with_error(self) -> None: self.vm.event_wait('BLOCK_JOB_READY') @@ -107,8 +104,7 @@ class TestMirrorReadyCancelError(iotests.QMPTestCase): while self.vm.event_wait('JOB_STATUS_CHANGE', timeout=0.0) is not None: pass - res = self.vm.qmp('block-job-cancel', device='mirror') - self.assert_qmp(res, 'return', {}) + self.vm.cmd('block-job-cancel', device='mirror') self.vm.event_wait('BLOCK_JOB_ERROR') diff --git a/tests/qemu-iotests/tests/mirror-top-perms b/tests/qemu-iotests/tests/mirror-top-perms index 8bca592708..fab9907e92 100755 --- a/tests/qemu-iotests/tests/mirror-top-perms +++ b/tests/qemu-iotests/tests/mirror-top-perms @@ -78,12 +78,11 @@ class TestMirrorTopPerms(iotests.QMPTestCase): difficult to let some other qemu process open the image.) """ - result = self.vm.qmp('blockdev-mirror', - job_id='mirror', - device='drive0', - target='null', - sync='full') - self.assert_qmp(result, 'return', {}) + self.vm.cmd('blockdev-mirror', + job_id='mirror', + device='drive0', + target='null', + sync='full') self.vm.event_wait('BLOCK_JOB_READY') @@ -105,9 +104,8 @@ class TestMirrorTopPerms(iotests.QMPTestCase): except machine.VMLaunchFailure as exc: assert 'Is another process using the image' in exc.output - result = self.vm.qmp('block-job-cancel', - device='mirror') - self.assert_qmp(result, 'return', {}) + self.vm.cmd('block-job-cancel', + device='mirror') self.vm.event_wait('BLOCK_JOB_COMPLETED') diff --git a/tests/qemu-iotests/tests/nbd-multiconn b/tests/qemu-iotests/tests/nbd-multiconn index 7e686a786e..479e872f2a 100755 --- a/tests/qemu-iotests/tests/nbd-multiconn +++ b/tests/qemu-iotests/tests/nbd-multiconn @@ -48,12 +48,11 @@ class TestNbdMulticonn(iotests.QMPTestCase): self.vm = iotests.VM() self.vm.launch() - result = self.vm.qmp('blockdev-add', { + self.vm.cmd('blockdev-add', { 'driver': 'qcow2', 'node-name': 'n', 'file': {'driver': 'file', 'filename': disk} }) - self.assert_qmp(result, 'return', {}) def tearDown(self): self.vm.shutdown() @@ -74,12 +73,10 @@ class TestNbdMulticonn(iotests.QMPTestCase): if max_connections is not None: args['max-connections'] = max_connections - result = self.vm.qmp('nbd-server-start', args) - self.assert_qmp(result, 'return', {}) + self.vm.cmd('nbd-server-start', args) yield - result = self.vm.qmp('nbd-server-stop') - self.assert_qmp(result, 'return', {}) + self.vm.cmd('nbd-server-stop') def add_export(self, name, writable=None): args = { @@ -91,8 +88,7 @@ class TestNbdMulticonn(iotests.QMPTestCase): if writable is not None: args['writable'] = writable - result = self.vm.qmp('block-export-add', args) - self.assert_qmp(result, 'return', {}) + self.vm.cmd('block-export-add', args) def test_default_settings(self): with self.run_server(): diff --git a/tests/qemu-iotests/tests/reopen-file b/tests/qemu-iotests/tests/reopen-file index 8590a94d53..5a50794ffc 100755 --- a/tests/qemu-iotests/tests/reopen-file +++ b/tests/qemu-iotests/tests/reopen-file @@ -64,12 +64,11 @@ class TestReopenFile(QMPTestCase): self.fail('qemu-io pattern verification failed') def test_reopen_file(self) -> None: - result = self.vm.qmp('blockdev-reopen', options=[{ + self.vm.cmd('blockdev-reopen', options=[{ 'driver': imgfmt, 'node-name': 'format', 'file': 'raw' }]) - self.assert_qmp(result, 'return', {}) # Do some I/O to the image to see whether it still works # (Pattern verification will be checked by tearDown()) diff --git a/tests/qemu-iotests/tests/stream-error-on-reset b/tests/qemu-iotests/tests/stream-error-on-reset index 5a8c3a9e8d..b60aabb68e 100755 --- a/tests/qemu-iotests/tests/stream-error-on-reset +++ b/tests/qemu-iotests/tests/stream-error-on-reset @@ -115,8 +115,7 @@ class TestStreamErrorOnReset(QMPTestCase): # Launch a stream job, which will take at least a second to # complete, because the base image is throttled (so we can # get in between it having started and it having completed) - res = self.vm.qmp('block-stream', job_id='stream', device='top') - self.assert_qmp(res, 'return', {}) + self.vm.cmd('block-stream', job_id='stream', device='top') while True: ev = self.vm.event_wait('JOB_STATUS_CHANGE') @@ -125,8 +124,7 @@ class TestStreamErrorOnReset(QMPTestCase): # forces the virtio-scsi device to be reset, thus draining # the stream job, and making it complete. Completing # inside of that drain should not result in a segfault. - res = self.vm.qmp('system_reset') - self.assert_qmp(res, 'return', {}) + self.vm.cmd('system_reset') elif ev['data']['status'] == 'null': # The test is done once the job is gone break diff --git a/tests/qemu-iotests/tests/stream-under-throttle b/tests/qemu-iotests/tests/stream-under-throttle index c24dfbcaa2..1a50b682fc 100755 --- a/tests/qemu-iotests/tests/stream-under-throttle +++ b/tests/qemu-iotests/tests/stream-under-throttle @@ -102,10 +102,9 @@ class TestStreamWithThrottle(iotests.QMPTestCase): Do a simple stream beneath the two throttle nodes. Should complete with no problems. ''' - result = self.vm.qmp('block-stream', - job_id='stream', - device='unthrottled-node') - self.assert_qmp(result, 'return', {}) + self.vm.cmd('block-stream', + job_id='stream', + device='unthrottled-node') # Should succeed and not time out try: From 32f4916cfb569b6b3eb8a29e8aca586ab990920e Mon Sep 17 00:00:00 2001 From: Jiajie Chen Date: Sat, 30 Sep 2023 19:28:23 +0800 Subject: [PATCH 0660/1077] target/loongarch: fix ASXE flag conflict HW_FLAGS_EUEN_ASXE acccidentally conflicts with HW_FLAGS_CRMD_PG, enabling LASX instructions even when CSR_EUEN.ASXE=0. Closes: https://gitlab.com/qemu-project/qemu/-/issues/1907 Signed-off-by: Jiajie Chen Reviewed-by: Richard Henderson Reviewed-by: Song Gao Message-Id: <20230930112837.1871691-1-c@jia.je> Signed-off-by: Song Gao --- target/loongarch/cpu.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/target/loongarch/cpu.h b/target/loongarch/cpu.h index 40e70a8119..8b54cf109c 100644 --- a/target/loongarch/cpu.h +++ b/target/loongarch/cpu.h @@ -458,11 +458,11 @@ static inline void set_pc(CPULoongArchState *env, uint64_t value) * LoongArch CPUs hardware flags. */ #define HW_FLAGS_PLV_MASK R_CSR_CRMD_PLV_MASK /* 0x03 */ -#define HW_FLAGS_CRMD_PG R_CSR_CRMD_PG_MASK /* 0x10 */ #define HW_FLAGS_EUEN_FPE 0x04 #define HW_FLAGS_EUEN_SXE 0x08 -#define HW_FLAGS_EUEN_ASXE 0x10 +#define HW_FLAGS_CRMD_PG R_CSR_CRMD_PG_MASK /* 0x10 */ #define HW_FLAGS_VA32 0x20 +#define HW_FLAGS_EUEN_ASXE 0x40 static inline void cpu_get_tb_cpu_state(CPULoongArchState *env, vaddr *pc, uint64_t *cs_base, uint32_t *flags) From 5f1a3132c6281ed402f7d10190226fecd804c96e Mon Sep 17 00:00:00 2001 From: Song Gao Date: Tue, 5 Sep 2023 20:39:10 +0800 Subject: [PATCH 0661/1077] target/loongarch: Add preldx instruction MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Resolve the issue of starting the Loongnix 20.5[1] system failure. Logs: Loading Linux 4.19.0-19-loongson-3 ... Loading initial ramdisk ... PROGRESS CODE: V02010004 I0 PROGRESS CODE: V03101019 I0 Error: unknown opcode. 90000000003a3e6c: 0x382c6d82 [1] http://pkg.loongnix.cn/loongnix/isos/Loongnix-20.5/Loongnix-20.5.cartoon.gui.loongarch64.en.qcow2 Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Song Gao Message-Id: <20230905123910.3052023-1-gaosong@loongson.cn> --- target/loongarch/disas.c | 7 +++++++ target/loongarch/insn_trans/trans_memory.c.inc | 5 +++++ target/loongarch/insns.decode | 3 +++ 3 files changed, 15 insertions(+) diff --git a/target/loongarch/disas.c b/target/loongarch/disas.c index c8a29eac2b..2040f3e44d 100644 --- a/target/loongarch/disas.c +++ b/target/loongarch/disas.c @@ -190,6 +190,12 @@ static void output_hint_r_i(DisasContext *ctx, arg_hint_r_i *a, output(ctx, mnemonic, "%d, r%d, %d", a->hint, a->rj, a->imm); } +static void output_hint_rr(DisasContext *ctx, arg_hint_rr *a, + const char *mnemonic) +{ + output(ctx, mnemonic, "%d, r%d, r%d", a->hint, a->rj, a->rk); +} + static void output_i(DisasContext *ctx, arg_i *a, const char *mnemonic) { output(ctx, mnemonic, "%d", a->imm); @@ -549,6 +555,7 @@ INSN(ld_bu, rr_i) INSN(ld_hu, rr_i) INSN(ld_wu, rr_i) INSN(preld, hint_r_i) +INSN(preldx, hint_rr) INSN(fld_s, fr_i) INSN(fst_s, fr_i) INSN(fld_d, fr_i) diff --git a/target/loongarch/insn_trans/trans_memory.c.inc b/target/loongarch/insn_trans/trans_memory.c.inc index c3de1404ea..42f4e74012 100644 --- a/target/loongarch/insn_trans/trans_memory.c.inc +++ b/target/loongarch/insn_trans/trans_memory.c.inc @@ -110,6 +110,11 @@ static bool trans_preld(DisasContext *ctx, arg_preld *a) return true; } +static bool trans_preldx(DisasContext *ctx, arg_preldx * a) +{ + return true; +} + static bool trans_dbar(DisasContext *ctx, arg_dbar * a) { tcg_gen_mb(TCG_BAR_SC | TCG_MO_ALL); diff --git a/target/loongarch/insns.decode b/target/loongarch/insns.decode index 64b308f9fb..62f58cc541 100644 --- a/target/loongarch/insns.decode +++ b/target/loongarch/insns.decode @@ -24,6 +24,7 @@ &rrr rd rj rk &rr_i rd rj imm &hint_r_i hint rj imm +&hint_rr hint rj rk &rrr_sa rd rj rk sa &rr_ms_ls rd rj ms ls &ff fd fj @@ -69,6 +70,7 @@ @rr_i16 .... .. imm:s16 rj:5 rd:5 &rr_i @rr_i16s2 .... .. ................ rj:5 rd:5 &rr_i imm=%offs16 @hint_r_i12 .... ...... imm:s12 rj:5 hint:5 &hint_r_i +@hint_rr .... ........ ..... rk:5 rj:5 hint:5 &hint_rr @rrr_sa2p1 .... ........ ... .. rk:5 rj:5 rd:5 &rrr_sa sa=%sa2p1 @rrr_sa2 .... ........ ... sa:2 rk:5 rj:5 rd:5 &rrr_sa @rrr_sa3 .... ........ .. sa:3 rk:5 rj:5 rd:5 &rrr_sa @@ -228,6 +230,7 @@ ldx_bu 0011 10000010 00000 ..... ..... ..... @rrr ldx_hu 0011 10000010 01000 ..... ..... ..... @rrr ldx_wu 0011 10000010 10000 ..... ..... ..... @rrr preld 0010 101011 ............ ..... ..... @hint_r_i12 +preldx 0011 10000010 11000 ..... ..... ..... @hint_rr dbar 0011 10000111 00100 ............... @i15 ibar 0011 10000111 00101 ............... @i15 ldptr_w 0010 0100 .............. ..... ..... @rr_i14s2 From 2cfdab739a18fcff36f10d42f796dcb35027c92f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20Wei=C3=9Fschuh?= Date: Tue, 10 Oct 2023 11:49:16 +0200 Subject: [PATCH 0662/1077] hw/loongarch: remove global loaderparams variable MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Passing the struct around explicitly makes the control-flow more obvious. Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Song Gao Signed-off-by: Thomas Weißschuh Message-Id: <20231010-loongarch-loader-params-v2-1-512cc7959683@t-8ch.de> Signed-off-by: Song Gao --- hw/loongarch/virt.c | 50 ++++++++++++++++++++++++--------------------- 1 file changed, 27 insertions(+), 23 deletions(-) diff --git a/hw/loongarch/virt.c b/hw/loongarch/virt.c index b0a004f860..c6f64e941b 100644 --- a/hw/loongarch/virt.c +++ b/hw/loongarch/virt.c @@ -47,6 +47,13 @@ #include "qemu/error-report.h" +struct loaderparams { + uint64_t ram_size; + const char *kernel_filename; + const char *kernel_cmdline; + const char *initrd_filename; +}; + static void virt_flash_create(LoongArchMachineState *lams) { DeviceState *dev = qdev_new(TYPE_PFLASH_CFI01); @@ -411,24 +418,17 @@ static const MemoryRegionOps loongarch_virt_pm_ops = { } }; -static struct _loaderparams { - uint64_t ram_size; - const char *kernel_filename; - const char *kernel_cmdline; - const char *initrd_filename; -} loaderparams; - static uint64_t cpu_loongarch_virt_to_phys(void *opaque, uint64_t addr) { return addr & MAKE_64BIT_MASK(0, TARGET_PHYS_ADDR_SPACE_BITS); } -static int64_t load_kernel_info(void) +static int64_t load_kernel_info(const struct loaderparams *loaderparams) { uint64_t kernel_entry, kernel_low, kernel_high; ssize_t kernel_size; - kernel_size = load_elf(loaderparams.kernel_filename, NULL, + kernel_size = load_elf(loaderparams->kernel_filename, NULL, cpu_loongarch_virt_to_phys, NULL, &kernel_entry, &kernel_low, &kernel_high, NULL, 0, @@ -436,7 +436,7 @@ static int64_t load_kernel_info(void) if (kernel_size < 0) { error_report("could not load kernel '%s': %s", - loaderparams.kernel_filename, + loaderparams->kernel_filename, load_elf_strerror(kernel_size)); exit(1); } @@ -728,7 +728,8 @@ static void reset_load_elf(void *opaque) } } -static void fw_cfg_add_kernel_info(FWCfgState *fw_cfg) +static void fw_cfg_add_kernel_info(const struct loaderparams *loaderparams, + FWCfgState *fw_cfg) { /* * Expose the kernel, the command line, and the initrd in fw_cfg. @@ -737,36 +738,38 @@ static void fw_cfg_add_kernel_info(FWCfgState *fw_cfg) */ load_image_to_fw_cfg(fw_cfg, FW_CFG_KERNEL_SIZE, FW_CFG_KERNEL_DATA, - loaderparams.kernel_filename, + loaderparams->kernel_filename, false); - if (loaderparams.initrd_filename) { + if (loaderparams->initrd_filename) { load_image_to_fw_cfg(fw_cfg, FW_CFG_INITRD_SIZE, FW_CFG_INITRD_DATA, - loaderparams.initrd_filename, false); + loaderparams->initrd_filename, false); } - if (loaderparams.kernel_cmdline) { + if (loaderparams->kernel_cmdline) { fw_cfg_add_i32(fw_cfg, FW_CFG_CMDLINE_SIZE, - strlen(loaderparams.kernel_cmdline) + 1); + strlen(loaderparams->kernel_cmdline) + 1); fw_cfg_add_string(fw_cfg, FW_CFG_CMDLINE_DATA, - loaderparams.kernel_cmdline); + loaderparams->kernel_cmdline); } } -static void loongarch_firmware_boot(LoongArchMachineState *lams) +static void loongarch_firmware_boot(LoongArchMachineState *lams, + const struct loaderparams *loaderparams) { - fw_cfg_add_kernel_info(lams->fw_cfg); + fw_cfg_add_kernel_info(loaderparams, lams->fw_cfg); } -static void loongarch_direct_kernel_boot(LoongArchMachineState *lams) +static void loongarch_direct_kernel_boot(LoongArchMachineState *lams, + const struct loaderparams *loaderparams) { MachineState *machine = MACHINE(lams); int64_t kernel_addr = 0; LoongArchCPU *lacpu; int i; - kernel_addr = load_kernel_info(); + kernel_addr = load_kernel_info(loaderparams); if (!machine->firmware) { for (i = 0; i < machine->smp.cpus; i++) { lacpu = LOONGARCH_CPU(qemu_get_cpu(i)); @@ -793,6 +796,7 @@ static void loongarch_init(MachineState *machine) MachineClass *mc = MACHINE_GET_CLASS(machine); CPUState *cpu; char *ramName = NULL; + struct loaderparams loaderparams = { }; if (!cpu_model) { cpu_model = LOONGARCH_CPU_TYPE_NAME("la464"); @@ -898,9 +902,9 @@ static void loongarch_init(MachineState *machine) /* load the kernel. */ if (loaderparams.kernel_filename) { if (lams->bios_loaded) { - loongarch_firmware_boot(lams); + loongarch_firmware_boot(lams, &loaderparams); } else { - loongarch_direct_kernel_boot(lams); + loongarch_direct_kernel_boot(lams, &loaderparams); } } fdt_add_flash_node(lams); From cb041aed1b5befaaa563aaf75e094412b2063fec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Tue, 10 Oct 2023 15:53:41 +0200 Subject: [PATCH 0663/1077] hw/loongarch/virt: Remove unused ISA UART MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The LoongArch 'virt' machine doesn't use any ISA UART. No need to build the device model, remove its Kconfig entry. Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Song Gao Message-Id: <20231010135342.40219-2-philmd@linaro.org> Signed-off-by: Song Gao --- hw/loongarch/Kconfig | 1 - 1 file changed, 1 deletion(-) diff --git a/hw/loongarch/Kconfig b/hw/loongarch/Kconfig index 1e7c5b43c5..fcd5f2b4b6 100644 --- a/hw/loongarch/Kconfig +++ b/hw/loongarch/Kconfig @@ -7,7 +7,6 @@ config LOONGARCH_VIRT imply NVDIMM select ISA_BUS select SERIAL - select SERIAL_ISA select VIRTIO_PCI select PLATFORM_BUS select LOONGARCH_IPI From 3866e2f98ef4f9b84d920af31a98c4c642ff8d77 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Tue, 10 Oct 2023 15:53:42 +0200 Subject: [PATCH 0664/1077] hw/loongarch/virt: Remove unused ISA Bus MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The LoongArch 'virt' machine doesn't use its ISA I/O region. If a ISA device were to be mapped there, there is no support for ISA IRQ. Unlikely useful. Simply remove. Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Song Gao Message-Id: <20231010135342.40219-3-philmd@linaro.org> Signed-off-by: Song Gao --- hw/loongarch/Kconfig | 1 - hw/loongarch/virt.c | 5 ----- include/hw/loongarch/virt.h | 3 --- 3 files changed, 9 deletions(-) diff --git a/hw/loongarch/Kconfig b/hw/loongarch/Kconfig index fcd5f2b4b6..5727efed6d 100644 --- a/hw/loongarch/Kconfig +++ b/hw/loongarch/Kconfig @@ -5,7 +5,6 @@ config LOONGARCH_VIRT imply VIRTIO_VGA imply PCI_DEVICES imply NVDIMM - select ISA_BUS select SERIAL select VIRTIO_PCI select PLATFORM_BUS diff --git a/hw/loongarch/virt.c b/hw/loongarch/virt.c index c6f64e941b..c1791f80dd 100644 --- a/hw/loongarch/virt.c +++ b/hw/loongarch/virt.c @@ -878,11 +878,6 @@ static void loongarch_init(MachineState *machine) machine_memory_devices_init(machine, device_mem_base, device_mem_size); } - /* Add isa io region */ - memory_region_init_alias(&lams->isa_io, NULL, "isa-io", - get_system_io(), 0, VIRT_ISA_IO_SIZE); - memory_region_add_subregion(address_space_mem, VIRT_ISA_IO_BASE, - &lams->isa_io); /* load the BIOS image. */ loongarch_firmware_init(lams); diff --git a/include/hw/loongarch/virt.h b/include/hw/loongarch/virt.h index f1659655c6..674f4655e0 100644 --- a/include/hw/loongarch/virt.h +++ b/include/hw/loongarch/virt.h @@ -16,8 +16,6 @@ #define LOONGARCH_MAX_CPUS 256 -#define VIRT_ISA_IO_BASE 0x18000000UL -#define VIRT_ISA_IO_SIZE 0x0004000 #define VIRT_FWCFG_BASE 0x1e020000UL #define VIRT_BIOS_BASE 0x1c000000UL #define VIRT_BIOS_SIZE (4 * MiB) @@ -38,7 +36,6 @@ struct LoongArchMachineState { MemoryRegion lowmem; MemoryRegion highmem; - MemoryRegion isa_io; MemoryRegion bios; bool bios_loaded; /* State for other subsystems/APIs: */ From 89daabe385a58f52ee902c203bb9560f8c914e8f Mon Sep 17 00:00:00 2001 From: Song Gao Date: Thu, 12 Oct 2023 14:41:23 +0800 Subject: [PATCH 0665/1077] hw/loongarch/virt: Remove unused 'loongarch_virt_pm' region MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The system test shutdown uses the 'loongarch_virt_pm' region. We can use the write AcpiFadtData.sleep_clt register to realize the shutdown. Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Song Gao Message-ID: <20231012072351.1409344-1-gaosong@loongson.cn> Signed-off-by: Song Gao --- hw/loongarch/virt.c | 48 +---------------------------- tests/tcg/loongarch64/system/boot.S | 7 +++-- 2 files changed, 5 insertions(+), 50 deletions(-) diff --git a/hw/loongarch/virt.c b/hw/loongarch/virt.c index c1791f80dd..2952fe452e 100644 --- a/hw/loongarch/virt.c +++ b/hw/loongarch/virt.c @@ -308,10 +308,6 @@ static void fdt_add_memory_node(MachineState *ms, g_free(nodename); } -#define PM_BASE 0x10080000 -#define PM_SIZE 0x100 -#define PM_CTRL 0x10 - static void virt_build_smbios(LoongArchMachineState *lams) { MachineState *ms = MACHINE(lams); @@ -380,44 +376,6 @@ static void memmap_add_entry(uint64_t address, uint64_t length, uint32_t type) memmap_entries++; } -/* - * This is a placeholder for missing ACPI, - * and will eventually be replaced. - */ -static uint64_t loongarch_virt_pm_read(void *opaque, hwaddr addr, unsigned size) -{ - return 0; -} - -static void loongarch_virt_pm_write(void *opaque, hwaddr addr, - uint64_t val, unsigned size) -{ - if (addr != PM_CTRL) { - return; - } - - switch (val) { - case 0x00: - qemu_system_reset_request(SHUTDOWN_CAUSE_GUEST_RESET); - return; - case 0xff: - qemu_system_shutdown_request(SHUTDOWN_CAUSE_GUEST_SHUTDOWN); - return; - default: - return; - } -} - -static const MemoryRegionOps loongarch_virt_pm_ops = { - .read = loongarch_virt_pm_read, - .write = loongarch_virt_pm_write, - .endianness = DEVICE_NATIVE_ENDIAN, - .valid = { - .min_access_size = 1, - .max_access_size = 1 - } -}; - static uint64_t cpu_loongarch_virt_to_phys(void *opaque, uint64_t addr) { return addr & MAKE_64BIT_MASK(0, TARGET_PHYS_ADDR_SPACE_BITS); @@ -500,7 +458,7 @@ static void loongarch_devices_init(DeviceState *pch_pic, LoongArchMachineState * SysBusDevice *d; PCIBus *pci_bus; MemoryRegion *ecam_alias, *ecam_reg, *pio_alias, *pio_reg; - MemoryRegion *mmio_alias, *mmio_reg, *pm_mem; + MemoryRegion *mmio_alias, *mmio_reg; int i; gpex_dev = qdev_new(TYPE_GPEX_HOST); @@ -560,10 +518,6 @@ static void loongarch_devices_init(DeviceState *pch_pic, LoongArchMachineState * VIRT_RTC_IRQ - VIRT_GSI_BASE)); fdt_add_rtc_node(lams); - pm_mem = g_new(MemoryRegion, 1); - memory_region_init_io(pm_mem, NULL, &loongarch_virt_pm_ops, - NULL, "loongarch_virt_pm", PM_SIZE); - memory_region_add_subregion(get_system_memory(), PM_BASE, pm_mem); /* acpi ged */ lams->acpi_ged = create_acpi_ged(pch_pic, lams); /* platform bus */ diff --git a/tests/tcg/loongarch64/system/boot.S b/tests/tcg/loongarch64/system/boot.S index 67eb1c04ce..37a81bafe7 100644 --- a/tests/tcg/loongarch64/system/boot.S +++ b/tests/tcg/loongarch64/system/boot.S @@ -21,9 +21,10 @@ _start: .align 16 _exit: 2: /* QEMU ACPI poweroff */ - li.w t0, 0xff - li.w t1, 0x10080010 - st.w t0, t1, 0 + li.w t0, 0x34 + li.w t1, 0x100e001c + st.b t0, t1, 0 + idle 0 bl 2b From 1bea6930ca7b9587ea8d8fbb77069b6a13aa031a Mon Sep 17 00:00:00 2001 From: Xiaojuan Yang Date: Thu, 12 Oct 2023 17:51:35 +0800 Subject: [PATCH 0666/1077] LoongArch: step down as general arch maintainer I haven't really been working on LoongArch for some time now, so let's remove myself from this entry. Signed-off-by: Xiaojuan Yang Acked-by: Song Gao Message-Id: <20231012095135.1423071-1-yangxiaojuan@loongson.cn> Signed-off-by: Song Gao --- MAINTAINERS | 2 -- 1 file changed, 2 deletions(-) diff --git a/MAINTAINERS b/MAINTAINERS index ceea4c2bf2..fdbef227ac 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -248,7 +248,6 @@ F: disas/hppa.c LoongArch TCG CPUs M: Song Gao -M: Xiaojuan Yang S: Maintained F: target/loongarch/ F: tests/tcg/loongarch64/ @@ -1191,7 +1190,6 @@ F: pc-bios/hppa-firmware.img LoongArch Machines ------------------ Virt -M: Xiaojuan Yang M: Song Gao S: Maintained F: docs/system/loongarch/virt.rst From 97970dae534226f045ff08c77bdb8a25e19fa023 Mon Sep 17 00:00:00 2001 From: Jeuk Kim Date: Mon, 18 Sep 2023 10:02:36 +0900 Subject: [PATCH 0667/1077] hw/ufs: Fix code coverity issues Fixed four ufs-related coverity issues. The coverity issues and fixes are as follows 1. CID 1519042: Security issue with the rand() function Changed to use a fixed value (0xab) instead of rand() as the value for testing 2. CID 1519043: Dereference after null check Removed useless (redundant) null checks 3. CID 1519050: Out-of-bounds access issue Fix to pass an array type variable to find_first_bit and find_next_bit using DECLARE_BITMAP() 4. CID 1519051: Out-of-bounds read issue Fix incorrect range check for lun Fix coverity CID: 1519042 1519043 1519050 1519051 Signed-off-by: Jeuk Kim --- hw/ufs/lu.c | 16 +++++++--------- hw/ufs/ufs.c | 10 +++++----- tests/qtest/ufs-test.c | 2 +- 3 files changed, 13 insertions(+), 15 deletions(-) diff --git a/hw/ufs/lu.c b/hw/ufs/lu.c index e1c46bddb1..13b5e37b53 100644 --- a/hw/ufs/lu.c +++ b/hw/ufs/lu.c @@ -1345,13 +1345,12 @@ static void ufs_lu_realize(SCSIDevice *dev, Error **errp) return; } - if (lu->qdev.conf.blk) { - ctx = blk_get_aio_context(lu->qdev.conf.blk); - aio_context_acquire(ctx); - if (!blkconf_blocksizes(&lu->qdev.conf, errp)) { - goto out; - } + ctx = blk_get_aio_context(lu->qdev.conf.blk); + aio_context_acquire(ctx); + if (!blkconf_blocksizes(&lu->qdev.conf, errp)) { + goto out; } + lu->qdev.blocksize = UFS_BLOCK_SIZE; blk_get_geometry(lu->qdev.conf.blk, &nb_sectors); nb_blocks = nb_sectors / (lu->qdev.blocksize / BDRV_SECTOR_SIZE); @@ -1367,10 +1366,9 @@ static void ufs_lu_realize(SCSIDevice *dev, Error **errp) } ufs_lu_brdv_init(lu, errp); + out: - if (ctx) { - aio_context_release(ctx); - } + aio_context_release(ctx); } static void ufs_lu_unrealize(SCSIDevice *dev) diff --git a/hw/ufs/ufs.c b/hw/ufs/ufs.c index 0ecedb9aed..2e6d582cc3 100644 --- a/hw/ufs/ufs.c +++ b/hw/ufs/ufs.c @@ -258,7 +258,7 @@ static void ufs_irq_check(UfsHc *u) static void ufs_process_db(UfsHc *u, uint32_t val) { - unsigned long doorbell; + DECLARE_BITMAP(doorbell, UFS_MAX_NUTRS); uint32_t slot; uint32_t nutrs = u->params.nutrs; UfsRequest *req; @@ -268,8 +268,8 @@ static void ufs_process_db(UfsHc *u, uint32_t val) return; } - doorbell = val; - slot = find_first_bit(&doorbell, nutrs); + doorbell[0] = val; + slot = find_first_bit(doorbell, nutrs); while (slot < nutrs) { req = &u->req_list[slot]; @@ -285,7 +285,7 @@ static void ufs_process_db(UfsHc *u, uint32_t val) trace_ufs_process_db(slot); req->state = UFS_REQUEST_READY; - slot = find_next_bit(&doorbell, nutrs, slot + 1); + slot = find_next_bit(doorbell, nutrs, slot + 1); } qemu_bh_schedule(u->doorbell_bh); @@ -838,7 +838,7 @@ static QueryRespCode ufs_read_unit_desc(UfsRequest *req) uint8_t lun = req->req_upiu.qr.index; if (lun != UFS_UPIU_RPMB_WLUN && - (lun > UFS_MAX_LUS || u->lus[lun] == NULL)) { + (lun >= UFS_MAX_LUS || u->lus[lun] == NULL)) { trace_ufs_err_query_invalid_index(req->req_upiu.qr.opcode, lun); return UFS_QUERY_RESULT_INVALID_INDEX; } diff --git a/tests/qtest/ufs-test.c b/tests/qtest/ufs-test.c index ed3dbca154..15d467630c 100644 --- a/tests/qtest/ufs-test.c +++ b/tests/qtest/ufs-test.c @@ -497,7 +497,7 @@ static void ufstest_read_write(void *obj, void *data, QGuestAllocator *alloc) g_assert_cmpuint(block_size, ==, 4096); /* Write data */ - memset(write_buf, rand() % 255 + 1, block_size); + memset(write_buf, 0xab, block_size); ufs_send_scsi_command(ufs, 0, 1, write_cdb, write_buf, block_size, NULL, 0, &utrd, &rsp_upiu); g_assert_cmpuint(le32_to_cpu(utrd.header.dword_2), ==, UFS_OCS_SUCCESS); From ebca80bbdb5c1650e4b753a3d13b43634e7dfe05 Mon Sep 17 00:00:00 2001 From: Jeuk Kim Date: Tue, 10 Oct 2023 14:11:13 +0900 Subject: [PATCH 0668/1077] hw/ufs: Fix incorrect register fields This patch fixes invalid ufs register fields. This fixes an issue reported by Bin Meng that caused ufs to fail over riscv. Fixes: bc4e68d362ec ("hw/ufs: Initial commit for emulated Universal-Flash-Storage") Signed-off-by: Jeuk Kim Reported-by: Bin Meng Reviewed-by: Bin Meng Tested-by: Bin Meng --- include/block/ufs.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/block/ufs.h b/include/block/ufs.h index fd884eb8ce..7631a5af10 100644 --- a/include/block/ufs.h +++ b/include/block/ufs.h @@ -111,14 +111,14 @@ REG32(UECT, offsetof(UfsReg, uect)) REG32(UECDME, offsetof(UfsReg, uecdme)) REG32(UTRIACR, offsetof(UfsReg, utriacr)) REG32(UTRLBA, offsetof(UfsReg, utrlba)) - FIELD(UTRLBA, UTRLBA, 9, 22) + FIELD(UTRLBA, UTRLBA, 10, 22) REG32(UTRLBAU, offsetof(UfsReg, utrlbau)) REG32(UTRLDBR, offsetof(UfsReg, utrldbr)) REG32(UTRLCLR, offsetof(UfsReg, utrlclr)) REG32(UTRLRSR, offsetof(UfsReg, utrlrsr)) REG32(UTRLCNR, offsetof(UfsReg, utrlcnr)) REG32(UTMRLBA, offsetof(UfsReg, utmrlba)) - FIELD(UTMRLBA, UTMRLBA, 9, 22) + FIELD(UTMRLBA, UTMRLBA, 10, 22) REG32(UTMRLBAU, offsetof(UfsReg, utmrlbau)) REG32(UTMRLDBR, offsetof(UfsReg, utmrldbr)) REG32(UTMRLCLR, offsetof(UfsReg, utmrlclr)) From ce32a9e9912fd091d5ca7d604ae367b9d705eb87 Mon Sep 17 00:00:00 2001 From: Helge Deller Date: Sat, 14 Oct 2023 18:59:38 +0200 Subject: [PATCH 0669/1077] target/hppa: Update to SeaBIOS-hppa version 10 Enhancements: - Initial support for 64-bit CPUs with Astro/Elroy (e.g. C3700 workstation) - USB support (OHCI) - better PCI support - esp-scsi fixes from Mark Cave-Ayland Signed-off-by: Helge Deller --- pc-bios/hppa-firmware.img | Bin 732376 -> 755480 bytes roms/seabios-hppa | 2 +- 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/pc-bios/hppa-firmware.img b/pc-bios/hppa-firmware.img index c7196143b180af6e02d1d93591f2684e82f3fb0d..e976c0cc933214ef3d6f420c5936f6972ae8c343 100644 GIT binary patch literal 755480 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

2QrS%1K;LEDdUmZBX9V&FR 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
;1(DP8jAiwd5M~{5pr~%@{nda2l$nbu2kEJ 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%0DB+@E|dN!@G$4xhwe2r0ns?=+E6<5BuPDh zr_Iv{rjYBVkhoBQ4>39i+xdm`hw4SYkn1|?Efsf5A)`qinP14UpeZCJ6et-(A#eGG zjECwCuMlWdNXjjROedM)<#9N1a;&t)DHp#y104$7hN(RGrC$(JV(UWAywoHpP*5)2 zEropm30+Upkye&-d=lCJWIQ!PG@$0y3Qq8%2#)TfH&-)wW&S}Rm*p78_y58`-_OIKV}-K-q0w|%EgW_zrF|sy3_H8(-7nh z?dZ{Mz*Z{HWiNsQQ>c$65xb$WEP0-Ji??s3dD3xYwwc6u3`mFb1G_VauY1z*@fqm8 z^`rwjc4zp7u0T3I&V%HVd8YZ;JOn^OmToz@oy5R=(ry4e_hTKc=5_K>lGVv%Wddjx*)eM+N?8KpAkR(U0f%m4UhbYdGm+= z-c&<9+@qd)3pHC7hFTqAnqZzqSJ~4gwUlGpk5CJ@!lOQE+JC?1%5XP@X=uv%&7>?- z3OZbQGTm~Hn(u;m)J!{-ee@1dLq}ibUbmcY#}e02x|nEhf#nabW*K+C)6CvQwYchh zDSBBb(2#j#_Ii)b!E1N`N2XyFnOVGox&1?d#zB(h;>gxEF_Aj1H|>5(dSQQ^(me2S zDB$3&9KDC1V@VVwoA03JkKRK>7Su`9*>ad`_X_*&k!)#kX6ey;sABoHP@uF@__CkX z@!e3s9OfwUC~Q@vAbTs3Hnl^6=;D@rDVsFaj_RXgWysoFVjs+Lbr-Oev^05Ggne&p?t z!)pY*9=YyS&RJza)PVxTHC_zR#(fKS~cWsVT`I|Qrht*6eK3L zuzaeLNo0H}BGsr?J|F$e(Wz-tPrmBvI-yo)#_QLRv%(BCHzE*p_bac*Cq3)tS%Cwi zZ`1Q9=XA(ft&YIZZHoc!0D1UK$kA;u`7hg2fOxAV>!5E!&UCL(Y%7nW%QyVum8x!w zrq@tgA$|z>H%M_eofY)yULZyTLqWD*0J0gG>9%d}0So$cX9*Z`W|!eLZiO&Yee`Yj zkh7=~G|5gzG?QXvyhNM2;xz%>RRn7S-T=&GS30|eCY|S^yxXDX@~CZ=1S5NSsXa_; zG?UFuZLEnja6FVRg#8!!A~LkPj9G)W1H+q4fR*8YpMtAKVwt|V|M_^Vo;at2U*h{ z)KB=c?Rs>tC!c`wrr15jvOXS&`7mp*A^VWuL+P|~je6*0nA<~#Ocn6|FwoiS zp+j_n#Qu{pz_6Nb{f9cLeh^E6g%w;rat$9KvVpxIksv;U;LEioOp};h?Je{wKcOA zw~CD`IUH|O_UgpD41wLybNU#Y;rN)RyOEHov2kxq_cL>H_h@Zivp8z?~u-!rjFCBihc zpFv}pWh;@?A|bn<=`tb*%7pBJ>Z%Q4+D;4E!^*2p zQVu7E?BRZ7VE2$c*=R`S;>m3!tK<5(9VeOT-!Ej3k$Kn<_WTorDd!~Sr0A(Ho$(vq{09Ep2C6ig2`K6Eu(Ct3*8pxkPsx_580oq>LvbINp zoEa6e@4y~vLtuMNpgKsDl}q|xu#On+-WAIATE1IIo%B(fMRm#P;HUyz(O6(s%d3f59`K6w9ghpP}V`$>S-fhf4mo4JFfvPiUi$`x4wy27gGV2HJAIsi#pHV3f;{i>^R?)7l$4=!O<@ z_0~5JNu3NbbVG3#q|3hHqXfDNA;mP5u{StY0p4r9t)ZPg9R7cP-mV_*ec=YWd2ugH z-j9VtDpcNJ4|h;FuMSU#esfkhS0N6a=+SZbonHqlM3wg~Z^6p1W2uMZf$aP`SdF8=;TxfKjHL92AIR}rJdnB_V z|Ds-KxL?%=kgrDZjG|2IQOh~g&Rnwy_3)JN&W|C$b2j%XMs?8AonMaQLw!*a-)U=H z_bPT~0eifA6%ep;H)OZmt02z33J;rqufmOc_bPUxwssz*bVsQOpf9utLB#_cxWUl`OH3P z;hSW+0Gw03TmRR-q}i(X_a$lH$m3r75dCNErfOb4(;FjCvu#t9f^`aDzSCii)HFu? z&qfJlTn&%*hCAoaRwqI7J(%jf`EwR`0iVJ2gqc1f3C{QWQMzt&$xsJh*A-$YjI}+x z!_}f4VqD#{^G}-f3!4ktavD;|Sfh_achg~Km(gAv+(=wunt*@X8?9FY`fycjg>zlqiMfc=@c;5n4I2zG4%#lg{t}-e*Zc3 z_IN#1HAEG<$US0dsHzSZ6sDr8H9gLIJQ%8)4Bow~8mg`-y5XPGajA~znZ7)FW7d$( z(GV9>onva=1)QVDx~DoPDVFsmN&o7TYL?DFgr0JD8iGf{o_?{PmFkEkXc}17%I8zP z1uZu-;^hGnuWpthsTi`pscTI;NPL_;<4dKkrTfekh}3mPheU;Uvr;#(w|@V-tcE!? zt(iJm=Pf^cfCKl#NcgS$Sn50QM&}AM5zH6$Qs=oX5N4r^S>j^ULUOFU&E$|HuzFi+ zZRXAC@|RTqVCxa9dlfr1EOjerQgF9b?*& zXMNR}aonnrzIX#qZ+;j_RZQvDt}YC9r<(mNQ1x{rN^~qR8oILcK$2A+;jT@<8jxAa z+!|zW5J=Fj(~-L646>7uW&s{y*PzF$77Ao!SrnMiDZ;LaGOw-gIhhqig#RFbwHu|n z>o15_)QGU_V1+N<2xN@0L45cuh?9Lc66Wa{Xx|C zl=|)mENl0D$nS<{BJ5NjIS}NFl+~wognf4mkA=Ju$auqss^9bodx+V7fno|U2?c)w zJ8E^Xob%H?ie@FWQ9|lGfOqIvC)T)|kmt#FKa`okX^x&mV`Kh}sc6gbrc@ ztgHc+GAhpHlco%g5==?-bI%eeh|9l2@B?sGkxK-A1@f@5R|*F*E?czZLS!oG+1==~U@ zTF@AK@M`xwq(~eA#(7U4)z-|d?PQu;+m9vkYs0qXx9%jK*Db9RdnkIb_hY)(W?$R6 zyFMqFKYE$yk6leNLriyNM5@3B>dg~D(%BpQae$X@kmbBgQwhw?xQbucC)*&`!`WQ<2#Pc74zj_>4M8xv0x6GS+<>t0svf-#r$u zNTrd+4k}PWNnhy2UBgY4C{O2S_7*QD89o?q$p_4tLgnh4LOJB|y~UGwpC+-FpSZ@Y z(d5kX636+82X09`VVUpaUR+`7G99VXyWzojO+1zB&asQK?*$wEeMIs9Imb?&(Xo&+ zxtrA(FAH_ZtBBAcNT|hgA%47)iAP#p*`azo!Y+-jHg4@teNZsFR)eV}{Yb>=Or!zH z+9Q3vTZDZZQ?$;*W?v`5E^9PRn5zNHDYC(0ozrPrgm#{FZ}ZC_ESR@DT{?r6rR-Bk ztR5`dGXux~N2!|Ybsi?34Qw}8ts>a)FsgUYZ{RMY@nPjVw+d@7>U8gI;3^J_Fi#R~ zAf5`Oa8WPf3`&)&k-F_1akdhhzQvu4=w8^lh;wDUjZv~LZ5nYY+Hx+T#P>D_nt68j z%kIYGTesAHVSrR@2wn6QtzZe@Tw3V0wV0gWQ>==eOXt1h@CdsYSNktz;KE$`1D}%b zdsurhMSK6H2t4f_2@JM)>6P_WyeHfPDF=D`66b4=GID=T188td-CJ9i}HeiV(-f$D7Jh>V;!=Nz!;g_8Xu7BG@|+9$d4B!#1BvIeMveyZSkxTAuc z<6Z^*Re`xTcWVVX*Z)xg%K+Uw&*>qR&MyvQ#Ow$nzfp;b#`j4T0^GT2LL z=4E&x-t^U2t+PM{iVvu3dM~GIKBm-IOH+PRC}ON9KqWg+y?Lnk@|({~fW}74xwN0v zMcw{R#Pf!Z`cLY@TEz24ypYw(HzS^}tt~LZ14l$We<#JX#n6X$3wGrP|*N@}ZkaK;F2zEiK zL^(T{oNbLC?B;CSMrb#u?%>vHr<}FkAZPZS5$^RvV~3TE9MS;9}$;d z#cD$s=eHN;;#!b@wVSDyn~5rFS0-nXdT< zUHsm~#N#HX<@_=l>cImNkK?(f==r^osfnlXwNloEKh?)d{DIb<(G~Uf3lgOolhzPU z+mLwP58rV!@q!<2R4egEKiqG6;zee5$s)KR`|Lzp&lSAhB+-s4%QG+wjB!Y`OF_Z( zzT2{5ZcofK9OYRTm`2uhX_sqV&CTA#OwX;$T8QXQ!yW_=Bxb^+Y(&-%fNt^b?3}m* zC+u2R`W_9DT@l>;u*6+H4nDFU^b~lpl171NK~i>JqIWyl%0|Sq`x(WP__@oOl|35V zNERellWBNDZsJb&J|^1W+Eeh#Jp|SSGZQ&1b*`RcqF&of2BuiHo*KQjioiTT-z2yO z_u0#UrHV`=upW?ycjk)^VLv6V)GF}WUSy83 zSs6pPt1Evi8%zEOBWSA_mn5BtB4~Q2sR<)!t9?9zw%Xv$gPn-{YJfuO|b_c}6CiI1DJILrE!5zGFCqBc%R?Cwd&r|rSF?lqvNmH13J+)hP-Ly_Az z(Ok@JOKMM`n=2eIc*61NWN@S0OS_3nwO=;p*ThA6)^gp_3ME<2uYD*4q3O=F)LGxB zr-0*nq^%iOMVFbKFn*cJi7#Nhem%`tHhUkM>%gyy%)ypY+h@AY)hvSm(*Ic%MP4P4 z1SBxx%eq>D=FyCsyJD!TyB=I|QvU~|wZY`pw^XvTY$^3sN*v5u;Ws|yW9s{?H3hZw z>wADmC%?YFL|*Xg8%<=m>dW-%<6U=hI<+n;sIiKSrKxdwAx)1^)5Mo)-EWAxTiaBM z$?$7iON7^QxUJhpWUF6W4v}nXTORk{wG~v5ZYt=Q_$C!xFYQ?T`>=d;hBIFI-=&>11A^MR@I^1b2@B@Z zi<#TrYAId2bIaOUfp^kKK1J?Z<|w;o%Z$}l5sTd#elMC|gA@E)Lr4`O#3kACFLBEP z#?>K)jRGQB==G5aYZzCpuYb=B%6uefFYQljC!-TA8dfkKx zh9%U?ANAphx+gGKjOw872~E5(yuKYPUXAKVcpJ6k?Gq(TLK*zwKR4W_r7;n?R9kjl z!hDw@RLv z`-5IP_Op|<-{>)v{eF6GKRsuZ{r*-&(rL&0h5nZ!iIuju>27~8-bXg+uo?+ZG8i|< zdTrQGm+v=S&S30+66or+VL!dSzn9mB{q*hrK^lx2UPJc32IeKNA(Sn3r5Z{X49NZ^ zkSy{WvWCbiMbwb3z-GT8*+h1$A&pH#WTgg(SCzRm%~eo0b@kyE703`NmG!SQ;LY7i z^)z5vZHzRQ23*?5)qpoo|5F1hCsXQjH*#KebINmhznqjEan1B+9yLpaj>i&G{n`B2 z1I%XTTPkkKAN51sd%kETq_VoP+M1{C5>gv^OA#hlDx+gwLC5S*Gdj!V_l(x3lUr1;NAi+6tS6aOL3ZuE+$e zYzPMr2)lEuF`+VqpY{s&Fqu@<-)^oR)n)JqL)kM~3p!(hg6731 zZI$cJ@xi8kE?ef4x|*80++5A-73A`43%SNF3)aZb^(>UgXAPQ?v_>y&3f7=n^E!gQ zRxl2!s9#rAy)q+MK0niZH&c163Yi8z(aQ>!uc>}9wli4K&BgrrG&|hUc@I8Ez-bfN zhwI$EW0c8A3Xxixi$>bQoqlCS6xP2xRQ-{>=1-IG#w+2@01bv76$-yU+!=0$HB1k( zg*zimgp`kphdU$j5=~*rJHwrqOaZr1Vk*fAxfEa7ve{;gdeY*}u;I=q`pJ8nd-HNk zf!)7{JMKAOo;9mKi;zv&^FWc`Yl`WrhG`VwCE)v-(kUS0Ov9|tk&@5Ln5$|aX?1VR z^5@S1Pf$lfr*NklQl<+)pRWcM(e~$-gCv{P7Q+!781BTGwv+lRa0wBq*(ltp6BGle z)9C)))!GEpCcJ_Kpaw|c+Nq<6KMy=YY3idSb;~pm>jAy{ENgPOlWcksL@w|t$e!Pa zJLVzE4P4?Z1o8&RzQ;jIu7ykls@CBQi{}J;?lPX$^=Q2+Cfs?_EA1c_{NR}Ao}jv! z!63R2nBN9g{;&c8J$ zkNgwl@5oTm;(69=+->uVr4M&H7Q=roS`Q1iWy4rf5-mw^p;>t91BJi$?DkWwNOzB}%%Ryc?B04C5B$;TB7a)R!C-kahr^Zd z(R##4oX%x#nqRz_aHnK3#;?53?U%4~Tu#EA8@D(KPYqXPl*K>_6xWqoLC_gxfca zYN%t>hV|oiqc+Y(g>@SsrRhY8GOYg#&k+fj2>MwXyO1Ag{b9IMjGBu6V%#NkM=`d2 zzYCGE1TN2JT07}@xP4iz4VLy;yIfVQSzTF|?G3kgzChYy2 ziKKfrsMgcr_Rjh;k}xr@L%98EkXrO)2Ta&G5|&?xtfzp3Wt4}AI^rv%uH7cu?wWH^ zG-(6(gxlwDqhm^;+k&D-_1QVx!i9acMwxkqIjnkZvvXN0VwTKJ>_X$hWE}qWgGx!)E-qaC@Fx!_&P8FRNq)iXErP#TI!@e${QV zQ0t9Fw-=y|F;v22LDV8H++K;eH7{lQrTEcsdu;^0(AErc+Vn1%h05V}H*{%Kckt(A zjf-!t>ULqbDrU5;!xNZ8uYuGMcWbPE0<80QOsQlyl0M5 zqS%XRYR=93ark7;nB9|JJTS(%X|Zto0W`;=7sBm!NNQLq^W1#6-2rW*m-+;X=Xssk zv9RSnHy;QK{1fF1kw+m#kUc%z=KO~OpE3_g6GMKYs*tg0?Qpvm?s)TJM2fu?Zr9Nm z%CV9#B^qJ!hTMIQX;Ej3jh1G8!;hN+uQ53gj^hYQ)Z(Hh*Ow+!xTN5u5dzQ*?I|+{ z2s0tRHep|sj2E$}l_yHk=A0w^yy3&V*6;t}>s;V$tiHJaJm<{qIAe_4Amof0)5vYY z$lXlkQYngQC?t2e4KpMqL?y|!q~cF5B`GR&p;F4F6zX3|%8+}~W=x4+FMi@5f*&|vpQ>(3 zWf_O!H<-%IH3#t@hdW~Yod9t$8;!jY$M!ebPDldvZNi-5AEH$x>FZj}n;kFkzK+EE zI^0+BLyhZqg|W8rvoVDU9br_@KKuza893l+HWXt|VGG|7wkGRQSNw~nWxNN(|8HZH z^9$&8FUqT}C5=qKEn^<7#?K4mp|@|-Ji*zwpB6W)XJ;7`p3y9WUm6p?gb}-BKW~!p zZ3{{@^By;Xz$C+wIDMy_yE@UW0 z6!10Qe$IIXQ>EkhOO*uy%hd}W8X3R+p75yT|=^^~uYy z+?yq*%HBw5Chk?GxZi2H=TNiZ{=2>)^p>gVAa2V~WorD&)H+AQAKPr^Antd}pS~N$ z^seO=GIV-E2XWQtRkqQIRlG(kZ-Z&HKanl_@X3poJ3Kt5pC(VVFdEs4NlQjEeDN8^ zR*IZfSc)@VGAiBA$|!?rl{Ea_IKo3#Mj5rhQacwAo~LPOxPDkhpOCkKJT%-OETbLd zZ6gm2H}o|8-4XH%k&&qq86}1eh8{gZ?V z)KRx%$lXy-^ctDijknqlxm>r5jDTJsoT3-iY!-5Vh!X?h)qcp`ZJO>l zyO?P2s-@LFdAQ`P#iS<_Mlnnw7WZd~Weyp;2;0cqGCSn%RVFt11Lp8U0-3GGlL<+a zc_W$ElR5BE$Tj<9!ejvaK^KS&-$iC+4|6%0x>)7%7Qo^HvjrIPC8~llU}CoJld^$P8YrF_;(_hvf2h_Q7EUs zXp8a${I3W6TfhP{!CF+PJf%mCGZ#>3<+Zq{oCm-71z0Qv8#j5Yuif<4-FgVyqL4@i zp{~}HNyEVJV@mbGNJiUI1mJ{Pj@#_VgiwS3HLB$CA~mo3}KYF>|cDqP&h!n zaUpjD17ta_HZaTn-P6H)+8ZFjV}RuMUjrm*21qZrc!0ENZ-Csb8s}0>a#_sr*)OZv;}04x`ye#|InrtgDQa7ns{zobhzGC3SU{yVh6zXVwq zZ?N~<7CCj*!_QG-y~ufKph`3`{d$1eM(tRs*AqSu7&ap#{U8jcJ`AmJwG_*?$QW10Ctjaam z+npYAHJ32_R~+H-ula&mXN%?bmlvxc_x3QCSI-Z*9gXjxUOBKFlh9%{xmw+#PZ!28~+!(z2v?SVx3hGmFwXqSNA#I|4El zM*ys-+ZEL8+ikOz)r+j1_~Ma9r{2mm3y-NkXn(8XKeW^P1{&J2wlm1^Pq z#bpa7{&MZRUnMLiQ%Y^&txR__@bCVdObMr@w=&)RCz*d-WmVbQ2+47NtU{=WBaLQ& zuB4Ow;#r2}-hzIzKV8v&xunWU@>Lx)r0m7;&%eW zdv={!DXjmD;&o=FL7r^9tgsPyNv$*6z7=wL`3`~`%sP`4syFM*WlvlSY(Dg-u^RKNBy_>V!=|B6r(#$3)q2&R`9^4;slOlf!|A@O)sw(_e{jfb z%9yXdw0$MCGTiI0+G8;})C4ARxLbL>Oo~$N`i9hLRz8T&|J{@|-Qr1I|&V zX`V4$;@IK>+kZ)5I}5PO%8ei{_wylhn2+uZJ%R~ONF*;yCS0X^D(i!&kWN8lF+upT z51|L8Y2k#h{HOaukD9v8QZ+Qu#KC)OhW99O%<)%k z2~8{@%X1!kLf~EiJ9}z@SJTrD2q@8@MQDdKI`eXiwPVws zcJ^R%d+>)wJLBy-)L)hHKm2y@_-CwAs+#fNuJy+=tN9`ejg4o$rpZiIGwqAJHLRdz z+T$O;$MIiX&iFlVf6Xk;*S!^LM3Y)F!83=I{a3$Wh2JR63V#pAy@$n+gx{zhSO|Yl zFG4pf{KlT}_e>)1Q7v0V%AvB!R+5dwlAHm;G#OD#ytLVG;K>IjgBjdVDpbc9Pm$AP z8HM#$u)kV{<)lt^kCXpEKwmF}lRAjoaPk3py3iIg(3V^UrcQhI5`MB~kP%k-ujCzt zJ3}7ss-;=(>V>&G3&Lp)0!=oUPQhAb;Fc6$HNzJ8TUp7G#3a3y90|E_`#d(qSA$Mp zZL4-~Q+#O}Z=-PMjn}65t}!f-m@+BFmmW^MS0cq%FX)wTurbBg(3HVjS9{NlCQyuA zl%@DG7zw>aS*x|3xg+Mf6nB#+wCTrbQoMwg8pWavfZ@||^h)GUj#-qEDX-F&jHZP8 zW>H3_w_-Fj#&weteew^ZNSJSEeXSR`lzKYD;7gO9F;Y?ik&)1Q;Wp;}DbvTng z`EzsZux7Iq_uDu%F1+ANalbS20%00q5+z?7pW^NcmxP<2KQj+sQ`{ew3D0|@2+j^f zw#`lP@nYGmJs5;U$DcpBF*NG_mlk=CUiV@kd@LK384E$cW|N0$U76zUXAzbqVz&}* zrr4%BDef=cShV+UGCS*GY5dI;*>8*d9xgHxXuf%Xn&K9z2ol*lp702C>aR(0Plq#~ zCi6*;_@80o3&@;LZ=T8UmRerDd8FyhW1s}5Gx6?Dd&ghBo~hOs7q0eg%Dri;^_iD; zRPBd^^&*DPu*B?XBN1b%rv>7S(GHIf`Nbn4NgmHt@9QlP_im-QKH$-!kjS@$Z&WI^ zI|NUw6u*2#C&ibnmLa*F=^dS=1S^Ql%!PMu;IY&6_trTZP z$>Z{ixuv-Cak(ihO3g~K(9cCsuIF;Wz~vge2$xG5m+R#gyIh<0Ty9|kRN^7;w4(Z# z!7fLSpyvl5#z z)m!Dx0x|tY^g8Q6WCgh8GPI0Gp{eEXBT~;zFwZXOHg6a=!t5!vyB>#%y-UbC?HxF*YU zrl+_s7!y}&MwJwIL1|Fu7;ow>tZKWP)00P;IFkO3vMk>o(wdt6B(%X87! z_DgXGWEMZJOmT zX|=*z45qlbQY+2|SDDDo0Erk`+IF+1N^#3oWR%gfyR;P^Jw8w8J-bW$=-*jkk$V`L z@~1tXa#mCRYZA@X=_zNCbLr}_#(>U=?K#9-znyZ?NZFHxT~94(F9Pq*Oj&IR%)&5` z+G?!8TTi9%Z3|Qbf$ra>yk{h<$95_28xfEl^-Rh-BYome*GO3(X)|`2wWRrzm;yu1 zZ!EJ?b{aW?T#%n~(8R^T*U>494F~VS0jw@&om8V+La#pkoRq~i)dXSPotN^2u+m#v ztS4~(HM*I{b}3I8gG7eu7xRz8*DrOj65XV?%vc9RdRSO>!Hsj6zyXa<3(;`w7M2n`Ug@*8CE923LSM+Sx?T>eJSRooxQ>#WsI5_?&@}l zv!u3`3Dwu6^bC86^fzpKda_KQJz5&1^rJm24Z2d*8!30-`fnM5yJ7w`-eQ-dZKwxoY7Ciu0&d zytTqEHUB95iSUEvEj!E`V_l)X=>>0Q$pUZt80_}>$iv^Z_4wU~58PK7eod9)_mJh6 zv+Cxd(7tpK(lpexZZ3Yo;FSmanH^ug89-X!#PuSv@LEQIMh2I;f`+PV)9jd{g+l8A z;r2FUh*4R!y5;ed+Tm7@C##!UT`SABni~MkLTz6on5b`CUAvZT^}bHzb+E0j>$Q5{ zQ1S-bR@V!+kXgsR(YDoQ)-FlRCd^c;RVA&yc8_g!-EgZ}66~87e$3PQQ_U6l)m))T zH2iVM+&l`~w;a4>YFzkHSokqd>m^nKwKxS3e#X^$gC_yqAs3c`P9cP<2i;S{=`tS& z-5;pxXS5frB1trBT~p>ucE}UOI%-@)zv}xo^im6gh=klslcA`w6`sAu&%mOGqjA zsfHxpWG9xxcXg5kp^NMnbRq9*=uzZe?gRqfBIvTO@TDwAzfOG6eS^l;@p}`z{hv^9gEzqggE^(ai(=bV+u%WDxU#v0c*1;U>Eb=7s3mW+) zghUD(dlGS*8eVobAdhP}sPW#Q%Lmf^bq>SJ&YQrmOQ_x2F&Bb^;}?$adc7#3JI;T( zfskdSYAWAlD&J)**CWrm)xwqE1!iYejzl9L3m0~C{8@d#G;cwg38va80T*K8t=0nS zr0$@%r3T;)1z16umH;#pmal;BK00c)Ig20~Ts{E})4FCK1LVbJI3E;rHHei^C6c|N6$bsvb8*kg5tiR4b911$*klt?Bro-j%Y zBz9m8VWkqyh#Vw*{|Je8THZ7_+>|uG3^75sE6=~`^@gJs3_k}Ub+ED$w-I5iJji$E z{Vn>^dbP2+1X3&v+eR4^ePCaqQQ${GcSvo=pD_{|ROK9G3Usion)s3UzX%}_jPuXj zuXeNma2FoCeciA`& z&IJX3io*6MT1{qnS6X;nA(G|YP#1_PzseOw=L*CPWQU5lqB*gEG;Iyq{KT!-XN@yc(zGAJ7EWT znzrLM$leun6X_5cx&z&``#lQ0<8_Grr=2L_M6_8Id}0jpm#BX!OXE14xqHqRsmr*O zI}miIqx=T!wYoo*px{ozmty7sy8%BX`DY$ONA6G6$v#0axpiStnRMMl6$xePIqv=t zG*OEEb(+^%3fb%4f$V;4^w9N$dP-bJq$i;p+Uf zRHb^MZERU-{wjkwugE#jPNFFvRc8ZDsQ;phe@0QpwL|YIf%p$?CVZyE>qNdL>_BGa zqoBTTr>Mc>zMsh6OZbVZ4h)W{N;b!Koq3r{KI;Ilp;EeZozHMr^|yHL>Ja-ghmNo> zcYu3g*L)*${N)+D60Uzl=4jvDH23=W;!*`aFqfg9&6oP-{cp@#HM3kVeoV^{E(_qL zX#hNmrq-%KcNV>>5%0J9{z6rUv4X=fYE4yM4*Tn7QcOJ#S5|^~=ix?#3?=R(au8*!fAuLtmc_M2GtCT=XhjE36zvNNCc_y9* zSICa^>olzUC8pm{CwtE0Mh+vB!^gOU<9sg7*ZlOdK*#` zqj>pxjz6=%s$~>ELf<*!v?j5EQf3q{-@NXQvXaFaKvxs4QsO9)1_W%__ZNyi(vHB1 z0pDMAm?PZ@T_v*S(A9b9Bgo>&P$jAmK^8|i3hz75RQ1SnglFMF@B1I>CadL_zq)go zIyBVl(OHF{EFvtFP7j_o@AUf{?l3MWOL>Rlty^mNo5_2|b4#3l5U`6il1v`E-R~Q3 z=5Z5@pNq4FCpmiO-=BGn;CAEdA>-{1E!4~YK<+3msRvNQd+K>UB=jyHmPVv+ zApXTF;~y7`_%k1&yeXM(vOD6}A0T^vafL2-E%8?JcmrnSHDEp#6yDwu*p9OYA4VWx zWPV!=)djVxZK?tlF9I=DxlAt?> zA)~2g(asVCagI=gjg(u$)W%`_IfgqprX_^4o(SIdSOaz)oPQu;CcouJ#l6Tpr3uRM zyTa{FxL1ipB8+~=3S@GcCUsTt2~ZXgxTM7I z(tD4g;$yE~O+ue!LQzKwFFQ-r2_TcqB14Q{h;?G_(nJTH+&d|YRUE@A{4S&Ov5ka} zMXb9eb`%MPr-!C%9jz!y{Y$jweg|i3k#m%}9j%!dH=i~)Z4XW75cKFr$F?c4n~1_L zwRxhXc9N7(4tQ-oI$mt*7d9WH%}v=Ow{89dwBMCboBt+Uh-mZCd68_Q;v?_MxQHBW zs0d;?y5j%BIF@vzvvpTZ2NgHUZQyw`Nwbg21Crkv(GbSS+_%H|_rd_?9OqH`P+>WE zUL{He^bhl}(`0WUd-K1tsd`^WSZWF6M_aYlb^G%Eg=I{7FFsQ<*=FhnZhQ5tz0cSY zgF`FkxYvR3Om?*R+sho`$~$E!r(UgYLU#8-UEs?*-kRU>4-FGBTN^ zJ(T4o5mH<8#>=opLHABX5cZt%qB)JDRlvE-2EMf7-`9j!2JJBY~>>c?bKB z)8OOHS@w+jFPv%nD3Y_wmrh&u9O+=ksh|$yAtry;Z&tKj@E|A^=?`BS#7i1rcE|$T zh6E&zK-$)mKuR-#3@!+EN_4cx{rbFMeNzPSL{YS(%r*O0_(W;-O<{N(O6Xb3bkO=n zd89WG-ZCFF2-a_j@m+G9-^vi8C`)AxDp=|N)`vV@xPgKjBvV7%(NvYe1DCI;h}Xvc z-R4Mb7}Z#9c&e#jRl^G_OPh0wvWX(?9l!5ZHD&smV8~O$pqpspXf@@w)v$vaLUQD& z;kWk*%gDo!LamJ8oD?@GeC$geWB#D>X?h zN>l;^DM}}>WcJs9wW4N(CTxbaN;51lmcs~B$`qH+U-@r1Pi?IlfYXL>6NOr-5DSQ+ z4lMNjHSPnSEm62=p5hLN^PBckqQ-a-dJ*nc0$V70hA>6U=BVPQNo^)ACw1Y^V6s5cEkp{mE)dv>|ARw#%Qu8krnlj)6neAaLb9!eUaSg0_P$2 z&?!HJHM3sozUh5Y9%Cqv<97hG@K!^ZADXvA?Ls}$GkAMQ&=`6gB<6cJ@#Tx~xtP(0 zyJ1k*x!>02@;|#&vKvO0`(ah=OtE!sN>U>ezG0?8P#xCMa@LxyZ*O{P?^ZI54eR+Y z#*9pgceQxmy2#0&Va#rP@LH_y<~0~vTo&?tnZV-!e;h`8awCB~HGf>1>33n0`-@;?clFBjDHmGZiDl7y5=bE1PBueFdXw-v34OTc)HcGWN|YxeD9e9;pgJE1#yg&7`R@9TI{q&c>aOE)ApPomUro<#7IGfWuy^fH7&M<$PSGeg2 zZR1(Kze7hjeS~mGE!=c~chsC^Ag2>j)hPpOiky*&D6cW#?*x7y5c)dP!hp8`#?GD5fX@ib*ng%yp`B6t zr?$_wD<%7l?6U=42W^)k2yO}^DVSlcz1@wg4@NMg?scjz~4`p)8fnYi+dv7ZX`YR3nW6b<5n>jpjpz^&3shYABSn389?YI z=!YJZ0_~U%`{Ozpm^R&BSDGaTha?$=dnto3A-c)4LbB+P^oE{`rr0buf zQ=P*{n2|NFxoORuklO`^a%*?bp`4ov&J>wz#STTz@ScdM0PwRS(HYQO!W^t*_+-bv zE;f8MPp`~tc#O%WT(2T$M1faMzOrI($}Aq%KzoVmR&FVE(+*A}qX#q(fA<8u3|?Qc z2j&q7cE@KB-K0Fc0VPM^wx~$5tI&nyIb>Ik$!#rUSD`C%`1M%5N@_QY;_dB*fb$ z7`k$gUQajb$VWwz;cYJ!gD*QKv4ji1Y#e6QRep7iF%3H(QoUn*c&>>p-(a{~Ej;0*>C;=^d!iAP$JGeS4=$4L+%7Br~YVmU<$ZAZ;(DJevinO9RKJH&%MZrr?@ zbbE8}T$}3iYGOBVhC~wnp2yLCe}|q4!}|4e=2b(m&YXl{Ly1;X6za>$&Pxfm>V{_X z?3atkZx8;jhg$@yafI^bKrAchpeWY zzH+K9$+9<_Q{pfs0!OkcN^sgFD9F#McolIqxIx>jimU**aY3hOvns2>Vz1xEtSX9g zq|14Id6w3=wrM-wPrVy9IywLf@>6?Q3DM@Scck7XKqU*fqgZqcTBl~YImotoDw}6i z1yV~>U1~#9g(NnpNvb5)aSRpJYL;59r0O%$OXV$g6CdiN8tDy<*G65cm7c8V#++1q z9)%a$!WE28%w2e?6);B_@4(rWcB!RQ{m>$(Ei*^E({o1*vZlULran6FNx}*GTH8WS zX^GP_bf!|pyBLA-$#MViYAZ9VJRRR_TLhYMe{sY4f)WQ@Zw{P-l{>1&k8%QMtkhni z+Wyr8M@-{&Q|gKb0^3ZY$Z0VHRu*dgd}n4Yoy-jI4yal~AkK$b9l70_D{t zq_n{d=Tpb2Wa`*0&gYQLob0b#*s|a99aM3r<`-Dtdyci=q5GkA(fePygd9DA*zy7x zOk~Zk@b(ICm+)Q#rx&58JXwnajz34=Du~Hf2_Bq-q-Hn)Ud`~|sbejM z#1KdfG9=bJ{!U~6MZ#qx14#_&9(XH?k|?ElA^%rN5}is}Nxa42X`1#hghrvL4sQhB zGJS*eON19|^}a993B1K{ijJMXHW4-?4|D>nt?@a3?I%a4`WmkdtWll>^*7-!RNNw7 z4TIs&JFpx>=+qD! z2pkD4XX50@+f+^uEN6wyN3gQE1!!%+?DlsWYfj|`7A1*CTVjzs#ahz^0*lbQbs&L7 z^%XT;Ah5(X2{|_TGcY48M|JZZl4DLQD@PsFRm;!w|9nXV2tPBbled<1Pr_Xsf^6Q9 z3>w~9;`*{`U^XV_ehZLE#`!s{9qx?<$(-7V$_vav(Va`9=zCKDFDB@u&ApU4{{~?N z$2|P^zG@1r;4jLu&~6QSuB%st@E8&g{bcpIcm ztH2qHzc3rTOe#n!-uEf1ddw{n~{zEw5y@;L({==Pu8hc(!YEeV*h4uPw7{deic z22;x=@Gg3_T*P+ySOyyWqAci3q(S{UiGjz_;9Z<*@_)g|bP)|)}B#i{PG0K?>?xt@Qy!#-$CfW6jUeHfT9hHErFpr1 z!rZcQz4(yFEeN#8qD62!8I;E@v-o0}RqkUjTgtQ3VtZn)*zBS?aEv`|?ibMAdCppH zpMik0OZL>YsF+GZ`MarS zORdZvPSl5i0>sdznpzHxzwaS*Re~~q_apQP+Y$w2OP|{U9fgD3{$@1!J6{Rp_V;+g zBc=fUrj+fmd8eSyvyfoQr6(rDPmuEdqDvx1Ymr8VblQFwQ zKFg=eeUGMSH^A%OSy4RtcA^djc)7se<#?F4(Y*>e^z6S`-TwWd)kJs9 zUOoF#X+mr*&2|Fa>ypP9cPWR^mfqfu@m~J=ZoLSLhI)D$x`awEz36GET{rdi=xu@C zG^*>zp8PJ+WiGw!$?wwJB;E{5fdXhKdY3JrZ7ON#(kFxso)j*9N#cvJhT2UsH5?1{ zp@zFt!ZrK^&X3_5j*~cKdOEue?dHlo@Qbi*p)TNk@x9~x6Czx#1hV*tG4h|9l65;8 zDYf1`_;LqrH~#+ z`&9*pBe<@!h_KLejX)8w#VJ09>pHK4!fe%)uMI!gNjFaFg~#+ZNYK0s{{I-$+srd| zGAGbQ&D*CINgnSK)++Hnk&T3pB@e@@ae2{816^?{-D`w7{R*6IY^Q0+X|vwJkwhfyw`I;JA!7MHtx-xs0ol1I=i1R!^E&B%8W7*4k7vYg4Xs0>20Y0wBzsbg0-iXo;|r20G{#eDQg}So#>cAHsa`B zBne0FfL=Yu0(ldwHyeQIh*4)8jX zzlT1aV`{h+oSVZn+(n|Zgq1Y|FdFUA&(o;#Hdu$=@#sLEQc7_007W^eM#ryO9oL}< z{=j8d&GkKa4J(S50`-y{r&TK*d0H|#*(?jqn@n_G-(12RdWzP55M%9UNJa%RIHj$1 zpX*ypc!^c7<2A#ICOiTz-$e%_#k0R>l@hS<5*d}qF#91*Uzzp|G>JFezzva5x7wpv$Gg%fz!sr^~`Sw( zD*^5^GR@TmxUfu#)Yo&lk;C6xTV%*>6RcXmplZ1v z3NYIOJ}d@wYn7``-g|`wtStsC3*_=Py}$Q%TlsTWi>vrPT$+J^;O`c8KgZ;1Cj(vh zdmoR_>pjrP9a#)ayO=w~1NI468bg@++mh>^&b>DbY-xe_+6qSW?eFCFf*G^BnR6+3 z01hy&jT*P*Y;Gqw>XU0(y24 zm*ES>iMRYEH(Nfct@RV~HBPrY)wk)BT)t87@3YyK)>rARFz?=$tE;*C6k0&7V!+#t zbG1X+H^u_08C#F=KW{e{-OUNPT+iw6Tiaq)x)N)1f^0kLt~6JlH0b+{b%HMU6>zo2 z2WhUnkhw)5`_VM_Ym?~iaHuoQJr729mo)c?8n>2rvinX9_8Q@&xw->7dVpS&@2dlt z57$g{kIMbGHCY?U${n8O>X4l~kHnS}Y3}cA8kUJ6@j<&Zw@8D*Q1ec`%ARG_L0Pfc zxp|uVp4dELdIAa41=UHenw93h1*l(=2YTzumR>c>km#1?P7z*T4{wSg;mJ*(lJDG2 zOl?ndXNH?zke}wxGOaY{H`CnNMxRbkcARUcaSyo|6wSxX)eq#b%fpBTy!!4m7l&#G zw|+V^TJ<4v%7)>MeoJ$)GY|e5a8=ex1JzpdxuH8-q`BEHZEyEi8sFTcl9PSy7!&uc z6?Y~)BW`4{`PMY|Dp2~Dqy_I~q`7v-T+MEOU78y!&~;w3W2quMCOZffFH`n)PH-@0CvDoPfXo!^Wi2n5==Nvt{v7X&0y&lpf{N3Wf5LMJY5W*#9f% z(~cXd8l*tlM?(6>B7GEr^o2o+sF`hj$c`ABwvZA7qHT$VSMoPvtgS;26|f+cxHoOO zO4PC?rvFcgdxiDb{Iuc1>S(csM{x4kWm3)4a3lT!qb$xZG^PJBDIM?GULr!C(ChG*G)^-Q-pyTG^+NWY4$QD;{AV5t7)u} zc^P1KXFBlT1!V_q3+v)$hz*2&9^uUTCIaPv4bhF7lO! z9(cQXT9H=C7RP`p1hRd&SpUG~XgF{r+c!ehs(Y?y1AAv2L0xOY#-mE^536{LH9UM0_RDgfneQc$iw7Si%3}Nw{mgE z{%rRjHuvtI3aIAsY+sZS7m1RkNib{}pCtiA8v!8M`yU3J(LLK&TGMAl>m{r5pQO59 zR`qQ6XQX%kE2e9aFy2YMuJ_4ocbAyd*C>`nk+|lHUf27i@anbBcE1$fF%R!cgC|h+ z$Fki`fCfc-piRY~N{zDJRRV=P(5hlk!fV;?Y=PQ&pxFil)9B58*0fI4W4mYTGi3fj zy*<3C#UyHs&UPOZ=n)U3l>x&RrBaKs-QfZ~?}3IFgA$r#yMqK;?STdrgJOf(ZXbcd z!st^Biuoto%>*>~YOhqL0l{vEX4$TNAWNdn-PvyAumNrkWV=nmi4r?W7;6-N`Bk&s zG?D9+Xl%$$W8vxyh4#2XKx%u5=uIRtl~AFZzRGqhsnF11?_q;XV}9!sgkF4Mk0vfb#C_?Z>i*?$RVMZ76~!J+_obYC`i9{UIHOfZE{UaPVR z2I(Z*%+{AZzcaf~NN3{>$NNp`Si`WcL9j?yHOu}Kq#>2#4W&&6$yTSSg+&_uaP~SO zW!dW1X@TWcx2|p&Y1-=S*M!tJ!BqDeY?^6O@apW>t#Oc3^1?s1gp1{ip*;8x{y%en@6woVun>~far{$>j8`)!p{;l21Ph__Hv6+nn?yGA!M*8bwJ~%*Cb=w%#QzT1)qYNQ zuf?kjE8*c>d*zr^?PuBM-F?#Cknrkzcp-yFZwVYpcdJ`&gx4kA<&m_1Sbq<%R3u($ zgGZrP&ZoQOQJ~e_-R;wVQ<+udz~^t_u?*6`n-WIy>8BLe!+T1fHHAy_L^}PVr-NJg z*vU8Pdl7r+;f9^xqd(r*AOy z1Z@Pt%s~1EP0Z#HACQ~A0T*lxu^>NvLrulC?!V8EhEK7@T3)H6=rvYHHyIk*Icz*Hy*8V$+t`|O9@ehXh@0qBh`qi= zaeW^+u5S%HV_U0&#>G93lQ=lNDM#;y7xBnqYa=#|w(`=yZ#O|N1||+>jNWC&hhWP5#nXp28%8|e$~gkk<5Xl=49Q+jUz%y^-wZEi7Gw5sAm|+xq@w35iju# z-C*WKU++p!3fs_#Su_|M(l>$JJBVXLNh~tMHk4FP@%Vv#M>y$M16G{(n$o2mZ0lBD z_G%RC)4XrQx^V`xB7ral3NxoTztWUMd4vl1pWb#~wxDqbDyt`k4`@S|GSnFXC;+}%*T0QumJSa+q+bnmdx zRz{$`WzlHf{Oe=gd8T<9=7l#;{Zf42T`Jan$ykM@z04NsLjUL!%a!OwPN`*}nwQE7 zI^AzeKPBO`b?-+Rle&T>rD(76FTxpcCOk=|8AaRyBu*kGL#GK--RZIJ7`T*=Di{mz$jTjqi(rO3(1~>)78!Gp?3PQhXVt=j z=OD5yDpu!InHY6-oIW#S52zV=pf*-#7}(e<`gxe)??GP4%-F->yvNCV zguHL2#2yLfaZJ{~!+i8P_PDLs_46ph{|6hdqu!wk^Wd9b$BBB9vrF&DUT}0d{Il0Vj4SBpXn&c`T<+;Bts<$j`=0SeLAgP!NRHY)tGfgZ6|) z+hx!M`O=NuVIX!b7`wwla9@LNh}|s8b{{Zyb1~qXg>qP7-K}N+|$g0c4y2dgG^N-S`kRpo>01wqGFLo(erBcmnk+J4|)wUw_ z!S%7T45>S9iCM*@I%mW_B~pVd;HhH1*8dU932-1kSR!g88SJaIl$y-v#bea!6Me(`Aj-aFPmb>(*`r&~ zEtf@+Fg>mqhh97R=^UT!Jo0%nb8~z}iE4yWYo5t5w>FevED^aoGID%BiJaXgB4NmR zcF%qZ7@AtW_HvHz1L1w>Rr>*k{p%zWs_lbXqVE;j-ACwbo^5k;eBV=N92j4+yexA_ z94NJkO2h$#=S|7+Efe809^qwIjf6Js$Q|#hHnz0 zKO02ogV$haj#*xJJz!g|{9ExaMj(Jfw;m>ge!(HrC8^^c_2-_VN?N|hK9ulH__ z?;aIe@wHQ-Y_Cwe$U^O|EHpn^HEpSvS`lR4-Cs^{$k1gAOW`xjn~s4TT=ETY4lS z3teLhnf=NfJNSEh&f4swtV}MWJ0Lc;wMhZNj14(HEfXHH`+p=N35JT*R<~u2dr5e9 z{Z1kR&%Jadw{=@m)uO^2UyM4j2Khk?bA0mCjGD}Ra(t!jATJhP&T)^6^ieAa_jn}f z<5!Z-cv*aR*_7j|>pyIF21rDR+&y@u$h&M(p$a$WxO-G+h*#5|$U=KeA@OU9=SIo#rkHkW;4d+xH=>{_8t#Ur$obE!Ihh_UZLUX z99M(t*ohwA;z+#3#d!4}%WXb(9@BHp1!hB z`eqfXu{_6pfI^ShO)3(Rg&w%FP>tp69OgSY?xUDqO8el@!M#aLG@}fO0ZJfou3Z>9 zSZEV#n#AB<_mOy9Xlqq#wUIe)o@$-zv6>fIYu=T$RvT&BH#>)A35CA&3Jr`bH1Nto z>9b9tCv#l6)Ny*2&G6<%x>VP?)L@@sd9Zgc>xdM49e<8%#_Y(RpZ=uCh2G3@<$1^H zRt=Hs9LYoHD|raLsY2IaMSAo#?s2csZIOj;yRy(V`&6hBUysw8XWTlkP@Bj?ZLTa- zsk90uZ_RPbQfPdZSEy`cp|Ylsr@*901y+buV1-BpRxk>rLl@-dxK~B?61l_Vt=^2l zt?w;-7{!xc&G}P2Xby&m{xmEQXKecOO16_EfY zv7eKpQzc9b#a&*GX7>}eTJ+5k=$kFNG1sl8ZAhT;+8pZ{Bc>C{=F#Y|F*$NJk9tku z*63pH7H7&OQNyh-f?^#KfVm`~qTe$>3 zXSAxZdrvu|vBR(sM%TYw&FHMl)#wGKlqjppM@-ADD(&VC@tgB<#v3yrj#?*}xW~$` zAFEDlH&Y_)hBLgycB3VRu_5f{shWyI2uZyloVMDLDYZXmkZThDiM|9mfI%V0eej}S z-45r__3&?wf1eor<2W;U=W|~W!!n&9tT)0xx%Z0sNcWngsZ#uuWYa-WiseEU4LGI0T^%$%A zh9c){Dzu;8eXJUL0tjpBNlsLFXVmQ1&*QKNt6?YG(UMZ}pp3lfNGA z__&nEKWV84){fNI+Z_Ls>}5^TO#mumGC4Q)_98OBC(}1G03DsO8fFfmeZy%lQ{s3; ziEq*!|GRq~|6}@Ase8LuU@)63Ty&bDw?e+*K-j7pqL+_QIyg?R;S@PvJ>xk3 z)mm;%)-@%_=`oDoh>0zPsK*BzF-~bQkibZOYsd z&U=8oA)HFx83j^D$NzW*5DM}$ztdJF2hgII67=PeomC{Qu%z_Skexd~L0peF4Gm%T zndt^AIKHf#!QV>Q%rkHQ%B{%cUC^8|Ph>ucydQs!{gRcOnvDLIpqCU@9wf4lu$P^y zGEbnvm4A@p1Z4Cv&Rwp&2nF*RbD0G(*XiAiRTUkVWvd(gj}q}D6d2w(sOn2vUF2*p zbXfWF%cK6x^=y4U!8t%5?>M_LDw?Fk$3)TysoV(2tI%!?7YD`E8|(Ngk2Xcwy)guw zve9izU|riUI=+fOK&qO|qG8yM3S?wEIA6Z{DPXz+&zRQ?*$H>o_$ujqqsyBj1KpNb zkOi8HAbCaJH?5t&g!JWY*Y4y+B}DK>=1C4RKJf~z+lm%rvI(t}VB6LvB&avMZQGdJ z$!%}8ZNEBad(9J@sPun(&GtmwYo5^cXWrfA5&C7>~JsPe{=QoC-Z93 z5FmzIba5Zy9^?IDe52IM=tMCS2zt}!(FgY3F-4#$oR%)Z zg`Vqf@z2!NHokRtkPN6NJZ;976rI<|oW-x0p5 zOyVV~uV-tkZURyF;P~n~MzdqVOvygY_ee0Vs6mq@p`nI68r}o*PuIGKc z5@}(OD(Sc@0O#wAx>=K_o{P zxi62Wi!=sVp6~L-Kq~VF&&~dL%F>Xe9&|MI$f6v5;)h9CZ57_;(l29kj4vG z7a{`*y+x^r1}GDY3^JDpKFZ~`yGy`DA-TKDkn=I&12{bR3Awml^Gml*@a1s{^t1pR z9^4BKej~^WBEEx)(7S^_BhY2*P2coCZQg=K%E)2ar;hKC-h(pNZ6lQ3^~v0Y9O9st zkxoVfq3uyogN7A}R&&V@l#azRlo%w$<_6CAqT3Fp>Cz{w7dPWF6vgQM>}gK`b(=~7 zup_d3sHzb4PBXV4(BXk_vQUtDKrr2DYYZ0_d$r@=_9l7X+B_-WV?v)WahDzOsyU%* z8hh2yoL5oqPlYO!FP3@t*D8MN*TB*xR(>6KON_5Bil5m5Np9Vb6mb{9qf-0=6tb06 zJpCX(pak7Mo;NJw%aiy#n#eT-KGWy>ytHQ@pI0TP2_aJ`HHlyn@wX_ENu(d4kMOho zGaq#oxy?WGF%#)3FQ}Zp{+W|Z&TwlfpO2*wQ;PUJEameji`?a`W&PXVB7#dXzc}26 ze1FM5qXgr{_AkJlPIy9zkBEFq*nr<&PB-DT2ugjvnD(upz-!`+@gyFDjsLF_tBBwv zhVL5C4o8lsDQ~=<;RCQ(9W0;H!CO053LR~1F3SMg1HgD@@Nmue2G!Ehn!t=R z6yt$<+GDWg<+X4A5#AYJ2Afcxc>xc{?3{nDjnV`x?qlpz& ztfXhL2)jReWU-oz!dIkwK>7T*k&$YOlA2a9a>$#^+T+15t4XhOyDPGQ^Fq)pUH%p| zb23W{jS^cdaYkbSXO{zLZ*%b%d}=IjMIX^MxErkLtzb?g3!9D03XeW33M>{EzRZy6 za70t96pgtnw#k+7%Y)wruh1=K%K+3Z5*{N=#DrGt@VbS|<_x^PM$c0Zm@PptDw(|X zUfwF@jj?$}sujGg123%eGa60e8k=UXD6~R;mRDad3t5Fu!@|8P#56KI z`YtZ*q)6k_4YABfpq@a(1*Q$x^7H)cUX_ z8H7r04NLNS65k?}SK`Bx92FtSENibXpR=Nz^P!}cF9iRn4H6!+4Ha(hxMxZUHnO;| z%X1%10+){Fvl2M!IT`^XCV@>UM&~=T`QO>PXZl_@#uuX5=2*dVjT6o4FO;G+S?NXO zzx;WOuL-`dGp`C%i1Bd>(5x6ssnzE5#LxB0HDyYrsf>HSGn}R5k{I_Qn-+gCr7U4y zGhV){qT@S!ugOB^Np)k~OGx>-g%6QEn2Z~lejTPLXkQEgjad`99b(*nK%4uCvZs*E zRFUky2~m}ly$Y2l^~K7+n2Tul6AHPjZOc^#kv$L4(M^K?63fcDOc?!JYJu|`;aBd> z@_q3xDCS^D{@ZK0cid37@vbE7EHd^aStJKvRUIN4NvyHuM6dXlV8el6Y(91 zWg3z|CrKPrdcKk%bhX6VgmjTTbZ3z+)|7-7CHvmMi7()SJNHme5E!NtvqW%_iZQSy zGVCShD8ay%*o)9p36?sE!w7?vc!tPC0@u~Khv-L%%9y6a8$_65B`&Ah-&+nII1uh#4Q8({nvY&i_FE z>(w?=kg=xBXxT!TCU#=DnXY;)#G`rIgS>hr97{xuB_HSl=`D339~4mQr2Djxjk zmGDPQJI*w=@E2t~k>$1H*Iz`iF0RO=k}DCKdkDtd4($M~qcOKb$-V{H#r&^i7e6~L zXMf$&#?TH)t-q2=C0wP%IU?*Nl)kN^ zN>b{CN?}o@`KpEcdo+>hgr};Ks16A{x%p+ymh9?gm=}-AIzQ&XlaZvJZ*#4=V4kVAzBEb2_5I>a=K|I^o+R%LFU17UBYfOg1^nw9CYinn_Iqv!YkT+0y}{wjx}81)GhdrO+Sth-Y_bf&)zE2T;SK@2OEfY^*ZRuXvM5H1iNwgRRxVa_F$^k>`0JP$geY3H* z|IDR?SSgc2;OYUxioTLorjCjqF|0t%w4}(GSXQ!6-xvDNH{qg9!EPKb+J?kU6g?ef zii${c$G>tuGCb9ex>iz>L#E*i8`(7#q>HtY1py%LO(rYPn#h7{$l@cP#U^4NOP!kG zn2W>~;03uwPFo$$sTGb<(Sj~v6=ey?W+zs9>RrdZq$!5o{A`5_s7G!AqF@)yW#`W= z(}}<{CZoCO5ImVKviu^h7@uDw**obDw-xK>YFc)(w&Uycn4~+k2B{2(nCDDBvBez1MVjmzOciEYciw zV@YyX5?&XLjZA9(oMBAozYSbYxcL{eyz*_l6@(87>qSsIO&ggp~;O5{PpaH-TxfQnUmd5R-_pJNezg}#qhl=LaboKX5+tgUZP-*!m(bD7om;`NvH z{U>vB>3i`W<(cJ^DP#6E#l@$dzV%Hx)Gebz-5VQ!g9}9b+7M(y5~vV z6_a9ou}I{VItYz~<6A!*JXYD|w28j{5rb&%*em9Jk-L%T@j74N9+ zKEpGFSG1mA{|N{z{mOkKqS{)^>B4p)8$AZF(G%)PZoD_cdZL zP@%!Q{5V8uytJ1aejMVZy~iO*cSEHMN%YhaD(%)ce4Q8J-pYS63KTo%{-&WSvt1>z|-lG-x%)==! zGi0VL=dj!_C#f$Om*tT!&{G`Ee++NuShD0!r<&KvwTDB_<=O7>^2e&Vz@m-+Kjgg$ zbX7(6?_cLmgd~J8NCE^1^E@LUgCK(tW*Gz&xn#H*Bony_gQDVqVyi6*#m7D1hU8Zi18d5jK$# zM&zHN^LsS+&-^yzYpAI{5%RwS2F-5q1OnW}*kL*8-&97)E|j^&n}kCe6uXAPsRI&P z%ccVyo>Keo-Hp(8F^6gKDd9s9w&b-1->zAt@V+g6#F6Y`E$Q1;W}FN>SO${;->&nN zgDPa4Oz4ZA?z#cY$EBzIGP@tZLd5ttGr{uhVkVL?jW9)tEksbNjJZmzClVp#BZ;5n z9P|{?KY9}LV9W)0L^GIw%CaF7}g6&u#9oBUP6K|2(NK7AzPuTUn>l1c=Y*BH> zu;q*a-$U3vJT>t>#*85obCM~ZK8D%hI(R3uw-T6<%wYuPq`uuqEpt3!tP=kuawcJ# zNM^d2IG=!DXd{d4_rjeQm7r$rk2)L5;CJS^27@EwW3;@MhP%yo~p?H;`y zsk=_1{4+SFk-DoDJh_c4Q?ZIy8=)vCI)`Q)7Bc%fci$*+_6mqsOD&Cw<;^D<1=YG!pbvlQ{q1Qvs z15APJ`-dl=9daJj0g;0(7E~0?IB0630VYrX(4Ba z3l^;@1MIC>$@Hp_^R`NMP^Zao66|5wn`Q2MkDNY-Ah45hun;_#x$hgYy37tayX5=J zm9-_1#~U{P1S6F5K8()v_B$u!9L-dJ-Iry&l$MaN=Y?>H7ZKG6wWp`MWZ%ZINOKdc z6xsT08rXpyzdGdbVuxk>*2x|#M|4PF`-mZ8B^B>02stBZ)a)S9^?MSXghkRhp9CDY zC6`PjF;)q#yeNVbqbysX`XZhVjz-P4P9|}6vygL|%dqPH0|6To13S_`jNQsdDT{(3|CQ8RLm`!a}kfGIA*m~=f73N z!(NI~@(M%=7i#!6ET_GkWg*92s9|5hyKG13J6nnMw8_{IVh7AOM(_MpM?>FrrGAJw z$i6#OxOy9VW{WF}bQRrZ1AouBCxl-#{`>W=H-HDw2zySLb`Ef!lk4SmMmuCr9J^<< zLoZnt*)!Uqm%X^S`f4l=Q(ue4;pyu(&iwj}`$KOuS6k@d{a28I(&>dvjz8&eEvc{F zlvtT`CggRQ7OD_=52U!{Rdf`2z@pGg$g*$Wtvn~hJ+`PK`HgypYHU0;T3KyE_Jo%5 z?|UM|gwdGyh(~V@Ew>U=qvfkZSLi_44z}-&xn^BxhE%s)ZR-3sESb^XYZEP+ozSMe zK;LUKoY3Z?7%jA!8*B5n$3uBGt~Mclt~(gj=FOLea_n$Xo431d<}eOWi#c4nwmCEy zvCD=%@O)}s4faB>BQ_0r!t_2yxlOQr{vPTTgOx&T9vkY_OuccD_M$P4G?$oAUy(9F zRkp1Qb*6FJ;?S#GrL)+fD$9Neb#AG+9(KIkDrmpIspGA5D)^%W1ChmY%ODDhl!Jnmke!gaYNFLE!H;O7$%b0f^8`)U_o*LR z-xJ`EXrRdk0GS=OT-OsSKVro4jX$R)i`14Mxs80(&26L=)3jFI>29y)+G(V_bUeHk8A%a7n2RC^H zA6!MIy`1vlVPysVO>k41>N@9^MU}9`IwdZdo4R{so)4K(@nWyXi&kuvwA$F72KU8s zj*@fOj5g*E`+~Q^LI1<0sLQyT;H?ZR`=!dFg5a$T)fjoV_OsaO%PE%y*U*=Tw^N~C zb#RR)B{DrvzY$#1#;ZIn5?s^G%g=v5xMp}AqBS`d5ltU_A$TFjgqcpIRaRG-;Ds$L zUv%Yi@Ity~HTddg!3%rX8gQodzkhh6ZW%O)Wj4^1+vXdyA0AJAH zWw2Np(z-DrMY4EkbFh$BA1QL_FSIVurN0nhBm;^<+T_xID;ajwgo3JLUJK4u)jzvc z=O%Q0uI;+2&h0AF-Kuk`L{&(SP7F?hbRA7ili{$6{>Xk+n;l7}3|`#CPQU z-3;br$gjaZmL`o}x^&u!U?1D1G*Q*ZN}ue|ykMW6w0KjRDC>hCLMcGl$4atEDw@_` z24{jjYrkT5up>wv_P-iw>X9iKZQCyyb+r9-&TU_5f?b=q9n4~ula;Lwc8CPqh???R zbM_kkcT>gfbIPoBY6D$X@2y1I$foUZO2!Mog8OjXX9wG*qRHD?3uR#svUJ<@cIM|< zESs_>DZ$Q17F&5)3n8Sz*{trivl_`_BA!*H1gq{WtU=ZtV8^h&k`?5ZN(iE8J$!iT zZ^5Q9Wx4W5uxWd%ES8|AeMAs;Ie3x`=8jZN_kt~`MD5e4dV9dW{k#2ZW(J!BB)aLn z5fUx>k{F;mBqmQGF;R@c2Q*s|@SSNfkQm)M;IlV>?GU=$zXg0~lYhsl9=b_PPvYn% z;UwbdCXGozHzg6BohDgylZyksQ9`F1FGSraL~qfl*-_Y7qq{jo-6&c|FZtd7$AE8$ zDsA>E4PgYtD-F>gh*cWG@TbxeKE--vz}JuG8p{q+Y)9|T4BApN{g4SN4P#J@hCxBowx-B#X*ZE3C>Z0|;Mk;-^;mwU~1^O{5DoUEU` z=DK;!wPA(WrX9^icnVe5+|~bI%}qudJ`eb^VaZNid8$5TYepU8LN+==Uw~_ReZa?6 zEB>7ydaP@~V2!h`g>)%asf87v_shG%krBo=7SK^uqPe@h&4EO@7 zG}WsV$V#Xbu(Lx-#OlDX77BpLlk3O{!6-s5edk%%c$yTz~ONM z3C&zGlLET%(oPfhjwaWBs^-y`5Zl$wD8iP=#?l4a;Oz7~U>mkj+H63zIbG#6|J+WeHCw(hIpFMp)(%&&jX?UfV*%%JS+_jjbs*y{+IBZi+m5$5UjOtZ`^5fj{7wJv@%qltf}ZiZkxW!e4CxrUp1$Y#3NVZL+j+*nwzpeL%vTH1~A9CFSzAQ~6l>w)aMhcF{8+poWq%gy4WDSj65^tnB)(A_Y z$8Jr@uaTOa%d`5&o|2^bGPWye+wO+{*e*S6n(|L1e(5;@XAZ5Om_h5KCG|Z~uk|@B z18f&j+_rb$;+)RRb^+ysJtgJig;q(`*ApxM_iaMp%Xa|EHnII>2PWVwVxMeJ$)k+U zmp9woV64nPD4?g*C$2V5%~IX%b9*%K1(Ys2L`5s^eQ#sM_MH~sL^0Ba$X5t2^t7Y# z3)g5kZJB$t{RTLs^Th}eY@BvHqG{Kd*=gV_x}Yw$Lx37j7ZPTYw|!d46h+`<}^;-f?x^0p(i2L5I zHMy0BIY`oozzLp@KmKQC8~a!tbtoYeu>tGf_kFF&M>~O;7;t*>_+hUfpeLD@c3|*# zh$?{%>#&M&AxL$dJQe&@m>qbRHTUCRV_~>XUS+#%Sp&)z1>U3Vi4>JRZ_946Wenk@ z(!f!b^#wKG1amrEMYxjFt^Ox3urO)%mjecYqsaXU?bSYcKQMnJ{6UF76S<3UrxI-G zc6flWRf*pbd7AJf+Lm8Q#%|d%I>Ja=0pl==`Q6CA0KAXHi}VDmNaZRXWc*KerTE2I zF;C>}&1Lyhyo&Y#sKpttsOILWVqK*RXbuKH$)nu-SBRUWAV6D-m_rzk2jdf=A81BfzpGa2^q=~E}UX7m9|rg1v)T%uFRepMv! zfXLlJnuTJgjy**l?_CL#(+MluX~;q_y<%Am>Qe>;ZU=SBK_K3hFL~;Ki~4q~nk;mu z1%%ly>f3Q6<~`Dk>`s@JYS9%~&)n_VAZ!x^Tx!Wi&jae~tE(TqJ8qJ4N+vsX?E@pMR zzqzd#VBmiqVERZ-dy25jo$ufT^hsaw`tI}4@Y`m^klDq7>0-!!?uj*l=`N?PMO=$l z2ZlNh5D!lb^t2FXxh(6+JRg<;-Lr=!WU(<2~+s#w`PR)B0u-q2$#u2Z`>3$j5wQM&oedYF>&V2`oVLsY!; zbA-ppySiDAvHjh=E)B{1*}i?>V;oALt-CH`38V07&#VU>RJy+=wZ}Mo>@yrF@awck zm$`&lN?>HWEG878k_$$}4k7AknEMnGu0QhvMc8R(8$~_zg?axopHkyu0*^-h&oEu> zvXQWko-SYn*mI1D+kbX1Ft!er6>GS%$7tJSReu3))6>!L*qR1XLq<_=+8firpwEOr(H1&@Wj9scTU$Jn!zmEenk0M zJp}YcjkI9_vyf+BuQyce4XX$9di1fasn{ijBUfr;5?>A8)uU&uu+}Z?X?v%_$3O4U z%`1Gakz3f!T3QvJ-?K;OSYZ#hu(Ml852tNH?}tC~-zx*Yw9xd`C78?4(I+Zyq>ZfD^9mVF(SY-g{mWnY$Q>8GU? z6FWtDTG^yeW(+nxzhx&2_JzPYVG`0$gXRm5wd`~<@zZfO1D|f$B~$r!RIh8C}s&L1mKO^lUu15Hwhq;rf(Z1 zw<6!V!rm##?0QouR81!*XT%|IaUnCRn&<*LsOg4dfWbqy5J2j}Q>`+_(V`#w4}|EH)zYsJcavr2Uzb0*|xg(jege`&p7ehI%RgGYkovRrsqAqRddrTerIh=8ZT(er{QPh zbfZ(h*d>$S`-q5uZ^`jHS6Lnj^Wz?{ZuN-+UoCF$5D91hyqF;GNZEsEX zJEcPRp4!$mdBRef*mjv}zo+j1Y2%L$j@7l&sX z_iOcaP7N($l->EU-#M$fV*c)aXKr(-8t{bQnPRDW2&ztQNQ!nL;xbG)GIx;Ji=Q7swR4u`W8N zTO;FibD(?NVGf#<$&=TB7UCWs>v#HzxEH5+#Pvg4;>7hswT_m0#PvJH5=X6*r}>>; zww8A2)umpEwR-iz7KXf9y?}>zyPcA9$ZPBAP)dN@4Ypg)c-?Bt0C&!SP$mrBWW+woCr8twL=ry&0TJ)U%Qww#2 z3-u|}M*9R1s88W2P)vL8+2KEefE&sathID}2ophiMBr#!H--DjquLR-n$wLHNH?7f zYq-lJ&0q5o;P*OJ6;)UgThsrtzBjR9h5rS1n(S<+#RdKsAdjsL0b;kF@&KpWWuE^j z3&f7%XVTxR=6{7|#V+0DAK=Bd`m>tLDP4DgZ-JQj@?rXt zbE$7Zca0O`ue9(j7-f+_%1z6B^F)g5$jiqd#WxROVmByzGSz2&oTeYIq^oR>%Iw^5 z=KH>xswdm`N-veoRGD>dW5T}aF`TbVRN3@6&hsL^DJru#3sg2Gj&s>8Urrq7DwXB9 zIHz&@S~K5xi?h~@t)+f*3H+63dIB`wMecMvfoP92ry7Uxcy+oHD!CzW?hS#UT`<|{ z;7LFD#@NQGdQ|ww#M>V6q;FKb?Gq}~BP#kc$(W5d`$pKdWwTT?!fg>2-S({S6pIly zygE>2r^HdNYvdaoL;31-l?`@L(w!H&`?^|`C}KM8*tO!TUzW*S`nqP5^PWdOkNkX^ zi8}pLD~M$(#@hH*-r%8T0LWBdk5n@DiUe5Dy%nKFa}}^Z_8J0b!C}EWX|K;@`g&@? zVL^KX+EbvJ9;n2Ab(gr|S^f59W&^YXJzn~LJSZtL*h-Akc1M_frXjmAHurrm}mX60Bsq^VqffHA=Ae*qtSJ_id~r8l{u5 z8?^txLI$E{N@r~?RvYasHNriq?DZyEW7KHr#@!GNKjXk_9HgHIqPO1bK)y-@8SR10 ztp`$@2r|P1@ix4?hK?nIEb>5ZuZQJ$B1okNvacS$a51a9zz)6RqVlbe2+!QaUAAYr%MkV_Ie&WKEw46AK8`TIQ9$W(Cr2X z>#tFpP4chy4v;{TuU0Lh7176IvI)!&TzB`z7B$1m1U;@MT&Bb#BIs3*ZK6-WHv(*e z4|&c`#h(*C^eXmb`?aU8l$*eWPV~KTJ{0J~(=L4tPausF>zEMTg#AM50YD;KKkh9h zP2v>>wn{Y(e!Wr76ms_urqXfZc4qcwS6bcACPvQzgg#14C&EOb=VZv8$_p41MXd?$ z3-r|n(9|a>Lg#x{G*>1&xl{i_>W_pQAZKD$0y)s@k|P8(UAVf|N6(92MZTs+umHuA?cmBQ~n|01CH4H z3pZMzAV4PzNJw^4$a1>pSC$s%`J`Gixf}6SqUEi-*@@?VRHqk4uUBU!Iuc<*)9b7Y zjPr7TfX8Xin_o0O!x`KVjk7o^Mek&OO?C!Hl)<$!R{c7vUmHVw8;M)!v>{?DTHL#ANbH_{+&o_ns^5ZcN6QJpfru%o9ufACcA^z2b_Utq*2(XRa7#ut@F!`Y z1|6~Q|3;0T6HkTaC3i`&NJ~uR1!Nv3UabN0_8@GxQ@+&Ncc=VPr^Ke$I=Td;{B}_1 z6VB#5hOIbF#wM$^@7L6cWUSQ>FE>)Z8$Y)TKR3wKn(4a$v(Ew zP2>>*J@$R`Fp*aX`*~^XnHv8s44~!WmgoUw)0LY*dEvur)c` zwXJSGED*MrLBEV%$4dh*4MeaL&bkT#4=GayaeJCCs4* zw&oe=N3GGX8P{r~gm)z+{fYY?@uszIzIlS3Xbi z<%CsAyh-Fw_=9P%E7;`Vs#lhZjoR{s;_7rtR~kmNc=gxrG*{gL z?3kqfSrA#>S3e`d9^_}#GNDbaoe8X6T*xzloQ5?C9f7*)zN8q|{cDsMLF8t_^~aDv zHLBkrZ4i+~L^$>F?sI~PQ2qd6t5FfE-=I5mq^M{)+4~85M8ayiJL_s=-z9tZM|z+o zK3$u&UU^FEsS*OJ=1r$r8;J8liBqlSKPP-lhLpbDYqe(fZN!UhfA^z??LIQjfB-Nj z(7blPpn1HBlATN@u4q8lv&sCX1+C9!Nh)Rh>m>=wD7`yfbJE$oaG#w?sh)N^%sNXr z^MeWEU*@Gp>M?+Xy!+!CZd8 zLxcxJ)s32pfb;=Tm1KpKRB4GqXznY_c1-({me3B=_$z7j%m<0D6gBUU1!ZM-&^<|b z>}(Qkn(McTIDY0n>(Kn~H&E{e*sNFF7T?zd&C7b%%Nl5jxK{<%gq-=2s$0g`rmM!) znz_Ab+HRV>|0zvZ&7s*Z3GXXWW}JZ?32m5iRjnX$I)T^W{8c=y8#s?}CbU)MYUVhX zg@d~O{ymm9sVC~Hf_Z9{g2zRUm$%Z(dsTT+pExwv^3GD{RhFv z)ITH+@@u#N$+xd9c-l^+XdJ7V*Uqpdyrb)u`-b57{IBI%8*$cglW-q6YBp;Sk9JbQ zW0n2`t<7hhMtcJYJ(QSA530- zvf`7I(mIuC$k}MYStrQVWToEfr9O9fXM{(lYh&E`8@D$2AJ|GGhX}9mY}1zGs)6Fy zr0abW|KGGL@W57N8DS*s%uwq|BWc~9GTdf+9@)afrXG~I*I3i_t&ahJ6eOc1h`&8S z2e%%e8PsUdM@rD<$!!UlN*pCJhA@Jqh^<*mO_OvLuPk{LPcEQ%QLN&{By@+2t#}8C zTks4?SHX+Iq&SVd&g;^+S;$c9w;rH8o48$Ieh32JTa5UV_Y!t0fhRnfad`5FD92mx z7-w(>p>Z3p=0q{3kY8P-dVuNihf_Tag9ie~#Y+~$V0It|k6^a));sX5aJEMemxORU z#1i!90y{)DDqnnE@Bl7bjaR{RoPkXD^|x zGYFdSKFjQPu)=C3FqMN}Bxt_*>^;UAl0x7`dFR<3M8*?FWs(riqjbq6-IC$lL#I9( zJ zdd=*U?#Xa=pkE&q!MHHCZOB`MH>B!?hu{q3>LV?PeMvVeuPEJhiyz&hyhQHYD8?0K zGxj+9N>P9&y*u-gR$0L>x)Oi`v6~i`R-9%&mARJXW&jwxNT0k#^A*{p>;o z7QIdu6ThL+)+E4DoMkz+w{13z`uJQA&Crd2tc#&}js!dh4Uta?A1JZQIHxoq_{FHb zD957LVN@{#*BekBJwDyBh$iSy@fu#^(c86c-7(Dqq@$A%?cb@xz)n%qfoj8Gp zq8kFmHw63}gI(?A28%j?gD)_AvRl+E&NnXJlz#&t}#X^+Vxhk*s> zXoviAY?ixY22Xf0;dXbAoc3~laoQc>{Fj{>v!B#>y&X9o1kCDhMnA$+3L$RHjS=&xp6kS=@=Vd1KMb~g)h|Z#yTHB; z7v7BOXBDhi#Tc==%5|L+W4yqWQgqR=m`q&L>Rh$1)~wk8Uc37F$4N{gu6huRe22T80P|F1 zQWmtD*x300?uYX24#js6ZXOTgF0vp&K#ChL9EyPzpQzNp=JZKDpPb7T_xN)vp5|0Z zAFX$;X70b{7;&`z@Ax9;YW(`C&l8@L9FW(QNs<@8Xnm_0?Ce-kohtfY^F&1WHDIenG%jxeWb|#J5VoP%cDp zMm10Zf=0C=wDuS}isjHK?ZaI4<@xF-9H=IBbpr%>CAP$~M`w5aTILq9$$FfoHf#qG%+Qy?56G9yslJt(w{b={sEn+mIN~6$2 zOY>;tI68nu?lc+>T)Qo<<<1U|1$P~{T7K=(#8apri7C$eJT=>RBTd*{)mrY0bKd_9 ze4PpHl{iLZ65&+1f7B4UjIgS;aX#R=0X3N+H`>&@2o3)FHQ+y3Mlo~N(Kjlwn8*gg zdL_a{m|u?G)?8KEl5?ru!ErudP>hC$qhE#ojfahYlnAE`FY0I#fc3LC^7dhS-vlLmJeZ`*o-#ESRR6xKQUAa!>Uw@;G4(Nm^m`hVK>gx|5d zk$l{DT{ea}B}fJa_p}{krZk0*On8#N)W+DhSJ)yu-T1%hC3kyWww@C3-a2hjxV^c% zYxd0yTNvLpQxR^Imm~b&tW*(R0D6;_NIX2~(XBb!A@QcP+lv!uXPPN3+ux(s>{yPy z->ji`yaM^`AEKXe`kBrg)j~+sP2)BhJ|^S-;}JyJxD9%;e~ACOwOSIg+3uY7E#Y(J zPN!$oe5MPyw@42gkI(Qe3mX5iKdI(;V4fMoXQNc}86-FcBQmD7a;H&K|IhYccatqG zrer9gi$Lk#7-mLe&L2c#6_^$p|36<4{A$qwJ9Z(}=V9AF&x0Mx6F-*O8P2W(UU6hS z@z3=x6IHU@N_Hu~u?vQFt<;hhsC{)%nmXzlBFSVIgY3XgBLZ%KfKucCHctfH7$X2< zWC{2wfq)e*0XTdS@NMfl)Gh%Yf$zFae|vIWx!34dYLp@PC<^=NOLfI@`X%IQL<9?V z?Dx>D0ZvN1xPY$OZ-!}SwaDFV+=2g7Kfl$Mr-fQBhSd1%$QD?Ci|m*OrrXXe*wsSD z1x<|qII^8d&?jWafRbDV!v;^WqwgY^ovhl=8H)6^^W!0jt4^ zQ2l+xx&IvWkoF#B5J;NG4p5COp@hwn1YYP_A@g0A4i;^YvN_>Aa~JK@8ctF*UYp@t zjmm%jXQ}*J>BvJdm45;qeuVJQ1;#(E3Z?2K55_N@%y529$FXSzxvQVemYvPY@cFr8 z?7K~vmheYZeVQOIrxo>>mkFA2hYu3@knjOBD{n;!t-Ho0t|(JB=)DtTe*I~miLWb@ zN1M%B!A{Ww;BnCU7rHnFs6jOPjfg);_caEOfc_`KcVdq>+P<#m^{j=JiOP6 z<+!mcx$j|~m23&`&_GjjS6bh9w*s*$<4<1YmqaYUqnEKskFot8Jz`0Bwkkck*2`lC zLEZwJhuN}l5u108%{ydU_kVv)Y#Hr!8oA&o)y@7^h@T}mp~bjj?Jq58QfqcEvLd`A zgYP^V{}0c>+XXOTYzsnDC73#mJ(;=21x- zUSrvo8@ow%X*cZJnE{V>?=g1g>xUZ4kG0~*Zl)J{AoRl@l;=7L*Qh0}6(4rjn#8Ry z4bjqx(rO%o)%M*5LP}+1;|@gBPJ``-PssG_tdmnGykoA=fB2bVi_Wg|6edXzA;ANNzWIK7@D2xmy3w!r}fn6_H?3iG`@?c+xx2`5*SZ@>O_oT*rkrc{pZoQoj zz4(t>bGRG5`$|mz@qSqQ;t4wTGl4~fkCzjj@xuw)@P3IgHJ-Ws_zERD64^=EI*~*_ znElc@q`o11$yDj3ks|K!0+bPr{ZSi0T-3?vIE-P?{?CuryeIqVqPw8J+E%c`oKm=9 z)vhuXg6XO{yxg@1deS&ioLX3Gj-=Amd72&Faeb}hyP0vPDQF<&3N-YNb(zM0MjP_K z(ui!`JTq_%8}Snl(;VLk7ONb?`te^h6c|0Zlb&|Vb@AyCe}KIdrjvHVMXo})wV4Z! z4w-?k*vCqVl5E`pD|^Q}<^iN9~l2XJuJXK0J!CAfO-&(21ctuWRo_c^I`hxFSdQX zD>Lvj&7at*=I??T5BJ2TJ^YjfU=X*yE7MoOqgLnPS0HH=fz_MyFv{;H+8E~%0WZg| z>6eGwnZ9A^V7wf-M^tGJVU`lAWE1e!zs2S232XP+d)oq{MmTI({~W8P>-YYXJ?ZF@bqT~k?3Vi7B2|?yg()FTA%(pf%TY^ zj<(IZK>cO@s1B#UtLJ;l&hveL`e-nh-4ZCNh6;WW8Xk4(WMZbJpb%o#XB z&mUPWQr^_Km4C@pJJzbXGdrg#TA-T0VEnzB4A59rI@dH?04hX#7`@Blg;qct=hZsF zp<-@UyUbvyp$UZcBgl>C(pPNH>Bo^)Ry#Pb5lKyGN=Q@UG9u{lgibJP<8`1I2eUA2 zzwp4o*?1ErBM8Ho203^0wo%quCg9Jf=NpzWb9}r{Q7gM%Kfb{vWvi;aB{g zvnfb9TQ@nqN!)#$2n*_*vEtanpx6Yra?U2qM}o;{#eB9weto-66iL5I`;wQ()KLT5 za_l)U>_hi#hf(Mpq>)n~s@@>7nsBjDGQsBJ<$&oerJ%#e_`D>kOLCT1G9jTP)s}4V zN^%oQIL2PfCknk1EdyfMn%febrESN~g1mNkvzt1otu3+VKfIDGbt?5MDJ+zo(G(!=!sKGY!R zQ^JQzyhem6bV#7+26Bprjy39K{O8Od?{{t<11Hd=_Sdntj1`%Mzr%y4yN#v@J`QWQcq9k9 zc3%o;o)=G7*`c0%*f{qVk@wfSyp)M{cn5rqVjTM@?szsfvFi&yt2dz21qLSv-W1lg zo7ST07%lfg`C?zgU*(DYF8FBwMjo*Ff4}DG1%0wo3d$Wrr2cF(-|$(s^dXULr8fDm#7ju z>^5$IE)E`r_)@X6@g5q(yG+tZ-lzy`#7PGj!D3Ztn>;bUw3F$7hNZawkr=Cv0{5Od zpIT3XueYkRbu|f*P5MF!7M+u%fZr+cu5l&@2u6v|iF6=j!{;r0+bzT(0>zX}|7(pP z>kL@CWiI7?3EI}&0*@!pAWTtWB#|YAG9~&Ext{QQB{~wJJCipejy6+hX-feqh?=}d z303+VfrpLGmJ5meN|4>$a+PtWWD%MwaWj!K2;-GtyiUOmO}SW!hlwz5r`!YGd#6~s z+2U_goat}S*aU(dpOBEJw$0L?hxvbWZ0Fpu~m8r>_x_8DhtIzcXL3oDPQtqCpBj0VN- z7!GO$WKS&E{Rx%erZw_|YZ6PORSkcYPBmEL)%QZLSTd!>3vdKU*!yt9GPb zH6iTeHK@67oD@%uRqmOaP_x8xi_;n%6k}jwiE5r_M@5qD%5Tf)hFhA%s9H;@pDk8d zt_$q+;37@yF(W})9n1*-tr=Oxi-*78b&#vM;mzzZn|eQ9Pe857X35TV||h?t7~n0kuTVJW!oU|39LPB|5i>1=Fk zYrzWY8gp}IU^}yv236GDh?-AD4X0iz0!9+Kj-W?F8yOl?*AZ@2J&2ddZJ;Hvx2yz}1{Zb<7NwavhJWfeFZFA)EL-9&vk`K2e+RAYLwZYtTD{K9Ilk7z_= z%=x;h3Arqju)ym^!sXl1gpp#`sj#XKp$n+e8M#8$5JtsNRolUoj!m*9T@p%CrFQ8k zL}DY=m9|1?giCBgrra*EmkBzA9&g~SGk0kz4c+z+2<0I%G~JUKOhrSJ-;`4FN~p8# z1cc2XOo41v(6reJaraWf^M7X=CUsh#aBLq19V6r++dP};Y(ZC(W%RaB1ptOjTOx$d zsv53u8h&ls1xn!hrrk)mUR|H)(wp2s#9`*p2fLB$q|ei25tQv!0!t}j6>|yRD7~6& zuHUk~5fZ#4<0p_jr4E!Crb@0h`bK0RxlAQmZ3sOi|LT4t(n-gZv8V_n-&j}mJiv7G z7p%0a5^;N%!0JF&T9EVOAojHO_ACJR$WW-4?djp2gxi(DQq$9-6rL)(SySY;n(}L! zw|=1!4K|%^ABhE0p7XFSJD{F5T|@;|nV^a$ku0XhHtmt5PDMweOiHKiCTyGFl_M~q z_%+$BS#QK(-T~%_T0xRLcnhTJxQ|^_9;4g(V7uK{x(y?sPkP>Co4z^Tbk&hsrx_hG zyKK`3KwI@CC>1`YX z55;=jXspm)3(71)3pK5BI}z2dntswYEf|YNF$6M2sCs1olPX9i|``U%E&$$7O- z+fK3(?V7Ys`jnYj+6@fpcAT(tO0EX*Gy>l#aZ2>vGb-@LkSegx)2>5n|9u#QMn~1{ z3gG4tX7PC3soDb2gS@P%U%X{&|JF1xv%%?9JpmAUGh-nwRQ-j>VnPX>YrD%hl^Kd0 zpyY^wH*Fcl-HWLyji7yvZM%=@v^`{;#jKCh7W`YuF_)idn)Cd-7Tt2S<){Ba@w1(A z`AJi4PI%Si0>FmM% z7oa9h0LpDu>s-EmbBEsoIiI_PH|d;2(e-VNIl>$Ihq?Xik1(41rkuR3PErG|?Yp31 zAXrk4b_A5V!r@zr#<|x?(!Y&P5*;~mi{pUh+>0Haf}3-H=R#iMrY?1SKwf*u@lkzI z0c)!xm#u0{6YSrZBbQ#>f+&kwbENNO%H=q=Inrmfa=SPIAwShgQr=*tL;+)wJHrAhdXFI~c08)J!cTVrMgzI65lspOo|o6tQSPwr!GM3(oI z*jH0yd`+8xrnPVBQsZmpMxm&Aig3e*J_CH=urlbTml1N@)L(<)a3LsFWNvMeKHZtBv2E9`(PY`Pi~wxXV}74?Lzs3+`zE9`(P zY`3X(0aw^q`UGJk%LHMcRA1O>F<~dy2|GDa*zmPZ*csw~rpB`4UP^y!t>dx;`(^?I z8kZZ|Hn$?_vk21~7Z_}@P2WxW&n*Q+m7(HtpYcwxc``B%%%<#F!X71X!)JU?_=gfq zerFCNbU{=5jAvj3&e2b?exhhw;6e(iI`d&At~AapeA+B7C^vx{iJ*V8&QXF@)~vr1 zo>$^t zbN)oobz;F&iR>oqP+}61R|(H+1cutwI)8fCYkxQGhdL-bIJefhWdYfvq2X1sg9}7f z@M*~UqcQ#-$~vH*Lqd5JbiWe5Q{pS*oY|ewQHkS3nChI#jr=CW{Nzj)O=lJ;kxt|y z!ZM4v1jL&_e1j^Llg%d1nYQ!i5n(Iz%)KhPoX8i1_mp7MXKp*fNlM&7gk{Ivu}a)a zWEo+J5^QMA{R80|lTNdJY3MIxhw#*Mw-F@r&~PG85cbf?(CL7@gACfKWHPxg5hTkH zJ5qChB7CbvzH#PZjOMjh0!5gYN0_GsLYRlCns>PpR}g{s^R_90m!0=E;T22EdK&sw zJpT$#RiS zt>V(2Pp!H07xXj!&tzy<`}x$0|1)eW(Q@U=k`h&}%pK7IL}kQR`dz0f!bY0ang9mpDrae+i_KAdNkY6dAzoA$ zKXP9}{BAGq4~NT)7q^&8+_renHP+VCZd;QPpIPm;RTnP})WwVH;!l9&A+1|Q$& zX0O%_Iru&=6<``K-{&IOX+X?k)ndC7s@tkdw-Oq3c0FLTPk-wH?-+!Jd}f^D6aT;V zfPXs635M)=uXS9OSPwX#DUas?=eIY`{3eZ;#ysGB_5kN!+!E^+Ok$+VDbBx>a4X|C zFdr-4QJAGSVh60!A=UV;T z0!@L9#yJ~5cy2ga0~1h`t61F7X`erG6qpSI^<} zh6y!bC1ObMMG_OD&kIi?uwXDD9NEHNgf2?-Byu`oj1ohLoK2Wx8(K?4Q)$TdAGfv; z|G02Da6zvC?zY@WDFZ{$h zr!#4&h-^8%a3g|dA0ZSboK48m+@TDRWeD(el~j>CkkD6&3yDl5*be-Th)N4paubnF zgxi()Gm$q4)*;_dpjb_3Z&p0nXh5*=lO4*$hbHt6vG zoTChOa?O5%qrA|y@BbGZsuaDL_O4*inuA_9CnDmS$ zPSeKzwAN{z)0&~_#_3{oK_OeaIn5j*{`RE%%5HZuDJiF>_?ek$r#Ed_duMpcDeY5p znvH7dV^I}q;(&tk)@kXQJUThXmw6!tKHhps8TtKU97Q7S64~kD&Q4^Om)Aa#V_seduQj;jw$?F`=^jugFVC{l%j=v- zW=^wg+ubhpdI@P=>ybuAHxbSK|A{j2F!uOuKVb;BFME)QZTCtfI@We?HI>tBkk#Hk zu|yX7-S!Wf9-H^CaA$|c5O=O;n>XdjzV7j(+D-P38xWs8GjT;`cBY8xQS>-g-KpfeJ#-$RY zGtaY%a;m43@gXouvA1-?9W_6N$~K*W$QX1FAYc&SpCT ztn^OT=uzQ>cwwCq8#7U+!_Y4$amYWa-x2RW+YmXMk$L?jx)S0tAK9S%tWZ6nAus0Fv^%6Z^V;kA_a5eg&qZ7cg_S$ zolODD+rJU6=N=FgDzN)C7NBoV$6lfc1T{Ne_BysY+Qar zf?BxPshc=l;s}#+FLl(8VwX9#Q|*spuuf_3&uNC&ZIqHK$*p$mOaZDccj#Bru=dZG zn0vm$sm~rc>NRzFpaQ?unkyYoSDCFq-|xKkUKXnM4Re~gL-Z;~3S-RG;Hb0g#$1zF zTmAbzfIQ)-2bPV(t*w_MRM-6`M^M*0_4Q+olOnF)0MnR8NROaANqo7{36OPa`v!Iv zQm0^l0IN4Lto|5tlcOOQ8*Qrl$5_i20*9xL->jzLVJkI3zq8bjKauGU@LL?{Ft<7< zTQ=P0Wc+4cb32IrY0|5@D_O5~B0tG9$u9Zpr3P+)tQy=&Ll}_umpf|S&a3|X zo1O^wUG*q8T>l>Lt;E+Akd2mP0pD#qUZ;%e`liGR)-Q_fnYv@-FJ$-C>59uUS68+mntvC}R#%28Yn=9Q*;QvN$@_(c`LdhUET@?u z#I^@qo_JGE>A`~@Xj7PEXTc8v;u%`fvUv~3a_o@J!c{-wXfi6KqIsKJ-oA}HQpnC0 z=I!xpdeYW{+x#7LJ#J{*hq^Lz5tf~Hq+TkW*yYuRx}2iK$58?}7FA_iZDOOm3sL%nXE93c_n7fM5WBxtBGSMWp4Y1;@E30W>oZbOO-3LVeQvD!(}uMQ8TvI zo5KQ9>%BK(W}ZE)HyzeacBS~1jqyCMj=gYvR7=dB2Jn%3mV``s?zdgV;B=@I!&8KJ z>Otzd)x>cjKl@i!uH4G*TFsOcnyIV(ehk_bIQ=^6HWI3{s~=b)yW>up^tZ%;VL9)P zj1TMN1h%d%uW;;S|D(EWE9#iy8}o6UpzRp>qz-Wcln9b zlA**?8;;Z4iMKJ|s4PCE(h&Y=iu_+s~iVtn}xpXzTNX#p2Volu(pRwySWQYUg-)E7#IE0oOt zCKQe3mj7Yp)XG(n*7XOdI|8%nOQ=mE$9Nbf8!XrKe^FFYS5f|dEG&18|9>K?%m3dJ zm1o7Q!h8DD>OY9DwJW}QTXeDgr#AJ)*S5a++Qr3(1of9?*k#7X=!aLi^_R5A{&Rnt z+w#tCc|tyC>PX!gtH-9XvyvAQUp-E4YOVA7VKTC7o!0*5CV?VzOjq{JP>>1U7PmtpbesGoeex3Nhzpx9#}DG(@&910^WZ-I zQ~yEspBs|D8`GxrZl1HKKJVYV|1Yxd|7@mN(&Gzy5UIj((1Fi|nskJ}_3k7rOk*|E+vpto-uzn8yZgGhy1C?9*mt59l-S6eAo1IezA>oaxgn?AZQ8vilG0GoVlZ>;e4-4D2^#z|ib&Gb07r6LYJx$5vHDqh4|E z{@t^Cmlc#mbMs0gy$dU=B1KU$3Ui~?y-UgqN~$9H)xGm`OH0Wu%I-a#e}xrgCDpwP zt8&XCy(=p?V;HF-lZw5g)m1fsS4FC8s>;bDGZL-N1x-113(G5d7eq=U)sf!iHKnDo zy1ny@Bl(Mkw;;DVw|A5V>6y~N=U0@KRR|UFvPe}?gq(7rto8u%YD!A0OUip!RzXOi z3s_PKnyOqkQCSjkBh<=Y3|vJuEmVkPH^(+Vvb@49&9AJPs3Vi56_9Ixl*%v27x!c~#dihTWsBjp9AIv1L&RRG!f zu%kS@ye_)JM5_yy7Ug=#jTlf;ZYGw@h*Xv3mPg8~r$)*us#eS@IWJh6^J3 zqSnk3N5<3?7DlQjmJ}7AR!~r7$|6O%(cEYls>1LE{RMn!Nq&Sw9;MOhV%je@CHdjJ z+-StOqaj>UQIH=VKW+BR`Qe;tIkQcaHmb_#)RdN#tM^5g zo0Sz&Q&3g16bY3^%8ROt&6!2HGpA2g#mdSRbO>38^DAnkrZmRMm}q`3Y^(?`j;s(% zOwQPer_3tjQ=enTo$fNsu18b)fF|RrV>U-Al0T4 z4wOQg^obE5rGW$q!WEFMH`LTb^TNe7dEv^6s%o#Km?2gg2@mOKW>uDy*Hn&2^F)1K z0X;DJd9j{|a~_u>#rY*+hBdm1l2?T*ODZFhbS|x;NL40U8ObjxT+!d;l`gjIGX?p4 zk)X0HTwPWrUP~ZjO32DDu*y;usm!aWs7Cr_VH?SbMWf@p|JpNk5YdwQH- zoLhzZMo{m9+^Q8}eRUN@6eHkxb!A!q0k9~yAY2(67U9Cu+#&>z238v67+GrBkGfW% ztEDEgyt-NjEv6G179P6F+!}^(?y}sH>Tr2QbvQ4&!Yq&SUHM4)lA1_OL~3Cw^Yg12 zJ<*!Hu`~eLV=Kz6YA>rQsYZ=u#a4)6(P#xk!TyRG?nJ4q&R>B<;cTSbHeV1a%&jS{ z4kG}1gpzs#xg@tV4EypTs6};^nNdC?M^>%0)JlG=4C3^{LMcUll+j*MR+(EJwmpjJ zwZ)X1UtJ1k;6!vlG*X1x7Q{`8cnw0aBT@~`fSIc5XhmV689O#SHD}hW@#Dg?#?L%6 zXYBa!_?a`O&os!P90f6XIT|d5x%m+WTy;f$MX9mYp3k5&%)_}F;{_#{7o>?E)Knse zNI1VL--MB!wa3!>{K^&PwArW4$O-3+V`S%?K0ju|`u9WsJ$pvHzbVAkgmd#NOT12M zDCFl>qFYsY;rue}s8xb!F~)!>*vo6oxJWeL9e*CL>M#y9<*0yb4NKIKuoaipchO2= z6+=TFL3$TA5d%zBQQia@7K~(NB)8htd`T4LEG#KvL`N4dqY!-ymo6oN893{`G^VFiwZ?3$`*wY3xlFlm4t+%6wb zButZxZKZ2B8A`^pAN>c>$cmCkX#wW3q-u$AM+u|KfTkMHW&f>^ZE@Y9sV=K54Hr~- zPNIkrQCX(Jx+Gj&!nml)FJ2+7DvHP$#M@D4TqamuTD-JOMiV)h8RKV84WB;cvtU3VnsE(H!k3@jTw zNQMd46=D0!DvR+|rZ``ojd@Jelk~>B!WMe1RqEemhA)Pol+kc2SaFd`h^q61P-YmLHDd zQC(Na{DV?=SPrhL1~qlJ$6EPR&h;rLB+E2 z8C8)njJLRvV+==8o?L8aIKQx_Jb&N-+zaY1$}212v^=EAXG}4bu!f{+x#d2*v#hA7 zDk*Ypm@I{zJ5A)(wi@O@R_08EOtc6SscA_4Mx?l)k5pCFpcw8ztQt7Ln@ZrS3NR21 zJB({=ln$OZ&mcWaUnIB8RFoDl%c#VX;VooWYAW$anze?jmRViw-w)bKOY`KbHGP4* z;mYC_(GsThm?h>O<@ro6VJ@>A`LW{M(rV_@6`p~xJ=U;8D@tH4md|y+xP~wj2ux_1 zRw_8XYP`2y5*UV-Jbj$#e*FsMcgCNICkRiOK5Mq;b1)^UYqdg?G7)C<6ULR|70^Dj zIFIoKBc_)Y%&3T#XmW%btce!OdCEGWR#A7z!A>R%GA31JG#{3Erc0V#*x9qXkz0*4 z=OF(6gRQyh=T1X3j}GG&=#Q8u&n88#EUygXG^uFEn(SxTwaNwkhG?v57{X8nlkIT* z0a;kkZ>T#Um(<7wGiRw_pj4Z}Vw|W)l;%IKamZ(S9_CX|cv?%qayvCjnEm4j2K<(e z!lCY%cZDFwXXPD^aIpX1XVUQ=E{P`f9o~)m=4R)eU2hXH!+XKKAskkFH(SRgLG^?L*ta z5s5hw(izDdfpjJk(m@IrTyVh!O1R*H3(gElxR|4$Xe=QG=^!62MhTMh`~TPTyzjfK zu@fuFUD_UMf4uwsc%JpF^@o+OhUCfG1sO@NR(AgSiMXz&yyFu%_*d;?OFW7ms z`{D+gYJFpI8_5NtNx;J7ZftK~4m+OAIJXE?-MrdjzIT{mpKSP4u?h+VXUb$`)b8%ac^}`2;K5ax``VpRt;x&v`^y zdK;)7(zv=^%%fCfpD*lhZE?vtkdrh_Xf&H-mK+yHvhim$QVeH84V&voOPT~*fb9Td zeU`3k3pq06JM5tckX`^3-XLOkWgn-Rnc4QzZUy4PQiW$G;kT@XiAP`9l(*1~+1n94 z(ZcX`ueDak5CD??w|7BSNIes=%a+uw*7g?PcD7o>r_nZEW2mx~%@+ zc`*r638L(Fb~GJ^fLf#Wh_qk|rV`VPweGALyU4nt@q`L(YVp=Nt(*z_zIq{~-HNBN zM<&(WL0h2fR+%PlNVk5lwA(JuvKG&+EtRgTt?v3-Vbfjd{@q?%E^l?8!V#-&Ez=r& z8X8`TDZR46=x}~~IH~q6Ah^bd4=otIz5QhXbZ>{Rg=%nh(dC{SNgNhS-=fb!s>UY? z6=wtR$RnpP0Wvix%;h$Ko`tc`E?isodS8cCN7>iGkqax+6_SzogYEMT<>#H zlw-b8_yM5YsA_hTbPA&qFt$w=E%)Trw_Y#Cd zj&`^WnO?M1XKDKitOFXp%^0AL{?8y)+KBi%dRWGGSnSnx-0vI>jdVnyI8?(SW$Yl zm(bNKp}P!YgrDBt^AgHquyMc>4Hv8Slci7gcXyf2VrKd3e9&}wczBipVJzVw2vY!d z5GtOaT{;pPHiPCPMhBpYSsNDBcYC?m+Lf3{6KQILJIaa=C3dm+S(UgCpAry60?nz~dBT{M z%dTi2N=U+MN9YC8xh2_lu85B*x=eai_W}4@mqm#+?CCJ7x8kcgXF!almdps|M)!c9 z17(TIkpS5fm-77M?-dTKp8K&bE}FdC{Rh{BTV zd(iy}rv}hMQ=3!sJz}HU8{ih{=-SZ9*$AZ|K-SyntfBpIsgu9$y9U8A!+Y1PNHs}w zo}{htX{DzR<@H-xXgP)9(Gc1{k~Q>G=tv&J@UN~by{`A#22;ilb#xH|8T5_LBxBvO z_1;+>)&Ls@X;4`~$ih+^Sl3#)Vg=b6J~jFXct|6+-@PnC-Kqh2me<7aD4G(nksPk! z&*L@1NCsVI9M)kTB~uB$3-xv|FI>qBBV->d4*g0!%}|dsUlp;C z?ok-i7!ci)ARuzwhEEY88Q>l8%VG)NV}5dG%JMI0zqbN3H6wT-)a?bt*qnfde{*%I z$GqEdVGVY-0Tq|mS&He_1Q`&mo!$XrYrd{0|LR(%+E6HHIfl~KI)wwEhs3{{cwfc` z3r@vr*WN)^kiE@LYxt2z*M>*4*x|J_l7QO3T3k-}-_hsoTYJ2TUoJU7*vW$nRMv}Wdt2|UOr3CgVE9!%QDo}4(hy1A&4 zv-pX^-11z(?@e^~gEy)9a%*Fv*t{C0nb$hv&-|pl*4D1wMDF*B@N}@|atDlntaaM^ z3RlRz!`inXbd0rn==vHT%3K$FyBjM@S?C#WP$67TUSa|XsB2G^S9${HGBWTd4%2K) z8(>4x7wuj~(*opN9}&4~2DyNK5O!yQ?ryg>H_>V`PWFO)Vu_g^6c-Sr0Hb57{SV;3 z1cgnkkKx(wpjrgDnSVXsQahZppkE}r$+i=tV_4V}_J<5ae!QVm(vu7GvonjW#S7!- z7se+SiBBdy$!vN-g)_Y*G{FQgzB8D@Lk~e z41gYOk^(*UVC$h4Hz9g^;X;N;2_NArY!&StCUd0&1=F*ZM5z69`()LUF7Hv4VO(IP zhfJIv9XcEx8#)|wWJxBwS6o=#>0Udd5b1&}ygme$EF*dG!(@vLK)g6a&eRd04_z}C zi=7J2BQa;1yG}1L20XIj96g|wy!eFBfv^4J3lBle2?6JBh{EN=P+Ndw^q4(5Uw`#* zr$@zSB9J-*nIs71_gLi`de*#7fr;?ntF9ZS51o5O&!`OZG;r z(k!81OE~SsV%4c+;vWa&qTGeD1zn`j6}L9{!m$Hc!1B<5WCSEnJ(9n_ zYq)Hzn@KyH#EQg`ry|x6oC32x9F^-4&0QwQ=DIiI-AbkR2MA*6FbfugEX~WiP|WaT*hC z05d?u@+st8QBsU1go;p_MyhuZ;OD4?z;q?Q=-kfU%-rM*s58eg?4c)V6wxK6u(z~+ z;mL{bUL5E71Q{TzHjs#gNany>;-;2*DFn6)__341vbE58nBldOz$v`bl6(Q07!~oT zVSB`2LluZ1+##rL26Q<`F+yA{7<#(!QcVVntB>DB?uLKOz;+ z18O4D4J4t(32wtuutt<3(b-gTh(uIiP5BT4_l^UJa_g;k?REw17=GlDwMVcVAcY)K zD#Sp9K%%as)2k>?Lam)Gt=BAGh}tPB=WQI9-enW;5{8O1N|U1xlht?B0TEjW>kVpe z*(tU!hT=yp=;&CtGKBMz?dFaU8`_pD@D1A?H#PC$0!?( zM~eAN!kHJ)pp%kga%X*-q^6}ULUj--XPj!XKny5Qv2WdqH7`zVJLX@0f9VV= z=p?S#3VEe}SyO|$W3e!&o|Y5`TjO{1utzEjMvbfym#jq2%oQYV;<%b6nQisq=c zFbhPB5(?qIVcBxf+qPCSDjAC?Poym2q&f!xHR>dr70ey5V=cuKgjZIVv`QV}H=ttt zharRj6G8;(a+{>>Mc`rKU}v>PkZ+vsu+B))RX;rBiegSj${ zlE0YbALTne-#R}>bnN^%k?%|@Byie0=8~Ypf|K87Zfm86jk>UdX5NpByeVHi3_E>G_iD`q$Rwwl};ZaQhHNJdp*u*y^hC& zo8~pOw}QyXL;}CDS&rgo>^Ukzj3^vx>WKdWpmv~8Gq?}kvDN|fZjnKRQDZ{wN9YcN zHK^0tNhLz@UVs=u5gGw!QW@o|)IlqAX@8%{wxihFCaHg<&tP>dAwRIZ{Es>dgz z6AXr&_5~Rk+|>S-!`GVDUDj&iG}>FFRn^ivBuXhOH64=jdkCjZE{$fadUHY2l_LFN z9TH!0+uiL0q{nF(l`oiBc$Nq^o0B*Y9!|t%+UV`w6{JD`y(ap44Ffvax-fJ8$=1d5 zQzW5XJYRuk5JN2tf@?|cXmE%CWMyzVwbtta%N6Oei3PMakXN8_ACju9ybeuJ$ciwJ zd4I-ht%Lse)0nx@>gRf(90y#|b9p^Qj_Ts>K=(*Q~GFp+Gdhj>bRy&Ck&R$7$iXD+lB zWuq_~W~4&zlBgq<%sTJM;7=(vcSbRFGAm#x?c(mp!JEgoXnlA3+{M=9nI~J5i?ce$ zB(yFCTq+KhNp=%0(CS@DraCZZ3Fb!EoVtni%#m3Z+0_v%SDg)1M5ZyrLrw@nsi0@J z<#uw#HHSVI$t9^uF0hn6DiQ6H(teY{8^wsF0F~m;HYnmiZDI}k9sbwZa0R#a6jliw zkQf4UKg-pm{LD&!oU9}8SNSy+rypY4Q*IBJGS$-1;H9#lS%9WJB(rWd# z4T=>L_H%ir9CSC_Dg_8I9sx5h84d@U1xV{iMHx64eMB%!$g{vaC}3Ki;87SZrhz1K z5`%lrNjB{1MXNRl++DJx+GX;6zZ5Gr{bby zL&3+A3D| zcbJ6&ugmQqdRzE+=#vyvvG<~36B)+RHMCSzqz93{dH@}gRwU~k&)JV)wW3Rw~YoZ6sJdTn*ifoon?m*V&sG-S$du!%0Z zj_#+MNl`&$&Q;H!4CQq!p&FP{tYKQ)PDUBSd33G7O7dsVjR#+0ZPI zXX{eE(ujz;Z#2odi!Z$Haw>t~fL0?H$Y!>d4G@4fbI9`iIx8cBov@{mUIGQ8z_IR< z;afW*5o^M9NQ6ueG)!W~aSVchFzJQ&zbU_A6DzDF<`7MB=u$;niXHALNf0lK*dkf) zA(A{iad!t%f`Kzjx13oOR4r9Au`(4KaPm*A&0Y#`TB5T^jF9_w0NCJIKr(}Jv~NxKn!Ih-(?CS|F+u8Z0LokPiSYjMH4 zKW@G$Jpct3r23(x@RUm3u!?CBq)1P-+{Q)o`Vg{rxd_$RFzTHR4e#J;<~xs}J80>b48XbA0#;Y-S4b%)#L z*_8~HwAUupdrM^ho6=P<$|?r!>U0B5CIaeMuldQC(dD5Era%Skx>zQVd91vUYlo7DJ_g(I(E_8C+!69E~){*by5s9mr6^0Sz$|92aiQg2L&VUNs{Di zsx-wA)9gix)s_hlBB3x**12h&N2r3I6Dd=eiRd*U)g76AvIe9?l@Sg*0U}c!AWl}C zgjzf@yo^nf?v>h!!?(p@@G5Nl3(Sqy=zF(CXS&mm$CMm-u= z2^9}cXhB&EU?f$ZXvRafv&v7|+z~V(=>vMu2LU)_t9vW6p%Jb6v4<2+6*Ci;hV`Ej zf|@MFBFY$xzwVYyV<${cPwFLUHtpv=qmYF)T_G3Y0W|_2u zr!LGa67Nd)v@jYta`j3CaFfU!u__V)1TSG%#6)D$NFs4+rkWhyQbn8^RndX7vt6Hp z8D9oP_ez#~zLo;PQau~lcMB=SR&G1X3Sq#i>)HZa2_5RKge5D#WhO~UkutF<+H3e) zao@cKYnJZn@ade%wz9cnx4{m~?Djf#M1hU~4|+r!r(ISYNfEL3n9v2y@)j~7ZUW~q zt6IU2OkXSnfh=FR#c`GI-& zSoJ1I0?Yy@hjNL}%^3z&iYc-mJedsg;?s+)TvfYKi_m8P#aCpu8bM{$g@Liu)WGa* zY|ap>pq|PEzoQH?AE~xW3-sz1uFpn0(39;5Sv5ul{T9!a6{I3SA)^b{T1#6i8{(3s z>_v6;_E+TgFc_}96YXlYB4lr))5iN&XaI>6;uVRl5w};o-&4fO`2oyof(2K@RT3uf zE#pFMQw&Mo2zEE+`q{4})jSd(aZtGvXApb+ax*B?2z!NlF%O5ks4~$BhR~_6lTJ?R z*X2Tl(&d^i@O08sp*KC*n_w>-+O$-qjOW%;R4gbf)j^F7qcNeBm4p-OB$OHYJaA;? zC+hOTU?seW3YAnHCCjBLXFL24?SWGT~(rQmQI8Y9;vmn2o9_Q5h6-86hm^v z6IqDR9V-glzv?mEER}vSLx@>w-<50g<(!tbJYx3;$o-0!j88h+``-7yUTSY9u9|t6{+lS2~ z7_(f+g#5ld6?f)~@;+ zP0~uiEs(Tgi#dPM zLm8o%lh0T$AR^5bWM+GJ1WV>pJJBUj5opt3O*8?D7r1!bB)R>r%y`N7az2>DPp+Yi z3Iu@=@rVkM735FJ&fz9^c6uYW(L|V}CxgRt#xO9FK}|gs;1c!nK+B!8c6zhq&|%A@ z9boT?zaeQZ$B5`SA=6<+YJd~LCTNnlFwP3PN7l*|hzvcmA;d6Ii^~TLDCSl-(P|yD z?3tTb9XgFs!8JteeaGnOO6;7hoD0k&AJ2hyjoJO#b(&rZ%%8m%fBj|Yt4vY$i#ikG<3a#VW7 z;#Zl6vTK|qfw)C@^(u2VqzIKOlQ#|~C+4L(llG@!gA7~p)3mgu5XEbXFW`CCu+XVO zDltC_aHA3uM$1+>+#0SCSyQr7=Jq+2RB64)S;|@p#>$>c5`@4(j52RC^kgZsPH~`LcmaD&XCoZ17jSjk~-G3Vniw1He3Mi zlu$@jLovUrCLnu?;*`9(1lHAFM_t}>tr77ylu)*nu~6F)dB+nl$g6gg$h&Hb!jz+! zd4B7QfEr13q!}3LUBmumBTYoMs|Sx#7wRSyG1TB7P~b6WWDHg`CMoYZ7MK-UX2^pc zPiLW!{L4C(WPdXsbt+$Vcr*eGdmG3*TA=*=GrjLP@+Ix z;-t|n){IHHUC^d|$xvVBlQ8CtNqoJs*7!yckDLRbXXWr09z#%0|##HG^JwQ3n_-4b1<{b*z%-%Mab%@O-Xme@zvI1BO zW&rW&#jnVMmTi_y0qLrO&J(2a;rw8h^4(F9$_3moVRdJP0(ORJ$1>Ym+9W?&kkY9d zg!ek&h~5TvO>B*D4I&xU<sw#?D3lv2N(g{otaSypwNwz!f9|q^e$lBdJ(sjk~txdLvC@{kC z2E}sI6#aD-fPZ#0++%1UdUnClpfhG8)qQGqXGLk?J6Ela^4S64ph$!;y!#EfaeNsC zwo?8{$XI`ln_LVf7OvL{j8deMR2eD!mb#qeT(4yPghnhvaY}<%HH1=Pg>N(TzwG3J z-AU)sc%|unP_8MWMSzt-;W`Ss7zrsC77KWUC{nq-N7f!wJxD6@){!U{k|4aq-9a4e z47`lfx#EC&W3grOYo*1RX1Q8G9L=>LE1&op)Xhkb%i@L0Z8T}(dhsi9@Y#NH>PAU%D7 z^)fDp*bB#rhF&eg}$7<$AGu5$hJ#D1A*II+CaM~4crZjnY79z()wwgkPDS%O}? znyW#xj_0Ha5IZ$H3aCY=z~cy_YHBzRrjT!_sGM96TG8)?2!E&@sj!9;Ed zF$I37R;Feu((_Wv6c0{~d%PIQFI*ONZv5%i^wU&E%@US zS4HhdrzmBsq3XFak&Y8?$2E&Dk!+4uu!OZr@|mM2q>`%C{$_fuL*nhqOnX|{xUl`f z*e!^T?fX$Q15-x2L5%Z5DlSs%S@IG(EKiVY&qtuAD|Q&(BWz=@xCj{E(p529OWpX? zurzE^f14td%)=|v4S|3k+J1cp0w2U`^_$#s_wv}5erl#F7ZT`aC)Wu17i}~>j zpvLLhy67i`Tdu-KvDzIhjrk00Jb9Z(*bh!IH`)4wx%1PlvolYgRhZk0C7Vzi<6Vn3kyY;)uPo}`~I{*E@`hTWh`NIDM4zjDnZ3!X^8eYxKgf(PN+JO4)Qy> zOPNYTtcVUPi9igU;U^Y+Y2*>|&>|{VbjXz}y3i@vpx}oL$(>!_Ssii?^*CJ;&~o#8 zyE$)E5CCtOg{6%`r z@{HuTY~+mdqceGCmc;q*F^s(p@o;sr1I@N?w^%D8DO=M1TKmvN`+4SfR=ehe!iU>X zQShc(pJd2|S<(|bSE$6lW_gmq&;usDYYIh7I;&HRtf8fR@_1gbhq9t@bX4lg7*i{+ zta;2Y6f(lBz=6782#=^lO^ZAT>(=IqQ%S0@T$iwA%IedMDSMuIbrO-0Wa`Q}7xgEl z3na)4#8#=5AYC~j;#yK}W|r8~cn*SEL?hkj47U`gv&wHsn496zNOaZ0Q+SB3E1>?q z+`eH9q_a>AeJNq$PTTH?L{GYn=cB(g41pn^6Q-lB7^UQ-wz z1?z))9Strv+q0kfz?5^Ji_XSmdevB9^by8VSTUZrHdS;I1#$FG-3ZiHHpS7e07e;B z*0Q;qdm&Zg8A(R={>rNmE33U8uDu?~txU>JJ+kU6 z@PMgAy_V|s_hq?zm4?7#Pr9&$!h#3xUE4l+|Jx11uLS7-qGz8e7<6s(P zfoNw3Q8Tmf)FN4}GVds9GA}6wVS&4hUoo5HDy5dkh==QkG-CnzOyx;}5(dPO76*$e zc1X;Y(akyaez}lkejWeNrh(ikXygc9p`+ep0vB6(41Y{gncmzh?Z zziIW0m^(K=zBn^6Lob5w0Z}7yU8Pf0?Ij2#SCCN#^=+L>T;_dPLP zOioR2k~%MUimDP@#K6nZ4K9sdm3JcnFgu=2{TS$%(b=rb9!*oOwqD8beWzC8t-hOpMpM^ zh~3pG?j0!!s?zlB>BHeu2`U@hN&rPG$)xNq9n_c_;JMVJ z=GjT{ik_YtS;*OQ$fi}l5u+OT!QqQdPGDDEp&Tp^1BvUlLEPG;q9+b>>t>UQo3Y;! z=DV|A<{Z;q#3qZxs4HO!gEaK25s;cj{~>mgAXO-)oDXiP+oDN@33u*CPNV{1e2DA6 zAukc}A^VRyBVwdE${*P&f$bI7;t>?D!>Cf&QcWP+h4j6v5GCuHkVJ6VkETcd^gg-4TXm|)hm7#uQr9EDX!_;^e@ z4)}4^z~YKJG*xjKu(j2UERV)567Fm|5fGKeNFCv8#wpy7aV){9t~Guc);?#1sfomRmO>yn&$Jy|5lpxE0qQAj! zT0CRZc+ziSq*U4r>Su_yJ1CKO0gD>UltBlkf_Q@oW7$BWc@k;ly*OZ)6`$s;a%j_H z%$hg~E>~Du5N(!{+|QuBA16fjv(<*i$mv;CI^ZU9XW<}v%M1F#ppr_Stu=JWx>Sye z4L>l>6<0|z^lS<+61r0+Taa`S=YnpwYEPzMvx6c4ik>F9SUKlTv4!3ts%8c|-~;us zuBk3rH!%*_=2m-qdv|%2Q=Z$gCj#rnJy$)J?MUfv60NPSprO|=MyN8zODXVvPVs0) zUd*}aDa-;DIa+4>o14U4I89%P4rT3E+=ELr2Pxzcop35H*MOhW$py!EhKH4>x;xz2fkefnDK1eeP5}?+J zXxCjak_Hq;21P4F4zn4fQd=#OGqR~-^@xdQZjST-7xA%|hd#;SGQP$vOgyj~$HnT5 z6cud9LyeOdWZVW(i(H@P zoDoP~*q|EhKos6;7ev@v>ENQ9DcIx!$ z)TLSQK6PDioFjup#T&qu1n49mW|g%l&+;F^ONLLfPw+yw;PhlYzKBjR6a@2&rT zKdpcCep+m>bpQ#@9$~xND6`FiZ9ZbDTASo~6nr>U%xL1L0=>@=M%-V911Xm4>rz?H zr%p%iwQ~82)}&H!=Bwlz>5AY1sul~7mg-Xb-0Y<1W##d??%}9nr^5M{y6q z+`LoJmUjxW%&I6h+RH}*S`rU|!IYLK9vN=8r1En^lsPq*ODLy>g^g9Q|>p<}Xf6 zf5+=oKX<+tvjuU2Z|SOyk`sCwc(h6a3K{%mzK#GCrWE276-YPNvfpShSbCVF;R+fa zoSAtN--((MhMsis++}?t`n81w*Nf!Eka>C76voZA*fSd96R7!#oRiZ2yYbnDj4Wl{(C`Sv4CRYWWYb;6v zy=*E}gOn4u${5Mi>}V8~dLFoDlj@X|Bdg>P)hfcDYCkd;K3VWdDn&}1ArZxbLV~)S z&&&&^+}ErTA8`$G`#=~_fw%&;`}M~0x*j7azd5W|mwRTgoivJx7Q3NL48%m?Md3F^ z^L!pq{FFm6i+U7~WQNT$L}7`2)-fg38LdcyE&!1jHMbTn0ZK|cETrufIJdk76BcX>($juLjPxzr&{|~9$FuzrO=2BIC?^@ugT_Ry%cAtr^38Sv?QXdT@13M zle^C8+^I&(9;hZ?4-_*GZq$gd0==)5H$4z-BD&3jZS1LtY|Je4SgRGx{;86cB>rX; z4T@A|&Xn&eEt>ocHVW9?8P*n0np;S8Z;n-xx(vd^)VT0Vaw7M3mm|(^RVcxV`U|KR zrpK$Ote(v`rsXZhygyGQ%D)_`Ww6TjCcv1SZ(x;`=SeDfl%fT4CzKe9>yLNHC5N24 zNvUDfR#3Z?=3cjBEb5p87z=-a%vIHml+|PQoE z+FD*F?(KUfcpff$EgY?V680Hct&mef=|@tyAm&evxp#3+Pf}i$^A5DfW%-)Mg4=|h zg!)^fz|s`iM0yKvyO z^GmXA)S$w?RqdyXo*-o@rWxaNdX4X*9CK-9Z1*6t3&&JhGp$v zY*ckPqU2wtGe(w(4JV;KMMrTklzL<`Hhc0Z)wwWaT4e09ElLCyW@#yoWS~@jj(Z2{Tm18ncnFs zVGyTJXmKEDM=vIUNb)6fV1*1?ShmaOz^NRl1%LEq+gBG8tB8-}u)1Xem`w^~7SRq@xrJ6NtB+ z9VxnEYk~ATBG%D$eZ-b1@LucDQCpWR68?y_Az*fT{AhF{XX`=WWW!!165-FPBYIe+ z+J19Fr>ID^`%jU05lCg8MhKwTa#NC|~nNU6i$k(HKv3h<;~(s%`~JbY*dMaJ1PHbxACwQGX*5 zRj1Ll?MTaEOqJ!qvnYZb=#s|Q1O`!=j?$s59P&X{u9%VcR=)Yfrn^$(C*g@NajN{I ztnX}JT?hdbM^~yqmt;rO0EB)Caat{cW5Wsxq+Jv-i_57FBRWjxY!|djfA!7$+3zjP zOp*$V4qqU3lM2R}Gt)9!lrm0!N9k6vRf+P4#Nnx>2g;j$-$);nP>(T{j2esw(nO%F zl)svIYO5&nR!PpK;py()B*+dJn-g6vn$qgIyM=emixtN6N*sUzo86>nj%K<=E^m-p zoFzrM(sUdR=_dueZeJWs!ptQWo?F*ElhY4~r7?(Z!h#r#8`@42#`Fq)F}ry<67*X8?NTBC>9T@ zqjb4K3FNerjB*kDRW@%DrtfuVeaHgnY$bbI{xpJTNE>}%;DzBrCSA_-OsNzuwmrO&{f z(6SQ!mXgox&*LL*azRQv5nrm5oQ_dOZ(L3p)H)=JL=k+ce7-iQ#)wdBLz7+hA(T@$ zH9l$2HkM9!FKp75M;P;6Ra#LYQ~TT-3!`@3M%eqHRTCy3IZxzTghJDB2N})P(EN6! z96Tn;;YjXJ+7A<`5kpa)4?R)69?tCv)EQE((re!l1FUVAra`7$1#E|!Jc3i`JLq!K zAb=F^RGfj0$rWQZ4<+WrMT@0&MKw7Ilj+1RGO}niSt-9;$0oVd!#a_h`V=HgAhm+`DI!SI=$}0C&d{1gBPf?^@KzSjfR=F{TF3G z+bLGM-P#Hj(R3^vU?vNoLr{sf6q*gi@r5L`jU#DGJn9dr@?kk{sRGq|VIeh&tYkec zJnhE}WM?-Rd#`J$7Y(3LrshEL5b>gsjqXGv8FANJXd!z23XeL(@5G5z)r*ET#KXsO zZVsKelc4*|scO{$WT%(K4)e+lCxJ~~d{2T-_JRi{K^3;3Lcu_vI7>9T;T~yPEu5*+ z$|TQp5OyeLWyCaFnJp1*x&v-0rK?Oz*P_t!((f@YK^vD9p{a9=4zi=6zz;{m0zoEP za|zNSVYS}8zQ_^Xkb9gUdXFA7UXL0_mo4O#q=XcCQA$8C{*2#bu%$@svz_&kopR|dLCbT#M}}!8 zSQ~$~30Wcic7Jc#sxU=r?PJ8GM1F3`9%&5B4plqt@~l*UM~~5j%}gH1kr4K+crh(Q zdWWUw(>uJY;2I+ZH8&rlrRN^7h+$QBW?I$q%{4QzLtfeAo!#04v20x-Pm&!XZpi=uWpirEo;Z6EYpZ8H2lt*MQ&nh?k~TG5_qZeh0U~8 zo4i>Q&q_ITj8A%|bS*1a(~5)6KVmX%G+2xz{-RA&<*~PkQUxVuYdP=uGlQuQ9*DUh zxixT|{R;_A3})6iiFDQep(2^KyCWmR{9|iloQ9}_c2a&?#w<4PCj&6QEZNke=3L731SAYefPx(*@G>zt(}xRE5*J+5f8 znebtbr&{|4R`wA9yI4Tdm{sms?TG%dqFpGqLz^ZZSQXWWzCy$rN7NwCUfZB4>lr&C z_y^9iwtWHj5S3uL2TEft5w5oL;4Bo#!{{_rupP>o317GLEDR%!0piE?d1lGDP;-K= z>#eEj#py}y&ScYW4#g_Q>sBejPATOkAv$Lyb}C_*bhcr3J85O8*esz+`8|@>np+g6 z%8Mh_c3V8az6MwQ+i zN2EIX>g8FFdkV~NEl2E2?LFu~J_0WJ(jwi+nUr>Fxf(%3xOibAwfT5zW7}E*Xvc&( zN!0L-c%V4U07BfUCtGYn(tVh&=vXAxjp79hdpzO}|DIuR-^kYdoc2t+pdxA|1fc1p zW`i^G>`S@1@;!puo`RrxQ?Sk00AsIag)YxYFl|8;TP#3Up4MP(@jSL9rw&QLT$y?o zouD&eu*;fQS&$B4kskGKDv48qSBCV=9R(QsduwCVaVUjgdzT!ZltYW|l6RP$K>7ka2X;i$7Oin{K=G4d;~=1W;D*1Uuv`6niA)iNG6W-CN=%> zbu@siG`Ddw6C?6_e_2rzRsK{ZA7bH{1C6juhd2l)c0p4Mr4szK2GZvkWAS+*mL)#c zm9)Bd_f9f6RgOWa+LJcADxLs3oqBhht8m)Axo_D53xC={PMjfP`^mD0Jn071sn{Gx zFk+@5DrFI(X{S(CAZ#U=Xm3j#5Yz*Dpem%u?=w~T7-MOR#PoWTmyz5h3@Hn+BP99gP{`{ z`5VwL-F<|N$U9?REMAzHoK!FY{S~Mqb#&Pxu?`mBGfo40jI;bP%n(2Yi6^6i>hhE| zr!xsKlDf}Bi5?1*4{2`$6=znvfU-zU`9E?$+3m`?K*~R(LXcQeU!a&^iW>?fA>iz+ z8SqbT`mHIo1fd7C5jCD zjwE@FqoXyy_T7ObO3)4NxJmfX>UIotaTr{5E*&|I@0r1o{Qt#o766#EV;mFu0 z#AR-#H`-#y=j4y4!n&(A)r?@dx27owaV@rl1W}YJ8RhXQme^XxRd>6v)=H81lr)f) zS8B>4B_)G9Qur1SfQw+w6nsz5SJ6@;g5?ZfwhGyS2N4lLS>o!h+$6G3u!kI!qnhL= z+cddPh9rp*7l9HjUS*=)v7=ZKk_6uM0}FkRn58=)q&Wr9sb zeeM{bg=Lb9^dLQ17rbrFTUEj1@!O2x!)P-R(>O|vaDv!XGOU)ViWl#v_#?zpYRYT+ zRZv)R7hW{PDz1xgIn+x8eo8irI%hU%(R2_Qrq7$4N>-G6haW8ze(Y>Se6vlP9cO21 zo@;rV0Q(W2_2vK)O*Uh{H%+zns$o)1e=sFHDC?{1kVq?_&kp-0sX0g4MpXDIc@Q^e z!Y$BTUkyQ}_7G}Dlis0lII2^FcVo6LAN5v}-dfqD(pSO6(87W_lARcP`0y3lWU;p8 zr?N1Dh$&ksF}LfhuEMr&j3zP`RgVZBkC}`7lGYM!G1w2m<64DdhS@)XMSzKMV{>Fe zdM{)Xj3I_MnYm&gZ5&G=_nNS`qpM1I6GuD0(m?~-kqsC$7cqFna~2#OnpFEdRWf%3 zl!i~I10eK# zRy%40qvk%;h9ZePCbukN+u%S?tA!#fQF@xAOnfxt*C0nXHbGly(-L|mMd;|fOEV&f zkdh&$=5h8=sukH04ZOLS8APN@udoP|HDlFT%e!B)g=iGKDBQwwI+Ym6IuIW(7bS~( zbT}*FNHc`$$SLQkr@e*N0+&^Dpq1=j%F%VEDzb951G6!~Zqwin0d;`YuEaDfE0mB| zw-nzl*+sY)lS?}bG8U1bAfgcMjZ2*pCRe+PaA+Tu=xd#18uy__SoDSZ+;YOi3^ua@ zg?L!#he*(r>I-cuNzE7mY^0+1#krg6-nA`mDt=#aBSo5cEJMn$bLpH{#=M?Tep;#u zOR#3+fXFFL;*!@Vn^1!2NN28Z-I2L6b2yF}IT*oH>^Sq|=++A2o~0S(ac9d)Z6^`4dg3ceh;q?PYuB=?y#r?GNaQ-TCh<-qfg|lAdxdMwOJ6Ic$cbyR)kFQc zZlTyMo7Virs)|pA>(xy`r3;-+lyBD2_{=LgpvE5KR|xcgJftT~u}wR`#YPHvqpSj{ zbSaX|Bu9r0W;+EZ?82qQM*oDAIk%lcw04%RNvGAw+-#D{;0C;IFo?;WChMi zlqL$3?9raVT;viUe~@CP3ASKuy)1SC;eB4VO&r|%jv6YEtFXPlz9H=-*=3a6{wnRm ztjdEb?@uz{U0oBey{o;HY4ER@j}zwutd_!Cd4diHW0KP%Dzi?O)>w@&yUc)d?hY{F zl0D&|SSS5=P5PpefV>anP5#S#$JwOWGzdJ(@F)2ZJj5Kk<>mzX;mK9tv-U%W{|ZUu z$;pK%`(lhw%w1T-j9tMcT;C`z8(wm#VR%VSklPz7L9r*i4lExf3#FNcq7;qLYcDHs zrSCxlS7?6Z-Z_F>hiJSN?~9@bm)g+gR&+|7PU&9W%-cwcyR;=t1wCaO34M{$sDrrjb4na~r!+rm6v3a! z1fzy0(2-IB7$1G(aEW}xWGYOqDNM`?C(I-zmaMm;H(YLZXAdMom#9@jbOiC&3))o8 zojD^De1-;(^NSahO-;f}Di=|9AJJLjc1L;?>mlW0`N4)yAHq^u3w0QIVq+FnQWpLm z^FA>*m(9Df*qo3Tl@o2cft4xYdVth4Ner1;#K>WZ&AEedV6C>6SFYaF@NjB;alCbw zxB(ot&g7pnYNm`ez8cu79f}H++uXVY6p5obxG=b&kS0WAFutIY7StriZAxxZcwQ*M z;UOl$UJHu?D9j15E)*9F_dcW=`cwCY*9%auiNw zM5E$d+7k1gIt+sVnVu+)N!rhBfZELC0>{$U6RBOUW{+GXV!Sd(j^ar7p{SjST46Y} zg1gII*xw=voC$|6kALB3*WH$qGQP#w??3zfsv4fN9}&8gKH6sOrOeGN?CTenS>Zr@O^fFd5(IAv?r8v&Gc|p zMt#kPI%P;B8y4fwS;k`Etwhv3ExzF1h9PgtLMin;uOfB}d5hAh(CRsAZ){dwRW~YL zl?~`pz|?!Ss3P ziZA-I!c2En&BTK>uEHA{f7XDrzO_L6di}4Fd{OFa-D~Y;Zf=D!J9qv`?Sw`)wCK>} zqK9JLM~>h5eGf%+q9H$! zUeOf?nk4fCinhxNTVc^MkZsrDJ;GrPlc`0EcFl=9K6~sBCfzMGZCa)rXvu076F;Zw zv`dk=QL_P#V+b?`1i~Z8f@%$gfZ!8F2LKpTp3n;sYcGVYdRJSvN+Dz;s@`r4u9UrU zWl1Ya)-_z9h0gXAXd(PRr70MKn7*yk=9<#%JH^?gxkU^qb!5*3OY9@PUCd5DIZk8c zl>CkzesZDMV~cD2t*~>@9Pz?UMId+ft_9PXc5Qn~$n=QAUc;n80{aJtXnd;4@lV z&~i)_5V0ZHme6W-&||pvJf_A3QX+hG1y8F+?+XrpWo2tjD(fKlnzUbq6H;XWhMp_# zM;N3`7qR(c73*ekaj=QS#m%J!Ehn&dGQ83q3M?Iv02M7SoKu4`k<743-r7Fc5kt+W zG2v++1+qy=L^>B0zah5mmE|RnaPZ3-{xq@Kn=akfh^bdTYYU{>VGbbD5{4l_2);tt zq&x7Gmoy2XY7N+BWDx+Dnrw97v7rAEZp4-fEpbOm(V+SyVtGu;a@1sL(O{s=T*3L- ziw{xRQE@5B5CR7w{g_!be)i*>TU%#R0JJH>WQgW95iB5gD+f4&mgw$?phxnf6js&3 z#&vk~7LLx%E=+dyQUC*_L|F>~!FVWnw^a{pM4+xJ>m^6#!80ykA~hDPt5B_%kg3A7VK5nvl_s+y7~kwVsRP1d ze--n9@RSn&$fIgyp=F!Xy$h13yj_JLolyT0u%? zWnFuHufiiDmFz{X-r%9*Iuz|ehzp$($EU@>MiLx_a6(6HtkCKj*h3W@E(7`{kaD?1 zNg@{nES6QLEvk%EuO%gtE7)(#AQEi1b(V%xt$>`gmOYDgWE%q!A4!6=O36;~AExKP ztyVp^<1#M@tfLz|uEHg@EA;I};|yu7PN^=(sK8-G z&zB&wZ6VVrAQ~-b!;(5rUKLAKJ1397x^JFI-8aRrp)XWG?rac4Mk8r0p4d1?$k3q@ z62zmO6%Z7SNHYwo;G$C|qnk!U<@gbCA_2_NBl&n9&U*e?ga)~Y-Sh7D*7`~Rr|g0y zf-oW>%J0E*2jbyj6CcA{Oq*es4R=Ke>4tFum@%{lz4FyS679k&Pq--(P6FrxGBPu6 zzX;JFrMxW#6AGL0)+0u{kZO~&W!gz2&8#9)Gpg;hhUiox)y4CY%ucEZcbYn%C_EMW ztZ;*BsE9B`>I{{ck`LGrM1(8=!wY~r`@Zn7(N2&qyU;0-tfEx4;2hE-wk#xTs}wb$ z%*qOYTayT;rGmaM4BgkJhnD6U6NB1AoUfW|;cn78P5DaeiqCi@Rre}W1J|s>o?Q`dc1sV^xguW2a z3V$MFQ*^#u*_$A6K_o32`pGaTY|67&k|$vTTNznyf}~K)FjfHuyf%bZ-G)j?RYVZu zxDha4o>=UUEQSMyghW_%s$s7de0In7at$a^nj>1HJ@kmQh8`{Ll`a+{xKZ2vRc(tV z$0s?y!rh!zty1@*7ANb;rR8PE_MOP=oEvLJ8*Q*uP0;)Hx03;n-n34gS3bKL2bsIR zw0&qP2(x*N!VICA{+35v)6anRuPZS|vSRF%JR^iD6=iaexG!Z_(kmcBt=82&)6}HQ zP(+oA9K_o0?V%#%uq!7jMY`mPm;SlS_CuK&66I#)PV)95<|fa!CN7>iLmo{_XQRx(4isqS4i2|@^23Zg2vi6l20u$u?>lojGGHUY~}qa4piESfA6G7^tO zN>h6fTQjs)l@guTF~XI>6{$N_MfvGkCCkt-o&1=PsFSVj_9tz@{u!fwJS{httac}@ zo$)cyBKw~p+w!jY(ug2+^Go5Rmek zc9K)-giErWwV8r9WzG9Ckwo9FMx2Iq<=hI(<~>j%(_odQV$Y1&Ab=u?tkz_|wxaJ< zF!M?EVllEUVHrBd&pYJ>aS#$XvD}+Z?xe)MCTt5{HH!u~UY{bm+zLyUInqW1$5{_^ zYvoR71T~g+(KOce!clTVO1_$>$jiHQ{*tkkx-m!~XeHMmbsCU2qymJ@+mU8M|I=%c z%ydAkV3PPT2jj6}rj(49$WazEV3&@E$|?{7aGg44aRpJodBs^@>mD?Rx;SYvXXFhe zd9XWsNP@dXQyUwc^2P=|23h!4#>Uu0)UJ-nI96Z4dU8b;mGmIyF?A4g-YI3#h0Q9K zl$GWbAi5Z&084U|oaySuGRLm6@2F-4Q4oQ~%yFm8mzxSoHM{wAvMaRuPk1fw{DcpvdCP!IDSK&# z8DvqBV(U%QC;p6$OY%<7CFB;r6v63ez^6@Q3}S@mhXdqW!y3fgesFH_yIeCRl{Lr1X+W^{O;LjIMu{(yNv%stOc)VcbzV5?RqwW z0jP`Zkq4I(S$~-103oq|p8V!1*xLp3K?^Ci&Af#5D)SW_$Yu+ARRpk-uqeufaNBEd zsv-a`9Fb6X%1&?!tGSxi>E)b^=G+I>imM_9BCa;`X_s5N<&~y};IAbM->9Qx`jAo$ zamuh*Q^E%ZY~d_9Cge3werI}7<~!sO_6oWTJ#{2!C-(#JV*)?4O%s~bG)lHMLJ1X? z(7VbK>D@@SbICUyK7Cp3__pxs+&HIxp3!~^M++P+6&VXbEr_aDhd9=%iDD%X)oWt` ztl5t1>E#&VM2QcRXHn}~!orZ0DCkHAK~iBv2gPAl-koPF#Z0x3kVth^z`2k;*IwP& zT}daxX-Crbn`{gu6?cG}Qv-O|I-L=}sIVY6DGn5;DF+7B;* z5jUMvFvim?J}NAg^&B_A3ALd>+VzX^&pS^d1G<3a77;cbLlY9*jp!_ATV(s-_5#5;)@BdM6=ne~ zlx|+)z9c=?D=8@?hC>M4IEsYaRbVr?3fI5((J5R2XPSq!`|eWGpM=nvI!at2xjXT8 z=t@10#sSSKb~_e5Og&Gre14gYIMs$dQf0j{8l1FB9x*Z9XqbLZMGo_tTX2L%RZy$gXvI9&N$Orm1fxa%%x;_iCr{9Z9mBJldw zYI{mVWb#GiLMo?5*-~O6WnR_hhEGEDsRf)rcPRz4&nZSC#@-V>Il;(No2iC?v>3*0 z(7sHoQ4l{^k^}>}YmrD|xI^%(m50@043*;}gz5RK_m~rx%Mg*`#8}}M&ly??=kYFxMykwvdL>Jjep`JoHAtA=RX(Gik&9G6_9vvY(T6m49 zQ9YV=OppMEz{k^oPSL|@Zek`4oe%81$M2|4aCEF5F&A-weDxajF*nitEi3sq}m zN1@E{QWG|@Q`+OL$ z7IoNZ$JwGscuS=Kq@QQUle8_z0J4{rvWHXSIlwJW$)SaSEDm>_INNShM3HTQ=|TZg zaZELE4NDQoGMprFUy?JgrO*a`s;mh}7-Ic*X7ZetX6N){*pJw1kWn=g;GV%bM1Zza zoJ�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%0DK>Sx!=8g_AgzkF7%Vky@s!Bijs+K2J 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
RFn|3)E84bTL{z1Oe)Oe^92i2qv^83fl|r7 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

nUJQFd?~CnuaIUN#2%oa`$@kY;&2*3Ry>6k-QrP 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 DmV7~? diff --git a/roms/seabios-hppa b/roms/seabios-hppa index 763e3b7349..fd5b6cf823 160000 --- a/roms/seabios-hppa +++ b/roms/seabios-hppa @@ -1 +1 @@ -Subproject commit 763e3b73499db5fef94087bd310bfc8ccbcf7858 +Subproject commit fd5b6cf82369a1e53d68302fb6ede2b9e2afccd1 From 605a16a7621c139f7e112538d7773bb60108cef7 Mon Sep 17 00:00:00 2001 From: "Dr. David Alan Gilbert" Date: Thu, 4 May 2023 12:12:42 -0700 Subject: [PATCH 0670/1077] virtio: Add shared memory capability Define a new capability type 'VIRTIO_PCI_CAP_SHARED_MEMORY_CFG' to allow defining shared memory regions with sizes and offsets of 2^32 and more. Multiple instances of the capability are allowed and distinguished by a device-specific 'id'. Signed-off-by: Dr. David Alan Gilbert Signed-off-by: Antonio Caggiano Signed-off-by: Gurchetan Singh Tested-by: Alyssa Ross Tested-by: Huang Rui Tested-by: Akihiko Odaki Acked-by: Huang Rui Reviewed-by: Gurchetan Singh Reviewed-by: Akihiko Odaki --- hw/virtio/virtio-pci.c | 18 ++++++++++++++++++ include/hw/virtio/virtio-pci.h | 4 ++++ 2 files changed, 22 insertions(+) diff --git a/hw/virtio/virtio-pci.c b/hw/virtio/virtio-pci.c index abebd0075a..af1f4bc187 100644 --- a/hw/virtio/virtio-pci.c +++ b/hw/virtio/virtio-pci.c @@ -1435,6 +1435,24 @@ static int virtio_pci_add_mem_cap(VirtIOPCIProxy *proxy, return offset; } +int virtio_pci_add_shm_cap(VirtIOPCIProxy *proxy, + uint8_t bar, uint64_t offset, uint64_t length, + uint8_t id) +{ + struct virtio_pci_cap64 cap = { + .cap.cap_len = sizeof cap, + .cap.cfg_type = VIRTIO_PCI_CAP_SHARED_MEMORY_CFG, + }; + + cap.cap.bar = bar; + cap.cap.length = cpu_to_le32(length); + cap.length_hi = cpu_to_le32(length >> 32); + cap.cap.offset = cpu_to_le32(offset); + cap.offset_hi = cpu_to_le32(offset >> 32); + cap.cap.id = id; + return virtio_pci_add_mem_cap(proxy, &cap.cap); +} + static uint64_t virtio_pci_common_read(void *opaque, hwaddr addr, unsigned size) { diff --git a/include/hw/virtio/virtio-pci.h b/include/hw/virtio/virtio-pci.h index ab2051b64b..5a3f182f99 100644 --- a/include/hw/virtio/virtio-pci.h +++ b/include/hw/virtio/virtio-pci.h @@ -264,4 +264,8 @@ unsigned virtio_pci_optimal_num_queues(unsigned fixed_queues); void virtio_pci_set_guest_notifier_fd_handler(VirtIODevice *vdev, VirtQueue *vq, int n, bool assign, bool with_irqfd); + +int virtio_pci_add_shm_cap(VirtIOPCIProxy *proxy, uint8_t bar, uint64_t offset, + uint64_t length, uint8_t id); + #endif From 17b98f46b97037d7390057bc0dc5d2c579599c12 Mon Sep 17 00:00:00 2001 From: Antonio Caggiano Date: Thu, 4 May 2023 12:12:43 -0700 Subject: [PATCH 0671/1077] virtio-gpu: CONTEXT_INIT feature MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The feature can be enabled when a backend wants it. Signed-off-by: Antonio Caggiano Signed-off-by: Gurchetan Singh Tested-by: Alyssa Ross Tested-by: Akihiko Odaki Tested-by: Huang Rui Acked-by: Huang Rui Reviewed-by: Marc-André Lureau Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Akihiko Odaki --- hw/display/virtio-gpu-base.c | 3 +++ include/hw/virtio/virtio-gpu.h | 3 +++ 2 files changed, 6 insertions(+) diff --git a/hw/display/virtio-gpu-base.c b/hw/display/virtio-gpu-base.c index ca1fb7b16f..4f2b0ba1f3 100644 --- a/hw/display/virtio-gpu-base.c +++ b/hw/display/virtio-gpu-base.c @@ -232,6 +232,9 @@ virtio_gpu_base_get_features(VirtIODevice *vdev, uint64_t features, if (virtio_gpu_blob_enabled(g->conf)) { features |= (1 << VIRTIO_GPU_F_RESOURCE_BLOB); } + if (virtio_gpu_context_init_enabled(g->conf)) { + features |= (1 << VIRTIO_GPU_F_CONTEXT_INIT); + } return features; } diff --git a/include/hw/virtio/virtio-gpu.h b/include/hw/virtio/virtio-gpu.h index 390c4642b8..8377c365ef 100644 --- a/include/hw/virtio/virtio-gpu.h +++ b/include/hw/virtio/virtio-gpu.h @@ -93,6 +93,7 @@ enum virtio_gpu_base_conf_flags { VIRTIO_GPU_FLAG_EDID_ENABLED, VIRTIO_GPU_FLAG_DMABUF_ENABLED, VIRTIO_GPU_FLAG_BLOB_ENABLED, + VIRTIO_GPU_FLAG_CONTEXT_INIT_ENABLED, }; #define virtio_gpu_virgl_enabled(_cfg) \ @@ -105,6 +106,8 @@ enum virtio_gpu_base_conf_flags { (_cfg.flags & (1 << VIRTIO_GPU_FLAG_DMABUF_ENABLED)) #define virtio_gpu_blob_enabled(_cfg) \ (_cfg.flags & (1 << VIRTIO_GPU_FLAG_BLOB_ENABLED)) +#define virtio_gpu_context_init_enabled(_cfg) \ + (_cfg.flags & (1 << VIRTIO_GPU_FLAG_CONTEXT_INIT_ENABLED)) struct virtio_gpu_base_conf { uint32_t max_outputs; From ba62dfa7075c72ec9506ea461a41e8e2a545c692 Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Sun, 12 Mar 2023 17:22:28 +0800 Subject: [PATCH 0672/1077] virtio-gpu: hostmem Use VIRTIO_GPU_SHM_ID_HOST_VISIBLE as id for virtio-gpu. Signed-off-by: Antonio Caggiano Tested-by: Alyssa Ross Tested-by: Akihiko Odaki Tested-by: Huang Rui Acked-by: Huang Rui Acked-by: Michael S. Tsirkin Reviewed-by: Akihiko Odaki --- hw/display/virtio-gpu-pci.c | 14 ++++++++++++++ hw/display/virtio-gpu.c | 1 + hw/display/virtio-vga.c | 33 ++++++++++++++++++++++++--------- include/hw/virtio/virtio-gpu.h | 5 +++++ 4 files changed, 44 insertions(+), 9 deletions(-) diff --git a/hw/display/virtio-gpu-pci.c b/hw/display/virtio-gpu-pci.c index 93f214ff58..da6a99f038 100644 --- a/hw/display/virtio-gpu-pci.c +++ b/hw/display/virtio-gpu-pci.c @@ -33,6 +33,20 @@ static void virtio_gpu_pci_base_realize(VirtIOPCIProxy *vpci_dev, Error **errp) DeviceState *vdev = DEVICE(g); int i; + if (virtio_gpu_hostmem_enabled(g->conf)) { + vpci_dev->msix_bar_idx = 1; + vpci_dev->modern_mem_bar_idx = 2; + memory_region_init(&g->hostmem, OBJECT(g), "virtio-gpu-hostmem", + g->conf.hostmem); + pci_register_bar(&vpci_dev->pci_dev, 4, + PCI_BASE_ADDRESS_SPACE_MEMORY | + PCI_BASE_ADDRESS_MEM_PREFETCH | + PCI_BASE_ADDRESS_MEM_TYPE_64, + &g->hostmem); + virtio_pci_add_shm_cap(vpci_dev, 4, 0, g->conf.hostmem, + VIRTIO_GPU_SHM_ID_HOST_VISIBLE); + } + virtio_pci_force_virtio_1(vpci_dev); if (!qdev_realize(vdev, BUS(&vpci_dev->bus), errp)) { return; diff --git a/hw/display/virtio-gpu.c b/hw/display/virtio-gpu.c index 93857ad523..5585558855 100644 --- a/hw/display/virtio-gpu.c +++ b/hw/display/virtio-gpu.c @@ -1511,6 +1511,7 @@ static Property virtio_gpu_properties[] = { 256 * MiB), DEFINE_PROP_BIT("blob", VirtIOGPU, parent_obj.conf.flags, VIRTIO_GPU_FLAG_BLOB_ENABLED, false), + DEFINE_PROP_SIZE("hostmem", VirtIOGPU, parent_obj.conf.hostmem, 0), DEFINE_PROP_END_OF_LIST(), }; diff --git a/hw/display/virtio-vga.c b/hw/display/virtio-vga.c index e6fb0aa876..c8552ff760 100644 --- a/hw/display/virtio-vga.c +++ b/hw/display/virtio-vga.c @@ -115,17 +115,32 @@ static void virtio_vga_base_realize(VirtIOPCIProxy *vpci_dev, Error **errp) pci_register_bar(&vpci_dev->pci_dev, 0, PCI_BASE_ADDRESS_MEM_PREFETCH, &vga->vram); - /* - * Configure virtio bar and regions - * - * We use bar #2 for the mmio regions, to be compatible with stdvga. - * virtio regions are moved to the end of bar #2, to make room for - * the stdvga mmio registers at the start of bar #2. - */ - vpci_dev->modern_mem_bar_idx = 2; - vpci_dev->msix_bar_idx = 4; vpci_dev->modern_io_bar_idx = 5; + if (!virtio_gpu_hostmem_enabled(g->conf)) { + /* + * Configure virtio bar and regions + * + * We use bar #2 for the mmio regions, to be compatible with stdvga. + * virtio regions are moved to the end of bar #2, to make room for + * the stdvga mmio registers at the start of bar #2. + */ + vpci_dev->modern_mem_bar_idx = 2; + vpci_dev->msix_bar_idx = 4; + } else { + vpci_dev->msix_bar_idx = 1; + vpci_dev->modern_mem_bar_idx = 2; + memory_region_init(&g->hostmem, OBJECT(g), "virtio-gpu-hostmem", + g->conf.hostmem); + pci_register_bar(&vpci_dev->pci_dev, 4, + PCI_BASE_ADDRESS_SPACE_MEMORY | + PCI_BASE_ADDRESS_MEM_PREFETCH | + PCI_BASE_ADDRESS_MEM_TYPE_64, + &g->hostmem); + virtio_pci_add_shm_cap(vpci_dev, 4, 0, g->conf.hostmem, + VIRTIO_GPU_SHM_ID_HOST_VISIBLE); + } + if (!(vpci_dev->flags & VIRTIO_PCI_FLAG_PAGE_PER_VQ)) { /* * with page-per-vq=off there is no padding space we can use diff --git a/include/hw/virtio/virtio-gpu.h b/include/hw/virtio/virtio-gpu.h index 8377c365ef..de4f624e94 100644 --- a/include/hw/virtio/virtio-gpu.h +++ b/include/hw/virtio/virtio-gpu.h @@ -108,12 +108,15 @@ enum virtio_gpu_base_conf_flags { (_cfg.flags & (1 << VIRTIO_GPU_FLAG_BLOB_ENABLED)) #define virtio_gpu_context_init_enabled(_cfg) \ (_cfg.flags & (1 << VIRTIO_GPU_FLAG_CONTEXT_INIT_ENABLED)) +#define virtio_gpu_hostmem_enabled(_cfg) \ + (_cfg.hostmem > 0) struct virtio_gpu_base_conf { uint32_t max_outputs; uint32_t flags; uint32_t xres; uint32_t yres; + uint64_t hostmem; }; struct virtio_gpu_ctrl_command { @@ -137,6 +140,8 @@ struct VirtIOGPUBase { int renderer_blocked; int enable; + MemoryRegion hostmem; + struct virtio_gpu_scanout scanout[VIRTIO_GPU_MAX_SCANOUTS]; int enabled_output_bitmask; From 49a8b659324fe105aaa8ed6d83c742ebace9b932 Mon Sep 17 00:00:00 2001 From: Antonio Caggiano Date: Sun, 12 Mar 2023 17:22:29 +0800 Subject: [PATCH 0673/1077] virtio-gpu: blob prep This adds preparatory functions needed to: - decode blob cmds - tracking iovecs Signed-off-by: Antonio Caggiano Signed-off-by: Dmitry Osipenko Signed-off-by: Gurchetan Singh Tested-by: Alyssa Ross Tested-by: Emmanouil Pitsidianakis Tested-by: Akihiko Odaki Tested-by: Huang Rui Acked-by: Huang Rui Reviewed-by: Emmanouil Pitsidianakis Reviewed-by: Akihiko Odaki --- hw/display/virtio-gpu.c | 10 +++------- include/hw/virtio/virtio-gpu-bswap.h | 15 +++++++++++++++ include/hw/virtio/virtio-gpu.h | 5 +++++ 3 files changed, 23 insertions(+), 7 deletions(-) diff --git a/hw/display/virtio-gpu.c b/hw/display/virtio-gpu.c index 5585558855..be16efbd38 100644 --- a/hw/display/virtio-gpu.c +++ b/hw/display/virtio-gpu.c @@ -33,15 +33,11 @@ #define VIRTIO_GPU_VM_VERSION 1 -static struct virtio_gpu_simple_resource* -virtio_gpu_find_resource(VirtIOGPU *g, uint32_t resource_id); static struct virtio_gpu_simple_resource * virtio_gpu_find_check_resource(VirtIOGPU *g, uint32_t resource_id, bool require_backing, const char *caller, uint32_t *error); -static void virtio_gpu_cleanup_mapping(VirtIOGPU *g, - struct virtio_gpu_simple_resource *res); static void virtio_gpu_reset_bh(void *opaque); void virtio_gpu_update_cursor_data(VirtIOGPU *g, @@ -116,7 +112,7 @@ static void update_cursor(VirtIOGPU *g, struct virtio_gpu_update_cursor *cursor) cursor->resource_id ? 1 : 0); } -static struct virtio_gpu_simple_resource * +struct virtio_gpu_simple_resource * virtio_gpu_find_resource(VirtIOGPU *g, uint32_t resource_id) { struct virtio_gpu_simple_resource *res; @@ -904,8 +900,8 @@ void virtio_gpu_cleanup_mapping_iov(VirtIOGPU *g, g_free(iov); } -static void virtio_gpu_cleanup_mapping(VirtIOGPU *g, - struct virtio_gpu_simple_resource *res) +void virtio_gpu_cleanup_mapping(VirtIOGPU *g, + struct virtio_gpu_simple_resource *res) { virtio_gpu_cleanup_mapping_iov(g, res->iov, res->iov_cnt); res->iov = NULL; diff --git a/include/hw/virtio/virtio-gpu-bswap.h b/include/hw/virtio/virtio-gpu-bswap.h index 637a0585d0..dd1975e2d4 100644 --- a/include/hw/virtio/virtio-gpu-bswap.h +++ b/include/hw/virtio/virtio-gpu-bswap.h @@ -70,6 +70,21 @@ virtio_gpu_create_blob_bswap(struct virtio_gpu_resource_create_blob *cblob) le64_to_cpus(&cblob->size); } +static inline void +virtio_gpu_map_blob_bswap(struct virtio_gpu_resource_map_blob *mblob) +{ + virtio_gpu_ctrl_hdr_bswap(&mblob->hdr); + le32_to_cpus(&mblob->resource_id); + le64_to_cpus(&mblob->offset); +} + +static inline void +virtio_gpu_unmap_blob_bswap(struct virtio_gpu_resource_unmap_blob *ublob) +{ + virtio_gpu_ctrl_hdr_bswap(&ublob->hdr); + le32_to_cpus(&ublob->resource_id); +} + static inline void virtio_gpu_scanout_blob_bswap(struct virtio_gpu_set_scanout_blob *ssb) { diff --git a/include/hw/virtio/virtio-gpu.h b/include/hw/virtio/virtio-gpu.h index de4f624e94..55973e112f 100644 --- a/include/hw/virtio/virtio-gpu.h +++ b/include/hw/virtio/virtio-gpu.h @@ -257,6 +257,9 @@ void virtio_gpu_base_fill_display_info(VirtIOGPUBase *g, void virtio_gpu_base_generate_edid(VirtIOGPUBase *g, int scanout, struct virtio_gpu_resp_edid *edid); /* virtio-gpu.c */ +struct virtio_gpu_simple_resource * +virtio_gpu_find_resource(VirtIOGPU *g, uint32_t resource_id); + void virtio_gpu_ctrl_response(VirtIOGPU *g, struct virtio_gpu_ctrl_command *cmd, struct virtio_gpu_ctrl_hdr *resp, @@ -275,6 +278,8 @@ int virtio_gpu_create_mapping_iov(VirtIOGPU *g, uint32_t *niov); void virtio_gpu_cleanup_mapping_iov(VirtIOGPU *g, struct iovec *iov, uint32_t count); +void virtio_gpu_cleanup_mapping(VirtIOGPU *g, + struct virtio_gpu_simple_resource *res); void virtio_gpu_process_cmdq(VirtIOGPU *g); void virtio_gpu_device_realize(DeviceState *qdev, Error **errp); void virtio_gpu_reset(VirtIODevice *vdev); From ac8767c7436b1328a4173b032d61f1f53f369d9b Mon Sep 17 00:00:00 2001 From: Gurchetan Singh Date: Tue, 21 Mar 2023 15:57:06 -0700 Subject: [PATCH 0674/1077] gfxstream + rutabaga prep: added need defintions, fields, and options This modifies the common virtio-gpu.h file have the fields and defintions needed by gfxstream/rutabaga, by VirtioGpuRutabaga. Signed-off-by: Gurchetan Singh Tested-by: Alyssa Ross Tested-by: Emmanouil Pitsidianakis Tested-by: Akihiko Odaki Reviewed-by: Emmanouil Pitsidianakis Reviewed-by: Antonio Caggiano Reviewed-by: Akihiko Odaki --- include/hw/virtio/virtio-gpu.h | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/include/hw/virtio/virtio-gpu.h b/include/hw/virtio/virtio-gpu.h index 55973e112f..39018377d2 100644 --- a/include/hw/virtio/virtio-gpu.h +++ b/include/hw/virtio/virtio-gpu.h @@ -38,6 +38,9 @@ OBJECT_DECLARE_SIMPLE_TYPE(VirtIOGPUGL, VIRTIO_GPU_GL) #define TYPE_VHOST_USER_GPU "vhost-user-gpu" OBJECT_DECLARE_SIMPLE_TYPE(VhostUserGPU, VHOST_USER_GPU) +#define TYPE_VIRTIO_GPU_RUTABAGA "virtio-gpu-rutabaga-device" +OBJECT_DECLARE_SIMPLE_TYPE(VirtIOGPURutabaga, VIRTIO_GPU_RUTABAGA) + struct virtio_gpu_simple_resource { uint32_t resource_id; uint32_t width; @@ -94,6 +97,7 @@ enum virtio_gpu_base_conf_flags { VIRTIO_GPU_FLAG_DMABUF_ENABLED, VIRTIO_GPU_FLAG_BLOB_ENABLED, VIRTIO_GPU_FLAG_CONTEXT_INIT_ENABLED, + VIRTIO_GPU_FLAG_RUTABAGA_ENABLED, }; #define virtio_gpu_virgl_enabled(_cfg) \ @@ -108,6 +112,8 @@ enum virtio_gpu_base_conf_flags { (_cfg.flags & (1 << VIRTIO_GPU_FLAG_BLOB_ENABLED)) #define virtio_gpu_context_init_enabled(_cfg) \ (_cfg.flags & (1 << VIRTIO_GPU_FLAG_CONTEXT_INIT_ENABLED)) +#define virtio_gpu_rutabaga_enabled(_cfg) \ + (_cfg.flags & (1 << VIRTIO_GPU_FLAG_RUTABAGA_ENABLED)) #define virtio_gpu_hostmem_enabled(_cfg) \ (_cfg.hostmem > 0) @@ -232,6 +238,27 @@ struct VhostUserGPU { bool backend_blocked; }; +#define MAX_SLOTS 4096 + +struct MemoryRegionInfo { + int used; + MemoryRegion mr; + uint32_t resource_id; +}; + +struct rutabaga; + +struct VirtIOGPURutabaga { + VirtIOGPU parent_obj; + struct MemoryRegionInfo memory_regions[MAX_SLOTS]; + uint64_t capset_mask; + char *wayland_socket_path; + char *wsi; + bool headless; + uint32_t num_capsets; + struct rutabaga *rutabaga; +}; + #define VIRTIO_GPU_FILL_CMD(out) do { \ size_t s; \ s = iov_to_buf(cmd->elem.out_sg, cmd->elem.out_num, 0, \ From 1dcc6adbc168366ece9b7fa3b68a96b475ed4ba8 Mon Sep 17 00:00:00 2001 From: Gurchetan Singh Date: Tue, 21 Mar 2023 09:47:29 -0700 Subject: [PATCH 0675/1077] gfxstream + rutabaga: add initial support for gfxstream This adds initial support for gfxstream and cross-domain. Both features rely on virtio-gpu blob resources and context types, which are also implemented in this patch. gfxstream has a long and illustrious history in Android graphics paravirtualization. It has been powering graphics in the Android Studio Emulator for more than a decade, which is the main developer platform. Originally conceived by Jesse Hall, it was first known as "EmuGL" [a]. The key design characteristic was a 1:1 threading model and auto-generation, which fit nicely with the OpenGLES spec. It also allowed easy layering with ANGLE on the host, which provides the GLES implementations on Windows or MacOS enviroments. gfxstream has traditionally been maintained by a single engineer, and between 2015 to 2021, the goldfish throne passed to Frank Yang. Historians often remark this glorious reign ("pax gfxstreama" is the academic term) was comparable to that of Augustus and both Queen Elizabeths. Just to name a few accomplishments in a resplendent panoply: higher versions of GLES, address space graphics, snapshot support and CTS compliant Vulkan [b]. One major drawback was the use of out-of-tree goldfish drivers. Android engineers didn't know much about DRM/KMS and especially TTM so a simple guest to host pipe was conceived. Luckily, virtio-gpu 3D started to emerge in 2016 due to the work of the Mesa/virglrenderer communities. In 2018, the initial virtio-gpu port of gfxstream was done by Cuttlefish enthusiast Alistair Delva. It was a symbol compatible replacement of virglrenderer [c] and named "AVDVirglrenderer". This implementation forms the basis of the current gfxstream host implementation still in use today. cross-domain support follows a similar arc. Originally conceived by Wayland aficionado David Reveman and crosvm enjoyer Zach Reizner in 2018, it initially relied on the downstream "virtio-wl" device. In 2020 and 2021, virtio-gpu was extended to include blob resources and multiple timelines by yours truly, features gfxstream/cross-domain both require to function correctly. Right now, we stand at the precipice of a truly fantastic possibility: the Android Emulator powered by upstream QEMU and upstream Linux kernel. gfxstream will then be packaged properfully, and app developers can even fix gfxstream bugs on their own if they encounter them. It's been quite the ride, my friends. Where will gfxstream head next, nobody really knows. I wouldn't be surprised if it's around for another decade, maintained by a new generation of Android graphics enthusiasts. Technical details: - Very simple initial display integration: just used Pixman - Largely, 1:1 mapping of virtio-gpu hypercalls to rutabaga function calls Next steps for Android VMs: - The next step would be improving display integration and UI interfaces with the goal of the QEMU upstream graphics being in an emulator release [d]. Next steps for Linux VMs for display virtualization: - For widespread distribution, someone needs to package Sommelier or the wayland-proxy-virtwl [e] ideally into Debian main. In addition, newer versions of the Linux kernel come with DRM_VIRTIO_GPU_KMS option, which allows disabling KMS hypercalls. If anyone cares enough, it'll probably be possible to build a custom VM variant that uses this display virtualization strategy. [a] https://android-review.googlesource.com/c/platform/development/+/34470 [b] https://android-review.googlesource.com/q/topic:%22vulkan-hostconnection-start%22 [c] https://android-review.googlesource.com/c/device/generic/goldfish-opengl/+/761927 [d] https://developer.android.com/studio/releases/emulator [e] https://github.com/talex5/wayland-proxy-virtwl Signed-off-by: Gurchetan Singh Tested-by: Alyssa Ross Tested-by: Emmanouil Pitsidianakis Tested-by: Akihiko Odaki Reviewed-by: Emmanouil Pitsidianakis Reviewed-by: Antonio Caggiano Reviewed-by: Akihiko Odaki --- hw/display/virtio-gpu-pci-rutabaga.c | 47 ++ hw/display/virtio-gpu-rutabaga.c | 1120 ++++++++++++++++++++++++++ hw/display/virtio-vga-rutabaga.c | 50 ++ 3 files changed, 1217 insertions(+) create mode 100644 hw/display/virtio-gpu-pci-rutabaga.c create mode 100644 hw/display/virtio-gpu-rutabaga.c create mode 100644 hw/display/virtio-vga-rutabaga.c diff --git a/hw/display/virtio-gpu-pci-rutabaga.c b/hw/display/virtio-gpu-pci-rutabaga.c new file mode 100644 index 0000000000..c96729e198 --- /dev/null +++ b/hw/display/virtio-gpu-pci-rutabaga.c @@ -0,0 +1,47 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +#include "qemu/osdep.h" +#include "qapi/error.h" +#include "qemu/module.h" +#include "hw/pci/pci.h" +#include "hw/qdev-properties.h" +#include "hw/virtio/virtio.h" +#include "hw/virtio/virtio-bus.h" +#include "hw/virtio/virtio-gpu-pci.h" +#include "qom/object.h" + +#define TYPE_VIRTIO_GPU_RUTABAGA_PCI "virtio-gpu-rutabaga-pci" +OBJECT_DECLARE_SIMPLE_TYPE(VirtIOGPURutabagaPCI, VIRTIO_GPU_RUTABAGA_PCI) + +struct VirtIOGPURutabagaPCI { + VirtIOGPUPCIBase parent_obj; + + VirtIOGPURutabaga vdev; +}; + +static void virtio_gpu_rutabaga_initfn(Object *obj) +{ + VirtIOGPURutabagaPCI *dev = VIRTIO_GPU_RUTABAGA_PCI(obj); + + virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev), + TYPE_VIRTIO_GPU_RUTABAGA); + VIRTIO_GPU_PCI_BASE(obj)->vgpu = VIRTIO_GPU_BASE(&dev->vdev); +} + +static const TypeInfo virtio_gpu_rutabaga_pci_info[] = { + { + .name = TYPE_VIRTIO_GPU_RUTABAGA_PCI, + .parent = TYPE_VIRTIO_GPU_PCI_BASE, + .instance_size = sizeof(VirtIOGPURutabagaPCI), + .instance_init = virtio_gpu_rutabaga_initfn, + .interfaces = (InterfaceInfo[]) { + { INTERFACE_CONVENTIONAL_PCI_DEVICE }, + } + }, +}; + +DEFINE_TYPES(virtio_gpu_rutabaga_pci_info) + +module_obj(TYPE_VIRTIO_GPU_RUTABAGA_PCI); +module_kconfig(VIRTIO_PCI); +module_dep("hw-display-virtio-gpu-pci"); diff --git a/hw/display/virtio-gpu-rutabaga.c b/hw/display/virtio-gpu-rutabaga.c new file mode 100644 index 0000000000..9e67f9bd51 --- /dev/null +++ b/hw/display/virtio-gpu-rutabaga.c @@ -0,0 +1,1120 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +#include "qemu/osdep.h" +#include "qapi/error.h" +#include "qemu/error-report.h" +#include "qemu/iov.h" +#include "trace.h" +#include "hw/virtio/virtio.h" +#include "hw/virtio/virtio-gpu.h" +#include "hw/virtio/virtio-gpu-pixman.h" +#include "hw/virtio/virtio-iommu.h" + +#include +#include + +#define CHECK(condition, cmd) \ + do { \ + if (!(condition)) { \ + error_report("CHECK failed in %s() %s:" "%d", __func__, \ + __FILE__, __LINE__); \ + (cmd)->error = VIRTIO_GPU_RESP_ERR_UNSPEC; \ + return; \ + } \ + } while (0) + +struct rutabaga_aio_data { + struct VirtIOGPURutabaga *vr; + struct rutabaga_fence fence; +}; + +static void +virtio_gpu_rutabaga_update_cursor(VirtIOGPU *g, struct virtio_gpu_scanout *s, + uint32_t resource_id) +{ + struct virtio_gpu_simple_resource *res; + struct rutabaga_transfer transfer = { 0 }; + struct iovec transfer_iovec; + + VirtIOGPURutabaga *vr = VIRTIO_GPU_RUTABAGA(g); + + res = virtio_gpu_find_resource(g, resource_id); + if (!res) { + return; + } + + if (res->width != s->current_cursor->width || + res->height != s->current_cursor->height) { + return; + } + + transfer.x = 0; + transfer.y = 0; + transfer.z = 0; + transfer.w = res->width; + transfer.h = res->height; + transfer.d = 1; + + transfer_iovec.iov_base = s->current_cursor->data; + transfer_iovec.iov_len = res->width * res->height * 4; + + rutabaga_resource_transfer_read(vr->rutabaga, 0, + resource_id, &transfer, + &transfer_iovec); +} + +static void +virtio_gpu_rutabaga_gl_flushed(VirtIOGPUBase *b) +{ + VirtIOGPU *g = VIRTIO_GPU(b); + virtio_gpu_process_cmdq(g); +} + +static void +rutabaga_cmd_create_resource_2d(VirtIOGPU *g, + struct virtio_gpu_ctrl_command *cmd) +{ + int32_t result; + struct rutabaga_create_3d rc_3d = { 0 }; + struct virtio_gpu_simple_resource *res; + struct virtio_gpu_resource_create_2d c2d; + + VirtIOGPURutabaga *vr = VIRTIO_GPU_RUTABAGA(g); + + VIRTIO_GPU_FILL_CMD(c2d); + trace_virtio_gpu_cmd_res_create_2d(c2d.resource_id, c2d.format, + c2d.width, c2d.height); + + rc_3d.target = 2; + rc_3d.format = c2d.format; + rc_3d.bind = (1 << 1); + rc_3d.width = c2d.width; + rc_3d.height = c2d.height; + rc_3d.depth = 1; + rc_3d.array_size = 1; + rc_3d.last_level = 0; + rc_3d.nr_samples = 0; + rc_3d.flags = VIRTIO_GPU_RESOURCE_FLAG_Y_0_TOP; + + result = rutabaga_resource_create_3d(vr->rutabaga, c2d.resource_id, &rc_3d); + CHECK(!result, cmd); + + res = g_new0(struct virtio_gpu_simple_resource, 1); + res->width = c2d.width; + res->height = c2d.height; + res->format = c2d.format; + res->resource_id = c2d.resource_id; + + QTAILQ_INSERT_HEAD(&g->reslist, res, next); +} + +static void +rutabaga_cmd_create_resource_3d(VirtIOGPU *g, + struct virtio_gpu_ctrl_command *cmd) +{ + int32_t result; + struct rutabaga_create_3d rc_3d = { 0 }; + struct virtio_gpu_simple_resource *res; + struct virtio_gpu_resource_create_3d c3d; + + VirtIOGPURutabaga *vr = VIRTIO_GPU_RUTABAGA(g); + + VIRTIO_GPU_FILL_CMD(c3d); + + trace_virtio_gpu_cmd_res_create_3d(c3d.resource_id, c3d.format, + c3d.width, c3d.height, c3d.depth); + + rc_3d.target = c3d.target; + rc_3d.format = c3d.format; + rc_3d.bind = c3d.bind; + rc_3d.width = c3d.width; + rc_3d.height = c3d.height; + rc_3d.depth = c3d.depth; + rc_3d.array_size = c3d.array_size; + rc_3d.last_level = c3d.last_level; + rc_3d.nr_samples = c3d.nr_samples; + rc_3d.flags = c3d.flags; + + result = rutabaga_resource_create_3d(vr->rutabaga, c3d.resource_id, &rc_3d); + CHECK(!result, cmd); + + res = g_new0(struct virtio_gpu_simple_resource, 1); + res->width = c3d.width; + res->height = c3d.height; + res->format = c3d.format; + res->resource_id = c3d.resource_id; + + QTAILQ_INSERT_HEAD(&g->reslist, res, next); +} + +static void +rutabaga_cmd_resource_unref(VirtIOGPU *g, + struct virtio_gpu_ctrl_command *cmd) +{ + int32_t result; + struct virtio_gpu_simple_resource *res; + struct virtio_gpu_resource_unref unref; + + VirtIOGPURutabaga *vr = VIRTIO_GPU_RUTABAGA(g); + + VIRTIO_GPU_FILL_CMD(unref); + + trace_virtio_gpu_cmd_res_unref(unref.resource_id); + + res = virtio_gpu_find_resource(g, unref.resource_id); + CHECK(res, cmd); + + result = rutabaga_resource_unref(vr->rutabaga, unref.resource_id); + CHECK(!result, cmd); + + if (res->image) { + pixman_image_unref(res->image); + } + + QTAILQ_REMOVE(&g->reslist, res, next); + g_free(res); +} + +static void +rutabaga_cmd_context_create(VirtIOGPU *g, + struct virtio_gpu_ctrl_command *cmd) +{ + int32_t result; + struct virtio_gpu_ctx_create cc; + + VirtIOGPURutabaga *vr = VIRTIO_GPU_RUTABAGA(g); + + VIRTIO_GPU_FILL_CMD(cc); + trace_virtio_gpu_cmd_ctx_create(cc.hdr.ctx_id, + cc.debug_name); + + result = rutabaga_context_create(vr->rutabaga, cc.hdr.ctx_id, + cc.context_init, cc.debug_name, cc.nlen); + CHECK(!result, cmd); +} + +static void +rutabaga_cmd_context_destroy(VirtIOGPU *g, + struct virtio_gpu_ctrl_command *cmd) +{ + int32_t result; + struct virtio_gpu_ctx_destroy cd; + + VirtIOGPURutabaga *vr = VIRTIO_GPU_RUTABAGA(g); + + VIRTIO_GPU_FILL_CMD(cd); + trace_virtio_gpu_cmd_ctx_destroy(cd.hdr.ctx_id); + + result = rutabaga_context_destroy(vr->rutabaga, cd.hdr.ctx_id); + CHECK(!result, cmd); +} + +static void +rutabaga_cmd_resource_flush(VirtIOGPU *g, struct virtio_gpu_ctrl_command *cmd) +{ + int32_t result, i; + struct virtio_gpu_scanout *scanout = NULL; + struct virtio_gpu_simple_resource *res; + struct rutabaga_transfer transfer = { 0 }; + struct iovec transfer_iovec; + struct virtio_gpu_resource_flush rf; + bool found = false; + + VirtIOGPUBase *vb = VIRTIO_GPU_BASE(g); + VirtIOGPURutabaga *vr = VIRTIO_GPU_RUTABAGA(g); + if (vr->headless) { + return; + } + + VIRTIO_GPU_FILL_CMD(rf); + trace_virtio_gpu_cmd_res_flush(rf.resource_id, + rf.r.width, rf.r.height, rf.r.x, rf.r.y); + + res = virtio_gpu_find_resource(g, rf.resource_id); + CHECK(res, cmd); + + for (i = 0; i < vb->conf.max_outputs; i++) { + scanout = &vb->scanout[i]; + if (i == res->scanout_bitmask) { + found = true; + break; + } + } + + if (!found) { + return; + } + + transfer.x = 0; + transfer.y = 0; + transfer.z = 0; + transfer.w = res->width; + transfer.h = res->height; + transfer.d = 1; + + transfer_iovec.iov_base = pixman_image_get_data(res->image); + transfer_iovec.iov_len = res->width * res->height * 4; + + result = rutabaga_resource_transfer_read(vr->rutabaga, 0, + rf.resource_id, &transfer, + &transfer_iovec); + CHECK(!result, cmd); + dpy_gfx_update_full(scanout->con); +} + +static void +rutabaga_cmd_set_scanout(VirtIOGPU *g, struct virtio_gpu_ctrl_command *cmd) +{ + struct virtio_gpu_simple_resource *res; + struct virtio_gpu_scanout *scanout = NULL; + struct virtio_gpu_set_scanout ss; + + VirtIOGPUBase *vb = VIRTIO_GPU_BASE(g); + VirtIOGPURutabaga *vr = VIRTIO_GPU_RUTABAGA(g); + if (vr->headless) { + return; + } + + VIRTIO_GPU_FILL_CMD(ss); + trace_virtio_gpu_cmd_set_scanout(ss.scanout_id, ss.resource_id, + ss.r.width, ss.r.height, ss.r.x, ss.r.y); + + CHECK(ss.scanout_id < VIRTIO_GPU_MAX_SCANOUTS, cmd); + scanout = &vb->scanout[ss.scanout_id]; + + if (ss.resource_id == 0) { + dpy_gfx_replace_surface(scanout->con, NULL); + dpy_gl_scanout_disable(scanout->con); + return; + } + + res = virtio_gpu_find_resource(g, ss.resource_id); + CHECK(res, cmd); + + if (!res->image) { + pixman_format_code_t pformat; + pformat = virtio_gpu_get_pixman_format(res->format); + CHECK(pformat, cmd); + + res->image = pixman_image_create_bits(pformat, + res->width, + res->height, + NULL, 0); + CHECK(res->image, cmd); + pixman_image_ref(res->image); + } + + vb->enable = 1; + + /* realloc the surface ptr */ + scanout->ds = qemu_create_displaysurface_pixman(res->image); + dpy_gfx_replace_surface(scanout->con, NULL); + dpy_gfx_replace_surface(scanout->con, scanout->ds); + res->scanout_bitmask = ss.scanout_id; +} + +static void +rutabaga_cmd_submit_3d(VirtIOGPU *g, + struct virtio_gpu_ctrl_command *cmd) +{ + int32_t result; + struct virtio_gpu_cmd_submit cs; + struct rutabaga_command rutabaga_cmd = { 0 }; + g_autofree uint8_t *buf = NULL; + size_t s; + + VirtIOGPURutabaga *vr = VIRTIO_GPU_RUTABAGA(g); + + VIRTIO_GPU_FILL_CMD(cs); + trace_virtio_gpu_cmd_ctx_submit(cs.hdr.ctx_id, cs.size); + + buf = g_new0(uint8_t, cs.size); + s = iov_to_buf(cmd->elem.out_sg, cmd->elem.out_num, + sizeof(cs), buf, cs.size); + CHECK(s == cs.size, cmd); + + rutabaga_cmd.ctx_id = cs.hdr.ctx_id; + rutabaga_cmd.cmd = buf; + rutabaga_cmd.cmd_size = cs.size; + + result = rutabaga_submit_command(vr->rutabaga, &rutabaga_cmd); + CHECK(!result, cmd); +} + +static void +rutabaga_cmd_transfer_to_host_2d(VirtIOGPU *g, + struct virtio_gpu_ctrl_command *cmd) +{ + int32_t result; + struct rutabaga_transfer transfer = { 0 }; + struct virtio_gpu_transfer_to_host_2d t2d; + + VirtIOGPURutabaga *vr = VIRTIO_GPU_RUTABAGA(g); + + VIRTIO_GPU_FILL_CMD(t2d); + trace_virtio_gpu_cmd_res_xfer_toh_2d(t2d.resource_id); + + transfer.x = t2d.r.x; + transfer.y = t2d.r.y; + transfer.z = 0; + transfer.w = t2d.r.width; + transfer.h = t2d.r.height; + transfer.d = 1; + + result = rutabaga_resource_transfer_write(vr->rutabaga, 0, t2d.resource_id, + &transfer); + CHECK(!result, cmd); +} + +static void +rutabaga_cmd_transfer_to_host_3d(VirtIOGPU *g, + struct virtio_gpu_ctrl_command *cmd) +{ + int32_t result; + struct rutabaga_transfer transfer = { 0 }; + struct virtio_gpu_transfer_host_3d t3d; + + VirtIOGPURutabaga *vr = VIRTIO_GPU_RUTABAGA(g); + + VIRTIO_GPU_FILL_CMD(t3d); + trace_virtio_gpu_cmd_res_xfer_toh_3d(t3d.resource_id); + + transfer.x = t3d.box.x; + transfer.y = t3d.box.y; + transfer.z = t3d.box.z; + transfer.w = t3d.box.w; + transfer.h = t3d.box.h; + transfer.d = t3d.box.d; + transfer.level = t3d.level; + transfer.stride = t3d.stride; + transfer.layer_stride = t3d.layer_stride; + transfer.offset = t3d.offset; + + result = rutabaga_resource_transfer_write(vr->rutabaga, t3d.hdr.ctx_id, + t3d.resource_id, &transfer); + CHECK(!result, cmd); +} + +static void +rutabaga_cmd_transfer_from_host_3d(VirtIOGPU *g, + struct virtio_gpu_ctrl_command *cmd) +{ + int32_t result; + struct rutabaga_transfer transfer = { 0 }; + struct virtio_gpu_transfer_host_3d t3d; + + VirtIOGPURutabaga *vr = VIRTIO_GPU_RUTABAGA(g); + + VIRTIO_GPU_FILL_CMD(t3d); + trace_virtio_gpu_cmd_res_xfer_fromh_3d(t3d.resource_id); + + transfer.x = t3d.box.x; + transfer.y = t3d.box.y; + transfer.z = t3d.box.z; + transfer.w = t3d.box.w; + transfer.h = t3d.box.h; + transfer.d = t3d.box.d; + transfer.level = t3d.level; + transfer.stride = t3d.stride; + transfer.layer_stride = t3d.layer_stride; + transfer.offset = t3d.offset; + + result = rutabaga_resource_transfer_read(vr->rutabaga, t3d.hdr.ctx_id, + t3d.resource_id, &transfer, NULL); + CHECK(!result, cmd); +} + +static void +rutabaga_cmd_attach_backing(VirtIOGPU *g, struct virtio_gpu_ctrl_command *cmd) +{ + struct rutabaga_iovecs vecs = { 0 }; + struct virtio_gpu_simple_resource *res; + struct virtio_gpu_resource_attach_backing att_rb; + int ret; + + VirtIOGPURutabaga *vr = VIRTIO_GPU_RUTABAGA(g); + + VIRTIO_GPU_FILL_CMD(att_rb); + trace_virtio_gpu_cmd_res_back_attach(att_rb.resource_id); + + res = virtio_gpu_find_resource(g, att_rb.resource_id); + CHECK(res, cmd); + CHECK(!res->iov, cmd); + + ret = virtio_gpu_create_mapping_iov(g, att_rb.nr_entries, sizeof(att_rb), + cmd, NULL, &res->iov, &res->iov_cnt); + CHECK(!ret, cmd); + + vecs.iovecs = res->iov; + vecs.num_iovecs = res->iov_cnt; + + ret = rutabaga_resource_attach_backing(vr->rutabaga, att_rb.resource_id, + &vecs); + if (ret != 0) { + virtio_gpu_cleanup_mapping(g, res); + } + + CHECK(!ret, cmd); +} + +static void +rutabaga_cmd_detach_backing(VirtIOGPU *g, struct virtio_gpu_ctrl_command *cmd) +{ + struct virtio_gpu_simple_resource *res; + struct virtio_gpu_resource_detach_backing detach_rb; + + VirtIOGPURutabaga *vr = VIRTIO_GPU_RUTABAGA(g); + + VIRTIO_GPU_FILL_CMD(detach_rb); + trace_virtio_gpu_cmd_res_back_detach(detach_rb.resource_id); + + res = virtio_gpu_find_resource(g, detach_rb.resource_id); + CHECK(res, cmd); + + rutabaga_resource_detach_backing(vr->rutabaga, + detach_rb.resource_id); + + virtio_gpu_cleanup_mapping(g, res); +} + +static void +rutabaga_cmd_ctx_attach_resource(VirtIOGPU *g, + struct virtio_gpu_ctrl_command *cmd) +{ + int32_t result; + struct virtio_gpu_ctx_resource att_res; + + VirtIOGPURutabaga *vr = VIRTIO_GPU_RUTABAGA(g); + + VIRTIO_GPU_FILL_CMD(att_res); + trace_virtio_gpu_cmd_ctx_res_attach(att_res.hdr.ctx_id, + att_res.resource_id); + + result = rutabaga_context_attach_resource(vr->rutabaga, att_res.hdr.ctx_id, + att_res.resource_id); + CHECK(!result, cmd); +} + +static void +rutabaga_cmd_ctx_detach_resource(VirtIOGPU *g, + struct virtio_gpu_ctrl_command *cmd) +{ + int32_t result; + struct virtio_gpu_ctx_resource det_res; + + VirtIOGPURutabaga *vr = VIRTIO_GPU_RUTABAGA(g); + + VIRTIO_GPU_FILL_CMD(det_res); + trace_virtio_gpu_cmd_ctx_res_detach(det_res.hdr.ctx_id, + det_res.resource_id); + + result = rutabaga_context_detach_resource(vr->rutabaga, det_res.hdr.ctx_id, + det_res.resource_id); + CHECK(!result, cmd); +} + +static void +rutabaga_cmd_get_capset_info(VirtIOGPU *g, struct virtio_gpu_ctrl_command *cmd) +{ + int32_t result; + struct virtio_gpu_get_capset_info info; + struct virtio_gpu_resp_capset_info resp; + + VirtIOGPURutabaga *vr = VIRTIO_GPU_RUTABAGA(g); + + VIRTIO_GPU_FILL_CMD(info); + + result = rutabaga_get_capset_info(vr->rutabaga, info.capset_index, + &resp.capset_id, &resp.capset_max_version, + &resp.capset_max_size); + CHECK(!result, cmd); + + resp.hdr.type = VIRTIO_GPU_RESP_OK_CAPSET_INFO; + virtio_gpu_ctrl_response(g, cmd, &resp.hdr, sizeof(resp)); +} + +static void +rutabaga_cmd_get_capset(VirtIOGPU *g, struct virtio_gpu_ctrl_command *cmd) +{ + int32_t result; + struct virtio_gpu_get_capset gc; + struct virtio_gpu_resp_capset *resp; + uint32_t capset_size, capset_version; + uint32_t current_id, i; + + VirtIOGPURutabaga *vr = VIRTIO_GPU_RUTABAGA(g); + + VIRTIO_GPU_FILL_CMD(gc); + for (i = 0; i < vr->num_capsets; i++) { + result = rutabaga_get_capset_info(vr->rutabaga, i, + ¤t_id, &capset_version, + &capset_size); + CHECK(!result, cmd); + + if (current_id == gc.capset_id) { + break; + } + } + + CHECK(i < vr->num_capsets, cmd); + + resp = g_malloc0(sizeof(*resp) + capset_size); + resp->hdr.type = VIRTIO_GPU_RESP_OK_CAPSET; + rutabaga_get_capset(vr->rutabaga, gc.capset_id, gc.capset_version, + resp->capset_data, capset_size); + + virtio_gpu_ctrl_response(g, cmd, &resp->hdr, sizeof(*resp) + capset_size); + g_free(resp); +} + +static void +rutabaga_cmd_resource_create_blob(VirtIOGPU *g, + struct virtio_gpu_ctrl_command *cmd) +{ + int result; + struct rutabaga_iovecs vecs = { 0 }; + g_autofree struct virtio_gpu_simple_resource *res = NULL; + struct virtio_gpu_resource_create_blob cblob; + struct rutabaga_create_blob rc_blob = { 0 }; + + VirtIOGPURutabaga *vr = VIRTIO_GPU_RUTABAGA(g); + + VIRTIO_GPU_FILL_CMD(cblob); + trace_virtio_gpu_cmd_res_create_blob(cblob.resource_id, cblob.size); + + CHECK(cblob.resource_id != 0, cmd); + + res = g_new0(struct virtio_gpu_simple_resource, 1); + + res->resource_id = cblob.resource_id; + res->blob_size = cblob.size; + + if (cblob.blob_mem != VIRTIO_GPU_BLOB_MEM_HOST3D) { + result = virtio_gpu_create_mapping_iov(g, cblob.nr_entries, + sizeof(cblob), cmd, &res->addrs, + &res->iov, &res->iov_cnt); + CHECK(!result, cmd); + } + + rc_blob.blob_id = cblob.blob_id; + rc_blob.blob_mem = cblob.blob_mem; + rc_blob.blob_flags = cblob.blob_flags; + rc_blob.size = cblob.size; + + vecs.iovecs = res->iov; + vecs.num_iovecs = res->iov_cnt; + + result = rutabaga_resource_create_blob(vr->rutabaga, cblob.hdr.ctx_id, + cblob.resource_id, &rc_blob, &vecs, + NULL); + + if (result && cblob.blob_mem != VIRTIO_GPU_BLOB_MEM_HOST3D) { + virtio_gpu_cleanup_mapping(g, res); + } + + CHECK(!result, cmd); + + QTAILQ_INSERT_HEAD(&g->reslist, res, next); + res = NULL; +} + +static void +rutabaga_cmd_resource_map_blob(VirtIOGPU *g, + struct virtio_gpu_ctrl_command *cmd) +{ + int32_t result; + uint32_t map_info = 0; + uint32_t slot = 0; + struct virtio_gpu_simple_resource *res; + struct rutabaga_mapping mapping = { 0 }; + struct virtio_gpu_resource_map_blob mblob; + struct virtio_gpu_resp_map_info resp = { 0 }; + + VirtIOGPUBase *vb = VIRTIO_GPU_BASE(g); + VirtIOGPURutabaga *vr = VIRTIO_GPU_RUTABAGA(g); + + VIRTIO_GPU_FILL_CMD(mblob); + + CHECK(mblob.resource_id != 0, cmd); + + res = virtio_gpu_find_resource(g, mblob.resource_id); + CHECK(res, cmd); + + result = rutabaga_resource_map_info(vr->rutabaga, mblob.resource_id, + &map_info); + CHECK(!result, cmd); + + /* + * RUTABAGA_MAP_ACCESS_* flags are not part of the virtio-gpu spec, but do + * exist to potentially allow the hypervisor to restrict write access to + * memory. QEMU does not need to use this functionality at the moment. + */ + resp.map_info = map_info & RUTABAGA_MAP_CACHE_MASK; + + result = rutabaga_resource_map(vr->rutabaga, mblob.resource_id, &mapping); + CHECK(!result, cmd); + + /* + * There is small risk of the MemoryRegion dereferencing the pointer after + * rutabaga unmaps it. Please see discussion here: + * + * https://lists.gnu.org/archive/html/qemu-devel/2023-09/msg05141.html + * + * It is highly unlikely to happen in practice and doesn't affect known + * use cases. However, it should be fixed and is noted here for posterity. + */ + for (slot = 0; slot < MAX_SLOTS; slot++) { + if (vr->memory_regions[slot].used) { + continue; + } + + MemoryRegion *mr = &(vr->memory_regions[slot].mr); + memory_region_init_ram_ptr(mr, OBJECT(vr), "blob", mapping.size, + mapping.ptr); + memory_region_add_subregion(&vb->hostmem, mblob.offset, mr); + vr->memory_regions[slot].resource_id = mblob.resource_id; + vr->memory_regions[slot].used = 1; + break; + } + + if (slot >= MAX_SLOTS) { + result = rutabaga_resource_unmap(vr->rutabaga, mblob.resource_id); + CHECK(!result, cmd); + } + + CHECK(slot < MAX_SLOTS, cmd); + + resp.hdr.type = VIRTIO_GPU_RESP_OK_MAP_INFO; + virtio_gpu_ctrl_response(g, cmd, &resp.hdr, sizeof(resp)); +} + +static void +rutabaga_cmd_resource_unmap_blob(VirtIOGPU *g, + struct virtio_gpu_ctrl_command *cmd) +{ + int32_t result; + uint32_t slot = 0; + struct virtio_gpu_simple_resource *res; + struct virtio_gpu_resource_unmap_blob ublob; + + VirtIOGPUBase *vb = VIRTIO_GPU_BASE(g); + VirtIOGPURutabaga *vr = VIRTIO_GPU_RUTABAGA(g); + + VIRTIO_GPU_FILL_CMD(ublob); + + CHECK(ublob.resource_id != 0, cmd); + + res = virtio_gpu_find_resource(g, ublob.resource_id); + CHECK(res, cmd); + + for (slot = 0; slot < MAX_SLOTS; slot++) { + if (vr->memory_regions[slot].resource_id != ublob.resource_id) { + continue; + } + + MemoryRegion *mr = &(vr->memory_regions[slot].mr); + memory_region_del_subregion(&vb->hostmem, mr); + + vr->memory_regions[slot].resource_id = 0; + vr->memory_regions[slot].used = 0; + break; + } + + CHECK(slot < MAX_SLOTS, cmd); + result = rutabaga_resource_unmap(vr->rutabaga, res->resource_id); + CHECK(!result, cmd); +} + +static void +virtio_gpu_rutabaga_process_cmd(VirtIOGPU *g, + struct virtio_gpu_ctrl_command *cmd) +{ + struct rutabaga_fence fence = { 0 }; + int32_t result; + + VirtIOGPURutabaga *vr = VIRTIO_GPU_RUTABAGA(g); + + VIRTIO_GPU_FILL_CMD(cmd->cmd_hdr); + + switch (cmd->cmd_hdr.type) { + case VIRTIO_GPU_CMD_CTX_CREATE: + rutabaga_cmd_context_create(g, cmd); + break; + case VIRTIO_GPU_CMD_CTX_DESTROY: + rutabaga_cmd_context_destroy(g, cmd); + break; + case VIRTIO_GPU_CMD_RESOURCE_CREATE_2D: + rutabaga_cmd_create_resource_2d(g, cmd); + break; + case VIRTIO_GPU_CMD_RESOURCE_CREATE_3D: + rutabaga_cmd_create_resource_3d(g, cmd); + break; + case VIRTIO_GPU_CMD_SUBMIT_3D: + rutabaga_cmd_submit_3d(g, cmd); + break; + case VIRTIO_GPU_CMD_TRANSFER_TO_HOST_2D: + rutabaga_cmd_transfer_to_host_2d(g, cmd); + break; + case VIRTIO_GPU_CMD_TRANSFER_TO_HOST_3D: + rutabaga_cmd_transfer_to_host_3d(g, cmd); + break; + case VIRTIO_GPU_CMD_TRANSFER_FROM_HOST_3D: + rutabaga_cmd_transfer_from_host_3d(g, cmd); + break; + case VIRTIO_GPU_CMD_RESOURCE_ATTACH_BACKING: + rutabaga_cmd_attach_backing(g, cmd); + break; + case VIRTIO_GPU_CMD_RESOURCE_DETACH_BACKING: + rutabaga_cmd_detach_backing(g, cmd); + break; + case VIRTIO_GPU_CMD_SET_SCANOUT: + rutabaga_cmd_set_scanout(g, cmd); + break; + case VIRTIO_GPU_CMD_RESOURCE_FLUSH: + rutabaga_cmd_resource_flush(g, cmd); + break; + case VIRTIO_GPU_CMD_RESOURCE_UNREF: + rutabaga_cmd_resource_unref(g, cmd); + break; + case VIRTIO_GPU_CMD_CTX_ATTACH_RESOURCE: + rutabaga_cmd_ctx_attach_resource(g, cmd); + break; + case VIRTIO_GPU_CMD_CTX_DETACH_RESOURCE: + rutabaga_cmd_ctx_detach_resource(g, cmd); + break; + case VIRTIO_GPU_CMD_GET_CAPSET_INFO: + rutabaga_cmd_get_capset_info(g, cmd); + break; + case VIRTIO_GPU_CMD_GET_CAPSET: + rutabaga_cmd_get_capset(g, cmd); + break; + case VIRTIO_GPU_CMD_GET_DISPLAY_INFO: + virtio_gpu_get_display_info(g, cmd); + break; + case VIRTIO_GPU_CMD_GET_EDID: + virtio_gpu_get_edid(g, cmd); + break; + case VIRTIO_GPU_CMD_RESOURCE_CREATE_BLOB: + rutabaga_cmd_resource_create_blob(g, cmd); + break; + case VIRTIO_GPU_CMD_RESOURCE_MAP_BLOB: + rutabaga_cmd_resource_map_blob(g, cmd); + break; + case VIRTIO_GPU_CMD_RESOURCE_UNMAP_BLOB: + rutabaga_cmd_resource_unmap_blob(g, cmd); + break; + default: + cmd->error = VIRTIO_GPU_RESP_ERR_UNSPEC; + break; + } + + if (cmd->finished) { + return; + } + if (cmd->error) { + error_report("%s: ctrl 0x%x, error 0x%x", __func__, + cmd->cmd_hdr.type, cmd->error); + virtio_gpu_ctrl_response_nodata(g, cmd, cmd->error); + return; + } + if (!(cmd->cmd_hdr.flags & VIRTIO_GPU_FLAG_FENCE)) { + virtio_gpu_ctrl_response_nodata(g, cmd, VIRTIO_GPU_RESP_OK_NODATA); + return; + } + + fence.flags = cmd->cmd_hdr.flags; + fence.ctx_id = cmd->cmd_hdr.ctx_id; + fence.fence_id = cmd->cmd_hdr.fence_id; + fence.ring_idx = cmd->cmd_hdr.ring_idx; + + trace_virtio_gpu_fence_ctrl(cmd->cmd_hdr.fence_id, cmd->cmd_hdr.type); + + result = rutabaga_create_fence(vr->rutabaga, &fence); + CHECK(!result, cmd); +} + +static void +virtio_gpu_rutabaga_aio_cb(void *opaque) +{ + struct rutabaga_aio_data *data = opaque; + VirtIOGPU *g = VIRTIO_GPU(data->vr); + struct rutabaga_fence fence_data = data->fence; + struct virtio_gpu_ctrl_command *cmd, *tmp; + + uint32_t signaled_ctx_specific = fence_data.flags & + RUTABAGA_FLAG_INFO_RING_IDX; + + QTAILQ_FOREACH_SAFE(cmd, &g->fenceq, next, tmp) { + /* + * Due to context specific timelines. + */ + uint32_t target_ctx_specific = cmd->cmd_hdr.flags & + RUTABAGA_FLAG_INFO_RING_IDX; + + if (signaled_ctx_specific != target_ctx_specific) { + continue; + } + + if (signaled_ctx_specific && + (cmd->cmd_hdr.ring_idx != fence_data.ring_idx)) { + continue; + } + + if (cmd->cmd_hdr.fence_id > fence_data.fence_id) { + continue; + } + + trace_virtio_gpu_fence_resp(cmd->cmd_hdr.fence_id); + virtio_gpu_ctrl_response_nodata(g, cmd, VIRTIO_GPU_RESP_OK_NODATA); + QTAILQ_REMOVE(&g->fenceq, cmd, next); + g_free(cmd); + } + + g_free(data); +} + +static void +virtio_gpu_rutabaga_fence_cb(uint64_t user_data, + const struct rutabaga_fence *fence) +{ + struct rutabaga_aio_data *data; + VirtIOGPU *g = (VirtIOGPU *)user_data; + VirtIOGPURutabaga *vr = VIRTIO_GPU_RUTABAGA(g); + + /* + * gfxstream and both cross-domain (and even newer versions virglrenderer: + * see VIRGL_RENDERER_ASYNC_FENCE_CB) like to signal fence completion on + * threads ("callback threads") that are different from the thread that + * processes the command queue ("main thread"). + * + * crosvm and other virtio-gpu 1.1 implementations enable callback threads + * via locking. However, on QEMU a deadlock is observed if + * virtio_gpu_ctrl_response_nodata(..) [used in the fence callback] is used + * from a thread that is not the main thread. + * + * The reason is QEMU's internal locking is designed to work with QEMU + * threads (see rcu_register_thread()) and not generic C/C++/Rust threads. + * For now, we can workaround this by scheduling the return of the + * fence descriptors on the main thread. + */ + + data = g_new0(struct rutabaga_aio_data, 1); + data->vr = vr; + data->fence = *fence; + aio_bh_schedule_oneshot(qemu_get_aio_context(), + virtio_gpu_rutabaga_aio_cb, + data); +} + +static void +virtio_gpu_rutabaga_debug_cb(uint64_t user_data, + const struct rutabaga_debug *debug) +{ + switch (debug->debug_type) { + case RUTABAGA_DEBUG_ERROR: + error_report("%s", debug->message); + break; + case RUTABAGA_DEBUG_WARN: + warn_report("%s", debug->message); + break; + case RUTABAGA_DEBUG_INFO: + info_report("%s", debug->message); + break; + default: + error_report("unknown debug type: %u", debug->debug_type); + } +} + +static bool virtio_gpu_rutabaga_init(VirtIOGPU *g, Error **errp) +{ + int result; + struct rutabaga_builder builder = { 0 }; + struct rutabaga_channel channel = { 0 }; + struct rutabaga_channels channels = { 0 }; + + VirtIOGPURutabaga *vr = VIRTIO_GPU_RUTABAGA(g); + vr->rutabaga = NULL; + + builder.wsi = RUTABAGA_WSI_SURFACELESS; + /* + * Currently, if WSI is specified, the only valid strings are "surfaceless" + * or "headless". Surfaceless doesn't create a native window surface, but + * does copy from the render target to the Pixman buffer if a virtio-gpu + * 2D hypercall is issued. Surfacless is the default. + * + * Headless is like surfaceless, but doesn't copy to the Pixman buffer. The + * use case is automated testing environments where there is no need to view + * results. + * + * In the future, more performant virtio-gpu 2D UI integration may be added. + */ + if (vr->wsi) { + if (g_str_equal(vr->wsi, "surfaceless")) { + vr->headless = false; + } else if (g_str_equal(vr->wsi, "headless")) { + vr->headless = true; + } else { + error_setg(errp, "invalid wsi option selected"); + return false; + } + } + + builder.fence_cb = virtio_gpu_rutabaga_fence_cb; + builder.debug_cb = virtio_gpu_rutabaga_debug_cb; + builder.capset_mask = vr->capset_mask; + builder.user_data = (uint64_t)g; + + /* + * If the user doesn't specify the wayland socket path, we try to infer + * the socket via a process similar to the one used by libwayland. + * libwayland does the following: + * + * 1) If $WAYLAND_DISPLAY is set, attempt to connect to + * $XDG_RUNTIME_DIR/$WAYLAND_DISPLAY + * 2) Otherwise, attempt to connect to $XDG_RUNTIME_DIR/wayland-0 + * 3) Otherwise, don't pass a wayland socket to rutabaga. If a guest + * wayland proxy is launched, it will fail to work. + */ + channel.channel_type = RUTABAGA_CHANNEL_TYPE_WAYLAND; + g_autofree gchar *path = NULL; + if (!vr->wayland_socket_path) { + const gchar *runtime_dir = g_get_user_runtime_dir(); + const gchar *display = g_getenv("WAYLAND_DISPLAY"); + if (!display) { + display = "wayland-0"; + } + + if (runtime_dir) { + path = g_build_filename(runtime_dir, display, NULL); + channel.channel_name = path; + } + } else { + channel.channel_name = vr->wayland_socket_path; + } + + if ((builder.capset_mask & (1 << RUTABAGA_CAPSET_CROSS_DOMAIN))) { + if (channel.channel_name) { + channels.channels = &channel; + channels.num_channels = 1; + builder.channels = &channels; + } + } + + result = rutabaga_init(&builder, &vr->rutabaga); + if (result) { + error_setg_errno(errp, -result, "Failed to init rutabaga"); + return false; + } + + return true; +} + +static int virtio_gpu_rutabaga_get_num_capsets(VirtIOGPU *g) +{ + int result; + uint32_t num_capsets; + VirtIOGPURutabaga *vr = VIRTIO_GPU_RUTABAGA(g); + + result = rutabaga_get_num_capsets(vr->rutabaga, &num_capsets); + if (result) { + error_report("Failed to get capsets"); + return 0; + } + vr->num_capsets = num_capsets; + return num_capsets; +} + +static void virtio_gpu_rutabaga_handle_ctrl(VirtIODevice *vdev, VirtQueue *vq) +{ + VirtIOGPU *g = VIRTIO_GPU(vdev); + struct virtio_gpu_ctrl_command *cmd; + + if (!virtio_queue_ready(vq)) { + return; + } + + cmd = virtqueue_pop(vq, sizeof(struct virtio_gpu_ctrl_command)); + while (cmd) { + cmd->vq = vq; + cmd->error = 0; + cmd->finished = false; + QTAILQ_INSERT_TAIL(&g->cmdq, cmd, next); + cmd = virtqueue_pop(vq, sizeof(struct virtio_gpu_ctrl_command)); + } + + virtio_gpu_process_cmdq(g); +} + +static void virtio_gpu_rutabaga_realize(DeviceState *qdev, Error **errp) +{ + int num_capsets; + VirtIOGPUBase *bdev = VIRTIO_GPU_BASE(qdev); + VirtIOGPU *gpudev = VIRTIO_GPU(qdev); + +#if HOST_BIG_ENDIAN + error_setg(errp, "rutabaga is not supported on bigendian platforms"); + return; +#endif + + if (!virtio_gpu_rutabaga_init(gpudev, errp)) { + return; + } + + num_capsets = virtio_gpu_rutabaga_get_num_capsets(gpudev); + if (!num_capsets) { + return; + } + + bdev->conf.flags |= (1 << VIRTIO_GPU_FLAG_RUTABAGA_ENABLED); + bdev->conf.flags |= (1 << VIRTIO_GPU_FLAG_BLOB_ENABLED); + bdev->conf.flags |= (1 << VIRTIO_GPU_FLAG_CONTEXT_INIT_ENABLED); + + bdev->virtio_config.num_capsets = num_capsets; + virtio_gpu_device_realize(qdev, errp); +} + +static Property virtio_gpu_rutabaga_properties[] = { + DEFINE_PROP_BIT64("gfxstream-vulkan", VirtIOGPURutabaga, capset_mask, + RUTABAGA_CAPSET_GFXSTREAM_VULKAN, false), + DEFINE_PROP_BIT64("cross-domain", VirtIOGPURutabaga, capset_mask, + RUTABAGA_CAPSET_CROSS_DOMAIN, false), + DEFINE_PROP_BIT64("x-gfxstream-gles", VirtIOGPURutabaga, capset_mask, + RUTABAGA_CAPSET_GFXSTREAM_GLES, false), + DEFINE_PROP_BIT64("x-gfxstream-composer", VirtIOGPURutabaga, capset_mask, + RUTABAGA_CAPSET_GFXSTREAM_COMPOSER, false), + DEFINE_PROP_STRING("wayland-socket-path", VirtIOGPURutabaga, + wayland_socket_path), + DEFINE_PROP_STRING("wsi", VirtIOGPURutabaga, wsi), + DEFINE_PROP_END_OF_LIST(), +}; + +static void virtio_gpu_rutabaga_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + VirtioDeviceClass *vdc = VIRTIO_DEVICE_CLASS(klass); + VirtIOGPUBaseClass *vbc = VIRTIO_GPU_BASE_CLASS(klass); + VirtIOGPUClass *vgc = VIRTIO_GPU_CLASS(klass); + + vbc->gl_flushed = virtio_gpu_rutabaga_gl_flushed; + vgc->handle_ctrl = virtio_gpu_rutabaga_handle_ctrl; + vgc->process_cmd = virtio_gpu_rutabaga_process_cmd; + vgc->update_cursor_data = virtio_gpu_rutabaga_update_cursor; + + vdc->realize = virtio_gpu_rutabaga_realize; + device_class_set_props(dc, virtio_gpu_rutabaga_properties); +} + +static const TypeInfo virtio_gpu_rutabaga_info[] = { + { + .name = TYPE_VIRTIO_GPU_RUTABAGA, + .parent = TYPE_VIRTIO_GPU, + .instance_size = sizeof(VirtIOGPURutabaga), + .class_init = virtio_gpu_rutabaga_class_init, + }, +}; + +DEFINE_TYPES(virtio_gpu_rutabaga_info) + +module_obj(TYPE_VIRTIO_GPU_RUTABAGA); +module_kconfig(VIRTIO_GPU); +module_dep("hw-display-virtio-gpu"); diff --git a/hw/display/virtio-vga-rutabaga.c b/hw/display/virtio-vga-rutabaga.c new file mode 100644 index 0000000000..a7bef6da24 --- /dev/null +++ b/hw/display/virtio-vga-rutabaga.c @@ -0,0 +1,50 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +#include "qemu/osdep.h" +#include "hw/pci/pci.h" +#include "hw/qdev-properties.h" +#include "hw/virtio/virtio-gpu.h" +#include "hw/display/vga.h" +#include "qapi/error.h" +#include "qemu/module.h" +#include "virtio-vga.h" +#include "qom/object.h" + +#define TYPE_VIRTIO_VGA_RUTABAGA "virtio-vga-rutabaga" + +OBJECT_DECLARE_SIMPLE_TYPE(VirtIOVGARutabaga, VIRTIO_VGA_RUTABAGA) + +struct VirtIOVGARutabaga { + VirtIOVGABase parent_obj; + + VirtIOGPURutabaga vdev; +}; + +static void virtio_vga_rutabaga_inst_initfn(Object *obj) +{ + VirtIOVGARutabaga *dev = VIRTIO_VGA_RUTABAGA(obj); + + virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev), + TYPE_VIRTIO_GPU_RUTABAGA); + VIRTIO_VGA_BASE(dev)->vgpu = VIRTIO_GPU_BASE(&dev->vdev); +} + +static VirtioPCIDeviceTypeInfo virtio_vga_rutabaga_info = { + .generic_name = TYPE_VIRTIO_VGA_RUTABAGA, + .parent = TYPE_VIRTIO_VGA_BASE, + .instance_size = sizeof(VirtIOVGARutabaga), + .instance_init = virtio_vga_rutabaga_inst_initfn, +}; +module_obj(TYPE_VIRTIO_VGA_RUTABAGA); +module_kconfig(VIRTIO_VGA); + +static void virtio_vga_register_types(void) +{ + if (have_vga) { + virtio_pci_types_register(&virtio_vga_rutabaga_info); + } +} + +type_init(virtio_vga_register_types) + +module_dep("hw-display-virtio-vga"); From cd9adbefcc6fd9bf61dcebc20dbc2507bfaebc08 Mon Sep 17 00:00:00 2001 From: Gurchetan Singh Date: Tue, 21 Mar 2023 09:47:36 -0700 Subject: [PATCH 0676/1077] gfxstream + rutabaga: meson support - Add meson detection of rutabaga_gfx - Build virtio-gpu-rutabaga.c + associated vga/pci files when present Signed-off-by: Gurchetan Singh Tested-by: Alyssa Ross Tested-by: Emmanouil Pitsidianakis Tested-by: Akihiko Odaki Reviewed-by: Emmanouil Pitsidianakis Reviewed-by: Antonio Caggiano Reviewed-by: Akihiko Odaki --- hw/display/meson.build | 22 ++++++++++++++++++++++ meson.build | 7 +++++++ meson_options.txt | 2 ++ scripts/meson-buildoptions.sh | 3 +++ 4 files changed, 34 insertions(+) diff --git a/hw/display/meson.build b/hw/display/meson.build index 05619c6968..2b64fd9f9d 100644 --- a/hw/display/meson.build +++ b/hw/display/meson.build @@ -80,6 +80,13 @@ if config_all_devices.has_key('CONFIG_VIRTIO_GPU') if_true: [files('virtio-gpu-gl.c', 'virtio-gpu-virgl.c'), pixman, virgl]) hw_display_modules += {'virtio-gpu-gl': virtio_gpu_gl_ss} endif + + if rutabaga.found() + virtio_gpu_rutabaga_ss = ss.source_set() + virtio_gpu_rutabaga_ss.add(when: ['CONFIG_VIRTIO_GPU', rutabaga], + if_true: [files('virtio-gpu-rutabaga.c'), pixman]) + hw_display_modules += {'virtio-gpu-rutabaga': virtio_gpu_rutabaga_ss} + endif endif if config_all_devices.has_key('CONFIG_VIRTIO_PCI') @@ -96,6 +103,12 @@ if config_all_devices.has_key('CONFIG_VIRTIO_PCI') if_true: [files('virtio-gpu-pci-gl.c'), pixman]) hw_display_modules += {'virtio-gpu-pci-gl': virtio_gpu_pci_gl_ss} endif + if rutabaga.found() + virtio_gpu_pci_rutabaga_ss = ss.source_set() + virtio_gpu_pci_rutabaga_ss.add(when: ['CONFIG_VIRTIO_GPU', 'CONFIG_VIRTIO_PCI', rutabaga], + if_true: [files('virtio-gpu-pci-rutabaga.c'), pixman]) + hw_display_modules += {'virtio-gpu-pci-rutabaga': virtio_gpu_pci_rutabaga_ss} + endif endif if config_all_devices.has_key('CONFIG_VIRTIO_VGA') @@ -114,6 +127,15 @@ if config_all_devices.has_key('CONFIG_VIRTIO_VGA') virtio_vga_gl_ss.add(when: 'CONFIG_ACPI', if_true: files('acpi-vga.c'), if_false: files('acpi-vga-stub.c')) hw_display_modules += {'virtio-vga-gl': virtio_vga_gl_ss} + + if rutabaga.found() + virtio_vga_rutabaga_ss = ss.source_set() + virtio_vga_rutabaga_ss.add(when: ['CONFIG_VIRTIO_VGA', rutabaga], + if_true: [files('virtio-vga-rutabaga.c'), pixman]) + virtio_vga_rutabaga_ss.add(when: 'CONFIG_ACPI', if_true: files('acpi-vga.c'), + if_false: files('acpi-vga-stub.c')) + hw_display_modules += {'virtio-vga-rutabaga': virtio_vga_rutabaga_ss} + endif endif system_ss.add(when: 'CONFIG_OMAP', if_true: files('omap_lcdc.c')) diff --git a/meson.build b/meson.build index bd65a111aa..e0d1f84b26 100644 --- a/meson.build +++ b/meson.build @@ -1046,6 +1046,12 @@ if not get_option('virglrenderer').auto() or have_system or have_vhost_user_gpu dependencies: virgl)) endif endif +rutabaga = not_found +if not get_option('rutabaga_gfx').auto() or have_system or have_vhost_user_gpu + rutabaga = dependency('rutabaga_gfx_ffi', + method: 'pkg-config', + required: get_option('rutabaga_gfx')) +endif blkio = not_found if not get_option('blkio').auto() or have_block blkio = dependency('blkio', @@ -4277,6 +4283,7 @@ summary_info += {'libtasn1': tasn1} summary_info += {'PAM': pam} summary_info += {'iconv support': iconv} summary_info += {'virgl support': virgl} +summary_info += {'rutabaga support': rutabaga} summary_info += {'blkio support': blkio} summary_info += {'curl support': curl} summary_info += {'Multipath support': mpathpersist} diff --git a/meson_options.txt b/meson_options.txt index 6a17b90968..e49309dd78 100644 --- a/meson_options.txt +++ b/meson_options.txt @@ -230,6 +230,8 @@ option('vmnet', type : 'feature', value : 'auto', description: 'vmnet.framework network backend support') option('virglrenderer', type : 'feature', value : 'auto', description: 'virgl rendering support') +option('rutabaga_gfx', type : 'feature', value : 'auto', + description: 'rutabaga_gfx support') option('png', type : 'feature', value : 'auto', description: 'PNG support with libpng') option('vnc', type : 'feature', value : 'auto', diff --git a/scripts/meson-buildoptions.sh b/scripts/meson-buildoptions.sh index 2a74b0275b..a28ccbcaf6 100644 --- a/scripts/meson-buildoptions.sh +++ b/scripts/meson-buildoptions.sh @@ -156,6 +156,7 @@ meson_options_help() { printf "%s\n" ' rbd Ceph block device driver' printf "%s\n" ' rdma Enable RDMA-based migration' printf "%s\n" ' replication replication support' + printf "%s\n" ' rutabaga-gfx rutabaga_gfx support' printf "%s\n" ' sdl SDL user interface' printf "%s\n" ' sdl-image SDL Image support for icons' printf "%s\n" ' seccomp seccomp support' @@ -425,6 +426,8 @@ _meson_option_parse() { --disable-replication) printf "%s" -Dreplication=disabled ;; --enable-rng-none) printf "%s" -Drng_none=true ;; --disable-rng-none) printf "%s" -Drng_none=false ;; + --enable-rutabaga-gfx) printf "%s" -Drutabaga_gfx=enabled ;; + --disable-rutabaga-gfx) printf "%s" -Drutabaga_gfx=disabled ;; --enable-safe-stack) printf "%s" -Dsafe_stack=true ;; --disable-safe-stack) printf "%s" -Dsafe_stack=false ;; --enable-sanitizers) printf "%s" -Dsanitizers=true ;; From 8e7b21ca16cb1109faff5cbc6a12dc5f7f4e09c1 Mon Sep 17 00:00:00 2001 From: Gurchetan Singh Date: Tue, 21 Mar 2023 16:13:29 -0700 Subject: [PATCH 0677/1077] gfxstream + rutabaga: enable rutabaga This change enables rutabaga to receive virtio-gpu-3d hypercalls when it is active. Signed-off-by: Gurchetan Singh Tested-by: Alyssa Ross Tested-by: Emmanouil Pitsidianakis Tested-by: Akihiko Odaki Reviewed-by: Antonio Caggiano Reviewed-by: Emmanouil Pitsidianakis Reviewed-by: Akihiko Odaki --- hw/display/virtio-gpu-base.c | 3 ++- hw/display/virtio-gpu.c | 5 +++-- system/qdev-monitor.c | 3 +++ system/vl.c | 1 + 4 files changed, 9 insertions(+), 3 deletions(-) diff --git a/hw/display/virtio-gpu-base.c b/hw/display/virtio-gpu-base.c index 4f2b0ba1f3..50c5373b65 100644 --- a/hw/display/virtio-gpu-base.c +++ b/hw/display/virtio-gpu-base.c @@ -223,7 +223,8 @@ virtio_gpu_base_get_features(VirtIODevice *vdev, uint64_t features, { VirtIOGPUBase *g = VIRTIO_GPU_BASE(vdev); - if (virtio_gpu_virgl_enabled(g->conf)) { + if (virtio_gpu_virgl_enabled(g->conf) || + virtio_gpu_rutabaga_enabled(g->conf)) { features |= (1 << VIRTIO_GPU_F_VIRGL); } if (virtio_gpu_edid_enabled(g->conf)) { diff --git a/hw/display/virtio-gpu.c b/hw/display/virtio-gpu.c index be16efbd38..6efd15b6ae 100644 --- a/hw/display/virtio-gpu.c +++ b/hw/display/virtio-gpu.c @@ -1363,8 +1363,9 @@ void virtio_gpu_device_realize(DeviceState *qdev, Error **errp) VirtIOGPU *g = VIRTIO_GPU(qdev); if (virtio_gpu_blob_enabled(g->parent_obj.conf)) { - if (!virtio_gpu_have_udmabuf()) { - error_setg(errp, "cannot enable blob resources without udmabuf"); + if (!virtio_gpu_rutabaga_enabled(g->parent_obj.conf) && + !virtio_gpu_have_udmabuf()) { + error_setg(errp, "need rutabaga or udmabuf for blob resources"); return; } diff --git a/system/qdev-monitor.c b/system/qdev-monitor.c index 74f4e41338..1b8005ae55 100644 --- a/system/qdev-monitor.c +++ b/system/qdev-monitor.c @@ -86,6 +86,9 @@ static const QDevAlias qdev_alias_table[] = { { "virtio-gpu-pci", "virtio-gpu", QEMU_ARCH_VIRTIO_PCI }, { "virtio-gpu-gl-device", "virtio-gpu-gl", QEMU_ARCH_VIRTIO_MMIO }, { "virtio-gpu-gl-pci", "virtio-gpu-gl", QEMU_ARCH_VIRTIO_PCI }, + { "virtio-gpu-rutabaga-device", "virtio-gpu-rutabaga", + QEMU_ARCH_VIRTIO_MMIO }, + { "virtio-gpu-rutabaga-pci", "virtio-gpu-rutabaga", QEMU_ARCH_VIRTIO_PCI }, { "virtio-input-host-device", "virtio-input-host", QEMU_ARCH_VIRTIO_MMIO }, { "virtio-input-host-ccw", "virtio-input-host", QEMU_ARCH_VIRTIO_CCW }, { "virtio-input-host-pci", "virtio-input-host", QEMU_ARCH_VIRTIO_PCI }, diff --git a/system/vl.c b/system/vl.c index ba83040675..3100ac01ed 100644 --- a/system/vl.c +++ b/system/vl.c @@ -216,6 +216,7 @@ static struct { { .driver = "ati-vga", .flag = &default_vga }, { .driver = "vhost-user-vga", .flag = &default_vga }, { .driver = "virtio-vga-gl", .flag = &default_vga }, + { .driver = "virtio-vga-rutabaga", .flag = &default_vga }, }; static QemuOptsList qemu_rtc_opts = { From 773f61e997d4f12cacb715bf8ec01bf0a40e8755 Mon Sep 17 00:00:00 2001 From: Gurchetan Singh Date: Mon, 10 Jul 2023 12:21:39 -0700 Subject: [PATCH 0678/1077] docs/system: add basic virtio-gpu documentation This adds basic documentation for virtio-gpu. Suggested-by: Akihiko Odaki Signed-off-by: Gurchetan Singh Tested-by: Alyssa Ross Tested-by: Emmanouil Pitsidianakis Tested-by: Akihiko Odaki Reviewed-by: Emmanouil Pitsidianakis Reviewed-by: Antonio Caggiano Reviewed-by: Akihiko Odaki --- docs/system/device-emulation.rst | 1 + docs/system/devices/virtio-gpu.rst | 112 +++++++++++++++++++++++++++++ 2 files changed, 113 insertions(+) create mode 100644 docs/system/devices/virtio-gpu.rst diff --git a/docs/system/device-emulation.rst b/docs/system/device-emulation.rst index 4491c4cbf7..1167f3a9f2 100644 --- a/docs/system/device-emulation.rst +++ b/docs/system/device-emulation.rst @@ -91,6 +91,7 @@ Emulated Devices devices/nvme.rst devices/usb.rst devices/vhost-user.rst + devices/virtio-gpu.rst devices/virtio-pmem.rst devices/vhost-user-rng.rst devices/canokey.rst diff --git a/docs/system/devices/virtio-gpu.rst b/docs/system/devices/virtio-gpu.rst new file mode 100644 index 0000000000..cb73dd7998 --- /dev/null +++ b/docs/system/devices/virtio-gpu.rst @@ -0,0 +1,112 @@ +.. + SPDX-License-Identifier: GPL-2.0-or-later + +virtio-gpu +========== + +This document explains the setup and usage of the virtio-gpu device. +The virtio-gpu device paravirtualizes the GPU and display controller. + +Linux kernel support +-------------------- + +virtio-gpu requires a guest Linux kernel built with the +``CONFIG_DRM_VIRTIO_GPU`` option. + +QEMU virtio-gpu variants +------------------------ + +QEMU virtio-gpu device variants come in the following form: + + * ``virtio-vga[-BACKEND]`` + * ``virtio-gpu[-BACKEND][-INTERFACE]`` + * ``vhost-user-vga`` + * ``vhost-user-pci`` + +**Backends:** QEMU provides a 2D virtio-gpu backend, and two accelerated +backends: virglrenderer ('gl' device label) and rutabaga_gfx ('rutabaga' +device label). There is a vhost-user backend that runs the graphics stack +in a separate process for improved isolation. + +**Interfaces:** QEMU further categorizes virtio-gpu device variants based +on the interface exposed to the guest. The interfaces can be classified +into VGA and non-VGA variants. The VGA ones are prefixed with virtio-vga +or vhost-user-vga while the non-VGA ones are prefixed with virtio-gpu or +vhost-user-gpu. + +The VGA ones always use the PCI interface, but for the non-VGA ones, the +user can further pick between MMIO or PCI. For MMIO, the user can suffix +the device name with -device, though vhost-user-gpu does not support MMIO. +For PCI, the user can suffix it with -pci. Without these suffixes, the +platform default will be chosen. + +virtio-gpu 2d +------------- + +The default 2D backend only performs 2D operations. The guest needs to +employ a software renderer for 3D graphics. + +Typically, the software renderer is provided by `Mesa`_ or `SwiftShader`_. +Mesa's implementations (LLVMpipe, Lavapipe and virgl below) work out of box +on typical modern Linux distributions. + +.. parsed-literal:: + -device virtio-gpu + +.. _Mesa: https://www.mesa3d.org/ +.. _SwiftShader: https://github.com/google/swiftshader + +virtio-gpu virglrenderer +------------------------ + +When using virgl accelerated graphics mode in the guest, OpenGL API calls +are translated into an intermediate representation (see `Gallium3D`_). The +intermediate representation is communicated to the host and the +`virglrenderer`_ library on the host translates the intermediate +representation back to OpenGL API calls. + +.. parsed-literal:: + -device virtio-gpu-gl + +.. _Gallium3D: https://www.freedesktop.org/wiki/Software/gallium/ +.. _virglrenderer: https://gitlab.freedesktop.org/virgl/virglrenderer/ + +virtio-gpu rutabaga +------------------- + +virtio-gpu can also leverage rutabaga_gfx to provide `gfxstream`_ +rendering and `Wayland display passthrough`_. With the gfxstream rendering +mode, GLES and Vulkan calls are forwarded to the host with minimal +modification. + +The crosvm book provides directions on how to build a `gfxstream-enabled +rutabaga`_ and launch a `guest Wayland proxy`_. + +This device does require host blob support (``hostmem`` field below). The +``hostmem`` field specifies the size of virtio-gpu host memory window. +This is typically between 256M and 8G. + +At least one virtio-gpu capability set ("capset") must be specified when +starting the device. The currently capsets supported are ``gfxstream-vulkan`` +and ``cross-domain`` for Linux guests. For Android guests, the experimental +``x-gfxstream-gles`` and ``x-gfxstream-composer`` capsets are also supported. + +The device will try to auto-detect the wayland socket path if the +``cross-domain`` capset name is set. The user may optionally specify +``wayland-socket-path`` for non-standard paths. + +The ``wsi`` option can be set to ``surfaceless`` or ``headless``. +Surfaceless doesn't create a native window surface, but does copy from the +render target to the Pixman buffer if a virtio-gpu 2D hypercall is issued. +Headless is like surfaceless, but doesn't copy to the Pixman buffer. +Surfaceless is the default if ``wsi`` is not specified. + +.. parsed-literal:: + -device virtio-gpu-rutabaga,gfxstream-vulkan=on,cross-domain=on, + hostmem=8G,wayland-socket-path=/tmp/nonstandard/mock_wayland.sock, + wsi=headless + +.. _gfxstream: https://android.googlesource.com/platform/hardware/google/gfxstream/ +.. _Wayland display passthrough: https://www.youtube.com/watch?v=OZJiHMtIQ2M +.. _gfxstream-enabled rutabaga: https://crosvm.dev/book/appendix/rutabaga_gfx.html +.. _guest Wayland proxy: https://crosvm.dev/book/devices/wayland.html From d7f5a04320187b94664539fc3aa9a87c9381a025 Mon Sep 17 00:00:00 2001 From: Wei Wang Date: Fri, 4 Aug 2023 17:30:53 +0800 Subject: [PATCH 0679/1077] migration: refactor migration_completion Current migration_completion function is a bit long. Refactor the long implementation into different subfunctions: - migration_completion_precopy: completion code related to precopy - migration_completion_postcopy: completion code related to postcopy Rename await_return_path_close_on_source to close_return_path_on_source: It is renamed to match with open_return_path_on_source. This improves readability and is easier for future updates (e.g. add new subfunctions when completion code related to new features are needed). No functional changes intended. Signed-off-by: Wei Wang Reviewed-by: Peter Xu Reviewed-by: Isaku Yamahata Reviewed-by: Juan Quintela Message-ID: <20230804093053.5037-1-wei.w.wang@intel.com> Signed-off-by: Juan Quintela --- migration/migration.c | 175 +++++++++++++++++++++++------------------- 1 file changed, 98 insertions(+), 77 deletions(-) diff --git a/migration/migration.c b/migration/migration.c index 1c6c81ad49..0e1002d017 100644 --- a/migration/migration.c +++ b/migration/migration.c @@ -99,7 +99,7 @@ static int migration_maybe_pause(MigrationState *s, int *current_active_state, int new_state); static void migrate_fd_cancel(MigrationState *s); -static int await_return_path_close_on_source(MigrationState *s); +static int close_return_path_on_source(MigrationState *s); static bool migration_needs_multiple_sockets(void) { @@ -1191,7 +1191,7 @@ static void migrate_fd_cleanup(MigrationState *s) * We already cleaned up to_dst_file, so errors from the return * path might be due to that, ignore them. */ - await_return_path_close_on_source(s); + close_return_path_on_source(s); assert(!migration_is_active(s)); @@ -2049,8 +2049,7 @@ static int open_return_path_on_source(MigrationState *ms) return 0; } -/* Returns 0 if the RP was ok, otherwise there was an error on the RP */ -static int await_return_path_close_on_source(MigrationState *ms) +static int close_return_path_on_source(MigrationState *ms) { int ret; @@ -2317,90 +2316,65 @@ static int migration_maybe_pause(MigrationState *s, return s->state == new_state ? 0 : -EINVAL; } -/** - * migration_completion: Used by migration_thread when there's not much left. - * The caller 'breaks' the loop when this returns. - * - * @s: Current migration state - */ -static void migration_completion(MigrationState *s) +static int migration_completion_precopy(MigrationState *s, + int *current_active_state) { int ret; - int current_active_state = s->state; - if (s->state == MIGRATION_STATUS_ACTIVE) { - qemu_mutex_lock_iothread(); - s->downtime_start = qemu_clock_get_ms(QEMU_CLOCK_REALTIME); - qemu_system_wakeup_request(QEMU_WAKEUP_REASON_OTHER, NULL); + qemu_mutex_lock_iothread(); + s->downtime_start = qemu_clock_get_ms(QEMU_CLOCK_REALTIME); + qemu_system_wakeup_request(QEMU_WAKEUP_REASON_OTHER, NULL); - s->vm_old_state = runstate_get(); - global_state_store(); + s->vm_old_state = runstate_get(); + global_state_store(); - ret = vm_stop_force_state(RUN_STATE_FINISH_MIGRATE); - trace_migration_completion_vm_stop(ret); - if (ret >= 0) { - ret = migration_maybe_pause(s, ¤t_active_state, - MIGRATION_STATUS_DEVICE); - } - if (ret >= 0) { - /* - * Inactivate disks except in COLO, and track that we - * have done so in order to remember to reactivate - * them if migration fails or is cancelled. - */ - s->block_inactive = !migrate_colo(); - migration_rate_set(RATE_LIMIT_DISABLED); - ret = qemu_savevm_state_complete_precopy(s->to_dst_file, false, - s->block_inactive); - } - - qemu_mutex_unlock_iothread(); - - if (ret < 0) { - goto fail; - } - } else if (s->state == MIGRATION_STATUS_POSTCOPY_ACTIVE) { - trace_migration_completion_postcopy_end(); - - qemu_mutex_lock_iothread(); - qemu_savevm_state_complete_postcopy(s->to_dst_file); - qemu_mutex_unlock_iothread(); - - /* - * Shutdown the postcopy fast path thread. This is only needed - * when dest QEMU binary is old (7.1/7.2). QEMU 8.0+ doesn't need - * this. - */ - if (migrate_postcopy_preempt() && s->preempt_pre_7_2) { - postcopy_preempt_shutdown_file(s); - } - - trace_migration_completion_postcopy_end_after_complete(); - } else { - goto fail; + ret = vm_stop_force_state(RUN_STATE_FINISH_MIGRATE); + trace_migration_completion_vm_stop(ret); + if (ret < 0) { + goto out_unlock; } - if (await_return_path_close_on_source(s)) { - goto fail; + ret = migration_maybe_pause(s, current_active_state, + MIGRATION_STATUS_DEVICE); + if (ret < 0) { + goto out_unlock; } - if (qemu_file_get_error(s->to_dst_file)) { - trace_migration_completion_file_err(); - goto fail; + /* + * Inactivate disks except in COLO, and track that we have done so in order + * to remember to reactivate them if migration fails or is cancelled. + */ + s->block_inactive = !migrate_colo(); + migration_rate_set(RATE_LIMIT_DISABLED); + ret = qemu_savevm_state_complete_precopy(s->to_dst_file, false, + s->block_inactive); +out_unlock: + qemu_mutex_unlock_iothread(); + return ret; +} + +static void migration_completion_postcopy(MigrationState *s) +{ + trace_migration_completion_postcopy_end(); + + qemu_mutex_lock_iothread(); + qemu_savevm_state_complete_postcopy(s->to_dst_file); + qemu_mutex_unlock_iothread(); + + /* + * Shutdown the postcopy fast path thread. This is only needed when dest + * QEMU binary is old (7.1/7.2). QEMU 8.0+ doesn't need this. + */ + if (migrate_postcopy_preempt() && s->preempt_pre_7_2) { + postcopy_preempt_shutdown_file(s); } - if (migrate_colo() && s->state == MIGRATION_STATUS_ACTIVE) { - /* COLO does not support postcopy */ - migrate_set_state(&s->state, MIGRATION_STATUS_ACTIVE, - MIGRATION_STATUS_COLO); - } else { - migrate_set_state(&s->state, current_active_state, - MIGRATION_STATUS_COMPLETED); - } + trace_migration_completion_postcopy_end_after_complete(); +} - return; - -fail: +static void migration_completion_failed(MigrationState *s, + int current_active_state) +{ if (s->block_inactive && (s->state == MIGRATION_STATUS_ACTIVE || s->state == MIGRATION_STATUS_DEVICE)) { /* @@ -2423,6 +2397,53 @@ fail: MIGRATION_STATUS_FAILED); } +/** + * migration_completion: Used by migration_thread when there's not much left. + * The caller 'breaks' the loop when this returns. + * + * @s: Current migration state + */ +static void migration_completion(MigrationState *s) +{ + int ret = 0; + int current_active_state = s->state; + + if (s->state == MIGRATION_STATUS_ACTIVE) { + ret = migration_completion_precopy(s, ¤t_active_state); + } else if (s->state == MIGRATION_STATUS_POSTCOPY_ACTIVE) { + migration_completion_postcopy(s); + } else { + ret = -1; + } + + if (ret < 0) { + goto fail; + } + + if (close_return_path_on_source(s)) { + goto fail; + } + + if (qemu_file_get_error(s->to_dst_file)) { + trace_migration_completion_file_err(); + goto fail; + } + + if (migrate_colo() && s->state == MIGRATION_STATUS_ACTIVE) { + /* COLO does not support postcopy */ + migrate_set_state(&s->state, MIGRATION_STATUS_ACTIVE, + MIGRATION_STATUS_COLO); + } else { + migrate_set_state(&s->state, current_active_state, + MIGRATION_STATUS_COMPLETED); + } + + return; + +fail: + migration_completion_failed(s, current_active_state); +} + /** * bg_migration_completion: Used by bg_migration_thread when after all the * RAM has been saved. The caller 'breaks' the loop when this returns. @@ -2563,7 +2584,7 @@ static MigThrError postcopy_pause(MigrationState *s) * path and just wait for the thread to finish. It will be * re-created when we resume. */ - await_return_path_close_on_source(s); + close_return_path_on_source(s); migrate_set_state(&s->state, s->state, MIGRATION_STATUS_POSTCOPY_PAUSED); From 1a36e4c9d040cb053efa10721eb4e45dcf6a321d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Wed, 11 Oct 2023 04:36:27 +0200 Subject: [PATCH 0680/1077] migration: Use g_autofree to simplify ram_dirty_bitmap_reload() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Markus Armbruster Reviewed-by: Fabiano Rosas Reviewed-by: Juan Quintela Signed-off-by: Juan Quintela Message-ID: <20231011023627.86691-1-philmd@linaro.org> --- migration/ram.c | 17 ++++++----------- 1 file changed, 6 insertions(+), 11 deletions(-) diff --git a/migration/ram.c b/migration/ram.c index 2f5ce4d60b..24d91de8b3 100644 --- a/migration/ram.c +++ b/migration/ram.c @@ -4159,7 +4159,8 @@ int ram_dirty_bitmap_reload(MigrationState *s, RAMBlock *block) int ret = -EINVAL; /* from_dst_file is always valid because we're within rp_thread */ QEMUFile *file = s->rp_state.from_dst_file; - unsigned long *le_bitmap, nbits = block->used_length >> TARGET_PAGE_BITS; + g_autofree unsigned long *le_bitmap = NULL; + unsigned long nbits = block->used_length >> TARGET_PAGE_BITS; uint64_t local_size = DIV_ROUND_UP(nbits, 8); uint64_t size, end_mark; RAMState *rs = ram_state; @@ -4188,8 +4189,7 @@ int ram_dirty_bitmap_reload(MigrationState *s, RAMBlock *block) error_report("%s: ramblock '%s' bitmap size mismatch " "(0x%"PRIx64" != 0x%"PRIx64")", __func__, block->idstr, size, local_size); - ret = -EINVAL; - goto out; + return -EINVAL; } size = qemu_get_buffer(file, (uint8_t *)le_bitmap, local_size); @@ -4200,15 +4200,13 @@ int ram_dirty_bitmap_reload(MigrationState *s, RAMBlock *block) error_report("%s: read bitmap failed for ramblock '%s': %d" " (size 0x%"PRIx64", got: 0x%"PRIx64")", __func__, block->idstr, ret, local_size, size); - ret = -EIO; - goto out; + return -EIO; } if (end_mark != RAMBLOCK_RECV_BITMAP_ENDING) { error_report("%s: ramblock '%s' end mark incorrect: 0x%"PRIx64, __func__, block->idstr, end_mark); - ret = -EINVAL; - goto out; + return -EINVAL; } /* @@ -4240,10 +4238,7 @@ int ram_dirty_bitmap_reload(MigrationState *s, RAMBlock *block) */ migration_rp_kick(s); - ret = 0; -out: - g_free(le_bitmap); - return ret; + return 0; } static int ram_resume_prepare(MigrationState *s, void *opaque) From 8b2395970aa3beab91b98dda89c7ed471e65ad25 Mon Sep 17 00:00:00 2001 From: Peter Xu Date: Tue, 10 Oct 2023 18:19:22 -0400 Subject: [PATCH 0681/1077] migration: Allow user to specify available switchover bandwidth Migration bandwidth is a very important value to live migration. It's because it's one of the major factors that we'll make decision on when to switchover to destination in a precopy process. This value is currently estimated by QEMU during the whole live migration process by monitoring how fast we were sending the data. This can be the most accurate bandwidth if in the ideal world, where we're always feeding unlimited data to the migration channel, and then it'll be limited to the bandwidth that is available. However in reality it may be very different, e.g., over a 10Gbps network we can see query-migrate showing migration bandwidth of only a few tens of MB/s just because there are plenty of other things the migration thread might be doing. For example, the migration thread can be busy scanning zero pages, or it can be fetching dirty bitmap from other external dirty sources (like vhost or KVM). It means we may not be pushing data as much as possible to migration channel, so the bandwidth estimated from "how many data we sent in the channel" can be dramatically inaccurate sometimes. With that, the decision to switchover will be affected, by assuming that we may not be able to switchover at all with such a low bandwidth, but in reality we can. The migration may not even converge at all with the downtime specified, with that wrong estimation of bandwidth, keeping iterations forever with a low estimation of bandwidth. The issue is QEMU itself may not be able to avoid those uncertainties on measuing the real "available migration bandwidth". At least not something I can think of so far. One way to fix this is when the user is fully aware of the available bandwidth, then we can allow the user to help providing an accurate value. For example, if the user has a dedicated channel of 10Gbps for migration for this specific VM, the user can specify this bandwidth so QEMU can always do the calculation based on this fact, trusting the user as long as specified. It may not be the exact bandwidth when switching over (in which case qemu will push migration data as fast as possible), but much better than QEMU trying to wildly guess, especially when very wrong. A new parameter "avail-switchover-bandwidth" is introduced just for this. So when the user specified this parameter, instead of trusting the estimated value from QEMU itself (based on the QEMUFile send speed), it trusts the user more by using this value to decide when to switchover, assuming that we'll have such bandwidth available then. Note that specifying this value will not throttle the bandwidth for switchover yet, so QEMU will always use the full bandwidth possible for sending switchover data, assuming that should always be the most important way to use the network at that time. This can resolve issues like "unconvergence migration" which is caused by hilarious low "migration bandwidth" detected for whatever reason. Reported-by: Zhiyi Guo Reviewed-by: Joao Martins Reviewed-by: Juan Quintela Signed-off-by: Peter Xu Signed-off-by: Juan Quintela Message-ID: <20231010221922.40638-1-peterx@redhat.com> --- migration/migration-hmp-cmds.c | 14 ++++++++++++++ migration/migration.c | 24 +++++++++++++++++++++--- migration/migration.h | 2 +- migration/options.c | 28 ++++++++++++++++++++++++++++ migration/options.h | 1 + migration/trace-events | 2 +- qapi/migration.json | 34 +++++++++++++++++++++++++++++++++- 7 files changed, 99 insertions(+), 6 deletions(-) diff --git a/migration/migration-hmp-cmds.c b/migration/migration-hmp-cmds.c index 5b25ba24f7..d206700a43 100644 --- a/migration/migration-hmp-cmds.c +++ b/migration/migration-hmp-cmds.c @@ -321,6 +321,10 @@ void hmp_info_migrate_parameters(Monitor *mon, const QDict *qdict) monitor_printf(mon, "%s: %" PRIu64 " bytes/second\n", MigrationParameter_str(MIGRATION_PARAMETER_MAX_BANDWIDTH), params->max_bandwidth); + assert(params->has_avail_switchover_bandwidth); + monitor_printf(mon, "%s: %" PRIu64 " bytes/second\n", + MigrationParameter_str(MIGRATION_PARAMETER_AVAIL_SWITCHOVER_BANDWIDTH), + params->avail_switchover_bandwidth); assert(params->has_downtime_limit); monitor_printf(mon, "%s: %" PRIu64 " ms\n", MigrationParameter_str(MIGRATION_PARAMETER_DOWNTIME_LIMIT), @@ -574,6 +578,16 @@ void hmp_migrate_set_parameter(Monitor *mon, const QDict *qdict) } p->max_bandwidth = valuebw; break; + case MIGRATION_PARAMETER_AVAIL_SWITCHOVER_BANDWIDTH: + p->has_avail_switchover_bandwidth = true; + ret = qemu_strtosz_MiB(valuestr, NULL, &valuebw); + if (ret < 0 || valuebw > INT64_MAX + || (size_t)valuebw != valuebw) { + error_setg(&err, "Invalid size %s", valuestr); + break; + } + p->avail_switchover_bandwidth = valuebw; + break; case MIGRATION_PARAMETER_DOWNTIME_LIMIT: p->has_downtime_limit = true; visit_type_size(v, param, &p->downtime_limit, &err); diff --git a/migration/migration.c b/migration/migration.c index 0e1002d017..ed04ca3b1c 100644 --- a/migration/migration.c +++ b/migration/migration.c @@ -2710,17 +2710,33 @@ static void migration_update_counters(MigrationState *s, { uint64_t transferred, transferred_pages, time_spent; uint64_t current_bytes; /* bytes transferred since the beginning */ + uint64_t switchover_bw; + /* Expected bandwidth when switching over to destination QEMU */ + double expected_bw_per_ms; double bandwidth; if (current_time < s->iteration_start_time + BUFFER_DELAY) { return; } + switchover_bw = migrate_avail_switchover_bandwidth(); current_bytes = migration_transferred_bytes(s->to_dst_file); transferred = current_bytes - s->iteration_initial_bytes; time_spent = current_time - s->iteration_start_time; bandwidth = (double)transferred / time_spent; - s->threshold_size = bandwidth * migrate_downtime_limit(); + + if (switchover_bw) { + /* + * If the user specified a switchover bandwidth, let's trust the + * user so that can be more accurate than what we estimated. + */ + expected_bw_per_ms = switchover_bw / 1000; + } else { + /* If the user doesn't specify bandwidth, we use the estimated */ + expected_bw_per_ms = bandwidth; + } + + s->threshold_size = expected_bw_per_ms * migrate_downtime_limit(); s->mbps = (((double) transferred * 8.0) / ((double) time_spent / 1000.0)) / 1000.0 / 1000.0; @@ -2737,7 +2753,7 @@ static void migration_update_counters(MigrationState *s, if (stat64_get(&mig_stats.dirty_pages_rate) && transferred > 10000) { s->expected_downtime = - stat64_get(&mig_stats.dirty_bytes_last_sync) / bandwidth; + stat64_get(&mig_stats.dirty_bytes_last_sync) / expected_bw_per_ms; } migration_rate_reset(s->to_dst_file); @@ -2745,7 +2761,9 @@ static void migration_update_counters(MigrationState *s, update_iteration_initial_status(s); trace_migrate_transferred(transferred, time_spent, - bandwidth, s->threshold_size); + /* Both in unit bytes/ms */ + bandwidth, switchover_bw / 1000, + s->threshold_size); } static bool migration_can_switchover(MigrationState *s) diff --git a/migration/migration.h b/migration/migration.h index cd5534337c..974897a8d0 100644 --- a/migration/migration.h +++ b/migration/migration.h @@ -294,7 +294,7 @@ struct MigrationState { /* * The final stage happens when the remaining data is smaller than * this threshold; it's calculated from the requested downtime and - * measured bandwidth + * measured bandwidth, or avail-switchover-bandwidth if specified. */ int64_t threshold_size; diff --git a/migration/options.c b/migration/options.c index 6bbfd4853d..546cbe3106 100644 --- a/migration/options.c +++ b/migration/options.c @@ -125,6 +125,8 @@ Property migration_properties[] = { parameters.cpu_throttle_tailslow, false), DEFINE_PROP_SIZE("x-max-bandwidth", MigrationState, parameters.max_bandwidth, MAX_THROTTLE), + DEFINE_PROP_SIZE("avail-switchover-bandwidth", MigrationState, + parameters.avail_switchover_bandwidth, 0), DEFINE_PROP_UINT64("x-downtime-limit", MigrationState, parameters.downtime_limit, DEFAULT_MIGRATE_SET_DOWNTIME), @@ -780,6 +782,13 @@ uint64_t migrate_max_bandwidth(void) return s->parameters.max_bandwidth; } +uint64_t migrate_avail_switchover_bandwidth(void) +{ + MigrationState *s = migrate_get_current(); + + return s->parameters.avail_switchover_bandwidth; +} + uint64_t migrate_max_postcopy_bandwidth(void) { MigrationState *s = migrate_get_current(); @@ -917,6 +926,8 @@ MigrationParameters *qmp_query_migrate_parameters(Error **errp) s->parameters.tls_authz : ""); params->has_max_bandwidth = true; params->max_bandwidth = s->parameters.max_bandwidth; + params->has_avail_switchover_bandwidth = true; + params->avail_switchover_bandwidth = s->parameters.avail_switchover_bandwidth; params->has_downtime_limit = true; params->downtime_limit = s->parameters.downtime_limit; params->has_x_checkpoint_delay = true; @@ -1056,6 +1067,15 @@ bool migrate_params_check(MigrationParameters *params, Error **errp) return false; } + if (params->has_avail_switchover_bandwidth && + (params->avail_switchover_bandwidth > SIZE_MAX)) { + error_setg(errp, QERR_INVALID_PARAMETER_VALUE, + "avail_switchover_bandwidth", + "an integer in the range of 0 to "stringify(SIZE_MAX) + " bytes/second"); + return false; + } + if (params->has_downtime_limit && (params->downtime_limit > MAX_MIGRATE_DOWNTIME)) { error_setg(errp, QERR_INVALID_PARAMETER_VALUE, @@ -1225,6 +1245,10 @@ static void migrate_params_test_apply(MigrateSetParameters *params, dest->max_bandwidth = params->max_bandwidth; } + if (params->has_avail_switchover_bandwidth) { + dest->avail_switchover_bandwidth = params->avail_switchover_bandwidth; + } + if (params->has_downtime_limit) { dest->downtime_limit = params->downtime_limit; } @@ -1341,6 +1365,10 @@ static void migrate_params_apply(MigrateSetParameters *params, Error **errp) } } + if (params->has_avail_switchover_bandwidth) { + s->parameters.avail_switchover_bandwidth = params->avail_switchover_bandwidth; + } + if (params->has_downtime_limit) { s->parameters.downtime_limit = params->downtime_limit; } diff --git a/migration/options.h b/migration/options.h index 045e2a41a2..93ee938ab8 100644 --- a/migration/options.h +++ b/migration/options.h @@ -80,6 +80,7 @@ int migrate_decompress_threads(void); uint64_t migrate_downtime_limit(void); uint8_t migrate_max_cpu_throttle(void); uint64_t migrate_max_bandwidth(void); +uint64_t migrate_avail_switchover_bandwidth(void); uint64_t migrate_max_postcopy_bandwidth(void); int migrate_multifd_channels(void); MultiFDCompression migrate_multifd_compression(void); diff --git a/migration/trace-events b/migration/trace-events index ee9c8f4d63..d8c2aa846d 100644 --- a/migration/trace-events +++ b/migration/trace-events @@ -186,7 +186,7 @@ source_return_path_thread_shut(uint32_t val) "0x%x" source_return_path_thread_resume_ack(uint32_t v) "%"PRIu32 source_return_path_thread_switchover_acked(void) "" migration_thread_low_pending(uint64_t pending) "%" PRIu64 -migrate_transferred(uint64_t transferred, uint64_t time_spent, uint64_t bandwidth, uint64_t size) "transferred %" PRIu64 " time_spent %" PRIu64 " bandwidth %" PRIu64 " max_size %" PRId64 +migrate_transferred(uint64_t transferred, uint64_t time_spent, uint64_t bandwidth, uint64_t avail_bw, uint64_t size) "transferred %" PRIu64 " time_spent %" PRIu64 " bandwidth %" PRIu64 " switchover_bw %" PRIu64 " max_size %" PRId64 process_incoming_migration_co_end(int ret, int ps) "ret=%d postcopy-state=%d" process_incoming_migration_co_postcopy_end_main(void) "" postcopy_preempt_enabled(bool value) "%d" diff --git a/qapi/migration.json b/qapi/migration.json index d7dfaa5db9..360e609f66 100644 --- a/qapi/migration.json +++ b/qapi/migration.json @@ -758,6 +758,16 @@ # @max-bandwidth: to set maximum speed for migration. maximum speed # in bytes per second. (Since 2.8) # +# @avail-switchover-bandwidth: to set the available bandwidth that +# migration can use during switchover phase. NOTE! This does not +# limit the bandwidth during switchover, but only for calculations when +# making decisions to switchover. By default, this value is zero, +# which means QEMU will estimate the bandwidth automatically. This can +# be set when the estimated value is not accurate, while the user is +# able to guarantee such bandwidth is available when switching over. +# When specified correctly, this can make the switchover decision much +# more accurate. (Since 8.2) +# # @downtime-limit: set maximum tolerated downtime for migration. # maximum downtime in milliseconds (Since 2.8) # @@ -839,7 +849,7 @@ 'cpu-throttle-initial', 'cpu-throttle-increment', 'cpu-throttle-tailslow', 'tls-creds', 'tls-hostname', 'tls-authz', 'max-bandwidth', - 'downtime-limit', + 'avail-switchover-bandwidth', 'downtime-limit', { 'name': 'x-checkpoint-delay', 'features': [ 'unstable' ] }, 'block-incremental', 'multifd-channels', @@ -924,6 +934,16 @@ # @max-bandwidth: to set maximum speed for migration. maximum speed # in bytes per second. (Since 2.8) # +# @avail-switchover-bandwidth: to set the available bandwidth that +# migration can use during switchover phase. NOTE! This does not +# limit the bandwidth during switchover, but only for calculations when +# making decisions to switchover. By default, this value is zero, +# which means QEMU will estimate the bandwidth automatically. This can +# be set when the estimated value is not accurate, while the user is +# able to guarantee such bandwidth is available when switching over. +# When specified correctly, this can make the switchover decision much +# more accurate. (Since 8.2) +# # @downtime-limit: set maximum tolerated downtime for migration. # maximum downtime in milliseconds (Since 2.8) # @@ -1017,6 +1037,7 @@ '*tls-hostname': 'StrOrNull', '*tls-authz': 'StrOrNull', '*max-bandwidth': 'size', + '*avail-switchover-bandwidth': 'size', '*downtime-limit': 'uint64', '*x-checkpoint-delay': { 'type': 'uint32', 'features': [ 'unstable' ] }, @@ -1127,6 +1148,16 @@ # @max-bandwidth: to set maximum speed for migration. maximum speed # in bytes per second. (Since 2.8) # +# @avail-switchover-bandwidth: to set the available bandwidth that +# migration can use during switchover phase. NOTE! This does not +# limit the bandwidth during switchover, but only for calculations when +# making decisions to switchover. By default, this value is zero, +# which means QEMU will estimate the bandwidth automatically. This can +# be set when the estimated value is not accurate, while the user is +# able to guarantee such bandwidth is available when switching over. +# When specified correctly, this can make the switchover decision much +# more accurate. (Since 8.2) +# # @downtime-limit: set maximum tolerated downtime for migration. # maximum downtime in milliseconds (Since 2.8) # @@ -1217,6 +1248,7 @@ '*tls-hostname': 'str', '*tls-authz': 'str', '*max-bandwidth': 'size', + '*avail-switchover-bandwidth': 'size', '*downtime-limit': 'uint64', '*x-checkpoint-delay': { 'type': 'uint32', 'features': [ 'unstable' ] }, From f75ed59f40bed3ce94adad4b3ebbb7bfacfdf4ab Mon Sep 17 00:00:00 2001 From: Dmitry Frolov Date: Tue, 10 Oct 2023 13:48:53 +0300 Subject: [PATCH 0682/1077] migration: fix RAMBlock add NULL check qemu_ram_block_from_host() may return NULL, which will be dereferenced w/o check. Usualy return value is checked for this function. Found by Linux Verification Center (linuxtesting.org) with SVACE. Signed-off-by: Dmitry Frolov Reviewed-by: Fabiano Rosas Reviewed-by: Peter Xu Reviewed-by: Juan Quintela Signed-off-by: Juan Quintela Message-ID: <20231010104851.802947-1-frolov@swemel.ru> --- migration/ram.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/migration/ram.c b/migration/ram.c index 24d91de8b3..e8df4dc862 100644 --- a/migration/ram.c +++ b/migration/ram.c @@ -4285,6 +4285,11 @@ static void ram_mig_ram_block_resized(RAMBlockNotifier *n, void *host, RAMBlock *rb = qemu_ram_block_from_host(host, false, &offset); Error *err = NULL; + if (!rb) { + error_report("RAM block not found"); + return; + } + if (migrate_ram_is_ignored(rb)) { return; } From 2aae1eb8da6560cf58fa14f6bb65d00e0304f0e0 Mon Sep 17 00:00:00 2001 From: Nikolay Borisov Date: Mon, 9 Oct 2023 15:43:21 -0300 Subject: [PATCH 0683/1077] migration: Add the configuration vmstate to the json writer Make the migration json writer part of MigrationState struct, allowing the 'configuration' object be serialized to json. This will facilitate the parsing of the 'configuration' object in the next patch that fixes analyze-migration.py for arm. Signed-off-by: Nikolay Borisov Signed-off-by: Fabiano Rosas Reviewed-by: Juan Quintela Signed-off-by: Juan Quintela Message-ID: <20231009184326.15777-2-farosas@suse.de> --- migration/migration.c | 1 + migration/savevm.c | 20 ++++++++++++++++---- 2 files changed, 17 insertions(+), 4 deletions(-) diff --git a/migration/migration.c b/migration/migration.c index ed04ca3b1c..98151b1424 100644 --- a/migration/migration.c +++ b/migration/migration.c @@ -1442,6 +1442,7 @@ int migrate_init(MigrationState *s, Error **errp) error_free(s->error); s->error = NULL; s->hostname = NULL; + s->vmdesc = NULL; migrate_set_state(&s->state, MIGRATION_STATUS_NONE, MIGRATION_STATUS_SETUP); diff --git a/migration/savevm.c b/migration/savevm.c index 497ce02bd7..bce698b0af 100644 --- a/migration/savevm.c +++ b/migration/savevm.c @@ -1217,13 +1217,27 @@ void qemu_savevm_non_migratable_list(strList **reasons) void qemu_savevm_state_header(QEMUFile *f) { + MigrationState *s = migrate_get_current(); + + s->vmdesc = json_writer_new(false); + trace_savevm_state_header(); qemu_put_be32(f, QEMU_VM_FILE_MAGIC); qemu_put_be32(f, QEMU_VM_FILE_VERSION); - if (migrate_get_current()->send_configuration) { + if (s->send_configuration) { qemu_put_byte(f, QEMU_VM_CONFIGURATION); - vmstate_save_state(f, &vmstate_configuration, &savevm_state, 0); + + /* + * This starts the main json object and is paired with the + * json_writer_end_object in + * qemu_savevm_state_complete_precopy_non_iterable + */ + json_writer_start_object(s->vmdesc, NULL); + + json_writer_start_object(s->vmdesc, "configuration"); + vmstate_save_state(f, &vmstate_configuration, &savevm_state, s->vmdesc); + json_writer_end_object(s->vmdesc); } } @@ -1272,8 +1286,6 @@ void qemu_savevm_state_setup(QEMUFile *f) Error *local_err = NULL; int ret; - ms->vmdesc = json_writer_new(false); - json_writer_start_object(ms->vmdesc, NULL); json_writer_int64(ms->vmdesc, "page_size", qemu_target_page_size()); json_writer_start_array(ms->vmdesc, "devices"); From c36c31c86b48ff4c10734ffdacf0a5712bdac216 Mon Sep 17 00:00:00 2001 From: Fabiano Rosas Date: Mon, 9 Oct 2023 15:43:22 -0300 Subject: [PATCH 0684/1077] migration: Fix analyze-migration.py 'configuration' parsing The 'configuration' state subsections are currently not being parsed and the script fails when analyzing an aarch64 stream: Traceback (most recent call last): File "./scripts/analyze-migration.py", line 625, in dump.read(dump_memory = args.memory) File "./scripts/analyze-migration.py", line 571, in read raise Exception("Unknown section type: %d" % section_type) Exception: Unknown section type: 5 Signed-off-by: Fabiano Rosas Reviewed-by: Juan Quintela Signed-off-by: Juan Quintela Message-ID: <20231009184326.15777-3-farosas@suse.de> --- scripts/analyze-migration.py | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/scripts/analyze-migration.py b/scripts/analyze-migration.py index 082424558b..24687db497 100755 --- a/scripts/analyze-migration.py +++ b/scripts/analyze-migration.py @@ -261,12 +261,21 @@ class HTABSection(object): class ConfigurationSection(object): - def __init__(self, file): + def __init__(self, file, desc): self.file = file + self.desc = desc def read(self): - name_len = self.file.read32() - name = self.file.readstr(len = name_len) + if self.desc: + version_id = self.desc['version'] + section = VMSDSection(self.file, version_id, self.desc, + 'configuration') + section.read() + else: + # backward compatibility for older streams that don't have + # the configuration section in the json + name_len = self.file.read32() + name = self.file.readstr(len = name_len) class VMSDFieldGeneric(object): def __init__(self, desc, file): @@ -532,7 +541,8 @@ class MigrationDump(object): if section_type == self.QEMU_VM_EOF: break elif section_type == self.QEMU_VM_CONFIGURATION: - section = ConfigurationSection(file) + config_desc = self.vmsd_desc.get('configuration') + section = ConfigurationSection(file, config_desc) section.read() elif section_type == self.QEMU_VM_SECTION_START or section_type == self.QEMU_VM_SECTION_FULL: section_id = file.read32() From 31499a9dc1910d695d7df4145a30e3b9ddedf8fe Mon Sep 17 00:00:00 2001 From: Fabiano Rosas Date: Mon, 9 Oct 2023 15:43:23 -0300 Subject: [PATCH 0685/1077] migration: Add capability parsing to analyze-migration.py The script is broken when the configuration/capabilities section is present. Add support for parsing the capabilities so we can fix it in the next patch. Signed-off-by: Fabiano Rosas Reviewed-by: Juan Quintela Signed-off-by: Juan Quintela Message-ID: <20231009184326.15777-4-farosas@suse.de> --- scripts/analyze-migration.py | 38 ++++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/scripts/analyze-migration.py b/scripts/analyze-migration.py index 24687db497..c700fed64d 100755 --- a/scripts/analyze-migration.py +++ b/scripts/analyze-migration.py @@ -264,6 +264,24 @@ class ConfigurationSection(object): def __init__(self, file, desc): self.file = file self.desc = desc + self.caps = [] + + def parse_capabilities(self, vmsd_caps): + if not vmsd_caps: + return + + ncaps = vmsd_caps.data['caps_count'].data + self.caps = vmsd_caps.data['capabilities'] + + if type(self.caps) != list: + self.caps = [self.caps] + + if len(self.caps) != ncaps: + raise Exception("Number of capabilities doesn't match " + "caps_count field") + + def has_capability(self, cap): + return any([str(c) == cap for c in self.caps]) def read(self): if self.desc: @@ -271,6 +289,8 @@ class ConfigurationSection(object): section = VMSDSection(self.file, version_id, self.desc, 'configuration') section.read() + self.parse_capabilities( + section.data.get("configuration/capabilities")) else: # backward compatibility for older streams that don't have # the configuration section in the json @@ -297,6 +317,23 @@ class VMSDFieldGeneric(object): self.data = self.file.readvar(size) return self.data +class VMSDFieldCap(object): + def __init__(self, desc, file): + self.file = file + self.desc = desc + self.data = "" + + def __repr__(self): + return self.data + + def __str__(self): + return self.data + + def read(self): + len = self.file.read8() + self.data = self.file.readstr(len) + + class VMSDFieldInt(VMSDFieldGeneric): def __init__(self, desc, file): super(VMSDFieldInt, self).__init__(desc, file) @@ -471,6 +508,7 @@ vmsd_field_readers = { "unused_buffer" : VMSDFieldGeneric, "bitmap" : VMSDFieldGeneric, "struct" : VMSDFieldStruct, + "capability": VMSDFieldCap, "unknown" : VMSDFieldGeneric, } From ff40c7f0b787f47cf767b39a3226a113c06930f2 Mon Sep 17 00:00:00 2001 From: Fabiano Rosas Date: Mon, 9 Oct 2023 15:43:24 -0300 Subject: [PATCH 0686/1077] migration: Fix analyze-migration.py when ignore-shared is used The script is currently broken when the x-ignore-shared capability is used: Traceback (most recent call last): File "./scripts/analyze-migration.py", line 656, in dump.read(dump_memory = args.memory) File "./scripts/analyze-migration.py", line 593, in read section.read() File "./scripts/analyze-migration.py", line 163, in read self.name = self.file.readstr(len = namelen) File "./scripts/analyze-migration.py", line 53, in readstr return self.readvar(len).decode('utf-8') UnicodeDecodeError: 'utf-8' codec can't decode byte 0x82 in position 55: invalid start byte We're currently adding data to the middle of the ram section depending on the presence of the capability. As a consequence, any code loading the ram section needs to know about capabilities so it can interpret the stream. Skip the byte that's added when x-ignore-shared is used to fix the script. Signed-off-by: Fabiano Rosas Reviewed-by: Juan Quintela Signed-off-by: Juan Quintela Message-ID: <20231009184326.15777-5-farosas@suse.de> --- scripts/analyze-migration.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/scripts/analyze-migration.py b/scripts/analyze-migration.py index c700fed64d..56ab04dd2d 100755 --- a/scripts/analyze-migration.py +++ b/scripts/analyze-migration.py @@ -123,6 +123,7 @@ class RamSection(object): self.TARGET_PAGE_SIZE = ramargs['page_size'] self.dump_memory = ramargs['dump_memory'] self.write_memory = ramargs['write_memory'] + self.ignore_shared = ramargs['ignore_shared'] self.sizeinfo = collections.OrderedDict() self.data = collections.OrderedDict() self.data['section sizes'] = self.sizeinfo @@ -169,6 +170,8 @@ class RamSection(object): f.truncate(0) f.truncate(len) self.files[self.name] = f + if self.ignore_shared: + mr_addr = self.file.read64() flags &= ~self.RAM_SAVE_FLAG_MEM_SIZE if flags & self.RAM_SAVE_FLAG_COMPRESS: @@ -572,6 +575,7 @@ class MigrationDump(object): ramargs['page_size'] = self.vmsd_desc['page_size'] ramargs['dump_memory'] = dump_memory ramargs['write_memory'] = write_memory + ramargs['ignore_shared'] = False self.section_classes[('ram',0)][1] = ramargs while True: @@ -582,6 +586,7 @@ class MigrationDump(object): config_desc = self.vmsd_desc.get('configuration') section = ConfigurationSection(file, config_desc) section.read() + ramargs['ignore_shared'] = section.has_capability('x-ignore-shared') elif section_type == self.QEMU_VM_SECTION_START or section_type == self.QEMU_VM_SECTION_FULL: section_id = file.read32() name = file.readstr() From caea03279e11dfcb0e5a567b81fe7f02ee80af02 Mon Sep 17 00:00:00 2001 From: Fabiano Rosas Date: Mon, 9 Oct 2023 15:43:25 -0300 Subject: [PATCH 0687/1077] migration: Fix analyze-migration read operation signedness The migration code uses unsigned values for 16, 32 and 64-bit operations. Fix the script to do the same. This was causing an issue when parsing the migration stream generated on the ppc64 target because one of instance_ids was larger than the 32bit signed maximum: Traceback (most recent call last): File "/home/fabiano/kvm/qemu/build/scripts/analyze-migration.py", line 658, in dump.read(dump_memory = args.memory) File "/home/fabiano/kvm/qemu/build/scripts/analyze-migration.py", line 592, in read classdesc = self.section_classes[section_key] KeyError: ('spapr_iommu', -2147483648) Signed-off-by: Fabiano Rosas Reviewed-by: Juan Quintela Signed-off-by: Juan Quintela Message-ID: <20231009184326.15777-6-farosas@suse.de> --- scripts/analyze-migration.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/scripts/analyze-migration.py b/scripts/analyze-migration.py index 56ab04dd2d..de506cb8bf 100755 --- a/scripts/analyze-migration.py +++ b/scripts/analyze-migration.py @@ -38,13 +38,13 @@ class MigrationFile(object): self.file = open(self.filename, "rb") def read64(self): - return int.from_bytes(self.file.read(8), byteorder='big', signed=True) + return int.from_bytes(self.file.read(8), byteorder='big', signed=False) def read32(self): - return int.from_bytes(self.file.read(4), byteorder='big', signed=True) + return int.from_bytes(self.file.read(4), byteorder='big', signed=False) def read16(self): - return int.from_bytes(self.file.read(2), byteorder='big', signed=True) + return int.from_bytes(self.file.read(2), byteorder='big', signed=False) def read8(self): return int.from_bytes(self.file.read(1), byteorder='big', signed=True) From d864756e8734b22a9e7825c0fa46c7459a7ad105 Mon Sep 17 00:00:00 2001 From: Fabiano Rosas Date: Mon, 9 Oct 2023 15:43:26 -0300 Subject: [PATCH 0688/1077] tests/qtest/migration: Add a test for the analyze-migration script Add a smoke test that migrates to a file and gives it to the script. It should catch the most annoying errors such as changes in the ram flags. After code has been merged it becomes way harder to figure out what is causing the script to fail, the person making the change is the most likely to know right away what the problem is. Signed-off-by: Fabiano Rosas Acked-by: Thomas Huth Reviewed-by: Juan Quintela Signed-off-by: Juan Quintela Message-ID: <20231009184326.15777-7-farosas@suse.de> --- tests/qtest/meson.build | 2 ++ tests/qtest/migration-test.c | 60 ++++++++++++++++++++++++++++++++++++ 2 files changed, 62 insertions(+) diff --git a/tests/qtest/meson.build b/tests/qtest/meson.build index 66795cfcd2..d6022ebd64 100644 --- a/tests/qtest/meson.build +++ b/tests/qtest/meson.build @@ -357,6 +357,8 @@ foreach dir : target_dirs test_deps += [qsd] endif + qtest_env.set('PYTHON', python.full_path()) + foreach test : target_qtests # Executables are shared across targets, declare them only the first time we # encounter them diff --git a/tests/qtest/migration-test.c b/tests/qtest/migration-test.c index 8eb2053dbb..cef5081f8c 100644 --- a/tests/qtest/migration-test.c +++ b/tests/qtest/migration-test.c @@ -66,6 +66,8 @@ static bool got_dst_resume; */ #define DIRTYLIMIT_TOLERANCE_RANGE 25 /* MB/s */ +#define ANALYZE_SCRIPT "scripts/analyze-migration.py" + #if defined(__linux__) #include #include @@ -1501,6 +1503,61 @@ static void test_baddest(void) test_migrate_end(from, to, false); } +#ifndef _WIN32 +static void test_analyze_script(void) +{ + MigrateStart args = { + .opts_source = "-uuid 11111111-1111-1111-1111-111111111111", + }; + QTestState *from, *to; + g_autofree char *uri = NULL; + g_autofree char *file = NULL; + int pid, wstatus; + const char *python = g_getenv("PYTHON"); + + if (!python) { + g_test_skip("PYTHON variable not set"); + return; + } + + /* dummy url */ + if (test_migrate_start(&from, &to, "tcp:127.0.0.1:0", &args)) { + return; + } + + /* + * Setting these two capabilities causes the "configuration" + * vmstate to include subsections for them. The script needs to + * parse those subsections properly. + */ + migrate_set_capability(from, "validate-uuid", true); + migrate_set_capability(from, "x-ignore-shared", true); + + file = g_strdup_printf("%s/migfile", tmpfs); + uri = g_strdup_printf("exec:cat > %s", file); + + migrate_ensure_converge(from); + migrate_qmp(from, uri, "{}"); + wait_for_migration_complete(from); + + pid = fork(); + if (!pid) { + close(1); + open("/dev/null", O_WRONLY); + execl(python, python, ANALYZE_SCRIPT, "-f", file, NULL); + g_assert_not_reached(); + } + + g_assert(waitpid(pid, &wstatus, 0) == pid); + if (WIFEXITED(wstatus) && WEXITSTATUS(wstatus) != 0) { + g_test_message("Failed to analyze the migration stream"); + g_test_fail(); + } + test_migrate_end(from, to, false); + cleanup("migfile"); +} +#endif + static void test_precopy_common(MigrateCommon *args) { QTestState *from, *to; @@ -2837,6 +2894,9 @@ int main(int argc, char **argv) } qtest_add_func("/migration/bad_dest", test_baddest); +#ifndef _WIN32 + qtest_add_func("/migration/analyze-script", test_analyze_script); +#endif qtest_add_func("/migration/precopy/unix/plain", test_precopy_unix_plain); qtest_add_func("/migration/precopy/unix/xbzrle", test_precopy_unix_xbzrle); /* From 3dc35470c888b21eba4ebd22e51ff376eb4fbdbf Mon Sep 17 00:00:00 2001 From: Fabiano Rosas Date: Wed, 12 Jul 2023 16:07:42 -0300 Subject: [PATCH 0689/1077] tests/qtest: migration-test: Add tests for file-based migration Add basic tests for file-based migration. Note that we cannot use test_precopy_common because that routine expects it to be possible to run the migration live. With the file transport there is no live migration because we must wait for the source to finish writing the migration data to the file before the destination can start reading. Add a new migration function specifically to handle the file migration. Reviewed-by: Peter Xu Reviewed-by: Juan Quintela Signed-off-by: Fabiano Rosas Signed-off-by: Juan Quintela Message-ID: <20230712190742.22294-7-farosas@suse.de> --- tests/qtest/migration-test.c | 147 +++++++++++++++++++++++++++++++++++ 1 file changed, 147 insertions(+) diff --git a/tests/qtest/migration-test.c b/tests/qtest/migration-test.c index cef5081f8c..e1c110537b 100644 --- a/tests/qtest/migration-test.c +++ b/tests/qtest/migration-test.c @@ -68,6 +68,10 @@ static bool got_dst_resume; #define ANALYZE_SCRIPT "scripts/analyze-migration.py" +#define QEMU_VM_FILE_MAGIC 0x5145564d +#define FILE_TEST_FILENAME "migfile" +#define FILE_TEST_OFFSET 0x1000 + #if defined(__linux__) #include #include @@ -884,6 +888,7 @@ static void test_migrate_end(QTestState *from, QTestState *to, bool test_dest) cleanup("migsocket"); cleanup("src_serial"); cleanup("dest_serial"); + cleanup(FILE_TEST_FILENAME); } #ifdef CONFIG_GNUTLS @@ -1667,6 +1672,70 @@ finish: test_migrate_end(from, to, args->result == MIG_TEST_SUCCEED); } +static void test_file_common(MigrateCommon *args, bool stop_src) +{ + QTestState *from, *to; + void *data_hook = NULL; + g_autofree char *connect_uri = g_strdup(args->connect_uri); + + if (test_migrate_start(&from, &to, args->listen_uri, &args->start)) { + return; + } + + /* + * File migration is never live. We can keep the source VM running + * during migration, but the destination will not be running + * concurrently. + */ + g_assert_false(args->live); + + if (args->start_hook) { + data_hook = args->start_hook(from, to); + } + + migrate_ensure_converge(from); + wait_for_serial("src_serial"); + + if (stop_src) { + qtest_qmp_assert_success(from, "{ 'execute' : 'stop'}"); + if (!got_src_stop) { + qtest_qmp_eventwait(from, "STOP"); + } + } + + if (args->result == MIG_TEST_QMP_ERROR) { + migrate_qmp_fail(from, connect_uri, "{}"); + goto finish; + } + + migrate_qmp(from, connect_uri, "{}"); + wait_for_migration_complete(from); + + /* + * We need to wait for the source to finish before starting the + * destination. + */ + migrate_incoming_qmp(to, connect_uri, "{}"); + wait_for_migration_complete(to); + + if (stop_src) { + qtest_qmp_assert_success(to, "{ 'execute' : 'cont'}"); + } + + if (!got_dst_resume) { + qtest_qmp_eventwait(to, "RESUME"); + } + + wait_for_serial("dest_serial"); + +finish: + if (args->finish_hook) { + args->finish_hook(from, to, data_hook); + } + + test_migrate_end(from, to, args->result == MIG_TEST_SUCCEED); +} + static void test_precopy_unix_plain(void) { g_autofree char *uri = g_strdup_printf("unix:%s/migsocket", tmpfs); @@ -1862,6 +1931,76 @@ static void test_precopy_unix_compress_nowait(void) test_precopy_common(&args); } +static void test_precopy_file(void) +{ + g_autofree char *uri = g_strdup_printf("file:%s/%s", tmpfs, + FILE_TEST_FILENAME); + MigrateCommon args = { + .connect_uri = uri, + .listen_uri = "defer", + }; + + test_file_common(&args, true); +} + +static void file_offset_finish_hook(QTestState *from, QTestState *to, + void *opaque) +{ +#if defined(__linux__) + g_autofree char *path = g_strdup_printf("%s/%s", tmpfs, FILE_TEST_FILENAME); + size_t size = FILE_TEST_OFFSET + sizeof(QEMU_VM_FILE_MAGIC); + uintptr_t *addr, *p; + int fd; + + fd = open(path, O_RDONLY); + g_assert(fd != -1); + addr = mmap(NULL, size, PROT_READ, MAP_SHARED, fd, 0); + g_assert(addr != MAP_FAILED); + + /* + * Ensure the skipped offset contains zeros and the migration + * stream starts at the right place. + */ + p = addr; + while (p < addr + FILE_TEST_OFFSET / sizeof(uintptr_t)) { + g_assert(*p == 0); + p++; + } + g_assert_cmpint(cpu_to_be64(*p) >> 32, ==, QEMU_VM_FILE_MAGIC); + + munmap(addr, size); + close(fd); +#endif +} + +static void test_precopy_file_offset(void) +{ + g_autofree char *uri = g_strdup_printf("file:%s/%s,offset=%d", tmpfs, + FILE_TEST_FILENAME, + FILE_TEST_OFFSET); + MigrateCommon args = { + .connect_uri = uri, + .listen_uri = "defer", + .finish_hook = file_offset_finish_hook, + }; + + test_file_common(&args, false); +} + +static void test_precopy_file_offset_bad(void) +{ + /* using a value not supported by qemu_strtosz() */ + g_autofree char *uri = g_strdup_printf("file:%s/%s,offset=0x20M", + tmpfs, FILE_TEST_FILENAME); + MigrateCommon args = { + .connect_uri = uri, + .listen_uri = "defer", + .result = MIG_TEST_QMP_ERROR, + }; + + test_file_common(&args, false); +} + static void test_precopy_tcp_plain(void) { MigrateCommon args = { @@ -2909,6 +3048,14 @@ int main(int argc, char **argv) qtest_add_func("/migration/precopy/unix/compress/nowait", test_precopy_unix_compress_nowait); } + + qtest_add_func("/migration/precopy/file", + test_precopy_file); + qtest_add_func("/migration/precopy/file/offset", + test_precopy_file_offset); + qtest_add_func("/migration/precopy/file/offset/bad", + test_precopy_file_offset_bad); + #ifdef CONFIG_GNUTLS qtest_add_func("/migration/precopy/unix/tls/psk", test_precopy_unix_tls_psk); From 930e239d11e28a3e8c01bae6c38f8894cfe66eb3 Mon Sep 17 00:00:00 2001 From: Fiona Ebner Date: Fri, 13 Oct 2023 12:58:39 +0200 Subject: [PATCH 0690/1077] migration: hold the BQL during setup This is intended to be a semantic revert of commit 9b09503752 ("migration: run setup callbacks out of big lock"). There have been so many changes since that commit (e.g. a new setup callback dirty_bitmap_save_setup() that also needs to be adapted now), it's easier to do the revert manually. For snapshots, the bdrv_writev_vmstate() function is used during setup (in QIOChannelBlock backing the QEMUFile), but not holding the BQL while calling it could lead to an assertion failure. To understand how, first note the following: 1. Generated coroutine wrappers for block layer functions spawn the coroutine and use AIO_WAIT_WHILE()/aio_poll() to wait for it. 2. If the host OS switches threads at an inconvenient time, it can happen that a bottom half scheduled for the main thread's AioContext is executed as part of a vCPU thread's aio_poll(). An example leading to the assertion failure is as follows: main thread: 1. A snapshot-save QMP command gets issued. 2. snapshot_save_job_bh() is scheduled. vCPU thread: 3. aio_poll() for the main thread's AioContext is called (e.g. when the guest writes to a pflash device, as part of blk_pwrite which is a generated coroutine wrapper). 4. snapshot_save_job_bh() is executed as part of aio_poll(). 3. qemu_savevm_state() is called. 4. qemu_mutex_unlock_iothread() is called. Now qemu_get_current_aio_context() returns 0x0. 5. bdrv_writev_vmstate() is executed during the usual savevm setup via qemu_fflush(). But this function is a generated coroutine wrapper, so it uses AIO_WAIT_WHILE. There, the assertion assert(qemu_get_current_aio_context() == qemu_get_aio_context()); will fail. To fix it, ensure that the BQL is held during setup. While it would only be needed for snapshots, adapting migration too avoids additional logic for conditional locking/unlocking in the setup callbacks. Writing the header could (in theory) also trigger qemu_fflush() and thus bdrv_writev_vmstate(), so the locked section also covers the qemu_savevm_state_header() call, even for migration for consistency. The section around multifd_send_sync_main() needs to be unlocked to avoid a deadlock. In particular, the multifd_save_setup() function calls socket_send_channel_create() using multifd_new_send_channel_async() as a callback and then waits for the callback to signal via the channels_ready semaphore. The connection happens via qio_task_run_in_thread(), but the callback is only executed via qio_task_thread_result() which is scheduled for the main event loop. Without unlocking the section, the main thread would never get to process the task result and the callback meaning there would be no signal via the channels_ready semaphore. The comment in ram_init_bitmaps() was introduced by 4987783400 ("migration: fix incorrect memory_global_dirty_log_start outside BQL") and is removed, because it referred to the qemu_mutex_lock_iothread() call. Signed-off-by: Fiona Ebner Reviewed-by: Fabiano Rosas Reviewed-by: Juan Quintela Signed-off-by: Juan Quintela Message-ID: <20231013105839.415989-1-f.ebner@proxmox.com> --- include/migration/register.h | 2 +- migration/block-dirty-bitmap.c | 3 --- migration/block.c | 5 ----- migration/migration.c | 6 ++++++ migration/ram.c | 6 +++--- migration/savevm.c | 2 -- 6 files changed, 10 insertions(+), 14 deletions(-) diff --git a/include/migration/register.h b/include/migration/register.h index 2b12c6adec..fed1d04a3c 100644 --- a/include/migration/register.h +++ b/include/migration/register.h @@ -25,6 +25,7 @@ typedef struct SaveVMHandlers { * used to perform early checks. */ int (*save_prepare)(void *opaque, Error **errp); + int (*save_setup)(QEMUFile *f, void *opaque); void (*save_cleanup)(void *opaque); int (*save_live_complete_postcopy)(QEMUFile *f, void *opaque); int (*save_live_complete_precopy)(QEMUFile *f, void *opaque); @@ -50,7 +51,6 @@ typedef struct SaveVMHandlers { int (*save_live_iterate)(QEMUFile *f, void *opaque); /* This runs outside the iothread lock! */ - int (*save_setup)(QEMUFile *f, void *opaque); /* Note for save_live_pending: * must_precopy: * - must be migrated in precopy or in stopped state diff --git a/migration/block-dirty-bitmap.c b/migration/block-dirty-bitmap.c index 032fc5f405..03cb2e72ee 100644 --- a/migration/block-dirty-bitmap.c +++ b/migration/block-dirty-bitmap.c @@ -1214,9 +1214,7 @@ static int dirty_bitmap_save_setup(QEMUFile *f, void *opaque) DBMSaveState *s = &((DBMState *)opaque)->save; SaveBitmapState *dbms = NULL; - qemu_mutex_lock_iothread(); if (init_dirty_bitmap_migration(s) < 0) { - qemu_mutex_unlock_iothread(); return -1; } @@ -1224,7 +1222,6 @@ static int dirty_bitmap_save_setup(QEMUFile *f, void *opaque) send_bitmap_start(f, s, dbms); } qemu_put_bitmap_flags(f, DIRTY_BITMAP_MIG_FLAG_EOS); - qemu_mutex_unlock_iothread(); return 0; } diff --git a/migration/block.c b/migration/block.c index d115e1cfa5..b60698d6e2 100644 --- a/migration/block.c +++ b/migration/block.c @@ -731,18 +731,13 @@ static int block_save_setup(QEMUFile *f, void *opaque) trace_migration_block_save("setup", block_mig_state.submitted, block_mig_state.transferred); - qemu_mutex_lock_iothread(); ret = init_blk_migration(f); if (ret < 0) { - qemu_mutex_unlock_iothread(); return ret; } /* start track dirty blocks */ ret = set_dirty_tracking(); - - qemu_mutex_unlock_iothread(); - if (ret) { return ret; } diff --git a/migration/migration.c b/migration/migration.c index 98151b1424..79fa11e3f6 100644 --- a/migration/migration.c +++ b/migration/migration.c @@ -3020,7 +3020,9 @@ static void *migration_thread(void *opaque) object_ref(OBJECT(s)); update_iteration_initial_status(s); + qemu_mutex_lock_iothread(); qemu_savevm_state_header(s->to_dst_file); + qemu_mutex_unlock_iothread(); /* * If we opened the return path, we need to make sure dst has it @@ -3048,7 +3050,9 @@ static void *migration_thread(void *opaque) qemu_savevm_send_colo_enable(s->to_dst_file); } + qemu_mutex_lock_iothread(); qemu_savevm_state_setup(s->to_dst_file); + qemu_mutex_unlock_iothread(); qemu_savevm_wait_unplug(s, MIGRATION_STATUS_SETUP, MIGRATION_STATUS_ACTIVE); @@ -3159,8 +3163,10 @@ static void *bg_migration_thread(void *opaque) ram_write_tracking_prepare(); #endif + qemu_mutex_lock_iothread(); qemu_savevm_state_header(s->to_dst_file); qemu_savevm_state_setup(s->to_dst_file); + qemu_mutex_unlock_iothread(); qemu_savevm_wait_unplug(s, MIGRATION_STATUS_SETUP, MIGRATION_STATUS_ACTIVE); diff --git a/migration/ram.c b/migration/ram.c index e8df4dc862..d3d9c8b65b 100644 --- a/migration/ram.c +++ b/migration/ram.c @@ -2891,8 +2891,6 @@ static void migration_bitmap_clear_discarded_pages(RAMState *rs) static void ram_init_bitmaps(RAMState *rs) { - /* For memory_global_dirty_log_start below. */ - qemu_mutex_lock_iothread(); qemu_mutex_lock_ramlist(); WITH_RCU_READ_LOCK_GUARD() { @@ -2904,7 +2902,6 @@ static void ram_init_bitmaps(RAMState *rs) } } qemu_mutex_unlock_ramlist(); - qemu_mutex_unlock_iothread(); /* * After an eventual first bitmap sync, fixup the initial bitmap @@ -3067,7 +3064,10 @@ static int ram_save_setup(QEMUFile *f, void *opaque) migration_ops = g_malloc0(sizeof(MigrationOps)); migration_ops->ram_save_target_page = ram_save_target_page_legacy; + + qemu_mutex_unlock_iothread(); ret = multifd_send_sync_main(f); + qemu_mutex_lock_iothread(); if (ret < 0) { return ret; } diff --git a/migration/savevm.c b/migration/savevm.c index bce698b0af..8622f229e5 100644 --- a/migration/savevm.c +++ b/migration/savevm.c @@ -1672,10 +1672,8 @@ static int qemu_savevm_state(QEMUFile *f, Error **errp) } ms->to_dst_file = f; - qemu_mutex_unlock_iothread(); qemu_savevm_state_header(f); qemu_savevm_state_setup(f); - qemu_mutex_lock_iothread(); while (qemu_file_get_error(f) == 0) { if (qemu_savevm_state_iterate(f, false) > 0) { From d4f34485ca8a077c98fc2303451e9bece9200dd7 Mon Sep 17 00:00:00 2001 From: Juan Quintela Date: Wed, 11 Oct 2023 22:55:48 +0200 Subject: [PATCH 0691/1077] migration: Non multifd migration don't care about multifd flushes RDMA was having trouble because migrate_multifd_flush_after_each_section() can only be true or false, but we don't want to send any flush when we are not in multifd migration. CC: Fabiano Rosas Reviewed-by: Li Zhijian Reviewed-by: Peter Xu Signed-off-by: Juan Quintela Message-ID: <20231011205548.10571-2-quintela@redhat.com> --- migration/ram.c | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/migration/ram.c b/migration/ram.c index d3d9c8b65b..acb8f95f00 100644 --- a/migration/ram.c +++ b/migration/ram.c @@ -1395,7 +1395,8 @@ static int find_dirty_block(RAMState *rs, PageSearchStatus *pss) pss->page = 0; pss->block = QLIST_NEXT_RCU(pss->block, next); if (!pss->block) { - if (!migrate_multifd_flush_after_each_section()) { + if (migrate_multifd() && + !migrate_multifd_flush_after_each_section()) { QEMUFile *f = rs->pss[RAM_CHANNEL_PRECOPY].pss_channel; int ret = multifd_send_sync_main(f); if (ret < 0) { @@ -3072,7 +3073,7 @@ static int ram_save_setup(QEMUFile *f, void *opaque) return ret; } - if (!migrate_multifd_flush_after_each_section()) { + if (migrate_multifd() && !migrate_multifd_flush_after_each_section()) { qemu_put_be64(f, RAM_SAVE_FLAG_MULTIFD_FLUSH); } @@ -3184,7 +3185,7 @@ static int ram_save_iterate(QEMUFile *f, void *opaque) out: if (ret >= 0 && migration_is_setup_or_active(migrate_get_current()->state)) { - if (migrate_multifd_flush_after_each_section()) { + if (migrate_multifd() && migrate_multifd_flush_after_each_section()) { ret = multifd_send_sync_main(rs->pss[RAM_CHANNEL_PRECOPY].pss_channel); if (ret < 0) { return ret; @@ -3261,7 +3262,7 @@ static int ram_save_complete(QEMUFile *f, void *opaque) return ret; } - if (!migrate_multifd_flush_after_each_section()) { + if (migrate_multifd() && !migrate_multifd_flush_after_each_section()) { qemu_put_be64(f, RAM_SAVE_FLAG_MULTIFD_FLUSH); } qemu_put_be64(f, RAM_SAVE_FLAG_EOS); @@ -3768,7 +3769,8 @@ int ram_load_postcopy(QEMUFile *f, int channel) break; case RAM_SAVE_FLAG_EOS: /* normal exit */ - if (migrate_multifd_flush_after_each_section()) { + if (migrate_multifd() && + migrate_multifd_flush_after_each_section()) { multifd_recv_sync_main(); } break; @@ -4046,7 +4048,8 @@ static int ram_load_precopy(QEMUFile *f) break; case RAM_SAVE_FLAG_EOS: /* normal exit */ - if (migrate_multifd_flush_after_each_section()) { + if (migrate_multifd() && + migrate_multifd_flush_after_each_section()) { multifd_recv_sync_main(); } break; From 27fd25b0fbcbcf2546fb2cb13fd9c8fe840eef02 Mon Sep 17 00:00:00 2001 From: Juan Quintela Date: Wed, 11 Oct 2023 22:35:15 +0200 Subject: [PATCH 0692/1077] migration: Create migrate_rdma() Helper to say if we are doing a migration over rdma. Reviewed-by: Peter Xu Reviewed-by: Li Zhijian Signed-off-by: Juan Quintela Message-ID: <20231011203527.9061-2-quintela@redhat.com> --- migration/migration.c | 1 + migration/migration.h | 2 ++ migration/options.c | 7 +++++++ migration/options.h | 1 + migration/rdma.c | 4 +++- 5 files changed, 14 insertions(+), 1 deletion(-) diff --git a/migration/migration.c b/migration/migration.c index 79fa11e3f6..6ba5e145ac 100644 --- a/migration/migration.c +++ b/migration/migration.c @@ -1452,6 +1452,7 @@ int migrate_init(MigrationState *s, Error **errp) s->iteration_initial_bytes = 0; s->threshold_size = 0; s->switchover_acked = false; + s->rdma_migration = false; /* * set mig_stats compression_counters memory to zero for a * new migration diff --git a/migration/migration.h b/migration/migration.h index 974897a8d0..ae82004892 100644 --- a/migration/migration.h +++ b/migration/migration.h @@ -469,6 +469,8 @@ struct MigrationState { * switchover has been received. */ bool switchover_acked; + /* Is this a rdma migration */ + bool rdma_migration; }; void migrate_set_state(int *state, int old_state, int new_state); diff --git a/migration/options.c b/migration/options.c index 546cbe3106..42fb818956 100644 --- a/migration/options.c +++ b/migration/options.c @@ -378,6 +378,13 @@ bool migrate_postcopy(void) return migrate_postcopy_ram() || migrate_dirty_bitmaps(); } +bool migrate_rdma(void) +{ + MigrationState *s = migrate_get_current(); + + return s->rdma_migration; +} + bool migrate_tls(void) { MigrationState *s = migrate_get_current(); diff --git a/migration/options.h b/migration/options.h index 93ee938ab8..237f2d6b4a 100644 --- a/migration/options.h +++ b/migration/options.h @@ -56,6 +56,7 @@ bool migrate_zero_copy_send(void); bool migrate_multifd_flush_after_each_section(void); bool migrate_postcopy(void); +bool migrate_rdma(void); bool migrate_tls(void); /* capabilities helpers */ diff --git a/migration/rdma.c b/migration/rdma.c index f6fc226c9b..f155f3e1c8 100644 --- a/migration/rdma.c +++ b/migration/rdma.c @@ -4113,6 +4113,7 @@ static void rdma_accept_incoming_migration(void *opaque) void rdma_start_incoming_migration(const char *host_port, Error **errp) { + MigrationState *s = migrate_get_current(); int ret; RDMAContext *rdma; @@ -4144,7 +4145,7 @@ void rdma_start_incoming_migration(const char *host_port, Error **errp) } trace_rdma_start_incoming_migration_after_rdma_listen(); - + s->rdma_migration = true; qemu_set_fd_handler(rdma->channel->fd, rdma_accept_incoming_migration, NULL, (void *)(intptr_t)rdma); return; @@ -4220,6 +4221,7 @@ void rdma_start_outgoing_migration(void *opaque, trace_rdma_start_outgoing_migration_after_rdma_connect(); s->to_dst_file = rdma_new_output(rdma); + s->rdma_migration = true; migrate_fd_connect(s, NULL); return; return_path_err: From 48408174a7ec7bfdc18c6d9886d0eeb20520a349 Mon Sep 17 00:00:00 2001 From: Juan Quintela Date: Wed, 11 Oct 2023 22:35:16 +0200 Subject: [PATCH 0693/1077] migration/rdma: Unfold ram_control_before_iterate() Once there: - Remove unused data parameter - unfold it in its callers. - change all callers to call qemu_rdma_registration_start() - We need to call QIO_CHANNEL_RDMA() after we check for migrate_rdma() Reviewed-by: Li Zhijian Reviewed-by: Fabiano Rosas Signed-off-by: Juan Quintela Message-ID: <20231011203527.9061-3-quintela@redhat.com> --- migration/qemu-file.c | 13 +------------ migration/qemu-file.h | 2 -- migration/ram.c | 16 +++++++++++++--- migration/rdma.c | 12 ++++-------- migration/rdma.h | 7 +++++++ 5 files changed, 25 insertions(+), 25 deletions(-) diff --git a/migration/qemu-file.c b/migration/qemu-file.c index 7fb659296f..5e2d73fd68 100644 --- a/migration/qemu-file.c +++ b/migration/qemu-file.c @@ -32,6 +32,7 @@ #include "trace.h" #include "options.h" #include "qapi/error.h" +#include "rdma.h" #define IO_BUF_SIZE 32768 #define MAX_IOV_SIZE MIN_CONST(IOV_MAX, 64) @@ -297,18 +298,6 @@ void qemu_fflush(QEMUFile *f) f->iovcnt = 0; } -void ram_control_before_iterate(QEMUFile *f, uint64_t flags) -{ - int ret = 0; - - if (f->hooks && f->hooks->before_ram_iterate) { - ret = f->hooks->before_ram_iterate(f, flags, NULL); - if (ret < 0) { - qemu_file_set_error(f, ret); - } - } -} - void ram_control_after_iterate(QEMUFile *f, uint64_t flags) { int ret = 0; diff --git a/migration/qemu-file.h b/migration/qemu-file.h index 03e718c264..d6a370c569 100644 --- a/migration/qemu-file.h +++ b/migration/qemu-file.h @@ -55,7 +55,6 @@ typedef int (QEMURamSaveFunc)(QEMUFile *f, size_t size); typedef struct QEMUFileHooks { - QEMURamHookFunc *before_ram_iterate; QEMURamHookFunc *after_ram_iterate; QEMURamHookFunc *hook_ram_load; QEMURamSaveFunc *save_page; @@ -127,7 +126,6 @@ void qemu_fflush(QEMUFile *f); void qemu_file_set_blocking(QEMUFile *f, bool block); int qemu_file_get_to_fd(QEMUFile *f, int fd, size_t size); -void ram_control_before_iterate(QEMUFile *f, uint64_t flags); void ram_control_after_iterate(QEMUFile *f, uint64_t flags); void ram_control_load_hook(QEMUFile *f, uint64_t flags, void *data); diff --git a/migration/ram.c b/migration/ram.c index acb8f95f00..6592431a4e 100644 --- a/migration/ram.c +++ b/migration/ram.c @@ -59,6 +59,7 @@ #include "qemu/iov.h" #include "multifd.h" #include "sysemu/runstate.h" +#include "rdma.h" #include "options.h" #include "sysemu/dirtylimit.h" #include "sysemu/kvm.h" @@ -3060,7 +3061,10 @@ static int ram_save_setup(QEMUFile *f, void *opaque) } } - ram_control_before_iterate(f, RAM_CONTROL_SETUP); + ret = qemu_rdma_registration_start(f, RAM_CONTROL_SETUP); + if (ret < 0) { + qemu_file_set_error(f, ret); + } ram_control_after_iterate(f, RAM_CONTROL_SETUP); migration_ops = g_malloc0(sizeof(MigrationOps)); @@ -3123,7 +3127,10 @@ static int ram_save_iterate(QEMUFile *f, void *opaque) /* Read version before ram_list.blocks */ smp_rmb(); - ram_control_before_iterate(f, RAM_CONTROL_ROUND); + ret = qemu_rdma_registration_start(f, RAM_CONTROL_ROUND); + if (ret < 0) { + qemu_file_set_error(f, ret); + } t0 = qemu_clock_get_ns(QEMU_CLOCK_REALTIME); i = 0; @@ -3228,7 +3235,10 @@ static int ram_save_complete(QEMUFile *f, void *opaque) migration_bitmap_sync_precopy(rs, true); } - ram_control_before_iterate(f, RAM_CONTROL_FINISH); + ret = qemu_rdma_registration_start(f, RAM_CONTROL_FINISH); + if (ret < 0) { + qemu_file_set_error(f, ret); + } /* try transferring iterative blocks of memory */ diff --git a/migration/rdma.c b/migration/rdma.c index f155f3e1c8..3d74ad6db0 100644 --- a/migration/rdma.c +++ b/migration/rdma.c @@ -3850,18 +3850,15 @@ static int rdma_load_hook(QEMUFile *f, uint64_t flags, void *data) } } -static int qemu_rdma_registration_start(QEMUFile *f, - uint64_t flags, void *data) +int qemu_rdma_registration_start(QEMUFile *f, uint64_t flags) { - QIOChannelRDMA *rioc = QIO_CHANNEL_RDMA(qemu_file_get_ioc(f)); - RDMAContext *rdma; - - if (migration_in_postcopy()) { + if (!migrate_rdma() || migration_in_postcopy()) { return 0; } + QIOChannelRDMA *rioc = QIO_CHANNEL_RDMA(qemu_file_get_ioc(f)); RCU_READ_LOCK_GUARD(); - rdma = qatomic_rcu_read(&rioc->rdmaout); + RDMAContext *rdma = qatomic_rcu_read(&rioc->rdmaout); if (!rdma) { return -1; } @@ -4002,7 +3999,6 @@ static const QEMUFileHooks rdma_read_hooks = { }; static const QEMUFileHooks rdma_write_hooks = { - .before_ram_iterate = qemu_rdma_registration_start, .after_ram_iterate = qemu_rdma_registration_stop, .save_page = qemu_rdma_save_page, }; diff --git a/migration/rdma.h b/migration/rdma.h index de2ba09dc5..670c67a8cb 100644 --- a/migration/rdma.h +++ b/migration/rdma.h @@ -22,4 +22,11 @@ void rdma_start_outgoing_migration(void *opaque, const char *host_port, void rdma_start_incoming_migration(const char *host_port, Error **errp); + +#ifdef CONFIG_RDMA +int qemu_rdma_registration_start(QEMUFile *f, uint64_t flags); +#else +static inline +int qemu_rdma_registration_start(QEMUFile *f, uint64_t flags) { return 0; } +#endif #endif From 5f5b8858dc1c11916000a5a2038044dec31640d6 Mon Sep 17 00:00:00 2001 From: Juan Quintela Date: Wed, 11 Oct 2023 22:35:17 +0200 Subject: [PATCH 0694/1077] migration/rdma: Unfold ram_control_after_iterate() Once there: - Remove unused data parameter - unfold it in its callers - change all callers to call qemu_rdma_registration_stop() - We need to call QIO_CHANNEL_RDMA() after we check for migrate_rdma() Reviewed-by: Li Zhijian Signed-off-by: Juan Quintela Message-ID: <20231011203527.9061-4-quintela@redhat.com> --- migration/qemu-file.c | 12 ------------ migration/qemu-file.h | 2 -- migration/ram.c | 17 ++++++++++++++--- migration/rdma.c | 9 ++++----- migration/rdma.h | 3 +++ 5 files changed, 21 insertions(+), 22 deletions(-) diff --git a/migration/qemu-file.c b/migration/qemu-file.c index 5e2d73fd68..e7dba2a849 100644 --- a/migration/qemu-file.c +++ b/migration/qemu-file.c @@ -298,18 +298,6 @@ void qemu_fflush(QEMUFile *f) f->iovcnt = 0; } -void ram_control_after_iterate(QEMUFile *f, uint64_t flags) -{ - int ret = 0; - - if (f->hooks && f->hooks->after_ram_iterate) { - ret = f->hooks->after_ram_iterate(f, flags, NULL); - if (ret < 0) { - qemu_file_set_error(f, ret); - } - } -} - void ram_control_load_hook(QEMUFile *f, uint64_t flags, void *data) { if (f->hooks && f->hooks->hook_ram_load) { diff --git a/migration/qemu-file.h b/migration/qemu-file.h index d6a370c569..35e671a01e 100644 --- a/migration/qemu-file.h +++ b/migration/qemu-file.h @@ -55,7 +55,6 @@ typedef int (QEMURamSaveFunc)(QEMUFile *f, size_t size); typedef struct QEMUFileHooks { - QEMURamHookFunc *after_ram_iterate; QEMURamHookFunc *hook_ram_load; QEMURamSaveFunc *save_page; } QEMUFileHooks; @@ -126,7 +125,6 @@ void qemu_fflush(QEMUFile *f); void qemu_file_set_blocking(QEMUFile *f, bool block); int qemu_file_get_to_fd(QEMUFile *f, int fd, size_t size); -void ram_control_after_iterate(QEMUFile *f, uint64_t flags); void ram_control_load_hook(QEMUFile *f, uint64_t flags, void *data); /* Whenever this is found in the data stream, the flags diff --git a/migration/ram.c b/migration/ram.c index 6592431a4e..f1ddc1f9fa 100644 --- a/migration/ram.c +++ b/migration/ram.c @@ -3065,7 +3065,11 @@ static int ram_save_setup(QEMUFile *f, void *opaque) if (ret < 0) { qemu_file_set_error(f, ret); } - ram_control_after_iterate(f, RAM_CONTROL_SETUP); + + ret = qemu_rdma_registration_stop(f, RAM_CONTROL_SETUP); + if (ret < 0) { + qemu_file_set_error(f, ret); + } migration_ops = g_malloc0(sizeof(MigrationOps)); migration_ops->ram_save_target_page = ram_save_target_page_legacy; @@ -3187,7 +3191,10 @@ static int ram_save_iterate(QEMUFile *f, void *opaque) * Must occur before EOS (or any QEMUFile operation) * because of RDMA protocol. */ - ram_control_after_iterate(f, RAM_CONTROL_ROUND); + ret = qemu_rdma_registration_stop(f, RAM_CONTROL_ROUND); + if (ret < 0) { + qemu_file_set_error(f, ret); + } out: if (ret >= 0 @@ -3260,7 +3267,11 @@ static int ram_save_complete(QEMUFile *f, void *opaque) qemu_mutex_unlock(&rs->bitmap_mutex); ram_flush_compressed_data(rs); - ram_control_after_iterate(f, RAM_CONTROL_FINISH); + + int ret = qemu_rdma_registration_stop(f, RAM_CONTROL_FINISH); + if (ret < 0) { + qemu_file_set_error(f, ret); + } } if (ret < 0) { diff --git a/migration/rdma.c b/migration/rdma.c index 3d74ad6db0..4b32d375ec 100644 --- a/migration/rdma.c +++ b/migration/rdma.c @@ -3878,20 +3878,20 @@ int qemu_rdma_registration_start(QEMUFile *f, uint64_t flags) * Inform dest that dynamic registrations are done for now. * First, flush writes, if any. */ -static int qemu_rdma_registration_stop(QEMUFile *f, - uint64_t flags, void *data) +int qemu_rdma_registration_stop(QEMUFile *f, uint64_t flags) { - QIOChannelRDMA *rioc = QIO_CHANNEL_RDMA(qemu_file_get_ioc(f)); + QIOChannelRDMA *rioc; Error *err = NULL; RDMAContext *rdma; RDMAControlHeader head = { .len = 0, .repeat = 1 }; int ret; - if (migration_in_postcopy()) { + if (!migrate_rdma() || migration_in_postcopy()) { return 0; } RCU_READ_LOCK_GUARD(); + rioc = QIO_CHANNEL_RDMA(qemu_file_get_ioc(f)); rdma = qatomic_rcu_read(&rioc->rdmaout); if (!rdma) { return -1; @@ -3999,7 +3999,6 @@ static const QEMUFileHooks rdma_read_hooks = { }; static const QEMUFileHooks rdma_write_hooks = { - .after_ram_iterate = qemu_rdma_registration_stop, .save_page = qemu_rdma_save_page, }; diff --git a/migration/rdma.h b/migration/rdma.h index 670c67a8cb..c13b94c782 100644 --- a/migration/rdma.h +++ b/migration/rdma.h @@ -25,8 +25,11 @@ void rdma_start_incoming_migration(const char *host_port, Error **errp); #ifdef CONFIG_RDMA int qemu_rdma_registration_start(QEMUFile *f, uint64_t flags); +int qemu_rdma_registration_stop(QEMUFile *f, uint64_t flags); #else static inline int qemu_rdma_registration_start(QEMUFile *f, uint64_t flags) { return 0; } +static inline +int qemu_rdma_registration_stop(QEMUFile *f, uint64_t flags) { return 0; } #endif #endif From f6d6c089b78a6492416408b93a799edecfd736d6 Mon Sep 17 00:00:00 2001 From: Juan Quintela Date: Wed, 11 Oct 2023 22:35:18 +0200 Subject: [PATCH 0695/1077] migration/rdma: Remove all uses of RAM_CONTROL_HOOK Instead of going through ram_control_load_hook(), call qemu_rdma_registration_handle() directly. Reviewed-by: Li Zhijian Signed-off-by: Juan Quintela Message-ID: <20231011203527.9061-5-quintela@redhat.com> --- migration/qemu-file.h | 1 - migration/ram.c | 5 ++++- migration/rdma.c | 12 +++++++----- migration/rdma.h | 3 +++ 4 files changed, 14 insertions(+), 7 deletions(-) diff --git a/migration/qemu-file.h b/migration/qemu-file.h index 35e671a01e..14ff0d9cc4 100644 --- a/migration/qemu-file.h +++ b/migration/qemu-file.h @@ -41,7 +41,6 @@ typedef int (QEMURamHookFunc)(QEMUFile *f, uint64_t flags, void *data); */ #define RAM_CONTROL_SETUP 0 #define RAM_CONTROL_ROUND 1 -#define RAM_CONTROL_HOOK 2 #define RAM_CONTROL_FINISH 3 #define RAM_CONTROL_BLOCK_REG 4 diff --git a/migration/ram.c b/migration/ram.c index f1ddc1f9fa..f6ea1831b5 100644 --- a/migration/ram.c +++ b/migration/ram.c @@ -4075,7 +4075,10 @@ static int ram_load_precopy(QEMUFile *f) } break; case RAM_SAVE_FLAG_HOOK: - ram_control_load_hook(f, RAM_CONTROL_HOOK, NULL); + ret = qemu_rdma_registration_handle(f); + if (ret < 0) { + qemu_file_set_error(f, ret); + } break; default: error_report("Unknown combination of migration flags: 0x%x", flags); diff --git a/migration/rdma.c b/migration/rdma.c index 4b32d375ec..5c20f425a9 100644 --- a/migration/rdma.c +++ b/migration/rdma.c @@ -3522,7 +3522,7 @@ static int dest_ram_sort_func(const void *a, const void *b) * * Keep doing this until the source tells us to stop. */ -static int qemu_rdma_registration_handle(QEMUFile *f) +int qemu_rdma_registration_handle(QEMUFile *f) { RDMAControlHeader reg_resp = { .len = sizeof(RDMARegisterResult), .type = RDMA_CONTROL_REGISTER_RESULT, @@ -3534,7 +3534,7 @@ static int qemu_rdma_registration_handle(QEMUFile *f) }; RDMAControlHeader blocks = { .type = RDMA_CONTROL_RAM_BLOCKS_RESULT, .repeat = 1 }; - QIOChannelRDMA *rioc = QIO_CHANNEL_RDMA(qemu_file_get_ioc(f)); + QIOChannelRDMA *rioc; Error *err = NULL; RDMAContext *rdma; RDMALocalBlocks *local; @@ -3550,7 +3550,12 @@ static int qemu_rdma_registration_handle(QEMUFile *f) int count = 0; int i = 0; + if (!migrate_rdma()) { + return 0; + } + RCU_READ_LOCK_GUARD(); + rioc = QIO_CHANNEL_RDMA(qemu_file_get_ioc(f)); rdma = qatomic_rcu_read(&rioc->rdmain); if (!rdma) { @@ -3841,9 +3846,6 @@ static int rdma_load_hook(QEMUFile *f, uint64_t flags, void *data) case RAM_CONTROL_BLOCK_REG: return rdma_block_notification_handle(f, data); - case RAM_CONTROL_HOOK: - return qemu_rdma_registration_handle(f); - default: /* Shouldn't be called with any other values */ abort(); diff --git a/migration/rdma.h b/migration/rdma.h index c13b94c782..8bd277efb9 100644 --- a/migration/rdma.h +++ b/migration/rdma.h @@ -24,10 +24,13 @@ void rdma_start_incoming_migration(const char *host_port, Error **errp); #ifdef CONFIG_RDMA +int qemu_rdma_registration_handle(QEMUFile *f); int qemu_rdma_registration_start(QEMUFile *f, uint64_t flags); int qemu_rdma_registration_stop(QEMUFile *f, uint64_t flags); #else static inline +int qemu_rdma_registration_handle(QEMUFile *f) { return 0; } +static inline int qemu_rdma_registration_start(QEMUFile *f, uint64_t flags) { return 0; } static inline int qemu_rdma_registration_stop(QEMUFile *f, uint64_t flags) { return 0; } From a6323300e879558055948cb16ba6da52a9836869 Mon Sep 17 00:00:00 2001 From: Juan Quintela Date: Wed, 11 Oct 2023 22:35:19 +0200 Subject: [PATCH 0696/1077] migration/rdma: Unfold hook_ram_load() There is only one flag called with: RAM_CONTROL_BLOCK_REG. Reviewed-by: Li Zhijian Signed-off-by: Juan Quintela Message-ID: <20231011203527.9061-6-quintela@redhat.com> --- migration/qemu-file.c | 10 ---------- migration/qemu-file.h | 11 ----------- migration/ram.c | 6 ++++-- migration/rdma.c | 34 +++++++++++----------------------- migration/rdma.h | 3 +++ 5 files changed, 18 insertions(+), 46 deletions(-) diff --git a/migration/qemu-file.c b/migration/qemu-file.c index e7dba2a849..4a414b8976 100644 --- a/migration/qemu-file.c +++ b/migration/qemu-file.c @@ -298,16 +298,6 @@ void qemu_fflush(QEMUFile *f) f->iovcnt = 0; } -void ram_control_load_hook(QEMUFile *f, uint64_t flags, void *data) -{ - if (f->hooks && f->hooks->hook_ram_load) { - int ret = f->hooks->hook_ram_load(f, flags, data); - if (ret < 0) { - qemu_file_set_error(f, ret); - } - } -} - int ram_control_save_page(QEMUFile *f, ram_addr_t block_offset, ram_addr_t offset, size_t size) { diff --git a/migration/qemu-file.h b/migration/qemu-file.h index 14ff0d9cc4..80c30631dc 100644 --- a/migration/qemu-file.h +++ b/migration/qemu-file.h @@ -29,20 +29,12 @@ #include "exec/cpu-common.h" #include "io/channel.h" -/* - * This function provides hooks around different - * stages of RAM migration. - * 'data' is call specific data associated with the 'flags' value - */ -typedef int (QEMURamHookFunc)(QEMUFile *f, uint64_t flags, void *data); - /* * Constants used by ram_control_* hooks */ #define RAM_CONTROL_SETUP 0 #define RAM_CONTROL_ROUND 1 #define RAM_CONTROL_FINISH 3 -#define RAM_CONTROL_BLOCK_REG 4 /* * This function allows override of where the RAM page @@ -54,7 +46,6 @@ typedef int (QEMURamSaveFunc)(QEMUFile *f, size_t size); typedef struct QEMUFileHooks { - QEMURamHookFunc *hook_ram_load; QEMURamSaveFunc *save_page; } QEMUFileHooks; @@ -124,8 +115,6 @@ void qemu_fflush(QEMUFile *f); void qemu_file_set_blocking(QEMUFile *f, bool block); int qemu_file_get_to_fd(QEMUFile *f, int fd, size_t size); -void ram_control_load_hook(QEMUFile *f, uint64_t flags, void *data); - /* Whenever this is found in the data stream, the flags * will be passed to ram_control_load_hook in the incoming-migration * side. This lets before_ram_iterate/after_ram_iterate add diff --git a/migration/ram.c b/migration/ram.c index f6ea1831b5..8c462276cd 100644 --- a/migration/ram.c +++ b/migration/ram.c @@ -4025,8 +4025,10 @@ static int ram_load_precopy(QEMUFile *f) ret = -EINVAL; } } - ram_control_load_hook(f, RAM_CONTROL_BLOCK_REG, - block->idstr); + ret = rdma_block_notification_handle(f, block->idstr); + if (ret < 0) { + qemu_file_set_error(f, ret); + } } else { error_report("Unknown ramblock \"%s\", cannot " "accept migration", id); diff --git a/migration/rdma.c b/migration/rdma.c index 5c20f425a9..0b1cb03b2b 100644 --- a/migration/rdma.c +++ b/migration/rdma.c @@ -3799,22 +3799,23 @@ err: } /* Destination: - * Called via a ram_control_load_hook during the initial RAM load section which - * lists the RAMBlocks by name. This lets us know the order of the RAMBlocks - * on the source. - * We've already built our local RAMBlock list, but not yet sent the list to - * the source. + * Called during the initial RAM load section which lists the + * RAMBlocks by name. This lets us know the order of the RAMBlocks on + * the source. We've already built our local RAMBlock list, but not + * yet sent the list to the source. */ -static int -rdma_block_notification_handle(QEMUFile *f, const char *name) +int rdma_block_notification_handle(QEMUFile *f, const char *name) { - RDMAContext *rdma; - QIOChannelRDMA *rioc = QIO_CHANNEL_RDMA(qemu_file_get_ioc(f)); int curr; int found = -1; + if (!migrate_rdma()) { + return 0; + } + RCU_READ_LOCK_GUARD(); - rdma = qatomic_rcu_read(&rioc->rdmain); + QIOChannelRDMA *rioc = QIO_CHANNEL_RDMA(qemu_file_get_ioc(f)); + RDMAContext *rdma = qatomic_rcu_read(&rioc->rdmain); if (!rdma) { return -1; @@ -3840,18 +3841,6 @@ rdma_block_notification_handle(QEMUFile *f, const char *name) return 0; } -static int rdma_load_hook(QEMUFile *f, uint64_t flags, void *data) -{ - switch (flags) { - case RAM_CONTROL_BLOCK_REG: - return rdma_block_notification_handle(f, data); - - default: - /* Shouldn't be called with any other values */ - abort(); - } -} - int qemu_rdma_registration_start(QEMUFile *f, uint64_t flags) { if (!migrate_rdma() || migration_in_postcopy()) { @@ -3997,7 +3986,6 @@ err: } static const QEMUFileHooks rdma_read_hooks = { - .hook_ram_load = rdma_load_hook, }; static const QEMUFileHooks rdma_write_hooks = { diff --git a/migration/rdma.h b/migration/rdma.h index 8bd277efb9..8df8b4089a 100644 --- a/migration/rdma.h +++ b/migration/rdma.h @@ -27,6 +27,7 @@ void rdma_start_incoming_migration(const char *host_port, Error **errp); int qemu_rdma_registration_handle(QEMUFile *f); int qemu_rdma_registration_start(QEMUFile *f, uint64_t flags); int qemu_rdma_registration_stop(QEMUFile *f, uint64_t flags); +int rdma_block_notification_handle(QEMUFile *f, const char *name); #else static inline int qemu_rdma_registration_handle(QEMUFile *f) { return 0; } @@ -34,5 +35,7 @@ static inline int qemu_rdma_registration_start(QEMUFile *f, uint64_t flags) { return 0; } static inline int qemu_rdma_registration_stop(QEMUFile *f, uint64_t flags) { return 0; } +static inline +int rdma_block_notification_handle(QEMUFile *f, const char *name) { return 0; } #endif #endif From e493008d504b3513e64f90e87924fd4b4a2f0751 Mon Sep 17 00:00:00 2001 From: Juan Quintela Date: Wed, 11 Oct 2023 22:35:20 +0200 Subject: [PATCH 0697/1077] migration/rdma: Create rdma_control_save_page() The only user of ram_control_save_page() and save_page() hook was rdma. Just move the function to rdma.c, rename it to rdma_control_save_page(). Reviewed-by: Peter Xu Reviewed-by: Li Zhijian Signed-off-by: Juan Quintela Message-ID: <20231011203527.9061-7-quintela@redhat.com> --- migration/qemu-file.c | 20 -------------------- migration/qemu-file.h | 12 ------------ migration/ram.c | 4 ++-- migration/rdma.c | 19 ++++++++++++++++++- migration/rdma.h | 10 ++++++++++ 5 files changed, 30 insertions(+), 35 deletions(-) diff --git a/migration/qemu-file.c b/migration/qemu-file.c index 4a414b8976..745eaf7a5b 100644 --- a/migration/qemu-file.c +++ b/migration/qemu-file.c @@ -298,26 +298,6 @@ void qemu_fflush(QEMUFile *f) f->iovcnt = 0; } -int ram_control_save_page(QEMUFile *f, ram_addr_t block_offset, - ram_addr_t offset, size_t size) -{ - if (f->hooks && f->hooks->save_page) { - int ret = f->hooks->save_page(f, block_offset, offset, size); - /* - * RAM_SAVE_CONTROL_* are negative values - */ - if (ret != RAM_SAVE_CONTROL_DELAYED && - ret != RAM_SAVE_CONTROL_NOT_SUPP) { - if (ret < 0) { - qemu_file_set_error(f, ret); - } - } - return ret; - } - - return RAM_SAVE_CONTROL_NOT_SUPP; -} - /* * Attempt to fill the buffer from the underlying file * Returns the number of bytes read, or negative value for an error. diff --git a/migration/qemu-file.h b/migration/qemu-file.h index 80c30631dc..60510a2819 100644 --- a/migration/qemu-file.h +++ b/migration/qemu-file.h @@ -36,17 +36,7 @@ #define RAM_CONTROL_ROUND 1 #define RAM_CONTROL_FINISH 3 -/* - * This function allows override of where the RAM page - * is saved (such as RDMA, for example.) - */ -typedef int (QEMURamSaveFunc)(QEMUFile *f, - ram_addr_t block_offset, - ram_addr_t offset, - size_t size); - typedef struct QEMUFileHooks { - QEMURamSaveFunc *save_page; } QEMUFileHooks; QEMUFile *qemu_file_new_input(QIOChannel *ioc); @@ -125,8 +115,6 @@ int qemu_file_get_to_fd(QEMUFile *f, int fd, size_t size); #define RAM_SAVE_CONTROL_NOT_SUPP -1000 #define RAM_SAVE_CONTROL_DELAYED -2000 -int ram_control_save_page(QEMUFile *f, ram_addr_t block_offset, - ram_addr_t offset, size_t size); QIOChannel *qemu_file_get_ioc(QEMUFile *file); #endif diff --git a/migration/ram.c b/migration/ram.c index 8c462276cd..3b4b09f6ff 100644 --- a/migration/ram.c +++ b/migration/ram.c @@ -1197,8 +1197,8 @@ static bool control_save_page(PageSearchStatus *pss, RAMBlock *block, { int ret; - ret = ram_control_save_page(pss->pss_channel, block->offset, offset, - TARGET_PAGE_SIZE); + ret = rdma_control_save_page(pss->pss_channel, block->offset, offset, + TARGET_PAGE_SIZE); if (ret == RAM_SAVE_CONTROL_NOT_SUPP) { return false; } diff --git a/migration/rdma.c b/migration/rdma.c index 0b1cb03b2b..f66bd939d7 100644 --- a/migration/rdma.c +++ b/migration/rdma.c @@ -3314,6 +3314,24 @@ err: return -1; } +int rdma_control_save_page(QEMUFile *f, ram_addr_t block_offset, + ram_addr_t offset, size_t size) +{ + if (!migrate_rdma()) { + return RAM_SAVE_CONTROL_NOT_SUPP; + } + + int ret = qemu_rdma_save_page(f, block_offset, offset, size); + + if (ret != RAM_SAVE_CONTROL_DELAYED && + ret != RAM_SAVE_CONTROL_NOT_SUPP) { + if (ret < 0) { + qemu_file_set_error(f, ret); + } + } + return ret; +} + static void rdma_accept_incoming_migration(void *opaque); static void rdma_cm_poll_handler(void *opaque) @@ -3989,7 +4007,6 @@ static const QEMUFileHooks rdma_read_hooks = { }; static const QEMUFileHooks rdma_write_hooks = { - .save_page = qemu_rdma_save_page, }; diff --git a/migration/rdma.h b/migration/rdma.h index 8df8b4089a..09a16c1e3c 100644 --- a/migration/rdma.h +++ b/migration/rdma.h @@ -17,6 +17,8 @@ #ifndef QEMU_MIGRATION_RDMA_H #define QEMU_MIGRATION_RDMA_H +#include "exec/memory.h" + void rdma_start_outgoing_migration(void *opaque, const char *host_port, Error **errp); @@ -28,6 +30,8 @@ int qemu_rdma_registration_handle(QEMUFile *f); int qemu_rdma_registration_start(QEMUFile *f, uint64_t flags); int qemu_rdma_registration_stop(QEMUFile *f, uint64_t flags); int rdma_block_notification_handle(QEMUFile *f, const char *name); +int rdma_control_save_page(QEMUFile *f, ram_addr_t block_offset, + ram_addr_t offset, size_t size); #else static inline int qemu_rdma_registration_handle(QEMUFile *f) { return 0; } @@ -37,5 +41,11 @@ static inline int qemu_rdma_registration_stop(QEMUFile *f, uint64_t flags) { return 0; } static inline int rdma_block_notification_handle(QEMUFile *f, const char *name) { return 0; } +static inline +int rdma_control_save_page(QEMUFile *f, ram_addr_t block_offset, + ram_addr_t offset, size_t size) +{ + return RAM_SAVE_CONTROL_NOT_SUPP; +} #endif #endif From 8b670f48ed40e0086b01fe9f603fa2f7470e9148 Mon Sep 17 00:00:00 2001 From: Juan Quintela Date: Wed, 11 Oct 2023 22:35:21 +0200 Subject: [PATCH 0698/1077] qemu-file: Remove QEMUFileHooks The only user was rdma, and its use is gone. Reviewed-by: Peter Xu Reviewed-by: Li Zhijian Signed-off-by: Juan Quintela Message-ID: <20231011203527.9061-8-quintela@redhat.com> --- migration/qemu-file.c | 6 ------ migration/qemu-file.h | 4 ---- migration/rdma.c | 9 --------- 3 files changed, 19 deletions(-) diff --git a/migration/qemu-file.c b/migration/qemu-file.c index 745eaf7a5b..3fb25148d1 100644 --- a/migration/qemu-file.c +++ b/migration/qemu-file.c @@ -38,7 +38,6 @@ #define MAX_IOV_SIZE MIN_CONST(IOV_MAX, 64) struct QEMUFile { - const QEMUFileHooks *hooks; QIOChannel *ioc; bool is_writable; @@ -133,11 +132,6 @@ QEMUFile *qemu_file_new_input(QIOChannel *ioc) return qemu_file_new_impl(ioc, false); } -void qemu_file_set_hooks(QEMUFile *f, const QEMUFileHooks *hooks) -{ - f->hooks = hooks; -} - /* * Get last error for stream f with optional Error* * diff --git a/migration/qemu-file.h b/migration/qemu-file.h index 60510a2819..0b22d8335f 100644 --- a/migration/qemu-file.h +++ b/migration/qemu-file.h @@ -36,12 +36,8 @@ #define RAM_CONTROL_ROUND 1 #define RAM_CONTROL_FINISH 3 -typedef struct QEMUFileHooks { -} QEMUFileHooks; - QEMUFile *qemu_file_new_input(QIOChannel *ioc); QEMUFile *qemu_file_new_output(QIOChannel *ioc); -void qemu_file_set_hooks(QEMUFile *f, const QEMUFileHooks *hooks); int qemu_fclose(QEMUFile *f); /* diff --git a/migration/rdma.c b/migration/rdma.c index f66bd939d7..9883b0a250 100644 --- a/migration/rdma.c +++ b/migration/rdma.c @@ -4003,13 +4003,6 @@ err: return -1; } -static const QEMUFileHooks rdma_read_hooks = { -}; - -static const QEMUFileHooks rdma_write_hooks = { -}; - - static void qio_channel_rdma_finalize(Object *obj) { QIOChannelRDMA *rioc = QIO_CHANNEL_RDMA(obj); @@ -4061,7 +4054,6 @@ static QEMUFile *rdma_new_input(RDMAContext *rdma) rioc->file = qemu_file_new_input(QIO_CHANNEL(rioc)); rioc->rdmain = rdma; rioc->rdmaout = rdma->return_path; - qemu_file_set_hooks(rioc->file, &rdma_read_hooks); return rioc->file; } @@ -4073,7 +4065,6 @@ static QEMUFile *rdma_new_output(RDMAContext *rdma) rioc->file = qemu_file_new_output(QIO_CHANNEL(rioc)); rioc->rdmaout = rdma; rioc->rdmain = rdma->return_path; - qemu_file_set_hooks(rioc->file, &rdma_write_hooks); return rioc->file; } From 10cb3336b11edeabae324148cbf924dfb7464bfa Mon Sep 17 00:00:00 2001 From: Juan Quintela Date: Wed, 11 Oct 2023 22:35:22 +0200 Subject: [PATCH 0699/1077] migration/rdma: Move rdma constants from qemu-file.h to rdma.h Reviewed-by: Peter Xu Reviewed-by: Li Zhijian Signed-off-by: Juan Quintela Message-ID: <20231011203527.9061-9-quintela@redhat.com> --- migration/qemu-file.h | 17 ----------------- migration/ram.c | 2 +- migration/rdma.h | 16 ++++++++++++++++ 3 files changed, 17 insertions(+), 18 deletions(-) diff --git a/migration/qemu-file.h b/migration/qemu-file.h index 0b22d8335f..a29c37b0d0 100644 --- a/migration/qemu-file.h +++ b/migration/qemu-file.h @@ -29,13 +29,6 @@ #include "exec/cpu-common.h" #include "io/channel.h" -/* - * Constants used by ram_control_* hooks - */ -#define RAM_CONTROL_SETUP 0 -#define RAM_CONTROL_ROUND 1 -#define RAM_CONTROL_FINISH 3 - QEMUFile *qemu_file_new_input(QIOChannel *ioc); QEMUFile *qemu_file_new_output(QIOChannel *ioc); int qemu_fclose(QEMUFile *f); @@ -101,16 +94,6 @@ void qemu_fflush(QEMUFile *f); void qemu_file_set_blocking(QEMUFile *f, bool block); int qemu_file_get_to_fd(QEMUFile *f, int fd, size_t size); -/* Whenever this is found in the data stream, the flags - * will be passed to ram_control_load_hook in the incoming-migration - * side. This lets before_ram_iterate/after_ram_iterate add - * transport-specific sections to the RAM migration data. - */ -#define RAM_SAVE_FLAG_HOOK 0x80 - -#define RAM_SAVE_CONTROL_NOT_SUPP -1000 -#define RAM_SAVE_CONTROL_DELAYED -2000 - QIOChannel *qemu_file_get_ioc(QEMUFile *file); #endif diff --git a/migration/ram.c b/migration/ram.c index 3b4b09f6ff..6a4aed2a75 100644 --- a/migration/ram.c +++ b/migration/ram.c @@ -89,7 +89,7 @@ #define RAM_SAVE_FLAG_EOS 0x10 #define RAM_SAVE_FLAG_CONTINUE 0x20 #define RAM_SAVE_FLAG_XBZRLE 0x40 -/* 0x80 is reserved in qemu-file.h for RAM_SAVE_FLAG_HOOK */ +/* 0x80 is reserved in rdma.h for RAM_SAVE_FLAG_HOOK */ #define RAM_SAVE_FLAG_COMPRESS_PAGE 0x100 #define RAM_SAVE_FLAG_MULTIFD_FLUSH 0x200 /* We can't use any flag that is bigger than 0x200 */ diff --git a/migration/rdma.h b/migration/rdma.h index 09a16c1e3c..1ff3718a76 100644 --- a/migration/rdma.h +++ b/migration/rdma.h @@ -24,6 +24,22 @@ void rdma_start_outgoing_migration(void *opaque, const char *host_port, void rdma_start_incoming_migration(const char *host_port, Error **errp); +/* + * Constants used by rdma return codes + */ +#define RAM_CONTROL_SETUP 0 +#define RAM_CONTROL_ROUND 1 +#define RAM_CONTROL_FINISH 3 + +/* + * Whenever this is found in the data stream, the flags + * will be passed to rdma functions in the incoming-migration + * side. + */ +#define RAM_SAVE_FLAG_HOOK 0x80 + +#define RAM_SAVE_CONTROL_NOT_SUPP -1000 +#define RAM_SAVE_CONTROL_DELAYED -2000 #ifdef CONFIG_RDMA int qemu_rdma_registration_handle(QEMUFile *f); From b1b383872211a80a2011313969cb26e2ec43fa24 Mon Sep 17 00:00:00 2001 From: Juan Quintela Date: Wed, 11 Oct 2023 22:35:23 +0200 Subject: [PATCH 0700/1077] migration/rdma: Remove qemu_ prefix from exported functions Functions are long enough even without this. Reviewed-by: Peter Xu Reviewed-by: Li Zhijian Signed-off-by: Juan Quintela Message-ID: <20231011203527.9061-10-quintela@redhat.com> --- migration/ram.c | 14 +++++++------- migration/rdma.c | 40 +++++++++++++++++++--------------------- migration/rdma.h | 12 ++++++------ migration/trace-events | 28 ++++++++++++++-------------- 4 files changed, 46 insertions(+), 48 deletions(-) diff --git a/migration/ram.c b/migration/ram.c index 6a4aed2a75..a9bc6ae1f1 100644 --- a/migration/ram.c +++ b/migration/ram.c @@ -3061,12 +3061,12 @@ static int ram_save_setup(QEMUFile *f, void *opaque) } } - ret = qemu_rdma_registration_start(f, RAM_CONTROL_SETUP); + ret = rdma_registration_start(f, RAM_CONTROL_SETUP); if (ret < 0) { qemu_file_set_error(f, ret); } - ret = qemu_rdma_registration_stop(f, RAM_CONTROL_SETUP); + ret = rdma_registration_stop(f, RAM_CONTROL_SETUP); if (ret < 0) { qemu_file_set_error(f, ret); } @@ -3131,7 +3131,7 @@ static int ram_save_iterate(QEMUFile *f, void *opaque) /* Read version before ram_list.blocks */ smp_rmb(); - ret = qemu_rdma_registration_start(f, RAM_CONTROL_ROUND); + ret = rdma_registration_start(f, RAM_CONTROL_ROUND); if (ret < 0) { qemu_file_set_error(f, ret); } @@ -3191,7 +3191,7 @@ static int ram_save_iterate(QEMUFile *f, void *opaque) * Must occur before EOS (or any QEMUFile operation) * because of RDMA protocol. */ - ret = qemu_rdma_registration_stop(f, RAM_CONTROL_ROUND); + ret = rdma_registration_stop(f, RAM_CONTROL_ROUND); if (ret < 0) { qemu_file_set_error(f, ret); } @@ -3242,7 +3242,7 @@ static int ram_save_complete(QEMUFile *f, void *opaque) migration_bitmap_sync_precopy(rs, true); } - ret = qemu_rdma_registration_start(f, RAM_CONTROL_FINISH); + ret = rdma_registration_start(f, RAM_CONTROL_FINISH); if (ret < 0) { qemu_file_set_error(f, ret); } @@ -3268,7 +3268,7 @@ static int ram_save_complete(QEMUFile *f, void *opaque) ram_flush_compressed_data(rs); - int ret = qemu_rdma_registration_stop(f, RAM_CONTROL_FINISH); + int ret = rdma_registration_stop(f, RAM_CONTROL_FINISH); if (ret < 0) { qemu_file_set_error(f, ret); } @@ -4077,7 +4077,7 @@ static int ram_load_precopy(QEMUFile *f) } break; case RAM_SAVE_FLAG_HOOK: - ret = qemu_rdma_registration_handle(f); + ret = rdma_registration_handle(f); if (ret < 0) { qemu_file_set_error(f, ret); } diff --git a/migration/rdma.c b/migration/rdma.c index 9883b0a250..c147c94b08 100644 --- a/migration/rdma.c +++ b/migration/rdma.c @@ -3540,7 +3540,7 @@ static int dest_ram_sort_func(const void *a, const void *b) * * Keep doing this until the source tells us to stop. */ -int qemu_rdma_registration_handle(QEMUFile *f) +int rdma_registration_handle(QEMUFile *f) { RDMAControlHeader reg_resp = { .len = sizeof(RDMARegisterResult), .type = RDMA_CONTROL_REGISTER_RESULT, @@ -3586,7 +3586,7 @@ int qemu_rdma_registration_handle(QEMUFile *f) local = &rdma->local_ram_blocks; do { - trace_qemu_rdma_registration_handle_wait(); + trace_rdma_registration_handle_wait(); ret = qemu_rdma_exchange_recv(rdma, &head, RDMA_CONTROL_NONE, &err); @@ -3606,9 +3606,9 @@ int qemu_rdma_registration_handle(QEMUFile *f) comp = (RDMACompress *) rdma->wr_data[idx].control_curr; network_to_compress(comp); - trace_qemu_rdma_registration_handle_compress(comp->length, - comp->block_idx, - comp->offset); + trace_rdma_registration_handle_compress(comp->length, + comp->block_idx, + comp->offset); if (comp->block_idx >= rdma->local_ram_blocks.nb_blocks) { error_report("rdma: 'compress' bad block index %u (vs %d)", (unsigned int)comp->block_idx, @@ -3624,11 +3624,11 @@ int qemu_rdma_registration_handle(QEMUFile *f) break; case RDMA_CONTROL_REGISTER_FINISHED: - trace_qemu_rdma_registration_handle_finished(); + trace_rdma_registration_handle_finished(); return 0; case RDMA_CONTROL_RAM_BLOCKS_REQUEST: - trace_qemu_rdma_registration_handle_ram_blocks(); + trace_rdma_registration_handle_ram_blocks(); /* Sort our local RAM Block list so it's the same as the source, * we can do this since we've filled in a src_index in the list @@ -3667,7 +3667,7 @@ int qemu_rdma_registration_handle(QEMUFile *f) rdma->dest_blocks[i].length = local->block[i].length; dest_block_to_network(&rdma->dest_blocks[i]); - trace_qemu_rdma_registration_handle_ram_blocks_loop( + trace_rdma_registration_handle_ram_blocks_loop( local->block[i].block_name, local->block[i].offset, local->block[i].length, @@ -3690,7 +3690,7 @@ int qemu_rdma_registration_handle(QEMUFile *f) break; case RDMA_CONTROL_REGISTER_REQUEST: - trace_qemu_rdma_registration_handle_register(head.repeat); + trace_rdma_registration_handle_register(head.repeat); reg_resp.repeat = head.repeat; registers = (RDMARegister *) rdma->wr_data[idx].control_curr; @@ -3704,7 +3704,7 @@ int qemu_rdma_registration_handle(QEMUFile *f) reg_result = &results[count]; - trace_qemu_rdma_registration_handle_register_loop(count, + trace_rdma_registration_handle_register_loop(count, reg->current_index, reg->key.current_addr, reg->chunks); if (reg->current_index >= rdma->local_ram_blocks.nb_blocks) { @@ -3752,8 +3752,7 @@ int qemu_rdma_registration_handle(QEMUFile *f) reg_result->host_addr = (uintptr_t)block->local_host_addr; - trace_qemu_rdma_registration_handle_register_rkey( - reg_result->rkey); + trace_rdma_registration_handle_register_rkey(reg_result->rkey); result_to_network(reg_result); } @@ -3767,7 +3766,7 @@ int qemu_rdma_registration_handle(QEMUFile *f) } break; case RDMA_CONTROL_UNREGISTER_REQUEST: - trace_qemu_rdma_registration_handle_unregister(head.repeat); + trace_rdma_registration_handle_unregister(head.repeat); unreg_resp.repeat = head.repeat; registers = (RDMARegister *) rdma->wr_data[idx].control_curr; @@ -3775,7 +3774,7 @@ int qemu_rdma_registration_handle(QEMUFile *f) reg = ®isters[count]; network_to_register(reg); - trace_qemu_rdma_registration_handle_unregister_loop(count, + trace_rdma_registration_handle_unregister_loop(count, reg->current_index, reg->key.chunk); block = &(rdma->local_ram_blocks.block[reg->current_index]); @@ -3791,8 +3790,7 @@ int qemu_rdma_registration_handle(QEMUFile *f) rdma->total_registrations--; - trace_qemu_rdma_registration_handle_unregister_success( - reg->key.chunk); + trace_rdma_registration_handle_unregister_success(reg->key.chunk); } ret = qemu_rdma_post_send_control(rdma, NULL, &unreg_resp, &err); @@ -3859,7 +3857,7 @@ int rdma_block_notification_handle(QEMUFile *f, const char *name) return 0; } -int qemu_rdma_registration_start(QEMUFile *f, uint64_t flags) +int rdma_registration_start(QEMUFile *f, uint64_t flags) { if (!migrate_rdma() || migration_in_postcopy()) { return 0; @@ -3876,7 +3874,7 @@ int qemu_rdma_registration_start(QEMUFile *f, uint64_t flags) return -1; } - trace_qemu_rdma_registration_start(flags); + trace_rdma_registration_start(flags); qemu_put_be64(f, RAM_SAVE_FLAG_HOOK); qemu_fflush(f); @@ -3887,7 +3885,7 @@ int qemu_rdma_registration_start(QEMUFile *f, uint64_t flags) * Inform dest that dynamic registrations are done for now. * First, flush writes, if any. */ -int qemu_rdma_registration_stop(QEMUFile *f, uint64_t flags) +int rdma_registration_stop(QEMUFile *f, uint64_t flags) { QIOChannelRDMA *rioc; Error *err = NULL; @@ -3923,7 +3921,7 @@ int qemu_rdma_registration_stop(QEMUFile *f, uint64_t flags) int reg_result_idx, i, nb_dest_blocks; head.type = RDMA_CONTROL_RAM_BLOCKS_REQUEST; - trace_qemu_rdma_registration_stop_ram(); + trace_rdma_registration_stop_ram(); /* * Make sure that we parallelize the pinning on both sides. @@ -3987,7 +3985,7 @@ int qemu_rdma_registration_stop(QEMUFile *f, uint64_t flags) } } - trace_qemu_rdma_registration_stop(flags); + trace_rdma_registration_stop(flags); head.type = RDMA_CONTROL_REGISTER_FINISHED; ret = qemu_rdma_exchange_send(rdma, &head, NULL, NULL, NULL, NULL, &err); diff --git a/migration/rdma.h b/migration/rdma.h index 1ff3718a76..30b15b4466 100644 --- a/migration/rdma.h +++ b/migration/rdma.h @@ -42,19 +42,19 @@ void rdma_start_incoming_migration(const char *host_port, Error **errp); #define RAM_SAVE_CONTROL_DELAYED -2000 #ifdef CONFIG_RDMA -int qemu_rdma_registration_handle(QEMUFile *f); -int qemu_rdma_registration_start(QEMUFile *f, uint64_t flags); -int qemu_rdma_registration_stop(QEMUFile *f, uint64_t flags); +int rdma_registration_handle(QEMUFile *f); +int rdma_registration_start(QEMUFile *f, uint64_t flags); +int rdma_registration_stop(QEMUFile *f, uint64_t flags); int rdma_block_notification_handle(QEMUFile *f, const char *name); int rdma_control_save_page(QEMUFile *f, ram_addr_t block_offset, ram_addr_t offset, size_t size); #else static inline -int qemu_rdma_registration_handle(QEMUFile *f) { return 0; } +int rdma_registration_handle(QEMUFile *f) { return 0; } static inline -int qemu_rdma_registration_start(QEMUFile *f, uint64_t flags) { return 0; } +int rdma_registration_start(QEMUFile *f, uint64_t flags) { return 0; } static inline -int qemu_rdma_registration_stop(QEMUFile *f, uint64_t flags) { return 0; } +int rdma_registration_stop(QEMUFile *f, uint64_t flags) { return 0; } static inline int rdma_block_notification_handle(QEMUFile *f, const char *name) { return 0; } static inline diff --git a/migration/trace-events b/migration/trace-events index d8c2aa846d..403cc1ae11 100644 --- a/migration/trace-events +++ b/migration/trace-events @@ -231,20 +231,6 @@ qemu_rdma_post_send_control(const char *desc) "CONTROL: sending %s.." qemu_rdma_register_and_get_keys(uint64_t len, void *start) "Registering %" PRIu64 " bytes @ %p" qemu_rdma_register_odp_mr(const char *name) "Try to register On-Demand Paging memory region: %s" qemu_rdma_advise_mr(const char *name, uint32_t len, uint64_t addr, const char *res) "Try to advise block %s prefetch at %" PRIu32 "@0x%" PRIx64 ": %s" -qemu_rdma_registration_handle_compress(int64_t length, int index, int64_t offset) "Zapping zero chunk: %" PRId64 " bytes, index %d, offset %" PRId64 -qemu_rdma_registration_handle_finished(void) "" -qemu_rdma_registration_handle_ram_blocks(void) "" -qemu_rdma_registration_handle_ram_blocks_loop(const char *name, uint64_t offset, uint64_t length, void *local_host_addr, unsigned int src_index) "%s: @0x%" PRIx64 "/%" PRIu64 " host:@%p src_index: %u" -qemu_rdma_registration_handle_register(int requests) "%d requests" -qemu_rdma_registration_handle_register_loop(int req, int index, uint64_t addr, uint64_t chunks) "Registration request (%d): index %d, current_addr %" PRIu64 " chunks: %" PRIu64 -qemu_rdma_registration_handle_register_rkey(int rkey) "0x%x" -qemu_rdma_registration_handle_unregister(int requests) "%d requests" -qemu_rdma_registration_handle_unregister_loop(int count, int index, uint64_t chunk) "Unregistration request (%d): index %d, chunk %" PRIu64 -qemu_rdma_registration_handle_unregister_success(uint64_t chunk) "%" PRIu64 -qemu_rdma_registration_handle_wait(void) "" -qemu_rdma_registration_start(uint64_t flags) "%" PRIu64 -qemu_rdma_registration_stop(uint64_t flags) "%" PRIu64 -qemu_rdma_registration_stop_ram(void) "" qemu_rdma_resolve_host_trying(const char *host, const char *ip) "Trying %s => %s" qemu_rdma_signal_unregister_append(uint64_t chunk, int pos) "Appending unregister chunk %" PRIu64 " at position %d" qemu_rdma_signal_unregister_already(uint64_t chunk) "Unregister chunk %" PRIu64 " already in queue" @@ -263,6 +249,20 @@ qemu_rdma_write_one_zero(uint64_t chunk, int len, int index, int64_t offset) "En rdma_add_block(const char *block_name, int block, uint64_t addr, uint64_t offset, uint64_t len, uint64_t end, uint64_t bits, int chunks) "Added Block: '%s':%d, addr: %" PRIu64 ", offset: %" PRIu64 " length: %" PRIu64 " end: %" PRIu64 " bits %" PRIu64 " chunks %d" rdma_block_notification_handle(const char *name, int index) "%s at %d" rdma_delete_block(void *block, uint64_t addr, uint64_t offset, uint64_t len, uint64_t end, uint64_t bits, int chunks) "Deleted Block: %p, addr: %" PRIu64 ", offset: %" PRIu64 " length: %" PRIu64 " end: %" PRIu64 " bits %" PRIu64 " chunks %d" +rdma_registration_handle_compress(int64_t length, int index, int64_t offset) "Zapping zero chunk: %" PRId64 " bytes, index %d, offset %" PRId64 +rdma_registration_handle_finished(void) "" +rdma_registration_handle_ram_blocks(void) "" +rdma_registration_handle_ram_blocks_loop(const char *name, uint64_t offset, uint64_t length, void *local_host_addr, unsigned int src_index) "%s: @0x%" PRIx64 "/%" PRIu64 " host:@%p src_index: %u" +rdma_registration_handle_register(int requests) "%d requests" +rdma_registration_handle_register_loop(int req, int index, uint64_t addr, uint64_t chunks) "Registration request (%d): index %d, current_addr %" PRIu64 " chunks: %" PRIu64 +rdma_registration_handle_register_rkey(int rkey) "0x%x" +rdma_registration_handle_unregister(int requests) "%d requests" +rdma_registration_handle_unregister_loop(int count, int index, uint64_t chunk) "Unregistration request (%d): index %d, chunk %" PRIu64 +rdma_registration_handle_unregister_success(uint64_t chunk) "%" PRIu64 +rdma_registration_handle_wait(void) "" +rdma_registration_start(uint64_t flags) "%" PRIu64 +rdma_registration_stop(uint64_t flags) "%" PRIu64 +rdma_registration_stop_ram(void) "" rdma_start_incoming_migration(void) "" rdma_start_incoming_migration_after_dest_init(void) "" rdma_start_incoming_migration_after_rdma_listen(void) "" From a4832d299ddefb3bbcf8561d9444a17addb1076c Mon Sep 17 00:00:00 2001 From: Juan Quintela Date: Wed, 11 Oct 2023 22:35:24 +0200 Subject: [PATCH 0701/1077] migration/rdma: Check sooner if we are in postcopy for save_page() Reviewed-by: Peter Xu Reviewed-by: Li Zhijian Signed-off-by: Juan Quintela Message-ID: <20231011203527.9061-11-quintela@redhat.com> --- migration/rdma.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/migration/rdma.c b/migration/rdma.c index c147c94b08..e973579a52 100644 --- a/migration/rdma.c +++ b/migration/rdma.c @@ -3240,10 +3240,6 @@ static int qemu_rdma_save_page(QEMUFile *f, ram_addr_t block_offset, RDMAContext *rdma; int ret; - if (migration_in_postcopy()) { - return RAM_SAVE_CONTROL_NOT_SUPP; - } - RCU_READ_LOCK_GUARD(); rdma = qatomic_rcu_read(&rioc->rdmaout); @@ -3317,7 +3313,7 @@ err: int rdma_control_save_page(QEMUFile *f, ram_addr_t block_offset, ram_addr_t offset, size_t size) { - if (!migrate_rdma()) { + if (!migrate_rdma() || migration_in_postcopy()) { return RAM_SAVE_CONTROL_NOT_SUPP; } From ebdb85f9d13237287a165f1097e68206a7d5181b Mon Sep 17 00:00:00 2001 From: Juan Quintela Date: Wed, 11 Oct 2023 22:35:25 +0200 Subject: [PATCH 0702/1077] migration/rdma: Use i as for index instead of idx Once there, all the uses are local to the for, so declare the variable inside the for statement. Reviewed-by: Fabiano Rosas Reviewed-by: Li Zhijian Signed-off-by: Juan Quintela Message-ID: <20231011203527.9061-12-quintela@redhat.com> --- migration/rdma.c | 49 ++++++++++++++++++++++-------------------------- 1 file changed, 22 insertions(+), 27 deletions(-) diff --git a/migration/rdma.c b/migration/rdma.c index e973579a52..5f6a771e8e 100644 --- a/migration/rdma.c +++ b/migration/rdma.c @@ -2354,7 +2354,6 @@ static int qemu_rdma_write(RDMAContext *rdma, static void qemu_rdma_cleanup(RDMAContext *rdma) { Error *err = NULL; - int idx; if (rdma->cm_id && rdma->connected) { if ((rdma->errored || @@ -2381,12 +2380,12 @@ static void qemu_rdma_cleanup(RDMAContext *rdma) g_free(rdma->dest_blocks); rdma->dest_blocks = NULL; - for (idx = 0; idx < RDMA_WRID_MAX; idx++) { - if (rdma->wr_data[idx].control_mr) { + for (int i = 0; i < RDMA_WRID_MAX; i++) { + if (rdma->wr_data[i].control_mr) { rdma->total_registrations--; - ibv_dereg_mr(rdma->wr_data[idx].control_mr); + ibv_dereg_mr(rdma->wr_data[i].control_mr); } - rdma->wr_data[idx].control_mr = NULL; + rdma->wr_data[i].control_mr = NULL; } if (rdma->local_ram_blocks.block) { @@ -2452,7 +2451,7 @@ static void qemu_rdma_cleanup(RDMAContext *rdma) static int qemu_rdma_source_init(RDMAContext *rdma, bool pin_all, Error **errp) { - int ret, idx; + int ret; /* * Will be validated against destination's actual capabilities @@ -2480,18 +2479,17 @@ static int qemu_rdma_source_init(RDMAContext *rdma, bool pin_all, Error **errp) /* Build the hash that maps from offset to RAMBlock */ rdma->blockmap = g_hash_table_new(g_direct_hash, g_direct_equal); - for (idx = 0; idx < rdma->local_ram_blocks.nb_blocks; idx++) { + for (int i = 0; i < rdma->local_ram_blocks.nb_blocks; i++) { g_hash_table_insert(rdma->blockmap, - (void *)(uintptr_t)rdma->local_ram_blocks.block[idx].offset, - &rdma->local_ram_blocks.block[idx]); + (void *)(uintptr_t)rdma->local_ram_blocks.block[i].offset, + &rdma->local_ram_blocks.block[i]); } - for (idx = 0; idx < RDMA_WRID_MAX; idx++) { - ret = qemu_rdma_reg_control(rdma, idx); + for (int i = 0; i < RDMA_WRID_MAX; i++) { + ret = qemu_rdma_reg_control(rdma, i); if (ret < 0) { - error_setg(errp, - "RDMA ERROR: rdma migration: error registering %d control!", - idx); + error_setg(errp, "RDMA ERROR: rdma migration: error " + "registering %d control!", i); goto err_rdma_source_init; } } @@ -2625,16 +2623,16 @@ err_rdma_source_connect: static int qemu_rdma_dest_init(RDMAContext *rdma, Error **errp) { Error *err = NULL; - int ret, idx; + int ret; struct rdma_cm_id *listen_id; char ip[40] = "unknown"; struct rdma_addrinfo *res, *e; char port_str[16]; int reuse = 1; - for (idx = 0; idx < RDMA_WRID_MAX; idx++) { - rdma->wr_data[idx].control_len = 0; - rdma->wr_data[idx].control_curr = NULL; + for (int i = 0; i < RDMA_WRID_MAX; i++) { + rdma->wr_data[i].control_len = 0; + rdma->wr_data[i].control_curr = NULL; } if (!rdma->host || !rdma->host[0]) { @@ -2723,11 +2721,9 @@ err_dest_init_create_listen_id: static void qemu_rdma_return_path_dest_init(RDMAContext *rdma_return_path, RDMAContext *rdma) { - int idx; - - for (idx = 0; idx < RDMA_WRID_MAX; idx++) { - rdma_return_path->wr_data[idx].control_len = 0; - rdma_return_path->wr_data[idx].control_curr = NULL; + for (int i = 0; i < RDMA_WRID_MAX; i++) { + rdma_return_path->wr_data[i].control_len = 0; + rdma_return_path->wr_data[i].control_curr = NULL; } /*the CM channel and CM id is shared*/ @@ -3376,7 +3372,6 @@ static int qemu_rdma_accept(RDMAContext *rdma) struct rdma_cm_event *cm_event; struct ibv_context *verbs; int ret; - int idx; ret = rdma_get_cm_event(rdma->channel, &cm_event); if (ret < 0) { @@ -3462,10 +3457,10 @@ static int qemu_rdma_accept(RDMAContext *rdma) qemu_rdma_init_ram_blocks(rdma); - for (idx = 0; idx < RDMA_WRID_MAX; idx++) { - ret = qemu_rdma_reg_control(rdma, idx); + for (int i = 0; i < RDMA_WRID_MAX; i++) { + ret = qemu_rdma_reg_control(rdma, i); if (ret < 0) { - error_report("rdma: error registering %d control", idx); + error_report("rdma: error registering %d control", i); goto err_rdma_dest_wait; } } From 14e2fcbbf80fc3c25c182f6624207daf64de9d88 Mon Sep 17 00:00:00 2001 From: Juan Quintela Date: Wed, 11 Oct 2023 22:35:26 +0200 Subject: [PATCH 0703/1077] migration/rdma: Declare for index variables local Declare all variables that are only used inside a for loop inside the for statement. This makes clear that they are not used outside of the for loop. Reviewed-by: Fabiano Rosas Reviewed-by: Li Zhijian Signed-off-by: Juan Quintela Message-ID: <20231011203527.9061-13-quintela@redhat.com> --- migration/rdma.c | 44 ++++++++++++++++++-------------------------- 1 file changed, 18 insertions(+), 26 deletions(-) diff --git a/migration/rdma.c b/migration/rdma.c index 5f6a771e8e..09015fbd1a 100644 --- a/migration/rdma.c +++ b/migration/rdma.c @@ -559,10 +559,8 @@ static void rdma_add_block(RDMAContext *rdma, const char *block_name, local->block = g_new0(RDMALocalBlock, local->nb_blocks + 1); if (local->nb_blocks) { - int x; - if (rdma->blockmap) { - for (x = 0; x < local->nb_blocks; x++) { + for (int x = 0; x < local->nb_blocks; x++) { g_hash_table_remove(rdma->blockmap, (void *)(uintptr_t)old[x].offset); g_hash_table_insert(rdma->blockmap, @@ -649,15 +647,12 @@ static void rdma_delete_block(RDMAContext *rdma, RDMALocalBlock *block) { RDMALocalBlocks *local = &rdma->local_ram_blocks; RDMALocalBlock *old = local->block; - int x; if (rdma->blockmap) { g_hash_table_remove(rdma->blockmap, (void *)(uintptr_t)block->offset); } if (block->pmr) { - int j; - - for (j = 0; j < block->nb_chunks; j++) { + for (int j = 0; j < block->nb_chunks; j++) { if (!block->pmr[j]) { continue; } @@ -687,7 +682,7 @@ static void rdma_delete_block(RDMAContext *rdma, RDMALocalBlock *block) block->block_name = NULL; if (rdma->blockmap) { - for (x = 0; x < local->nb_blocks; x++) { + for (int x = 0; x < local->nb_blocks; x++) { g_hash_table_remove(rdma->blockmap, (void *)(uintptr_t)old[x].offset); } @@ -705,7 +700,7 @@ static void rdma_delete_block(RDMAContext *rdma, RDMALocalBlock *block) memcpy(local->block + block->index, old + (block->index + 1), sizeof(RDMALocalBlock) * (local->nb_blocks - (block->index + 1))); - for (x = block->index; x < local->nb_blocks - 1; x++) { + for (int x = block->index; x < local->nb_blocks - 1; x++) { local->block[x].index--; } } @@ -725,7 +720,7 @@ static void rdma_delete_block(RDMAContext *rdma, RDMALocalBlock *block) local->nb_blocks--; if (local->nb_blocks && rdma->blockmap) { - for (x = 0; x < local->nb_blocks; x++) { + for (int x = 0; x < local->nb_blocks; x++) { g_hash_table_insert(rdma->blockmap, (void *)(uintptr_t)local->block[x].offset, &local->block[x]); @@ -828,12 +823,12 @@ static int qemu_rdma_broken_ipv6_kernel(struct ibv_context *verbs, Error **errp) * Otherwise, there are no guarantees until the bug is fixed in linux. */ if (!verbs) { - int num_devices, x; + int num_devices; struct ibv_device **dev_list = ibv_get_device_list(&num_devices); bool roce_found = false; bool ib_found = false; - for (x = 0; x < num_devices; x++) { + for (int x = 0; x < num_devices; x++) { verbs = ibv_open_device(dev_list[x]); /* * ibv_open_device() is not documented to set errno. If @@ -925,7 +920,6 @@ static int qemu_rdma_resolve_host(RDMAContext *rdma, Error **errp) char port_str[16]; struct rdma_cm_event *cm_event; char ip[40] = "unknown"; - struct rdma_addrinfo *e; if (rdma->host == NULL || !strcmp(rdma->host, "")) { error_setg(errp, "RDMA ERROR: RDMA hostname has not been set"); @@ -957,7 +951,7 @@ static int qemu_rdma_resolve_host(RDMAContext *rdma, Error **errp) } /* Try all addresses, saving the first error in @err */ - for (e = res; e != NULL; e = e->ai_next) { + for (struct rdma_addrinfo *e = res; e != NULL; e = e->ai_next) { Error **local_errp = err ? NULL : &err; inet_ntop(e->ai_family, @@ -2777,7 +2771,7 @@ static ssize_t qio_channel_rdma_writev(QIOChannel *ioc, RDMAContext *rdma; int ret; ssize_t done = 0; - size_t i, len; + size_t len; RCU_READ_LOCK_GUARD(); rdma = qatomic_rcu_read(&rioc->rdmaout); @@ -2803,7 +2797,7 @@ static ssize_t qio_channel_rdma_writev(QIOChannel *ioc, return -1; } - for (i = 0; i < niov; i++) { + for (int i = 0; i < niov; i++) { size_t remaining = iov[i].iov_len; uint8_t * data = (void *)iov[i].iov_base; while (remaining) { @@ -2866,7 +2860,7 @@ static ssize_t qio_channel_rdma_readv(QIOChannel *ioc, RDMAControlHeader head; int ret; ssize_t done = 0; - size_t i, len; + size_t len; RCU_READ_LOCK_GUARD(); rdma = qatomic_rcu_read(&rioc->rdmain); @@ -2882,7 +2876,7 @@ static ssize_t qio_channel_rdma_readv(QIOChannel *ioc, return -1; } - for (i = 0; i < niov; i++) { + for (int i = 0; i < niov; i++) { size_t want = iov[i].iov_len; uint8_t *data = (void *)iov[i].iov_base; @@ -3556,8 +3550,6 @@ int rdma_registration_handle(QEMUFile *f) void *host_addr; int ret; int idx = 0; - int count = 0; - int i = 0; if (!migrate_rdma()) { return 0; @@ -3628,7 +3620,7 @@ int rdma_registration_handle(QEMUFile *f) qsort(rdma->local_ram_blocks.block, rdma->local_ram_blocks.nb_blocks, sizeof(RDMALocalBlock), dest_ram_sort_func); - for (i = 0; i < local->nb_blocks; i++) { + for (int i = 0; i < local->nb_blocks; i++) { local->block[i].index = i; } @@ -3646,7 +3638,7 @@ int rdma_registration_handle(QEMUFile *f) * Both sides use the "remote" structure to communicate and update * their "local" descriptions with what was sent. */ - for (i = 0; i < local->nb_blocks; i++) { + for (int i = 0; i < local->nb_blocks; i++) { rdma->dest_blocks[i].remote_host_addr = (uintptr_t)(local->block[i].local_host_addr); @@ -3686,7 +3678,7 @@ int rdma_registration_handle(QEMUFile *f) reg_resp.repeat = head.repeat; registers = (RDMARegister *) rdma->wr_data[idx].control_curr; - for (count = 0; count < head.repeat; count++) { + for (int count = 0; count < head.repeat; count++) { uint64_t chunk; uint8_t *chunk_start, *chunk_end; @@ -3761,7 +3753,7 @@ int rdma_registration_handle(QEMUFile *f) unreg_resp.repeat = head.repeat; registers = (RDMARegister *) rdma->wr_data[idx].control_curr; - for (count = 0; count < head.repeat; count++) { + for (int count = 0; count < head.repeat; count++) { reg = ®isters[count]; network_to_register(reg); @@ -3909,7 +3901,7 @@ int rdma_registration_stop(QEMUFile *f, uint64_t flags) if (flags == RAM_CONTROL_SETUP) { RDMAControlHeader resp = {.type = RDMA_CONTROL_RAM_BLOCKS_RESULT }; RDMALocalBlocks *local = &rdma->local_ram_blocks; - int reg_result_idx, i, nb_dest_blocks; + int reg_result_idx, nb_dest_blocks; head.type = RDMA_CONTROL_RAM_BLOCKS_REQUEST; trace_rdma_registration_stop_ram(); @@ -3957,7 +3949,7 @@ int rdma_registration_stop(QEMUFile *f, uint64_t flags) qemu_rdma_move_header(rdma, reg_result_idx, &resp); memcpy(rdma->dest_blocks, rdma->wr_data[reg_result_idx].control_curr, resp.len); - for (i = 0; i < nb_dest_blocks; i++) { + for (int i = 0; i < nb_dest_blocks; i++) { network_to_dest_block(&rdma->dest_blocks[i]); /* We require that the blocks are in the same order */ From 8f5a7faa4e60e93cf4f014ed100efa4206f6d7ae Mon Sep 17 00:00:00 2001 From: Juan Quintela Date: Wed, 11 Oct 2023 22:35:27 +0200 Subject: [PATCH 0704/1077] migration/rdma: Remove all "ret" variables that are used only once Change code that is: int ret; ... ret = foo(); if (ret[ < 0]?) { to: if (foo()[ < 0]) { Reviewed-by: Fabiano Rosas Reviewed-by: Li Zhijian Signed-off-by: Juan Quintela Message-ID: <20231011203527.9061-14-quintela@redhat.com> --- migration/rdma.c | 29 ++++++++--------------------- 1 file changed, 8 insertions(+), 21 deletions(-) diff --git a/migration/rdma.c b/migration/rdma.c index 09015fbd1a..2a1852ec7f 100644 --- a/migration/rdma.c +++ b/migration/rdma.c @@ -1107,7 +1107,6 @@ err_alloc_pd_cq: static int qemu_rdma_alloc_qp(RDMAContext *rdma) { struct ibv_qp_init_attr attr = { 0 }; - int ret; attr.cap.max_send_wr = RDMA_SIGNALED_SEND_MAX; attr.cap.max_recv_wr = 3; @@ -1117,8 +1116,7 @@ static int qemu_rdma_alloc_qp(RDMAContext *rdma) attr.recv_cq = rdma->recv_cq; attr.qp_type = IBV_QPT_RC; - ret = rdma_create_qp(rdma->cm_id, rdma->pd, &attr); - if (ret < 0) { + if (rdma_create_qp(rdma->cm_id, rdma->pd, &attr) < 0) { return -1; } @@ -1130,8 +1128,8 @@ static int qemu_rdma_alloc_qp(RDMAContext *rdma) static bool rdma_support_odp(struct ibv_context *dev) { struct ibv_device_attr_ex attr = {0}; - int ret = ibv_query_device_ex(dev, NULL, &attr); - if (ret) { + + if (ibv_query_device_ex(dev, NULL, &attr)) { return false; } @@ -1508,7 +1506,6 @@ static int qemu_rdma_wait_comp_channel(RDMAContext *rdma, struct ibv_comp_channel *comp_channel) { struct rdma_cm_event *cm_event; - int ret; /* * Coroutine doesn't start until migration_fd_process_incoming() @@ -1544,8 +1541,7 @@ static int qemu_rdma_wait_comp_channel(RDMAContext *rdma, } if (pfds[1].revents) { - ret = rdma_get_cm_event(rdma->channel, &cm_event); - if (ret < 0) { + if (rdma_get_cm_event(rdma->channel, &cm_event) < 0) { return -1; } @@ -2317,12 +2313,10 @@ static int qemu_rdma_write(RDMAContext *rdma, uint64_t current_addr = block_offset + offset; uint64_t index = rdma->current_index; uint64_t chunk = rdma->current_chunk; - int ret; /* If we cannot merge it, we flush the current buffer first. */ if (!qemu_rdma_buffer_mergeable(rdma, current_addr, len)) { - ret = qemu_rdma_write_flush(rdma, errp); - if (ret < 0) { + if (qemu_rdma_write_flush(rdma, errp) < 0) { return -1; } rdma->current_length = 0; @@ -2936,7 +2930,6 @@ static ssize_t qio_channel_rdma_readv(QIOChannel *ioc, static int qemu_rdma_drain_cq(RDMAContext *rdma) { Error *err = NULL; - int ret; if (qemu_rdma_write_flush(rdma, &err) < 0) { error_report_err(err); @@ -2944,8 +2937,7 @@ static int qemu_rdma_drain_cq(RDMAContext *rdma) } while (rdma->nb_sent) { - ret = qemu_rdma_block_for_wrid(rdma, RDMA_WRID_RDMA_WRITE, NULL); - if (ret < 0) { + if (qemu_rdma_block_for_wrid(rdma, RDMA_WRID_RDMA_WRITE, NULL) < 0) { error_report("rdma migration: complete polling error!"); return -1; } @@ -3323,12 +3315,10 @@ static void rdma_accept_incoming_migration(void *opaque); static void rdma_cm_poll_handler(void *opaque) { RDMAContext *rdma = opaque; - int ret; struct rdma_cm_event *cm_event; MigrationIncomingState *mis = migration_incoming_get_current(); - ret = rdma_get_cm_event(rdma->channel, &cm_event); - if (ret < 0) { + if (rdma_get_cm_event(rdma->channel, &cm_event) < 0) { error_report("get_cm_event failed %d", errno); return; } @@ -4053,14 +4043,11 @@ static QEMUFile *rdma_new_output(RDMAContext *rdma) static void rdma_accept_incoming_migration(void *opaque) { RDMAContext *rdma = opaque; - int ret; QEMUFile *f; Error *local_err = NULL; trace_qemu_rdma_accept_incoming_migration(); - ret = qemu_rdma_accept(rdma); - - if (ret < 0) { + if (qemu_rdma_accept(rdma) < 0) { error_report("RDMA ERROR: Migration initialization failed"); return; } From e4ceec292fcdcae390eee539b79fbb6107f402e9 Mon Sep 17 00:00:00 2001 From: Juan Quintela Date: Fri, 13 Oct 2023 12:47:27 +0200 Subject: [PATCH 0705/1077] migration: Improve json and formatting Reviewed-by: Markus Armbruster Signed-off-by: Juan Quintela Message-ID: <20231013104736.31722-2-quintela@redhat.com> --- qapi/migration.json | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/qapi/migration.json b/qapi/migration.json index 360e609f66..db3df12d6c 100644 --- a/qapi/migration.json +++ b/qapi/migration.json @@ -73,7 +73,7 @@ { 'struct': 'MigrationStats', 'data': {'transferred': 'int', 'remaining': 'int', 'total': 'int' , 'duplicate': 'int', - 'skipped': { 'type': 'int', 'features': ['deprecated'] }, + 'skipped': { 'type': 'int', 'features': [ 'deprecated' ] }, 'normal': 'int', 'normal-bytes': 'int', 'dirty-pages-rate': 'int', 'mbps': 'number', 'dirty-sync-count': 'int', @@ -440,10 +440,9 @@ # compress and xbzrle are both on, compress only takes effect in # the ram bulk stage, after that, it will be disabled and only # xbzrle takes effect, this can help to minimize migration -# traffic. The feature is disabled by default. (since 2.4 ) +# traffic. The feature is disabled by default. (since 2.4) # -# @events: generate events for each migration state change (since 2.4 -# ) +# @events: generate events for each migration state change (since 2.4) # # @auto-converge: If enabled, QEMU will automatically throttle down # the guest to speed up convergence of RAM migration. (since 1.6) From 60c7981aa3e84eb6d926fd4f7bb4aca4d2edf7cc Mon Sep 17 00:00:00 2001 From: Elena Ufimtseva Date: Wed, 11 Oct 2023 11:43:55 -0700 Subject: [PATCH 0706/1077] migration: check for rate_limit_max for RATE_LIMIT_DISABLED In migration rate limiting atomic operations are used to read the rate limit variables and transferred bytes and they are expensive. Check first if rate_limit_max is equal to RATE_LIMIT_DISABLED and return false immediately if so. Note that with this patch we will also will stop flushing by not calling qemu_fflush() from migration_transferred_bytes() if the migration rate is not exceeded. This should be fine since migration thread calls in the loop migration_update_counters from migration_rate_limit() that calls the migration_transferred_bytes() and flushes there. Signed-off-by: Elena Ufimtseva Reviewed-by: Fabiano Rosas Reviewed-by: Peter Xu Reviewed-by: Juan Quintela Signed-off-by: Juan Quintela Message-ID: <20231011184358.97349-2-elena.ufimtseva@oracle.com> --- migration/migration-stats.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/migration/migration-stats.c b/migration/migration-stats.c index 84e11e6dd8..4cc989d975 100644 --- a/migration/migration-stats.c +++ b/migration/migration-stats.c @@ -24,14 +24,15 @@ bool migration_rate_exceeded(QEMUFile *f) return true; } - uint64_t rate_limit_start = stat64_get(&mig_stats.rate_limit_start); - uint64_t rate_limit_current = migration_transferred_bytes(f); - uint64_t rate_limit_used = rate_limit_current - rate_limit_start; - uint64_t rate_limit_max = stat64_get(&mig_stats.rate_limit_max); - + uint64_t rate_limit_max = migration_rate_get(); if (rate_limit_max == RATE_LIMIT_DISABLED) { return false; } + + uint64_t rate_limit_start = stat64_get(&mig_stats.rate_limit_start); + uint64_t rate_limit_current = migration_transferred_bytes(f); + uint64_t rate_limit_used = rate_limit_current - rate_limit_start; + if (rate_limit_max > 0 && rate_limit_used > rate_limit_max) { return true; } From 68b6e000484c6df34d5cd097e5ae94e9612f5df7 Mon Sep 17 00:00:00 2001 From: Elena Ufimtseva Date: Wed, 11 Oct 2023 11:43:57 -0700 Subject: [PATCH 0707/1077] multifd: fix counters in multifd_send_thread Previous commit cbec7eb76879d419e7dbf531ee2506ec0722e825 "migration/multifd: Compute transferred bytes correctly" removed accounting for packet_len in non-rdma case, but the next_packet_size only accounts for pages, not for the header packet (normal_pages * PAGE_SIZE) that is being sent as iov[0]. The packet_len part should be added to account for the size of MultiFDPacket and the array of the offsets. Signed-off-by: Elena Ufimtseva Reviewed-by: Fabiano Rosas Reviewed-by: Juan Quintela Signed-off-by: Juan Quintela Message-ID: <20231011184358.97349-4-elena.ufimtseva@oracle.com> --- migration/multifd.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/migration/multifd.c b/migration/multifd.c index 0f6b203877..e6e0013c16 100644 --- a/migration/multifd.c +++ b/migration/multifd.c @@ -714,8 +714,6 @@ static void *multifd_send_thread(void *opaque) if (ret != 0) { break; } - stat64_add(&mig_stats.multifd_bytes, p->packet_len); - stat64_add(&mig_stats.transferred, p->packet_len); } else { /* Send header using the same writev call */ p->iov[0].iov_len = p->packet_len; @@ -728,8 +726,10 @@ static void *multifd_send_thread(void *opaque) break; } - stat64_add(&mig_stats.multifd_bytes, p->next_packet_size); - stat64_add(&mig_stats.transferred, p->next_packet_size); + stat64_add(&mig_stats.multifd_bytes, + p->next_packet_size + p->packet_len); + stat64_add(&mig_stats.transferred, + p->next_packet_size + p->packet_len); qemu_mutex_lock(&p->mutex); p->pending_job--; qemu_mutex_unlock(&p->mutex); From 1618f5522145b3cab4d9eb154b921417b577dc2c Mon Sep 17 00:00:00 2001 From: Elena Ufimtseva Date: Wed, 11 Oct 2023 11:43:58 -0700 Subject: [PATCH 0708/1077] multifd: reset next_packet_len after sending pages Sometimes multifd sends just sync packet with no pages (normal_num is 0). In this case the old value is being preserved and being accounted for while only packet_len is being transferred. Reset it to 0 after sending and accounting for. Signed-off-by: Elena Ufimtseva Reviewed-by: Fabiano Rosas Reviewed-by: Juan Quintela Signed-off-by: Juan Quintela Message-ID: <20231011184358.97349-5-elena.ufimtseva@oracle.com> --- migration/multifd.c | 1 + 1 file changed, 1 insertion(+) diff --git a/migration/multifd.c b/migration/multifd.c index e6e0013c16..c45f5015f8 100644 --- a/migration/multifd.c +++ b/migration/multifd.c @@ -730,6 +730,7 @@ static void *multifd_send_thread(void *opaque) p->next_packet_size + p->packet_len); stat64_add(&mig_stats.transferred, p->next_packet_size + p->packet_len); + p->next_packet_size = 0; qemu_mutex_lock(&p->mutex); p->pending_job--; qemu_mutex_unlock(&p->mutex); From 2f5ced5b93720218509fbf7278b5c651d3bbd806 Mon Sep 17 00:00:00 2001 From: Nikolay Borisov Date: Wed, 11 Oct 2023 15:45:59 -0300 Subject: [PATCH 0709/1077] migration/ram: Refactor precopy ram loading code MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Extract the ramblock parsing code into a routine that operates on the sequence of headers from the stream and another the parses the individual ramblock. This makes ram_load_precopy() easier to comprehend. Signed-off-by: Nikolay Borisov Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Peter Xu Reviewed-by: Juan Quintela Signed-off-by: Fabiano Rosas Signed-off-by: Juan Quintela Message-ID: <20231011184604.32364-3-farosas@suse.de> --- migration/ram.c | 146 +++++++++++++++++++++++++++--------------------- 1 file changed, 82 insertions(+), 64 deletions(-) diff --git a/migration/ram.c b/migration/ram.c index a9bc6ae1f1..2bd51d6bb5 100644 --- a/migration/ram.c +++ b/migration/ram.c @@ -3884,6 +3884,85 @@ void colo_flush_ram_cache(void) trace_colo_flush_ram_cache_end(); } +static int parse_ramblock(QEMUFile *f, RAMBlock *block, ram_addr_t length) +{ + int ret = 0; + /* ADVISE is earlier, it shows the source has the postcopy capability on */ + bool postcopy_advised = migration_incoming_postcopy_advised(); + + assert(block); + + if (!qemu_ram_is_migratable(block)) { + error_report("block %s should not be migrated !", block->idstr); + return -EINVAL; + } + + if (length != block->used_length) { + Error *local_err = NULL; + + ret = qemu_ram_resize(block, length, &local_err); + if (local_err) { + error_report_err(local_err); + } + } + /* For postcopy we need to check hugepage sizes match */ + if (postcopy_advised && migrate_postcopy_ram() && + block->page_size != qemu_host_page_size) { + uint64_t remote_page_size = qemu_get_be64(f); + if (remote_page_size != block->page_size) { + error_report("Mismatched RAM page size %s " + "(local) %zd != %" PRId64, block->idstr, + block->page_size, remote_page_size); + ret = -EINVAL; + } + } + if (migrate_ignore_shared()) { + hwaddr addr = qemu_get_be64(f); + if (migrate_ram_is_ignored(block) && + block->mr->addr != addr) { + error_report("Mismatched GPAs for block %s " + "%" PRId64 "!= %" PRId64, block->idstr, + (uint64_t)addr, (uint64_t)block->mr->addr); + ret = -EINVAL; + } + } + ret = rdma_block_notification_handle(f, block->idstr); + if (ret < 0) { + qemu_file_set_error(f, ret); + } + + return ret; +} + +static int parse_ramblocks(QEMUFile *f, ram_addr_t total_ram_bytes) +{ + int ret = 0; + + /* Synchronize RAM block list */ + while (!ret && total_ram_bytes) { + RAMBlock *block; + char id[256]; + ram_addr_t length; + int len = qemu_get_byte(f); + + qemu_get_buffer(f, (uint8_t *)id, len); + id[len] = 0; + length = qemu_get_be64(f); + + block = qemu_ram_block_by_name(id); + if (block) { + ret = parse_ramblock(f, block, length); + } else { + error_report("Unknown ramblock \"%s\", cannot accept " + "migration", id); + ret = -EINVAL; + } + total_ram_bytes -= length; + } + + return ret; +} + /** * ram_load_precopy: load pages in precopy case * @@ -3898,14 +3977,13 @@ static int ram_load_precopy(QEMUFile *f) { MigrationIncomingState *mis = migration_incoming_get_current(); int flags = 0, ret = 0, invalid_flags = 0, len = 0, i = 0; - /* ADVISE is earlier, it shows the source has the postcopy capability on */ - bool postcopy_advised = migration_incoming_postcopy_advised(); + if (!migrate_compress()) { invalid_flags |= RAM_SAVE_FLAG_COMPRESS_PAGE; } while (!ret && !(flags & RAM_SAVE_FLAG_EOS)) { - ram_addr_t addr, total_ram_bytes; + ram_addr_t addr; void *host = NULL, *host_bak = NULL; uint8_t ch; @@ -3976,67 +4054,7 @@ static int ram_load_precopy(QEMUFile *f) switch (flags & ~RAM_SAVE_FLAG_CONTINUE) { case RAM_SAVE_FLAG_MEM_SIZE: - /* Synchronize RAM block list */ - total_ram_bytes = addr; - while (!ret && total_ram_bytes) { - RAMBlock *block; - char id[256]; - ram_addr_t length; - - len = qemu_get_byte(f); - qemu_get_buffer(f, (uint8_t *)id, len); - id[len] = 0; - length = qemu_get_be64(f); - - block = qemu_ram_block_by_name(id); - if (block && !qemu_ram_is_migratable(block)) { - error_report("block %s should not be migrated !", id); - ret = -EINVAL; - } else if (block) { - if (length != block->used_length) { - Error *local_err = NULL; - - ret = qemu_ram_resize(block, length, - &local_err); - if (local_err) { - error_report_err(local_err); - } - } - /* For postcopy we need to check hugepage sizes match */ - if (postcopy_advised && migrate_postcopy_ram() && - block->page_size != qemu_host_page_size) { - uint64_t remote_page_size = qemu_get_be64(f); - if (remote_page_size != block->page_size) { - error_report("Mismatched RAM page size %s " - "(local) %zd != %" PRId64, - id, block->page_size, - remote_page_size); - ret = -EINVAL; - } - } - if (migrate_ignore_shared()) { - hwaddr addr2 = qemu_get_be64(f); - if (migrate_ram_is_ignored(block) && - block->mr->addr != addr2) { - error_report("Mismatched GPAs for block %s " - "%" PRId64 "!= %" PRId64, - id, (uint64_t)addr2, - (uint64_t)block->mr->addr); - ret = -EINVAL; - } - } - ret = rdma_block_notification_handle(f, block->idstr); - if (ret < 0) { - qemu_file_set_error(f, ret); - } - } else { - error_report("Unknown ramblock \"%s\", cannot " - "accept migration", id); - ret = -EINVAL; - } - - total_ram_bytes -= length; - } + ret = parse_ramblocks(f, addr); break; case RAM_SAVE_FLAG_ZERO: From 8f47d4ee434ea23fac81b33d7200367f05220495 Mon Sep 17 00:00:00 2001 From: Fabiano Rosas Date: Wed, 11 Oct 2023 15:46:00 -0300 Subject: [PATCH 0710/1077] migration/ram: Remove RAMState from xbzrle_cache_zero_page 'rs' is not used in that function. It's a leftover from commit 9360447d34 ("ram: Use MigrationStats for statistics"). Reviewed-by: Peter Xu Signed-off-by: Fabiano Rosas Reviewed-by: Juan Quintela Signed-off-by: Juan Quintela Message-ID: <20231011184604.32364-4-farosas@suse.de> --- migration/ram.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/migration/ram.c b/migration/ram.c index 2bd51d6bb5..535172d9be 100644 --- a/migration/ram.c +++ b/migration/ram.c @@ -570,7 +570,6 @@ void mig_throttle_counter_reset(void) /** * xbzrle_cache_zero_page: insert a zero page in the XBZRLE cache * - * @rs: current RAM state * @current_addr: address for the zero page * * Update the xbzrle cache to reflect a page that's been sent as all 0. @@ -579,7 +578,7 @@ void mig_throttle_counter_reset(void) * As a bonus, if the page wasn't in the cache it gets added so that * when a small write is made into the 0'd page it gets XBZRLE sent. */ -static void xbzrle_cache_zero_page(RAMState *rs, ram_addr_t current_addr) +static void xbzrle_cache_zero_page(ram_addr_t current_addr) { /* We don't care if this fails to allocate a new cache page * as long as it updated an old one */ @@ -2146,7 +2145,7 @@ static int ram_save_target_page_legacy(RAMState *rs, PageSearchStatus *pss) */ if (rs->xbzrle_started) { XBZRLE_cache_lock(); - xbzrle_cache_zero_page(rs, block->offset + offset); + xbzrle_cache_zero_page(block->offset + offset); XBZRLE_cache_unlock(); } return res; From 1e43f165d0810cdd015ade9c37c93b2c2e720d5c Mon Sep 17 00:00:00 2001 From: Fabiano Rosas Date: Wed, 11 Oct 2023 15:46:01 -0300 Subject: [PATCH 0711/1077] migration/ram: Stop passing QEMUFile around in save_zero_page We don't need the QEMUFile when we're already passing the PageSearchStatus. Reviewed-by: Peter Xu Signed-off-by: Fabiano Rosas Reviewed-by: Juan Quintela Signed-off-by: Juan Quintela Message-ID: <20231011184604.32364-5-farosas@suse.de> --- migration/ram.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/migration/ram.c b/migration/ram.c index 535172d9be..2ec28c4507 100644 --- a/migration/ram.c +++ b/migration/ram.c @@ -1147,10 +1147,11 @@ void ram_release_page(const char *rbname, uint64_t offset) * @block: block that contains the page we want to send * @offset: offset inside the block for the page */ -static int save_zero_page_to_file(PageSearchStatus *pss, QEMUFile *file, - RAMBlock *block, ram_addr_t offset) +static int save_zero_page_to_file(PageSearchStatus *pss, RAMBlock *block, + ram_addr_t offset) { uint8_t *p = block->host + offset; + QEMUFile *file = pss->pss_channel; int len = 0; if (buffer_is_zero(p, TARGET_PAGE_SIZE)) { @@ -1171,10 +1172,10 @@ static int save_zero_page_to_file(PageSearchStatus *pss, QEMUFile *file, * @block: block that contains the page we want to send * @offset: offset inside the block for the page */ -static int save_zero_page(PageSearchStatus *pss, QEMUFile *f, RAMBlock *block, +static int save_zero_page(PageSearchStatus *pss, RAMBlock *block, ram_addr_t offset) { - int len = save_zero_page_to_file(pss, f, block, offset); + int len = save_zero_page_to_file(pss, block, offset); if (len) { stat64_add(&mig_stats.zero_pages, 1); @@ -2138,7 +2139,7 @@ static int ram_save_target_page_legacy(RAMState *rs, PageSearchStatus *pss) return 1; } - res = save_zero_page(pss, pss->pss_channel, block, offset); + res = save_zero_page(pss, block, offset); if (res > 0) { /* Must let xbzrle know, otherwise a previous (now 0'd) cached * page would be stale From ccc09db87c7e5e6d52cdde320540f3dc0ee8b147 Mon Sep 17 00:00:00 2001 From: Fabiano Rosas Date: Wed, 11 Oct 2023 15:46:02 -0300 Subject: [PATCH 0712/1077] migration/ram: Move xbzrle zero page handling into save_zero_page It makes a bit more sense to have the zero page handling of xbzrle right where we save the zero page. Also invert the exit condition to remove one level of indentation which makes the next patch easier to grasp. Reviewed-by: Peter Xu Signed-off-by: Fabiano Rosas Reviewed-by: Juan Quintela Signed-off-by: Juan Quintela Message-ID: <20231011184604.32364-6-farosas@suse.de> --- migration/ram.c | 35 ++++++++++++++++++++--------------- 1 file changed, 20 insertions(+), 15 deletions(-) diff --git a/migration/ram.c b/migration/ram.c index 2ec28c4507..229cad5c74 100644 --- a/migration/ram.c +++ b/migration/ram.c @@ -1168,21 +1168,34 @@ static int save_zero_page_to_file(PageSearchStatus *pss, RAMBlock *block, * * Returns the number of pages written. * + * @rs: current RAM state * @pss: current PSS channel * @block: block that contains the page we want to send * @offset: offset inside the block for the page */ -static int save_zero_page(PageSearchStatus *pss, RAMBlock *block, +static int save_zero_page(RAMState *rs, PageSearchStatus *pss, RAMBlock *block, ram_addr_t offset) { int len = save_zero_page_to_file(pss, block, offset); - if (len) { - stat64_add(&mig_stats.zero_pages, 1); - ram_transferred_add(len); - return 1; + if (!len) { + return -1; } - return -1; + + stat64_add(&mig_stats.zero_pages, 1); + ram_transferred_add(len); + + /* + * Must let xbzrle know, otherwise a previous (now 0'd) cached + * page would be stale. + */ + if (rs->xbzrle_started) { + XBZRLE_cache_lock(); + xbzrle_cache_zero_page(block->offset + offset); + XBZRLE_cache_unlock(); + } + + return 1; } /* @@ -2139,16 +2152,8 @@ static int ram_save_target_page_legacy(RAMState *rs, PageSearchStatus *pss) return 1; } - res = save_zero_page(pss, block, offset); + res = save_zero_page(rs, pss, block, offset); if (res > 0) { - /* Must let xbzrle know, otherwise a previous (now 0'd) cached - * page would be stale - */ - if (rs->xbzrle_started) { - XBZRLE_cache_lock(); - xbzrle_cache_zero_page(block->offset + offset); - XBZRLE_cache_unlock(); - } return res; } From 8697eb8577692d16317655c2efa11a7edf9c02aa Mon Sep 17 00:00:00 2001 From: Fabiano Rosas Date: Wed, 11 Oct 2023 15:46:03 -0300 Subject: [PATCH 0713/1077] migration/ram: Merge save_zero_page functions We don't need to do this in two pieces. One single function makes it easier to grasp, specially since it removes the indirection on the return value handling. Reviewed-by: Peter Xu Signed-off-by: Fabiano Rosas Reviewed-by: Juan Quintela Signed-off-by: Juan Quintela Message-ID: <20231011184604.32364-7-farosas@suse.de> --- migration/ram.c | 46 +++++++++++++--------------------------------- 1 file changed, 13 insertions(+), 33 deletions(-) diff --git a/migration/ram.c b/migration/ram.c index 229cad5c74..c844151ee9 100644 --- a/migration/ram.c +++ b/migration/ram.c @@ -1137,32 +1137,6 @@ void ram_release_page(const char *rbname, uint64_t offset) ram_discard_range(rbname, offset, TARGET_PAGE_SIZE); } -/** - * save_zero_page_to_file: send the zero page to the file - * - * Returns the size of data written to the file, 0 means the page is not - * a zero page - * - * @pss: current PSS channel - * @block: block that contains the page we want to send - * @offset: offset inside the block for the page - */ -static int save_zero_page_to_file(PageSearchStatus *pss, RAMBlock *block, - ram_addr_t offset) -{ - uint8_t *p = block->host + offset; - QEMUFile *file = pss->pss_channel; - int len = 0; - - if (buffer_is_zero(p, TARGET_PAGE_SIZE)) { - len += save_page_header(pss, file, block, offset | RAM_SAVE_FLAG_ZERO); - qemu_put_byte(file, 0); - len += 1; - ram_release_page(block->idstr, offset); - } - return len; -} - /** * save_zero_page: send the zero page to the stream * @@ -1176,12 +1150,19 @@ static int save_zero_page_to_file(PageSearchStatus *pss, RAMBlock *block, static int save_zero_page(RAMState *rs, PageSearchStatus *pss, RAMBlock *block, ram_addr_t offset) { - int len = save_zero_page_to_file(pss, block, offset); + uint8_t *p = block->host + offset; + QEMUFile *file = pss->pss_channel; + int len = 0; - if (!len) { - return -1; + if (!buffer_is_zero(p, TARGET_PAGE_SIZE)) { + return 0; } + len += save_page_header(pss, file, block, offset | RAM_SAVE_FLAG_ZERO); + qemu_put_byte(file, 0); + len += 1; + ram_release_page(block->idstr, offset); + stat64_add(&mig_stats.zero_pages, 1); ram_transferred_add(len); @@ -1195,7 +1176,7 @@ static int save_zero_page(RAMState *rs, PageSearchStatus *pss, RAMBlock *block, XBZRLE_cache_unlock(); } - return 1; + return len; } /* @@ -2152,9 +2133,8 @@ static int ram_save_target_page_legacy(RAMState *rs, PageSearchStatus *pss) return 1; } - res = save_zero_page(rs, pss, block, offset); - if (res > 0) { - return res; + if (save_zero_page(rs, pss, block, offset)) { + return 1; } /* From 0e92f6444834a84aefab8f31b4f6a04c0dfed801 Mon Sep 17 00:00:00 2001 From: Fabiano Rosas Date: Thu, 12 Oct 2023 10:43:41 -0300 Subject: [PATCH 0714/1077] migration/multifd: Remove direct "socket" references MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We're about to enable support for other transports in multifd, so remove direct references to sockets. Signed-off-by: Fabiano Rosas Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Juan Quintela Signed-off-by: Juan Quintela Message-ID: <20231012134343.23757-2-farosas@suse.de> --- migration/multifd.c | 22 ++++++++++++++++------ 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/migration/multifd.c b/migration/multifd.c index c45f5015f8..8e9a5ee394 100644 --- a/migration/multifd.c +++ b/migration/multifd.c @@ -510,6 +510,11 @@ static void multifd_send_terminate_threads(Error *err) } } +static int multifd_send_channel_destroy(QIOChannel *send) +{ + return socket_send_channel_destroy(send); +} + void multifd_save_cleanup(void) { int i; @@ -532,7 +537,7 @@ void multifd_save_cleanup(void) if (p->registered_yank) { migration_ioc_unregister_yank(p->c); } - socket_send_channel_destroy(p->c); + multifd_send_channel_destroy(p->c); p->c = NULL; qemu_mutex_destroy(&p->mutex); qemu_sem_destroy(&p->sem); @@ -890,20 +895,25 @@ static void multifd_new_send_channel_cleanup(MultiFDSendParams *p, static void multifd_new_send_channel_async(QIOTask *task, gpointer opaque) { MultiFDSendParams *p = opaque; - QIOChannel *sioc = QIO_CHANNEL(qio_task_get_source(task)); + QIOChannel *ioc = QIO_CHANNEL(qio_task_get_source(task)); Error *local_err = NULL; trace_multifd_new_send_channel_async(p->id); if (!qio_task_propagate_error(task, &local_err)) { - p->c = sioc; + p->c = ioc; qio_channel_set_delay(p->c, false); p->running = true; - if (multifd_channel_connect(p, sioc, local_err)) { + if (multifd_channel_connect(p, ioc, local_err)) { return; } } - multifd_new_send_channel_cleanup(p, sioc, local_err); + multifd_new_send_channel_cleanup(p, ioc, local_err); +} + +static void multifd_new_send_channel_create(gpointer opaque) +{ + socket_send_channel_create(multifd_new_send_channel_async, opaque); } int multifd_save_setup(Error **errp) @@ -952,7 +962,7 @@ int multifd_save_setup(Error **errp) p->write_flags = 0; } - socket_send_channel_create(multifd_new_send_channel_async, p); + multifd_new_send_channel_create(p); } for (i = 0; i < thread_count; i++) { From ee8a7c9c46b8f06969a975ac3fd3fd30491611a7 Mon Sep 17 00:00:00 2001 From: Fabiano Rosas Date: Thu, 12 Oct 2023 10:43:42 -0300 Subject: [PATCH 0715/1077] migration/multifd: Unify multifd_send_thread error paths The preferred usage of the Error type is to always set both the return code and the error when a failure happens. As all code called from the send thread follows this pattern, we'll always have the return code and the error set at the same time. Aside from the convention, in this piece of code this must be the case, otherwise the if (ret != 0) would be exiting the thread without calling multifd_send_terminate_threads() which is incorrect. Unify both paths to make it clear that both are taken when there's an error. Signed-off-by: Fabiano Rosas Reviewed-by: Juan Quintela Signed-off-by: Juan Quintela Message-ID: <20231012134343.23757-3-farosas@suse.de> --- migration/multifd.c | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/migration/multifd.c b/migration/multifd.c index 8e9a5ee394..c92955de41 100644 --- a/migration/multifd.c +++ b/migration/multifd.c @@ -753,19 +753,13 @@ static void *multifd_send_thread(void *opaque) } out: - if (local_err) { + if (ret) { + assert(local_err); trace_multifd_send_error(p->id); multifd_send_terminate_threads(local_err); - error_free(local_err); - } - - /* - * Error happen, I will exit, but I can't just leave, tell - * who pay attention to me. - */ - if (ret != 0) { qemu_sem_post(&p->sem_sync); qemu_sem_post(&multifd_send_state->channels_ready); + error_free(local_err); } qemu_mutex_lock(&p->mutex); From 967e3889874b1116090a60c0cb43157130bdbd16 Mon Sep 17 00:00:00 2001 From: Fabiano Rosas Date: Thu, 12 Oct 2023 10:43:43 -0300 Subject: [PATCH 0716/1077] migration/multifd: Clarify Error usage in multifd_channel_connect MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The function is currently called from two sites, one always gives it a NULL Error and the other always gives it a non-NULL Error. In the non-NULL case, all it does it trace the error and return. One of the callers already have tracing, add a tracepoint to the other and stop passing the error into the function. Cc: Markus Armbruster Signed-off-by: Fabiano Rosas Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Juan Quintela Signed-off-by: Juan Quintela Message-ID: <20231012134343.23757-4-farosas@suse.de> --- migration/multifd.c | 60 ++++++++++++++++++++---------------------- migration/trace-events | 3 ++- 2 files changed, 30 insertions(+), 33 deletions(-) diff --git a/migration/multifd.c b/migration/multifd.c index c92955de41..1fe53d3b98 100644 --- a/migration/multifd.c +++ b/migration/multifd.c @@ -775,7 +775,7 @@ out: static bool multifd_channel_connect(MultiFDSendParams *p, QIOChannel *ioc, - Error *error); + Error **errp); static void multifd_tls_outgoing_handshake(QIOTask *task, gpointer opaque) @@ -784,21 +784,22 @@ static void multifd_tls_outgoing_handshake(QIOTask *task, QIOChannel *ioc = QIO_CHANNEL(qio_task_get_source(task)); Error *err = NULL; - if (qio_task_propagate_error(task, &err)) { - trace_multifd_tls_outgoing_handshake_error(ioc, error_get_pretty(err)); - } else { + if (!qio_task_propagate_error(task, &err)) { trace_multifd_tls_outgoing_handshake_complete(ioc); + if (multifd_channel_connect(p, ioc, &err)) { + return; + } } - if (!multifd_channel_connect(p, ioc, err)) { - /* - * Error happen, mark multifd_send_thread status as 'quit' although it - * is not created, and then tell who pay attention to me. - */ - p->quit = true; - qemu_sem_post(&multifd_send_state->channels_ready); - qemu_sem_post(&p->sem_sync); - } + trace_multifd_tls_outgoing_handshake_error(ioc, error_get_pretty(err)); + + /* + * Error happen, mark multifd_send_thread status as 'quit' although it + * is not created, and then tell who pay attention to me. + */ + p->quit = true; + qemu_sem_post(&multifd_send_state->channels_ready); + qemu_sem_post(&p->sem_sync); } static void *multifd_tls_handshake_thread(void *opaque) @@ -814,7 +815,7 @@ static void *multifd_tls_handshake_thread(void *opaque) return NULL; } -static void multifd_tls_channel_connect(MultiFDSendParams *p, +static bool multifd_tls_channel_connect(MultiFDSendParams *p, QIOChannel *ioc, Error **errp) { @@ -824,7 +825,7 @@ static void multifd_tls_channel_connect(MultiFDSendParams *p, tioc = migration_tls_client_create(ioc, hostname, errp); if (!tioc) { - return; + return false; } object_unref(OBJECT(ioc)); @@ -834,31 +835,25 @@ static void multifd_tls_channel_connect(MultiFDSendParams *p, qemu_thread_create(&p->thread, "multifd-tls-handshake-worker", multifd_tls_handshake_thread, p, QEMU_THREAD_JOINABLE); + return true; } static bool multifd_channel_connect(MultiFDSendParams *p, QIOChannel *ioc, - Error *error) + Error **errp) { trace_multifd_set_outgoing_channel( ioc, object_get_typename(OBJECT(ioc)), - migrate_get_current()->hostname, error); + migrate_get_current()->hostname); - if (error) { - return false; - } if (migrate_channel_requires_tls_upgrade(ioc)) { - multifd_tls_channel_connect(p, ioc, &error); - if (!error) { - /* - * tls_channel_connect will call back to this - * function after the TLS handshake, - * so we mustn't call multifd_send_thread until then - */ - return true; - } else { - return false; - } + /* + * tls_channel_connect will call back to this + * function after the TLS handshake, + * so we mustn't call multifd_send_thread until then + */ + return multifd_tls_channel_connect(p, ioc, errp); + } else { migration_ioc_register_yank(ioc); p->registered_yank = true; @@ -897,11 +892,12 @@ static void multifd_new_send_channel_async(QIOTask *task, gpointer opaque) p->c = ioc; qio_channel_set_delay(p->c, false); p->running = true; - if (multifd_channel_connect(p, ioc, local_err)) { + if (multifd_channel_connect(p, ioc, &local_err)) { return; } } + trace_multifd_new_send_channel_async_error(p->id, local_err); multifd_new_send_channel_cleanup(p, ioc, local_err); } diff --git a/migration/trace-events b/migration/trace-events index 403cc1ae11..fa9486dffe 100644 --- a/migration/trace-events +++ b/migration/trace-events @@ -125,6 +125,7 @@ postcopy_preempt_reset_channel(void) "" # multifd.c multifd_new_send_channel_async(uint8_t id) "channel %u" +multifd_new_send_channel_async_error(uint8_t id, void *err) "channel=%u err=%p" multifd_recv(uint8_t id, uint64_t packet_num, uint32_t used, uint32_t flags, uint32_t next_packet_size) "channel %u packet_num %" PRIu64 " pages %u flags 0x%x next packet size %u" multifd_recv_new_channel(uint8_t id) "channel %u" multifd_recv_sync_main(long packet_num) "packet num %ld" @@ -144,7 +145,7 @@ multifd_send_thread_start(uint8_t id) "%u" multifd_tls_outgoing_handshake_start(void *ioc, void *tioc, const char *hostname) "ioc=%p tioc=%p hostname=%s" multifd_tls_outgoing_handshake_error(void *ioc, const char *err) "ioc=%p err=%s" multifd_tls_outgoing_handshake_complete(void *ioc) "ioc=%p" -multifd_set_outgoing_channel(void *ioc, const char *ioctype, const char *hostname, void *err) "ioc=%p ioctype=%s hostname=%s err=%p" +multifd_set_outgoing_channel(void *ioc, const char *ioctype, const char *hostname) "ioc=%p ioctype=%s hostname=%s" # migration.c await_return_path_close_on_source_close(void) "" From 9444e5f5a1b160413023165827a0ffd69c091ff7 Mon Sep 17 00:00:00 2001 From: John Snow Date: Tue, 20 Jun 2023 20:21:18 -0400 Subject: [PATCH 0717/1077] iotests: get rid of '..' in path environment output Resolve the build_root before we append more items onto it so that the environment output is more concise with less parent directory confetti in it. Signed-off-by: John Snow Message-ID: <20230621002121.1609612-4-jsnow@redhat.com> Signed-off-by: Paolo Bonzini --- tests/qemu-iotests/testenv.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/qemu-iotests/testenv.py b/tests/qemu-iotests/testenv.py index 9a37ad9152..e67ebd254b 100644 --- a/tests/qemu-iotests/testenv.py +++ b/tests/qemu-iotests/testenv.py @@ -216,7 +216,7 @@ class TestEnv(ContextManager['TestEnv']): self.source_iotests = source_dir self.build_iotests = build_dir - self.build_root = os.path.join(self.build_iotests, '..', '..') + self.build_root = Path(self.build_iotests).parent.parent self.init_directories() From c624cb32a92b84e7978e512e4d67c4e2b72b0e2b Mon Sep 17 00:00:00 2001 From: John Snow Date: Tue, 20 Jun 2023 20:21:19 -0400 Subject: [PATCH 0718/1077] iotests: use the correct python to run linters Whichever python is used to run iotest 297 should be the one used to actually run the linters. Signed-off-by: John Snow Message-ID: <20230621002121.1609612-5-jsnow@redhat.com> Signed-off-by: Paolo Bonzini --- tests/qemu-iotests/linters.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/qemu-iotests/linters.py b/tests/qemu-iotests/linters.py index 65c4c4e827..9fb3fd1449 100644 --- a/tests/qemu-iotests/linters.py +++ b/tests/qemu-iotests/linters.py @@ -68,7 +68,7 @@ def run_linter( :raise CalledProcessError: If the linter process exits with failure. """ subprocess.run( - ('python3', '-m', tool, *args), + (sys.executable, '-m', tool, *args), env=env, check=True, stdout=subprocess.PIPE if suppress_output else None, From 4f94781196a5bea7c07f6a6d6c301abf2a069e2b Mon Sep 17 00:00:00 2001 From: Yonggang Luo Date: Tue, 10 Oct 2023 00:51:13 +0800 Subject: [PATCH 0719/1077] Revert "configure: Add workaround for ccache and clang" This reverts commit fd0e60530f10078f488fa3e9591cc7db5732989c. According to https://peter.eisentraut.org/blog/2014/12/01/ccache-and-clang-part-3 it's already fixed in new version of ccache According to https://ccache.dev/manual/4.8.html#config_run_second_cpp CCACHE_CPP2 are default to true for new version ccache Signed-off-by: Yonggang Luo Message-ID: <20231009165113.498-1-luoyonggang@gmail.com> Signed-off-by: Paolo Bonzini --- configure | 32 -------------------------------- 1 file changed, 32 deletions(-) diff --git a/configure b/configure index 96d0dd5ffc..d6103a0141 100755 --- a/configure +++ b/configure @@ -1166,34 +1166,6 @@ EOF fi fi -######################################## -# check if ccache is interfering with -# semantic analysis of macros - -unset CCACHE_CPP2 -ccache_cpp2=no -cat > $TMPC << EOF -static const int Z = 1; -#define fn() ({ Z; }) -#define TAUT(X) ((X) == Z) -#define PAREN(X, Y) (X == Y) -#define ID(X) (X) -int main(void) -{ - int x = 0, y = 0; - x = ID(x); - x = fn(); - fn(); - if (PAREN(x, y)) return 0; - if (TAUT(Z)) return 0; - return 0; -} -EOF - -if ! compile_object "-Werror"; then - ccache_cpp2=yes -fi - ########################################## # functions to probe cross compilers @@ -1726,10 +1698,6 @@ if test "$default_targets" = "yes"; then echo "CONFIG_DEFAULT_TARGETS=y" >> $config_host_mak fi -if test "$ccache_cpp2" = "yes"; then - echo "export CCACHE_CPP2=y" >> $config_host_mak -fi - # contrib/plugins configuration echo "# Automatically generated by configure - do not modify" > contrib/plugins/$config_host_mak echo "SRC_PATH=$source_path/contrib/plugins" >> contrib/plugins/$config_host_mak From 83629b14614a7b56358addd96ff85d92eb6f72dc Mon Sep 17 00:00:00 2001 From: Xiaoyao Li Date: Tue, 10 Oct 2023 02:05:39 -0400 Subject: [PATCH 0720/1077] target/i386/cpu: Fix CPUID_HT exposure When explicitly booting a multiple vcpus vm with "-cpu +ht", it gets warning of warning: host doesn't support requested feature: CPUID.01H:EDX.ht [bit 28] Make CPUID_HT as supported unconditionally can resolve the warning. However it introduces another issue that it also expose CPUID_HT to guest when "-cpu host/max" with only 1 vcpu. To fix this, need mark CPUID_HT as the no_autoenable_flags. Signed-off-by: Xiaoyao Li Message-ID: <20231010060539.210258-1-xiaoyao.li@intel.com> Signed-off-by: Paolo Bonzini --- target/i386/cpu.c | 1 + target/i386/kvm/kvm.c | 2 ++ 2 files changed, 3 insertions(+) diff --git a/target/i386/cpu.c b/target/i386/cpu.c index 3aab05ddad..bdca901dfa 100644 --- a/target/i386/cpu.c +++ b/target/i386/cpu.c @@ -778,6 +778,7 @@ FeatureWordInfo feature_word_info[FEATURE_WORDS] = { }, .cpuid = {.eax = 1, .reg = R_EDX, }, .tcg_features = TCG_FEATURES, + .no_autoenable_flags = CPUID_HT, }, [FEAT_1_ECX] = { .type = CPUID_FEATURE_WORD, diff --git a/target/i386/kvm/kvm.c b/target/i386/kvm/kvm.c index f6c7f7e268..ab72bcdfad 100644 --- a/target/i386/kvm/kvm.c +++ b/target/i386/kvm/kvm.c @@ -373,6 +373,8 @@ uint32_t kvm_arch_get_supported_cpuid(KVMState *s, uint32_t function, if (function == 1 && reg == R_EDX) { /* KVM before 2.6.30 misreports the following features */ ret |= CPUID_MTRR | CPUID_PAT | CPUID_MCE | CPUID_MCA; + /* KVM never reports CPUID_HT but QEMU can support when vcpus > 1 */ + ret |= CPUID_HT; } else if (function == 1 && reg == R_ECX) { /* We can set the hypervisor flag, even if KVM does not return it on * GET_SUPPORTED_CPUID From 24b34590d07f885a906ebb52fd84aa5e33d4e421 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Fri, 13 Oct 2023 09:27:02 +0200 Subject: [PATCH 0721/1077] target/i386: check intercept for XSETBV Note that this intercept is special; it is checked before the #GP exception. Signed-off-by: Paolo Bonzini --- target/i386/svm.h | 1 + target/i386/tcg/translate.c | 1 + 2 files changed, 2 insertions(+) diff --git a/target/i386/svm.h b/target/i386/svm.h index f9a785489d..1bd7844730 100644 --- a/target/i386/svm.h +++ b/target/i386/svm.h @@ -132,6 +132,7 @@ /* only included in documentation, maybe wrong */ #define SVM_EXIT_MONITOR 0x08a #define SVM_EXIT_MWAIT 0x08b +#define SVM_EXIT_XSETBV 0x08d #define SVM_EXIT_NPF 0x400 #define SVM_EXIT_ERR -1 diff --git a/target/i386/tcg/translate.c b/target/i386/tcg/translate.c index d2061ec44a..4f6f9fa7e5 100644 --- a/target/i386/tcg/translate.c +++ b/target/i386/tcg/translate.c @@ -5916,6 +5916,7 @@ static bool disas_insn(DisasContext *s, CPUState *cpu) | PREFIX_REPZ | PREFIX_REPNZ))) { goto illegal_op; } + gen_svm_check_intercept(s, SVM_EXIT_XSETBV); if (!check_cpl0(s)) { break; } From a6b75c9f6788db93769f0598a467a23befe30573 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Fri, 13 Oct 2023 17:28:32 +0200 Subject: [PATCH 0722/1077] tests/vm: netbsd: install dtc Install dtc as it is now a mandatory external dependency in order to build QEMU. Co-developed-by: Thomas Huth Signed-off-by: Thomas Huth Signed-off-by: Paolo Bonzini --- tests/vm/netbsd | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/tests/vm/netbsd b/tests/vm/netbsd index c7e3f1e735..40b27a3469 100755 --- a/tests/vm/netbsd +++ b/tests/vm/netbsd @@ -40,6 +40,9 @@ class NetBSDVM(basevm.BaseVM): "gsed", "gettext-tools", + # libs: basic + "dtc", + # libs: crypto "gnutls", @@ -67,7 +70,8 @@ class NetBSDVM(basevm.BaseVM): mkdir src build; cd src; tar -xf /dev/rld1a; cd ../build - ../src/configure --disable-opengl {configure_opts}; + ../src/configure --disable-opengl --extra-ldflags=-L/usr/pkg/lib \ + --extra-cflags=-I/usr/pkg/include {configure_opts}; gmake --output-sync -j{jobs} {target} {verbose}; """ poweroff = "/sbin/poweroff" From d7fd737bf478f37fbd5a140599e022127c9a650d Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Mon, 16 Oct 2023 11:49:17 +0200 Subject: [PATCH 0723/1077] scripts: Mark feature_to_c.py as non-executable to fix a build issue Meson tries to run scripts via the shebang line if they files are marked as executable. If "python3" is not in the $PATH, or if it is a version that is too old, then the script execution fails. We should make sure to run scripts via the python3 interpreter that is used for Meson itself. For this, the files need to be marked as non-executable, then meson will use the python3 binary that has been used to run itself. Fixes: 956af7daad ("gdbstub: Introduce GDBFeature structure") Signed-off-by: Thomas Huth Message-ID: <20231016094917.19044-1-thuth@redhat.com> Signed-off-by: Paolo Bonzini --- scripts/feature_to_c.py | 0 1 file changed, 0 insertions(+), 0 deletions(-) mode change 100755 => 100644 scripts/feature_to_c.py diff --git a/scripts/feature_to_c.py b/scripts/feature_to_c.py old mode 100755 new mode 100644 From 2845bab65a145b2bc447e156436ddf45a7e090e1 Mon Sep 17 00:00:00 2001 From: Emmanouil Pitsidianakis Date: Fri, 13 Oct 2023 12:16:28 +0300 Subject: [PATCH 0724/1077] scripts/get_maintainer.pl: don't print parentheses MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When called from git-send-email, some results contain unclosed parentheses from the subsystem title, for example: (cc-cmd) Adding cc: qemu-ppc@nongnu.org (open list:PowerNV (Non-Virt...) from: 'scripts/get_maintainer.pl --nogit-fallback' (cc-cmd) Adding cc: qemu-devel@nongnu.org (open list:All patches CC here) from: 'scripts/get_maintainer.pl --nogit-fallback' Unmatched () '(open list:PowerNV (Non-Virt...)' '' at /usr/lib/git-core/git-send-email line 642. error: unable to extract a valid address from: qemu-ppc@nongnu.org (open list:PowerNV (Non-Virt...) What to do with this address? ([q]uit|[d]rop|[e]dit): d This commit removes all parentheses from results. Signed-off-by: Emmanouil Pitsidianakis Reviewed-by: Philippe Mathieu-Daudé Message-ID: <20231013091628.669415-1-manos.pitsidianakis@linaro.org> Signed-off-by: Paolo Bonzini --- scripts/get_maintainer.pl | 1 + 1 file changed, 1 insertion(+) diff --git a/scripts/get_maintainer.pl b/scripts/get_maintainer.pl index 02fa828100..00a0870b26 100755 --- a/scripts/get_maintainer.pl +++ b/scripts/get_maintainer.pl @@ -907,6 +907,7 @@ sub get_subsystem_name { if (length($subsystem) > 20) { $subsystem = substr($subsystem, 0, 17); $subsystem =~ s/\s*$//; + $subsystem =~ s/[()]//g; $subsystem = $subsystem . "..."; } return $subsystem; From a5e3cb3b90a62a42cd19ad9a20ca25c7df1dc3da Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Mon, 16 Oct 2023 08:22:56 +0200 Subject: [PATCH 0725/1077] tests/docker: avoid invalid escape in Python string This is an error in Python 3.12; fix it by using a raw string literal. Cc: qemu-stable@nongnu.org Signed-off-by: Paolo Bonzini --- tests/docker/docker.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/docker/docker.py b/tests/docker/docker.py index 688ef62989..3b8a26704d 100755 --- a/tests/docker/docker.py +++ b/tests/docker/docker.py @@ -186,7 +186,7 @@ def _check_binfmt_misc(executable): (binary)) return None, True - m = re.search("interpreter (\S+)\n", entry) + m = re.search(r"interpreter (\S+)\n", entry) interp = m.group(1) if interp and interp != executable: print("binfmt_misc for %s does not point to %s, using %s" % From e4b6532cc0a5518c0dea15eeca573829df9ec1df Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Mon, 16 Oct 2023 08:22:56 +0200 Subject: [PATCH 0726/1077] docs/sphinx: avoid invalid escape in Python string This is an error in Python 3.12; fix it by using a raw string literal. Cc: qemu-stable@nongnu.org Signed-off-by: Paolo Bonzini --- docs/sphinx/hxtool.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/sphinx/hxtool.py b/docs/sphinx/hxtool.py index fb0649a3d5..9f6b9d87dc 100644 --- a/docs/sphinx/hxtool.py +++ b/docs/sphinx/hxtool.py @@ -49,7 +49,7 @@ def serror(file, lnum, errtext): def parse_directive(line): """Return first word of line, if any""" - return re.split('\W', line)[0] + return re.split(r'\W', line)[0] def parse_defheading(file, lnum, line): """Handle a DEFHEADING directive""" From e41c40d101fce79af4d679955eb6e0d31e02c47c Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Mon, 16 Oct 2023 08:22:56 +0200 Subject: [PATCH 0727/1077] target/hexagon: avoid invalid escape in Python string This is an error in Python 3.12; fix it by using a raw string literal. Cc: qemu-stable@nongnu.org Signed-off-by: Paolo Bonzini --- target/hexagon/hex_common.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/target/hexagon/hex_common.py b/target/hexagon/hex_common.py index dce1b852a7..0da65d6dd6 100755 --- a/target/hexagon/hex_common.py +++ b/target/hexagon/hex_common.py @@ -45,7 +45,7 @@ regre = re.compile(r"((? Date: Mon, 16 Oct 2023 08:22:56 +0200 Subject: [PATCH 0728/1077] tests/avocado: avoid invalid escape in Python string This is an error in Python 3.12; fix it by using a raw string literal. Cc: qemu-stable@nongnu.org Signed-off-by: Paolo Bonzini --- tests/avocado/virtio_check_params.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/avocado/virtio_check_params.py b/tests/avocado/virtio_check_params.py index f4314ef824..5fe370a179 100644 --- a/tests/avocado/virtio_check_params.py +++ b/tests/avocado/virtio_check_params.py @@ -43,7 +43,7 @@ VM_DEV_PARAMS = {'virtio-scsi-pci': ['-device', 'virtio-scsi-pci,id=scsi0'], class VirtioMaxSegSettingsCheck(QemuSystemTest): @staticmethod def make_pattern(props): - pattern_items = ['{0} = \w+'.format(prop) for prop in props] + pattern_items = [r'{0} = \w+'.format(prop) for prop in props] return '|'.join(pattern_items) def query_virtqueue(self, vm, dev_type_name): From 86a8989d4557a09b68f8b78b6c3fb6ad3f23ca6f Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Mon, 16 Oct 2023 08:22:56 +0200 Subject: [PATCH 0729/1077] tests/vm: avoid invalid escape in Python string This is an error in Python 3.12; fix it by using a raw string literal or by double-escaping the backslash. Cc: qemu-stable@nongnu.org Signed-off-by: Paolo Bonzini --- tests/vm/basevm.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/vm/basevm.py b/tests/vm/basevm.py index 8aef4cff96..61725b8325 100644 --- a/tests/vm/basevm.py +++ b/tests/vm/basevm.py @@ -331,8 +331,8 @@ class BaseVM(object): def console_log(self, text): for line in re.split("[\r\n]", text): # filter out terminal escape sequences - line = re.sub("\x1b\[[0-9;?]*[a-zA-Z]", "", line) - line = re.sub("\x1b\([0-9;?]*[a-zA-Z]", "", line) + line = re.sub("\x1b\\[[0-9;?]*[a-zA-Z]", "", line) + line = re.sub("\x1b\\([0-9;?]*[a-zA-Z]", "", line) # replace unprintable chars line = re.sub("\x1b", "", line) line = re.sub("[\x00-\x1f]", ".", line) @@ -530,7 +530,7 @@ def get_qemu_version(qemu_path): and return the major number.""" output = subprocess.check_output([qemu_path, '--version']) version_line = output.decode("utf-8") - version_num = re.split(' |\(', version_line)[3].split('.')[0] + version_num = re.split(r' |\(', version_line)[3].split('.')[0] return int(version_num) def parse_config(config, args): From e6d8e5e6e366ab4c9ed7d8ed1572f98c6ad6a38e Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Mon, 16 Oct 2023 08:22:56 +0200 Subject: [PATCH 0730/1077] tracetool: avoid invalid escape in Python string This is an error in Python 3.12; fix it by using a raw string literal. Cc: qemu-stable@nongnu.org Signed-off-by: Paolo Bonzini --- scripts/tracetool/__init__.py | 14 +++++++------- scripts/tracetool/format/log_stap.py | 2 +- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/scripts/tracetool/__init__.py b/scripts/tracetool/__init__.py index 33cf85e2b0..b29594d75e 100644 --- a/scripts/tracetool/__init__.py +++ b/scripts/tracetool/__init__.py @@ -210,12 +210,12 @@ class Event(object): """ - _CRE = re.compile("((?P[\w\s]+)\s+)?" - "(?P\w+)" - "\((?P[^)]*)\)" - "\s*" - "(?:(?:(?P\".+),)?\s*(?P\".+))?" - "\s*") + _CRE = re.compile(r"((?P[\w\s]+)\s+)?" + r"(?P\w+)" + r"\((?P[^)]*)\)" + r"\s*" + r"(?:(?:(?P\".+),)?\s*(?P\".+))?" + r"\s*") _VALID_PROPS = set(["disable", "vcpu"]) @@ -326,7 +326,7 @@ class Event(object): fmt) # Star matching on PRI is dangerous as one might have multiple # arguments with that format, hence the non-greedy version of it. - _FMT = re.compile("(%[\d\.]*\w+|%.*?PRI\S+)") + _FMT = re.compile(r"(%[\d\.]*\w+|%.*?PRI\S+)") def formats(self): """List conversion specifiers in the argument print format string.""" diff --git a/scripts/tracetool/format/log_stap.py b/scripts/tracetool/format/log_stap.py index 0b6549d534..b49afababd 100644 --- a/scripts/tracetool/format/log_stap.py +++ b/scripts/tracetool/format/log_stap.py @@ -83,7 +83,7 @@ def c_fmt_to_stap(fmt): # and "%ll" is not valid at all. Similarly the size_t # based "%z" size qualifier is not valid. We just # strip all size qualifiers for sanity. - fmt = re.sub("%(\d*)(l+|z)(x|u|d)", "%\\1\\3", "".join(bits)) + fmt = re.sub(r"%(\d*)(l+|z)(x|u|d)", r"%\1\3", "".join(bits)) return fmt def generate(events, backend, group): From 9bad39c7e86a7fea05b66e7d3425f5874b3bbcfb Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Wed, 11 Oct 2023 15:53:01 +0200 Subject: [PATCH 0731/1077] meson: do not build shaders by default They are not needed when building user-mode emulators. Reviewed-by: Emmanouil Pitsidianakis Signed-off-by: Paolo Bonzini --- ui/shader/meson.build | 1 + 1 file changed, 1 insertion(+) diff --git a/ui/shader/meson.build b/ui/shader/meson.build index 592bf596b9..3137e65578 100644 --- a/ui/shader/meson.build +++ b/ui/shader/meson.build @@ -10,5 +10,6 @@ foreach e : shaders output: output, capture: true, input: files('@0@.@1@'.format(e[0], e[1])), + build_by_default: false, command: [shaderinclude, '@INPUT0@']) endforeach From 230f6e06b83474314898f27c0a7b2f0593071875 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Thu, 5 Oct 2023 14:31:27 +0200 Subject: [PATCH 0732/1077] meson: do not use set10 Make all items of config-host.h consistent. To keep the --disable-coroutine-pool code visible to the compiler, mutuate the IS_ENABLED() macro from Linux. Signed-off-by: Paolo Bonzini --- include/qemu/compiler.h | 15 +++++++++++++++ meson.build | 2 +- tests/unit/test-coroutine.c | 2 +- util/qemu-coroutine.c | 4 ++-- 4 files changed, 19 insertions(+), 4 deletions(-) diff --git a/include/qemu/compiler.h b/include/qemu/compiler.h index 1109482a00..c797f0d457 100644 --- a/include/qemu/compiler.h +++ b/include/qemu/compiler.h @@ -212,4 +212,19 @@ # define QEMU_USED #endif +/* + * Ugly CPP trick that is like "defined FOO", but also works in C + * code. Useful to replace #ifdef with "if" statements; assumes + * the symbol was defined with Meson's "config.set()", so it is empty + * if defined. + */ +#define IS_ENABLED(x) IS_EMPTY(x) + +#define IS_EMPTY_JUNK_ junk, +#define IS_EMPTY(value) IS_EMPTY_(IS_EMPTY_JUNK_##value) + +/* Expands to either SECOND_ARG(junk, 1, 0) or SECOND_ARG(IS_EMPTY_JUNK_CONFIG_FOO 1, 0) */ +#define SECOND_ARG(first, second, ...) second +#define IS_EMPTY_(junk_maybecomma) SECOND_ARG(junk_maybecomma 1, 0) + #endif /* COMPILER_H */ diff --git a/meson.build b/meson.build index bd65a111aa..010d2c649c 100644 --- a/meson.build +++ b/meson.build @@ -2194,7 +2194,7 @@ if get_option('debug_stack_usage') and have_coroutine_pool message('Disabling coroutine pool to measure stack usage') have_coroutine_pool = false endif -config_host_data.set10('CONFIG_COROUTINE_POOL', have_coroutine_pool) +config_host_data.set('CONFIG_COROUTINE_POOL', have_coroutine_pool) config_host_data.set('CONFIG_DEBUG_GRAPH_LOCK', get_option('debug_graph_lock')) config_host_data.set('CONFIG_DEBUG_MUTEX', get_option('debug_mutex')) config_host_data.set('CONFIG_DEBUG_STACK_USAGE', get_option('debug_stack_usage')) diff --git a/tests/unit/test-coroutine.c b/tests/unit/test-coroutine.c index b0d21d673a..a2563647e7 100644 --- a/tests/unit/test-coroutine.c +++ b/tests/unit/test-coroutine.c @@ -645,7 +645,7 @@ int main(int argc, char **argv) * with a sentinel value. If there is no freelist this would legitimately * crash, so skip it. */ - if (CONFIG_COROUTINE_POOL) { + if (IS_ENABLED(CONFIG_COROUTINE_POOL)) { g_test_add_func("/basic/no-dangling-access", test_no_dangling_access); } diff --git a/util/qemu-coroutine.c b/util/qemu-coroutine.c index 17a88f6505..5fd2dbaf8b 100644 --- a/util/qemu-coroutine.c +++ b/util/qemu-coroutine.c @@ -57,7 +57,7 @@ Coroutine *qemu_coroutine_create(CoroutineEntry *entry, void *opaque) { Coroutine *co = NULL; - if (CONFIG_COROUTINE_POOL) { + if (IS_ENABLED(CONFIG_COROUTINE_POOL)) { CoroutineQSList *alloc_pool = get_ptr_alloc_pool(); co = QSLIST_FIRST(alloc_pool); @@ -99,7 +99,7 @@ static void coroutine_delete(Coroutine *co) { co->caller = NULL; - if (CONFIG_COROUTINE_POOL) { + if (IS_ENABLED(CONFIG_COROUTINE_POOL)) { if (release_pool_size < qatomic_read(&pool_max_size) * 2) { QSLIST_INSERT_HEAD_ATOMIC(&release_pool, co, pool_next); qatomic_inc(&release_pool_size); From b88a3306fdfc768f09b2f2a56b739f3d054ce776 Mon Sep 17 00:00:00 2001 From: Juan Quintela Date: Tue, 13 Jun 2023 16:57:42 +0200 Subject: [PATCH 0733/1077] migration: RDMA is not compatible with anything else So give an error instead of just ignoring the other methods. Signed-off-by: Juan Quintela Reviewed-by: Lukas Straub Message-ID: <20230613145757.10131-4-quintela@redhat.com> --- migration/migration.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/migration/migration.c b/migration/migration.c index 6ba5e145ac..81862fcaa9 100644 --- a/migration/migration.c +++ b/migration/migration.c @@ -447,6 +447,18 @@ static void qemu_start_incoming_migration(const char *uri, Error **errp) socket_start_incoming_migration(p ? p : uri, errp); #ifdef CONFIG_RDMA } else if (strstart(uri, "rdma:", &p)) { + if (migrate_compress()) { + error_setg(errp, "RDMA and compression can't be used together"); + return; + } + if (migrate_xbzrle()) { + error_setg(errp, "RDMA and XBZRLE can't be used together"); + return; + } + if (migrate_multifd()) { + error_setg(errp, "RDMA and multifd can't be used together"); + return; + } rdma_start_incoming_migration(p, errp); #endif } else if (strstart(uri, "exec:", &p)) { From 809f188a1a874ead74a784977e15dec33100891e Mon Sep 17 00:00:00 2001 From: Juan Quintela Date: Tue, 13 Jun 2023 16:57:44 +0200 Subject: [PATCH 0734/1077] migration: Move compression_counters cleanup ram-compress.c Signed-off-by: Juan Quintela Reviewed-by: Lukas Straub Message-ID: <20230613145757.10131-6-quintela@redhat.com> --- migration/migration.c | 4 +--- migration/ram-compress.c | 5 +++++ 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/migration/migration.c b/migration/migration.c index 81862fcaa9..a808abd294 100644 --- a/migration/migration.c +++ b/migration/migration.c @@ -1466,11 +1466,9 @@ int migrate_init(MigrationState *s, Error **errp) s->switchover_acked = false; s->rdma_migration = false; /* - * set mig_stats compression_counters memory to zero for a - * new migration + * set mig_stats memory to zero for a new migration */ memset(&mig_stats, 0, sizeof(mig_stats)); - memset(&compression_counters, 0, sizeof(compression_counters)); migration_reset_vfio_bytes_transferred(); return 0; diff --git a/migration/ram-compress.c b/migration/ram-compress.c index 06254d8c69..a0f6a56470 100644 --- a/migration/ram-compress.c +++ b/migration/ram-compress.c @@ -430,6 +430,11 @@ int compress_threads_load_setup(QEMUFile *f) return 0; } + /* + * set compression_counters memory to zero for a new migration + */ + memset(&compression_counters, 0, sizeof(compression_counters)); + thread_count = migrate_decompress_threads(); decompress_threads = g_new0(QemuThread, thread_count); decomp_param = g_new0(DecompressParam, thread_count); From 6f609005730d51e085d7404fcfc72576add237e1 Mon Sep 17 00:00:00 2001 From: Juan Quintela Date: Tue, 13 Jun 2023 16:57:45 +0200 Subject: [PATCH 0735/1077] migration: Create populate_compress() So we don't have to access compression_counters from outside ram-compress.c. Signed-off-by: Juan Quintela Reviewed-by: Lukas Straub Message-ID: <20230613145757.10131-7-quintela@redhat.com> --- migration/migration.c | 11 +---------- migration/ram-compress.c | 13 +++++++++++++ migration/ram-compress.h | 3 +++ 3 files changed, 17 insertions(+), 10 deletions(-) diff --git a/migration/migration.c b/migration/migration.c index a808abd294..05c0b801ba 100644 --- a/migration/migration.c +++ b/migration/migration.c @@ -974,16 +974,7 @@ static void populate_ram_info(MigrationInfo *info, MigrationState *s) info->xbzrle_cache->overflow = xbzrle_counters.overflow; } - if (migrate_compress()) { - info->compression = g_malloc0(sizeof(*info->compression)); - info->compression->pages = compression_counters.pages; - info->compression->busy = compression_counters.busy; - info->compression->busy_rate = compression_counters.busy_rate; - info->compression->compressed_size = - compression_counters.compressed_size; - info->compression->compression_rate = - compression_counters.compression_rate; - } + populate_compress(info); if (cpu_throttle_active()) { info->has_cpu_throttle_percentage = true; diff --git a/migration/ram-compress.c b/migration/ram-compress.c index a0f6a56470..bbf78a02d4 100644 --- a/migration/ram-compress.c +++ b/migration/ram-compress.c @@ -488,3 +488,16 @@ void decompress_data_with_multi_threads(QEMUFile *f, void *host, int len) } } } + +void populate_compress(MigrationInfo *info) +{ + if (!migrate_compress()) { + return; + } + info->compression = g_malloc0(sizeof(*info->compression)); + info->compression->pages = compression_counters.pages; + info->compression->busy = compression_counters.busy; + info->compression->busy_rate = compression_counters.busy_rate; + info->compression->compressed_size = compression_counters.compressed_size; + info->compression->compression_rate = compression_counters.compression_rate; +} diff --git a/migration/ram-compress.h b/migration/ram-compress.h index 6f7fe2f472..43ff44c0ba 100644 --- a/migration/ram-compress.h +++ b/migration/ram-compress.h @@ -30,6 +30,7 @@ #define QEMU_MIGRATION_COMPRESS_H #include "qemu-file.h" +#include "qapi/qapi-types-migration.h" enum CompressResult { RES_NONE = 0, @@ -67,4 +68,6 @@ void compress_threads_load_cleanup(void); int compress_threads_load_setup(QEMUFile *f); void decompress_data_with_multi_threads(QEMUFile *f, void *host, int len); +void populate_compress(MigrationInfo *info); + #endif From f504789de509cded05562bb3bb9abfa222446222 Mon Sep 17 00:00:00 2001 From: Juan Quintela Date: Tue, 13 Jun 2023 16:57:46 +0200 Subject: [PATCH 0736/1077] migration: Create ram_compressed_pages() Signed-off-by: Juan Quintela Reviewed-by: Lukas Straub Message-ID: <20230613145757.10131-8-quintela@redhat.com> --- migration/ram-compress.c | 6 ++++++ migration/ram-compress.h | 1 + migration/ram.c | 2 +- 3 files changed, 8 insertions(+), 1 deletion(-) diff --git a/migration/ram-compress.c b/migration/ram-compress.c index bbf78a02d4..d54345d0c1 100644 --- a/migration/ram-compress.c +++ b/migration/ram-compress.c @@ -501,3 +501,9 @@ void populate_compress(MigrationInfo *info) info->compression->compressed_size = compression_counters.compressed_size; info->compression->compression_rate = compression_counters.compression_rate; } + +uint64_t ram_compressed_pages(void) +{ + return compression_counters.pages; +} + diff --git a/migration/ram-compress.h b/migration/ram-compress.h index 43ff44c0ba..77465dad4b 100644 --- a/migration/ram-compress.h +++ b/migration/ram-compress.h @@ -69,5 +69,6 @@ int compress_threads_load_setup(QEMUFile *f); void decompress_data_with_multi_threads(QEMUFile *f, void *host, int len); void populate_compress(MigrationInfo *info); +uint64_t ram_compressed_pages(void); #endif diff --git a/migration/ram.c b/migration/ram.c index c844151ee9..2a9c899cb0 100644 --- a/migration/ram.c +++ b/migration/ram.c @@ -939,7 +939,7 @@ uint64_t ram_get_total_transferred_pages(void) { return stat64_get(&mig_stats.normal_pages) + stat64_get(&mig_stats.zero_pages) + - compression_counters.pages + xbzrle_counters.pages; + ram_compressed_pages() + xbzrle_counters.pages; } static void migration_update_rates(RAMState *rs, int64_t end_time) From 1fd03d41b86daa1eb8c941dfa013cc806bcaf053 Mon Sep 17 00:00:00 2001 From: Juan Quintela Date: Tue, 13 Jun 2023 16:57:47 +0200 Subject: [PATCH 0737/1077] migration: Move update_compress_threads_counts() to ram-compress.c Signed-off-by: Juan Quintela Reviewed-by: Lukas Straub Message-ID: <20230613145757.10131-9-quintela@redhat.com> --- migration/ram-compress.c | 17 +++++++++++++++++ migration/ram-compress.h | 1 + migration/ram.c | 15 --------------- 3 files changed, 18 insertions(+), 15 deletions(-) diff --git a/migration/ram-compress.c b/migration/ram-compress.c index d54345d0c1..3ad5975d48 100644 --- a/migration/ram-compress.c +++ b/migration/ram-compress.c @@ -32,11 +32,14 @@ #include "ram-compress.h" #include "qemu/error-report.h" +#include "qemu/stats64.h" #include "migration.h" #include "options.h" #include "io/channel-null.h" #include "exec/target_page.h" #include "exec/ramblock.h" +#include "ram.h" +#include "migration-stats.h" CompressionStats compression_counters; @@ -507,3 +510,17 @@ uint64_t ram_compressed_pages(void) return compression_counters.pages; } +void update_compress_thread_counts(const CompressParam *param, int bytes_xmit) +{ + ram_transferred_add(bytes_xmit); + + if (param->result == RES_ZEROPAGE) { + stat64_add(&mig_stats.zero_pages, 1); + return; + } + + /* 8 means a header with RAM_SAVE_FLAG_CONTINUE. */ + compression_counters.compressed_size += bytes_xmit - 8; + compression_counters.pages++; +} + diff --git a/migration/ram-compress.h b/migration/ram-compress.h index 77465dad4b..e55d3b50bd 100644 --- a/migration/ram-compress.h +++ b/migration/ram-compress.h @@ -70,5 +70,6 @@ void decompress_data_with_multi_threads(QEMUFile *f, void *host, int len); void populate_compress(MigrationInfo *info); uint64_t ram_compressed_pages(void); +void update_compress_thread_counts(const CompressParam *param, int bytes_xmit); #endif diff --git a/migration/ram.c b/migration/ram.c index 2a9c899cb0..5595379fa6 100644 --- a/migration/ram.c +++ b/migration/ram.c @@ -1292,21 +1292,6 @@ static int ram_save_multifd_page(QEMUFile *file, RAMBlock *block, return 1; } -static void -update_compress_thread_counts(const CompressParam *param, int bytes_xmit) -{ - ram_transferred_add(bytes_xmit); - - if (param->result == RES_ZEROPAGE) { - stat64_add(&mig_stats.zero_pages, 1); - return; - } - - /* 8 means a header with RAM_SAVE_FLAG_CONTINUE. */ - compression_counters.compressed_size += bytes_xmit - 8; - compression_counters.pages++; -} - static bool save_page_use_compression(RAMState *rs); static int send_queued_data(CompressParam *param) From 4703d1958ca149b3baa8df73945c5ddfc9808e73 Mon Sep 17 00:00:00 2001 From: Juan Quintela Date: Tue, 13 Jun 2023 16:57:52 +0200 Subject: [PATCH 0738/1077] migration: Simplify decompress_data_with_multi_threads() Doing a break to do another break is just confused. Just call return when we know we want to return. Signed-off-by: Juan Quintela Reviewed-by: Lukas Straub Message-ID: <20230613145757.10131-14-quintela@redhat.com> --- migration/ram-compress.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/migration/ram-compress.c b/migration/ram-compress.c index 3ad5975d48..95a8d6b906 100644 --- a/migration/ram-compress.c +++ b/migration/ram-compress.c @@ -481,14 +481,10 @@ void decompress_data_with_multi_threads(QEMUFile *f, void *host, int len) decomp_param[idx].len = len; qemu_cond_signal(&decomp_param[idx].cond); qemu_mutex_unlock(&decomp_param[idx].mutex); - break; + return; } } - if (idx < thread_count) { - break; - } else { - qemu_cond_wait(&decomp_done_cond, &decomp_done_lock); - } + qemu_cond_wait(&decomp_done_cond, &decomp_done_lock); } } From bef4e2ed8ea9de96f3c5493deadcd0f33367da2e Mon Sep 17 00:00:00 2001 From: Juan Quintela Date: Tue, 13 Jun 2023 16:57:53 +0200 Subject: [PATCH 0739/1077] migration: Use "i" as an for index in ram-compress.c It is used everywhere else in C. Once there, make sure that we don't use the index outside of the for declaring the variable there. Signed-off-by: Juan Quintela Reviewed-by: Lukas Straub Message-ID: <20230613145757.10131-15-quintela@redhat.com> --- migration/ram-compress.c | 56 ++++++++++++++++++---------------------- 1 file changed, 25 insertions(+), 31 deletions(-) diff --git a/migration/ram-compress.c b/migration/ram-compress.c index 95a8d6b906..d037dfe6cf 100644 --- a/migration/ram-compress.c +++ b/migration/ram-compress.c @@ -230,27 +230,25 @@ static inline void compress_reset_result(CompressParam *param) void flush_compressed_data(int (send_queued_data(CompressParam *))) { - int idx, thread_count; - - thread_count = migrate_compress_threads(); + int thread_count = migrate_compress_threads(); qemu_mutex_lock(&comp_done_lock); - for (idx = 0; idx < thread_count; idx++) { - while (!comp_param[idx].done) { + for (int i = 0; i < thread_count; i++) { + while (!comp_param[i].done) { qemu_cond_wait(&comp_done_cond, &comp_done_lock); } } qemu_mutex_unlock(&comp_done_lock); - for (idx = 0; idx < thread_count; idx++) { - qemu_mutex_lock(&comp_param[idx].mutex); - if (!comp_param[idx].quit) { - CompressParam *param = &comp_param[idx]; + for (int i = 0; i < thread_count; i++) { + qemu_mutex_lock(&comp_param[i].mutex); + if (!comp_param[i].quit) { + CompressParam *param = &comp_param[i]; send_queued_data(param); assert(qemu_file_buffer_empty(param->file)); compress_reset_result(param); } - qemu_mutex_unlock(&comp_param[idx].mutex); + qemu_mutex_unlock(&comp_param[i].mutex); } } @@ -265,15 +263,15 @@ static inline void set_compress_params(CompressParam *param, RAMBlock *block, int compress_page_with_multi_thread(RAMBlock *block, ram_addr_t offset, int (send_queued_data(CompressParam *))) { - int idx, thread_count, pages = -1; + int thread_count, pages = -1; bool wait = migrate_compress_wait_thread(); thread_count = migrate_compress_threads(); qemu_mutex_lock(&comp_done_lock); retry: - for (idx = 0; idx < thread_count; idx++) { - if (comp_param[idx].done) { - CompressParam *param = &comp_param[idx]; + for (int i = 0; i < thread_count; i++) { + if (comp_param[i].done) { + CompressParam *param = &comp_param[i]; qemu_mutex_lock(¶m->mutex); param->done = false; send_queued_data(param); @@ -367,16 +365,14 @@ static void *do_data_decompress(void *opaque) int wait_for_decompress_done(void) { - int idx, thread_count; - if (!migrate_compress()) { return 0; } - thread_count = migrate_decompress_threads(); + int thread_count = migrate_decompress_threads(); qemu_mutex_lock(&decomp_done_lock); - for (idx = 0; idx < thread_count; idx++) { - while (!decomp_param[idx].done) { + for (int i = 0; i < thread_count; i++) { + while (!decomp_param[i].done) { qemu_cond_wait(&decomp_done_cond, &decomp_done_lock); } } @@ -467,20 +463,18 @@ exit: void decompress_data_with_multi_threads(QEMUFile *f, void *host, int len) { - int idx, thread_count; - - thread_count = migrate_decompress_threads(); + int thread_count = migrate_decompress_threads(); QEMU_LOCK_GUARD(&decomp_done_lock); while (true) { - for (idx = 0; idx < thread_count; idx++) { - if (decomp_param[idx].done) { - decomp_param[idx].done = false; - qemu_mutex_lock(&decomp_param[idx].mutex); - qemu_get_buffer(f, decomp_param[idx].compbuf, len); - decomp_param[idx].des = host; - decomp_param[idx].len = len; - qemu_cond_signal(&decomp_param[idx].cond); - qemu_mutex_unlock(&decomp_param[idx].mutex); + for (int i = 0; i < thread_count; i++) { + if (decomp_param[i].done) { + decomp_param[i].done = false; + qemu_mutex_lock(&decomp_param[i].mutex); + qemu_get_buffer(f, decomp_param[i].compbuf, len); + decomp_param[i].des = host; + decomp_param[i].len = len; + qemu_cond_signal(&decomp_param[i].cond); + qemu_mutex_unlock(&decomp_param[i].mutex); return; } } From 17cd011d06ba91eb8f8f1ba97d0b1be6effcad41 Mon Sep 17 00:00:00 2001 From: Juan Quintela Date: Tue, 17 Oct 2023 19:23:03 +0200 Subject: [PATCH 0740/1077] migration: Print block status when needed The new line was only printed when command options were used. When we used migration parameters and capabilities, it wasn't. Reviewed-by: Fabiano Rosas Signed-off-by: Juan Quintela Message-ID: <20231017172307.22858-2-quintela@redhat.com> --- migration/migration-hmp-cmds.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/migration/migration-hmp-cmds.c b/migration/migration-hmp-cmds.c index d206700a43..a82597f18e 100644 --- a/migration/migration-hmp-cmds.c +++ b/migration/migration-hmp-cmds.c @@ -30,6 +30,7 @@ #include "sysemu/runstate.h" #include "ui/qemu-spice.h" #include "sysemu/sysemu.h" +#include "options.h" #include "migration.h" static void migration_global_dump(Monitor *mon) @@ -696,7 +697,6 @@ void hmp_x_colo_lost_heartbeat(Monitor *mon, const QDict *qdict) typedef struct HMPMigrationStatus { QEMUTimer *timer; Monitor *mon; - bool is_block_migration; } HMPMigrationStatus; static void hmp_migrate_status_cb(void *opaque) @@ -722,7 +722,7 @@ static void hmp_migrate_status_cb(void *opaque) timer_mod(status->timer, qemu_clock_get_ms(QEMU_CLOCK_REALTIME) + 1000); } else { - if (status->is_block_migration) { + if (migrate_block()) { monitor_printf(status->mon, "\n"); } if (info->error_desc) { @@ -762,7 +762,6 @@ void hmp_migrate(Monitor *mon, const QDict *qdict) status = g_malloc0(sizeof(*status)); status->mon = mon; - status->is_block_migration = blk || inc; status->timer = timer_new_ms(QEMU_CLOCK_REALTIME, hmp_migrate_status_cb, status); timer_mod(status->timer, qemu_clock_get_ms(QEMU_CLOCK_REALTIME)); From a536f564d3281014478ef100a0cd1204a47eb9e1 Mon Sep 17 00:00:00 2001 From: Helge Deller Date: Sat, 14 Oct 2023 07:06:04 +0200 Subject: [PATCH 0741/1077] hw/hppa: Require at least SeaBIOS-hppa version 10 The new SeaBIOS-hppa version 10 includes initial support for PA2.0 CPUs. Additionally update copyright and drop commented-out code. Signed-off-by: Helge Deller --- hw/hppa/machine.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/hw/hppa/machine.c b/hw/hppa/machine.c index cf28cb9586..c6d8deffcf 100644 --- a/hw/hppa/machine.c +++ b/hw/hppa/machine.c @@ -1,6 +1,8 @@ /* * QEMU HPPA hardware system emulator. - * Copyright 2018 Helge Deller + * (C) Copyright 2018-2023 Helge Deller + * + * This work is licensed under the GNU GPL license version 2 or later. */ #include "qemu/osdep.h" @@ -29,7 +31,7 @@ #include "net/net.h" #include "qemu/log.h" -#define MIN_SEABIOS_HPPA_VERSION 6 /* require at least this fw version */ +#define MIN_SEABIOS_HPPA_VERSION 10 /* require at least this fw version */ #define HPA_POWER_BUTTON (FIRMWARE_END - 0x10) @@ -95,9 +97,7 @@ static ISABus *hppa_isa_bus(void) isa_bus = isa_bus_new(NULL, get_system_memory(), isa_region, &error_abort); - isa_irqs = i8259_init(isa_bus, - /* qemu_allocate_irq(dino_set_isa_irq, s, 0)); */ - NULL); + isa_irqs = i8259_init(isa_bus, NULL); isa_bus_register_input_irqs(isa_bus, isa_irqs); return isa_bus; From 2e90154eea04c25bd30042ba4d6a9056e781437f Mon Sep 17 00:00:00 2001 From: Helge Deller Date: Sat, 14 Oct 2023 06:42:37 +0200 Subject: [PATCH 0742/1077] pci_ids/tulip: Add PCI vendor ID for HP and use it in tulip Signed-off-by: Helge Deller --- hw/net/tulip.c | 2 +- include/hw/pci/pci_ids.h | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/hw/net/tulip.c b/hw/net/tulip.c index 915e5fb595..11d866e431 100644 --- a/hw/net/tulip.c +++ b/hw/net/tulip.c @@ -1020,7 +1020,7 @@ static void tulip_class_init(ObjectClass *klass, void *data) k->exit = pci_tulip_exit; k->vendor_id = PCI_VENDOR_ID_DEC; k->device_id = PCI_DEVICE_ID_DEC_21143; - k->subsystem_vendor_id = 0x103c; + k->subsystem_vendor_id = PCI_VENDOR_ID_HP; k->subsystem_id = 0x104f; k->class_id = PCI_CLASS_NETWORK_ETHERNET; dc->vmsd = &vmstate_pci_tulip; diff --git a/include/hw/pci/pci_ids.h b/include/hw/pci/pci_ids.h index 85469b9b53..f1a53fea8d 100644 --- a/include/hw/pci/pci_ids.h +++ b/include/hw/pci/pci_ids.h @@ -179,6 +179,8 @@ #define PCI_DEVICE_ID_AMD_LANCE 0x2000 #define PCI_DEVICE_ID_AMD_SCSI 0x2020 +#define PCI_VENDOR_ID_HP 0x103c + #define PCI_VENDOR_ID_TI 0x104c #define PCI_VENDOR_ID_MOTOROLA 0x1057 From a1e6a5c46219bada2c7b932748527553b36559ae Mon Sep 17 00:00:00 2001 From: Helge Deller Date: Sat, 14 Oct 2023 06:50:55 +0200 Subject: [PATCH 0743/1077] lasips2: LASI PS/2 devices are not user-createable Those PS/2 ports are created with the LASI controller when a 32-bit PA-RISC machine is created. Mark them not user-createable to avoid showing them in the qemu device list. Signed-off-by: Helge Deller Cc: qemu-stable@nongnu.org --- hw/input/lasips2.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/hw/input/lasips2.c b/hw/input/lasips2.c index ea7c07a2ba..6075121b72 100644 --- a/hw/input/lasips2.c +++ b/hw/input/lasips2.c @@ -351,6 +351,11 @@ static void lasips2_port_class_init(ObjectClass *klass, void *data) { DeviceClass *dc = DEVICE_CLASS(klass); + /* + * The PS/2 mouse port is integreal part of LASI and can not be + * created by users without LASI. + */ + dc->user_creatable = false; dc->realize = lasips2_port_realize; } @@ -397,6 +402,11 @@ static void lasips2_kbd_port_class_init(ObjectClass *klass, void *data) DeviceClass *dc = DEVICE_CLASS(klass); LASIPS2PortDeviceClass *lpdc = LASIPS2_PORT_CLASS(klass); + /* + * The PS/2 keyboard port is integreal part of LASI and can not be + * created by users without LASI. + */ + dc->user_creatable = false; device_class_set_parent_realize(dc, lasips2_kbd_port_realize, &lpdc->parent_realize); } From 655e2a778dd701822bbe0bf90dad74c25bb05e49 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Thu, 5 Oct 2023 14:19:34 +0200 Subject: [PATCH 0744/1077] meson, cutils: allow non-relocatable installs Say QEMU is configured with bindir = "/usr/bin" and a firmware path that starts with "/usr/share/qemu". Ever since QEMU 5.2, QEMU's install has been relocatable: if you move qemu-system-x86_64 from /usr/bin to /home/username/bin, it will start looking for firmware in /home/username/share/qemu. Previously, you would get a non-relocatable install where the moved QEMU will keep looking for firmware in /usr/share/qemu. Windows almost always wants relocatable installs, and in fact that is why QEMU 5.2 introduced relocatability in the first place. However, newfangled distribution mechanisms such as AppImage (https://docs.appimage.org/reference/best-practices.html), and possibly NixOS, also dislike using at runtime the absolute paths that were established at build time. On POSIX systems you almost never care; if you do, your usecase dictates which one is desirable, so there's no single answer. Obviously relocatability works fine most of the time, because not many people have complained about QEMU's switch to relocatable install, and that's why until now there was no way to disable relocatability. But a non-relocatable, non-modular binary can help if you want to do experiments with old firmware and new QEMU or vice versa (because you can just upgrade/downgrade the firmware package, and use rpm2cpio or similar to extract the QEMU binaries outside /usr), so allow both. This patch allows one to build a non-relocatable install using a new option to configure. Why? Because it's not too hard, and because it helps the user double check the relocatability of their install. Note that the same code that handles relocation also lets you run QEMU from the build tree and pick e.g. firmware files from the source tree transparently. Therefore that part remains active with this patch, even if you configure with --disable-relocatable. Suggested-by: Michael Tokarev Reviewed-by: Emmanouil Pitsidianakis Signed-off-by: Paolo Bonzini --- meson.build | 20 ++++++++++++++++++++ meson_options.txt | 2 ++ scripts/meson-buildoptions.sh | 3 +++ util/cutils.c | 11 ++++++++--- 4 files changed, 33 insertions(+), 3 deletions(-) diff --git a/meson.build b/meson.build index 010d2c649c..1be9f92f7d 100644 --- a/meson.build +++ b/meson.build @@ -2111,6 +2111,7 @@ config_host_data.set('CONFIG_OPENGL', opengl.found()) config_host_data.set('CONFIG_PLUGIN', get_option('plugins')) config_host_data.set('CONFIG_RBD', rbd.found()) config_host_data.set('CONFIG_RDMA', rdma.found()) +config_host_data.set('CONFIG_RELOCATABLE', get_option('relocatable')) config_host_data.set('CONFIG_SAFESTACK', get_option('safe_stack')) config_host_data.set('CONFIG_SDL', sdl.found()) config_host_data.set('CONFIG_SDL_IMAGE', sdl_image.found()) @@ -4054,6 +4055,7 @@ if 'simple' in get_option('trace_backends') endif summary_info += {'D-Bus display': dbus_display} summary_info += {'QOM debugging': get_option('qom_cast_debug')} +summary_info += {'Relocatable install': get_option('relocatable')} summary_info += {'vhost-kernel support': have_vhost_kernel} summary_info += {'vhost-net support': have_vhost_net} summary_info += {'vhost-user support': have_vhost_user} @@ -4356,3 +4358,21 @@ if host_arch == 'unknown' or not supported_oses.contains(targetos) message('If you want to help supporting QEMU on this platform, please') message('contact the developers at qemu-devel@nongnu.org.') endif + +actually_reloc = get_option('relocatable') +# check if get_relocated_path() is actually able to relocate paths +if get_option('relocatable') and \ + not (get_option('prefix') / get_option('bindir')).startswith(get_option('prefix') / '') + message() + warning('bindir not included within prefix, the installation will not be relocatable.') + actually_reloc = false +endif +if not actually_reloc and (targetos == 'windows' or get_option('relocatable')) + if targetos == 'windows' + message() + warning('Windows installs should usually be relocatable.') + endif + message() + message('QEMU will have to be installed under ' + get_option('prefix') + '.') + message('Use --disable-relocatable to remove this warning.') +endif diff --git a/meson_options.txt b/meson_options.txt index 6a17b90968..e237b26846 100644 --- a/meson_options.txt +++ b/meson_options.txt @@ -101,6 +101,8 @@ option('cfi_debug', type: 'boolean', value: false, description: 'Verbose errors in case of CFI violation') option('multiprocess', type: 'feature', value: 'auto', description: 'Out of process device emulation support') +option('relocatable', type : 'boolean', value : 'true', + description: 'toggle relocatable install') option('vfio_user_server', type: 'feature', value: 'disabled', description: 'vfio-user server support') option('dbus_display', type: 'feature', value: 'auto', diff --git a/scripts/meson-buildoptions.sh b/scripts/meson-buildoptions.sh index 2a74b0275b..d4b89e6b44 100644 --- a/scripts/meson-buildoptions.sh +++ b/scripts/meson-buildoptions.sh @@ -17,6 +17,7 @@ meson_options_help() { printf "%s\n" ' code for the Hexagon frontend' printf "%s\n" ' --disable-install-blobs install provided firmware blobs' printf "%s\n" ' --disable-qom-cast-debug cast debugging support' + printf "%s\n" ' --disable-relocatable toggle relocatable install' printf "%s\n" ' --docdir=VALUE Base directory for documentation installation' printf "%s\n" ' (can be empty) [share/doc]' printf "%s\n" ' --enable-block-drv-whitelist-in-tools' @@ -421,6 +422,8 @@ _meson_option_parse() { --disable-rbd) printf "%s" -Drbd=disabled ;; --enable-rdma) printf "%s" -Drdma=enabled ;; --disable-rdma) printf "%s" -Drdma=disabled ;; + --enable-relocatable) printf "%s" -Drelocatable=true ;; + --disable-relocatable) printf "%s" -Drelocatable=false ;; --enable-replication) printf "%s" -Dreplication=enabled ;; --disable-replication) printf "%s" -Dreplication=disabled ;; --enable-rng-none) printf "%s" -Drng_none=true ;; diff --git a/util/cutils.c b/util/cutils.c index c99d26c5e2..64f817b477 100644 --- a/util/cutils.c +++ b/util/cutils.c @@ -1178,9 +1178,11 @@ char *get_relocated_path(const char *dir) #else g_string_append(result, dir); #endif - } else if (!starts_with_prefix(dir) || !starts_with_prefix(bindir)) { - g_string_assign(result, dir); - } else { + goto out; + } + + if (IS_ENABLED(CONFIG_RELOCATABLE) && + starts_with_prefix(dir) && starts_with_prefix(bindir)) { g_string_assign(result, exec_dir); /* Advance over common components. */ @@ -1203,7 +1205,10 @@ char *get_relocated_path(const char *dir) assert(G_IS_DIR_SEPARATOR(dir[-1])); g_string_append(result, dir - 1); } + goto out; } + g_string_assign(result, dir); +out: return g_string_free(result, false); } From ae22ae651515045ea06eac9abc55dacbfd616bd4 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Tue, 26 Sep 2023 17:20:53 +0200 Subject: [PATCH 0745/1077] configure: clean up handling of CFI option MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Avoid that --enable-cfi --disable-cfi leaves b_lto set to true. Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Paolo Bonzini --- configure | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/configure b/configure index d6103a0141..9f78205450 100755 --- a/configure +++ b/configure @@ -625,7 +625,10 @@ meson_option_build_array() { meson_options= meson_option_add() { - meson_options="$meson_options $(quote_sh "$1")" + local arg + for arg; do + meson_options="$meson_options $(quote_sh "$arg")" + done } meson_option_parse() { meson_options="$meson_options $(_meson_option_parse "$@")" @@ -767,11 +770,9 @@ for opt do ;; --disable-werror) werror="no" ;; - --enable-cfi) - cfi="true"; - meson_option_add -Db_lto=true + --enable-cfi) cfi=true ;; - --disable-cfi) cfi="false" + --disable-cfi) cfi=false ;; --disable-download) download="disabled"; git_submodules_action=validate; ;; @@ -1845,7 +1846,7 @@ if test "$skip_meson" = no; then test "$werror" = yes && meson_option_add -Dwerror=true # QEMU options - test "$cfi" != false && meson_option_add "-Dcfi=$cfi" + test "$cfi" != false && meson_option_add "-Dcfi=$cfi" "-Db_lto=$cfi" test "$docs" != auto && meson_option_add "-Ddocs=$docs" test -n "${LIB_FUZZING_ENGINE+xxx}" && meson_option_add "-Dfuzzing_engine=$LIB_FUZZING_ENGINE" test "$plugins" = yes && meson_option_add "-Dplugins=true" From adfa939e735688dba1098d91e8c71aef6d5ccd6b Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Thu, 31 Aug 2023 11:14:18 +0200 Subject: [PATCH 0746/1077] hw/xen: cleanup sourcesets xen_ss is added unconditionally to arm_ss and i386_ss (the only targets that can have CONFIG_XEN enabled) and its contents are gated by CONFIG_XEN; xen_specific_ss has no condition for its constituent files but is gated on CONFIG_XEN when its added to specific_ss. So xen_ss is a duplicate of xen_specific_ss, though defined in a different way. Merge the two by eliminating xen_ss. Signed-off-by: Paolo Bonzini --- hw/arm/meson.build | 1 - hw/i386/meson.build | 1 - hw/xen/meson.build | 11 ++++------- 3 files changed, 4 insertions(+), 9 deletions(-) diff --git a/hw/arm/meson.build b/hw/arm/meson.build index 11eb9112f8..a6feaf1af9 100644 --- a/hw/arm/meson.build +++ b/hw/arm/meson.build @@ -64,7 +64,6 @@ arm_ss.add(when: 'CONFIG_ARM_SMMUV3', if_true: files('smmuv3.c')) arm_ss.add(when: 'CONFIG_FSL_IMX6UL', if_true: files('fsl-imx6ul.c', 'mcimx6ul-evk.c')) arm_ss.add(when: 'CONFIG_NRF51_SOC', if_true: files('nrf51_soc.c')) arm_ss.add(when: 'CONFIG_XEN', if_true: files('xen_arm.c')) -arm_ss.add_all(xen_ss) system_ss.add(when: 'CONFIG_ARM_SMMUV3', if_true: files('smmu-common.c')) system_ss.add(when: 'CONFIG_EXYNOS4', if_true: files('exynos4_boards.c')) diff --git a/hw/i386/meson.build b/hw/i386/meson.build index ff879069c9..369c6bf823 100644 --- a/hw/i386/meson.build +++ b/hw/i386/meson.build @@ -32,6 +32,5 @@ subdir('kvm') subdir('xen') i386_ss.add_all(xenpv_ss) -i386_ss.add_all(xen_ss) hw_arch += {'i386': i386_ss} diff --git a/hw/xen/meson.build b/hw/xen/meson.build index 277f9f292b..d887fa9ba4 100644 --- a/hw/xen/meson.build +++ b/hw/xen/meson.build @@ -12,6 +12,10 @@ system_ss.add(when: ['CONFIG_XEN', xen], if_true: files( )) xen_specific_ss = ss.source_set() +xen_specific_ss.add(files( + 'xen-mapcache.c', + 'xen-hvm-common.c', +)) if have_xen_pci_passthrough xen_specific_ss.add(files( 'xen-host-pci-device.c', @@ -26,10 +30,3 @@ else endif specific_ss.add_all(when: ['CONFIG_XEN', xen], if_true: xen_specific_ss) - -xen_ss = ss.source_set() - -xen_ss.add(when: 'CONFIG_XEN', if_true: files( - 'xen-mapcache.c', - 'xen-hvm-common.c', -)) From 1725253647a7b579f205adb6e9a91e9406fc0ef9 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Thu, 31 Aug 2023 10:58:23 +0200 Subject: [PATCH 0747/1077] hw/remote: move stub vfu_object_set_bus_irq out of stubs/ Signed-off-by: Paolo Bonzini --- hw/remote/meson.build | 4 +++- stubs/vfio-user-obj.c => hw/remote/vfio-user-obj-stub.c | 0 stubs/meson.build | 1 - 3 files changed, 3 insertions(+), 2 deletions(-) rename stubs/vfio-user-obj.c => hw/remote/vfio-user-obj-stub.c (100%) diff --git a/hw/remote/meson.build b/hw/remote/meson.build index a1e8708c73..a3aa29aaf1 100644 --- a/hw/remote/meson.build +++ b/hw/remote/meson.build @@ -7,9 +7,11 @@ remote_ss.add(when: 'CONFIG_MULTIPROCESS', if_true: files('remote-obj.c')) remote_ss.add(when: 'CONFIG_MULTIPROCESS', if_true: files('proxy.c')) remote_ss.add(when: 'CONFIG_MULTIPROCESS', if_true: files('iohub.c')) remote_ss.add(when: 'CONFIG_MULTIPROCESS', if_true: files('iommu.c')) -remote_ss.add(when: 'CONFIG_VFIO_USER_SERVER', if_true: files('vfio-user-obj.c')) remote_ss.add(when: 'CONFIG_VFIO_USER_SERVER', if_true: libvfio_user_dep) +remote_ss.add(when: 'CONFIG_VFIO_USER_SERVER', if_true: files('vfio-user-obj.c'), + if_false: files('vfio-user-obj-stub.c')) +remote_ss.add(when: 'CONFIG_ALL', if_true: files('vfio-user-obj-stub.c')) specific_ss.add(when: 'CONFIG_MULTIPROCESS', if_true: files('memory.c')) specific_ss.add(when: 'CONFIG_MULTIPROCESS', if_true: files('proxy-memory-listener.c')) diff --git a/stubs/vfio-user-obj.c b/hw/remote/vfio-user-obj-stub.c similarity index 100% rename from stubs/vfio-user-obj.c rename to hw/remote/vfio-user-obj-stub.c diff --git a/stubs/meson.build b/stubs/meson.build index cde44972bf..0bf25e6ca5 100644 --- a/stubs/meson.build +++ b/stubs/meson.build @@ -65,4 +65,3 @@ else stub_ss.add(files('qdev.c')) endif stub_ss.add(files('semihost-all.c')) -stub_ss.add(when: 'CONFIG_VFIO_USER_SERVER', if_false: files('vfio-user-obj.c')) From 730be6138e5efa949b351e2b649cc9b5d96dce7d Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Thu, 28 Sep 2023 10:27:24 +0200 Subject: [PATCH 0748/1077] tests/tcg/arm: move non-SVE tests out of conditional test-aes, sha1-vector and sha512-vector need not be conditional on $(CROSS_CC_HAS_SVE), reorganize the "if"s to move them outside. Signed-off-by: Paolo Bonzini --- tests/tcg/aarch64/Makefile.target | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/tests/tcg/aarch64/Makefile.target b/tests/tcg/aarch64/Makefile.target index 2efacf9a5a..d01b8ff47c 100644 --- a/tests/tcg/aarch64/Makefile.target +++ b/tests/tcg/aarch64/Makefile.target @@ -73,11 +73,6 @@ endif # System Registers Tests AARCH64_TESTS += sysregs -ifneq ($(CROSS_CC_HAS_SVE),) -# SVE ioctl test -AARCH64_TESTS += sve-ioctls -sve-ioctls: CFLAGS+=-march=armv8.1-a+sve - AARCH64_TESTS += test-aes test-aes: CFLAGS += -O -march=armv8-a+aes test-aes: test-aes-main.c.inc @@ -100,12 +95,15 @@ sha512-vector: sha512.c TESTS += sha512-vector ifneq ($(CROSS_CC_HAS_SVE),) +# SVE ioctl test +AARCH64_TESTS += sve-ioctls +sve-ioctls: CFLAGS+=-march=armv8.1-a+sve + sha512-sve: CFLAGS=-O3 -march=armv8.1-a+sve sha512-sve: sha512.c $(CC) $(CFLAGS) $(EXTRA_CFLAGS) $< -o $@ $(LDFLAGS) TESTS += sha512-sve -endif ifeq ($(HOST_GDB_SUPPORTS_ARCH),y) GDB_SCRIPT=$(SRC_PATH)/tests/guest-debug/run-test.py From a47dd5c516ed7fff768554ac1ec4cba2145c5ea9 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Thu, 28 Sep 2023 10:44:56 +0200 Subject: [PATCH 0749/1077] configure, tests/tcg: simplify GDB conditionals Unify HAVE_GDB_BIN (currently in config-host.mak) and HOST_GDB_SUPPORTS_ARCH into a single GDB variable in config-target.mak. Reviewed-by: Emmanouil Pitsidianakis Signed-off-by: Paolo Bonzini --- configure | 30 +++++++++---------- meson.build | 4 +-- tests/tcg/aarch64/Makefile.target | 6 ++-- tests/tcg/multiarch/Makefile.target | 18 ++++------- .../multiarch/system/Makefile.softmmu-target | 15 ++++------ tests/tcg/s390x/Makefile.target | 6 ++-- 6 files changed, 33 insertions(+), 46 deletions(-) diff --git a/configure b/configure index 9f78205450..ffcfabb8d3 100755 --- a/configure +++ b/configure @@ -1140,6 +1140,18 @@ if test "$tcg" = "auto"; then fi fi +######################################### +# gdb test + +if test -n "$gdb_bin"; then + gdb_version=$($gdb_bin --version | head -n 1) + if version_ge ${gdb_version##* } 9.1; then + gdb_arches=$($python "$source_path/scripts/probe-gdb-support.py" $gdb_bin) + else + gdb_bin="" + fi +fi + ########################################## # big/little endian test cat > $TMPC << EOF @@ -1660,17 +1672,7 @@ fi echo "SRC_PATH=$source_path" >> $config_host_mak echo "TARGET_DIRS=$target_list" >> $config_host_mak - -if test -n "$gdb_bin"; then - gdb_version=$($gdb_bin --version | head -n 1) - if version_ge ${gdb_version##* } 9.1; then - echo "HAVE_GDB_BIN=$gdb_bin" >> $config_host_mak - gdb_arches=$($python "$source_path/scripts/probe-gdb-support.py" $gdb_bin) - else - gdb_bin="" - fi -fi - +echo "GDB=$gdb_bin" >> $config_host_mak if test "$container" != no; then echo "RUNC=$runc" >> $config_host_mak fi @@ -1715,10 +1717,6 @@ mkdir -p tests/tcg echo "# Automatically generated by configure - do not modify" > $config_host_mak echo "SRC_PATH=$source_path" >> $config_host_mak -# versioned checked in the main config_host.mak above -if test -n "$gdb_bin"; then - echo "HAVE_GDB_BIN=$gdb_bin" >> $config_host_mak -fi if test "$plugins" = "yes" ; then echo "CONFIG_PLUGIN=y" >> $config_host_mak fi @@ -1755,7 +1753,7 @@ for target in $target_list; do # will GDB work with these binaries? if test "${gdb_arches#*$arch}" != "$gdb_arches"; then - echo "HOST_GDB_SUPPORTS_ARCH=y" >> "$config_target_mak" + echo "GDB=$gdb_bin" >> $config_target_mak fi echo "run-tcg-tests-$target: $qemu\$(EXESUF)" >> Makefile.prereqs diff --git a/meson.build b/meson.build index 1be9f92f7d..2bda62a2b1 100644 --- a/meson.build +++ b/meson.build @@ -4021,8 +4021,8 @@ summary(summary_info, bool_yn: true, section: 'Directories') summary_info = {} summary_info += {'python': '@0@ (version: @1@)'.format(python.full_path(), python.language_version())} summary_info += {'sphinx-build': sphinx_build} -if config_host.has_key('HAVE_GDB_BIN') - summary_info += {'gdb': config_host['HAVE_GDB_BIN']} +if config_host.has_key('GDB') + summary_info += {'gdb': config_host['GDB']} endif summary_info += {'iasl': iasl} summary_info += {'genisoimage': config_host['GENISOIMAGE']} diff --git a/tests/tcg/aarch64/Makefile.target b/tests/tcg/aarch64/Makefile.target index d01b8ff47c..62b38c792f 100644 --- a/tests/tcg/aarch64/Makefile.target +++ b/tests/tcg/aarch64/Makefile.target @@ -105,19 +105,19 @@ sha512-sve: sha512.c TESTS += sha512-sve -ifeq ($(HOST_GDB_SUPPORTS_ARCH),y) +ifneq ($(GDB),) GDB_SCRIPT=$(SRC_PATH)/tests/guest-debug/run-test.py run-gdbstub-sysregs: sysregs $(call run-test, $@, $(GDB_SCRIPT) \ - --gdb $(HAVE_GDB_BIN) \ + --gdb $(GDB) \ --qemu $(QEMU) --qargs "$(QEMU_OPTS)" \ --bin $< --test $(AARCH64_SRC)/gdbstub/test-sve.py, \ basic gdbstub SVE support) run-gdbstub-sve-ioctls: sve-ioctls $(call run-test, $@, $(GDB_SCRIPT) \ - --gdb $(HAVE_GDB_BIN) \ + --gdb $(GDB) \ --qemu $(QEMU) --qargs "$(QEMU_OPTS)" \ --bin $< --test $(AARCH64_SRC)/gdbstub/test-sve-ioctl.py, \ basic gdbstub SVE ZLEN support) diff --git a/tests/tcg/multiarch/Makefile.target b/tests/tcg/multiarch/Makefile.target index 43bddeaf21..f3bfaf1a22 100644 --- a/tests/tcg/multiarch/Makefile.target +++ b/tests/tcg/multiarch/Makefile.target @@ -63,45 +63,39 @@ run-test-mmap: test-mmap run-test-mmap-%: test-mmap $(call run-test, test-mmap-$*, $(QEMU) -p $* $<, $< ($* byte pages)) -ifneq ($(HAVE_GDB_BIN),) -ifeq ($(HOST_GDB_SUPPORTS_ARCH),y) +ifneq ($(GDB),) GDB_SCRIPT=$(SRC_PATH)/tests/guest-debug/run-test.py run-gdbstub-sha1: sha1 $(call run-test, $@, $(GDB_SCRIPT) \ - --gdb $(HAVE_GDB_BIN) \ + --gdb $(GDB) \ --qemu $(QEMU) --qargs "$(QEMU_OPTS)" \ --bin $< --test $(MULTIARCH_SRC)/gdbstub/sha1.py, \ basic gdbstub support) run-gdbstub-qxfer-auxv-read: sha1 $(call run-test, $@, $(GDB_SCRIPT) \ - --gdb $(HAVE_GDB_BIN) \ + --gdb $(GDB) \ --qemu $(QEMU) --qargs "$(QEMU_OPTS)" \ --bin $< --test $(MULTIARCH_SRC)/gdbstub/test-qxfer-auxv-read.py, \ basic gdbstub qXfer:auxv:read support) run-gdbstub-proc-mappings: sha1 $(call run-test, $@, $(GDB_SCRIPT) \ - --gdb $(HAVE_GDB_BIN) \ + --gdb $(GDB) \ --qemu $(QEMU) --qargs "$(QEMU_OPTS)" \ --bin $< --test $(MULTIARCH_SRC)/gdbstub/test-proc-mappings.py, \ proc mappings support) run-gdbstub-thread-breakpoint: testthread $(call run-test, $@, $(GDB_SCRIPT) \ - --gdb $(HAVE_GDB_BIN) \ + --gdb $(GDB) \ --qemu $(QEMU) --qargs "$(QEMU_OPTS)" \ --bin $< --test $(MULTIARCH_SRC)/gdbstub/test-thread-breakpoint.py, \ hitting a breakpoint on non-main thread) - else run-gdbstub-%: - $(call skip-test, "gdbstub test $*", "no guest arch support") -endif -else -run-gdbstub-%: - $(call skip-test, "gdbstub test $*", "need working gdb") + $(call skip-test, "gdbstub test $*", "need working gdb with $(patsubst -%,,$(TARGET_NAME)) support") endif EXTRA_RUNS += run-gdbstub-sha1 run-gdbstub-qxfer-auxv-read \ run-gdbstub-proc-mappings run-gdbstub-thread-breakpoint diff --git a/tests/tcg/multiarch/system/Makefile.softmmu-target b/tests/tcg/multiarch/system/Makefile.softmmu-target index 90810a32b2..dee4f58dea 100644 --- a/tests/tcg/multiarch/system/Makefile.softmmu-target +++ b/tests/tcg/multiarch/system/Makefile.softmmu-target @@ -14,13 +14,12 @@ VPATH+=$(MULTIARCH_SYSTEM_SRC) MULTIARCH_TEST_SRCS=$(wildcard $(MULTIARCH_SYSTEM_SRC)/*.c) MULTIARCH_TESTS = $(patsubst $(MULTIARCH_SYSTEM_SRC)/%.c, %, $(MULTIARCH_TEST_SRCS)) -ifneq ($(HAVE_GDB_BIN),) -ifeq ($(HOST_GDB_SUPPORTS_ARCH),y) +ifneq ($(GDB),) GDB_SCRIPT=$(SRC_PATH)/tests/guest-debug/run-test.py run-gdbstub-memory: memory $(call run-test, $@, $(GDB_SCRIPT) \ - --gdb $(HAVE_GDB_BIN) \ + --gdb $(GDB) \ --qemu $(QEMU) \ --output $<.gdb.out \ --qargs \ @@ -29,7 +28,7 @@ run-gdbstub-memory: memory softmmu gdbstub support) run-gdbstub-interrupt: interrupt $(call run-test, $@, $(GDB_SCRIPT) \ - --gdb $(HAVE_GDB_BIN) \ + --gdb $(GDB) \ --qemu $(QEMU) \ --output $<.gdb.out \ --qargs \ @@ -38,7 +37,7 @@ run-gdbstub-interrupt: interrupt softmmu gdbstub support) run-gdbstub-untimely-packet: hello $(call run-test, $@, $(GDB_SCRIPT) \ - --gdb $(HAVE_GDB_BIN) \ + --gdb $(GDB) \ --gdb-args "-ex 'set debug remote 1'" \ --output untimely-packet.gdb.out \ --stderr untimely-packet.gdb.err \ @@ -51,11 +50,7 @@ run-gdbstub-untimely-packet: hello "GREP", file untimely-packet.gdb.err) else run-gdbstub-%: - $(call skip-test, "gdbstub test $*", "no guest arch support") -endif -else -run-gdbstub-%: - $(call skip-test, "gdbstub test $*", "need working gdb") + $(call skip-test, "gdbstub test $*", "need working gdb with $(patsubst -%,,$(TARGET_NAME)) support") endif MULTIARCH_RUNS += run-gdbstub-memory run-gdbstub-interrupt run-gdbstub-untimely-packet diff --git a/tests/tcg/s390x/Makefile.target b/tests/tcg/s390x/Makefile.target index c650aefe5c..826f0a18e4 100644 --- a/tests/tcg/s390x/Makefile.target +++ b/tests/tcg/s390x/Makefile.target @@ -81,12 +81,12 @@ $(Z15_TESTS): CFLAGS+=-march=z15 -O2 TESTS+=$(Z15_TESTS) endif -ifeq ($(HOST_GDB_SUPPORTS_ARCH),y) +ifneq ($(GDB),) GDB_SCRIPT=$(SRC_PATH)/tests/guest-debug/run-test.py run-gdbstub-signals-s390x: signals-s390x $(call run-test, $@, $(GDB_SCRIPT) \ - --gdb $(HAVE_GDB_BIN) \ + --gdb $(GDB) \ --qemu $(QEMU) --qargs "$(QEMU_OPTS)" \ --bin $< --test $(S390X_SRC)/gdbstub/test-signals-s390x.py, \ mixing signals and debugging) @@ -95,7 +95,7 @@ hello-s390x-asm: CFLAGS+=-nostdlib run-gdbstub-svc: hello-s390x-asm $(call run-test, $@, $(GDB_SCRIPT) \ - --gdb $(HAVE_GDB_BIN) \ + --gdb $(GDB) \ --qemu $(QEMU) --qargs "$(QEMU_OPTS)" \ --bin $< --test $(S390X_SRC)/gdbstub/test-svc.py, \ single-stepping svc) From 39fb3cfc28baac007ea8dafaf7a2c22c44faba19 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Mon, 18 Sep 2023 11:06:48 +0200 Subject: [PATCH 0750/1077] configure: clean up plugin option handling Keep together all the conditions that lead to disabling plugins, and remove now-dead code. Since the option was not in SKIP_OPTIONS, it was present twice in the help message, both from configure and from meson-buildoptions.sh. Remove the duplication and take the occasion to document the option as autodetected, which it is. Signed-off-by: Paolo Bonzini --- configure | 39 +++++++++++++++-------------------- scripts/meson-buildoptions.py | 17 ++++++++++----- scripts/meson-buildoptions.sh | 2 +- 3 files changed, 30 insertions(+), 28 deletions(-) diff --git a/configure b/configure index ffcfabb8d3..688577bebd 100755 --- a/configure +++ b/configure @@ -377,7 +377,6 @@ fi case $targetos in windows) - plugins="no" pie="no" ;; haiku) @@ -741,7 +740,6 @@ for opt do default_cflags='-O0 -g' ;; --disable-tcg) tcg="disabled" - plugins="no" ;; --enable-tcg) tcg="enabled" ;; @@ -778,11 +776,7 @@ for opt do ;; --enable-download) download="enabled"; git_submodules_action=update; ;; - --enable-plugins) if test "$targetos" = "windows"; then - error_exit "TCG plugins not currently supported on Windows platforms" - else - plugins="yes" - fi + --enable-plugins) plugins="yes" ;; --disable-plugins) plugins="no" ;; @@ -808,11 +802,6 @@ then git_submodules_action="validate" fi -# test for any invalid configuration combinations -if test "$plugins" = "yes" -a "$tcg" = "disabled"; then - error_exit "Can't enable plugins on non-TCG builds" -fi - if ! test -f "$source_path/subprojects/keycodemapdb/README" \ && test "$download" = disabled then @@ -923,8 +912,6 @@ Advanced options (experts only): --enable-debug enable common debug build options --disable-werror disable compilation abort on warning --cpu=CPU Build for host CPU [$cpu] - --enable-plugins - enable plugins via shared library loading --disable-containers don't use containers for cross-building --container-engine=TYPE which container engine to use [$container_engine] --gdb=GDB-path gdb to use for gdbstub tests [$gdb_bin] @@ -1066,15 +1053,27 @@ if test "$targetos" = "bogus"; then error_exit "Unrecognized host OS (uname -s reports '$(uname -s)')" fi +# test for any invalid configuration combinations +if test "$targetos" = "windows"; then + if test "$plugins" = "yes"; then + error_exit "TCG plugins not currently supported on Windows platforms" + fi + plugins="no" +fi +if test "$tcg" = "disabled" ; then + if test "$plugins" = "yes"; then + error_exit "Can't enable plugins on non-TCG builds" + fi + plugins="no" +fi if test "$static" = "yes" ; then if test "$plugins" = "yes"; then error_exit "static and plugins are mutually incompatible" - else - plugins="no" fi + plugins="no" fi -test "$plugins" = "" && plugins=yes -if test "$plugins" = "yes"; then +if test "$plugins" != "no"; then + plugins=yes subdirs="$subdirs contrib/plugins" fi @@ -1717,10 +1716,6 @@ mkdir -p tests/tcg echo "# Automatically generated by configure - do not modify" > $config_host_mak echo "SRC_PATH=$source_path" >> $config_host_mak -if test "$plugins" = "yes" ; then - echo "CONFIG_PLUGIN=y" >> $config_host_mak -fi - tcg_tests_targets= for target in $target_list; do arch=${target%%-*} diff --git a/scripts/meson-buildoptions.py b/scripts/meson-buildoptions.py index 8d2e526132..b787c84e91 100644 --- a/scripts/meson-buildoptions.py +++ b/scripts/meson-buildoptions.py @@ -44,6 +44,11 @@ OPTION_NAMES = { "trace_file": "with-trace-file", } +# Options that configure autodetects, even though meson defines them as boolean +AUTO_OPTIONS = { + "plugins", +} + BUILTIN_OPTIONS = { "b_coverage", "b_lto", @@ -168,6 +173,7 @@ def cli_metavar(opt): def print_help(options): print("meson_options_help() {") + feature_opts = [] for opt in sorted(options, key=cli_help_key): key = cli_help_key(opt) # The first section includes options that have an arguments, @@ -176,7 +182,7 @@ def print_help(options): metavar = cli_metavar(opt) left = f"--{key}={metavar}" help_line(left, opt, 27, True) - elif opt["type"] == "boolean": + elif opt["type"] == "boolean" and opt["name"] not in AUTO_OPTIONS: left = f"--{key}" help_line(left, opt, 27, False) elif allow_arg(opt): @@ -185,16 +191,17 @@ def print_help(options): else: left = f"--{key}=CHOICE" help_line(left, opt, 27, True) + else: + feature_opts.append(opt) sh_print() sh_print("Optional features, enabled with --enable-FEATURE and") sh_print("disabled with --disable-FEATURE, default is enabled if available") sh_print("(unless built with --without-default-features):") sh_print() - for opt in options: - key = opt["name"].replace("_", "-") - if opt["type"] != "boolean" and not allow_arg(opt): - help_line(key, opt, 18, False) + for opt in sorted(feature_opts, key=cli_option): + key = cli_option(opt) + help_line(key, opt, 18, False) print("}") diff --git a/scripts/meson-buildoptions.sh b/scripts/meson-buildoptions.sh index d4b89e6b44..22d6996660 100644 --- a/scripts/meson-buildoptions.sh +++ b/scripts/meson-buildoptions.sh @@ -40,7 +40,6 @@ meson_options_help() { printf "%s\n" ' jemalloc/system/tcmalloc)' printf "%s\n" ' --enable-module-upgrades try to load modules from alternate paths for' printf "%s\n" ' upgrades' - printf "%s\n" ' --enable-plugins TCG plugins via shared library loading' printf "%s\n" ' --enable-rng-none dummy RNG, avoid using /dev/(u)random and' printf "%s\n" ' getrandom()' printf "%s\n" ' --enable-safe-stack SafeStack Stack Smash Protection (requires' @@ -149,6 +148,7 @@ meson_options_help() { printf "%s\n" ' pa PulseAudio sound support' printf "%s\n" ' parallels parallels image format support' printf "%s\n" ' pipewire PipeWire sound support' + printf "%s\n" ' plugins TCG plugins via shared library loading' printf "%s\n" ' png PNG support with libpng' printf "%s\n" ' pvrdma Enable PVRDMA support' printf "%s\n" ' qcow1 qcow1 image format support' From 2e938a9a6145be52488af74949d49a60ce8baaad Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Thu, 28 Sep 2023 10:41:29 +0200 Subject: [PATCH 0751/1077] configure: clean up PIE option handling Keep together all the conditions that lead to disabling PIE. Signed-off-by: Paolo Bonzini --- configure | 35 ++++++++++++++--------------------- 1 file changed, 14 insertions(+), 21 deletions(-) diff --git a/configure b/configure index 688577bebd..5c1d618f10 100755 --- a/configure +++ b/configure @@ -373,17 +373,6 @@ else targetos=bogus fi -# OS specific - -case $targetos in -windows) - pie="no" -;; -haiku) - pie="no" -;; -esac - if test ! -z "$cpu" ; then # command line argument : @@ -1088,19 +1077,23 @@ static THREAD int tls_var; int main(void) { return tls_var; } EOF -if test "$static" = "yes"; then - if test "$pie" != "no" && compile_prog "-Werror -fPIE -DPIE" "-static-pie"; then +if test "$targetos" = windows || test "$targetos" = haiku; then + if test "$pie" = "yes"; then + error_exit "PIE not available due to missing OS support" + fi + pie=no +fi + +if test "$pie" != "no"; then + if test "$static" = "yes"; then + pie_ldflags=-static-pie + else + pie_ldflags=-pie + fi + if compile_prog "-Werror -fPIE -DPIE" "$pie_ldflags"; then pie="yes" elif test "$pie" = "yes"; then error_exit "-static-pie not available due to missing toolchain support" - else - pie="no" - fi -elif test "$pie" != "no"; then - if compile_prog "-Werror -fPIE -DPIE" "-pie"; then - pie="yes" - elif test "$pie" = "yes"; then - error_exit "PIE not available due to missing toolchain support" else echo "Disabling PIE due to missing toolchain support" pie="no" From 050b439887edbbd1b07b94111ffdffbc817e97cf Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Thu, 28 Sep 2023 12:07:23 +0200 Subject: [PATCH 0752/1077] configure: remove some dead cruft print_error is only invoked in one place, and $git is unused. Reviewed-by: Thomas Huth Signed-off-by: Paolo Bonzini --- configure | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/configure b/configure index 5c1d618f10..0994f54530 100755 --- a/configure +++ b/configure @@ -94,7 +94,7 @@ quote_sh() { printf "%s" "$1" | sed "s,','\\\\'',g; s,.*,'&'," } -print_error() { +error_exit() { (echo echo "ERROR: $1" while test -n "$2"; do @@ -102,10 +102,6 @@ print_error() { shift done echo) >&2 -} - -error_exit() { - print_error "$@" exit 1 } @@ -248,7 +244,6 @@ done default_cflags='-O2 -g' git_submodules_action="update" -git="git" docs="auto" EXESUF="" prefix="/usr/local" From c36dd41ba2a8bd8d51f4f7499fbdc02b1bd5c865 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Mon, 16 Oct 2023 08:18:08 +0200 Subject: [PATCH 0753/1077] configure: move target-specific defaults to an external machine file Enable Windows-specific defaults with a machine file, so that related options can be automatically parsed and included in the help message. Signed-off-by: Paolo Bonzini --- configs/meson/windows.txt | 9 +++++++++ configure | 37 ++++++++++++++--------------------- scripts/meson-buildoptions.py | 4 +++- scripts/meson-buildoptions.sh | 7 +++++++ 4 files changed, 34 insertions(+), 23 deletions(-) create mode 100644 configs/meson/windows.txt diff --git a/configs/meson/windows.txt b/configs/meson/windows.txt new file mode 100644 index 0000000000..55b192e71b --- /dev/null +++ b/configs/meson/windows.txt @@ -0,0 +1,9 @@ +# target-specific defaults, can still be overridden on +# the command line + +[built-in options] +bindir = '' +prefix = '/qemu' + +[project options] +qemu_suffix = '' diff --git a/configure b/configure index 0994f54530..8f23c8d165 100755 --- a/configure +++ b/configure @@ -246,8 +246,6 @@ default_cflags='-O2 -g' git_submodules_action="update" docs="auto" EXESUF="" -prefix="/usr/local" -qemu_suffix="qemu" system="yes" linux_user="" bsd_user="" @@ -256,7 +254,6 @@ subdirs="" ninja="" python= download="enabled" -bindir="bin" skip_meson=no use_containers="yes" gdb_bin=$(command -v "gdb-multiarch" || command -v "gdb") @@ -583,9 +580,6 @@ done if test "$targetos" = "windows" ; then EXESUF=".exe" - prefix="/qemu" - bindir="" - qemu_suffix="" fi meson_option_build_array() { @@ -622,6 +616,14 @@ meson_option_parse() { fi } +meson_add_machine_file() { + if test "$cross_compile" = "yes"; then + meson_option_add --cross-file "$1" + else + meson_option_add --native-file "$1" + fi +} + for opt do optarg=$(expr "x$opt" : 'x[^=]*=\(.*\)') case "$opt" in @@ -629,8 +631,6 @@ for opt do ;; --version|-V) exec cat "$source_path/VERSION" ;; - --prefix=*) prefix="$optarg" - ;; --cross-prefix=*) ;; --cc=*) @@ -701,10 +701,6 @@ for opt do ;; --static) static="yes" ;; - --bindir=*) bindir="$optarg" - ;; - --with-suffix=*) qemu_suffix="$optarg" - ;; --host=*|--build=*|\ --disable-dependency-tracking|\ --sbindir=*|--sharedstatedir=*|\ @@ -861,7 +857,6 @@ Options: [defaults in brackets after descriptions] Standard options: --help print this message - --prefix=PREFIX install in PREFIX [$prefix] --target-list=LIST set target list (default: build all) $(echo Available targets: $default_target_list | \ fold -s -w 53 | sed -e 's/^/ /') @@ -886,8 +881,6 @@ Advanced options (experts only): --ninja=NINJA use specified ninja [$ninja] --smbd=SMBD use specified smbd [$smbd] --static enable static build [$static] - --bindir=PATH install binaries in PATH - --with-suffix=SUFFIX suffix for QEMU data inside datadir/libdir/sysconfdir/docdir [$qemu_suffix] --without-default-features default all --enable-* options to "disabled" --without-default-devices do not include any device that is not needed to start the emulator (only use if you are including @@ -1803,24 +1796,25 @@ if test "$skip_meson" = no; then else echo "endian = 'little'" >> $cross fi - cross_arg="--cross-file config-meson.cross" native="config-meson.native.new" echo "# Automatically generated by configure - do not modify" > $native echo "[binaries]" >> $native echo "c = [$(meson_quote $host_cc)]" >> $native mv $native config-meson.native - cross_arg="$cross_arg --native-file config-meson.native" - else - cross_arg="--native-file config-meson.cross" + meson_option_add --native-file + meson_option_add config-meson.native fi mv $cross config-meson.cross + meson_add_machine_file config-meson.cross + if test -f "$source_path/configs/meson/$targetos.txt"; then + meson_add_machine_file $source_path/configs/meson/$targetos.txt + fi rm -rf meson-private meson-info meson-logs # Built-in options test "$download" = "disabled" && meson_option_add "--wrap-mode=nodownload" - test "$bindir" != "bin" && meson_option_add "-Dbindir=$bindir" test "$default_feature" = no && meson_option_add -Dauto_features=disabled test "$static" = yes && meson_option_add -Dprefer_static=true test "$pie" = no && meson_option_add -Db_pie=false @@ -1831,11 +1825,10 @@ if test "$skip_meson" = no; then test "$docs" != auto && meson_option_add "-Ddocs=$docs" test -n "${LIB_FUZZING_ENGINE+xxx}" && meson_option_add "-Dfuzzing_engine=$LIB_FUZZING_ENGINE" test "$plugins" = yes && meson_option_add "-Dplugins=true" - test "$qemu_suffix" != qemu && meson_option_add "-Dqemu_suffix=$qemu_suffix" test "$smbd" != '' && meson_option_add "-Dsmbd=$smbd" test "$tcg" != enabled && meson_option_add "-Dtcg=$tcg" run_meson() { - NINJA=$ninja $meson setup --prefix "$prefix" "$@" $cross_arg "$PWD" "$source_path" + NINJA=$ninja $meson setup "$@" "$PWD" "$source_path" } eval run_meson $meson_options if test "$?" -ne 0 ; then diff --git a/scripts/meson-buildoptions.py b/scripts/meson-buildoptions.py index b787c84e91..0c24bdc1e8 100644 --- a/scripts/meson-buildoptions.py +++ b/scripts/meson-buildoptions.py @@ -28,7 +28,6 @@ import sys SKIP_OPTIONS = { "default_devices", "fuzzing_engine", - "qemu_suffix", "smbd", } @@ -40,6 +39,7 @@ OPTION_NAMES = { "malloc": "enable-malloc", "pkgversion": "with-pkgversion", "qemu_firmwarepath": "firmwarepath", + "qemu_suffix": "with-suffix", "trace_backends": "enable-trace-backends", "trace_file": "with-trace-file", } @@ -52,6 +52,7 @@ AUTO_OPTIONS = { BUILTIN_OPTIONS = { "b_coverage", "b_lto", + "bindir", "datadir", "debug", "includedir", @@ -60,6 +61,7 @@ BUILTIN_OPTIONS = { "localedir", "localstatedir", "mandir", + "prefix", "strip", "sysconfdir", } diff --git a/scripts/meson-buildoptions.sh b/scripts/meson-buildoptions.sh index 22d6996660..e152203061 100644 --- a/scripts/meson-buildoptions.sh +++ b/scripts/meson-buildoptions.sh @@ -3,6 +3,7 @@ meson_options_help() { printf "%s\n" ' --audio-drv-list=CHOICES Set audio driver list [default] (choices: alsa/co' printf "%s\n" ' reaudio/default/dsound/jack/oss/pa/pipewire/sdl/s' printf "%s\n" ' ndio)' + printf "%s\n" ' --bindir=VALUE Executable directory [bin]' printf "%s\n" ' --block-drv-ro-whitelist=VALUE' printf "%s\n" ' set block driver read-only whitelist (by default' printf "%s\n" ' affects only QEMU, not tools like qemu-img)' @@ -62,6 +63,7 @@ meson_options_help() { printf "%s\n" ' --localedir=VALUE Locale data directory [share/locale]' printf "%s\n" ' --localstatedir=VALUE Localstate data directory [/var/local]' printf "%s\n" ' --mandir=VALUE Manual page directory [share/man]' + printf "%s\n" ' --prefix=VALUE Installation prefix [/usr/local]' printf "%s\n" ' --sysconfdir=VALUE Sysconf data directory [etc]' printf "%s\n" ' --tls-priority=VALUE Default TLS protocol/cipher priority string' printf "%s\n" ' [NORMAL]' @@ -69,6 +71,8 @@ meson_options_help() { printf "%s\n" ' auto/sigaltstack/ucontext/windows)' printf "%s\n" ' --with-pkgversion=VALUE use specified string as sub-version of the' printf "%s\n" ' package' + printf "%s\n" ' --with-suffix=VALUE Suffix for QEMU data/modules/config directories' + printf "%s\n" ' (can be empty) [qemu]' printf "%s\n" ' --with-trace-file=VALUE Trace file prefix for simple backend [trace]' printf "%s\n" '' printf "%s\n" 'Optional features, enabled with --enable-FEATURE and' @@ -229,6 +233,7 @@ _meson_option_parse() { --disable-gcov) printf "%s" -Db_coverage=false ;; --enable-lto) printf "%s" -Db_lto=true ;; --disable-lto) printf "%s" -Db_lto=false ;; + --bindir=*) quote_sh "-Dbindir=$2" ;; --enable-blkio) printf "%s" -Dblkio=enabled ;; --disable-blkio) printf "%s" -Dblkio=disabled ;; --block-drv-ro-whitelist=*) quote_sh "-Dblock_drv_ro_whitelist=$2" ;; @@ -407,6 +412,7 @@ _meson_option_parse() { --disable-plugins) printf "%s" -Dplugins=false ;; --enable-png) printf "%s" -Dpng=enabled ;; --disable-png) printf "%s" -Dpng=disabled ;; + --prefix=*) quote_sh "-Dprefix=$2" ;; --enable-pvrdma) printf "%s" -Dpvrdma=enabled ;; --disable-pvrdma) printf "%s" -Dpvrdma=disabled ;; --enable-qcow1) printf "%s" -Dqcow1=enabled ;; @@ -414,6 +420,7 @@ _meson_option_parse() { --enable-qed) printf "%s" -Dqed=enabled ;; --disable-qed) printf "%s" -Dqed=disabled ;; --firmwarepath=*) quote_sh "-Dqemu_firmwarepath=$(meson_option_build_array $2)" ;; + --with-suffix=*) quote_sh "-Dqemu_suffix=$2" ;; --enable-qga-vss) printf "%s" -Dqga_vss=enabled ;; --disable-qga-vss) printf "%s" -Dqga_vss=disabled ;; --enable-qom-cast-debug) printf "%s" -Dqom_cast_debug=true ;; From 090a188cc1a85b8b5e33ad164c923003935323cc Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Mon, 16 Oct 2023 08:20:13 +0200 Subject: [PATCH 0754/1077] configure: move environment-specific defaults to config-meson.cross Store the -Werror and SMBD defaults in the machine file, which still allows them to be overridden on the command line and enables automatic parsing of the related options. Signed-off-by: Paolo Bonzini --- configure | 37 +++++++++++++---------------------- scripts/meson-buildoptions.py | 3 ++- scripts/meson-buildoptions.sh | 5 +++++ 3 files changed, 21 insertions(+), 24 deletions(-) diff --git a/configure b/configure index 8f23c8d165..200570a3d1 100755 --- a/configure +++ b/configure @@ -258,7 +258,6 @@ skip_meson=no use_containers="yes" gdb_bin=$(command -v "gdb-multiarch" || command -v "gdb") gdb_arches="" -werror="" # Don't accept a target_list environment variable. unset target_list @@ -314,7 +313,6 @@ objcopy="${OBJCOPY-${cross_prefix}objcopy}" ld="${LD-${cross_prefix}ld}" ranlib="${RANLIB-${cross_prefix}ranlib}" nm="${NM-${cross_prefix}nm}" -smbd="$SMBD" strip="${STRIP-${cross_prefix}strip}" widl="${WIDL-${cross_prefix}widl}" windres="${WINDRES-${cross_prefix}windres}" @@ -651,8 +649,6 @@ for opt do ;; --ninja=*) ninja="$optarg" ;; - --smbd=*) smbd="$optarg" - ;; --extra-cflags=*) ;; --extra-cxxflags=*) @@ -744,10 +740,6 @@ for opt do ;; --disable-pie) pie="no" ;; - --enable-werror) werror="yes" - ;; - --disable-werror) werror="no" - ;; --enable-cfi) cfi=true ;; --disable-cfi) cfi=false @@ -879,7 +871,6 @@ Advanced options (experts only): --cross-prefix-ARCH=PREFIX cross compiler prefix when building ARCH guest test cases --python=PYTHON use specified python [$python] --ninja=NINJA use specified ninja [$ninja] - --smbd=SMBD use specified smbd [$smbd] --static enable static build [$static] --without-default-features default all --enable-* options to "disabled" --without-default-devices do not include any device that is not needed to @@ -887,7 +878,6 @@ Advanced options (experts only): desired devices in configs/devices/) --with-devices-ARCH=NAME override default configs/devices --enable-debug enable common debug build options - --disable-werror disable compilation abort on warning --cpu=CPU Build for host CPU [$cpu] --disable-containers don't use containers for cross-building --container-engine=TYPE which container engine to use [$container_engine] @@ -1011,17 +1001,6 @@ if test -z "$ninja"; then fi fi -# Consult white-list to determine whether to enable werror -# by default. Only enable by default for git builds -if test -z "$werror" ; then - if test -e "$source_path/.git" && \ - { test "$targetos" = linux || test "$targetos" = "windows"; }; then - werror="yes" - else - werror="no" - fi -fi - if test "$targetos" = "bogus"; then # Now that we know that we're not printing the help and that # the compiler works (so the results of the check_defines we used @@ -1764,6 +1743,20 @@ if test "$skip_meson" = no; then test -n "$objcc" && echo "objc_args = [$(meson_quote $OBJCFLAGS $EXTRA_OBJCFLAGS)]" >> $cross echo "c_link_args = [$(meson_quote $CFLAGS $LDFLAGS $EXTRA_CFLAGS $EXTRA_LDFLAGS)]" >> $cross echo "cpp_link_args = [$(meson_quote $CXXFLAGS $LDFLAGS $EXTRA_CXXFLAGS $EXTRA_LDFLAGS)]" >> $cross + + # Only enable by default for git builds and on select OSes + echo "# environment defaults, can still be overridden on " >> $cross + echo "# the command line" >> $cross + if test -e "$source_path/.git" && \ + { test "$targetos" = linux || test "$targetos" = "windows"; }; then + echo 'werror = true' >> $cross + fi + echo "[project options]" >> $cross + if test "$SMBD" != ''; then + echo "smbd = $(meson_quote "$SMBD")" >> $cross + fi + + echo >> $cross echo "[binaries]" >> $cross echo "c = [$(meson_quote $cc $CPU_CFLAGS)]" >> $cross test -n "$cxx" && echo "cpp = [$(meson_quote $cxx $CPU_CFLAGS)]" >> $cross @@ -1818,14 +1811,12 @@ if test "$skip_meson" = no; then test "$default_feature" = no && meson_option_add -Dauto_features=disabled test "$static" = yes && meson_option_add -Dprefer_static=true test "$pie" = no && meson_option_add -Db_pie=false - test "$werror" = yes && meson_option_add -Dwerror=true # QEMU options test "$cfi" != false && meson_option_add "-Dcfi=$cfi" "-Db_lto=$cfi" test "$docs" != auto && meson_option_add "-Ddocs=$docs" test -n "${LIB_FUZZING_ENGINE+xxx}" && meson_option_add "-Dfuzzing_engine=$LIB_FUZZING_ENGINE" test "$plugins" = yes && meson_option_add "-Dplugins=true" - test "$smbd" != '' && meson_option_add "-Dsmbd=$smbd" test "$tcg" != enabled && meson_option_add "-Dtcg=$tcg" run_meson() { NINJA=$ninja $meson setup "$@" "$PWD" "$source_path" diff --git a/scripts/meson-buildoptions.py b/scripts/meson-buildoptions.py index 0c24bdc1e8..2e88732a29 100644 --- a/scripts/meson-buildoptions.py +++ b/scripts/meson-buildoptions.py @@ -28,7 +28,6 @@ import sys SKIP_OPTIONS = { "default_devices", "fuzzing_engine", - "smbd", } OPTION_NAMES = { @@ -47,6 +46,7 @@ OPTION_NAMES = { # Options that configure autodetects, even though meson defines them as boolean AUTO_OPTIONS = { "plugins", + "werror", } BUILTIN_OPTIONS = { @@ -64,6 +64,7 @@ BUILTIN_OPTIONS = { "prefix", "strip", "sysconfdir", + "werror", } LINE_WIDTH = 76 diff --git a/scripts/meson-buildoptions.sh b/scripts/meson-buildoptions.sh index e152203061..dec3382016 100644 --- a/scripts/meson-buildoptions.sh +++ b/scripts/meson-buildoptions.sh @@ -64,6 +64,7 @@ meson_options_help() { printf "%s\n" ' --localstatedir=VALUE Localstate data directory [/var/local]' printf "%s\n" ' --mandir=VALUE Manual page directory [share/man]' printf "%s\n" ' --prefix=VALUE Installation prefix [/usr/local]' + printf "%s\n" ' --smbd=VALUE Path to smbd for slirp networking' printf "%s\n" ' --sysconfdir=VALUE Sysconf data directory [etc]' printf "%s\n" ' --tls-priority=VALUE Default TLS protocol/cipher priority string' printf "%s\n" ' [NORMAL]' @@ -205,6 +206,7 @@ meson_options_help() { printf "%s\n" ' vpc vpc image format support' printf "%s\n" ' vte vte support for the gtk UI' printf "%s\n" ' vvfat vvfat image format support' + printf "%s\n" ' werror Treat warnings as errors' printf "%s\n" ' whpx WHPX acceleration support' printf "%s\n" ' xen Xen backend support' printf "%s\n" ' xen-pci-passthrough' @@ -453,6 +455,7 @@ _meson_option_parse() { --disable-slirp-smbd) printf "%s" -Dslirp_smbd=disabled ;; --enable-smartcard) printf "%s" -Dsmartcard=enabled ;; --disable-smartcard) printf "%s" -Dsmartcard=disabled ;; + --smbd=*) quote_sh "-Dsmbd=$2" ;; --enable-snappy) printf "%s" -Dsnappy=enabled ;; --disable-snappy) printf "%s" -Dsnappy=disabled ;; --enable-sndio) printf "%s" -Dsndio=enabled ;; @@ -529,6 +532,8 @@ _meson_option_parse() { --disable-vte) printf "%s" -Dvte=disabled ;; --enable-vvfat) printf "%s" -Dvvfat=enabled ;; --disable-vvfat) printf "%s" -Dvvfat=disabled ;; + --enable-werror) printf "%s" -Dwerror=true ;; + --disable-werror) printf "%s" -Dwerror=false ;; --enable-whpx) printf "%s" -Dwhpx=enabled ;; --disable-whpx) printf "%s" -Dwhpx=disabled ;; --enable-xen) printf "%s" -Dxen=enabled ;; From 17599573bf1ff18442e34d6760bbb8d090a30a08 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Mon, 9 Oct 2023 14:03:56 +0200 Subject: [PATCH 0755/1077] configure: unify handling of several Debian cross containers The Debian and GNU architecture names match very often, even though there are common cases (32-bit Arm or 64-bit x86) where they do not and other cases in which the GNU triplet is actually a quadruplet. But it is still possible to group the common case into a single case inside probe_target_compiler. Signed-off-by: Paolo Bonzini --- configure | 41 +++++------------------------------------ 1 file changed, 5 insertions(+), 36 deletions(-) diff --git a/configure b/configure index 200570a3d1..4b24c572d5 100755 --- a/configure +++ b/configure @@ -1281,10 +1281,6 @@ probe_target_compiler() { container_cross_prefix=aarch64-linux-gnu- container_cross_cc=${container_cross_prefix}gcc ;; - alpha) - container_image=debian-alpha-cross - container_cross_prefix=alpha-linux-gnu- - ;; arm) # We don't have any bigendian build tools so we only use this for ARM container_image=debian-armhf-cross @@ -1299,10 +1295,6 @@ probe_target_compiler() { container_cross_prefix=hexagon-unknown-linux-musl- container_cross_cc=${container_cross_prefix}clang ;; - hppa) - container_image=debian-hppa-cross - container_cross_prefix=hppa-linux-gnu- - ;; i386) container_image=fedora-i386-cross container_cross_prefix= @@ -1311,10 +1303,6 @@ probe_target_compiler() { container_image=debian-loongarch-cross container_cross_prefix=loongarch64-unknown-linux-gnu- ;; - m68k) - container_image=debian-m68k-cross - container_cross_prefix=m68k-linux-gnu- - ;; microblaze) container_image=debian-microblaze-cross container_cross_prefix=microblaze-linux-musl- @@ -1327,14 +1315,6 @@ probe_target_compiler() { container_image=debian-mips64-cross container_cross_prefix=mips64-linux-gnuabi64- ;; - mipsel) - container_image=debian-mipsel-cross - container_cross_prefix=mipsel-linux-gnu- - ;; - mips) - container_image=debian-mips-cross - container_cross_prefix=mips-linux-gnu- - ;; nios2) container_image=debian-nios2-cross container_cross_prefix=nios2-linux-gnu- @@ -1349,22 +1329,6 @@ probe_target_compiler() { container_cross_prefix=powerpc${target_arch#ppc}-linux-gnu- container_cross_cc=${container_cross_prefix}gcc-10 ;; - riscv64) - container_image=debian-riscv64-test-cross - container_cross_prefix=riscv64-linux-gnu- - ;; - s390x) - container_image=debian-s390x-cross - container_cross_prefix=s390x-linux-gnu- - ;; - sh4) - container_image=debian-sh4-cross - container_cross_prefix=sh4-linux-gnu- - ;; - sparc64) - container_image=debian-sparc64-cross - container_cross_prefix=sparc64-linux-gnu- - ;; tricore) container_image=debian-tricore-cross container_cross_prefix=tricore- @@ -1379,6 +1343,11 @@ probe_target_compiler() { # default to the dc232b cpu container_cross_prefix=/opt/2020.07/xtensa-dc232b-elf/bin/xtensa-dc232b-elf- ;; + *) + # Debian and GNU architecture names usually match + container_image=debian-$target_arch-cross + container_cross_prefix=$target_arch-linux-gnu- + ;; esac : ${container_cross_cc:=${container_cross_prefix}gcc} : ${container_cross_ar:=${container_cross_prefix}ar} From e20d68aa0b9546655c4017fb7341173bba825958 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Mon, 9 Oct 2023 14:13:59 +0200 Subject: [PATCH 0756/1077] configure, meson: use command line options to configure qemu-ga Preserve the functionality of the environment variables, but allow using the command line instead. Signed-off-by: Paolo Bonzini --- configure | 16 +++++++++------- meson_options.txt | 7 +++++++ qga/meson.build | 9 ++++++--- scripts/meson-buildoptions.sh | 9 +++++++++ 4 files changed, 31 insertions(+), 10 deletions(-) diff --git a/configure b/configure index 4b24c572d5..8827a29bf4 100755 --- a/configure +++ b/configure @@ -1592,12 +1592,6 @@ echo >> $config_host_mak echo all: >> $config_host_mak -if test "$targetos" = "windows"; then - echo "QEMU_GA_MANUFACTURER=${QEMU_GA_MANUFACTURER-QEMU}" >> $config_host_mak - echo "QEMU_GA_DISTRO=${QEMU_GA_DISTRO-Linux}" >> $config_host_mak - echo "QEMU_GA_VERSION=${QEMU_GA_VERSION-$(cat "$source_path"/VERSION)}" >> $config_host_mak -fi - echo "SRC_PATH=$source_path" >> $config_host_mak echo "TARGET_DIRS=$target_list" >> $config_host_mak echo "GDB=$gdb_bin" >> $config_host_mak @@ -1724,6 +1718,15 @@ if test "$skip_meson" = no; then if test "$SMBD" != ''; then echo "smbd = $(meson_quote "$SMBD")" >> $cross fi + if test "${QEMU_GA_MANUFACTURER}" != ''; then + echo "qemu_ga_manufacturer = $(meson_quote "${QEMU_GA_MANUFACTURER}")" >> $cross + fi + if test "${QEMU_GA_DISTRO}" != ''; then + echo "qemu_ga_distro = $(meson_quote "${QEMU_GA_DISTRO}")" >> $cross + fi + if test "${QEMU_GA_VERSION}" != ''; then + echo "qemu_ga_version = $(meson_quote "${QEMU_GA_VERSION}")" >> $cross + fi echo >> $cross echo "[binaries]" >> $cross @@ -1775,7 +1778,6 @@ if test "$skip_meson" = no; then rm -rf meson-private meson-info meson-logs - # Built-in options test "$download" = "disabled" && meson_option_add "--wrap-mode=nodownload" test "$default_feature" = no && meson_option_add -Dauto_features=disabled test "$static" = yes && meson_option_add -Dprefer_static=true diff --git a/meson_options.txt b/meson_options.txt index e237b26846..1b0c02b4a5 100644 --- a/meson_options.txt +++ b/meson_options.txt @@ -353,5 +353,12 @@ option('qom_cast_debug', type: 'boolean', value: true, option('slirp_smbd', type : 'feature', value : 'auto', description: 'use smbd (at path --smbd=*) in slirp networking') +option('qemu_ga_manufacturer', type: 'string', value: 'QEMU', + description: '"manufacturer" name for qemu-ga registry entries') +option('qemu_ga_distro', type: 'string', value: 'Linux', + description: 'second path element in qemu-ga registry entries') +option('qemu_ga_version', type: 'string', value: '', + description: 'version number for qemu-ga installer') + option('hexagon_idef_parser', type : 'boolean', value : true, description: 'use idef-parser to automatically generate TCG code for the Hexagon frontend') diff --git a/qga/meson.build b/qga/meson.build index 59cae0cc6e..940a51d55d 100644 --- a/qga/meson.build +++ b/qga/meson.build @@ -145,6 +145,9 @@ if targetos == 'windows' else libpcre = 'libpcre2' endif + qga_msi_version = get_option('qemu_ga_version') == '' \ + ? project.version() \ + : get_option('qemu_ga_version') qga_msi = custom_target('QGA MSI', input: files('installer/qemu-ga.wxs'), output: 'qemu-ga-@0@.msi'.format(host_arch), @@ -155,9 +158,9 @@ if targetos == 'windows' qemu_ga_msi_vss, '-D', 'BUILD_DIR=' + meson.project_build_root(), '-D', 'BIN_DIR=' + glib_pc.get_variable('bindir'), - '-D', 'QEMU_GA_VERSION=' + config_host['QEMU_GA_VERSION'], - '-D', 'QEMU_GA_MANUFACTURER=' + config_host['QEMU_GA_MANUFACTURER'], - '-D', 'QEMU_GA_DISTRO=' + config_host['QEMU_GA_DISTRO'], + '-D', 'QEMU_GA_VERSION=' + qga_msi_version, + '-D', 'QEMU_GA_MANUFACTURER=' + get_option('qemu_ga_manufacturer'), + '-D', 'QEMU_GA_DISTRO=' + get_option('qemu_ga_distro'), '-D', 'LIBPCRE=' + libpcre, ]) all_qga += [qga_msi] diff --git a/scripts/meson-buildoptions.sh b/scripts/meson-buildoptions.sh index dec3382016..bda88993bd 100644 --- a/scripts/meson-buildoptions.sh +++ b/scripts/meson-buildoptions.sh @@ -64,6 +64,12 @@ meson_options_help() { printf "%s\n" ' --localstatedir=VALUE Localstate data directory [/var/local]' printf "%s\n" ' --mandir=VALUE Manual page directory [share/man]' printf "%s\n" ' --prefix=VALUE Installation prefix [/usr/local]' + printf "%s\n" ' --qemu-ga-distro=VALUE second path element in qemu-ga registry entries' + printf "%s\n" ' [Linux]' + printf "%s\n" ' --qemu-ga-manufacturer=VALUE' + printf "%s\n" ' "manufacturer" name for qemu-ga registry entries' + printf "%s\n" ' [QEMU]' + printf "%s\n" ' --qemu-ga-version=VALUE version number for qemu-ga installer' printf "%s\n" ' --smbd=VALUE Path to smbd for slirp networking' printf "%s\n" ' --sysconfdir=VALUE Sysconf data directory [etc]' printf "%s\n" ' --tls-priority=VALUE Default TLS protocol/cipher priority string' @@ -422,6 +428,9 @@ _meson_option_parse() { --enable-qed) printf "%s" -Dqed=enabled ;; --disable-qed) printf "%s" -Dqed=disabled ;; --firmwarepath=*) quote_sh "-Dqemu_firmwarepath=$(meson_option_build_array $2)" ;; + --qemu-ga-distro=*) quote_sh "-Dqemu_ga_distro=$2" ;; + --qemu-ga-manufacturer=*) quote_sh "-Dqemu_ga_manufacturer=$2" ;; + --qemu-ga-version=*) quote_sh "-Dqemu_ga_version=$2" ;; --with-suffix=*) quote_sh "-Dqemu_suffix=$2" ;; --enable-qga-vss) printf "%s" -Dqga_vss=enabled ;; --disable-qga-vss) printf "%s" -Dqga_vss=disabled ;; From 79fccf7e2bd792e20f2ceab9b5a30d9f47dbf409 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Thu, 28 Sep 2023 11:20:01 +0200 Subject: [PATCH 0757/1077] meson-buildoptions: document the data at the top Signed-off-by: Paolo Bonzini --- scripts/meson-buildoptions.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/scripts/meson-buildoptions.py b/scripts/meson-buildoptions.py index 2e88732a29..4814a8ff61 100644 --- a/scripts/meson-buildoptions.py +++ b/scripts/meson-buildoptions.py @@ -25,11 +25,15 @@ import textwrap import shlex import sys +# Options with nonstandard names (e.g. --with/--without) or OS-dependent +# defaults. Try not to add any. SKIP_OPTIONS = { "default_devices", "fuzzing_engine", } +# Options whose name doesn't match the option for backwards compatibility +# reasons, because Meson gives them a funny name, or both OPTION_NAMES = { "b_coverage": "gcov", "b_lto": "lto", @@ -49,6 +53,10 @@ AUTO_OPTIONS = { "werror", } +# Builtin options that should be definable via configure. Some of the others +# we really do not want (e.g. c_args is defined via the native file, not +# via -D, because it's a mix of CFLAGS and --extra-cflags); for specific +# cases "../configure -D" can be used as an escape hatch. BUILTIN_OPTIONS = { "b_coverage", "b_lto", From b4d61d3d816fcde0aa560d16a44f4790d7c8de3f Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Thu, 28 Sep 2023 12:00:48 +0200 Subject: [PATCH 0758/1077] meson: add a note on why we use config_host for program paths Signed-off-by: Paolo Bonzini --- meson.build | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/meson.build b/meson.build index 2bda62a2b1..0182622aed 100644 --- a/meson.build +++ b/meson.build @@ -4021,6 +4021,11 @@ summary(summary_info, bool_yn: true, section: 'Directories') summary_info = {} summary_info += {'python': '@0@ (version: @1@)'.format(python.full_path(), python.language_version())} summary_info += {'sphinx-build': sphinx_build} + +# FIXME: the [binaries] section of machine files, which can be probed +# with find_program(), would be great for passing gdb and genisoimage +# paths from configure to Meson. However, there seems to be no way to +# hide a program (for example if gdb is too old). if config_host.has_key('GDB') summary_info += {'gdb': config_host['GDB']} endif From 528148980adb78bc368a5254204e2ea98e4f6b6c Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Tue, 17 Oct 2023 17:32:50 +0200 Subject: [PATCH 0759/1077] configure: define "pkg-config" in addition to "pkgconfig" Meson used to allow both "pkgconfig" and "pkg-config" entries in machine files; the former was used for dependency lookup and the latter was used as return value for "find_program('pkg-config')", which is a less common use-case and one that QEMU does not need. This inconsistency is going to be fixed by Meson 1.3, which will deprecate "pkgconfig" in favor of "pkg-config" (the less common one, but it makes sense because it matches the name of the binary). For backward compatibility it is still allowed to define both, so do that in the configure-generated machine file. Related: https://github.com/mesonbuild/meson/pull/12385 Reviewed-by: Thomas Huth Signed-off-by: Paolo Bonzini --- configure | 1 + 1 file changed, 1 insertion(+) diff --git a/configure b/configure index 8827a29bf4..b4ea78c77d 100755 --- a/configure +++ b/configure @@ -1736,6 +1736,7 @@ if test "$skip_meson" = no; then echo "ar = [$(meson_quote $ar)]" >> $cross echo "nm = [$(meson_quote $nm)]" >> $cross echo "pkgconfig = [$(meson_quote $pkg_config)]" >> $cross + echo "pkg-config = [$(meson_quote $pkg_config)]" >> $cross echo "ranlib = [$(meson_quote $ranlib)]" >> $cross if has $sdl2_config; then echo "sdl2-config = [$(meson_quote $sdl2_config)]" >> $cross From 8cba58b57865140b16e38b6c5a273db81f827860 Mon Sep 17 00:00:00 2001 From: Eric Auger Date: Mon, 9 Oct 2023 11:09:03 +0200 Subject: [PATCH 0760/1077] scripts/update-linux-headers: Add iommufd.h MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Update the script to import iommufd.h Signed-off-by: Eric Auger Signed-off-by: Yi Liu Signed-off-by: Zhenzhong Duan Reviewed-by: Cédric Le Goater Signed-off-by: Cédric Le Goater --- scripts/update-linux-headers.sh | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/scripts/update-linux-headers.sh b/scripts/update-linux-headers.sh index 35a64bb501..34295c0fe5 100755 --- a/scripts/update-linux-headers.sh +++ b/scripts/update-linux-headers.sh @@ -161,7 +161,8 @@ done rm -rf "$output/linux-headers/linux" mkdir -p "$output/linux-headers/linux" for header in const.h stddef.h kvm.h vfio.h vfio_ccw.h vfio_zdev.h vhost.h \ - psci.h psp-sev.h userfaultfd.h memfd.h mman.h nvme_ioctl.h vduse.h; do + psci.h psp-sev.h userfaultfd.h memfd.h mman.h nvme_ioctl.h \ + vduse.h iommufd.h; do cp "$tmpdir/include/linux/$header" "$output/linux-headers/linux" done From f7cbfa71303c2ecf31d240f764516a5fc823cf97 Mon Sep 17 00:00:00 2001 From: Zhenzhong Duan Date: Mon, 9 Oct 2023 11:09:04 +0200 Subject: [PATCH 0761/1077] linux-headers: Add iommufd.h MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Since commit da3c22c74a3c ("linux-headers: Update to Linux v6.6-rc1"), linux-headers has been updated to v6.6-rc1. As previous patch added iommufd.h to update-linux-headers.sh, run the script again against TAG v6.6-rc1 to have iommufd.h included. Signed-off-by: Zhenzhong Duan Reviewed-by: Cédric Le Goater Signed-off-by: Cédric Le Goater --- linux-headers/linux/iommufd.h | 444 ++++++++++++++++++++++++++++++++++ 1 file changed, 444 insertions(+) create mode 100644 linux-headers/linux/iommufd.h diff --git a/linux-headers/linux/iommufd.h b/linux-headers/linux/iommufd.h new file mode 100644 index 0000000000..218bf7ac98 --- /dev/null +++ b/linux-headers/linux/iommufd.h @@ -0,0 +1,444 @@ +/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ +/* Copyright (c) 2021-2022, NVIDIA CORPORATION & AFFILIATES. + */ +#ifndef _IOMMUFD_H +#define _IOMMUFD_H + +#include +#include + +#define IOMMUFD_TYPE (';') + +/** + * DOC: General ioctl format + * + * The ioctl interface follows a general format to allow for extensibility. Each + * ioctl is passed in a structure pointer as the argument providing the size of + * the structure in the first u32. The kernel checks that any structure space + * beyond what it understands is 0. This allows userspace to use the backward + * compatible portion while consistently using the newer, larger, structures. + * + * ioctls use a standard meaning for common errnos: + * + * - ENOTTY: The IOCTL number itself is not supported at all + * - E2BIG: The IOCTL number is supported, but the provided structure has + * non-zero in a part the kernel does not understand. + * - EOPNOTSUPP: The IOCTL number is supported, and the structure is + * understood, however a known field has a value the kernel does not + * understand or support. + * - EINVAL: Everything about the IOCTL was understood, but a field is not + * correct. + * - ENOENT: An ID or IOVA provided does not exist. + * - ENOMEM: Out of memory. + * - EOVERFLOW: Mathematics overflowed. + * + * As well as additional errnos, within specific ioctls. + */ +enum { + IOMMUFD_CMD_BASE = 0x80, + IOMMUFD_CMD_DESTROY = IOMMUFD_CMD_BASE, + IOMMUFD_CMD_IOAS_ALLOC, + IOMMUFD_CMD_IOAS_ALLOW_IOVAS, + IOMMUFD_CMD_IOAS_COPY, + IOMMUFD_CMD_IOAS_IOVA_RANGES, + IOMMUFD_CMD_IOAS_MAP, + IOMMUFD_CMD_IOAS_UNMAP, + IOMMUFD_CMD_OPTION, + IOMMUFD_CMD_VFIO_IOAS, + IOMMUFD_CMD_HWPT_ALLOC, + IOMMUFD_CMD_GET_HW_INFO, +}; + +/** + * struct iommu_destroy - ioctl(IOMMU_DESTROY) + * @size: sizeof(struct iommu_destroy) + * @id: iommufd object ID to destroy. Can be any destroyable object type. + * + * Destroy any object held within iommufd. + */ +struct iommu_destroy { + __u32 size; + __u32 id; +}; +#define IOMMU_DESTROY _IO(IOMMUFD_TYPE, IOMMUFD_CMD_DESTROY) + +/** + * struct iommu_ioas_alloc - ioctl(IOMMU_IOAS_ALLOC) + * @size: sizeof(struct iommu_ioas_alloc) + * @flags: Must be 0 + * @out_ioas_id: Output IOAS ID for the allocated object + * + * Allocate an IO Address Space (IOAS) which holds an IO Virtual Address (IOVA) + * to memory mapping. + */ +struct iommu_ioas_alloc { + __u32 size; + __u32 flags; + __u32 out_ioas_id; +}; +#define IOMMU_IOAS_ALLOC _IO(IOMMUFD_TYPE, IOMMUFD_CMD_IOAS_ALLOC) + +/** + * struct iommu_iova_range - ioctl(IOMMU_IOVA_RANGE) + * @start: First IOVA + * @last: Inclusive last IOVA + * + * An interval in IOVA space. + */ +struct iommu_iova_range { + __aligned_u64 start; + __aligned_u64 last; +}; + +/** + * struct iommu_ioas_iova_ranges - ioctl(IOMMU_IOAS_IOVA_RANGES) + * @size: sizeof(struct iommu_ioas_iova_ranges) + * @ioas_id: IOAS ID to read ranges from + * @num_iovas: Input/Output total number of ranges in the IOAS + * @__reserved: Must be 0 + * @allowed_iovas: Pointer to the output array of struct iommu_iova_range + * @out_iova_alignment: Minimum alignment required for mapping IOVA + * + * Query an IOAS for ranges of allowed IOVAs. Mapping IOVA outside these ranges + * is not allowed. num_iovas will be set to the total number of iovas and + * the allowed_iovas[] will be filled in as space permits. + * + * The allowed ranges are dependent on the HW path the DMA operation takes, and + * can change during the lifetime of the IOAS. A fresh empty IOAS will have a + * full range, and each attached device will narrow the ranges based on that + * device's HW restrictions. Detaching a device can widen the ranges. Userspace + * should query ranges after every attach/detach to know what IOVAs are valid + * for mapping. + * + * On input num_iovas is the length of the allowed_iovas array. On output it is + * the total number of iovas filled in. The ioctl will return -EMSGSIZE and set + * num_iovas to the required value if num_iovas is too small. In this case the + * caller should allocate a larger output array and re-issue the ioctl. + * + * out_iova_alignment returns the minimum IOVA alignment that can be given + * to IOMMU_IOAS_MAP/COPY. IOVA's must satisfy:: + * + * starting_iova % out_iova_alignment == 0 + * (starting_iova + length) % out_iova_alignment == 0 + * + * out_iova_alignment can be 1 indicating any IOVA is allowed. It cannot + * be higher than the system PAGE_SIZE. + */ +struct iommu_ioas_iova_ranges { + __u32 size; + __u32 ioas_id; + __u32 num_iovas; + __u32 __reserved; + __aligned_u64 allowed_iovas; + __aligned_u64 out_iova_alignment; +}; +#define IOMMU_IOAS_IOVA_RANGES _IO(IOMMUFD_TYPE, IOMMUFD_CMD_IOAS_IOVA_RANGES) + +/** + * struct iommu_ioas_allow_iovas - ioctl(IOMMU_IOAS_ALLOW_IOVAS) + * @size: sizeof(struct iommu_ioas_allow_iovas) + * @ioas_id: IOAS ID to allow IOVAs from + * @num_iovas: Input/Output total number of ranges in the IOAS + * @__reserved: Must be 0 + * @allowed_iovas: Pointer to array of struct iommu_iova_range + * + * Ensure a range of IOVAs are always available for allocation. If this call + * succeeds then IOMMU_IOAS_IOVA_RANGES will never return a list of IOVA ranges + * that are narrower than the ranges provided here. This call will fail if + * IOMMU_IOAS_IOVA_RANGES is currently narrower than the given ranges. + * + * When an IOAS is first created the IOVA_RANGES will be maximally sized, and as + * devices are attached the IOVA will narrow based on the device restrictions. + * When an allowed range is specified any narrowing will be refused, ie device + * attachment can fail if the device requires limiting within the allowed range. + * + * Automatic IOVA allocation is also impacted by this call. MAP will only + * allocate within the allowed IOVAs if they are present. + * + * This call replaces the entire allowed list with the given list. + */ +struct iommu_ioas_allow_iovas { + __u32 size; + __u32 ioas_id; + __u32 num_iovas; + __u32 __reserved; + __aligned_u64 allowed_iovas; +}; +#define IOMMU_IOAS_ALLOW_IOVAS _IO(IOMMUFD_TYPE, IOMMUFD_CMD_IOAS_ALLOW_IOVAS) + +/** + * enum iommufd_ioas_map_flags - Flags for map and copy + * @IOMMU_IOAS_MAP_FIXED_IOVA: If clear the kernel will compute an appropriate + * IOVA to place the mapping at + * @IOMMU_IOAS_MAP_WRITEABLE: DMA is allowed to write to this mapping + * @IOMMU_IOAS_MAP_READABLE: DMA is allowed to read from this mapping + */ +enum iommufd_ioas_map_flags { + IOMMU_IOAS_MAP_FIXED_IOVA = 1 << 0, + IOMMU_IOAS_MAP_WRITEABLE = 1 << 1, + IOMMU_IOAS_MAP_READABLE = 1 << 2, +}; + +/** + * struct iommu_ioas_map - ioctl(IOMMU_IOAS_MAP) + * @size: sizeof(struct iommu_ioas_map) + * @flags: Combination of enum iommufd_ioas_map_flags + * @ioas_id: IOAS ID to change the mapping of + * @__reserved: Must be 0 + * @user_va: Userspace pointer to start mapping from + * @length: Number of bytes to map + * @iova: IOVA the mapping was placed at. If IOMMU_IOAS_MAP_FIXED_IOVA is set + * then this must be provided as input. + * + * Set an IOVA mapping from a user pointer. If FIXED_IOVA is specified then the + * mapping will be established at iova, otherwise a suitable location based on + * the reserved and allowed lists will be automatically selected and returned in + * iova. + * + * If IOMMU_IOAS_MAP_FIXED_IOVA is specified then the iova range must currently + * be unused, existing IOVA cannot be replaced. + */ +struct iommu_ioas_map { + __u32 size; + __u32 flags; + __u32 ioas_id; + __u32 __reserved; + __aligned_u64 user_va; + __aligned_u64 length; + __aligned_u64 iova; +}; +#define IOMMU_IOAS_MAP _IO(IOMMUFD_TYPE, IOMMUFD_CMD_IOAS_MAP) + +/** + * struct iommu_ioas_copy - ioctl(IOMMU_IOAS_COPY) + * @size: sizeof(struct iommu_ioas_copy) + * @flags: Combination of enum iommufd_ioas_map_flags + * @dst_ioas_id: IOAS ID to change the mapping of + * @src_ioas_id: IOAS ID to copy from + * @length: Number of bytes to copy and map + * @dst_iova: IOVA the mapping was placed at. If IOMMU_IOAS_MAP_FIXED_IOVA is + * set then this must be provided as input. + * @src_iova: IOVA to start the copy + * + * Copy an already existing mapping from src_ioas_id and establish it in + * dst_ioas_id. The src iova/length must exactly match a range used with + * IOMMU_IOAS_MAP. + * + * This may be used to efficiently clone a subset of an IOAS to another, or as a + * kind of 'cache' to speed up mapping. Copy has an efficiency advantage over + * establishing equivalent new mappings, as internal resources are shared, and + * the kernel will pin the user memory only once. + */ +struct iommu_ioas_copy { + __u32 size; + __u32 flags; + __u32 dst_ioas_id; + __u32 src_ioas_id; + __aligned_u64 length; + __aligned_u64 dst_iova; + __aligned_u64 src_iova; +}; +#define IOMMU_IOAS_COPY _IO(IOMMUFD_TYPE, IOMMUFD_CMD_IOAS_COPY) + +/** + * struct iommu_ioas_unmap - ioctl(IOMMU_IOAS_UNMAP) + * @size: sizeof(struct iommu_ioas_unmap) + * @ioas_id: IOAS ID to change the mapping of + * @iova: IOVA to start the unmapping at + * @length: Number of bytes to unmap, and return back the bytes unmapped + * + * Unmap an IOVA range. The iova/length must be a superset of a previously + * mapped range used with IOMMU_IOAS_MAP or IOMMU_IOAS_COPY. Splitting or + * truncating ranges is not allowed. The values 0 to U64_MAX will unmap + * everything. + */ +struct iommu_ioas_unmap { + __u32 size; + __u32 ioas_id; + __aligned_u64 iova; + __aligned_u64 length; +}; +#define IOMMU_IOAS_UNMAP _IO(IOMMUFD_TYPE, IOMMUFD_CMD_IOAS_UNMAP) + +/** + * enum iommufd_option - ioctl(IOMMU_OPTION_RLIMIT_MODE) and + * ioctl(IOMMU_OPTION_HUGE_PAGES) + * @IOMMU_OPTION_RLIMIT_MODE: + * Change how RLIMIT_MEMLOCK accounting works. The caller must have privilege + * to invoke this. Value 0 (default) is user based accouting, 1 uses process + * based accounting. Global option, object_id must be 0 + * @IOMMU_OPTION_HUGE_PAGES: + * Value 1 (default) allows contiguous pages to be combined when generating + * iommu mappings. Value 0 disables combining, everything is mapped to + * PAGE_SIZE. This can be useful for benchmarking. This is a per-IOAS + * option, the object_id must be the IOAS ID. + */ +enum iommufd_option { + IOMMU_OPTION_RLIMIT_MODE = 0, + IOMMU_OPTION_HUGE_PAGES = 1, +}; + +/** + * enum iommufd_option_ops - ioctl(IOMMU_OPTION_OP_SET) and + * ioctl(IOMMU_OPTION_OP_GET) + * @IOMMU_OPTION_OP_SET: Set the option's value + * @IOMMU_OPTION_OP_GET: Get the option's value + */ +enum iommufd_option_ops { + IOMMU_OPTION_OP_SET = 0, + IOMMU_OPTION_OP_GET = 1, +}; + +/** + * struct iommu_option - iommu option multiplexer + * @size: sizeof(struct iommu_option) + * @option_id: One of enum iommufd_option + * @op: One of enum iommufd_option_ops + * @__reserved: Must be 0 + * @object_id: ID of the object if required + * @val64: Option value to set or value returned on get + * + * Change a simple option value. This multiplexor allows controlling options + * on objects. IOMMU_OPTION_OP_SET will load an option and IOMMU_OPTION_OP_GET + * will return the current value. + */ +struct iommu_option { + __u32 size; + __u32 option_id; + __u16 op; + __u16 __reserved; + __u32 object_id; + __aligned_u64 val64; +}; +#define IOMMU_OPTION _IO(IOMMUFD_TYPE, IOMMUFD_CMD_OPTION) + +/** + * enum iommufd_vfio_ioas_op - IOMMU_VFIO_IOAS_* ioctls + * @IOMMU_VFIO_IOAS_GET: Get the current compatibility IOAS + * @IOMMU_VFIO_IOAS_SET: Change the current compatibility IOAS + * @IOMMU_VFIO_IOAS_CLEAR: Disable VFIO compatibility + */ +enum iommufd_vfio_ioas_op { + IOMMU_VFIO_IOAS_GET = 0, + IOMMU_VFIO_IOAS_SET = 1, + IOMMU_VFIO_IOAS_CLEAR = 2, +}; + +/** + * struct iommu_vfio_ioas - ioctl(IOMMU_VFIO_IOAS) + * @size: sizeof(struct iommu_vfio_ioas) + * @ioas_id: For IOMMU_VFIO_IOAS_SET the input IOAS ID to set + * For IOMMU_VFIO_IOAS_GET will output the IOAS ID + * @op: One of enum iommufd_vfio_ioas_op + * @__reserved: Must be 0 + * + * The VFIO compatibility support uses a single ioas because VFIO APIs do not + * support the ID field. Set or Get the IOAS that VFIO compatibility will use. + * When VFIO_GROUP_SET_CONTAINER is used on an iommufd it will get the + * compatibility ioas, either by taking what is already set, or auto creating + * one. From then on VFIO will continue to use that ioas and is not effected by + * this ioctl. SET or CLEAR does not destroy any auto-created IOAS. + */ +struct iommu_vfio_ioas { + __u32 size; + __u32 ioas_id; + __u16 op; + __u16 __reserved; +}; +#define IOMMU_VFIO_IOAS _IO(IOMMUFD_TYPE, IOMMUFD_CMD_VFIO_IOAS) + +/** + * struct iommu_hwpt_alloc - ioctl(IOMMU_HWPT_ALLOC) + * @size: sizeof(struct iommu_hwpt_alloc) + * @flags: Must be 0 + * @dev_id: The device to allocate this HWPT for + * @pt_id: The IOAS to connect this HWPT to + * @out_hwpt_id: The ID of the new HWPT + * @__reserved: Must be 0 + * + * Explicitly allocate a hardware page table object. This is the same object + * type that is returned by iommufd_device_attach() and represents the + * underlying iommu driver's iommu_domain kernel object. + * + * A HWPT will be created with the IOVA mappings from the given IOAS. + */ +struct iommu_hwpt_alloc { + __u32 size; + __u32 flags; + __u32 dev_id; + __u32 pt_id; + __u32 out_hwpt_id; + __u32 __reserved; +}; +#define IOMMU_HWPT_ALLOC _IO(IOMMUFD_TYPE, IOMMUFD_CMD_HWPT_ALLOC) + +/** + * struct iommu_hw_info_vtd - Intel VT-d hardware information + * + * @flags: Must be 0 + * @__reserved: Must be 0 + * + * @cap_reg: Value of Intel VT-d capability register defined in VT-d spec + * section 11.4.2 Capability Register. + * @ecap_reg: Value of Intel VT-d capability register defined in VT-d spec + * section 11.4.3 Extended Capability Register. + * + * User needs to understand the Intel VT-d specification to decode the + * register value. + */ +struct iommu_hw_info_vtd { + __u32 flags; + __u32 __reserved; + __aligned_u64 cap_reg; + __aligned_u64 ecap_reg; +}; + +/** + * enum iommu_hw_info_type - IOMMU Hardware Info Types + * @IOMMU_HW_INFO_TYPE_NONE: Used by the drivers that do not report hardware + * info + * @IOMMU_HW_INFO_TYPE_INTEL_VTD: Intel VT-d iommu info type + */ +enum iommu_hw_info_type { + IOMMU_HW_INFO_TYPE_NONE, + IOMMU_HW_INFO_TYPE_INTEL_VTD, +}; + +/** + * struct iommu_hw_info - ioctl(IOMMU_GET_HW_INFO) + * @size: sizeof(struct iommu_hw_info) + * @flags: Must be 0 + * @dev_id: The device bound to the iommufd + * @data_len: Input the length of a user buffer in bytes. Output the length of + * data that kernel supports + * @data_uptr: User pointer to a user-space buffer used by the kernel to fill + * the iommu type specific hardware information data + * @out_data_type: Output the iommu hardware info type as defined in the enum + * iommu_hw_info_type. + * @__reserved: Must be 0 + * + * Query an iommu type specific hardware information data from an iommu behind + * a given device that has been bound to iommufd. This hardware info data will + * be used to sync capabilities between the virtual iommu and the physical + * iommu, e.g. a nested translation setup needs to check the hardware info, so + * a guest stage-1 page table can be compatible with the physical iommu. + * + * To capture an iommu type specific hardware information data, @data_uptr and + * its length @data_len must be provided. Trailing bytes will be zeroed if the + * user buffer is larger than the data that kernel has. Otherwise, kernel only + * fills the buffer using the given length in @data_len. If the ioctl succeeds, + * @data_len will be updated to the length that kernel actually supports, + * @out_data_type will be filled to decode the data filled in the buffer + * pointed by @data_uptr. Input @data_len == zero is allowed. + */ +struct iommu_hw_info { + __u32 size; + __u32 flags; + __u32 dev_id; + __u32 data_len; + __aligned_u64 data_uptr; + __u32 out_data_type; + __u32 __reserved; +}; +#define IOMMU_GET_HW_INFO _IO(IOMMUFD_TYPE, IOMMUFD_CMD_GET_HW_INFO) +#endif From 1e09f52f4d1f1775004c9c64bbef1f498a915758 Mon Sep 17 00:00:00 2001 From: Yi Liu Date: Mon, 9 Oct 2023 11:09:05 +0200 Subject: [PATCH 0762/1077] vfio/common: Move IOMMU agnostic helpers to a separate file MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Move low-level iommu agnostic helpers to a separate helpers.c file. They relate to regions, interrupts, device/region capabilities and etc. Signed-off-by: Eric Auger Signed-off-by: Yi Sun Signed-off-by: Yi Liu Signed-off-by: Zhenzhong Duan Reviewed-by: Cédric Le Goater Signed-off-by: Cédric Le Goater --- hw/vfio/common.c | 588 -------------------------------- hw/vfio/helpers.c | 612 ++++++++++++++++++++++++++++++++++ hw/vfio/meson.build | 1 + include/hw/vfio/vfio-common.h | 9 + 4 files changed, 622 insertions(+), 588 deletions(-) create mode 100644 hw/vfio/helpers.c diff --git a/hw/vfio/common.c b/hw/vfio/common.c index 134649226d..4e122fc4e4 100644 --- a/hw/vfio/common.c +++ b/hw/vfio/common.c @@ -62,84 +62,6 @@ static QLIST_HEAD(, VFIOAddressSpace) vfio_address_spaces = static int vfio_kvm_device_fd = -1; #endif -/* - * Common VFIO interrupt disable - */ -void vfio_disable_irqindex(VFIODevice *vbasedev, int index) -{ - struct vfio_irq_set irq_set = { - .argsz = sizeof(irq_set), - .flags = VFIO_IRQ_SET_DATA_NONE | VFIO_IRQ_SET_ACTION_TRIGGER, - .index = index, - .start = 0, - .count = 0, - }; - - ioctl(vbasedev->fd, VFIO_DEVICE_SET_IRQS, &irq_set); -} - -void vfio_unmask_single_irqindex(VFIODevice *vbasedev, int index) -{ - struct vfio_irq_set irq_set = { - .argsz = sizeof(irq_set), - .flags = VFIO_IRQ_SET_DATA_NONE | VFIO_IRQ_SET_ACTION_UNMASK, - .index = index, - .start = 0, - .count = 1, - }; - - ioctl(vbasedev->fd, VFIO_DEVICE_SET_IRQS, &irq_set); -} - -void vfio_mask_single_irqindex(VFIODevice *vbasedev, int index) -{ - struct vfio_irq_set irq_set = { - .argsz = sizeof(irq_set), - .flags = VFIO_IRQ_SET_DATA_NONE | VFIO_IRQ_SET_ACTION_MASK, - .index = index, - .start = 0, - .count = 1, - }; - - ioctl(vbasedev->fd, VFIO_DEVICE_SET_IRQS, &irq_set); -} - -static inline const char *action_to_str(int action) -{ - switch (action) { - case VFIO_IRQ_SET_ACTION_MASK: - return "MASK"; - case VFIO_IRQ_SET_ACTION_UNMASK: - return "UNMASK"; - case VFIO_IRQ_SET_ACTION_TRIGGER: - return "TRIGGER"; - default: - return "UNKNOWN ACTION"; - } -} - -static const char *index_to_str(VFIODevice *vbasedev, int index) -{ - if (vbasedev->type != VFIO_DEVICE_TYPE_PCI) { - return NULL; - } - - switch (index) { - case VFIO_PCI_INTX_IRQ_INDEX: - return "INTX"; - case VFIO_PCI_MSI_IRQ_INDEX: - return "MSI"; - case VFIO_PCI_MSIX_IRQ_INDEX: - return "MSIX"; - case VFIO_PCI_ERR_IRQ_INDEX: - return "ERR"; - case VFIO_PCI_REQ_IRQ_INDEX: - return "REQ"; - default: - return NULL; - } -} - static int vfio_ram_block_discard_disable(VFIOContainer *container, bool state) { switch (container->iommu_type) { @@ -163,183 +85,10 @@ static int vfio_ram_block_discard_disable(VFIOContainer *container, bool state) } } -int vfio_set_irq_signaling(VFIODevice *vbasedev, int index, int subindex, - int action, int fd, Error **errp) -{ - struct vfio_irq_set *irq_set; - int argsz, ret = 0; - const char *name; - int32_t *pfd; - - argsz = sizeof(*irq_set) + sizeof(*pfd); - - irq_set = g_malloc0(argsz); - irq_set->argsz = argsz; - irq_set->flags = VFIO_IRQ_SET_DATA_EVENTFD | action; - irq_set->index = index; - irq_set->start = subindex; - irq_set->count = 1; - pfd = (int32_t *)&irq_set->data; - *pfd = fd; - - if (ioctl(vbasedev->fd, VFIO_DEVICE_SET_IRQS, irq_set)) { - ret = -errno; - } - g_free(irq_set); - - if (!ret) { - return 0; - } - - error_setg_errno(errp, -ret, "VFIO_DEVICE_SET_IRQS failure"); - - name = index_to_str(vbasedev, index); - if (name) { - error_prepend(errp, "%s-%d: ", name, subindex); - } else { - error_prepend(errp, "index %d-%d: ", index, subindex); - } - error_prepend(errp, - "Failed to %s %s eventfd signaling for interrupt ", - fd < 0 ? "tear down" : "set up", action_to_str(action)); - return ret; -} - -/* - * IO Port/MMIO - Beware of the endians, VFIO is always little endian - */ -void vfio_region_write(void *opaque, hwaddr addr, - uint64_t data, unsigned size) -{ - VFIORegion *region = opaque; - VFIODevice *vbasedev = region->vbasedev; - union { - uint8_t byte; - uint16_t word; - uint32_t dword; - uint64_t qword; - } buf; - - switch (size) { - case 1: - buf.byte = data; - break; - case 2: - buf.word = cpu_to_le16(data); - break; - case 4: - buf.dword = cpu_to_le32(data); - break; - case 8: - buf.qword = cpu_to_le64(data); - break; - default: - hw_error("vfio: unsupported write size, %u bytes", size); - break; - } - - if (pwrite(vbasedev->fd, &buf, size, region->fd_offset + addr) != size) { - error_report("%s(%s:region%d+0x%"HWADDR_PRIx", 0x%"PRIx64 - ",%d) failed: %m", - __func__, vbasedev->name, region->nr, - addr, data, size); - } - - trace_vfio_region_write(vbasedev->name, region->nr, addr, data, size); - - /* - * A read or write to a BAR always signals an INTx EOI. This will - * do nothing if not pending (including not in INTx mode). We assume - * that a BAR access is in response to an interrupt and that BAR - * accesses will service the interrupt. Unfortunately, we don't know - * which access will service the interrupt, so we're potentially - * getting quite a few host interrupts per guest interrupt. - */ - vbasedev->ops->vfio_eoi(vbasedev); -} - -uint64_t vfio_region_read(void *opaque, - hwaddr addr, unsigned size) -{ - VFIORegion *region = opaque; - VFIODevice *vbasedev = region->vbasedev; - union { - uint8_t byte; - uint16_t word; - uint32_t dword; - uint64_t qword; - } buf; - uint64_t data = 0; - - if (pread(vbasedev->fd, &buf, size, region->fd_offset + addr) != size) { - error_report("%s(%s:region%d+0x%"HWADDR_PRIx", %d) failed: %m", - __func__, vbasedev->name, region->nr, - addr, size); - return (uint64_t)-1; - } - switch (size) { - case 1: - data = buf.byte; - break; - case 2: - data = le16_to_cpu(buf.word); - break; - case 4: - data = le32_to_cpu(buf.dword); - break; - case 8: - data = le64_to_cpu(buf.qword); - break; - default: - hw_error("vfio: unsupported read size, %u bytes", size); - break; - } - - trace_vfio_region_read(vbasedev->name, region->nr, addr, size, data); - - /* Same as write above */ - vbasedev->ops->vfio_eoi(vbasedev); - - return data; -} - -const MemoryRegionOps vfio_region_ops = { - .read = vfio_region_read, - .write = vfio_region_write, - .endianness = DEVICE_LITTLE_ENDIAN, - .valid = { - .min_access_size = 1, - .max_access_size = 8, - }, - .impl = { - .min_access_size = 1, - .max_access_size = 8, - }, -}; - /* * Device state interfaces */ -typedef struct { - unsigned long *bitmap; - hwaddr size; - hwaddr pages; -} VFIOBitmap; - -static int vfio_bitmap_alloc(VFIOBitmap *vbmap, hwaddr size) -{ - vbmap->pages = REAL_HOST_PAGE_ALIGN(size) / qemu_real_host_page_size(); - vbmap->size = ROUND_UP(vbmap->pages, sizeof(__u64) * BITS_PER_BYTE) / - BITS_PER_BYTE; - vbmap->bitmap = g_try_malloc0(vbmap->size); - if (!vbmap->bitmap) { - return -ENOMEM; - } - - return 0; -} - static int vfio_get_dirty_bitmap(VFIOContainer *container, uint64_t iova, uint64_t size, ram_addr_t ram_addr); @@ -1994,30 +1743,6 @@ static void vfio_listener_release(VFIOContainer *container) } } -static struct vfio_info_cap_header * -vfio_get_cap(void *ptr, uint32_t cap_offset, uint16_t id) -{ - struct vfio_info_cap_header *hdr; - - for (hdr = ptr + cap_offset; hdr != ptr; hdr = ptr + hdr->next) { - if (hdr->id == id) { - return hdr; - } - } - - return NULL; -} - -struct vfio_info_cap_header * -vfio_get_region_info_cap(struct vfio_region_info *info, uint16_t id) -{ - if (!(info->flags & VFIO_REGION_INFO_FLAG_CAPS)) { - return NULL; - } - - return vfio_get_cap((void *)info, info->cap_offset, id); -} - static struct vfio_info_cap_header * vfio_get_iommu_type1_info_cap(struct vfio_iommu_type1_info *info, uint16_t id) { @@ -2028,16 +1753,6 @@ vfio_get_iommu_type1_info_cap(struct vfio_iommu_type1_info *info, uint16_t id) return vfio_get_cap((void *)info, info->cap_offset, id); } -struct vfio_info_cap_header * -vfio_get_device_info_cap(struct vfio_device_info *info, uint16_t id) -{ - if (!(info->flags & VFIO_DEVICE_FLAGS_CAPS)) { - return NULL; - } - - return vfio_get_cap((void *)info, info->cap_offset, id); -} - bool vfio_get_info_dma_avail(struct vfio_iommu_type1_info *info, unsigned int *avail) { @@ -2059,232 +1774,6 @@ bool vfio_get_info_dma_avail(struct vfio_iommu_type1_info *info, return true; } -static int vfio_setup_region_sparse_mmaps(VFIORegion *region, - struct vfio_region_info *info) -{ - struct vfio_info_cap_header *hdr; - struct vfio_region_info_cap_sparse_mmap *sparse; - int i, j; - - hdr = vfio_get_region_info_cap(info, VFIO_REGION_INFO_CAP_SPARSE_MMAP); - if (!hdr) { - return -ENODEV; - } - - sparse = container_of(hdr, struct vfio_region_info_cap_sparse_mmap, header); - - trace_vfio_region_sparse_mmap_header(region->vbasedev->name, - region->nr, sparse->nr_areas); - - region->mmaps = g_new0(VFIOMmap, sparse->nr_areas); - - for (i = 0, j = 0; i < sparse->nr_areas; i++) { - if (sparse->areas[i].size) { - trace_vfio_region_sparse_mmap_entry(i, sparse->areas[i].offset, - sparse->areas[i].offset + - sparse->areas[i].size - 1); - region->mmaps[j].offset = sparse->areas[i].offset; - region->mmaps[j].size = sparse->areas[i].size; - j++; - } - } - - region->nr_mmaps = j; - region->mmaps = g_realloc(region->mmaps, j * sizeof(VFIOMmap)); - - return 0; -} - -int vfio_region_setup(Object *obj, VFIODevice *vbasedev, VFIORegion *region, - int index, const char *name) -{ - struct vfio_region_info *info; - int ret; - - ret = vfio_get_region_info(vbasedev, index, &info); - if (ret) { - return ret; - } - - region->vbasedev = vbasedev; - region->flags = info->flags; - region->size = info->size; - region->fd_offset = info->offset; - region->nr = index; - - if (region->size) { - region->mem = g_new0(MemoryRegion, 1); - memory_region_init_io(region->mem, obj, &vfio_region_ops, - region, name, region->size); - - if (!vbasedev->no_mmap && - region->flags & VFIO_REGION_INFO_FLAG_MMAP) { - - ret = vfio_setup_region_sparse_mmaps(region, info); - - if (ret) { - region->nr_mmaps = 1; - region->mmaps = g_new0(VFIOMmap, region->nr_mmaps); - region->mmaps[0].offset = 0; - region->mmaps[0].size = region->size; - } - } - } - - g_free(info); - - trace_vfio_region_setup(vbasedev->name, index, name, - region->flags, region->fd_offset, region->size); - return 0; -} - -static void vfio_subregion_unmap(VFIORegion *region, int index) -{ - trace_vfio_region_unmap(memory_region_name(®ion->mmaps[index].mem), - region->mmaps[index].offset, - region->mmaps[index].offset + - region->mmaps[index].size - 1); - memory_region_del_subregion(region->mem, ®ion->mmaps[index].mem); - munmap(region->mmaps[index].mmap, region->mmaps[index].size); - object_unparent(OBJECT(®ion->mmaps[index].mem)); - region->mmaps[index].mmap = NULL; -} - -int vfio_region_mmap(VFIORegion *region) -{ - int i, prot = 0; - char *name; - - if (!region->mem) { - return 0; - } - - prot |= region->flags & VFIO_REGION_INFO_FLAG_READ ? PROT_READ : 0; - prot |= region->flags & VFIO_REGION_INFO_FLAG_WRITE ? PROT_WRITE : 0; - - for (i = 0; i < region->nr_mmaps; i++) { - region->mmaps[i].mmap = mmap(NULL, region->mmaps[i].size, prot, - MAP_SHARED, region->vbasedev->fd, - region->fd_offset + - region->mmaps[i].offset); - if (region->mmaps[i].mmap == MAP_FAILED) { - int ret = -errno; - - trace_vfio_region_mmap_fault(memory_region_name(region->mem), i, - region->fd_offset + - region->mmaps[i].offset, - region->fd_offset + - region->mmaps[i].offset + - region->mmaps[i].size - 1, ret); - - region->mmaps[i].mmap = NULL; - - for (i--; i >= 0; i--) { - vfio_subregion_unmap(region, i); - } - - return ret; - } - - name = g_strdup_printf("%s mmaps[%d]", - memory_region_name(region->mem), i); - memory_region_init_ram_device_ptr(®ion->mmaps[i].mem, - memory_region_owner(region->mem), - name, region->mmaps[i].size, - region->mmaps[i].mmap); - g_free(name); - memory_region_add_subregion(region->mem, region->mmaps[i].offset, - ®ion->mmaps[i].mem); - - trace_vfio_region_mmap(memory_region_name(®ion->mmaps[i].mem), - region->mmaps[i].offset, - region->mmaps[i].offset + - region->mmaps[i].size - 1); - } - - return 0; -} - -void vfio_region_unmap(VFIORegion *region) -{ - int i; - - if (!region->mem) { - return; - } - - for (i = 0; i < region->nr_mmaps; i++) { - if (region->mmaps[i].mmap) { - vfio_subregion_unmap(region, i); - } - } -} - -void vfio_region_exit(VFIORegion *region) -{ - int i; - - if (!region->mem) { - return; - } - - for (i = 0; i < region->nr_mmaps; i++) { - if (region->mmaps[i].mmap) { - memory_region_del_subregion(region->mem, ®ion->mmaps[i].mem); - } - } - - trace_vfio_region_exit(region->vbasedev->name, region->nr); -} - -void vfio_region_finalize(VFIORegion *region) -{ - int i; - - if (!region->mem) { - return; - } - - for (i = 0; i < region->nr_mmaps; i++) { - if (region->mmaps[i].mmap) { - munmap(region->mmaps[i].mmap, region->mmaps[i].size); - object_unparent(OBJECT(®ion->mmaps[i].mem)); - } - } - - object_unparent(OBJECT(region->mem)); - - g_free(region->mem); - g_free(region->mmaps); - - trace_vfio_region_finalize(region->vbasedev->name, region->nr); - - region->mem = NULL; - region->mmaps = NULL; - region->nr_mmaps = 0; - region->size = 0; - region->flags = 0; - region->nr = 0; -} - -void vfio_region_mmaps_set_enabled(VFIORegion *region, bool enabled) -{ - int i; - - if (!region->mem) { - return; - } - - for (i = 0; i < region->nr_mmaps; i++) { - if (region->mmaps[i].mmap) { - memory_region_set_enabled(®ion->mmaps[i].mem, enabled); - } - } - - trace_vfio_region_mmaps_set_enabled(memory_region_name(region->mem), - enabled); -} - void vfio_reset_handler(void *opaque) { VFIOGroup *group; @@ -2983,83 +2472,6 @@ void vfio_put_base_device(VFIODevice *vbasedev) close(vbasedev->fd); } -int vfio_get_region_info(VFIODevice *vbasedev, int index, - struct vfio_region_info **info) -{ - size_t argsz = sizeof(struct vfio_region_info); - - *info = g_malloc0(argsz); - - (*info)->index = index; -retry: - (*info)->argsz = argsz; - - if (ioctl(vbasedev->fd, VFIO_DEVICE_GET_REGION_INFO, *info)) { - g_free(*info); - *info = NULL; - return -errno; - } - - if ((*info)->argsz > argsz) { - argsz = (*info)->argsz; - *info = g_realloc(*info, argsz); - - goto retry; - } - - return 0; -} - -int vfio_get_dev_region_info(VFIODevice *vbasedev, uint32_t type, - uint32_t subtype, struct vfio_region_info **info) -{ - int i; - - for (i = 0; i < vbasedev->num_regions; i++) { - struct vfio_info_cap_header *hdr; - struct vfio_region_info_cap_type *cap_type; - - if (vfio_get_region_info(vbasedev, i, info)) { - continue; - } - - hdr = vfio_get_region_info_cap(*info, VFIO_REGION_INFO_CAP_TYPE); - if (!hdr) { - g_free(*info); - continue; - } - - cap_type = container_of(hdr, struct vfio_region_info_cap_type, header); - - trace_vfio_get_dev_region(vbasedev->name, i, - cap_type->type, cap_type->subtype); - - if (cap_type->type == type && cap_type->subtype == subtype) { - return 0; - } - - g_free(*info); - } - - *info = NULL; - return -ENODEV; -} - -bool vfio_has_region_cap(VFIODevice *vbasedev, int region, uint16_t cap_type) -{ - struct vfio_region_info *info = NULL; - bool ret = false; - - if (!vfio_get_region_info(vbasedev, region, &info)) { - if (vfio_get_region_info_cap(info, cap_type)) { - ret = true; - } - g_free(info); - } - - return ret; -} - /* * Interfaces for IBM EEH (Enhanced Error Handling) */ diff --git a/hw/vfio/helpers.c b/hw/vfio/helpers.c new file mode 100644 index 0000000000..7e5da21b31 --- /dev/null +++ b/hw/vfio/helpers.c @@ -0,0 +1,612 @@ +/* + * low level and IOMMU backend agnostic helpers used by VFIO devices, + * related to regions, interrupts, capabilities + * + * Copyright Red Hat, Inc. 2012 + * + * Authors: + * Alex Williamson + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + * + * Based on qemu-kvm device-assignment: + * Adapted for KVM by Qumranet. + * Copyright (c) 2007, Neocleus, Alex Novik (alex@neocleus.com) + * Copyright (c) 2007, Neocleus, Guy Zana (guy@neocleus.com) + * Copyright (C) 2008, Qumranet, Amit Shah (amit.shah@qumranet.com) + * Copyright (C) 2008, Red Hat, Amit Shah (amit.shah@redhat.com) + * Copyright (C) 2008, IBM, Muli Ben-Yehuda (muli@il.ibm.com) + */ + +#include "qemu/osdep.h" +#include + +#include "hw/vfio/vfio-common.h" +#include "hw/vfio/vfio.h" +#include "hw/hw.h" +#include "trace.h" +#include "qapi/error.h" +#include "qemu/error-report.h" + +/* + * Common VFIO interrupt disable + */ +void vfio_disable_irqindex(VFIODevice *vbasedev, int index) +{ + struct vfio_irq_set irq_set = { + .argsz = sizeof(irq_set), + .flags = VFIO_IRQ_SET_DATA_NONE | VFIO_IRQ_SET_ACTION_TRIGGER, + .index = index, + .start = 0, + .count = 0, + }; + + ioctl(vbasedev->fd, VFIO_DEVICE_SET_IRQS, &irq_set); +} + +void vfio_unmask_single_irqindex(VFIODevice *vbasedev, int index) +{ + struct vfio_irq_set irq_set = { + .argsz = sizeof(irq_set), + .flags = VFIO_IRQ_SET_DATA_NONE | VFIO_IRQ_SET_ACTION_UNMASK, + .index = index, + .start = 0, + .count = 1, + }; + + ioctl(vbasedev->fd, VFIO_DEVICE_SET_IRQS, &irq_set); +} + +void vfio_mask_single_irqindex(VFIODevice *vbasedev, int index) +{ + struct vfio_irq_set irq_set = { + .argsz = sizeof(irq_set), + .flags = VFIO_IRQ_SET_DATA_NONE | VFIO_IRQ_SET_ACTION_MASK, + .index = index, + .start = 0, + .count = 1, + }; + + ioctl(vbasedev->fd, VFIO_DEVICE_SET_IRQS, &irq_set); +} + +static inline const char *action_to_str(int action) +{ + switch (action) { + case VFIO_IRQ_SET_ACTION_MASK: + return "MASK"; + case VFIO_IRQ_SET_ACTION_UNMASK: + return "UNMASK"; + case VFIO_IRQ_SET_ACTION_TRIGGER: + return "TRIGGER"; + default: + return "UNKNOWN ACTION"; + } +} + +static const char *index_to_str(VFIODevice *vbasedev, int index) +{ + if (vbasedev->type != VFIO_DEVICE_TYPE_PCI) { + return NULL; + } + + switch (index) { + case VFIO_PCI_INTX_IRQ_INDEX: + return "INTX"; + case VFIO_PCI_MSI_IRQ_INDEX: + return "MSI"; + case VFIO_PCI_MSIX_IRQ_INDEX: + return "MSIX"; + case VFIO_PCI_ERR_IRQ_INDEX: + return "ERR"; + case VFIO_PCI_REQ_IRQ_INDEX: + return "REQ"; + default: + return NULL; + } +} + +int vfio_set_irq_signaling(VFIODevice *vbasedev, int index, int subindex, + int action, int fd, Error **errp) +{ + struct vfio_irq_set *irq_set; + int argsz, ret = 0; + const char *name; + int32_t *pfd; + + argsz = sizeof(*irq_set) + sizeof(*pfd); + + irq_set = g_malloc0(argsz); + irq_set->argsz = argsz; + irq_set->flags = VFIO_IRQ_SET_DATA_EVENTFD | action; + irq_set->index = index; + irq_set->start = subindex; + irq_set->count = 1; + pfd = (int32_t *)&irq_set->data; + *pfd = fd; + + if (ioctl(vbasedev->fd, VFIO_DEVICE_SET_IRQS, irq_set)) { + ret = -errno; + } + g_free(irq_set); + + if (!ret) { + return 0; + } + + error_setg_errno(errp, -ret, "VFIO_DEVICE_SET_IRQS failure"); + + name = index_to_str(vbasedev, index); + if (name) { + error_prepend(errp, "%s-%d: ", name, subindex); + } else { + error_prepend(errp, "index %d-%d: ", index, subindex); + } + error_prepend(errp, + "Failed to %s %s eventfd signaling for interrupt ", + fd < 0 ? "tear down" : "set up", action_to_str(action)); + return ret; +} + +/* + * IO Port/MMIO - Beware of the endians, VFIO is always little endian + */ +void vfio_region_write(void *opaque, hwaddr addr, + uint64_t data, unsigned size) +{ + VFIORegion *region = opaque; + VFIODevice *vbasedev = region->vbasedev; + union { + uint8_t byte; + uint16_t word; + uint32_t dword; + uint64_t qword; + } buf; + + switch (size) { + case 1: + buf.byte = data; + break; + case 2: + buf.word = cpu_to_le16(data); + break; + case 4: + buf.dword = cpu_to_le32(data); + break; + case 8: + buf.qword = cpu_to_le64(data); + break; + default: + hw_error("vfio: unsupported write size, %u bytes", size); + break; + } + + if (pwrite(vbasedev->fd, &buf, size, region->fd_offset + addr) != size) { + error_report("%s(%s:region%d+0x%"HWADDR_PRIx", 0x%"PRIx64 + ",%d) failed: %m", + __func__, vbasedev->name, region->nr, + addr, data, size); + } + + trace_vfio_region_write(vbasedev->name, region->nr, addr, data, size); + + /* + * A read or write to a BAR always signals an INTx EOI. This will + * do nothing if not pending (including not in INTx mode). We assume + * that a BAR access is in response to an interrupt and that BAR + * accesses will service the interrupt. Unfortunately, we don't know + * which access will service the interrupt, so we're potentially + * getting quite a few host interrupts per guest interrupt. + */ + vbasedev->ops->vfio_eoi(vbasedev); +} + +uint64_t vfio_region_read(void *opaque, + hwaddr addr, unsigned size) +{ + VFIORegion *region = opaque; + VFIODevice *vbasedev = region->vbasedev; + union { + uint8_t byte; + uint16_t word; + uint32_t dword; + uint64_t qword; + } buf; + uint64_t data = 0; + + if (pread(vbasedev->fd, &buf, size, region->fd_offset + addr) != size) { + error_report("%s(%s:region%d+0x%"HWADDR_PRIx", %d) failed: %m", + __func__, vbasedev->name, region->nr, + addr, size); + return (uint64_t)-1; + } + switch (size) { + case 1: + data = buf.byte; + break; + case 2: + data = le16_to_cpu(buf.word); + break; + case 4: + data = le32_to_cpu(buf.dword); + break; + case 8: + data = le64_to_cpu(buf.qword); + break; + default: + hw_error("vfio: unsupported read size, %u bytes", size); + break; + } + + trace_vfio_region_read(vbasedev->name, region->nr, addr, size, data); + + /* Same as write above */ + vbasedev->ops->vfio_eoi(vbasedev); + + return data; +} + +const MemoryRegionOps vfio_region_ops = { + .read = vfio_region_read, + .write = vfio_region_write, + .endianness = DEVICE_LITTLE_ENDIAN, + .valid = { + .min_access_size = 1, + .max_access_size = 8, + }, + .impl = { + .min_access_size = 1, + .max_access_size = 8, + }, +}; + +int vfio_bitmap_alloc(VFIOBitmap *vbmap, hwaddr size) +{ + vbmap->pages = REAL_HOST_PAGE_ALIGN(size) / qemu_real_host_page_size(); + vbmap->size = ROUND_UP(vbmap->pages, sizeof(__u64) * BITS_PER_BYTE) / + BITS_PER_BYTE; + vbmap->bitmap = g_try_malloc0(vbmap->size); + if (!vbmap->bitmap) { + return -ENOMEM; + } + + return 0; +} + +struct vfio_info_cap_header * +vfio_get_cap(void *ptr, uint32_t cap_offset, uint16_t id) +{ + struct vfio_info_cap_header *hdr; + + for (hdr = ptr + cap_offset; hdr != ptr; hdr = ptr + hdr->next) { + if (hdr->id == id) { + return hdr; + } + } + + return NULL; +} + +struct vfio_info_cap_header * +vfio_get_region_info_cap(struct vfio_region_info *info, uint16_t id) +{ + if (!(info->flags & VFIO_REGION_INFO_FLAG_CAPS)) { + return NULL; + } + + return vfio_get_cap((void *)info, info->cap_offset, id); +} + +struct vfio_info_cap_header * +vfio_get_device_info_cap(struct vfio_device_info *info, uint16_t id) +{ + if (!(info->flags & VFIO_DEVICE_FLAGS_CAPS)) { + return NULL; + } + + return vfio_get_cap((void *)info, info->cap_offset, id); +} + +static int vfio_setup_region_sparse_mmaps(VFIORegion *region, + struct vfio_region_info *info) +{ + struct vfio_info_cap_header *hdr; + struct vfio_region_info_cap_sparse_mmap *sparse; + int i, j; + + hdr = vfio_get_region_info_cap(info, VFIO_REGION_INFO_CAP_SPARSE_MMAP); + if (!hdr) { + return -ENODEV; + } + + sparse = container_of(hdr, struct vfio_region_info_cap_sparse_mmap, header); + + trace_vfio_region_sparse_mmap_header(region->vbasedev->name, + region->nr, sparse->nr_areas); + + region->mmaps = g_new0(VFIOMmap, sparse->nr_areas); + + for (i = 0, j = 0; i < sparse->nr_areas; i++) { + if (sparse->areas[i].size) { + trace_vfio_region_sparse_mmap_entry(i, sparse->areas[i].offset, + sparse->areas[i].offset + + sparse->areas[i].size - 1); + region->mmaps[j].offset = sparse->areas[i].offset; + region->mmaps[j].size = sparse->areas[i].size; + j++; + } + } + + region->nr_mmaps = j; + region->mmaps = g_realloc(region->mmaps, j * sizeof(VFIOMmap)); + + return 0; +} + +int vfio_region_setup(Object *obj, VFIODevice *vbasedev, VFIORegion *region, + int index, const char *name) +{ + struct vfio_region_info *info; + int ret; + + ret = vfio_get_region_info(vbasedev, index, &info); + if (ret) { + return ret; + } + + region->vbasedev = vbasedev; + region->flags = info->flags; + region->size = info->size; + region->fd_offset = info->offset; + region->nr = index; + + if (region->size) { + region->mem = g_new0(MemoryRegion, 1); + memory_region_init_io(region->mem, obj, &vfio_region_ops, + region, name, region->size); + + if (!vbasedev->no_mmap && + region->flags & VFIO_REGION_INFO_FLAG_MMAP) { + + ret = vfio_setup_region_sparse_mmaps(region, info); + + if (ret) { + region->nr_mmaps = 1; + region->mmaps = g_new0(VFIOMmap, region->nr_mmaps); + region->mmaps[0].offset = 0; + region->mmaps[0].size = region->size; + } + } + } + + g_free(info); + + trace_vfio_region_setup(vbasedev->name, index, name, + region->flags, region->fd_offset, region->size); + return 0; +} + +static void vfio_subregion_unmap(VFIORegion *region, int index) +{ + trace_vfio_region_unmap(memory_region_name(®ion->mmaps[index].mem), + region->mmaps[index].offset, + region->mmaps[index].offset + + region->mmaps[index].size - 1); + memory_region_del_subregion(region->mem, ®ion->mmaps[index].mem); + munmap(region->mmaps[index].mmap, region->mmaps[index].size); + object_unparent(OBJECT(®ion->mmaps[index].mem)); + region->mmaps[index].mmap = NULL; +} + +int vfio_region_mmap(VFIORegion *region) +{ + int i, prot = 0; + char *name; + + if (!region->mem) { + return 0; + } + + prot |= region->flags & VFIO_REGION_INFO_FLAG_READ ? PROT_READ : 0; + prot |= region->flags & VFIO_REGION_INFO_FLAG_WRITE ? PROT_WRITE : 0; + + for (i = 0; i < region->nr_mmaps; i++) { + region->mmaps[i].mmap = mmap(NULL, region->mmaps[i].size, prot, + MAP_SHARED, region->vbasedev->fd, + region->fd_offset + + region->mmaps[i].offset); + if (region->mmaps[i].mmap == MAP_FAILED) { + int ret = -errno; + + trace_vfio_region_mmap_fault(memory_region_name(region->mem), i, + region->fd_offset + + region->mmaps[i].offset, + region->fd_offset + + region->mmaps[i].offset + + region->mmaps[i].size - 1, ret); + + region->mmaps[i].mmap = NULL; + + for (i--; i >= 0; i--) { + vfio_subregion_unmap(region, i); + } + + return ret; + } + + name = g_strdup_printf("%s mmaps[%d]", + memory_region_name(region->mem), i); + memory_region_init_ram_device_ptr(®ion->mmaps[i].mem, + memory_region_owner(region->mem), + name, region->mmaps[i].size, + region->mmaps[i].mmap); + g_free(name); + memory_region_add_subregion(region->mem, region->mmaps[i].offset, + ®ion->mmaps[i].mem); + + trace_vfio_region_mmap(memory_region_name(®ion->mmaps[i].mem), + region->mmaps[i].offset, + region->mmaps[i].offset + + region->mmaps[i].size - 1); + } + + return 0; +} + +void vfio_region_unmap(VFIORegion *region) +{ + int i; + + if (!region->mem) { + return; + } + + for (i = 0; i < region->nr_mmaps; i++) { + if (region->mmaps[i].mmap) { + vfio_subregion_unmap(region, i); + } + } +} + +void vfio_region_exit(VFIORegion *region) +{ + int i; + + if (!region->mem) { + return; + } + + for (i = 0; i < region->nr_mmaps; i++) { + if (region->mmaps[i].mmap) { + memory_region_del_subregion(region->mem, ®ion->mmaps[i].mem); + } + } + + trace_vfio_region_exit(region->vbasedev->name, region->nr); +} + +void vfio_region_finalize(VFIORegion *region) +{ + int i; + + if (!region->mem) { + return; + } + + for (i = 0; i < region->nr_mmaps; i++) { + if (region->mmaps[i].mmap) { + munmap(region->mmaps[i].mmap, region->mmaps[i].size); + object_unparent(OBJECT(®ion->mmaps[i].mem)); + } + } + + object_unparent(OBJECT(region->mem)); + + g_free(region->mem); + g_free(region->mmaps); + + trace_vfio_region_finalize(region->vbasedev->name, region->nr); + + region->mem = NULL; + region->mmaps = NULL; + region->nr_mmaps = 0; + region->size = 0; + region->flags = 0; + region->nr = 0; +} + +void vfio_region_mmaps_set_enabled(VFIORegion *region, bool enabled) +{ + int i; + + if (!region->mem) { + return; + } + + for (i = 0; i < region->nr_mmaps; i++) { + if (region->mmaps[i].mmap) { + memory_region_set_enabled(®ion->mmaps[i].mem, enabled); + } + } + + trace_vfio_region_mmaps_set_enabled(memory_region_name(region->mem), + enabled); +} + +int vfio_get_region_info(VFIODevice *vbasedev, int index, + struct vfio_region_info **info) +{ + size_t argsz = sizeof(struct vfio_region_info); + + *info = g_malloc0(argsz); + + (*info)->index = index; +retry: + (*info)->argsz = argsz; + + if (ioctl(vbasedev->fd, VFIO_DEVICE_GET_REGION_INFO, *info)) { + g_free(*info); + *info = NULL; + return -errno; + } + + if ((*info)->argsz > argsz) { + argsz = (*info)->argsz; + *info = g_realloc(*info, argsz); + + goto retry; + } + + return 0; +} + +int vfio_get_dev_region_info(VFIODevice *vbasedev, uint32_t type, + uint32_t subtype, struct vfio_region_info **info) +{ + int i; + + for (i = 0; i < vbasedev->num_regions; i++) { + struct vfio_info_cap_header *hdr; + struct vfio_region_info_cap_type *cap_type; + + if (vfio_get_region_info(vbasedev, i, info)) { + continue; + } + + hdr = vfio_get_region_info_cap(*info, VFIO_REGION_INFO_CAP_TYPE); + if (!hdr) { + g_free(*info); + continue; + } + + cap_type = container_of(hdr, struct vfio_region_info_cap_type, header); + + trace_vfio_get_dev_region(vbasedev->name, i, + cap_type->type, cap_type->subtype); + + if (cap_type->type == type && cap_type->subtype == subtype) { + return 0; + } + + g_free(*info); + } + + *info = NULL; + return -ENODEV; +} + +bool vfio_has_region_cap(VFIODevice *vbasedev, int region, uint16_t cap_type) +{ + struct vfio_region_info *info = NULL; + bool ret = false; + + if (!vfio_get_region_info(vbasedev, region, &info)) { + if (vfio_get_region_info_cap(info, cap_type)) { + ret = true; + } + g_free(info); + } + + return ret; +} diff --git a/hw/vfio/meson.build b/hw/vfio/meson.build index da9af297a0..3746c9f984 100644 --- a/hw/vfio/meson.build +++ b/hw/vfio/meson.build @@ -1,5 +1,6 @@ vfio_ss = ss.source_set() vfio_ss.add(files( + 'helpers.c', 'common.c', 'spapr.c', 'migration.c', diff --git a/include/hw/vfio/vfio-common.h b/include/hw/vfio/vfio-common.h index e9b8954595..e0483893d1 100644 --- a/include/hw/vfio/vfio-common.h +++ b/include/hw/vfio/vfio-common.h @@ -196,6 +196,12 @@ typedef struct VFIODisplay { } dmabuf; } VFIODisplay; +typedef struct { + unsigned long *bitmap; + hwaddr size; + hwaddr pages; +} VFIOBitmap; + void vfio_put_base_device(VFIODevice *vbasedev); void vfio_disable_irqindex(VFIODevice *vbasedev, int index); void vfio_unmask_single_irqindex(VFIODevice *vbasedev, int index); @@ -245,6 +251,8 @@ bool vfio_get_info_dma_avail(struct vfio_iommu_type1_info *info, unsigned int *avail); struct vfio_info_cap_header * vfio_get_device_info_cap(struct vfio_device_info *info, uint16_t id); +struct vfio_info_cap_header * +vfio_get_cap(void *ptr, uint32_t cap_offset, uint16_t id); #endif extern const MemoryListener vfio_prereg_listener; @@ -257,4 +265,5 @@ int vfio_spapr_remove_window(VFIOContainer *container, bool vfio_migration_realize(VFIODevice *vbasedev, Error **errp); void vfio_migration_exit(VFIODevice *vbasedev); +int vfio_bitmap_alloc(VFIOBitmap *vbmap, hwaddr size); #endif /* HW_VFIO_VFIO_COMMON_H */ From 77c212599d3851ebaaff435013f571f6870a00b1 Mon Sep 17 00:00:00 2001 From: Eric Auger Date: Mon, 9 Oct 2023 11:09:06 +0200 Subject: [PATCH 0763/1077] vfio/common: Propagate KVM_SET_DEVICE_ATTR error if any MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In the VFIO_SPAPR_TCE_v2_IOMMU container case, when KVM_SET_DEVICE_ATTR fails, we currently don't propagate the error as we do on the vfio_spapr_create_window() failure case. Let's align the code. Take the opportunity to reword the error message and make it more explicit. Signed-off-by: Eric Auger Reviewed-by: Cédric Le Goater Signed-off-by: Cédric Le Goater --- hw/vfio/common.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/hw/vfio/common.c b/hw/vfio/common.c index 4e122fc4e4..c54a72ec80 100644 --- a/hw/vfio/common.c +++ b/hw/vfio/common.c @@ -878,11 +878,11 @@ static void vfio_listener_region_add(MemoryListener *listener, QLIST_FOREACH(group, &container->group_list, container_next) { param.groupfd = group->fd; if (ioctl(vfio_kvm_device_fd, KVM_SET_DEVICE_ATTR, &attr)) { - error_report("vfio: failed to setup fd %d " - "for a group with fd %d: %s", - param.tablefd, param.groupfd, - strerror(errno)); - return; + error_setg_errno(&err, errno, + "vfio: failed GROUP_SET_SPAPR_TCE for " + "KVM VFIO device %d and group fd %d", + param.tablefd, param.groupfd); + goto fail; } trace_vfio_spapr_group_attach(param.groupfd, param.tablefd); } From a33832b1948561bb2606371de0c5e2ef03921d93 Mon Sep 17 00:00:00 2001 From: Eric Auger Date: Mon, 9 Oct 2023 11:09:07 +0200 Subject: [PATCH 0764/1077] vfio/common: Introduce vfio_container_add|del_section_window() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Introduce helper functions that isolate the code used for VFIO_SPAPR_TCE_v2_IOMMU. Those helpers hide implementation details beneath the container object and make the vfio_listener_region_add/del() implementations more readable. No code change intended. Signed-off-by: Eric Auger Signed-off-by: Yi Liu Signed-off-by: Zhenzhong Duan Reviewed-by: Cédric Le Goater Signed-off-by: Cédric Le Goater --- hw/vfio/common.c | 156 +++++++++++++++++++++++++++-------------------- 1 file changed, 89 insertions(+), 67 deletions(-) diff --git a/hw/vfio/common.c b/hw/vfio/common.c index c54a72ec80..0397788aa5 100644 --- a/hw/vfio/common.c +++ b/hw/vfio/common.c @@ -807,6 +807,92 @@ static bool vfio_get_section_iova_range(VFIOContainer *container, return true; } +static int vfio_container_add_section_window(VFIOContainer *container, + MemoryRegionSection *section, + Error **errp) +{ + VFIOHostDMAWindow *hostwin; + hwaddr pgsize = 0; + int ret; + + if (container->iommu_type != VFIO_SPAPR_TCE_v2_IOMMU) { + return 0; + } + + /* For now intersections are not allowed, we may relax this later */ + QLIST_FOREACH(hostwin, &container->hostwin_list, hostwin_next) { + if (ranges_overlap(hostwin->min_iova, + hostwin->max_iova - hostwin->min_iova + 1, + section->offset_within_address_space, + int128_get64(section->size))) { + error_setg(errp, + "region [0x%"PRIx64",0x%"PRIx64"] overlaps with existing" + "host DMA window [0x%"PRIx64",0x%"PRIx64"]", + section->offset_within_address_space, + section->offset_within_address_space + + int128_get64(section->size) - 1, + hostwin->min_iova, hostwin->max_iova); + return -EINVAL; + } + } + + ret = vfio_spapr_create_window(container, section, &pgsize); + if (ret) { + error_setg_errno(errp, -ret, "Failed to create SPAPR window"); + return ret; + } + + vfio_host_win_add(container, section->offset_within_address_space, + section->offset_within_address_space + + int128_get64(section->size) - 1, pgsize); +#ifdef CONFIG_KVM + if (kvm_enabled()) { + VFIOGroup *group; + IOMMUMemoryRegion *iommu_mr = IOMMU_MEMORY_REGION(section->mr); + struct kvm_vfio_spapr_tce param; + struct kvm_device_attr attr = { + .group = KVM_DEV_VFIO_GROUP, + .attr = KVM_DEV_VFIO_GROUP_SET_SPAPR_TCE, + .addr = (uint64_t)(unsigned long)¶m, + }; + + if (!memory_region_iommu_get_attr(iommu_mr, IOMMU_ATTR_SPAPR_TCE_FD, + ¶m.tablefd)) { + QLIST_FOREACH(group, &container->group_list, container_next) { + param.groupfd = group->fd; + if (ioctl(vfio_kvm_device_fd, KVM_SET_DEVICE_ATTR, &attr)) { + error_setg_errno(errp, errno, + "vfio: failed GROUP_SET_SPAPR_TCE for " + "KVM VFIO device %d and group fd %d", + param.tablefd, param.groupfd); + return -errno; + } + trace_vfio_spapr_group_attach(param.groupfd, param.tablefd); + } + } + } +#endif + return 0; +} + +static void vfio_container_del_section_window(VFIOContainer *container, + MemoryRegionSection *section) +{ + if (container->iommu_type != VFIO_SPAPR_TCE_v2_IOMMU) { + return; + } + + vfio_spapr_remove_window(container, + section->offset_within_address_space); + if (vfio_host_win_del(container, + section->offset_within_address_space, + section->offset_within_address_space + + int128_get64(section->size) - 1) < 0) { + hw_error("%s: Cannot delete missing window at %"HWADDR_PRIx, + __func__, section->offset_within_address_space); + } +} + static void vfio_listener_region_add(MemoryListener *listener, MemoryRegionSection *section) { @@ -833,62 +919,8 @@ static void vfio_listener_region_add(MemoryListener *listener, return; } - if (container->iommu_type == VFIO_SPAPR_TCE_v2_IOMMU) { - hwaddr pgsize = 0; - - /* For now intersections are not allowed, we may relax this later */ - QLIST_FOREACH(hostwin, &container->hostwin_list, hostwin_next) { - if (ranges_overlap(hostwin->min_iova, - hostwin->max_iova - hostwin->min_iova + 1, - section->offset_within_address_space, - int128_get64(section->size))) { - error_setg(&err, - "region [0x%"PRIx64",0x%"PRIx64"] overlaps with existing" - "host DMA window [0x%"PRIx64",0x%"PRIx64"]", - section->offset_within_address_space, - section->offset_within_address_space + - int128_get64(section->size) - 1, - hostwin->min_iova, hostwin->max_iova); - goto fail; - } - } - - ret = vfio_spapr_create_window(container, section, &pgsize); - if (ret) { - error_setg_errno(&err, -ret, "Failed to create SPAPR window"); - goto fail; - } - - vfio_host_win_add(container, section->offset_within_address_space, - section->offset_within_address_space + - int128_get64(section->size) - 1, pgsize); -#ifdef CONFIG_KVM - if (kvm_enabled()) { - VFIOGroup *group; - IOMMUMemoryRegion *iommu_mr = IOMMU_MEMORY_REGION(section->mr); - struct kvm_vfio_spapr_tce param; - struct kvm_device_attr attr = { - .group = KVM_DEV_VFIO_GROUP, - .attr = KVM_DEV_VFIO_GROUP_SET_SPAPR_TCE, - .addr = (uint64_t)(unsigned long)¶m, - }; - - if (!memory_region_iommu_get_attr(iommu_mr, IOMMU_ATTR_SPAPR_TCE_FD, - ¶m.tablefd)) { - QLIST_FOREACH(group, &container->group_list, container_next) { - param.groupfd = group->fd; - if (ioctl(vfio_kvm_device_fd, KVM_SET_DEVICE_ATTR, &attr)) { - error_setg_errno(&err, errno, - "vfio: failed GROUP_SET_SPAPR_TCE for " - "KVM VFIO device %d and group fd %d", - param.tablefd, param.groupfd); - goto fail; - } - trace_vfio_spapr_group_attach(param.groupfd, param.tablefd); - } - } - } -#endif + if (vfio_container_add_section_window(container, section, &err)) { + goto fail; } hostwin = vfio_find_hostwin(container, iova, end); @@ -1105,17 +1137,7 @@ static void vfio_listener_region_del(MemoryListener *listener, memory_region_unref(section->mr); - if (container->iommu_type == VFIO_SPAPR_TCE_v2_IOMMU) { - vfio_spapr_remove_window(container, - section->offset_within_address_space); - if (vfio_host_win_del(container, - section->offset_within_address_space, - section->offset_within_address_space + - int128_get64(section->size) - 1) < 0) { - hw_error("%s: Cannot delete missing window at %"HWADDR_PRIx, - __func__, section->offset_within_address_space); - } - } + vfio_container_del_section_window(container, section); } static int vfio_set_dirty_page_tracking(VFIOContainer *container, bool start) From 5621c02d5adf3841884bb751ec8cf43d931aaa25 Mon Sep 17 00:00:00 2001 From: Zhenzhong Duan Date: Mon, 9 Oct 2023 11:09:08 +0200 Subject: [PATCH 0765/1077] vfio/common: Extract out vfio_kvm_device_[add/del]_fd MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Introduce two new helpers, vfio_kvm_device_[add/del]_fd which take as input a file descriptor which can be either a group fd or a cdev fd. This uses the new KVM_DEV_VFIO_FILE VFIO KVM device group, which aliases to the legacy KVM_DEV_VFIO_GROUP. vfio_kvm_device_[add/del]_group then call those new helpers. Signed-off-by: Yi Liu Signed-off-by: Zhenzhong Duan Reviewed-by: Eric Auger Signed-off-by: Cédric Le Goater --- hw/vfio/common.c | 69 +++++++++++++++++++++++------------ include/hw/vfio/vfio-common.h | 3 ++ 2 files changed, 49 insertions(+), 23 deletions(-) diff --git a/hw/vfio/common.c b/hw/vfio/common.c index 0397788aa5..d8ed432cb6 100644 --- a/hw/vfio/common.c +++ b/hw/vfio/common.c @@ -1818,17 +1818,17 @@ void vfio_reset_handler(void *opaque) } } -static void vfio_kvm_device_add_group(VFIOGroup *group) +int vfio_kvm_device_add_fd(int fd, Error **errp) { #ifdef CONFIG_KVM struct kvm_device_attr attr = { - .group = KVM_DEV_VFIO_GROUP, - .attr = KVM_DEV_VFIO_GROUP_ADD, - .addr = (uint64_t)(unsigned long)&group->fd, + .group = KVM_DEV_VFIO_FILE, + .attr = KVM_DEV_VFIO_FILE_ADD, + .addr = (uint64_t)(unsigned long)&fd, }; if (!kvm_enabled()) { - return; + return 0; } if (vfio_kvm_device_fd < 0) { @@ -1837,38 +1837,61 @@ static void vfio_kvm_device_add_group(VFIOGroup *group) }; if (kvm_vm_ioctl(kvm_state, KVM_CREATE_DEVICE, &cd)) { - error_report("Failed to create KVM VFIO device: %m"); - return; + error_setg_errno(errp, errno, "Failed to create KVM VFIO device"); + return -errno; } vfio_kvm_device_fd = cd.fd; } if (ioctl(vfio_kvm_device_fd, KVM_SET_DEVICE_ATTR, &attr)) { - error_report("Failed to add group %d to KVM VFIO device: %m", - group->groupid); + error_setg_errno(errp, errno, "Failed to add fd %d to KVM VFIO device", + fd); + return -errno; } #endif + return 0; +} + +int vfio_kvm_device_del_fd(int fd, Error **errp) +{ +#ifdef CONFIG_KVM + struct kvm_device_attr attr = { + .group = KVM_DEV_VFIO_FILE, + .attr = KVM_DEV_VFIO_FILE_DEL, + .addr = (uint64_t)(unsigned long)&fd, + }; + + if (vfio_kvm_device_fd < 0) { + error_setg(errp, "KVM VFIO device isn't created yet"); + return -EINVAL; + } + + if (ioctl(vfio_kvm_device_fd, KVM_SET_DEVICE_ATTR, &attr)) { + error_setg_errno(errp, errno, + "Failed to remove fd %d from KVM VFIO device", fd); + return -errno; + } +#endif + return 0; +} + +static void vfio_kvm_device_add_group(VFIOGroup *group) +{ + Error *err = NULL; + + if (vfio_kvm_device_add_fd(group->fd, &err)) { + error_reportf_err(err, "group ID %d: ", group->groupid); + } } static void vfio_kvm_device_del_group(VFIOGroup *group) { -#ifdef CONFIG_KVM - struct kvm_device_attr attr = { - .group = KVM_DEV_VFIO_GROUP, - .attr = KVM_DEV_VFIO_GROUP_DEL, - .addr = (uint64_t)(unsigned long)&group->fd, - }; + Error *err = NULL; - if (vfio_kvm_device_fd < 0) { - return; + if (vfio_kvm_device_del_fd(group->fd, &err)) { + error_reportf_err(err, "group ID %d: ", group->groupid); } - - if (ioctl(vfio_kvm_device_fd, KVM_SET_DEVICE_ATTR, &attr)) { - error_report("Failed to remove group %d from KVM VFIO device: %m", - group->groupid); - } -#endif } static VFIOAddressSpace *vfio_get_address_space(AddressSpace *as) diff --git a/include/hw/vfio/vfio-common.h b/include/hw/vfio/vfio-common.h index e0483893d1..c4e7c3b4a7 100644 --- a/include/hw/vfio/vfio-common.h +++ b/include/hw/vfio/vfio-common.h @@ -226,6 +226,9 @@ struct vfio_device_info *vfio_get_device_info(int fd); int vfio_get_device(VFIOGroup *group, const char *name, VFIODevice *vbasedev, Error **errp); +int vfio_kvm_device_add_fd(int fd, Error **errp); +int vfio_kvm_device_del_fd(int fd, Error **errp); + extern const MemoryRegionOps vfio_region_ops; typedef QLIST_HEAD(VFIOGroupList, VFIOGroup) VFIOGroupList; extern VFIOGroupList vfio_group_list; From 5456b1867d10826e3857fda417b59a669fa5cce9 Mon Sep 17 00:00:00 2001 From: Eric Auger Date: Mon, 9 Oct 2023 11:09:09 +0200 Subject: [PATCH 0766/1077] vfio/pci: Introduce vfio_[attach/detach]_device MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We want the VFIO devices to be able to use two different IOMMU backends, the legacy VFIO one and the new iommufd one. Introduce vfio_[attach/detach]_device which aim at hiding the underlying IOMMU backend (IOCTLs, datatypes, ...). Once vfio_attach_device completes, the device is attached to a security context and its fd can be used. Conversely When vfio_detach_device completes, the device has been detached from the security context. At the moment only the implementation based on the legacy container/group exists. Let's use it from the vfio-pci device. Subsequent patches will handle other devices. We also take benefit of this patch to properly free vbasedev->name on failure. Signed-off-by: Eric Auger Signed-off-by: Yi Liu Signed-off-by: Zhenzhong Duan Reviewed-by: Cédric Le Goater Signed-off-by: Cédric Le Goater --- hw/vfio/common.c | 74 +++++++++++++++++++++++++++++++++++ hw/vfio/pci.c | 66 +++++++------------------------ hw/vfio/trace-events | 3 +- include/hw/vfio/vfio-common.h | 3 ++ 4 files changed, 93 insertions(+), 53 deletions(-) diff --git a/hw/vfio/common.c b/hw/vfio/common.c index d8ed432cb6..f4c33c9858 100644 --- a/hw/vfio/common.c +++ b/hw/vfio/common.c @@ -2611,3 +2611,77 @@ int vfio_eeh_as_op(AddressSpace *as, uint32_t op) } return vfio_eeh_container_op(container, op); } + +static int vfio_device_groupid(VFIODevice *vbasedev, Error **errp) +{ + char *tmp, group_path[PATH_MAX], *group_name; + int ret, groupid; + ssize_t len; + + tmp = g_strdup_printf("%s/iommu_group", vbasedev->sysfsdev); + len = readlink(tmp, group_path, sizeof(group_path)); + g_free(tmp); + + if (len <= 0 || len >= sizeof(group_path)) { + ret = len < 0 ? -errno : -ENAMETOOLONG; + error_setg_errno(errp, -ret, "no iommu_group found"); + return ret; + } + + group_path[len] = 0; + + group_name = basename(group_path); + if (sscanf(group_name, "%d", &groupid) != 1) { + error_setg_errno(errp, errno, "failed to read %s", group_path); + return -errno; + } + return groupid; +} + +/* + * vfio_attach_device: attach a device to a security context + * @name and @vbasedev->name are likely to be different depending + * on the type of the device, hence the need for passing @name + */ +int vfio_attach_device(char *name, VFIODevice *vbasedev, + AddressSpace *as, Error **errp) +{ + int groupid = vfio_device_groupid(vbasedev, errp); + VFIODevice *vbasedev_iter; + VFIOGroup *group; + int ret; + + if (groupid < 0) { + return groupid; + } + + trace_vfio_attach_device(vbasedev->name, groupid); + + group = vfio_get_group(groupid, as, errp); + if (!group) { + return -ENOENT; + } + + QLIST_FOREACH(vbasedev_iter, &group->device_list, next) { + if (strcmp(vbasedev_iter->name, vbasedev->name) == 0) { + error_setg(errp, "device is already attached"); + vfio_put_group(group); + return -EBUSY; + } + } + ret = vfio_get_device(group, name, vbasedev, errp); + if (ret) { + vfio_put_group(group); + } + + return ret; +} + +void vfio_detach_device(VFIODevice *vbasedev) +{ + VFIOGroup *group = vbasedev->group; + + trace_vfio_detach_device(vbasedev->name, group->groupid); + vfio_put_base_device(vbasedev); + vfio_put_group(group); +} diff --git a/hw/vfio/pci.c b/hw/vfio/pci.c index 898296fd54..40ae46266e 100644 --- a/hw/vfio/pci.c +++ b/hw/vfio/pci.c @@ -2895,10 +2895,10 @@ static void vfio_populate_device(VFIOPCIDevice *vdev, Error **errp) static void vfio_pci_put_device(VFIOPCIDevice *vdev) { + vfio_detach_device(&vdev->vbasedev); + g_free(vdev->vbasedev.name); g_free(vdev->msix); - - vfio_put_base_device(&vdev->vbasedev); } static void vfio_err_notifier_handler(void *opaque) @@ -3045,13 +3045,9 @@ static void vfio_realize(PCIDevice *pdev, Error **errp) { VFIOPCIDevice *vdev = VFIO_PCI(pdev); VFIODevice *vbasedev = &vdev->vbasedev; - VFIODevice *vbasedev_iter; - VFIOGroup *group; - char *tmp, *subsys, group_path[PATH_MAX], *group_name; + char *tmp, *subsys; Error *err = NULL; - ssize_t len; struct stat st; - int groupid; int i, ret; bool is_mdev; char uuid[UUID_FMT_LEN]; @@ -3082,39 +3078,6 @@ static void vfio_realize(PCIDevice *pdev, Error **errp) vbasedev->type = VFIO_DEVICE_TYPE_PCI; vbasedev->dev = DEVICE(vdev); - tmp = g_strdup_printf("%s/iommu_group", vbasedev->sysfsdev); - len = readlink(tmp, group_path, sizeof(group_path)); - g_free(tmp); - - if (len <= 0 || len >= sizeof(group_path)) { - error_setg_errno(errp, len < 0 ? errno : ENAMETOOLONG, - "no iommu_group found"); - goto error; - } - - group_path[len] = 0; - - group_name = basename(group_path); - if (sscanf(group_name, "%d", &groupid) != 1) { - error_setg_errno(errp, errno, "failed to read %s", group_path); - goto error; - } - - trace_vfio_realize(vbasedev->name, groupid); - - group = vfio_get_group(groupid, pci_device_iommu_address_space(pdev), errp); - if (!group) { - goto error; - } - - QLIST_FOREACH(vbasedev_iter, &group->device_list, next) { - if (strcmp(vbasedev_iter->name, vbasedev->name) == 0) { - error_setg(errp, "device is already attached"); - vfio_put_group(group); - goto error; - } - } - /* * Mediated devices *might* operate compatibly with discarding of RAM, but * we cannot know for certain, it depends on whether the mdev vendor driver @@ -3132,7 +3095,6 @@ static void vfio_realize(PCIDevice *pdev, Error **errp) if (vbasedev->ram_block_discard_allowed && !is_mdev) { error_setg(errp, "x-balloon-allowed only potentially compatible " "with mdev devices"); - vfio_put_group(group); goto error; } @@ -3143,17 +3105,17 @@ static void vfio_realize(PCIDevice *pdev, Error **errp) name = g_strdup(vbasedev->name); } - ret = vfio_get_device(group, name, vbasedev, errp); + ret = vfio_attach_device(name, vbasedev, + pci_device_iommu_address_space(pdev), errp); g_free(name); if (ret) { - vfio_put_group(group); goto error; } vfio_populate_device(vdev, &err); if (err) { error_propagate(errp, err); - goto error; + goto out_detach; } /* Get a copy of config space */ @@ -3163,7 +3125,7 @@ static void vfio_realize(PCIDevice *pdev, Error **errp) if (ret < (int)MIN(pci_config_size(&vdev->pdev), vdev->config_size)) { ret = ret < 0 ? -errno : -EFAULT; error_setg_errno(errp, -ret, "failed to read device config space"); - goto error; + goto out_detach; } /* vfio emulates a lot for us, but some bits need extra love */ @@ -3182,7 +3144,7 @@ static void vfio_realize(PCIDevice *pdev, Error **errp) if (vdev->vendor_id != PCI_ANY_ID) { if (vdev->vendor_id >= 0xffff) { error_setg(errp, "invalid PCI vendor ID provided"); - goto error; + goto out_detach; } vfio_add_emulated_word(vdev, PCI_VENDOR_ID, vdev->vendor_id, ~0); trace_vfio_pci_emulated_vendor_id(vbasedev->name, vdev->vendor_id); @@ -3193,7 +3155,7 @@ static void vfio_realize(PCIDevice *pdev, Error **errp) if (vdev->device_id != PCI_ANY_ID) { if (vdev->device_id > 0xffff) { error_setg(errp, "invalid PCI device ID provided"); - goto error; + goto out_detach; } vfio_add_emulated_word(vdev, PCI_DEVICE_ID, vdev->device_id, ~0); trace_vfio_pci_emulated_device_id(vbasedev->name, vdev->device_id); @@ -3204,7 +3166,7 @@ static void vfio_realize(PCIDevice *pdev, Error **errp) if (vdev->sub_vendor_id != PCI_ANY_ID) { if (vdev->sub_vendor_id > 0xffff) { error_setg(errp, "invalid PCI subsystem vendor ID provided"); - goto error; + goto out_detach; } vfio_add_emulated_word(vdev, PCI_SUBSYSTEM_VENDOR_ID, vdev->sub_vendor_id, ~0); @@ -3215,7 +3177,7 @@ static void vfio_realize(PCIDevice *pdev, Error **errp) if (vdev->sub_device_id != PCI_ANY_ID) { if (vdev->sub_device_id > 0xffff) { error_setg(errp, "invalid PCI subsystem device ID provided"); - goto error; + goto out_detach; } vfio_add_emulated_word(vdev, PCI_SUBSYSTEM_ID, vdev->sub_device_id, ~0); trace_vfio_pci_emulated_sub_device_id(vbasedev->name, @@ -3248,7 +3210,7 @@ static void vfio_realize(PCIDevice *pdev, Error **errp) vfio_msix_early_setup(vdev, &err); if (err) { error_propagate(errp, err); - goto error; + goto out_detach; } vfio_bars_register(vdev); @@ -3364,6 +3326,8 @@ out_deregister: out_teardown: vfio_teardown_msi(vdev); vfio_bars_exit(vdev); +out_detach: + vfio_detach_device(vbasedev); error: error_prepend(errp, VFIO_MSG_PREFIX, vbasedev->name); } @@ -3371,7 +3335,6 @@ error: static void vfio_instance_finalize(Object *obj) { VFIOPCIDevice *vdev = VFIO_PCI(obj); - VFIOGroup *group = vdev->vbasedev.group; vfio_display_finalize(vdev); vfio_bars_finalize(vdev); @@ -3385,7 +3348,6 @@ static void vfio_instance_finalize(Object *obj) * g_free(vdev->igd_opregion); */ vfio_pci_put_device(vdev); - vfio_put_group(group); } static void vfio_exitfn(PCIDevice *pdev) diff --git a/hw/vfio/trace-events b/hw/vfio/trace-events index 0ba3c5a0e2..8ac13eb106 100644 --- a/hw/vfio/trace-events +++ b/hw/vfio/trace-events @@ -37,7 +37,8 @@ vfio_pci_hot_reset_dep_devices(int domain, int bus, int slot, int function, int vfio_pci_hot_reset_result(const char *name, const char *result) "%s hot reset: %s" vfio_populate_device_config(const char *name, unsigned long size, unsigned long offset, unsigned long flags) "Device %s config:\n size: 0x%lx, offset: 0x%lx, flags: 0x%lx" vfio_populate_device_get_irq_info_failure(const char *errstr) "VFIO_DEVICE_GET_IRQ_INFO failure: %s" -vfio_realize(const char *name, int group_id) " (%s) group %d" +vfio_attach_device(const char *name, int group_id) " (%s) group %d" +vfio_detach_device(const char *name, int group_id) " (%s) group %d" vfio_mdev(const char *name, bool is_mdev) " (%s) is_mdev %d" vfio_add_ext_cap_dropped(const char *name, uint16_t cap, uint16_t offset) "%s 0x%x@0x%x" vfio_pci_reset(const char *name) " (%s)" diff --git a/include/hw/vfio/vfio-common.h b/include/hw/vfio/vfio-common.h index c4e7c3b4a7..12fbfbc37d 100644 --- a/include/hw/vfio/vfio-common.h +++ b/include/hw/vfio/vfio-common.h @@ -225,6 +225,9 @@ void vfio_put_group(VFIOGroup *group); struct vfio_device_info *vfio_get_device_info(int fd); int vfio_get_device(VFIOGroup *group, const char *name, VFIODevice *vbasedev, Error **errp); +int vfio_attach_device(char *name, VFIODevice *vbasedev, + AddressSpace *as, Error **errp); +void vfio_detach_device(VFIODevice *vbasedev); int vfio_kvm_device_add_fd(int fd, Error **errp); int vfio_kvm_device_del_fd(int fd, Error **errp); From da5ed43299bb5d99ffea819b8a3c3629005ea9fd Mon Sep 17 00:00:00 2001 From: Eric Auger Date: Mon, 9 Oct 2023 11:09:10 +0200 Subject: [PATCH 0767/1077] vfio/platform: Use vfio_[attach/detach]_device MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Let the vfio-platform device use vfio_attach_device() and vfio_detach_device(), hence hiding the details of the used IOMMU backend. Drop the trace event for vfio-platform as we have similar one in vfio_attach_device. Signed-off-by: Eric Auger Signed-off-by: Yi Liu Signed-off-by: Zhenzhong Duan Reviewed-by: Cédric Le Goater Signed-off-by: Cédric Le Goater --- hw/vfio/platform.c | 43 +++---------------------------------------- hw/vfio/trace-events | 1 - 2 files changed, 3 insertions(+), 41 deletions(-) diff --git a/hw/vfio/platform.c b/hw/vfio/platform.c index 5af73f9287..8e3d4ac458 100644 --- a/hw/vfio/platform.c +++ b/hw/vfio/platform.c @@ -529,12 +529,7 @@ static VFIODeviceOps vfio_platform_ops = { */ static int vfio_base_device_init(VFIODevice *vbasedev, Error **errp) { - VFIOGroup *group; - VFIODevice *vbasedev_iter; - char *tmp, group_path[PATH_MAX], *group_name; - ssize_t len; struct stat st; - int groupid; int ret; /* @sysfsdev takes precedence over @host */ @@ -557,47 +552,15 @@ static int vfio_base_device_init(VFIODevice *vbasedev, Error **errp) return -errno; } - tmp = g_strdup_printf("%s/iommu_group", vbasedev->sysfsdev); - len = readlink(tmp, group_path, sizeof(group_path)); - g_free(tmp); - - if (len < 0 || len >= sizeof(group_path)) { - ret = len < 0 ? -errno : -ENAMETOOLONG; - error_setg_errno(errp, -ret, "no iommu_group found"); - return ret; - } - - group_path[len] = 0; - - group_name = basename(group_path); - if (sscanf(group_name, "%d", &groupid) != 1) { - error_setg_errno(errp, errno, "failed to read %s", group_path); - return -errno; - } - - trace_vfio_platform_base_device_init(vbasedev->name, groupid); - - group = vfio_get_group(groupid, &address_space_memory, errp); - if (!group) { - return -ENOENT; - } - - QLIST_FOREACH(vbasedev_iter, &group->device_list, next) { - if (strcmp(vbasedev_iter->name, vbasedev->name) == 0) { - error_setg(errp, "device is already attached"); - vfio_put_group(group); - return -EBUSY; - } - } - ret = vfio_get_device(group, vbasedev->name, vbasedev, errp); + ret = vfio_attach_device(vbasedev->name, vbasedev, + &address_space_memory, errp); if (ret) { - vfio_put_group(group); return ret; } ret = vfio_populate_device(vbasedev, errp); if (ret) { - vfio_put_group(group); + vfio_detach_device(vbasedev); } return ret; diff --git a/hw/vfio/trace-events b/hw/vfio/trace-events index 8ac13eb106..0eb2387cf2 100644 --- a/hw/vfio/trace-events +++ b/hw/vfio/trace-events @@ -121,7 +121,6 @@ vfio_get_dirty_bitmap(int fd, uint64_t iova, uint64_t size, uint64_t bitmap_size vfio_iommu_map_dirty_notify(uint64_t iova_start, uint64_t iova_end) "iommu dirty @ 0x%"PRIx64" - 0x%"PRIx64 # platform.c -vfio_platform_base_device_init(char *name, int groupid) "%s belongs to group #%d" vfio_platform_realize(char *name, char *compat) "vfio device %s, compat = %s" vfio_platform_eoi(int pin, int fd) "EOI IRQ pin %d (fd=%d)" vfio_platform_intp_mmap_enable(int pin) "IRQ #%d still active, stay in slow path" From c95d128ee3cf3319c9b40b550eac8df3f86fa410 Mon Sep 17 00:00:00 2001 From: Eric Auger Date: Mon, 9 Oct 2023 11:09:11 +0200 Subject: [PATCH 0768/1077] vfio/ap: Use vfio_[attach/detach]_device MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Let the vfio-ap device use vfio_attach_device() and vfio_detach_device(), hence hiding the details of the used IOMMU backend. We take the opportunity to use g_path_get_basename() which is prefered, as suggested by 3e015d815b ("use g_path_get_basename instead of basename") Signed-off-by: Eric Auger Signed-off-by: Yi Liu Signed-off-by: Zhenzhong Duan Reviewed-by: Matthew Rosato Signed-off-by: Cédric Le Goater --- hw/vfio/ap.c | 67 ++++++++++------------------------------------------ 1 file changed, 13 insertions(+), 54 deletions(-) diff --git a/hw/vfio/ap.c b/hw/vfio/ap.c index 6e21d1da5a..f870f51ffa 100644 --- a/hw/vfio/ap.c +++ b/hw/vfio/ap.c @@ -53,40 +53,6 @@ struct VFIODeviceOps vfio_ap_ops = { .vfio_compute_needs_reset = vfio_ap_compute_needs_reset, }; -static void vfio_ap_put_device(VFIOAPDevice *vapdev) -{ - g_free(vapdev->vdev.name); - vfio_put_base_device(&vapdev->vdev); -} - -static VFIOGroup *vfio_ap_get_group(VFIOAPDevice *vapdev, Error **errp) -{ - GError *gerror = NULL; - char *symlink, *group_path; - int groupid; - - symlink = g_strdup_printf("%s/iommu_group", vapdev->vdev.sysfsdev); - group_path = g_file_read_link(symlink, &gerror); - g_free(symlink); - - if (!group_path) { - error_setg(errp, "%s: no iommu_group found for %s: %s", - TYPE_VFIO_AP_DEVICE, vapdev->vdev.sysfsdev, gerror->message); - g_error_free(gerror); - return NULL; - } - - if (sscanf(basename(group_path), "%d", &groupid) != 1) { - error_setg(errp, "vfio: failed to read %s", group_path); - g_free(group_path); - return NULL; - } - - g_free(group_path); - - return vfio_get_group(groupid, &address_space_memory, errp); -} - static void vfio_ap_req_notifier_handler(void *opaque) { VFIOAPDevice *vapdev = opaque; @@ -189,22 +155,15 @@ static void vfio_ap_unregister_irq_notifier(VFIOAPDevice *vapdev, static void vfio_ap_realize(DeviceState *dev, Error **errp) { int ret; - char *mdevid; Error *err = NULL; - VFIOGroup *vfio_group; APDevice *apdev = AP_DEVICE(dev); VFIOAPDevice *vapdev = VFIO_AP_DEVICE(apdev); + VFIODevice *vbasedev = &vapdev->vdev; - vfio_group = vfio_ap_get_group(vapdev, errp); - if (!vfio_group) { - return; - } - - vapdev->vdev.ops = &vfio_ap_ops; - vapdev->vdev.type = VFIO_DEVICE_TYPE_AP; - mdevid = basename(vapdev->vdev.sysfsdev); - vapdev->vdev.name = g_strdup_printf("%s", mdevid); - vapdev->vdev.dev = dev; + vbasedev->name = g_path_get_basename(vbasedev->sysfsdev); + vbasedev->ops = &vfio_ap_ops; + vbasedev->type = VFIO_DEVICE_TYPE_AP; + vbasedev->dev = dev; /* * vfio-ap devices operate in a way compatible with discarding of @@ -214,9 +173,10 @@ static void vfio_ap_realize(DeviceState *dev, Error **errp) */ vapdev->vdev.ram_block_discard_allowed = true; - ret = vfio_get_device(vfio_group, mdevid, &vapdev->vdev, errp); + ret = vfio_attach_device(vbasedev->name, vbasedev, + &address_space_memory, errp); if (ret) { - goto out_get_dev_err; + goto error; } vfio_ap_register_irq_notifier(vapdev, VFIO_AP_REQ_IRQ_INDEX, &err); @@ -230,20 +190,19 @@ static void vfio_ap_realize(DeviceState *dev, Error **errp) return; -out_get_dev_err: - vfio_ap_put_device(vapdev); - vfio_put_group(vfio_group); +error: + error_prepend(errp, VFIO_MSG_PREFIX, vbasedev->name); + g_free(vbasedev->name); } static void vfio_ap_unrealize(DeviceState *dev) { APDevice *apdev = AP_DEVICE(dev); VFIOAPDevice *vapdev = VFIO_AP_DEVICE(apdev); - VFIOGroup *group = vapdev->vdev.group; vfio_ap_unregister_irq_notifier(vapdev, VFIO_AP_REQ_IRQ_INDEX); - vfio_ap_put_device(vapdev); - vfio_put_group(group); + vfio_detach_device(&vapdev->vdev); + g_free(vapdev->vdev.name); } static Property vfio_ap_properties[] = { From e08041ece7392aae895487b97299f33ddc8de131 Mon Sep 17 00:00:00 2001 From: Eric Auger Date: Mon, 9 Oct 2023 11:09:12 +0200 Subject: [PATCH 0769/1077] vfio/ccw: Use vfio_[attach/detach]_device MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Let the vfio-ccw device use vfio_attach_device() and vfio_detach_device(), hence hiding the details of the used IOMMU backend. Note that the migration reduces the following trace "vfio: subchannel %s has already been attached" (featuring cssid.ssid.devid) into "device is already attached" Also now all the devices have been migrated to use the new vfio_attach_device/vfio_detach_device API, let's turn the legacy functions into static functions, local to container.c. Signed-off-by: Eric Auger Signed-off-by: Yi Liu Signed-off-by: Zhenzhong Duan Signed-off-by: Cédric Le Goater --- hw/vfio/ccw.c | 117 ++++++++-------------------------- hw/vfio/common.c | 10 +-- include/hw/vfio/vfio-common.h | 5 -- 3 files changed, 32 insertions(+), 100 deletions(-) diff --git a/hw/vfio/ccw.c b/hw/vfio/ccw.c index 1e2fce83b0..6623ae237b 100644 --- a/hw/vfio/ccw.c +++ b/hw/vfio/ccw.c @@ -572,88 +572,14 @@ static void vfio_ccw_put_region(VFIOCCWDevice *vcdev) g_free(vcdev->io_region); } -static void vfio_ccw_put_device(VFIOCCWDevice *vcdev) -{ - g_free(vcdev->vdev.name); - vfio_put_base_device(&vcdev->vdev); -} - -static void vfio_ccw_get_device(VFIOGroup *group, VFIOCCWDevice *vcdev, - Error **errp) -{ - S390CCWDevice *cdev = S390_CCW_DEVICE(vcdev); - char *name = g_strdup_printf("%x.%x.%04x", cdev->hostid.cssid, - cdev->hostid.ssid, - cdev->hostid.devid); - VFIODevice *vbasedev; - - QLIST_FOREACH(vbasedev, &group->device_list, next) { - if (strcmp(vbasedev->name, name) == 0) { - error_setg(errp, "vfio: subchannel %s has already been attached", - name); - goto out_err; - } - } - - /* - * All vfio-ccw devices are believed to operate in a way compatible with - * discarding of memory in RAM blocks, ie. pages pinned in the host are - * in the current working set of the guest driver and therefore never - * overlap e.g., with pages available to the guest balloon driver. This - * needs to be set before vfio_get_device() for vfio common to handle - * ram_block_discard_disable(). - */ - vcdev->vdev.ram_block_discard_allowed = true; - - if (vfio_get_device(group, cdev->mdevid, &vcdev->vdev, errp)) { - goto out_err; - } - - vcdev->vdev.ops = &vfio_ccw_ops; - vcdev->vdev.type = VFIO_DEVICE_TYPE_CCW; - vcdev->vdev.name = name; - vcdev->vdev.dev = DEVICE(vcdev); - - return; - -out_err: - g_free(name); -} - -static VFIOGroup *vfio_ccw_get_group(S390CCWDevice *cdev, Error **errp) -{ - char *tmp, group_path[PATH_MAX]; - ssize_t len; - int groupid; - - tmp = g_strdup_printf("/sys/bus/css/devices/%x.%x.%04x/%s/iommu_group", - cdev->hostid.cssid, cdev->hostid.ssid, - cdev->hostid.devid, cdev->mdevid); - len = readlink(tmp, group_path, sizeof(group_path)); - g_free(tmp); - - if (len <= 0 || len >= sizeof(group_path)) { - error_setg(errp, "vfio: no iommu_group found"); - return NULL; - } - - group_path[len] = 0; - - if (sscanf(basename(group_path), "%d", &groupid) != 1) { - error_setg(errp, "vfio: failed to read %s", group_path); - return NULL; - } - - return vfio_get_group(groupid, &address_space_memory, errp); -} - static void vfio_ccw_realize(DeviceState *dev, Error **errp) { - VFIOGroup *group; S390CCWDevice *cdev = S390_CCW_DEVICE(dev); VFIOCCWDevice *vcdev = VFIO_CCW(cdev); S390CCWDeviceClass *cdc = S390_CCW_DEVICE_GET_CLASS(cdev); + VFIODevice *vbasedev = &vcdev->vdev; Error *err = NULL; + int ret; /* Call the class init function for subchannel. */ if (cdc->realize) { @@ -663,14 +589,27 @@ static void vfio_ccw_realize(DeviceState *dev, Error **errp) } } - group = vfio_ccw_get_group(cdev, &err); - if (!group) { - goto out_group_err; - } + vbasedev->ops = &vfio_ccw_ops; + vbasedev->type = VFIO_DEVICE_TYPE_CCW; + vbasedev->name = g_strdup_printf("%x.%x.%04x", vcdev->cdev.hostid.cssid, + vcdev->cdev.hostid.ssid, + vcdev->cdev.hostid.devid); + vbasedev->dev = dev; - vfio_ccw_get_device(group, vcdev, &err); - if (err) { - goto out_device_err; + /* + * All vfio-ccw devices are believed to operate in a way compatible with + * discarding of memory in RAM blocks, ie. pages pinned in the host are + * in the current working set of the guest driver and therefore never + * overlap e.g., with pages available to the guest balloon driver. This + * needs to be set before vfio_get_device() for vfio common to handle + * ram_block_discard_disable(). + */ + vbasedev->ram_block_discard_allowed = true; + + ret = vfio_attach_device(cdev->mdevid, vbasedev, + &address_space_memory, errp); + if (ret) { + goto out_attach_dev_err; } vfio_ccw_get_region(vcdev, &err); @@ -708,10 +647,9 @@ out_irq_notifier_err: out_io_notifier_err: vfio_ccw_put_region(vcdev); out_region_err: - vfio_ccw_put_device(vcdev); -out_device_err: - vfio_put_group(group); -out_group_err: + vfio_detach_device(vbasedev); +out_attach_dev_err: + g_free(vbasedev->name); if (cdc->unrealize) { cdc->unrealize(cdev); } @@ -724,14 +662,13 @@ static void vfio_ccw_unrealize(DeviceState *dev) S390CCWDevice *cdev = S390_CCW_DEVICE(dev); VFIOCCWDevice *vcdev = VFIO_CCW(cdev); S390CCWDeviceClass *cdc = S390_CCW_DEVICE_GET_CLASS(cdev); - VFIOGroup *group = vcdev->vdev.group; vfio_ccw_unregister_irq_notifier(vcdev, VFIO_CCW_REQ_IRQ_INDEX); vfio_ccw_unregister_irq_notifier(vcdev, VFIO_CCW_CRW_IRQ_INDEX); vfio_ccw_unregister_irq_notifier(vcdev, VFIO_CCW_IO_IRQ_INDEX); vfio_ccw_put_region(vcdev); - vfio_ccw_put_device(vcdev); - vfio_put_group(group); + vfio_detach_device(&vcdev->vdev); + g_free(vcdev->vdev.name); if (cdc->unrealize) { cdc->unrealize(cdev); diff --git a/hw/vfio/common.c b/hw/vfio/common.c index f4c33c9858..56cfe94d97 100644 --- a/hw/vfio/common.c +++ b/hw/vfio/common.c @@ -2335,7 +2335,7 @@ static void vfio_disconnect_container(VFIOGroup *group) } } -VFIOGroup *vfio_get_group(int groupid, AddressSpace *as, Error **errp) +static VFIOGroup *vfio_get_group(int groupid, AddressSpace *as, Error **errp) { VFIOGroup *group; char path[32]; @@ -2402,7 +2402,7 @@ free_group_exit: return NULL; } -void vfio_put_group(VFIOGroup *group) +static void vfio_put_group(VFIOGroup *group) { if (!group || !QLIST_EMPTY(&group->device_list)) { return; @@ -2447,8 +2447,8 @@ retry: return info; } -int vfio_get_device(VFIOGroup *group, const char *name, - VFIODevice *vbasedev, Error **errp) +static int vfio_get_device(VFIOGroup *group, const char *name, + VFIODevice *vbasedev, Error **errp) { g_autofree struct vfio_device_info *info = NULL; int fd; @@ -2506,7 +2506,7 @@ int vfio_get_device(VFIOGroup *group, const char *name, return 0; } -void vfio_put_base_device(VFIODevice *vbasedev) +static void vfio_put_base_device(VFIODevice *vbasedev) { if (!vbasedev->group) { return; diff --git a/include/hw/vfio/vfio-common.h b/include/hw/vfio/vfio-common.h index 12fbfbc37d..c486bdef2a 100644 --- a/include/hw/vfio/vfio-common.h +++ b/include/hw/vfio/vfio-common.h @@ -202,7 +202,6 @@ typedef struct { hwaddr pages; } VFIOBitmap; -void vfio_put_base_device(VFIODevice *vbasedev); void vfio_disable_irqindex(VFIODevice *vbasedev, int index); void vfio_unmask_single_irqindex(VFIODevice *vbasedev, int index); void vfio_mask_single_irqindex(VFIODevice *vbasedev, int index); @@ -220,11 +219,7 @@ void vfio_region_unmap(VFIORegion *region); void vfio_region_exit(VFIORegion *region); void vfio_region_finalize(VFIORegion *region); void vfio_reset_handler(void *opaque); -VFIOGroup *vfio_get_group(int groupid, AddressSpace *as, Error **errp); -void vfio_put_group(VFIOGroup *group); struct vfio_device_info *vfio_get_device_info(int fd); -int vfio_get_device(VFIOGroup *group, const char *name, - VFIODevice *vbasedev, Error **errp); int vfio_attach_device(char *name, VFIODevice *vbasedev, AddressSpace *as, Error **errp); void vfio_detach_device(VFIODevice *vbasedev); From c8fcb90c968717323a763d2152bc6103ce720b65 Mon Sep 17 00:00:00 2001 From: Zhenzhong Duan Date: Mon, 9 Oct 2023 11:09:13 +0200 Subject: [PATCH 0770/1077] vfio/common: Move VFIO reset handler registration to a group agnostic function MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Move the reset handler registration/unregistration to a place that is not group specific. vfio_[get/put]_address_space are the best places for that purpose. Signed-off-by: Eric Auger Signed-off-by: Yi Liu Signed-off-by: Zhenzhong Duan Reviewed-by: Cédric Le Goater Signed-off-by: Cédric Le Goater --- hw/vfio/common.c | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/hw/vfio/common.c b/hw/vfio/common.c index 56cfe94d97..019da387d2 100644 --- a/hw/vfio/common.c +++ b/hw/vfio/common.c @@ -1909,6 +1909,10 @@ static VFIOAddressSpace *vfio_get_address_space(AddressSpace *as) space->as = as; QLIST_INIT(&space->containers); + if (QLIST_EMPTY(&vfio_address_spaces)) { + qemu_register_reset(vfio_reset_handler, NULL); + } + QLIST_INSERT_HEAD(&vfio_address_spaces, space, list); return space; @@ -1920,6 +1924,9 @@ static void vfio_put_address_space(VFIOAddressSpace *space) QLIST_REMOVE(space, list); g_free(space); } + if (QLIST_EMPTY(&vfio_address_spaces)) { + qemu_unregister_reset(vfio_reset_handler, NULL); + } } /* @@ -2385,10 +2392,6 @@ static VFIOGroup *vfio_get_group(int groupid, AddressSpace *as, Error **errp) goto close_fd_exit; } - if (QLIST_EMPTY(&vfio_group_list)) { - qemu_register_reset(vfio_reset_handler, NULL); - } - QLIST_INSERT_HEAD(&vfio_group_list, group, next); return group; @@ -2417,10 +2420,6 @@ static void vfio_put_group(VFIOGroup *group) trace_vfio_put_group(group->fd); close(group->fd); g_free(group); - - if (QLIST_EMPTY(&vfio_group_list)) { - qemu_unregister_reset(vfio_reset_handler, NULL); - } } struct vfio_device_info *vfio_get_device_info(int fd) From 7103ef7e765dfdf84ba7042f46d3cc0da682cb89 Mon Sep 17 00:00:00 2001 From: Zhenzhong Duan Date: Mon, 9 Oct 2023 11:09:14 +0200 Subject: [PATCH 0771/1077] vfio/common: Introduce a per container device list MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Several functions need to iterate over the VFIO devices attached to a given container. This is currently achieved by iterating over the groups attached to the container and then over the devices in the group. Let's introduce a per container device list that simplifies this search. Per container list is used in below functions: vfio_devices_all_dirty_tracking vfio_devices_all_device_dirty_tracking vfio_devices_all_running_and_mig_active vfio_devices_dma_logging_stop vfio_devices_dma_logging_start vfio_devices_query_dirty_bitmap This will also ease the migration of IOMMUFD by hiding the group specificity. Suggested-by: Alex Williamson Signed-off-by: Zhenzhong Duan Signed-off-by: Eric Auger Reviewed-by: Cédric Le Goater Signed-off-by: Cédric Le Goater --- hw/vfio/common.c | 145 +++++++++++++++------------------- include/hw/vfio/vfio-common.h | 2 + 2 files changed, 67 insertions(+), 80 deletions(-) diff --git a/hw/vfio/common.c b/hw/vfio/common.c index 019da387d2..ef9dc7c747 100644 --- a/hw/vfio/common.c +++ b/hw/vfio/common.c @@ -218,7 +218,6 @@ bool vfio_device_state_is_precopy(VFIODevice *vbasedev) static bool vfio_devices_all_dirty_tracking(VFIOContainer *container) { - VFIOGroup *group; VFIODevice *vbasedev; MigrationState *ms = migrate_get_current(); @@ -227,19 +226,17 @@ static bool vfio_devices_all_dirty_tracking(VFIOContainer *container) return false; } - QLIST_FOREACH(group, &container->group_list, container_next) { - QLIST_FOREACH(vbasedev, &group->device_list, next) { - VFIOMigration *migration = vbasedev->migration; + QLIST_FOREACH(vbasedev, &container->device_list, container_next) { + VFIOMigration *migration = vbasedev->migration; - if (!migration) { - return false; - } + if (!migration) { + return false; + } - if (vbasedev->pre_copy_dirty_page_tracking == ON_OFF_AUTO_OFF && - (vfio_device_state_is_running(vbasedev) || - vfio_device_state_is_precopy(vbasedev))) { - return false; - } + if (vbasedev->pre_copy_dirty_page_tracking == ON_OFF_AUTO_OFF && + (vfio_device_state_is_running(vbasedev) || + vfio_device_state_is_precopy(vbasedev))) { + return false; } } return true; @@ -247,14 +244,11 @@ static bool vfio_devices_all_dirty_tracking(VFIOContainer *container) static bool vfio_devices_all_device_dirty_tracking(VFIOContainer *container) { - VFIOGroup *group; VFIODevice *vbasedev; - QLIST_FOREACH(group, &container->group_list, container_next) { - QLIST_FOREACH(vbasedev, &group->device_list, next) { - if (!vbasedev->dirty_pages_supported) { - return false; - } + QLIST_FOREACH(vbasedev, &container->device_list, container_next) { + if (!vbasedev->dirty_pages_supported) { + return false; } } @@ -267,27 +261,24 @@ static bool vfio_devices_all_device_dirty_tracking(VFIOContainer *container) */ static bool vfio_devices_all_running_and_mig_active(VFIOContainer *container) { - VFIOGroup *group; VFIODevice *vbasedev; if (!migration_is_active(migrate_get_current())) { return false; } - QLIST_FOREACH(group, &container->group_list, container_next) { - QLIST_FOREACH(vbasedev, &group->device_list, next) { - VFIOMigration *migration = vbasedev->migration; + QLIST_FOREACH(vbasedev, &container->device_list, container_next) { + VFIOMigration *migration = vbasedev->migration; - if (!migration) { - return false; - } + if (!migration) { + return false; + } - if (vfio_device_state_is_running(vbasedev) || - vfio_device_state_is_precopy(vbasedev)) { - continue; - } else { - return false; - } + if (vfio_device_state_is_running(vbasedev) || + vfio_device_state_is_precopy(vbasedev)) { + continue; + } else { + return false; } } return true; @@ -1187,20 +1178,17 @@ static bool vfio_section_is_vfio_pci(MemoryRegionSection *section, { VFIOPCIDevice *pcidev; VFIODevice *vbasedev; - VFIOGroup *group; Object *owner; owner = memory_region_owner(section->mr); - QLIST_FOREACH(group, &container->group_list, container_next) { - QLIST_FOREACH(vbasedev, &group->device_list, next) { - if (vbasedev->type != VFIO_DEVICE_TYPE_PCI) { - continue; - } - pcidev = container_of(vbasedev, VFIOPCIDevice, vbasedev); - if (OBJECT(pcidev) == owner) { - return true; - } + QLIST_FOREACH(vbasedev, &container->device_list, container_next) { + if (vbasedev->type != VFIO_DEVICE_TYPE_PCI) { + continue; + } + pcidev = container_of(vbasedev, VFIOPCIDevice, vbasedev); + if (OBJECT(pcidev) == owner) { + return true; } } @@ -1296,24 +1284,21 @@ static void vfio_devices_dma_logging_stop(VFIOContainer *container) sizeof(uint64_t))] = {}; struct vfio_device_feature *feature = (struct vfio_device_feature *)buf; VFIODevice *vbasedev; - VFIOGroup *group; feature->argsz = sizeof(buf); feature->flags = VFIO_DEVICE_FEATURE_SET | VFIO_DEVICE_FEATURE_DMA_LOGGING_STOP; - QLIST_FOREACH(group, &container->group_list, container_next) { - QLIST_FOREACH(vbasedev, &group->device_list, next) { - if (!vbasedev->dirty_tracking) { - continue; - } - - if (ioctl(vbasedev->fd, VFIO_DEVICE_FEATURE, feature)) { - warn_report("%s: Failed to stop DMA logging, err %d (%s)", - vbasedev->name, -errno, strerror(errno)); - } - vbasedev->dirty_tracking = false; + QLIST_FOREACH(vbasedev, &container->device_list, container_next) { + if (!vbasedev->dirty_tracking) { + continue; } + + if (ioctl(vbasedev->fd, VFIO_DEVICE_FEATURE, feature)) { + warn_report("%s: Failed to stop DMA logging, err %d (%s)", + vbasedev->name, -errno, strerror(errno)); + } + vbasedev->dirty_tracking = false; } } @@ -1396,7 +1381,6 @@ static int vfio_devices_dma_logging_start(VFIOContainer *container) struct vfio_device_feature *feature; VFIODirtyRanges ranges; VFIODevice *vbasedev; - VFIOGroup *group; int ret = 0; vfio_dirty_tracking_init(container, &ranges); @@ -1406,21 +1390,19 @@ static int vfio_devices_dma_logging_start(VFIOContainer *container) return -errno; } - QLIST_FOREACH(group, &container->group_list, container_next) { - QLIST_FOREACH(vbasedev, &group->device_list, next) { - if (vbasedev->dirty_tracking) { - continue; - } - - ret = ioctl(vbasedev->fd, VFIO_DEVICE_FEATURE, feature); - if (ret) { - ret = -errno; - error_report("%s: Failed to start DMA logging, err %d (%s)", - vbasedev->name, ret, strerror(errno)); - goto out; - } - vbasedev->dirty_tracking = true; + QLIST_FOREACH(vbasedev, &container->device_list, container_next) { + if (vbasedev->dirty_tracking) { + continue; } + + ret = ioctl(vbasedev->fd, VFIO_DEVICE_FEATURE, feature); + if (ret) { + ret = -errno; + error_report("%s: Failed to start DMA logging, err %d (%s)", + vbasedev->name, ret, strerror(errno)); + goto out; + } + vbasedev->dirty_tracking = true; } out: @@ -1500,21 +1482,18 @@ static int vfio_devices_query_dirty_bitmap(VFIOContainer *container, hwaddr size) { VFIODevice *vbasedev; - VFIOGroup *group; int ret; - QLIST_FOREACH(group, &container->group_list, container_next) { - QLIST_FOREACH(vbasedev, &group->device_list, next) { - ret = vfio_device_dma_logging_report(vbasedev, iova, size, - vbmap->bitmap); - if (ret) { - error_report("%s: Failed to get DMA logging report, iova: " - "0x%" HWADDR_PRIx ", size: 0x%" HWADDR_PRIx - ", err: %d (%s)", - vbasedev->name, iova, size, ret, strerror(-ret)); + QLIST_FOREACH(vbasedev, &container->device_list, container_next) { + ret = vfio_device_dma_logging_report(vbasedev, iova, size, + vbmap->bitmap); + if (ret) { + error_report("%s: Failed to get DMA logging report, iova: " + "0x%" HWADDR_PRIx ", size: 0x%" HWADDR_PRIx + ", err: %d (%s)", + vbasedev->name, iova, size, ret, strerror(-ret)); - return ret; - } + return ret; } } @@ -2648,6 +2627,7 @@ int vfio_attach_device(char *name, VFIODevice *vbasedev, int groupid = vfio_device_groupid(vbasedev, errp); VFIODevice *vbasedev_iter; VFIOGroup *group; + VFIOContainer *container; int ret; if (groupid < 0) { @@ -2671,8 +2651,12 @@ int vfio_attach_device(char *name, VFIODevice *vbasedev, ret = vfio_get_device(group, name, vbasedev, errp); if (ret) { vfio_put_group(group); + return ret; } + container = group->container; + QLIST_INSERT_HEAD(&container->device_list, vbasedev, container_next); + return ret; } @@ -2680,6 +2664,7 @@ void vfio_detach_device(VFIODevice *vbasedev) { VFIOGroup *group = vbasedev->group; + QLIST_REMOVE(vbasedev, container_next); trace_vfio_detach_device(vbasedev->name, group->groupid); vfio_put_base_device(vbasedev); vfio_put_group(group); diff --git a/include/hw/vfio/vfio-common.h b/include/hw/vfio/vfio-common.h index c486bdef2a..8ca70dd821 100644 --- a/include/hw/vfio/vfio-common.h +++ b/include/hw/vfio/vfio-common.h @@ -98,6 +98,7 @@ typedef struct VFIOContainer { QLIST_HEAD(, VFIOGroup) group_list; QLIST_HEAD(, VFIORamDiscardListener) vrdl_list; QLIST_ENTRY(VFIOContainer) next; + QLIST_HEAD(, VFIODevice) device_list; } VFIOContainer; typedef struct VFIOGuestIOMMU { @@ -129,6 +130,7 @@ typedef struct VFIODeviceOps VFIODeviceOps; typedef struct VFIODevice { QLIST_ENTRY(VFIODevice) next; + QLIST_ENTRY(VFIODevice) container_next; struct VFIOGroup *group; char *sysfsdev; char *name; From 0bddd88027679d3c34b7c754a13c7af002adbd99 Mon Sep 17 00:00:00 2001 From: Zhenzhong Duan Date: Mon, 9 Oct 2023 11:09:15 +0200 Subject: [PATCH 0772/1077] vfio/common: Store the parent container in VFIODevice MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit let's store the parent contaienr within the VFIODevice. This simplifies the logic in vfio_viommu_preset() and brings the benefice to hide the group specificity which is useful for IOMMUFD migration. Signed-off-by: Eric Auger Signed-off-by: Zhenzhong Duan Signed-off-by: Cédric Le Goater --- hw/vfio/common.c | 8 +++++++- include/hw/vfio/vfio-common.h | 1 + 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/hw/vfio/common.c b/hw/vfio/common.c index ef9dc7c747..55f8a113ea 100644 --- a/hw/vfio/common.c +++ b/hw/vfio/common.c @@ -184,7 +184,7 @@ void vfio_unblock_multiple_devices_migration(void) bool vfio_viommu_preset(VFIODevice *vbasedev) { - return vbasedev->group->container->space->as != &address_space_memory; + return vbasedev->container->space->as != &address_space_memory; } static void vfio_set_migration_error(int err) @@ -2655,6 +2655,7 @@ int vfio_attach_device(char *name, VFIODevice *vbasedev, } container = group->container; + vbasedev->container = container; QLIST_INSERT_HEAD(&container->device_list, vbasedev, container_next); return ret; @@ -2664,7 +2665,12 @@ void vfio_detach_device(VFIODevice *vbasedev) { VFIOGroup *group = vbasedev->group; + if (!vbasedev->container) { + return; + } + QLIST_REMOVE(vbasedev, container_next); + vbasedev->container = NULL; trace_vfio_detach_device(vbasedev->name, group->groupid); vfio_put_base_device(vbasedev); vfio_put_group(group); diff --git a/include/hw/vfio/vfio-common.h b/include/hw/vfio/vfio-common.h index 8ca70dd821..bf12e40667 100644 --- a/include/hw/vfio/vfio-common.h +++ b/include/hw/vfio/vfio-common.h @@ -132,6 +132,7 @@ typedef struct VFIODevice { QLIST_ENTRY(VFIODevice) next; QLIST_ENTRY(VFIODevice) container_next; struct VFIOGroup *group; + VFIOContainer *container; char *sysfsdev; char *name; DeviceState *dev; From 3d779abafe9fff4fdbbc6c8dd2a6f6f901d98870 Mon Sep 17 00:00:00 2001 From: Zhenzhong Duan Date: Mon, 9 Oct 2023 11:09:16 +0200 Subject: [PATCH 0773/1077] vfio/common: Introduce a global VFIODevice list MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Some functions iterate over all the VFIODevices. This is currently achieved by iterating over all groups/devices. Let's introduce a global list of VFIODevices simplifying that scan. This will also be useful while migrating to IOMMUFD by hiding the group specificity. Signed-off-by: Eric Auger Signed-off-by: Zhenzhong Duan Suggested-by: Alex Williamson Signed-off-by: Cédric Le Goater --- hw/vfio/common.c | 45 +++++++++++++++-------------------- include/hw/vfio/vfio-common.h | 2 ++ 2 files changed, 21 insertions(+), 26 deletions(-) diff --git a/hw/vfio/common.c b/hw/vfio/common.c index 55f8a113ea..95bc50bcda 100644 --- a/hw/vfio/common.c +++ b/hw/vfio/common.c @@ -48,6 +48,8 @@ VFIOGroupList vfio_group_list = QLIST_HEAD_INITIALIZER(vfio_group_list); +static VFIODeviceList vfio_device_list = + QLIST_HEAD_INITIALIZER(vfio_device_list); static QLIST_HEAD(, VFIOAddressSpace) vfio_address_spaces = QLIST_HEAD_INITIALIZER(vfio_address_spaces); @@ -94,18 +96,15 @@ static int vfio_get_dirty_bitmap(VFIOContainer *container, uint64_t iova, bool vfio_mig_active(void) { - VFIOGroup *group; VFIODevice *vbasedev; - if (QLIST_EMPTY(&vfio_group_list)) { + if (QLIST_EMPTY(&vfio_device_list)) { return false; } - QLIST_FOREACH(group, &vfio_group_list, next) { - QLIST_FOREACH(vbasedev, &group->device_list, next) { - if (vbasedev->migration_blocker) { - return false; - } + QLIST_FOREACH(vbasedev, &vfio_device_list, next) { + if (vbasedev->migration_blocker) { + return false; } } return true; @@ -120,19 +119,16 @@ static Error *multiple_devices_migration_blocker; */ static bool vfio_multiple_devices_migration_is_supported(void) { - VFIOGroup *group; VFIODevice *vbasedev; unsigned int device_num = 0; bool all_support_p2p = true; - QLIST_FOREACH(group, &vfio_group_list, next) { - QLIST_FOREACH(vbasedev, &group->device_list, next) { - if (vbasedev->migration) { - device_num++; + QLIST_FOREACH(vbasedev, &vfio_device_list, next) { + if (vbasedev->migration) { + device_num++; - if (!(vbasedev->migration->mig_flags & VFIO_MIGRATION_P2P)) { - all_support_p2p = false; - } + if (!(vbasedev->migration->mig_flags & VFIO_MIGRATION_P2P)) { + all_support_p2p = false; } } } @@ -1777,22 +1773,17 @@ bool vfio_get_info_dma_avail(struct vfio_iommu_type1_info *info, void vfio_reset_handler(void *opaque) { - VFIOGroup *group; VFIODevice *vbasedev; - QLIST_FOREACH(group, &vfio_group_list, next) { - QLIST_FOREACH(vbasedev, &group->device_list, next) { - if (vbasedev->dev->realized) { - vbasedev->ops->vfio_compute_needs_reset(vbasedev); - } + QLIST_FOREACH(vbasedev, &vfio_device_list, next) { + if (vbasedev->dev->realized) { + vbasedev->ops->vfio_compute_needs_reset(vbasedev); } } - QLIST_FOREACH(group, &vfio_group_list, next) { - QLIST_FOREACH(vbasedev, &group->device_list, next) { - if (vbasedev->dev->realized && vbasedev->needs_reset) { - vbasedev->ops->vfio_hot_reset_multi(vbasedev); - } + QLIST_FOREACH(vbasedev, &vfio_device_list, next) { + if (vbasedev->dev->realized && vbasedev->needs_reset) { + vbasedev->ops->vfio_hot_reset_multi(vbasedev); } } } @@ -2657,6 +2648,7 @@ int vfio_attach_device(char *name, VFIODevice *vbasedev, container = group->container; vbasedev->container = container; QLIST_INSERT_HEAD(&container->device_list, vbasedev, container_next); + QLIST_INSERT_HEAD(&vfio_device_list, vbasedev, global_next); return ret; } @@ -2669,6 +2661,7 @@ void vfio_detach_device(VFIODevice *vbasedev) return; } + QLIST_REMOVE(vbasedev, global_next); QLIST_REMOVE(vbasedev, container_next); vbasedev->container = NULL; trace_vfio_detach_device(vbasedev->name, group->groupid); diff --git a/include/hw/vfio/vfio-common.h b/include/hw/vfio/vfio-common.h index bf12e40667..54905b9dd4 100644 --- a/include/hw/vfio/vfio-common.h +++ b/include/hw/vfio/vfio-common.h @@ -131,6 +131,7 @@ typedef struct VFIODeviceOps VFIODeviceOps; typedef struct VFIODevice { QLIST_ENTRY(VFIODevice) next; QLIST_ENTRY(VFIODevice) container_next; + QLIST_ENTRY(VFIODevice) global_next; struct VFIOGroup *group; VFIOContainer *container; char *sysfsdev; @@ -232,6 +233,7 @@ int vfio_kvm_device_del_fd(int fd, Error **errp); extern const MemoryRegionOps vfio_region_ops; typedef QLIST_HEAD(VFIOGroupList, VFIOGroup) VFIOGroupList; +typedef QLIST_HEAD(VFIODeviceList, VFIODevice) VFIODeviceList; extern VFIOGroupList vfio_group_list; bool vfio_mig_active(void); From 7e63b3113889b531cbb56b09d69cc182608bb78e Mon Sep 17 00:00:00 2001 From: Yi Liu Date: Mon, 9 Oct 2023 11:09:17 +0200 Subject: [PATCH 0774/1077] vfio/common: Move legacy VFIO backend code into separate container.c MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Move all the code really dependent on the legacy VFIO container/group into a separate file: container.c. What does remain in common.c is the code related to VFIOAddressSpace, MemoryListeners, migration and all other general operations. Signed-off-by: Eric Auger Signed-off-by: Yi Liu Signed-off-by: Zhenzhong Duan Reviewed-by: Cédric Le Goater Signed-off-by: Cédric Le Goater --- hw/vfio/common.c | 1155 +------------------------------- hw/vfio/container.c | 1161 +++++++++++++++++++++++++++++++++ hw/vfio/meson.build | 1 + include/hw/vfio/vfio-common.h | 35 + 4 files changed, 1213 insertions(+), 1139 deletions(-) create mode 100644 hw/vfio/container.c diff --git a/hw/vfio/common.c b/hw/vfio/common.c index 95bc50bcda..9e61de03ee 100644 --- a/hw/vfio/common.c +++ b/hw/vfio/common.c @@ -46,9 +46,7 @@ #include "migration/qemu-file.h" #include "sysemu/tpm.h" -VFIOGroupList vfio_group_list = - QLIST_HEAD_INITIALIZER(vfio_group_list); -static VFIODeviceList vfio_device_list = +VFIODeviceList vfio_device_list = QLIST_HEAD_INITIALIZER(vfio_device_list); static QLIST_HEAD(, VFIOAddressSpace) vfio_address_spaces = QLIST_HEAD_INITIALIZER(vfio_address_spaces); @@ -61,39 +59,13 @@ static QLIST_HEAD(, VFIOAddressSpace) vfio_address_spaces = * initialized, this file descriptor is only released on QEMU exit and * we'll re-use it should another vfio device be attached before then. */ -static int vfio_kvm_device_fd = -1; +int vfio_kvm_device_fd = -1; #endif -static int vfio_ram_block_discard_disable(VFIOContainer *container, bool state) -{ - switch (container->iommu_type) { - case VFIO_TYPE1v2_IOMMU: - case VFIO_TYPE1_IOMMU: - /* - * We support coordinated discarding of RAM via the RamDiscardManager. - */ - return ram_block_uncoordinated_discard_disable(state); - default: - /* - * VFIO_SPAPR_TCE_IOMMU most probably works just fine with - * RamDiscardManager, however, it is completely untested. - * - * VFIO_SPAPR_TCE_v2_IOMMU with "DMA memory preregistering" does - * completely the opposite of managing mapping/pinning dynamically as - * required by RamDiscardManager. We would have to special-case sections - * with a RamDiscardManager. - */ - return ram_block_discard_disable(state); - } -} - /* * Device state interfaces */ -static int vfio_get_dirty_bitmap(VFIOContainer *container, uint64_t iova, - uint64_t size, ram_addr_t ram_addr); - bool vfio_mig_active(void) { VFIODevice *vbasedev; @@ -238,7 +210,7 @@ static bool vfio_devices_all_dirty_tracking(VFIOContainer *container) return true; } -static bool vfio_devices_all_device_dirty_tracking(VFIOContainer *container) +bool vfio_devices_all_device_dirty_tracking(VFIOContainer *container) { VFIODevice *vbasedev; @@ -255,7 +227,7 @@ static bool vfio_devices_all_device_dirty_tracking(VFIOContainer *container) * Check if all VFIO devices are running and migration is active, which is * essentially equivalent to the migration being in pre-copy phase. */ -static bool vfio_devices_all_running_and_mig_active(VFIOContainer *container) +bool vfio_devices_all_running_and_mig_active(VFIOContainer *container) { VFIODevice *vbasedev; @@ -280,150 +252,8 @@ static bool vfio_devices_all_running_and_mig_active(VFIOContainer *container) return true; } -static int vfio_dma_unmap_bitmap(VFIOContainer *container, - hwaddr iova, ram_addr_t size, - IOMMUTLBEntry *iotlb) -{ - struct vfio_iommu_type1_dma_unmap *unmap; - struct vfio_bitmap *bitmap; - VFIOBitmap vbmap; - int ret; - - ret = vfio_bitmap_alloc(&vbmap, size); - if (ret) { - return ret; - } - - unmap = g_malloc0(sizeof(*unmap) + sizeof(*bitmap)); - - unmap->argsz = sizeof(*unmap) + sizeof(*bitmap); - unmap->iova = iova; - unmap->size = size; - unmap->flags |= VFIO_DMA_UNMAP_FLAG_GET_DIRTY_BITMAP; - bitmap = (struct vfio_bitmap *)&unmap->data; - - /* - * cpu_physical_memory_set_dirty_lebitmap() supports pages in bitmap of - * qemu_real_host_page_size to mark those dirty. Hence set bitmap_pgsize - * to qemu_real_host_page_size. - */ - bitmap->pgsize = qemu_real_host_page_size(); - bitmap->size = vbmap.size; - bitmap->data = (__u64 *)vbmap.bitmap; - - if (vbmap.size > container->max_dirty_bitmap_size) { - error_report("UNMAP: Size of bitmap too big 0x%"PRIx64, vbmap.size); - ret = -E2BIG; - goto unmap_exit; - } - - ret = ioctl(container->fd, VFIO_IOMMU_UNMAP_DMA, unmap); - if (!ret) { - cpu_physical_memory_set_dirty_lebitmap(vbmap.bitmap, - iotlb->translated_addr, vbmap.pages); - } else { - error_report("VFIO_UNMAP_DMA with DIRTY_BITMAP : %m"); - } - -unmap_exit: - g_free(unmap); - g_free(vbmap.bitmap); - - return ret; -} - -/* - * DMA - Mapping and unmapping for the "type1" IOMMU interface used on x86 - */ -static int vfio_dma_unmap(VFIOContainer *container, - hwaddr iova, ram_addr_t size, - IOMMUTLBEntry *iotlb) -{ - struct vfio_iommu_type1_dma_unmap unmap = { - .argsz = sizeof(unmap), - .flags = 0, - .iova = iova, - .size = size, - }; - bool need_dirty_sync = false; - int ret; - - if (iotlb && vfio_devices_all_running_and_mig_active(container)) { - if (!vfio_devices_all_device_dirty_tracking(container) && - container->dirty_pages_supported) { - return vfio_dma_unmap_bitmap(container, iova, size, iotlb); - } - - need_dirty_sync = true; - } - - while (ioctl(container->fd, VFIO_IOMMU_UNMAP_DMA, &unmap)) { - /* - * The type1 backend has an off-by-one bug in the kernel (71a7d3d78e3c - * v4.15) where an overflow in its wrap-around check prevents us from - * unmapping the last page of the address space. Test for the error - * condition and re-try the unmap excluding the last page. The - * expectation is that we've never mapped the last page anyway and this - * unmap request comes via vIOMMU support which also makes it unlikely - * that this page is used. This bug was introduced well after type1 v2 - * support was introduced, so we shouldn't need to test for v1. A fix - * is queued for kernel v5.0 so this workaround can be removed once - * affected kernels are sufficiently deprecated. - */ - if (errno == EINVAL && unmap.size && !(unmap.iova + unmap.size) && - container->iommu_type == VFIO_TYPE1v2_IOMMU) { - trace_vfio_dma_unmap_overflow_workaround(); - unmap.size -= 1ULL << ctz64(container->pgsizes); - continue; - } - error_report("VFIO_UNMAP_DMA failed: %s", strerror(errno)); - return -errno; - } - - if (need_dirty_sync) { - ret = vfio_get_dirty_bitmap(container, iova, size, - iotlb->translated_addr); - if (ret) { - return ret; - } - } - - return 0; -} - -static int vfio_dma_map(VFIOContainer *container, hwaddr iova, - ram_addr_t size, void *vaddr, bool readonly) -{ - struct vfio_iommu_type1_dma_map map = { - .argsz = sizeof(map), - .flags = VFIO_DMA_MAP_FLAG_READ, - .vaddr = (__u64)(uintptr_t)vaddr, - .iova = iova, - .size = size, - }; - - if (!readonly) { - map.flags |= VFIO_DMA_MAP_FLAG_WRITE; - } - - /* - * Try the mapping, if it fails with EBUSY, unmap the region and try - * again. This shouldn't be necessary, but we sometimes see it in - * the VGA ROM space. - */ - if (ioctl(container->fd, VFIO_IOMMU_MAP_DMA, &map) == 0 || - (errno == EBUSY && vfio_dma_unmap(container, iova, size, NULL) == 0 && - ioctl(container->fd, VFIO_IOMMU_MAP_DMA, &map) == 0)) { - return 0; - } - - error_report("VFIO_MAP_DMA failed: %s", strerror(errno)); - return -errno; -} - -static void vfio_host_win_add(VFIOContainer *container, - hwaddr min_iova, hwaddr max_iova, - uint64_t iova_pgsizes) +void vfio_host_win_add(VFIOContainer *container, hwaddr min_iova, + hwaddr max_iova, uint64_t iova_pgsizes) { VFIOHostDMAWindow *hostwin; @@ -444,8 +274,8 @@ static void vfio_host_win_add(VFIOContainer *container, QLIST_INSERT_HEAD(&container->hostwin_list, hostwin, hostwin_next); } -static int vfio_host_win_del(VFIOContainer *container, hwaddr min_iova, - hwaddr max_iova) +int vfio_host_win_del(VFIOContainer *container, + hwaddr min_iova, hwaddr max_iova) { VFIOHostDMAWindow *hostwin; @@ -794,92 +624,6 @@ static bool vfio_get_section_iova_range(VFIOContainer *container, return true; } -static int vfio_container_add_section_window(VFIOContainer *container, - MemoryRegionSection *section, - Error **errp) -{ - VFIOHostDMAWindow *hostwin; - hwaddr pgsize = 0; - int ret; - - if (container->iommu_type != VFIO_SPAPR_TCE_v2_IOMMU) { - return 0; - } - - /* For now intersections are not allowed, we may relax this later */ - QLIST_FOREACH(hostwin, &container->hostwin_list, hostwin_next) { - if (ranges_overlap(hostwin->min_iova, - hostwin->max_iova - hostwin->min_iova + 1, - section->offset_within_address_space, - int128_get64(section->size))) { - error_setg(errp, - "region [0x%"PRIx64",0x%"PRIx64"] overlaps with existing" - "host DMA window [0x%"PRIx64",0x%"PRIx64"]", - section->offset_within_address_space, - section->offset_within_address_space + - int128_get64(section->size) - 1, - hostwin->min_iova, hostwin->max_iova); - return -EINVAL; - } - } - - ret = vfio_spapr_create_window(container, section, &pgsize); - if (ret) { - error_setg_errno(errp, -ret, "Failed to create SPAPR window"); - return ret; - } - - vfio_host_win_add(container, section->offset_within_address_space, - section->offset_within_address_space + - int128_get64(section->size) - 1, pgsize); -#ifdef CONFIG_KVM - if (kvm_enabled()) { - VFIOGroup *group; - IOMMUMemoryRegion *iommu_mr = IOMMU_MEMORY_REGION(section->mr); - struct kvm_vfio_spapr_tce param; - struct kvm_device_attr attr = { - .group = KVM_DEV_VFIO_GROUP, - .attr = KVM_DEV_VFIO_GROUP_SET_SPAPR_TCE, - .addr = (uint64_t)(unsigned long)¶m, - }; - - if (!memory_region_iommu_get_attr(iommu_mr, IOMMU_ATTR_SPAPR_TCE_FD, - ¶m.tablefd)) { - QLIST_FOREACH(group, &container->group_list, container_next) { - param.groupfd = group->fd; - if (ioctl(vfio_kvm_device_fd, KVM_SET_DEVICE_ATTR, &attr)) { - error_setg_errno(errp, errno, - "vfio: failed GROUP_SET_SPAPR_TCE for " - "KVM VFIO device %d and group fd %d", - param.tablefd, param.groupfd); - return -errno; - } - trace_vfio_spapr_group_attach(param.groupfd, param.tablefd); - } - } - } -#endif - return 0; -} - -static void vfio_container_del_section_window(VFIOContainer *container, - MemoryRegionSection *section) -{ - if (container->iommu_type != VFIO_SPAPR_TCE_v2_IOMMU) { - return; - } - - vfio_spapr_remove_window(container, - section->offset_within_address_space); - if (vfio_host_win_del(container, - section->offset_within_address_space, - section->offset_within_address_space + - int128_get64(section->size) - 1) < 0) { - hw_error("%s: Cannot delete missing window at %"HWADDR_PRIx, - __func__, section->offset_within_address_space); - } -} - static void vfio_listener_region_add(MemoryListener *listener, MemoryRegionSection *section) { @@ -1127,33 +871,6 @@ static void vfio_listener_region_del(MemoryListener *listener, vfio_container_del_section_window(container, section); } -static int vfio_set_dirty_page_tracking(VFIOContainer *container, bool start) -{ - int ret; - struct vfio_iommu_type1_dirty_bitmap dirty = { - .argsz = sizeof(dirty), - }; - - if (!container->dirty_pages_supported) { - return 0; - } - - if (start) { - dirty.flags = VFIO_IOMMU_DIRTY_PAGES_FLAG_START; - } else { - dirty.flags = VFIO_IOMMU_DIRTY_PAGES_FLAG_STOP; - } - - ret = ioctl(container->fd, VFIO_IOMMU_DIRTY_PAGES, &dirty); - if (ret) { - ret = -errno; - error_report("Failed to set dirty tracking flag 0x%x errno: %d", - dirty.flags, errno); - } - - return ret; -} - typedef struct VFIODirtyRanges { hwaddr min32; hwaddr max32; @@ -1473,9 +1190,9 @@ static int vfio_device_dma_logging_report(VFIODevice *vbasedev, hwaddr iova, return 0; } -static int vfio_devices_query_dirty_bitmap(VFIOContainer *container, - VFIOBitmap *vbmap, hwaddr iova, - hwaddr size) +int vfio_devices_query_dirty_bitmap(VFIOContainer *container, + VFIOBitmap *vbmap, hwaddr iova, + hwaddr size) { VFIODevice *vbasedev; int ret; @@ -1496,45 +1213,8 @@ static int vfio_devices_query_dirty_bitmap(VFIOContainer *container, return 0; } -static int vfio_query_dirty_bitmap(VFIOContainer *container, VFIOBitmap *vbmap, - hwaddr iova, hwaddr size) -{ - struct vfio_iommu_type1_dirty_bitmap *dbitmap; - struct vfio_iommu_type1_dirty_bitmap_get *range; - int ret; - - dbitmap = g_malloc0(sizeof(*dbitmap) + sizeof(*range)); - - dbitmap->argsz = sizeof(*dbitmap) + sizeof(*range); - dbitmap->flags = VFIO_IOMMU_DIRTY_PAGES_FLAG_GET_BITMAP; - range = (struct vfio_iommu_type1_dirty_bitmap_get *)&dbitmap->data; - range->iova = iova; - range->size = size; - - /* - * cpu_physical_memory_set_dirty_lebitmap() supports pages in bitmap of - * qemu_real_host_page_size to mark those dirty. Hence set bitmap's pgsize - * to qemu_real_host_page_size. - */ - range->bitmap.pgsize = qemu_real_host_page_size(); - range->bitmap.size = vbmap->size; - range->bitmap.data = (__u64 *)vbmap->bitmap; - - ret = ioctl(container->fd, VFIO_IOMMU_DIRTY_PAGES, dbitmap); - if (ret) { - ret = -errno; - error_report("Failed to get dirty bitmap for iova: 0x%"PRIx64 - " size: 0x%"PRIx64" err: %d", (uint64_t)range->iova, - (uint64_t)range->size, errno); - } - - g_free(dbitmap); - - return ret; -} - -static int vfio_get_dirty_bitmap(VFIOContainer *container, uint64_t iova, - uint64_t size, ram_addr_t ram_addr) +int vfio_get_dirty_bitmap(VFIOContainer *container, uint64_t iova, + uint64_t size, ram_addr_t ram_addr) { bool all_device_dirty_tracking = vfio_devices_all_device_dirty_tracking(container); @@ -1723,7 +1403,7 @@ static void vfio_listener_log_sync(MemoryListener *listener, } } -static const MemoryListener vfio_memory_listener = { +const MemoryListener vfio_memory_listener = { .name = "vfio", .region_add = vfio_listener_region_add, .region_del = vfio_listener_region_del, @@ -1732,45 +1412,6 @@ static const MemoryListener vfio_memory_listener = { .log_sync = vfio_listener_log_sync, }; -static void vfio_listener_release(VFIOContainer *container) -{ - memory_listener_unregister(&container->listener); - if (container->iommu_type == VFIO_SPAPR_TCE_v2_IOMMU) { - memory_listener_unregister(&container->prereg_listener); - } -} - -static struct vfio_info_cap_header * -vfio_get_iommu_type1_info_cap(struct vfio_iommu_type1_info *info, uint16_t id) -{ - if (!(info->flags & VFIO_IOMMU_INFO_CAPS)) { - return NULL; - } - - return vfio_get_cap((void *)info, info->cap_offset, id); -} - -bool vfio_get_info_dma_avail(struct vfio_iommu_type1_info *info, - unsigned int *avail) -{ - struct vfio_info_cap_header *hdr; - struct vfio_iommu_type1_info_dma_avail *cap; - - /* If the capability cannot be found, assume no DMA limiting */ - hdr = vfio_get_iommu_type1_info_cap(info, - VFIO_IOMMU_TYPE1_INFO_DMA_AVAIL); - if (hdr == NULL) { - return false; - } - - if (avail != NULL) { - cap = (void *) hdr; - *avail = cap->avail; - } - - return true; -} - void vfio_reset_handler(void *opaque) { VFIODevice *vbasedev; @@ -1846,25 +1487,7 @@ int vfio_kvm_device_del_fd(int fd, Error **errp) return 0; } -static void vfio_kvm_device_add_group(VFIOGroup *group) -{ - Error *err = NULL; - - if (vfio_kvm_device_add_fd(group->fd, &err)) { - error_reportf_err(err, "group ID %d: ", group->groupid); - } -} - -static void vfio_kvm_device_del_group(VFIOGroup *group) -{ - Error *err = NULL; - - if (vfio_kvm_device_del_fd(group->fd, &err)) { - error_reportf_err(err, "group ID %d: ", group->groupid); - } -} - -static VFIOAddressSpace *vfio_get_address_space(AddressSpace *as) +VFIOAddressSpace *vfio_get_address_space(AddressSpace *as) { VFIOAddressSpace *space; @@ -1888,7 +1511,7 @@ static VFIOAddressSpace *vfio_get_address_space(AddressSpace *as) return space; } -static void vfio_put_address_space(VFIOAddressSpace *space) +void vfio_put_address_space(VFIOAddressSpace *space) { if (QLIST_EMPTY(&space->containers)) { QLIST_REMOVE(space, list); @@ -1899,499 +1522,6 @@ static void vfio_put_address_space(VFIOAddressSpace *space) } } -/* - * vfio_get_iommu_type - selects the richest iommu_type (v2 first) - */ -static int vfio_get_iommu_type(VFIOContainer *container, - Error **errp) -{ - int iommu_types[] = { VFIO_TYPE1v2_IOMMU, VFIO_TYPE1_IOMMU, - VFIO_SPAPR_TCE_v2_IOMMU, VFIO_SPAPR_TCE_IOMMU }; - int i; - - for (i = 0; i < ARRAY_SIZE(iommu_types); i++) { - if (ioctl(container->fd, VFIO_CHECK_EXTENSION, iommu_types[i])) { - return iommu_types[i]; - } - } - error_setg(errp, "No available IOMMU models"); - return -EINVAL; -} - -static int vfio_init_container(VFIOContainer *container, int group_fd, - Error **errp) -{ - int iommu_type, ret; - - iommu_type = vfio_get_iommu_type(container, errp); - if (iommu_type < 0) { - return iommu_type; - } - - ret = ioctl(group_fd, VFIO_GROUP_SET_CONTAINER, &container->fd); - if (ret) { - error_setg_errno(errp, errno, "Failed to set group container"); - return -errno; - } - - while (ioctl(container->fd, VFIO_SET_IOMMU, iommu_type)) { - if (iommu_type == VFIO_SPAPR_TCE_v2_IOMMU) { - /* - * On sPAPR, despite the IOMMU subdriver always advertises v1 and - * v2, the running platform may not support v2 and there is no - * way to guess it until an IOMMU group gets added to the container. - * So in case it fails with v2, try v1 as a fallback. - */ - iommu_type = VFIO_SPAPR_TCE_IOMMU; - continue; - } - error_setg_errno(errp, errno, "Failed to set iommu for container"); - return -errno; - } - - container->iommu_type = iommu_type; - return 0; -} - -static int vfio_get_iommu_info(VFIOContainer *container, - struct vfio_iommu_type1_info **info) -{ - - size_t argsz = sizeof(struct vfio_iommu_type1_info); - - *info = g_new0(struct vfio_iommu_type1_info, 1); -again: - (*info)->argsz = argsz; - - if (ioctl(container->fd, VFIO_IOMMU_GET_INFO, *info)) { - g_free(*info); - *info = NULL; - return -errno; - } - - if (((*info)->argsz > argsz)) { - argsz = (*info)->argsz; - *info = g_realloc(*info, argsz); - goto again; - } - - return 0; -} - -static struct vfio_info_cap_header * -vfio_get_iommu_info_cap(struct vfio_iommu_type1_info *info, uint16_t id) -{ - struct vfio_info_cap_header *hdr; - void *ptr = info; - - if (!(info->flags & VFIO_IOMMU_INFO_CAPS)) { - return NULL; - } - - for (hdr = ptr + info->cap_offset; hdr != ptr; hdr = ptr + hdr->next) { - if (hdr->id == id) { - return hdr; - } - } - - return NULL; -} - -static void vfio_get_iommu_info_migration(VFIOContainer *container, - struct vfio_iommu_type1_info *info) -{ - struct vfio_info_cap_header *hdr; - struct vfio_iommu_type1_info_cap_migration *cap_mig; - - hdr = vfio_get_iommu_info_cap(info, VFIO_IOMMU_TYPE1_INFO_CAP_MIGRATION); - if (!hdr) { - return; - } - - cap_mig = container_of(hdr, struct vfio_iommu_type1_info_cap_migration, - header); - - /* - * cpu_physical_memory_set_dirty_lebitmap() supports pages in bitmap of - * qemu_real_host_page_size to mark those dirty. - */ - if (cap_mig->pgsize_bitmap & qemu_real_host_page_size()) { - container->dirty_pages_supported = true; - container->max_dirty_bitmap_size = cap_mig->max_dirty_bitmap_size; - container->dirty_pgsizes = cap_mig->pgsize_bitmap; - } -} - -static int vfio_connect_container(VFIOGroup *group, AddressSpace *as, - Error **errp) -{ - VFIOContainer *container; - int ret, fd; - VFIOAddressSpace *space; - - space = vfio_get_address_space(as); - - /* - * VFIO is currently incompatible with discarding of RAM insofar as the - * madvise to purge (zap) the page from QEMU's address space does not - * interact with the memory API and therefore leaves stale virtual to - * physical mappings in the IOMMU if the page was previously pinned. We - * therefore set discarding broken for each group added to a container, - * whether the container is used individually or shared. This provides - * us with options to allow devices within a group to opt-in and allow - * discarding, so long as it is done consistently for a group (for instance - * if the device is an mdev device where it is known that the host vendor - * driver will never pin pages outside of the working set of the guest - * driver, which would thus not be discarding candidates). - * - * The first opportunity to induce pinning occurs here where we attempt to - * attach the group to existing containers within the AddressSpace. If any - * pages are already zapped from the virtual address space, such as from - * previous discards, new pinning will cause valid mappings to be - * re-established. Likewise, when the overall MemoryListener for a new - * container is registered, a replay of mappings within the AddressSpace - * will occur, re-establishing any previously zapped pages as well. - * - * Especially virtio-balloon is currently only prevented from discarding - * new memory, it will not yet set ram_block_discard_set_required() and - * therefore, neither stops us here or deals with the sudden memory - * consumption of inflated memory. - * - * We do support discarding of memory coordinated via the RamDiscardManager - * with some IOMMU types. vfio_ram_block_discard_disable() handles the - * details once we know which type of IOMMU we are using. - */ - - QLIST_FOREACH(container, &space->containers, next) { - if (!ioctl(group->fd, VFIO_GROUP_SET_CONTAINER, &container->fd)) { - ret = vfio_ram_block_discard_disable(container, true); - if (ret) { - error_setg_errno(errp, -ret, - "Cannot set discarding of RAM broken"); - if (ioctl(group->fd, VFIO_GROUP_UNSET_CONTAINER, - &container->fd)) { - error_report("vfio: error disconnecting group %d from" - " container", group->groupid); - } - return ret; - } - group->container = container; - QLIST_INSERT_HEAD(&container->group_list, group, container_next); - vfio_kvm_device_add_group(group); - return 0; - } - } - - fd = qemu_open_old("/dev/vfio/vfio", O_RDWR); - if (fd < 0) { - error_setg_errno(errp, errno, "failed to open /dev/vfio/vfio"); - ret = -errno; - goto put_space_exit; - } - - ret = ioctl(fd, VFIO_GET_API_VERSION); - if (ret != VFIO_API_VERSION) { - error_setg(errp, "supported vfio version: %d, " - "reported version: %d", VFIO_API_VERSION, ret); - ret = -EINVAL; - goto close_fd_exit; - } - - container = g_malloc0(sizeof(*container)); - container->space = space; - container->fd = fd; - container->error = NULL; - container->dirty_pages_supported = false; - container->dma_max_mappings = 0; - QLIST_INIT(&container->giommu_list); - QLIST_INIT(&container->hostwin_list); - QLIST_INIT(&container->vrdl_list); - - ret = vfio_init_container(container, group->fd, errp); - if (ret) { - goto free_container_exit; - } - - ret = vfio_ram_block_discard_disable(container, true); - if (ret) { - error_setg_errno(errp, -ret, "Cannot set discarding of RAM broken"); - goto free_container_exit; - } - - switch (container->iommu_type) { - case VFIO_TYPE1v2_IOMMU: - case VFIO_TYPE1_IOMMU: - { - struct vfio_iommu_type1_info *info; - - ret = vfio_get_iommu_info(container, &info); - if (ret) { - error_setg_errno(errp, -ret, "Failed to get VFIO IOMMU info"); - goto enable_discards_exit; - } - - if (info->flags & VFIO_IOMMU_INFO_PGSIZES) { - container->pgsizes = info->iova_pgsizes; - } else { - container->pgsizes = qemu_real_host_page_size(); - } - - if (!vfio_get_info_dma_avail(info, &container->dma_max_mappings)) { - container->dma_max_mappings = 65535; - } - vfio_get_iommu_info_migration(container, info); - g_free(info); - - /* - * FIXME: We should parse VFIO_IOMMU_TYPE1_INFO_CAP_IOVA_RANGE - * information to get the actual window extent rather than assume - * a 64-bit IOVA address space. - */ - vfio_host_win_add(container, 0, (hwaddr)-1, container->pgsizes); - - break; - } - case VFIO_SPAPR_TCE_v2_IOMMU: - case VFIO_SPAPR_TCE_IOMMU: - { - struct vfio_iommu_spapr_tce_info info; - bool v2 = container->iommu_type == VFIO_SPAPR_TCE_v2_IOMMU; - - /* - * The host kernel code implementing VFIO_IOMMU_DISABLE is called - * when container fd is closed so we do not call it explicitly - * in this file. - */ - if (!v2) { - ret = ioctl(fd, VFIO_IOMMU_ENABLE); - if (ret) { - error_setg_errno(errp, errno, "failed to enable container"); - ret = -errno; - goto enable_discards_exit; - } - } else { - container->prereg_listener = vfio_prereg_listener; - - memory_listener_register(&container->prereg_listener, - &address_space_memory); - if (container->error) { - memory_listener_unregister(&container->prereg_listener); - ret = -1; - error_propagate_prepend(errp, container->error, - "RAM memory listener initialization failed: "); - goto enable_discards_exit; - } - } - - info.argsz = sizeof(info); - ret = ioctl(fd, VFIO_IOMMU_SPAPR_TCE_GET_INFO, &info); - if (ret) { - error_setg_errno(errp, errno, - "VFIO_IOMMU_SPAPR_TCE_GET_INFO failed"); - ret = -errno; - if (v2) { - memory_listener_unregister(&container->prereg_listener); - } - goto enable_discards_exit; - } - - if (v2) { - container->pgsizes = info.ddw.pgsizes; - /* - * There is a default window in just created container. - * To make region_add/del simpler, we better remove this - * window now and let those iommu_listener callbacks - * create/remove them when needed. - */ - ret = vfio_spapr_remove_window(container, info.dma32_window_start); - if (ret) { - error_setg_errno(errp, -ret, - "failed to remove existing window"); - goto enable_discards_exit; - } - } else { - /* The default table uses 4K pages */ - container->pgsizes = 0x1000; - vfio_host_win_add(container, info.dma32_window_start, - info.dma32_window_start + - info.dma32_window_size - 1, - 0x1000); - } - } - } - - vfio_kvm_device_add_group(group); - - QLIST_INIT(&container->group_list); - QLIST_INSERT_HEAD(&space->containers, container, next); - - group->container = container; - QLIST_INSERT_HEAD(&container->group_list, group, container_next); - - container->listener = vfio_memory_listener; - - memory_listener_register(&container->listener, container->space->as); - - if (container->error) { - ret = -1; - error_propagate_prepend(errp, container->error, - "memory listener initialization failed: "); - goto listener_release_exit; - } - - container->initialized = true; - - return 0; -listener_release_exit: - QLIST_REMOVE(group, container_next); - QLIST_REMOVE(container, next); - vfio_kvm_device_del_group(group); - vfio_listener_release(container); - -enable_discards_exit: - vfio_ram_block_discard_disable(container, false); - -free_container_exit: - g_free(container); - -close_fd_exit: - close(fd); - -put_space_exit: - vfio_put_address_space(space); - - return ret; -} - -static void vfio_disconnect_container(VFIOGroup *group) -{ - VFIOContainer *container = group->container; - - QLIST_REMOVE(group, container_next); - group->container = NULL; - - /* - * Explicitly release the listener first before unset container, - * since unset may destroy the backend container if it's the last - * group. - */ - if (QLIST_EMPTY(&container->group_list)) { - vfio_listener_release(container); - } - - if (ioctl(group->fd, VFIO_GROUP_UNSET_CONTAINER, &container->fd)) { - error_report("vfio: error disconnecting group %d from container", - group->groupid); - } - - if (QLIST_EMPTY(&container->group_list)) { - VFIOAddressSpace *space = container->space; - VFIOGuestIOMMU *giommu, *tmp; - VFIOHostDMAWindow *hostwin, *next; - - QLIST_REMOVE(container, next); - - QLIST_FOREACH_SAFE(giommu, &container->giommu_list, giommu_next, tmp) { - memory_region_unregister_iommu_notifier( - MEMORY_REGION(giommu->iommu_mr), &giommu->n); - QLIST_REMOVE(giommu, giommu_next); - g_free(giommu); - } - - QLIST_FOREACH_SAFE(hostwin, &container->hostwin_list, hostwin_next, - next) { - QLIST_REMOVE(hostwin, hostwin_next); - g_free(hostwin); - } - - trace_vfio_disconnect_container(container->fd); - close(container->fd); - g_free(container); - - vfio_put_address_space(space); - } -} - -static VFIOGroup *vfio_get_group(int groupid, AddressSpace *as, Error **errp) -{ - VFIOGroup *group; - char path[32]; - struct vfio_group_status status = { .argsz = sizeof(status) }; - - QLIST_FOREACH(group, &vfio_group_list, next) { - if (group->groupid == groupid) { - /* Found it. Now is it already in the right context? */ - if (group->container->space->as == as) { - return group; - } else { - error_setg(errp, "group %d used in multiple address spaces", - group->groupid); - return NULL; - } - } - } - - group = g_malloc0(sizeof(*group)); - - snprintf(path, sizeof(path), "/dev/vfio/%d", groupid); - group->fd = qemu_open_old(path, O_RDWR); - if (group->fd < 0) { - error_setg_errno(errp, errno, "failed to open %s", path); - goto free_group_exit; - } - - if (ioctl(group->fd, VFIO_GROUP_GET_STATUS, &status)) { - error_setg_errno(errp, errno, "failed to get group %d status", groupid); - goto close_fd_exit; - } - - if (!(status.flags & VFIO_GROUP_FLAGS_VIABLE)) { - error_setg(errp, "group %d is not viable", groupid); - error_append_hint(errp, - "Please ensure all devices within the iommu_group " - "are bound to their vfio bus driver.\n"); - goto close_fd_exit; - } - - group->groupid = groupid; - QLIST_INIT(&group->device_list); - - if (vfio_connect_container(group, as, errp)) { - error_prepend(errp, "failed to setup container for group %d: ", - groupid); - goto close_fd_exit; - } - - QLIST_INSERT_HEAD(&vfio_group_list, group, next); - - return group; - -close_fd_exit: - close(group->fd); - -free_group_exit: - g_free(group); - - return NULL; -} - -static void vfio_put_group(VFIOGroup *group) -{ - if (!group || !QLIST_EMPTY(&group->device_list)) { - return; - } - - if (!group->ram_block_discard_allowed) { - vfio_ram_block_discard_disable(group->container, false); - } - vfio_kvm_device_del_group(group); - vfio_disconnect_container(group); - QLIST_REMOVE(group, next); - trace_vfio_put_group(group->fd); - close(group->fd); - g_free(group); -} - struct vfio_device_info *vfio_get_device_info(int fd) { struct vfio_device_info *info; @@ -2415,256 +1545,3 @@ retry: return info; } - -static int vfio_get_device(VFIOGroup *group, const char *name, - VFIODevice *vbasedev, Error **errp) -{ - g_autofree struct vfio_device_info *info = NULL; - int fd; - - fd = ioctl(group->fd, VFIO_GROUP_GET_DEVICE_FD, name); - if (fd < 0) { - error_setg_errno(errp, errno, "error getting device from group %d", - group->groupid); - error_append_hint(errp, - "Verify all devices in group %d are bound to vfio- " - "or pci-stub and not already in use\n", group->groupid); - return fd; - } - - info = vfio_get_device_info(fd); - if (!info) { - error_setg_errno(errp, errno, "error getting device info"); - close(fd); - return -1; - } - - /* - * Set discarding of RAM as not broken for this group if the driver knows - * the device operates compatibly with discarding. Setting must be - * consistent per group, but since compatibility is really only possible - * with mdev currently, we expect singleton groups. - */ - if (vbasedev->ram_block_discard_allowed != - group->ram_block_discard_allowed) { - if (!QLIST_EMPTY(&group->device_list)) { - error_setg(errp, "Inconsistent setting of support for discarding " - "RAM (e.g., balloon) within group"); - close(fd); - return -1; - } - - if (!group->ram_block_discard_allowed) { - group->ram_block_discard_allowed = true; - vfio_ram_block_discard_disable(group->container, false); - } - } - - vbasedev->fd = fd; - vbasedev->group = group; - QLIST_INSERT_HEAD(&group->device_list, vbasedev, next); - - vbasedev->num_irqs = info->num_irqs; - vbasedev->num_regions = info->num_regions; - vbasedev->flags = info->flags; - - trace_vfio_get_device(name, info->flags, info->num_regions, info->num_irqs); - - vbasedev->reset_works = !!(info->flags & VFIO_DEVICE_FLAGS_RESET); - - return 0; -} - -static void vfio_put_base_device(VFIODevice *vbasedev) -{ - if (!vbasedev->group) { - return; - } - QLIST_REMOVE(vbasedev, next); - vbasedev->group = NULL; - trace_vfio_put_base_device(vbasedev->fd); - close(vbasedev->fd); -} - -/* - * Interfaces for IBM EEH (Enhanced Error Handling) - */ -static bool vfio_eeh_container_ok(VFIOContainer *container) -{ - /* - * As of 2016-03-04 (linux-4.5) the host kernel EEH/VFIO - * implementation is broken if there are multiple groups in a - * container. The hardware works in units of Partitionable - * Endpoints (== IOMMU groups) and the EEH operations naively - * iterate across all groups in the container, without any logic - * to make sure the groups have their state synchronized. For - * certain operations (ENABLE) that might be ok, until an error - * occurs, but for others (GET_STATE) it's clearly broken. - */ - - /* - * XXX Once fixed kernels exist, test for them here - */ - - if (QLIST_EMPTY(&container->group_list)) { - return false; - } - - if (QLIST_NEXT(QLIST_FIRST(&container->group_list), container_next)) { - return false; - } - - return true; -} - -static int vfio_eeh_container_op(VFIOContainer *container, uint32_t op) -{ - struct vfio_eeh_pe_op pe_op = { - .argsz = sizeof(pe_op), - .op = op, - }; - int ret; - - if (!vfio_eeh_container_ok(container)) { - error_report("vfio/eeh: EEH_PE_OP 0x%x: " - "kernel requires a container with exactly one group", op); - return -EPERM; - } - - ret = ioctl(container->fd, VFIO_EEH_PE_OP, &pe_op); - if (ret < 0) { - error_report("vfio/eeh: EEH_PE_OP 0x%x failed: %m", op); - return -errno; - } - - return ret; -} - -static VFIOContainer *vfio_eeh_as_container(AddressSpace *as) -{ - VFIOAddressSpace *space = vfio_get_address_space(as); - VFIOContainer *container = NULL; - - if (QLIST_EMPTY(&space->containers)) { - /* No containers to act on */ - goto out; - } - - container = QLIST_FIRST(&space->containers); - - if (QLIST_NEXT(container, next)) { - /* We don't yet have logic to synchronize EEH state across - * multiple containers */ - container = NULL; - goto out; - } - -out: - vfio_put_address_space(space); - return container; -} - -bool vfio_eeh_as_ok(AddressSpace *as) -{ - VFIOContainer *container = vfio_eeh_as_container(as); - - return (container != NULL) && vfio_eeh_container_ok(container); -} - -int vfio_eeh_as_op(AddressSpace *as, uint32_t op) -{ - VFIOContainer *container = vfio_eeh_as_container(as); - - if (!container) { - return -ENODEV; - } - return vfio_eeh_container_op(container, op); -} - -static int vfio_device_groupid(VFIODevice *vbasedev, Error **errp) -{ - char *tmp, group_path[PATH_MAX], *group_name; - int ret, groupid; - ssize_t len; - - tmp = g_strdup_printf("%s/iommu_group", vbasedev->sysfsdev); - len = readlink(tmp, group_path, sizeof(group_path)); - g_free(tmp); - - if (len <= 0 || len >= sizeof(group_path)) { - ret = len < 0 ? -errno : -ENAMETOOLONG; - error_setg_errno(errp, -ret, "no iommu_group found"); - return ret; - } - - group_path[len] = 0; - - group_name = basename(group_path); - if (sscanf(group_name, "%d", &groupid) != 1) { - error_setg_errno(errp, errno, "failed to read %s", group_path); - return -errno; - } - return groupid; -} - -/* - * vfio_attach_device: attach a device to a security context - * @name and @vbasedev->name are likely to be different depending - * on the type of the device, hence the need for passing @name - */ -int vfio_attach_device(char *name, VFIODevice *vbasedev, - AddressSpace *as, Error **errp) -{ - int groupid = vfio_device_groupid(vbasedev, errp); - VFIODevice *vbasedev_iter; - VFIOGroup *group; - VFIOContainer *container; - int ret; - - if (groupid < 0) { - return groupid; - } - - trace_vfio_attach_device(vbasedev->name, groupid); - - group = vfio_get_group(groupid, as, errp); - if (!group) { - return -ENOENT; - } - - QLIST_FOREACH(vbasedev_iter, &group->device_list, next) { - if (strcmp(vbasedev_iter->name, vbasedev->name) == 0) { - error_setg(errp, "device is already attached"); - vfio_put_group(group); - return -EBUSY; - } - } - ret = vfio_get_device(group, name, vbasedev, errp); - if (ret) { - vfio_put_group(group); - return ret; - } - - container = group->container; - vbasedev->container = container; - QLIST_INSERT_HEAD(&container->device_list, vbasedev, container_next); - QLIST_INSERT_HEAD(&vfio_device_list, vbasedev, global_next); - - return ret; -} - -void vfio_detach_device(VFIODevice *vbasedev) -{ - VFIOGroup *group = vbasedev->group; - - if (!vbasedev->container) { - return; - } - - QLIST_REMOVE(vbasedev, global_next); - QLIST_REMOVE(vbasedev, container_next); - vbasedev->container = NULL; - trace_vfio_detach_device(vbasedev->name, group->groupid); - vfio_put_base_device(vbasedev); - vfio_put_group(group); -} diff --git a/hw/vfio/container.c b/hw/vfio/container.c new file mode 100644 index 0000000000..adc467210f --- /dev/null +++ b/hw/vfio/container.c @@ -0,0 +1,1161 @@ +/* + * generic functions used by VFIO devices + * + * Copyright Red Hat, Inc. 2012 + * + * Authors: + * Alex Williamson + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + * + * Based on qemu-kvm device-assignment: + * Adapted for KVM by Qumranet. + * Copyright (c) 2007, Neocleus, Alex Novik (alex@neocleus.com) + * Copyright (c) 2007, Neocleus, Guy Zana (guy@neocleus.com) + * Copyright (C) 2008, Qumranet, Amit Shah (amit.shah@qumranet.com) + * Copyright (C) 2008, Red Hat, Amit Shah (amit.shah@redhat.com) + * Copyright (C) 2008, IBM, Muli Ben-Yehuda (muli@il.ibm.com) + */ + +#include "qemu/osdep.h" +#include +#ifdef CONFIG_KVM +#include +#endif +#include + +#include "hw/vfio/vfio-common.h" +#include "hw/vfio/vfio.h" +#include "exec/address-spaces.h" +#include "exec/memory.h" +#include "exec/ram_addr.h" +#include "hw/hw.h" +#include "qemu/error-report.h" +#include "qemu/range.h" +#include "sysemu/kvm.h" +#include "sysemu/reset.h" +#include "trace.h" +#include "qapi/error.h" +#include "migration/migration.h" + +VFIOGroupList vfio_group_list = + QLIST_HEAD_INITIALIZER(vfio_group_list); + +static int vfio_ram_block_discard_disable(VFIOContainer *container, bool state) +{ + switch (container->iommu_type) { + case VFIO_TYPE1v2_IOMMU: + case VFIO_TYPE1_IOMMU: + /* + * We support coordinated discarding of RAM via the RamDiscardManager. + */ + return ram_block_uncoordinated_discard_disable(state); + default: + /* + * VFIO_SPAPR_TCE_IOMMU most probably works just fine with + * RamDiscardManager, however, it is completely untested. + * + * VFIO_SPAPR_TCE_v2_IOMMU with "DMA memory preregistering" does + * completely the opposite of managing mapping/pinning dynamically as + * required by RamDiscardManager. We would have to special-case sections + * with a RamDiscardManager. + */ + return ram_block_discard_disable(state); + } +} + +static int vfio_dma_unmap_bitmap(VFIOContainer *container, + hwaddr iova, ram_addr_t size, + IOMMUTLBEntry *iotlb) +{ + struct vfio_iommu_type1_dma_unmap *unmap; + struct vfio_bitmap *bitmap; + VFIOBitmap vbmap; + int ret; + + ret = vfio_bitmap_alloc(&vbmap, size); + if (ret) { + return ret; + } + + unmap = g_malloc0(sizeof(*unmap) + sizeof(*bitmap)); + + unmap->argsz = sizeof(*unmap) + sizeof(*bitmap); + unmap->iova = iova; + unmap->size = size; + unmap->flags |= VFIO_DMA_UNMAP_FLAG_GET_DIRTY_BITMAP; + bitmap = (struct vfio_bitmap *)&unmap->data; + + /* + * cpu_physical_memory_set_dirty_lebitmap() supports pages in bitmap of + * qemu_real_host_page_size to mark those dirty. Hence set bitmap_pgsize + * to qemu_real_host_page_size. + */ + bitmap->pgsize = qemu_real_host_page_size(); + bitmap->size = vbmap.size; + bitmap->data = (__u64 *)vbmap.bitmap; + + if (vbmap.size > container->max_dirty_bitmap_size) { + error_report("UNMAP: Size of bitmap too big 0x%"PRIx64, vbmap.size); + ret = -E2BIG; + goto unmap_exit; + } + + ret = ioctl(container->fd, VFIO_IOMMU_UNMAP_DMA, unmap); + if (!ret) { + cpu_physical_memory_set_dirty_lebitmap(vbmap.bitmap, + iotlb->translated_addr, vbmap.pages); + } else { + error_report("VFIO_UNMAP_DMA with DIRTY_BITMAP : %m"); + } + +unmap_exit: + g_free(unmap); + g_free(vbmap.bitmap); + + return ret; +} + +/* + * DMA - Mapping and unmapping for the "type1" IOMMU interface used on x86 + */ +int vfio_dma_unmap(VFIOContainer *container, hwaddr iova, + ram_addr_t size, IOMMUTLBEntry *iotlb) +{ + struct vfio_iommu_type1_dma_unmap unmap = { + .argsz = sizeof(unmap), + .flags = 0, + .iova = iova, + .size = size, + }; + bool need_dirty_sync = false; + int ret; + + if (iotlb && vfio_devices_all_running_and_mig_active(container)) { + if (!vfio_devices_all_device_dirty_tracking(container) && + container->dirty_pages_supported) { + return vfio_dma_unmap_bitmap(container, iova, size, iotlb); + } + + need_dirty_sync = true; + } + + while (ioctl(container->fd, VFIO_IOMMU_UNMAP_DMA, &unmap)) { + /* + * The type1 backend has an off-by-one bug in the kernel (71a7d3d78e3c + * v4.15) where an overflow in its wrap-around check prevents us from + * unmapping the last page of the address space. Test for the error + * condition and re-try the unmap excluding the last page. The + * expectation is that we've never mapped the last page anyway and this + * unmap request comes via vIOMMU support which also makes it unlikely + * that this page is used. This bug was introduced well after type1 v2 + * support was introduced, so we shouldn't need to test for v1. A fix + * is queued for kernel v5.0 so this workaround can be removed once + * affected kernels are sufficiently deprecated. + */ + if (errno == EINVAL && unmap.size && !(unmap.iova + unmap.size) && + container->iommu_type == VFIO_TYPE1v2_IOMMU) { + trace_vfio_dma_unmap_overflow_workaround(); + unmap.size -= 1ULL << ctz64(container->pgsizes); + continue; + } + error_report("VFIO_UNMAP_DMA failed: %s", strerror(errno)); + return -errno; + } + + if (need_dirty_sync) { + ret = vfio_get_dirty_bitmap(container, iova, size, + iotlb->translated_addr); + if (ret) { + return ret; + } + } + + return 0; +} + +int vfio_dma_map(VFIOContainer *container, hwaddr iova, + ram_addr_t size, void *vaddr, bool readonly) +{ + struct vfio_iommu_type1_dma_map map = { + .argsz = sizeof(map), + .flags = VFIO_DMA_MAP_FLAG_READ, + .vaddr = (__u64)(uintptr_t)vaddr, + .iova = iova, + .size = size, + }; + + if (!readonly) { + map.flags |= VFIO_DMA_MAP_FLAG_WRITE; + } + + /* + * Try the mapping, if it fails with EBUSY, unmap the region and try + * again. This shouldn't be necessary, but we sometimes see it in + * the VGA ROM space. + */ + if (ioctl(container->fd, VFIO_IOMMU_MAP_DMA, &map) == 0 || + (errno == EBUSY && vfio_dma_unmap(container, iova, size, NULL) == 0 && + ioctl(container->fd, VFIO_IOMMU_MAP_DMA, &map) == 0)) { + return 0; + } + + error_report("VFIO_MAP_DMA failed: %s", strerror(errno)); + return -errno; +} + +int vfio_container_add_section_window(VFIOContainer *container, + MemoryRegionSection *section, + Error **errp) +{ + VFIOHostDMAWindow *hostwin; + hwaddr pgsize = 0; + int ret; + + if (container->iommu_type != VFIO_SPAPR_TCE_v2_IOMMU) { + return 0; + } + + /* For now intersections are not allowed, we may relax this later */ + QLIST_FOREACH(hostwin, &container->hostwin_list, hostwin_next) { + if (ranges_overlap(hostwin->min_iova, + hostwin->max_iova - hostwin->min_iova + 1, + section->offset_within_address_space, + int128_get64(section->size))) { + error_setg(errp, + "region [0x%"PRIx64",0x%"PRIx64"] overlaps with existing" + "host DMA window [0x%"PRIx64",0x%"PRIx64"]", + section->offset_within_address_space, + section->offset_within_address_space + + int128_get64(section->size) - 1, + hostwin->min_iova, hostwin->max_iova); + return -EINVAL; + } + } + + ret = vfio_spapr_create_window(container, section, &pgsize); + if (ret) { + error_setg_errno(errp, -ret, "Failed to create SPAPR window"); + return ret; + } + + vfio_host_win_add(container, section->offset_within_address_space, + section->offset_within_address_space + + int128_get64(section->size) - 1, pgsize); +#ifdef CONFIG_KVM + if (kvm_enabled()) { + VFIOGroup *group; + IOMMUMemoryRegion *iommu_mr = IOMMU_MEMORY_REGION(section->mr); + struct kvm_vfio_spapr_tce param; + struct kvm_device_attr attr = { + .group = KVM_DEV_VFIO_GROUP, + .attr = KVM_DEV_VFIO_GROUP_SET_SPAPR_TCE, + .addr = (uint64_t)(unsigned long)¶m, + }; + + if (!memory_region_iommu_get_attr(iommu_mr, IOMMU_ATTR_SPAPR_TCE_FD, + ¶m.tablefd)) { + QLIST_FOREACH(group, &container->group_list, container_next) { + param.groupfd = group->fd; + if (ioctl(vfio_kvm_device_fd, KVM_SET_DEVICE_ATTR, &attr)) { + error_setg_errno(errp, errno, + "vfio: failed GROUP_SET_SPAPR_TCE for " + "KVM VFIO device %d and group fd %d", + param.tablefd, param.groupfd); + return -errno; + } + trace_vfio_spapr_group_attach(param.groupfd, param.tablefd); + } + } + } +#endif + return 0; +} + +void vfio_container_del_section_window(VFIOContainer *container, + MemoryRegionSection *section) +{ + if (container->iommu_type != VFIO_SPAPR_TCE_v2_IOMMU) { + return; + } + + vfio_spapr_remove_window(container, + section->offset_within_address_space); + if (vfio_host_win_del(container, + section->offset_within_address_space, + section->offset_within_address_space + + int128_get64(section->size) - 1) < 0) { + hw_error("%s: Cannot delete missing window at %"HWADDR_PRIx, + __func__, section->offset_within_address_space); + } +} + +int vfio_set_dirty_page_tracking(VFIOContainer *container, bool start) +{ + int ret; + struct vfio_iommu_type1_dirty_bitmap dirty = { + .argsz = sizeof(dirty), + }; + + if (!container->dirty_pages_supported) { + return 0; + } + + if (start) { + dirty.flags = VFIO_IOMMU_DIRTY_PAGES_FLAG_START; + } else { + dirty.flags = VFIO_IOMMU_DIRTY_PAGES_FLAG_STOP; + } + + ret = ioctl(container->fd, VFIO_IOMMU_DIRTY_PAGES, &dirty); + if (ret) { + ret = -errno; + error_report("Failed to set dirty tracking flag 0x%x errno: %d", + dirty.flags, errno); + } + + return ret; +} + +int vfio_query_dirty_bitmap(VFIOContainer *container, VFIOBitmap *vbmap, + hwaddr iova, hwaddr size) +{ + struct vfio_iommu_type1_dirty_bitmap *dbitmap; + struct vfio_iommu_type1_dirty_bitmap_get *range; + int ret; + + dbitmap = g_malloc0(sizeof(*dbitmap) + sizeof(*range)); + + dbitmap->argsz = sizeof(*dbitmap) + sizeof(*range); + dbitmap->flags = VFIO_IOMMU_DIRTY_PAGES_FLAG_GET_BITMAP; + range = (struct vfio_iommu_type1_dirty_bitmap_get *)&dbitmap->data; + range->iova = iova; + range->size = size; + + /* + * cpu_physical_memory_set_dirty_lebitmap() supports pages in bitmap of + * qemu_real_host_page_size to mark those dirty. Hence set bitmap's pgsize + * to qemu_real_host_page_size. + */ + range->bitmap.pgsize = qemu_real_host_page_size(); + range->bitmap.size = vbmap->size; + range->bitmap.data = (__u64 *)vbmap->bitmap; + + ret = ioctl(container->fd, VFIO_IOMMU_DIRTY_PAGES, dbitmap); + if (ret) { + ret = -errno; + error_report("Failed to get dirty bitmap for iova: 0x%"PRIx64 + " size: 0x%"PRIx64" err: %d", (uint64_t)range->iova, + (uint64_t)range->size, errno); + } + + g_free(dbitmap); + + return ret; +} + +static void vfio_listener_release(VFIOContainer *container) +{ + memory_listener_unregister(&container->listener); + if (container->iommu_type == VFIO_SPAPR_TCE_v2_IOMMU) { + memory_listener_unregister(&container->prereg_listener); + } +} + +static struct vfio_info_cap_header * +vfio_get_iommu_type1_info_cap(struct vfio_iommu_type1_info *info, uint16_t id) +{ + if (!(info->flags & VFIO_IOMMU_INFO_CAPS)) { + return NULL; + } + + return vfio_get_cap((void *)info, info->cap_offset, id); +} + +bool vfio_get_info_dma_avail(struct vfio_iommu_type1_info *info, + unsigned int *avail) +{ + struct vfio_info_cap_header *hdr; + struct vfio_iommu_type1_info_dma_avail *cap; + + /* If the capability cannot be found, assume no DMA limiting */ + hdr = vfio_get_iommu_type1_info_cap(info, + VFIO_IOMMU_TYPE1_INFO_DMA_AVAIL); + if (hdr == NULL) { + return false; + } + + if (avail != NULL) { + cap = (void *) hdr; + *avail = cap->avail; + } + + return true; +} + +static void vfio_kvm_device_add_group(VFIOGroup *group) +{ + Error *err = NULL; + + if (vfio_kvm_device_add_fd(group->fd, &err)) { + error_reportf_err(err, "group ID %d: ", group->groupid); + } +} + +static void vfio_kvm_device_del_group(VFIOGroup *group) +{ + Error *err = NULL; + + if (vfio_kvm_device_del_fd(group->fd, &err)) { + error_reportf_err(err, "group ID %d: ", group->groupid); + } +} + +/* + * vfio_get_iommu_type - selects the richest iommu_type (v2 first) + */ +static int vfio_get_iommu_type(VFIOContainer *container, + Error **errp) +{ + int iommu_types[] = { VFIO_TYPE1v2_IOMMU, VFIO_TYPE1_IOMMU, + VFIO_SPAPR_TCE_v2_IOMMU, VFIO_SPAPR_TCE_IOMMU }; + int i; + + for (i = 0; i < ARRAY_SIZE(iommu_types); i++) { + if (ioctl(container->fd, VFIO_CHECK_EXTENSION, iommu_types[i])) { + return iommu_types[i]; + } + } + error_setg(errp, "No available IOMMU models"); + return -EINVAL; +} + +static int vfio_init_container(VFIOContainer *container, int group_fd, + Error **errp) +{ + int iommu_type, ret; + + iommu_type = vfio_get_iommu_type(container, errp); + if (iommu_type < 0) { + return iommu_type; + } + + ret = ioctl(group_fd, VFIO_GROUP_SET_CONTAINER, &container->fd); + if (ret) { + error_setg_errno(errp, errno, "Failed to set group container"); + return -errno; + } + + while (ioctl(container->fd, VFIO_SET_IOMMU, iommu_type)) { + if (iommu_type == VFIO_SPAPR_TCE_v2_IOMMU) { + /* + * On sPAPR, despite the IOMMU subdriver always advertises v1 and + * v2, the running platform may not support v2 and there is no + * way to guess it until an IOMMU group gets added to the container. + * So in case it fails with v2, try v1 as a fallback. + */ + iommu_type = VFIO_SPAPR_TCE_IOMMU; + continue; + } + error_setg_errno(errp, errno, "Failed to set iommu for container"); + return -errno; + } + + container->iommu_type = iommu_type; + return 0; +} + +static int vfio_get_iommu_info(VFIOContainer *container, + struct vfio_iommu_type1_info **info) +{ + + size_t argsz = sizeof(struct vfio_iommu_type1_info); + + *info = g_new0(struct vfio_iommu_type1_info, 1); +again: + (*info)->argsz = argsz; + + if (ioctl(container->fd, VFIO_IOMMU_GET_INFO, *info)) { + g_free(*info); + *info = NULL; + return -errno; + } + + if (((*info)->argsz > argsz)) { + argsz = (*info)->argsz; + *info = g_realloc(*info, argsz); + goto again; + } + + return 0; +} + +static struct vfio_info_cap_header * +vfio_get_iommu_info_cap(struct vfio_iommu_type1_info *info, uint16_t id) +{ + struct vfio_info_cap_header *hdr; + void *ptr = info; + + if (!(info->flags & VFIO_IOMMU_INFO_CAPS)) { + return NULL; + } + + for (hdr = ptr + info->cap_offset; hdr != ptr; hdr = ptr + hdr->next) { + if (hdr->id == id) { + return hdr; + } + } + + return NULL; +} + +static void vfio_get_iommu_info_migration(VFIOContainer *container, + struct vfio_iommu_type1_info *info) +{ + struct vfio_info_cap_header *hdr; + struct vfio_iommu_type1_info_cap_migration *cap_mig; + + hdr = vfio_get_iommu_info_cap(info, VFIO_IOMMU_TYPE1_INFO_CAP_MIGRATION); + if (!hdr) { + return; + } + + cap_mig = container_of(hdr, struct vfio_iommu_type1_info_cap_migration, + header); + + /* + * cpu_physical_memory_set_dirty_lebitmap() supports pages in bitmap of + * qemu_real_host_page_size to mark those dirty. + */ + if (cap_mig->pgsize_bitmap & qemu_real_host_page_size()) { + container->dirty_pages_supported = true; + container->max_dirty_bitmap_size = cap_mig->max_dirty_bitmap_size; + container->dirty_pgsizes = cap_mig->pgsize_bitmap; + } +} + +static int vfio_connect_container(VFIOGroup *group, AddressSpace *as, + Error **errp) +{ + VFIOContainer *container; + int ret, fd; + VFIOAddressSpace *space; + + space = vfio_get_address_space(as); + + /* + * VFIO is currently incompatible with discarding of RAM insofar as the + * madvise to purge (zap) the page from QEMU's address space does not + * interact with the memory API and therefore leaves stale virtual to + * physical mappings in the IOMMU if the page was previously pinned. We + * therefore set discarding broken for each group added to a container, + * whether the container is used individually or shared. This provides + * us with options to allow devices within a group to opt-in and allow + * discarding, so long as it is done consistently for a group (for instance + * if the device is an mdev device where it is known that the host vendor + * driver will never pin pages outside of the working set of the guest + * driver, which would thus not be discarding candidates). + * + * The first opportunity to induce pinning occurs here where we attempt to + * attach the group to existing containers within the AddressSpace. If any + * pages are already zapped from the virtual address space, such as from + * previous discards, new pinning will cause valid mappings to be + * re-established. Likewise, when the overall MemoryListener for a new + * container is registered, a replay of mappings within the AddressSpace + * will occur, re-establishing any previously zapped pages as well. + * + * Especially virtio-balloon is currently only prevented from discarding + * new memory, it will not yet set ram_block_discard_set_required() and + * therefore, neither stops us here or deals with the sudden memory + * consumption of inflated memory. + * + * We do support discarding of memory coordinated via the RamDiscardManager + * with some IOMMU types. vfio_ram_block_discard_disable() handles the + * details once we know which type of IOMMU we are using. + */ + + QLIST_FOREACH(container, &space->containers, next) { + if (!ioctl(group->fd, VFIO_GROUP_SET_CONTAINER, &container->fd)) { + ret = vfio_ram_block_discard_disable(container, true); + if (ret) { + error_setg_errno(errp, -ret, + "Cannot set discarding of RAM broken"); + if (ioctl(group->fd, VFIO_GROUP_UNSET_CONTAINER, + &container->fd)) { + error_report("vfio: error disconnecting group %d from" + " container", group->groupid); + } + return ret; + } + group->container = container; + QLIST_INSERT_HEAD(&container->group_list, group, container_next); + vfio_kvm_device_add_group(group); + return 0; + } + } + + fd = qemu_open_old("/dev/vfio/vfio", O_RDWR); + if (fd < 0) { + error_setg_errno(errp, errno, "failed to open /dev/vfio/vfio"); + ret = -errno; + goto put_space_exit; + } + + ret = ioctl(fd, VFIO_GET_API_VERSION); + if (ret != VFIO_API_VERSION) { + error_setg(errp, "supported vfio version: %d, " + "reported version: %d", VFIO_API_VERSION, ret); + ret = -EINVAL; + goto close_fd_exit; + } + + container = g_malloc0(sizeof(*container)); + container->space = space; + container->fd = fd; + container->error = NULL; + container->dirty_pages_supported = false; + container->dma_max_mappings = 0; + QLIST_INIT(&container->giommu_list); + QLIST_INIT(&container->hostwin_list); + QLIST_INIT(&container->vrdl_list); + + ret = vfio_init_container(container, group->fd, errp); + if (ret) { + goto free_container_exit; + } + + ret = vfio_ram_block_discard_disable(container, true); + if (ret) { + error_setg_errno(errp, -ret, "Cannot set discarding of RAM broken"); + goto free_container_exit; + } + + switch (container->iommu_type) { + case VFIO_TYPE1v2_IOMMU: + case VFIO_TYPE1_IOMMU: + { + struct vfio_iommu_type1_info *info; + + ret = vfio_get_iommu_info(container, &info); + if (ret) { + error_setg_errno(errp, -ret, "Failed to get VFIO IOMMU info"); + goto enable_discards_exit; + } + + if (info->flags & VFIO_IOMMU_INFO_PGSIZES) { + container->pgsizes = info->iova_pgsizes; + } else { + container->pgsizes = qemu_real_host_page_size(); + } + + if (!vfio_get_info_dma_avail(info, &container->dma_max_mappings)) { + container->dma_max_mappings = 65535; + } + vfio_get_iommu_info_migration(container, info); + g_free(info); + + /* + * FIXME: We should parse VFIO_IOMMU_TYPE1_INFO_CAP_IOVA_RANGE + * information to get the actual window extent rather than assume + * a 64-bit IOVA address space. + */ + vfio_host_win_add(container, 0, (hwaddr)-1, container->pgsizes); + + break; + } + case VFIO_SPAPR_TCE_v2_IOMMU: + case VFIO_SPAPR_TCE_IOMMU: + { + struct vfio_iommu_spapr_tce_info info; + bool v2 = container->iommu_type == VFIO_SPAPR_TCE_v2_IOMMU; + + /* + * The host kernel code implementing VFIO_IOMMU_DISABLE is called + * when container fd is closed so we do not call it explicitly + * in this file. + */ + if (!v2) { + ret = ioctl(fd, VFIO_IOMMU_ENABLE); + if (ret) { + error_setg_errno(errp, errno, "failed to enable container"); + ret = -errno; + goto enable_discards_exit; + } + } else { + container->prereg_listener = vfio_prereg_listener; + + memory_listener_register(&container->prereg_listener, + &address_space_memory); + if (container->error) { + memory_listener_unregister(&container->prereg_listener); + ret = -1; + error_propagate_prepend(errp, container->error, + "RAM memory listener initialization failed: "); + goto enable_discards_exit; + } + } + + info.argsz = sizeof(info); + ret = ioctl(fd, VFIO_IOMMU_SPAPR_TCE_GET_INFO, &info); + if (ret) { + error_setg_errno(errp, errno, + "VFIO_IOMMU_SPAPR_TCE_GET_INFO failed"); + ret = -errno; + if (v2) { + memory_listener_unregister(&container->prereg_listener); + } + goto enable_discards_exit; + } + + if (v2) { + container->pgsizes = info.ddw.pgsizes; + /* + * There is a default window in just created container. + * To make region_add/del simpler, we better remove this + * window now and let those iommu_listener callbacks + * create/remove them when needed. + */ + ret = vfio_spapr_remove_window(container, info.dma32_window_start); + if (ret) { + error_setg_errno(errp, -ret, + "failed to remove existing window"); + goto enable_discards_exit; + } + } else { + /* The default table uses 4K pages */ + container->pgsizes = 0x1000; + vfio_host_win_add(container, info.dma32_window_start, + info.dma32_window_start + + info.dma32_window_size - 1, + 0x1000); + } + } + } + + vfio_kvm_device_add_group(group); + + QLIST_INIT(&container->group_list); + QLIST_INSERT_HEAD(&space->containers, container, next); + + group->container = container; + QLIST_INSERT_HEAD(&container->group_list, group, container_next); + + container->listener = vfio_memory_listener; + + memory_listener_register(&container->listener, container->space->as); + + if (container->error) { + ret = -1; + error_propagate_prepend(errp, container->error, + "memory listener initialization failed: "); + goto listener_release_exit; + } + + container->initialized = true; + + return 0; +listener_release_exit: + QLIST_REMOVE(group, container_next); + QLIST_REMOVE(container, next); + vfio_kvm_device_del_group(group); + vfio_listener_release(container); + +enable_discards_exit: + vfio_ram_block_discard_disable(container, false); + +free_container_exit: + g_free(container); + +close_fd_exit: + close(fd); + +put_space_exit: + vfio_put_address_space(space); + + return ret; +} + +static void vfio_disconnect_container(VFIOGroup *group) +{ + VFIOContainer *container = group->container; + + QLIST_REMOVE(group, container_next); + group->container = NULL; + + /* + * Explicitly release the listener first before unset container, + * since unset may destroy the backend container if it's the last + * group. + */ + if (QLIST_EMPTY(&container->group_list)) { + vfio_listener_release(container); + } + + if (ioctl(group->fd, VFIO_GROUP_UNSET_CONTAINER, &container->fd)) { + error_report("vfio: error disconnecting group %d from container", + group->groupid); + } + + if (QLIST_EMPTY(&container->group_list)) { + VFIOAddressSpace *space = container->space; + VFIOGuestIOMMU *giommu, *tmp; + VFIOHostDMAWindow *hostwin, *next; + + QLIST_REMOVE(container, next); + + QLIST_FOREACH_SAFE(giommu, &container->giommu_list, giommu_next, tmp) { + memory_region_unregister_iommu_notifier( + MEMORY_REGION(giommu->iommu_mr), &giommu->n); + QLIST_REMOVE(giommu, giommu_next); + g_free(giommu); + } + + QLIST_FOREACH_SAFE(hostwin, &container->hostwin_list, hostwin_next, + next) { + QLIST_REMOVE(hostwin, hostwin_next); + g_free(hostwin); + } + + trace_vfio_disconnect_container(container->fd); + close(container->fd); + g_free(container); + + vfio_put_address_space(space); + } +} + +static VFIOGroup *vfio_get_group(int groupid, AddressSpace *as, Error **errp) +{ + VFIOGroup *group; + char path[32]; + struct vfio_group_status status = { .argsz = sizeof(status) }; + + QLIST_FOREACH(group, &vfio_group_list, next) { + if (group->groupid == groupid) { + /* Found it. Now is it already in the right context? */ + if (group->container->space->as == as) { + return group; + } else { + error_setg(errp, "group %d used in multiple address spaces", + group->groupid); + return NULL; + } + } + } + + group = g_malloc0(sizeof(*group)); + + snprintf(path, sizeof(path), "/dev/vfio/%d", groupid); + group->fd = qemu_open_old(path, O_RDWR); + if (group->fd < 0) { + error_setg_errno(errp, errno, "failed to open %s", path); + goto free_group_exit; + } + + if (ioctl(group->fd, VFIO_GROUP_GET_STATUS, &status)) { + error_setg_errno(errp, errno, "failed to get group %d status", groupid); + goto close_fd_exit; + } + + if (!(status.flags & VFIO_GROUP_FLAGS_VIABLE)) { + error_setg(errp, "group %d is not viable", groupid); + error_append_hint(errp, + "Please ensure all devices within the iommu_group " + "are bound to their vfio bus driver.\n"); + goto close_fd_exit; + } + + group->groupid = groupid; + QLIST_INIT(&group->device_list); + + if (vfio_connect_container(group, as, errp)) { + error_prepend(errp, "failed to setup container for group %d: ", + groupid); + goto close_fd_exit; + } + + QLIST_INSERT_HEAD(&vfio_group_list, group, next); + + return group; + +close_fd_exit: + close(group->fd); + +free_group_exit: + g_free(group); + + return NULL; +} + +static void vfio_put_group(VFIOGroup *group) +{ + if (!group || !QLIST_EMPTY(&group->device_list)) { + return; + } + + if (!group->ram_block_discard_allowed) { + vfio_ram_block_discard_disable(group->container, false); + } + vfio_kvm_device_del_group(group); + vfio_disconnect_container(group); + QLIST_REMOVE(group, next); + trace_vfio_put_group(group->fd); + close(group->fd); + g_free(group); +} + +static int vfio_get_device(VFIOGroup *group, const char *name, + VFIODevice *vbasedev, Error **errp) +{ + g_autofree struct vfio_device_info *info = NULL; + int fd; + + fd = ioctl(group->fd, VFIO_GROUP_GET_DEVICE_FD, name); + if (fd < 0) { + error_setg_errno(errp, errno, "error getting device from group %d", + group->groupid); + error_append_hint(errp, + "Verify all devices in group %d are bound to vfio- " + "or pci-stub and not already in use\n", group->groupid); + return fd; + } + + info = vfio_get_device_info(fd); + if (!info) { + error_setg_errno(errp, errno, "error getting device info"); + close(fd); + return -1; + } + + /* + * Set discarding of RAM as not broken for this group if the driver knows + * the device operates compatibly with discarding. Setting must be + * consistent per group, but since compatibility is really only possible + * with mdev currently, we expect singleton groups. + */ + if (vbasedev->ram_block_discard_allowed != + group->ram_block_discard_allowed) { + if (!QLIST_EMPTY(&group->device_list)) { + error_setg(errp, "Inconsistent setting of support for discarding " + "RAM (e.g., balloon) within group"); + close(fd); + return -1; + } + + if (!group->ram_block_discard_allowed) { + group->ram_block_discard_allowed = true; + vfio_ram_block_discard_disable(group->container, false); + } + } + + vbasedev->fd = fd; + vbasedev->group = group; + QLIST_INSERT_HEAD(&group->device_list, vbasedev, next); + + vbasedev->num_irqs = info->num_irqs; + vbasedev->num_regions = info->num_regions; + vbasedev->flags = info->flags; + + trace_vfio_get_device(name, info->flags, info->num_regions, info->num_irqs); + + vbasedev->reset_works = !!(info->flags & VFIO_DEVICE_FLAGS_RESET); + + return 0; +} + +static void vfio_put_base_device(VFIODevice *vbasedev) +{ + if (!vbasedev->group) { + return; + } + QLIST_REMOVE(vbasedev, next); + vbasedev->group = NULL; + trace_vfio_put_base_device(vbasedev->fd); + close(vbasedev->fd); +} + +/* + * Interfaces for IBM EEH (Enhanced Error Handling) + */ +static bool vfio_eeh_container_ok(VFIOContainer *container) +{ + /* + * As of 2016-03-04 (linux-4.5) the host kernel EEH/VFIO + * implementation is broken if there are multiple groups in a + * container. The hardware works in units of Partitionable + * Endpoints (== IOMMU groups) and the EEH operations naively + * iterate across all groups in the container, without any logic + * to make sure the groups have their state synchronized. For + * certain operations (ENABLE) that might be ok, until an error + * occurs, but for others (GET_STATE) it's clearly broken. + */ + + /* + * XXX Once fixed kernels exist, test for them here + */ + + if (QLIST_EMPTY(&container->group_list)) { + return false; + } + + if (QLIST_NEXT(QLIST_FIRST(&container->group_list), container_next)) { + return false; + } + + return true; +} + +static int vfio_eeh_container_op(VFIOContainer *container, uint32_t op) +{ + struct vfio_eeh_pe_op pe_op = { + .argsz = sizeof(pe_op), + .op = op, + }; + int ret; + + if (!vfio_eeh_container_ok(container)) { + error_report("vfio/eeh: EEH_PE_OP 0x%x: " + "kernel requires a container with exactly one group", op); + return -EPERM; + } + + ret = ioctl(container->fd, VFIO_EEH_PE_OP, &pe_op); + if (ret < 0) { + error_report("vfio/eeh: EEH_PE_OP 0x%x failed: %m", op); + return -errno; + } + + return ret; +} + +static VFIOContainer *vfio_eeh_as_container(AddressSpace *as) +{ + VFIOAddressSpace *space = vfio_get_address_space(as); + VFIOContainer *container = NULL; + + if (QLIST_EMPTY(&space->containers)) { + /* No containers to act on */ + goto out; + } + + container = QLIST_FIRST(&space->containers); + + if (QLIST_NEXT(container, next)) { + /* + * We don't yet have logic to synchronize EEH state across + * multiple containers + */ + container = NULL; + goto out; + } + +out: + vfio_put_address_space(space); + return container; +} + +bool vfio_eeh_as_ok(AddressSpace *as) +{ + VFIOContainer *container = vfio_eeh_as_container(as); + + return (container != NULL) && vfio_eeh_container_ok(container); +} + +int vfio_eeh_as_op(AddressSpace *as, uint32_t op) +{ + VFIOContainer *container = vfio_eeh_as_container(as); + + if (!container) { + return -ENODEV; + } + return vfio_eeh_container_op(container, op); +} + +static int vfio_device_groupid(VFIODevice *vbasedev, Error **errp) +{ + char *tmp, group_path[PATH_MAX], *group_name; + int ret, groupid; + ssize_t len; + + tmp = g_strdup_printf("%s/iommu_group", vbasedev->sysfsdev); + len = readlink(tmp, group_path, sizeof(group_path)); + g_free(tmp); + + if (len <= 0 || len >= sizeof(group_path)) { + ret = len < 0 ? -errno : -ENAMETOOLONG; + error_setg_errno(errp, -ret, "no iommu_group found"); + return ret; + } + + group_path[len] = 0; + + group_name = basename(group_path); + if (sscanf(group_name, "%d", &groupid) != 1) { + error_setg_errno(errp, errno, "failed to read %s", group_path); + return -errno; + } + return groupid; +} + +/* + * vfio_attach_device: attach a device to a security context + * @name and @vbasedev->name are likely to be different depending + * on the type of the device, hence the need for passing @name + */ +int vfio_attach_device(char *name, VFIODevice *vbasedev, + AddressSpace *as, Error **errp) +{ + int groupid = vfio_device_groupid(vbasedev, errp); + VFIODevice *vbasedev_iter; + VFIOGroup *group; + VFIOContainer *container; + int ret; + + if (groupid < 0) { + return groupid; + } + + trace_vfio_attach_device(vbasedev->name, groupid); + + group = vfio_get_group(groupid, as, errp); + if (!group) { + return -ENOENT; + } + + QLIST_FOREACH(vbasedev_iter, &group->device_list, next) { + if (strcmp(vbasedev_iter->name, vbasedev->name) == 0) { + error_setg(errp, "device is already attached"); + vfio_put_group(group); + return -EBUSY; + } + } + ret = vfio_get_device(group, name, vbasedev, errp); + if (ret) { + vfio_put_group(group); + return ret; + } + + container = group->container; + vbasedev->container = container; + QLIST_INSERT_HEAD(&container->device_list, vbasedev, container_next); + QLIST_INSERT_HEAD(&vfio_device_list, vbasedev, global_next); + + return ret; +} + +void vfio_detach_device(VFIODevice *vbasedev) +{ + VFIOGroup *group = vbasedev->group; + + if (!vbasedev->container) { + return; + } + + QLIST_REMOVE(vbasedev, global_next); + QLIST_REMOVE(vbasedev, container_next); + vbasedev->container = NULL; + trace_vfio_detach_device(vbasedev->name, group->groupid); + vfio_put_base_device(vbasedev); + vfio_put_group(group); +} diff --git a/hw/vfio/meson.build b/hw/vfio/meson.build index 3746c9f984..2a6912c940 100644 --- a/hw/vfio/meson.build +++ b/hw/vfio/meson.build @@ -2,6 +2,7 @@ vfio_ss = ss.source_set() vfio_ss.add(files( 'helpers.c', 'common.c', + 'container.c', 'spapr.c', 'migration.c', )) diff --git a/include/hw/vfio/vfio-common.h b/include/hw/vfio/vfio-common.h index 54905b9dd4..7780b9073a 100644 --- a/include/hw/vfio/vfio-common.h +++ b/include/hw/vfio/vfio-common.h @@ -206,6 +206,30 @@ typedef struct { hwaddr pages; } VFIOBitmap; +void vfio_host_win_add(VFIOContainer *container, + hwaddr min_iova, hwaddr max_iova, + uint64_t iova_pgsizes); +int vfio_host_win_del(VFIOContainer *container, hwaddr min_iova, + hwaddr max_iova); +VFIOAddressSpace *vfio_get_address_space(AddressSpace *as); +void vfio_put_address_space(VFIOAddressSpace *space); +bool vfio_devices_all_running_and_saving(VFIOContainer *container); + +/* container->fd */ +int vfio_dma_unmap(VFIOContainer *container, hwaddr iova, + ram_addr_t size, IOMMUTLBEntry *iotlb); +int vfio_dma_map(VFIOContainer *container, hwaddr iova, + ram_addr_t size, void *vaddr, bool readonly); +int vfio_set_dirty_page_tracking(VFIOContainer *container, bool start); +int vfio_query_dirty_bitmap(VFIOContainer *container, VFIOBitmap *vbmap, + hwaddr iova, hwaddr size); + +int vfio_container_add_section_window(VFIOContainer *container, + MemoryRegionSection *section, + Error **errp); +void vfio_container_del_section_window(VFIOContainer *container, + MemoryRegionSection *section); + void vfio_disable_irqindex(VFIODevice *vbasedev, int index); void vfio_unmask_single_irqindex(VFIODevice *vbasedev, int index); void vfio_mask_single_irqindex(VFIODevice *vbasedev, int index); @@ -235,6 +259,10 @@ extern const MemoryRegionOps vfio_region_ops; typedef QLIST_HEAD(VFIOGroupList, VFIOGroup) VFIOGroupList; typedef QLIST_HEAD(VFIODeviceList, VFIODevice) VFIODeviceList; extern VFIOGroupList vfio_group_list; +extern VFIODeviceList vfio_device_list; + +extern const MemoryListener vfio_memory_listener; +extern int vfio_kvm_device_fd; bool vfio_mig_active(void); int vfio_block_multiple_devices_migration(VFIODevice *vbasedev, Error **errp); @@ -272,4 +300,11 @@ bool vfio_migration_realize(VFIODevice *vbasedev, Error **errp); void vfio_migration_exit(VFIODevice *vbasedev); int vfio_bitmap_alloc(VFIOBitmap *vbmap, hwaddr size); +bool vfio_devices_all_running_and_mig_active(VFIOContainer *container); +bool vfio_devices_all_device_dirty_tracking(VFIOContainer *container); +int vfio_devices_query_dirty_bitmap(VFIOContainer *container, + VFIOBitmap *vbmap, hwaddr iova, + hwaddr size); +int vfio_get_dirty_bitmap(VFIOContainer *container, uint64_t iova, + uint64_t size, ram_addr_t ram_addr); #endif /* HW_VFIO_VFIO_COMMON_H */ From fde4dbb7e61396a38fcc172ab02dbf839b468ebe Mon Sep 17 00:00:00 2001 From: Zhenzhong Duan Date: Mon, 9 Oct 2023 10:20:46 +0800 Subject: [PATCH 0775/1077] vfio/pci: Fix a potential memory leak in vfio_listener_region_add MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When there is an failure in vfio_listener_region_add() and the section belongs to a ram device, there is an inaccurate error report which should never be related to vfio_dma_map failure. The memory holding err is also incrementally leaked in each failure. Fix it by reporting the real error and free it. Fixes: 567b5b309ab ("vfio/pci: Relax DMA map errors for MMIO regions") Signed-off-by: Zhenzhong Duan Signed-off-by: Cédric Le Goater --- hw/vfio/common.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/vfio/common.c b/hw/vfio/common.c index 9e61de03ee..5ff5acf1d8 100644 --- a/hw/vfio/common.c +++ b/hw/vfio/common.c @@ -763,7 +763,7 @@ static void vfio_listener_region_add(MemoryListener *listener, fail: if (memory_region_is_ram_device(section->mr)) { - error_report("failed to vfio_dma_map. pci p2p may not work"); + error_reportf_err(err, "PCI p2p may not work: "); return; } /* From 88ceb67a6f9b049e2f0ae3df00862e9d6057a5f0 Mon Sep 17 00:00:00 2001 From: Zhenzhong Duan Date: Mon, 9 Oct 2023 10:20:47 +0800 Subject: [PATCH 0776/1077] vfio/ap: Remove pointless apdev variable MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit No need to double-cast, call VFIO_AP_DEVICE() on DeviceState. No functional changes. Signed-off-by: Zhenzhong Duan Reviewed-by: Tony Krowiak Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Cédric Le Goater --- hw/vfio/ap.c | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/hw/vfio/ap.c b/hw/vfio/ap.c index f870f51ffa..5f257bffb9 100644 --- a/hw/vfio/ap.c +++ b/hw/vfio/ap.c @@ -156,8 +156,7 @@ static void vfio_ap_realize(DeviceState *dev, Error **errp) { int ret; Error *err = NULL; - APDevice *apdev = AP_DEVICE(dev); - VFIOAPDevice *vapdev = VFIO_AP_DEVICE(apdev); + VFIOAPDevice *vapdev = VFIO_AP_DEVICE(dev); VFIODevice *vbasedev = &vapdev->vdev; vbasedev->name = g_path_get_basename(vbasedev->sysfsdev); @@ -197,8 +196,7 @@ error: static void vfio_ap_unrealize(DeviceState *dev) { - APDevice *apdev = AP_DEVICE(dev); - VFIOAPDevice *vapdev = VFIO_AP_DEVICE(apdev); + VFIOAPDevice *vapdev = VFIO_AP_DEVICE(dev); vfio_ap_unregister_irq_notifier(vapdev, VFIO_AP_REQ_IRQ_INDEX); vfio_detach_device(&vapdev->vdev); @@ -213,8 +211,7 @@ static Property vfio_ap_properties[] = { static void vfio_ap_reset(DeviceState *dev) { int ret; - APDevice *apdev = AP_DEVICE(dev); - VFIOAPDevice *vapdev = VFIO_AP_DEVICE(apdev); + VFIOAPDevice *vapdev = VFIO_AP_DEVICE(dev); ret = ioctl(vapdev->vdev.fd, VFIO_DEVICE_RESET); if (ret) { From 410ee49190f46b4e545acee9cb70717e12d8305b Mon Sep 17 00:00:00 2001 From: Zhenzhong Duan Date: Mon, 9 Oct 2023 10:20:48 +0800 Subject: [PATCH 0777/1077] vfio/ccw: Remove redundant definition of TYPE_VFIO_CCW MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit No functional changes. Signed-off-by: Zhenzhong Duan Reviewed-by: Eric Farman Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Cédric Le Goater --- include/hw/s390x/vfio-ccw.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/include/hw/s390x/vfio-ccw.h b/include/hw/s390x/vfio-ccw.h index 63a909eb7e..4209d27657 100644 --- a/include/hw/s390x/vfio-ccw.h +++ b/include/hw/s390x/vfio-ccw.h @@ -22,6 +22,4 @@ #define TYPE_VFIO_CCW "vfio-ccw" OBJECT_DECLARE_SIMPLE_TYPE(VFIOCCWDevice, VFIO_CCW) -#define TYPE_VFIO_CCW "vfio-ccw" - #endif From c0f527f4cc6659f55279f7d774dd804a1504a401 Mon Sep 17 00:00:00 2001 From: Eric Auger Date: Wed, 11 Oct 2023 22:09:34 +0200 Subject: [PATCH 0778/1077] vfio/pci: Remove vfio_detach_device from vfio_realize error path MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In vfio_realize, on the error path, we currently call vfio_detach_device() after a successful vfio_attach_device. While this looks natural, vfio_instance_finalize also induces a vfio_detach_device(), and it seems to be the right place instead as other resources are released there which happen to be a prerequisite to a successful UNSET_CONTAINER. So let's rely on the finalize vfio_detach_device call to free all the relevant resources. Fixes: a28e06621170 ("vfio/pci: Introduce vfio_[attach/detach]_device") Reported-by: Zhenzhong Duan Signed-off-by: Eric Auger Tested-by: Zhenzhong Duan Reviewed-by: Zhenzhong Duan Signed-off-by: Cédric Le Goater --- hw/vfio/pci.c | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/hw/vfio/pci.c b/hw/vfio/pci.c index 40ae46266e..6e3f6aba28 100644 --- a/hw/vfio/pci.c +++ b/hw/vfio/pci.c @@ -3115,7 +3115,7 @@ static void vfio_realize(PCIDevice *pdev, Error **errp) vfio_populate_device(vdev, &err); if (err) { error_propagate(errp, err); - goto out_detach; + goto error; } /* Get a copy of config space */ @@ -3125,7 +3125,7 @@ static void vfio_realize(PCIDevice *pdev, Error **errp) if (ret < (int)MIN(pci_config_size(&vdev->pdev), vdev->config_size)) { ret = ret < 0 ? -errno : -EFAULT; error_setg_errno(errp, -ret, "failed to read device config space"); - goto out_detach; + goto error; } /* vfio emulates a lot for us, but some bits need extra love */ @@ -3144,7 +3144,7 @@ static void vfio_realize(PCIDevice *pdev, Error **errp) if (vdev->vendor_id != PCI_ANY_ID) { if (vdev->vendor_id >= 0xffff) { error_setg(errp, "invalid PCI vendor ID provided"); - goto out_detach; + goto error; } vfio_add_emulated_word(vdev, PCI_VENDOR_ID, vdev->vendor_id, ~0); trace_vfio_pci_emulated_vendor_id(vbasedev->name, vdev->vendor_id); @@ -3155,7 +3155,7 @@ static void vfio_realize(PCIDevice *pdev, Error **errp) if (vdev->device_id != PCI_ANY_ID) { if (vdev->device_id > 0xffff) { error_setg(errp, "invalid PCI device ID provided"); - goto out_detach; + goto error; } vfio_add_emulated_word(vdev, PCI_DEVICE_ID, vdev->device_id, ~0); trace_vfio_pci_emulated_device_id(vbasedev->name, vdev->device_id); @@ -3166,7 +3166,7 @@ static void vfio_realize(PCIDevice *pdev, Error **errp) if (vdev->sub_vendor_id != PCI_ANY_ID) { if (vdev->sub_vendor_id > 0xffff) { error_setg(errp, "invalid PCI subsystem vendor ID provided"); - goto out_detach; + goto error; } vfio_add_emulated_word(vdev, PCI_SUBSYSTEM_VENDOR_ID, vdev->sub_vendor_id, ~0); @@ -3177,7 +3177,7 @@ static void vfio_realize(PCIDevice *pdev, Error **errp) if (vdev->sub_device_id != PCI_ANY_ID) { if (vdev->sub_device_id > 0xffff) { error_setg(errp, "invalid PCI subsystem device ID provided"); - goto out_detach; + goto error; } vfio_add_emulated_word(vdev, PCI_SUBSYSTEM_ID, vdev->sub_device_id, ~0); trace_vfio_pci_emulated_sub_device_id(vbasedev->name, @@ -3210,7 +3210,7 @@ static void vfio_realize(PCIDevice *pdev, Error **errp) vfio_msix_early_setup(vdev, &err); if (err) { error_propagate(errp, err); - goto out_detach; + goto error; } vfio_bars_register(vdev); @@ -3326,8 +3326,6 @@ out_deregister: out_teardown: vfio_teardown_msi(vdev); vfio_bars_exit(vdev); -out_detach: - vfio_detach_device(vbasedev); error: error_prepend(errp, VFIO_MSG_PREFIX, vbasedev->name); } From 303c33e606f629c7467b457a19c53698b114ee0f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= Date: Mon, 9 Oct 2023 10:32:45 +0400 Subject: [PATCH 0779/1077] ramfb: add migration support MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Implementing RAMFB migration is quite straightforward. One caveat is to treat the whole RAMFBCfg as a blob, since that's what is exposed to the guest directly. This avoid having to fiddle with endianness issues if we were to migrate fields individually as integers. The devices using RAMFB will have to include ramfb_vmstate in their migration description. Signed-off-by: Marc-André Lureau Reviewed-by: Laszlo Ersek Acked-by: Gerd Hoffmann Signed-off-by: Cédric Le Goater --- hw/display/ramfb.c | 19 +++++++++++++++++++ include/hw/display/ramfb.h | 4 ++++ 2 files changed, 23 insertions(+) diff --git a/hw/display/ramfb.c b/hw/display/ramfb.c index c2b002d534..477ef7272a 100644 --- a/hw/display/ramfb.c +++ b/hw/display/ramfb.c @@ -28,6 +28,8 @@ struct QEMU_PACKED RAMFBCfg { uint32_t stride; }; +typedef struct RAMFBCfg RAMFBCfg; + struct RAMFBState { DisplaySurface *ds; uint32_t width, height; @@ -116,6 +118,23 @@ void ramfb_display_update(QemuConsole *con, RAMFBState *s) dpy_gfx_update_full(con); } +static int ramfb_post_load(void *opaque, int version_id) +{ + ramfb_fw_cfg_write(opaque, 0, 0); + return 0; +} + +const VMStateDescription ramfb_vmstate = { + .name = "ramfb", + .version_id = 1, + .minimum_version_id = 1, + .post_load = ramfb_post_load, + .fields = (VMStateField[]) { + VMSTATE_BUFFER_UNSAFE(cfg, RAMFBState, 0, sizeof(RAMFBCfg)), + VMSTATE_END_OF_LIST() + } +}; + RAMFBState *ramfb_setup(Error **errp) { FWCfgState *fw_cfg = fw_cfg_find(); diff --git a/include/hw/display/ramfb.h b/include/hw/display/ramfb.h index b33a2c467b..a7e0019144 100644 --- a/include/hw/display/ramfb.h +++ b/include/hw/display/ramfb.h @@ -1,11 +1,15 @@ #ifndef RAMFB_H #define RAMFB_H +#include "migration/vmstate.h" + /* ramfb.c */ typedef struct RAMFBState RAMFBState; void ramfb_display_update(QemuConsole *con, RAMFBState *s); RAMFBState *ramfb_setup(Error **errp); +extern const VMStateDescription ramfb_vmstate; + /* ramfb-standalone.c */ #define TYPE_RAMFB_DEVICE "ramfb" From a1e88d2d2b89ad6371036aa07f7e96947786c873 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= Date: Mon, 9 Oct 2023 10:32:46 +0400 Subject: [PATCH 0780/1077] ramfb-standalone: add migration support MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add a "ramfb-dev" section whenever "x-migrate" is turned on. Turn it off by default on machines <= 8.1 for compatibility reasons. Signed-off-by: Marc-André Lureau Reviewed-by: Laszlo Ersek Acked-by: Gerd Hoffmann Signed-off-by: Cédric Le Goater --- hw/core/machine.c | 1 + hw/display/ramfb-standalone.c | 27 +++++++++++++++++++++++++++ 2 files changed, 28 insertions(+) diff --git a/hw/core/machine.c b/hw/core/machine.c index cfd1edfe20..6305f2d7a4 100644 --- a/hw/core/machine.c +++ b/hw/core/machine.c @@ -34,6 +34,7 @@ GlobalProperty hw_compat_8_1[] = { { TYPE_PCI_BRIDGE, "x-pci-express-writeable-slt-bug", "true" }, + { "ramfb", "x-migrate", "off" }, }; const size_t hw_compat_8_1_len = G_N_ELEMENTS(hw_compat_8_1); diff --git a/hw/display/ramfb-standalone.c b/hw/display/ramfb-standalone.c index 8c0094397f..a96e7ebcd9 100644 --- a/hw/display/ramfb-standalone.c +++ b/hw/display/ramfb-standalone.c @@ -1,4 +1,5 @@ #include "qemu/osdep.h" +#include "migration/vmstate.h" #include "qapi/error.h" #include "qemu/module.h" #include "hw/loader.h" @@ -15,6 +16,7 @@ struct RAMFBStandaloneState { SysBusDevice parent_obj; QemuConsole *con; RAMFBState *state; + bool migrate; }; static void display_update_wrapper(void *dev) @@ -40,14 +42,39 @@ static void ramfb_realizefn(DeviceState *dev, Error **errp) ramfb->state = ramfb_setup(errp); } +static bool migrate_needed(void *opaque) +{ + RAMFBStandaloneState *ramfb = RAMFB(opaque); + + return ramfb->migrate; +} + +static const VMStateDescription ramfb_dev_vmstate = { + .name = "ramfb-dev", + .version_id = 1, + .minimum_version_id = 1, + .needed = migrate_needed, + .fields = (VMStateField[]) { + VMSTATE_STRUCT_POINTER(state, RAMFBStandaloneState, ramfb_vmstate, RAMFBState), + VMSTATE_END_OF_LIST() + } +}; + +static Property ramfb_properties[] = { + DEFINE_PROP_BOOL("x-migrate", RAMFBStandaloneState, migrate, true), + DEFINE_PROP_END_OF_LIST(), +}; + static void ramfb_class_initfn(ObjectClass *klass, void *data) { DeviceClass *dc = DEVICE_CLASS(klass); set_bit(DEVICE_CATEGORY_DISPLAY, dc->categories); + dc->vmsd = &ramfb_dev_vmstate; dc->realize = ramfb_realizefn; dc->desc = "ram framebuffer standalone device"; dc->user_creatable = true; + device_class_set_props(dc, ramfb_properties); } static const TypeInfo ramfb_info = { From 8741781157f09a9f79bb652f8a0210d40f814cd0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= Date: Mon, 9 Oct 2023 10:32:47 +0400 Subject: [PATCH 0781/1077] hw/vfio: add ramfb migration support MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add a "VFIODisplay" subsection whenever "x-ramfb-migrate" is turned on. Turn it off by default on machines <= 8.1 for compatibility reasons. Signed-off-by: Marc-André Lureau Reviewed-by: Laszlo Ersek Acked-by: Gerd Hoffmann [ clg: - checkpatch fixes - improved warn_report() in vfio_realize() ] Signed-off-by: Cédric Le Goater --- hw/core/machine.c | 1 + hw/vfio/display.c | 21 +++++++++++++++++++++ hw/vfio/pci.c | 47 +++++++++++++++++++++++++++++++++++++++++++++++ hw/vfio/pci.h | 3 +++ stubs/ramfb.c | 2 ++ 5 files changed, 74 insertions(+) diff --git a/hw/core/machine.c b/hw/core/machine.c index 6305f2d7a4..05aef2cf9f 100644 --- a/hw/core/machine.c +++ b/hw/core/machine.c @@ -35,6 +35,7 @@ GlobalProperty hw_compat_8_1[] = { { TYPE_PCI_BRIDGE, "x-pci-express-writeable-slt-bug", "true" }, { "ramfb", "x-migrate", "off" }, + { "vfio-pci-nohotplug", "x-ramfb-migrate", "off" } }; const size_t hw_compat_8_1_len = G_N_ELEMENTS(hw_compat_8_1); diff --git a/hw/vfio/display.c b/hw/vfio/display.c index 837d9e6a30..7a10fa8604 100644 --- a/hw/vfio/display.c +++ b/hw/vfio/display.c @@ -544,3 +544,24 @@ void vfio_display_finalize(VFIOPCIDevice *vdev) vfio_display_edid_exit(vdev->dpy); g_free(vdev->dpy); } + +static bool migrate_needed(void *opaque) +{ + VFIODisplay *dpy = opaque; + bool ramfb_exists = dpy->ramfb != NULL; + + /* see vfio_display_migration_needed() */ + assert(ramfb_exists); + return ramfb_exists; +} + +const VMStateDescription vfio_display_vmstate = { + .name = "VFIODisplay", + .version_id = 1, + .minimum_version_id = 1, + .needed = migrate_needed, + .fields = (VMStateField[]) { + VMSTATE_STRUCT_POINTER(ramfb, VFIODisplay, ramfb_vmstate, RAMFBState), + VMSTATE_END_OF_LIST(), + } +}; diff --git a/hw/vfio/pci.c b/hw/vfio/pci.c index 6e3f6aba28..b27011cee7 100644 --- a/hw/vfio/pci.c +++ b/hw/vfio/pci.c @@ -2675,6 +2675,33 @@ static bool vfio_msix_present(void *opaque, int version_id) return msix_present(pdev); } +static bool vfio_display_migration_needed(void *opaque) +{ + VFIOPCIDevice *vdev = opaque; + + /* + * We need to migrate the VFIODisplay object if ramfb *migration* was + * explicitly requested (in which case we enforced both ramfb=on and + * display=on), or ramfb migration was left at the default "auto" + * setting, and *ramfb* was explicitly requested (in which case we + * enforced display=on). + */ + return vdev->ramfb_migrate == ON_OFF_AUTO_ON || + (vdev->ramfb_migrate == ON_OFF_AUTO_AUTO && vdev->enable_ramfb); +} + +const VMStateDescription vmstate_vfio_display = { + .name = "VFIOPCIDevice/VFIODisplay", + .version_id = 1, + .minimum_version_id = 1, + .needed = vfio_display_migration_needed, + .fields = (VMStateField[]){ + VMSTATE_STRUCT_POINTER(dpy, VFIOPCIDevice, vfio_display_vmstate, + VFIODisplay), + VMSTATE_END_OF_LIST() + } +}; + const VMStateDescription vmstate_vfio_pci_config = { .name = "VFIOPCIDevice", .version_id = 1, @@ -2683,6 +2710,10 @@ const VMStateDescription vmstate_vfio_pci_config = { VMSTATE_PCI_DEVICE(pdev, VFIOPCIDevice), VMSTATE_MSIX_TEST(pdev, VFIOPCIDevice, vfio_msix_present), VMSTATE_END_OF_LIST() + }, + .subsections = (const VMStateDescription * []) { + &vmstate_vfio_display, + NULL } }; @@ -3300,6 +3331,20 @@ static void vfio_realize(PCIDevice *pdev, Error **errp) } } + if (vdev->ramfb_migrate == ON_OFF_AUTO_ON && !vdev->enable_ramfb) { + warn_report("x-ramfb-migrate=on but ramfb=off. " + "Forcing x-ramfb-migrate to off."); + vdev->ramfb_migrate = ON_OFF_AUTO_OFF; + } + if (vbasedev->enable_migration == ON_OFF_AUTO_OFF) { + if (vdev->ramfb_migrate == ON_OFF_AUTO_AUTO) { + vdev->ramfb_migrate = ON_OFF_AUTO_OFF; + } else if (vdev->ramfb_migrate == ON_OFF_AUTO_ON) { + error_setg(errp, "x-ramfb-migrate requires enable-migration"); + goto out_deregister; + } + } + if (!pdev->failover_pair_id) { if (!vfio_migration_realize(vbasedev, errp)) { goto out_deregister; @@ -3511,6 +3556,8 @@ static const TypeInfo vfio_pci_dev_info = { static Property vfio_pci_dev_nohotplug_properties[] = { DEFINE_PROP_BOOL("ramfb", VFIOPCIDevice, enable_ramfb, false), + DEFINE_PROP_ON_OFF_AUTO("x-ramfb-migrate", VFIOPCIDevice, ramfb_migrate, + ON_OFF_AUTO_AUTO), DEFINE_PROP_END_OF_LIST(), }; diff --git a/hw/vfio/pci.h b/hw/vfio/pci.h index 0d89eb761e..fba8737ab2 100644 --- a/hw/vfio/pci.h +++ b/hw/vfio/pci.h @@ -174,6 +174,7 @@ struct VFIOPCIDevice { bool no_kvm_ioeventfd; bool no_vfio_ioeventfd; bool enable_ramfb; + OnOffAuto ramfb_migrate; bool defer_kvm_irq_routing; bool clear_parent_atomics_on_exit; VFIODisplay *dpy; @@ -227,4 +228,6 @@ void vfio_display_reset(VFIOPCIDevice *vdev); int vfio_display_probe(VFIOPCIDevice *vdev, Error **errp); void vfio_display_finalize(VFIOPCIDevice *vdev); +extern const VMStateDescription vfio_display_vmstate; + #endif /* HW_VFIO_VFIO_PCI_H */ diff --git a/stubs/ramfb.c b/stubs/ramfb.c index 48143f3354..cf64733b10 100644 --- a/stubs/ramfb.c +++ b/stubs/ramfb.c @@ -2,6 +2,8 @@ #include "qapi/error.h" #include "hw/display/ramfb.h" +const VMStateDescription ramfb_vmstate = {}; + void ramfb_display_update(QemuConsole *con, RAMFBState *s) { } From d637a182b98a082bf0b9cd1853fe3192c7ea88e8 Mon Sep 17 00:00:00 2001 From: Juan Quintela Date: Tue, 13 Jun 2023 13:34:12 +0200 Subject: [PATCH 0782/1077] migration: save_compress_page() can take block through pss Reviewed-by: Lukas Straub Signed-off-by: Juan Quintela --- migration/ram.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/migration/ram.c b/migration/ram.c index 5595379fa6..378d310fbd 100644 --- a/migration/ram.c +++ b/migration/ram.c @@ -2067,7 +2067,7 @@ static bool save_page_use_compression(RAMState *rs) * paths to handle it */ static bool save_compress_page(RAMState *rs, PageSearchStatus *pss, - RAMBlock *block, ram_addr_t offset) + ram_addr_t offset) { if (!save_page_use_compression(rs)) { return false; @@ -2083,12 +2083,13 @@ static bool save_compress_page(RAMState *rs, PageSearchStatus *pss, * We post the fist page as normal page as compression will take * much CPU resource. */ - if (block != pss->last_sent_block) { + if (pss->block != pss->last_sent_block) { ram_flush_compressed_data(rs); return false; } - if (compress_page_with_multi_thread(block, offset, send_queued_data) > 0) { + if (compress_page_with_multi_thread(pss->block, offset, + send_queued_data) > 0) { return true; } @@ -2114,7 +2115,7 @@ static int ram_save_target_page_legacy(RAMState *rs, PageSearchStatus *pss) return res; } - if (save_compress_page(rs, pss, block, offset)) { + if (save_compress_page(rs, pss, offset)) { return 1; } From 944853c201bc229ef02f209d2e6e42ada9d745dd Mon Sep 17 00:00:00 2001 From: Juan Quintela Date: Tue, 13 Jun 2023 13:36:24 +0200 Subject: [PATCH 0783/1077] migration: control_save_page() can take block through pss Reviewed-by: Lukas Straub Signed-off-by: Juan Quintela --- migration/ram.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/migration/ram.c b/migration/ram.c index 378d310fbd..7f18c1808d 100644 --- a/migration/ram.c +++ b/migration/ram.c @@ -1186,12 +1186,12 @@ static int save_zero_page(RAMState *rs, PageSearchStatus *pss, RAMBlock *block, * * Return true if the pages has been saved, otherwise false is returned. */ -static bool control_save_page(PageSearchStatus *pss, RAMBlock *block, +static bool control_save_page(PageSearchStatus *pss, ram_addr_t offset, int *pages) { int ret; - ret = rdma_control_save_page(pss->pss_channel, block->offset, offset, + ret = rdma_control_save_page(pss->pss_channel, pss->block->offset, offset, TARGET_PAGE_SIZE); if (ret == RAM_SAVE_CONTROL_NOT_SUPP) { return false; @@ -2111,7 +2111,7 @@ static int ram_save_target_page_legacy(RAMState *rs, PageSearchStatus *pss) ram_addr_t offset = ((ram_addr_t)pss->page) << TARGET_PAGE_BITS; int res; - if (control_save_page(pss, block, offset, &res)) { + if (control_save_page(pss, offset, &res)) { return res; } From e8e4e7acd8e2113d900fe6b9a9870daa7ecf1042 Mon Sep 17 00:00:00 2001 From: Juan Quintela Date: Tue, 13 Jun 2023 13:38:30 +0200 Subject: [PATCH 0784/1077] migration: save_zero_page() can take block through pss Reviewed-by: Lukas Straub Signed-off-by: Juan Quintela --- migration/ram.c | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/migration/ram.c b/migration/ram.c index 7f18c1808d..16c30a9d7a 100644 --- a/migration/ram.c +++ b/migration/ram.c @@ -1144,13 +1144,12 @@ void ram_release_page(const char *rbname, uint64_t offset) * * @rs: current RAM state * @pss: current PSS channel - * @block: block that contains the page we want to send * @offset: offset inside the block for the page */ -static int save_zero_page(RAMState *rs, PageSearchStatus *pss, RAMBlock *block, +static int save_zero_page(RAMState *rs, PageSearchStatus *pss, ram_addr_t offset) { - uint8_t *p = block->host + offset; + uint8_t *p = pss->block->host + offset; QEMUFile *file = pss->pss_channel; int len = 0; @@ -1158,10 +1157,10 @@ static int save_zero_page(RAMState *rs, PageSearchStatus *pss, RAMBlock *block, return 0; } - len += save_page_header(pss, file, block, offset | RAM_SAVE_FLAG_ZERO); + len += save_page_header(pss, file, pss->block, offset | RAM_SAVE_FLAG_ZERO); qemu_put_byte(file, 0); len += 1; - ram_release_page(block->idstr, offset); + ram_release_page(pss->block->idstr, offset); stat64_add(&mig_stats.zero_pages, 1); ram_transferred_add(len); @@ -1172,7 +1171,7 @@ static int save_zero_page(RAMState *rs, PageSearchStatus *pss, RAMBlock *block, */ if (rs->xbzrle_started) { XBZRLE_cache_lock(); - xbzrle_cache_zero_page(block->offset + offset); + xbzrle_cache_zero_page(pss->block->offset + offset); XBZRLE_cache_unlock(); } @@ -2119,7 +2118,7 @@ static int ram_save_target_page_legacy(RAMState *rs, PageSearchStatus *pss) return 1; } - if (save_zero_page(rs, pss, block, offset)) { + if (save_zero_page(rs, pss, offset)) { return 1; } From 0e6bff0d43bf04c6e7a16c2775879816ca056b3d Mon Sep 17 00:00:00 2001 From: Hawkins Jiawei Date: Fri, 13 Oct 2023 16:09:36 +0800 Subject: [PATCH 0785/1077] vdpa: Use iovec for vhost_vdpa_net_cvq_add() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Next patches in this series will no longer perform an immediate poll and check of the device's used buffers for each CVQ state load command. Consequently, there will be multiple pending buffers in the shadow VirtQueue, making it a must for every control command to have its own buffer. To achieve this, this patch refactor vhost_vdpa_net_cvq_add() to accept `struct iovec`, which eliminates the coupling of control commands to `s->cvq_cmd_out_buffer` and `s->status`, allowing them to use their own buffer. Signed-off-by: Hawkins Jiawei Acked-by: Eugenio Pérez Message-Id: <8a328f146fb043f34edb75ba6d043d2d6de88f99.1697165821.git.yin31149@gmail.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- net/vhost-vdpa.c | 39 ++++++++++++++++++++++----------------- 1 file changed, 22 insertions(+), 17 deletions(-) diff --git a/net/vhost-vdpa.c b/net/vhost-vdpa.c index 939c984d5b..618758596a 100644 --- a/net/vhost-vdpa.c +++ b/net/vhost-vdpa.c @@ -618,22 +618,14 @@ static void vhost_vdpa_net_cvq_stop(NetClientState *nc) vhost_vdpa_net_client_stop(nc); } -static ssize_t vhost_vdpa_net_cvq_add(VhostVDPAState *s, size_t out_len, - size_t in_len) +static ssize_t vhost_vdpa_net_cvq_add(VhostVDPAState *s, + const struct iovec *out_sg, size_t out_num, + const struct iovec *in_sg, size_t in_num) { - /* Buffers for the device */ - const struct iovec out = { - .iov_base = s->cvq_cmd_out_buffer, - .iov_len = out_len, - }; - const struct iovec in = { - .iov_base = s->status, - .iov_len = sizeof(virtio_net_ctrl_ack), - }; VhostShadowVirtqueue *svq = g_ptr_array_index(s->vhost_vdpa.shadow_vqs, 0); int r; - r = vhost_svq_add(svq, &out, 1, &in, 1, NULL); + r = vhost_svq_add(svq, out_sg, out_num, in_sg, in_num, NULL); if (unlikely(r != 0)) { if (unlikely(r == -ENOSPC)) { qemu_log_mask(LOG_GUEST_ERROR, "%s: No space on device queue\n", @@ -659,6 +651,15 @@ static ssize_t vhost_vdpa_net_load_cmd(VhostVDPAState *s, uint8_t class, .cmd = cmd, }; size_t data_size = iov_size(data_sg, data_num); + /* Buffers for the device */ + const struct iovec out = { + .iov_base = s->cvq_cmd_out_buffer, + .iov_len = sizeof(ctrl) + data_size, + }; + const struct iovec in = { + .iov_base = s->status, + .iov_len = sizeof(*s->status), + }; assert(data_size < vhost_vdpa_net_cvq_cmd_page_len() - sizeof(ctrl)); @@ -669,8 +670,7 @@ static ssize_t vhost_vdpa_net_load_cmd(VhostVDPAState *s, uint8_t class, iov_to_buf(data_sg, data_num, 0, s->cvq_cmd_out_buffer + sizeof(ctrl), data_size); - return vhost_vdpa_net_cvq_add(s, data_size + sizeof(ctrl), - sizeof(virtio_net_ctrl_ack)); + return vhost_vdpa_net_cvq_add(s, &out, 1, &in, 1); } static int vhost_vdpa_net_load_mac(VhostVDPAState *s, const VirtIONet *n) @@ -1248,10 +1248,15 @@ static int vhost_vdpa_net_handle_ctrl_avail(VhostShadowVirtqueue *svq, .iov_base = s->cvq_cmd_out_buffer, }; /* in buffer used for device model */ - const struct iovec in = { + const struct iovec model_in = { .iov_base = &status, .iov_len = sizeof(status), }; + /* in buffer used for vdpa device */ + const struct iovec vdpa_in = { + .iov_base = s->status, + .iov_len = sizeof(*s->status), + }; ssize_t dev_written = -EINVAL; out.iov_len = iov_to_buf(elem->out_sg, elem->out_num, 0, @@ -1285,7 +1290,7 @@ static int vhost_vdpa_net_handle_ctrl_avail(VhostShadowVirtqueue *svq, goto out; } } else { - dev_written = vhost_vdpa_net_cvq_add(s, out.iov_len, sizeof(status)); + dev_written = vhost_vdpa_net_cvq_add(s, &out, 1, &vdpa_in, 1); if (unlikely(dev_written < 0)) { goto out; } @@ -1301,7 +1306,7 @@ static int vhost_vdpa_net_handle_ctrl_avail(VhostShadowVirtqueue *svq, } status = VIRTIO_NET_ERR; - virtio_net_handle_ctrl_iov(svq->vdev, &in, 1, &out, 1); + virtio_net_handle_ctrl_iov(svq->vdev, &model_in, 1, &out, 1); if (status != VIRTIO_NET_OK) { error_report("Bad CVQ processing in model"); } From 327dedb8df91f57ef917ab5b5db519146ee6f08b Mon Sep 17 00:00:00 2001 From: Hawkins Jiawei Date: Fri, 13 Oct 2023 16:09:37 +0800 Subject: [PATCH 0786/1077] vdpa: Avoid using vhost_vdpa_net_load_*() outside vhost_vdpa_net_load() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Next patches in this series will refactor vhost_vdpa_net_load_cmd() to iterate through the control commands shadow buffers, allowing QEMU to send CVQ state load commands in parallel at device startup. Considering that QEMU always forwards the CVQ command serialized outside of vhost_vdpa_net_load(), it is more elegant to send the CVQ commands directly without invoking vhost_vdpa_net_load_*() helpers. Signed-off-by: Hawkins Jiawei Acked-by: Eugenio Pérez Message-Id: <254f0618efde7af7229ba4fdada667bb9d318991.1697165821.git.yin31149@gmail.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- net/vhost-vdpa.c | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/net/vhost-vdpa.c b/net/vhost-vdpa.c index 618758596a..86b8d31244 100644 --- a/net/vhost-vdpa.c +++ b/net/vhost-vdpa.c @@ -1114,12 +1114,14 @@ static NetClientInfo net_vhost_vdpa_cvq_info = { */ static int vhost_vdpa_net_excessive_mac_filter_cvq_add(VhostVDPAState *s, VirtQueueElement *elem, - struct iovec *out) + struct iovec *out, + const struct iovec *in) { struct virtio_net_ctrl_mac mac_data, *mac_ptr; struct virtio_net_ctrl_hdr *hdr_ptr; uint32_t cursor; ssize_t r; + uint8_t on = 1; /* parse the non-multicast MAC address entries from CVQ command */ cursor = sizeof(*hdr_ptr); @@ -1167,7 +1169,13 @@ static int vhost_vdpa_net_excessive_mac_filter_cvq_add(VhostVDPAState *s, * filter table to the vdpa device, it should send the * VIRTIO_NET_CTRL_RX_PROMISC CVQ command to enable promiscuous mode */ - r = vhost_vdpa_net_load_rx_mode(s, VIRTIO_NET_CTRL_RX_PROMISC, 1); + hdr_ptr = out->iov_base; + out->iov_len = sizeof(*hdr_ptr) + sizeof(on); + + hdr_ptr->class = VIRTIO_NET_CTRL_RX; + hdr_ptr->cmd = VIRTIO_NET_CTRL_RX_PROMISC; + iov_from_buf(out, 1, sizeof(*hdr_ptr), &on, sizeof(on)); + r = vhost_vdpa_net_cvq_add(s, out, 1, in, 1); if (unlikely(r < 0)) { return r; } @@ -1285,7 +1293,7 @@ static int vhost_vdpa_net_handle_ctrl_avail(VhostShadowVirtqueue *svq, * the CVQ command directly. */ dev_written = vhost_vdpa_net_excessive_mac_filter_cvq_add(s, elem, - &out); + &out, &vdpa_in); if (unlikely(dev_written < 0)) { goto out; } From 24e59cfe0cb53416b06c2c117bc22ff22dc54df3 Mon Sep 17 00:00:00 2001 From: Hawkins Jiawei Date: Fri, 13 Oct 2023 16:09:38 +0800 Subject: [PATCH 0787/1077] vdpa: Check device ack in vhost_vdpa_net_load_rx_mode() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Considering that vhost_vdpa_net_load_rx_mode() is only called within vhost_vdpa_net_load_rx() now, this patch refactors vhost_vdpa_net_load_rx_mode() to include a check for the device's ack, simplifying the code and improving its maintainability. Signed-off-by: Hawkins Jiawei Acked-by: Eugenio Pérez Message-Id: <68811d52f96ae12d68f0d67d996ac1642a623943.1697165821.git.yin31149@gmail.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- net/vhost-vdpa.c | 76 ++++++++++++++++++++---------------------------- 1 file changed, 31 insertions(+), 45 deletions(-) diff --git a/net/vhost-vdpa.c b/net/vhost-vdpa.c index 86b8d31244..36a4e57c0d 100644 --- a/net/vhost-vdpa.c +++ b/net/vhost-vdpa.c @@ -827,14 +827,24 @@ static int vhost_vdpa_net_load_rx_mode(VhostVDPAState *s, .iov_base = &on, .iov_len = sizeof(on), }; - return vhost_vdpa_net_load_cmd(s, VIRTIO_NET_CTRL_RX, - cmd, &data, 1); + ssize_t dev_written; + + dev_written = vhost_vdpa_net_load_cmd(s, VIRTIO_NET_CTRL_RX, + cmd, &data, 1); + if (unlikely(dev_written < 0)) { + return dev_written; + } + if (*s->status != VIRTIO_NET_OK) { + return -EIO; + } + + return 0; } static int vhost_vdpa_net_load_rx(VhostVDPAState *s, const VirtIONet *n) { - ssize_t dev_written; + ssize_t r; if (!virtio_vdev_has_feature(&n->parent_obj, VIRTIO_NET_F_CTRL_RX)) { return 0; @@ -859,13 +869,9 @@ static int vhost_vdpa_net_load_rx(VhostVDPAState *s, * configuration only at live migration. */ if (!n->mac_table.uni_overflow && !n->promisc) { - dev_written = vhost_vdpa_net_load_rx_mode(s, - VIRTIO_NET_CTRL_RX_PROMISC, 0); - if (unlikely(dev_written < 0)) { - return dev_written; - } - if (*s->status != VIRTIO_NET_OK) { - return -EIO; + r = vhost_vdpa_net_load_rx_mode(s, VIRTIO_NET_CTRL_RX_PROMISC, 0); + if (unlikely(r < 0)) { + return r; } } @@ -887,13 +893,9 @@ static int vhost_vdpa_net_load_rx(VhostVDPAState *s, * configuration only at live migration. */ if (n->mac_table.multi_overflow || n->allmulti) { - dev_written = vhost_vdpa_net_load_rx_mode(s, - VIRTIO_NET_CTRL_RX_ALLMULTI, 1); - if (unlikely(dev_written < 0)) { - return dev_written; - } - if (*s->status != VIRTIO_NET_OK) { - return -EIO; + r = vhost_vdpa_net_load_rx_mode(s, VIRTIO_NET_CTRL_RX_ALLMULTI, 1); + if (unlikely(r < 0)) { + return r; } } @@ -912,13 +914,9 @@ static int vhost_vdpa_net_load_rx(VhostVDPAState *s, * configuration only at live migration. */ if (n->alluni) { - dev_written = vhost_vdpa_net_load_rx_mode(s, - VIRTIO_NET_CTRL_RX_ALLUNI, 1); - if (dev_written < 0) { - return dev_written; - } - if (*s->status != VIRTIO_NET_OK) { - return -EIO; + r = vhost_vdpa_net_load_rx_mode(s, VIRTIO_NET_CTRL_RX_ALLUNI, 1); + if (r < 0) { + return r; } } @@ -933,13 +931,9 @@ static int vhost_vdpa_net_load_rx(VhostVDPAState *s, * configuration only at live migration. */ if (n->nomulti) { - dev_written = vhost_vdpa_net_load_rx_mode(s, - VIRTIO_NET_CTRL_RX_NOMULTI, 1); - if (dev_written < 0) { - return dev_written; - } - if (*s->status != VIRTIO_NET_OK) { - return -EIO; + r = vhost_vdpa_net_load_rx_mode(s, VIRTIO_NET_CTRL_RX_NOMULTI, 1); + if (r < 0) { + return r; } } @@ -954,13 +948,9 @@ static int vhost_vdpa_net_load_rx(VhostVDPAState *s, * configuration only at live migration. */ if (n->nouni) { - dev_written = vhost_vdpa_net_load_rx_mode(s, - VIRTIO_NET_CTRL_RX_NOUNI, 1); - if (dev_written < 0) { - return dev_written; - } - if (*s->status != VIRTIO_NET_OK) { - return -EIO; + r = vhost_vdpa_net_load_rx_mode(s, VIRTIO_NET_CTRL_RX_NOUNI, 1); + if (r < 0) { + return r; } } @@ -975,13 +965,9 @@ static int vhost_vdpa_net_load_rx(VhostVDPAState *s, * configuration only at live migration. */ if (n->nobcast) { - dev_written = vhost_vdpa_net_load_rx_mode(s, - VIRTIO_NET_CTRL_RX_NOBCAST, 1); - if (dev_written < 0) { - return dev_written; - } - if (*s->status != VIRTIO_NET_OK) { - return -EIO; + r = vhost_vdpa_net_load_rx_mode(s, VIRTIO_NET_CTRL_RX_NOBCAST, 1); + if (r < 0) { + return r; } } From a864a3219d7e63569583d204c12bff2a0f90463e Mon Sep 17 00:00:00 2001 From: Hawkins Jiawei Date: Fri, 13 Oct 2023 16:09:39 +0800 Subject: [PATCH 0788/1077] vdpa: Move vhost_svq_poll() to the caller of vhost_vdpa_net_cvq_add() This patch moves vhost_svq_poll() to the caller of vhost_vdpa_net_cvq_add() and introduces a helper funtion. By making this change, next patches in this series is able to refactor vhost_vdpa_net_load_x() only to delay the polling and checking process until either the SVQ is full or control commands shadow buffers are full. Signed-off-by: Hawkins Jiawei Message-Id: <196cadb55175a75275660c6634a538289f027ae3.1697165821.git.yin31149@gmail.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- net/vhost-vdpa.c | 53 +++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 43 insertions(+), 10 deletions(-) diff --git a/net/vhost-vdpa.c b/net/vhost-vdpa.c index 36a4e57c0d..ea73e3c410 100644 --- a/net/vhost-vdpa.c +++ b/net/vhost-vdpa.c @@ -631,15 +631,21 @@ static ssize_t vhost_vdpa_net_cvq_add(VhostVDPAState *s, qemu_log_mask(LOG_GUEST_ERROR, "%s: No space on device queue\n", __func__); } - return r; } - /* - * We can poll here since we've had BQL from the time we sent the - * descriptor. Also, we need to take the answer before SVQ pulls by itself, - * when BQL is released - */ - return vhost_svq_poll(svq, 1); + return r; +} + +/* + * Convenience wrapper to poll SVQ for multiple control commands. + * + * Caller should hold the BQL when invoking this function, and should take + * the answer before SVQ pulls by itself when BQL is released. + */ +static ssize_t vhost_vdpa_net_svq_poll(VhostVDPAState *s, size_t cmds_in_flight) +{ + VhostShadowVirtqueue *svq = g_ptr_array_index(s->vhost_vdpa.shadow_vqs, 0); + return vhost_svq_poll(svq, cmds_in_flight); } static ssize_t vhost_vdpa_net_load_cmd(VhostVDPAState *s, uint8_t class, @@ -660,6 +666,7 @@ static ssize_t vhost_vdpa_net_load_cmd(VhostVDPAState *s, uint8_t class, .iov_base = s->status, .iov_len = sizeof(*s->status), }; + ssize_t r; assert(data_size < vhost_vdpa_net_cvq_cmd_page_len() - sizeof(ctrl)); @@ -670,7 +677,16 @@ static ssize_t vhost_vdpa_net_load_cmd(VhostVDPAState *s, uint8_t class, iov_to_buf(data_sg, data_num, 0, s->cvq_cmd_out_buffer + sizeof(ctrl), data_size); - return vhost_vdpa_net_cvq_add(s, &out, 1, &in, 1); + r = vhost_vdpa_net_cvq_add(s, &out, 1, &in, 1); + if (unlikely(r < 0)) { + return r; + } + + /* + * We can poll here since we've had BQL from the time + * we sent the descriptor. + */ + return vhost_vdpa_net_svq_poll(s, 1); } static int vhost_vdpa_net_load_mac(VhostVDPAState *s, const VirtIONet *n) @@ -1165,6 +1181,15 @@ static int vhost_vdpa_net_excessive_mac_filter_cvq_add(VhostVDPAState *s, if (unlikely(r < 0)) { return r; } + + /* + * We can poll here since we've had BQL from the time + * we sent the descriptor. + */ + r = vhost_vdpa_net_svq_poll(s, 1); + if (unlikely(r < sizeof(*s->status))) { + return r; + } if (*s->status != VIRTIO_NET_OK) { return sizeof(*s->status); } @@ -1284,10 +1309,18 @@ static int vhost_vdpa_net_handle_ctrl_avail(VhostShadowVirtqueue *svq, goto out; } } else { - dev_written = vhost_vdpa_net_cvq_add(s, &out, 1, &vdpa_in, 1); - if (unlikely(dev_written < 0)) { + ssize_t r; + r = vhost_vdpa_net_cvq_add(s, &out, 1, &vdpa_in, 1); + if (unlikely(r < 0)) { + dev_written = r; goto out; } + + /* + * We can poll here since we've had BQL from the time + * we sent the descriptor. + */ + dev_written = vhost_vdpa_net_svq_poll(s, 1); } if (unlikely(dev_written < sizeof(status))) { From 1d7e2a8fd4996fdb20d74fce41fe897311f3b06a Mon Sep 17 00:00:00 2001 From: Hawkins Jiawei Date: Fri, 13 Oct 2023 16:09:40 +0800 Subject: [PATCH 0789/1077] vdpa: Introduce cursors to vhost_vdpa_net_loadx() This patch introduces two new arugments, `out_cursor` and `in_cursor`, to vhost_vdpa_net_loadx(). Addtionally, it includes a helper function vhost_vdpa_net_load_cursor_reset() for resetting these cursors. Furthermore, this patch refactors vhost_vdpa_net_load_cmd() so that vhost_vdpa_net_load_cmd() prepares buffers for the device using the cursors arguments, instead of directly accesses `s->cvq_cmd_out_buffer` and `s->status` fields. By making these change, next patches in this series can refactor vhost_vdpa_net_load_cmd() directly to iterate through the control commands shadow buffers, allowing QEMU to send CVQ state load commands in parallel at device startup. Signed-off-by: Hawkins Jiawei Message-Id: <1c6516e233a14cc222f0884e148e4e1adceda78d.1697165821.git.yin31149@gmail.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- net/vhost-vdpa.c | 111 ++++++++++++++++++++++++++++++++--------------- 1 file changed, 75 insertions(+), 36 deletions(-) diff --git a/net/vhost-vdpa.c b/net/vhost-vdpa.c index ea73e3c410..ef4d242811 100644 --- a/net/vhost-vdpa.c +++ b/net/vhost-vdpa.c @@ -648,7 +648,22 @@ static ssize_t vhost_vdpa_net_svq_poll(VhostVDPAState *s, size_t cmds_in_flight) return vhost_svq_poll(svq, cmds_in_flight); } -static ssize_t vhost_vdpa_net_load_cmd(VhostVDPAState *s, uint8_t class, +static void vhost_vdpa_net_load_cursor_reset(VhostVDPAState *s, + struct iovec *out_cursor, + struct iovec *in_cursor) +{ + /* reset the cursor of the output buffer for the device */ + out_cursor->iov_base = s->cvq_cmd_out_buffer; + out_cursor->iov_len = vhost_vdpa_net_cvq_cmd_page_len(); + + /* reset the cursor of the in buffer for the device */ + in_cursor->iov_base = s->status; + in_cursor->iov_len = vhost_vdpa_net_cvq_cmd_page_len(); +} + +static ssize_t vhost_vdpa_net_load_cmd(VhostVDPAState *s, + struct iovec *out_cursor, + struct iovec *in_cursor, uint8_t class, uint8_t cmd, const struct iovec *data_sg, size_t data_num) { @@ -657,25 +672,21 @@ static ssize_t vhost_vdpa_net_load_cmd(VhostVDPAState *s, uint8_t class, .cmd = cmd, }; size_t data_size = iov_size(data_sg, data_num); - /* Buffers for the device */ - const struct iovec out = { - .iov_base = s->cvq_cmd_out_buffer, - .iov_len = sizeof(ctrl) + data_size, - }; - const struct iovec in = { - .iov_base = s->status, - .iov_len = sizeof(*s->status), - }; + struct iovec out, in; ssize_t r; assert(data_size < vhost_vdpa_net_cvq_cmd_page_len() - sizeof(ctrl)); /* pack the CVQ command header */ - memcpy(s->cvq_cmd_out_buffer, &ctrl, sizeof(ctrl)); - + iov_from_buf(out_cursor, 1, 0, &ctrl, sizeof(ctrl)); /* pack the CVQ command command-specific-data */ iov_to_buf(data_sg, data_num, 0, - s->cvq_cmd_out_buffer + sizeof(ctrl), data_size); + out_cursor->iov_base + sizeof(ctrl), data_size); + + /* extract the required buffer from the cursor for output */ + iov_copy(&out, 1, out_cursor, 1, 0, sizeof(ctrl) + data_size); + /* extract the required buffer from the cursor for input */ + iov_copy(&in, 1, in_cursor, 1, 0, sizeof(*s->status)); r = vhost_vdpa_net_cvq_add(s, &out, 1, &in, 1); if (unlikely(r < 0)) { @@ -689,14 +700,17 @@ static ssize_t vhost_vdpa_net_load_cmd(VhostVDPAState *s, uint8_t class, return vhost_vdpa_net_svq_poll(s, 1); } -static int vhost_vdpa_net_load_mac(VhostVDPAState *s, const VirtIONet *n) +static int vhost_vdpa_net_load_mac(VhostVDPAState *s, const VirtIONet *n, + struct iovec *out_cursor, + struct iovec *in_cursor) { if (virtio_vdev_has_feature(&n->parent_obj, VIRTIO_NET_F_CTRL_MAC_ADDR)) { const struct iovec data = { .iov_base = (void *)n->mac, .iov_len = sizeof(n->mac), }; - ssize_t dev_written = vhost_vdpa_net_load_cmd(s, VIRTIO_NET_CTRL_MAC, + ssize_t dev_written = vhost_vdpa_net_load_cmd(s, out_cursor, in_cursor, + VIRTIO_NET_CTRL_MAC, VIRTIO_NET_CTRL_MAC_ADDR_SET, &data, 1); if (unlikely(dev_written < 0)) { @@ -748,7 +762,7 @@ static int vhost_vdpa_net_load_mac(VhostVDPAState *s, const VirtIONet *n) .iov_len = mul_macs_size, }, }; - ssize_t dev_written = vhost_vdpa_net_load_cmd(s, + ssize_t dev_written = vhost_vdpa_net_load_cmd(s, out_cursor, in_cursor, VIRTIO_NET_CTRL_MAC, VIRTIO_NET_CTRL_MAC_TABLE_SET, data, ARRAY_SIZE(data)); @@ -763,7 +777,9 @@ static int vhost_vdpa_net_load_mac(VhostVDPAState *s, const VirtIONet *n) } static int vhost_vdpa_net_load_mq(VhostVDPAState *s, - const VirtIONet *n) + const VirtIONet *n, + struct iovec *out_cursor, + struct iovec *in_cursor) { struct virtio_net_ctrl_mq mq; ssize_t dev_written; @@ -777,7 +793,8 @@ static int vhost_vdpa_net_load_mq(VhostVDPAState *s, .iov_base = &mq, .iov_len = sizeof(mq), }; - dev_written = vhost_vdpa_net_load_cmd(s, VIRTIO_NET_CTRL_MQ, + dev_written = vhost_vdpa_net_load_cmd(s, out_cursor, in_cursor, + VIRTIO_NET_CTRL_MQ, VIRTIO_NET_CTRL_MQ_VQ_PAIRS_SET, &data, 1); if (unlikely(dev_written < 0)) { @@ -791,7 +808,9 @@ static int vhost_vdpa_net_load_mq(VhostVDPAState *s, } static int vhost_vdpa_net_load_offloads(VhostVDPAState *s, - const VirtIONet *n) + const VirtIONet *n, + struct iovec *out_cursor, + struct iovec *in_cursor) { uint64_t offloads; ssize_t dev_written; @@ -822,7 +841,8 @@ static int vhost_vdpa_net_load_offloads(VhostVDPAState *s, .iov_base = &offloads, .iov_len = sizeof(offloads), }; - dev_written = vhost_vdpa_net_load_cmd(s, VIRTIO_NET_CTRL_GUEST_OFFLOADS, + dev_written = vhost_vdpa_net_load_cmd(s, out_cursor, in_cursor, + VIRTIO_NET_CTRL_GUEST_OFFLOADS, VIRTIO_NET_CTRL_GUEST_OFFLOADS_SET, &data, 1); if (unlikely(dev_written < 0)) { @@ -836,6 +856,8 @@ static int vhost_vdpa_net_load_offloads(VhostVDPAState *s, } static int vhost_vdpa_net_load_rx_mode(VhostVDPAState *s, + struct iovec *out_cursor, + struct iovec *in_cursor, uint8_t cmd, uint8_t on) { @@ -845,7 +867,8 @@ static int vhost_vdpa_net_load_rx_mode(VhostVDPAState *s, }; ssize_t dev_written; - dev_written = vhost_vdpa_net_load_cmd(s, VIRTIO_NET_CTRL_RX, + dev_written = vhost_vdpa_net_load_cmd(s, out_cursor, in_cursor, + VIRTIO_NET_CTRL_RX, cmd, &data, 1); if (unlikely(dev_written < 0)) { return dev_written; @@ -858,7 +881,9 @@ static int vhost_vdpa_net_load_rx_mode(VhostVDPAState *s, } static int vhost_vdpa_net_load_rx(VhostVDPAState *s, - const VirtIONet *n) + const VirtIONet *n, + struct iovec *out_cursor, + struct iovec *in_cursor) { ssize_t r; @@ -885,7 +910,8 @@ static int vhost_vdpa_net_load_rx(VhostVDPAState *s, * configuration only at live migration. */ if (!n->mac_table.uni_overflow && !n->promisc) { - r = vhost_vdpa_net_load_rx_mode(s, VIRTIO_NET_CTRL_RX_PROMISC, 0); + r = vhost_vdpa_net_load_rx_mode(s, out_cursor, in_cursor, + VIRTIO_NET_CTRL_RX_PROMISC, 0); if (unlikely(r < 0)) { return r; } @@ -909,7 +935,8 @@ static int vhost_vdpa_net_load_rx(VhostVDPAState *s, * configuration only at live migration. */ if (n->mac_table.multi_overflow || n->allmulti) { - r = vhost_vdpa_net_load_rx_mode(s, VIRTIO_NET_CTRL_RX_ALLMULTI, 1); + r = vhost_vdpa_net_load_rx_mode(s, out_cursor, in_cursor, + VIRTIO_NET_CTRL_RX_ALLMULTI, 1); if (unlikely(r < 0)) { return r; } @@ -930,7 +957,8 @@ static int vhost_vdpa_net_load_rx(VhostVDPAState *s, * configuration only at live migration. */ if (n->alluni) { - r = vhost_vdpa_net_load_rx_mode(s, VIRTIO_NET_CTRL_RX_ALLUNI, 1); + r = vhost_vdpa_net_load_rx_mode(s, out_cursor, in_cursor, + VIRTIO_NET_CTRL_RX_ALLUNI, 1); if (r < 0) { return r; } @@ -947,7 +975,8 @@ static int vhost_vdpa_net_load_rx(VhostVDPAState *s, * configuration only at live migration. */ if (n->nomulti) { - r = vhost_vdpa_net_load_rx_mode(s, VIRTIO_NET_CTRL_RX_NOMULTI, 1); + r = vhost_vdpa_net_load_rx_mode(s, out_cursor, in_cursor, + VIRTIO_NET_CTRL_RX_NOMULTI, 1); if (r < 0) { return r; } @@ -964,7 +993,8 @@ static int vhost_vdpa_net_load_rx(VhostVDPAState *s, * configuration only at live migration. */ if (n->nouni) { - r = vhost_vdpa_net_load_rx_mode(s, VIRTIO_NET_CTRL_RX_NOUNI, 1); + r = vhost_vdpa_net_load_rx_mode(s, out_cursor, in_cursor, + VIRTIO_NET_CTRL_RX_NOUNI, 1); if (r < 0) { return r; } @@ -981,7 +1011,8 @@ static int vhost_vdpa_net_load_rx(VhostVDPAState *s, * configuration only at live migration. */ if (n->nobcast) { - r = vhost_vdpa_net_load_rx_mode(s, VIRTIO_NET_CTRL_RX_NOBCAST, 1); + r = vhost_vdpa_net_load_rx_mode(s, out_cursor, in_cursor, + VIRTIO_NET_CTRL_RX_NOBCAST, 1); if (r < 0) { return r; } @@ -992,13 +1023,16 @@ static int vhost_vdpa_net_load_rx(VhostVDPAState *s, static int vhost_vdpa_net_load_single_vlan(VhostVDPAState *s, const VirtIONet *n, + struct iovec *out_cursor, + struct iovec *in_cursor, uint16_t vid) { const struct iovec data = { .iov_base = &vid, .iov_len = sizeof(vid), }; - ssize_t dev_written = vhost_vdpa_net_load_cmd(s, VIRTIO_NET_CTRL_VLAN, + ssize_t dev_written = vhost_vdpa_net_load_cmd(s, out_cursor, in_cursor, + VIRTIO_NET_CTRL_VLAN, VIRTIO_NET_CTRL_VLAN_ADD, &data, 1); if (unlikely(dev_written < 0)) { @@ -1012,7 +1046,9 @@ static int vhost_vdpa_net_load_single_vlan(VhostVDPAState *s, } static int vhost_vdpa_net_load_vlan(VhostVDPAState *s, - const VirtIONet *n) + const VirtIONet *n, + struct iovec *out_cursor, + struct iovec *in_cursor) { int r; @@ -1023,7 +1059,8 @@ static int vhost_vdpa_net_load_vlan(VhostVDPAState *s, for (int i = 0; i < MAX_VLAN >> 5; i++) { for (int j = 0; n->vlans[i] && j <= 0x1f; j++) { if (n->vlans[i] & (1U << j)) { - r = vhost_vdpa_net_load_single_vlan(s, n, (i << 5) + j); + r = vhost_vdpa_net_load_single_vlan(s, n, out_cursor, + in_cursor, (i << 5) + j); if (unlikely(r != 0)) { return r; } @@ -1040,6 +1077,7 @@ static int vhost_vdpa_net_cvq_load(NetClientState *nc) struct vhost_vdpa *v = &s->vhost_vdpa; const VirtIONet *n; int r; + struct iovec out_cursor, in_cursor; assert(nc->info->type == NET_CLIENT_DRIVER_VHOST_VDPA); @@ -1047,23 +1085,24 @@ static int vhost_vdpa_net_cvq_load(NetClientState *nc) if (v->shadow_vqs_enabled) { n = VIRTIO_NET(v->dev->vdev); - r = vhost_vdpa_net_load_mac(s, n); + vhost_vdpa_net_load_cursor_reset(s, &out_cursor, &in_cursor); + r = vhost_vdpa_net_load_mac(s, n, &out_cursor, &in_cursor); if (unlikely(r < 0)) { return r; } - r = vhost_vdpa_net_load_mq(s, n); + r = vhost_vdpa_net_load_mq(s, n, &out_cursor, &in_cursor); if (unlikely(r)) { return r; } - r = vhost_vdpa_net_load_offloads(s, n); + r = vhost_vdpa_net_load_offloads(s, n, &out_cursor, &in_cursor); if (unlikely(r)) { return r; } - r = vhost_vdpa_net_load_rx(s, n); + r = vhost_vdpa_net_load_rx(s, n, &out_cursor, &in_cursor); if (unlikely(r)) { return r; } - r = vhost_vdpa_net_load_vlan(s, n); + r = vhost_vdpa_net_load_vlan(s, n, &out_cursor, &in_cursor); if (unlikely(r)) { return r; } From 99d6a32469debf1a48921125879b614d15acfb7a Mon Sep 17 00:00:00 2001 From: Hawkins Jiawei Date: Fri, 13 Oct 2023 16:09:41 +0800 Subject: [PATCH 0790/1077] vhost: Expose vhost_svq_available_slots() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Next patches in this series will delay the polling and checking of buffers until either the SVQ is full or control commands shadow buffers are full, no longer perform an immediate poll and check of the device's used buffers for each CVQ state load command. To achieve this, this patch exposes vhost_svq_available_slots(), allowing QEMU to know whether the SVQ is full. Signed-off-by: Hawkins Jiawei Acked-by: Eugenio Pérez Message-Id: <25938079f0bd8185fd664c64e205e629f7a966be.1697165821.git.yin31149@gmail.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/virtio/vhost-shadow-virtqueue.c | 2 +- hw/virtio/vhost-shadow-virtqueue.h | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/hw/virtio/vhost-shadow-virtqueue.c b/hw/virtio/vhost-shadow-virtqueue.c index e731b1d2ea..fc5f408f77 100644 --- a/hw/virtio/vhost-shadow-virtqueue.c +++ b/hw/virtio/vhost-shadow-virtqueue.c @@ -66,7 +66,7 @@ bool vhost_svq_valid_features(uint64_t features, Error **errp) * * @svq: The svq */ -static uint16_t vhost_svq_available_slots(const VhostShadowVirtqueue *svq) +uint16_t vhost_svq_available_slots(const VhostShadowVirtqueue *svq) { return svq->num_free; } diff --git a/hw/virtio/vhost-shadow-virtqueue.h b/hw/virtio/vhost-shadow-virtqueue.h index 5bce67837b..19c842a15b 100644 --- a/hw/virtio/vhost-shadow-virtqueue.h +++ b/hw/virtio/vhost-shadow-virtqueue.h @@ -114,6 +114,7 @@ typedef struct VhostShadowVirtqueue { bool vhost_svq_valid_features(uint64_t features, Error **errp); +uint16_t vhost_svq_available_slots(const VhostShadowVirtqueue *svq); void vhost_svq_push_elem(VhostShadowVirtqueue *svq, const VirtQueueElement *elem, uint32_t len); int vhost_svq_add(VhostShadowVirtqueue *svq, const struct iovec *out_sg, From acec5f685c7ad6bd3c9bb9a57d4e509160480376 Mon Sep 17 00:00:00 2001 From: Hawkins Jiawei Date: Fri, 13 Oct 2023 16:09:42 +0800 Subject: [PATCH 0791/1077] vdpa: Send cvq state load commands in parallel MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This patch enables sending CVQ state load commands in parallel at device startup by following steps: * Refactor vhost_vdpa_net_load_cmd() to iterate through the control commands shadow buffers. This allows different CVQ state load commands to use their own unique buffers. * Delay the polling and checking of buffers until either the SVQ is full or control commands shadow buffers are full. Resolves: https://gitlab.com/qemu-project/qemu/-/issues/1578 Signed-off-by: Hawkins Jiawei Acked-by: Eugenio Pérez Message-Id: <9350f32278e39f7bce297b8f2d82dac27c6f8c9a.1697165821.git.yin31149@gmail.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- net/vhost-vdpa.c | 165 +++++++++++++++++++++++++++++------------------ 1 file changed, 102 insertions(+), 63 deletions(-) diff --git a/net/vhost-vdpa.c b/net/vhost-vdpa.c index ef4d242811..4b7c3b81b8 100644 --- a/net/vhost-vdpa.c +++ b/net/vhost-vdpa.c @@ -661,6 +661,31 @@ static void vhost_vdpa_net_load_cursor_reset(VhostVDPAState *s, in_cursor->iov_len = vhost_vdpa_net_cvq_cmd_page_len(); } +/* + * Poll SVQ for multiple pending control commands and check the device's ack. + * + * Caller should hold the BQL when invoking this function. + * + * @s: The VhostVDPAState + * @len: The length of the pending status shadow buffer + */ +static ssize_t vhost_vdpa_net_svq_flush(VhostVDPAState *s, size_t len) +{ + /* device uses a one-byte length ack for each control command */ + ssize_t dev_written = vhost_vdpa_net_svq_poll(s, len); + if (unlikely(dev_written != len)) { + return -EIO; + } + + /* check the device's ack */ + for (int i = 0; i < len; ++i) { + if (s->status[i] != VIRTIO_NET_OK) { + return -EIO; + } + } + return 0; +} + static ssize_t vhost_vdpa_net_load_cmd(VhostVDPAState *s, struct iovec *out_cursor, struct iovec *in_cursor, uint8_t class, @@ -671,11 +696,31 @@ static ssize_t vhost_vdpa_net_load_cmd(VhostVDPAState *s, .class = class, .cmd = cmd, }; - size_t data_size = iov_size(data_sg, data_num); + size_t data_size = iov_size(data_sg, data_num), cmd_size; struct iovec out, in; ssize_t r; + unsigned dummy_cursor_iov_cnt; + VhostShadowVirtqueue *svq = g_ptr_array_index(s->vhost_vdpa.shadow_vqs, 0); assert(data_size < vhost_vdpa_net_cvq_cmd_page_len() - sizeof(ctrl)); + cmd_size = sizeof(ctrl) + data_size; + if (vhost_svq_available_slots(svq) < 2 || + iov_size(out_cursor, 1) < cmd_size) { + /* + * It is time to flush all pending control commands if SVQ is full + * or control commands shadow buffers are full. + * + * We can poll here since we've had BQL from the time + * we sent the descriptor. + */ + r = vhost_vdpa_net_svq_flush(s, in_cursor->iov_base - + (void *)s->status); + if (unlikely(r < 0)) { + return r; + } + + vhost_vdpa_net_load_cursor_reset(s, out_cursor, in_cursor); + } /* pack the CVQ command header */ iov_from_buf(out_cursor, 1, 0, &ctrl, sizeof(ctrl)); @@ -684,7 +729,7 @@ static ssize_t vhost_vdpa_net_load_cmd(VhostVDPAState *s, out_cursor->iov_base + sizeof(ctrl), data_size); /* extract the required buffer from the cursor for output */ - iov_copy(&out, 1, out_cursor, 1, 0, sizeof(ctrl) + data_size); + iov_copy(&out, 1, out_cursor, 1, 0, cmd_size); /* extract the required buffer from the cursor for input */ iov_copy(&in, 1, in_cursor, 1, 0, sizeof(*s->status)); @@ -693,11 +738,13 @@ static ssize_t vhost_vdpa_net_load_cmd(VhostVDPAState *s, return r; } - /* - * We can poll here since we've had BQL from the time - * we sent the descriptor. - */ - return vhost_vdpa_net_svq_poll(s, 1); + /* iterate the cursors */ + dummy_cursor_iov_cnt = 1; + iov_discard_front(&out_cursor, &dummy_cursor_iov_cnt, cmd_size); + dummy_cursor_iov_cnt = 1; + iov_discard_front(&in_cursor, &dummy_cursor_iov_cnt, sizeof(*s->status)); + + return 0; } static int vhost_vdpa_net_load_mac(VhostVDPAState *s, const VirtIONet *n, @@ -709,15 +756,12 @@ static int vhost_vdpa_net_load_mac(VhostVDPAState *s, const VirtIONet *n, .iov_base = (void *)n->mac, .iov_len = sizeof(n->mac), }; - ssize_t dev_written = vhost_vdpa_net_load_cmd(s, out_cursor, in_cursor, - VIRTIO_NET_CTRL_MAC, - VIRTIO_NET_CTRL_MAC_ADDR_SET, - &data, 1); - if (unlikely(dev_written < 0)) { - return dev_written; - } - if (*s->status != VIRTIO_NET_OK) { - return -EIO; + ssize_t r = vhost_vdpa_net_load_cmd(s, out_cursor, in_cursor, + VIRTIO_NET_CTRL_MAC, + VIRTIO_NET_CTRL_MAC_ADDR_SET, + &data, 1); + if (unlikely(r < 0)) { + return r; } } @@ -762,15 +806,12 @@ static int vhost_vdpa_net_load_mac(VhostVDPAState *s, const VirtIONet *n, .iov_len = mul_macs_size, }, }; - ssize_t dev_written = vhost_vdpa_net_load_cmd(s, out_cursor, in_cursor, - VIRTIO_NET_CTRL_MAC, - VIRTIO_NET_CTRL_MAC_TABLE_SET, - data, ARRAY_SIZE(data)); - if (unlikely(dev_written < 0)) { - return dev_written; - } - if (*s->status != VIRTIO_NET_OK) { - return -EIO; + ssize_t r = vhost_vdpa_net_load_cmd(s, out_cursor, in_cursor, + VIRTIO_NET_CTRL_MAC, + VIRTIO_NET_CTRL_MAC_TABLE_SET, + data, ARRAY_SIZE(data)); + if (unlikely(r < 0)) { + return r; } return 0; @@ -782,7 +823,7 @@ static int vhost_vdpa_net_load_mq(VhostVDPAState *s, struct iovec *in_cursor) { struct virtio_net_ctrl_mq mq; - ssize_t dev_written; + ssize_t r; if (!virtio_vdev_has_feature(&n->parent_obj, VIRTIO_NET_F_MQ)) { return 0; @@ -793,15 +834,12 @@ static int vhost_vdpa_net_load_mq(VhostVDPAState *s, .iov_base = &mq, .iov_len = sizeof(mq), }; - dev_written = vhost_vdpa_net_load_cmd(s, out_cursor, in_cursor, - VIRTIO_NET_CTRL_MQ, - VIRTIO_NET_CTRL_MQ_VQ_PAIRS_SET, - &data, 1); - if (unlikely(dev_written < 0)) { - return dev_written; - } - if (*s->status != VIRTIO_NET_OK) { - return -EIO; + r = vhost_vdpa_net_load_cmd(s, out_cursor, in_cursor, + VIRTIO_NET_CTRL_MQ, + VIRTIO_NET_CTRL_MQ_VQ_PAIRS_SET, + &data, 1); + if (unlikely(r < 0)) { + return r; } return 0; @@ -813,7 +851,7 @@ static int vhost_vdpa_net_load_offloads(VhostVDPAState *s, struct iovec *in_cursor) { uint64_t offloads; - ssize_t dev_written; + ssize_t r; if (!virtio_vdev_has_feature(&n->parent_obj, VIRTIO_NET_F_CTRL_GUEST_OFFLOADS)) { @@ -841,15 +879,12 @@ static int vhost_vdpa_net_load_offloads(VhostVDPAState *s, .iov_base = &offloads, .iov_len = sizeof(offloads), }; - dev_written = vhost_vdpa_net_load_cmd(s, out_cursor, in_cursor, - VIRTIO_NET_CTRL_GUEST_OFFLOADS, - VIRTIO_NET_CTRL_GUEST_OFFLOADS_SET, - &data, 1); - if (unlikely(dev_written < 0)) { - return dev_written; - } - if (*s->status != VIRTIO_NET_OK) { - return -EIO; + r = vhost_vdpa_net_load_cmd(s, out_cursor, in_cursor, + VIRTIO_NET_CTRL_GUEST_OFFLOADS, + VIRTIO_NET_CTRL_GUEST_OFFLOADS_SET, + &data, 1); + if (unlikely(r < 0)) { + return r; } return 0; @@ -865,16 +900,12 @@ static int vhost_vdpa_net_load_rx_mode(VhostVDPAState *s, .iov_base = &on, .iov_len = sizeof(on), }; - ssize_t dev_written; + ssize_t r; - dev_written = vhost_vdpa_net_load_cmd(s, out_cursor, in_cursor, - VIRTIO_NET_CTRL_RX, - cmd, &data, 1); - if (unlikely(dev_written < 0)) { - return dev_written; - } - if (*s->status != VIRTIO_NET_OK) { - return -EIO; + r = vhost_vdpa_net_load_cmd(s, out_cursor, in_cursor, + VIRTIO_NET_CTRL_RX, cmd, &data, 1); + if (unlikely(r < 0)) { + return r; } return 0; @@ -1031,15 +1062,12 @@ static int vhost_vdpa_net_load_single_vlan(VhostVDPAState *s, .iov_base = &vid, .iov_len = sizeof(vid), }; - ssize_t dev_written = vhost_vdpa_net_load_cmd(s, out_cursor, in_cursor, - VIRTIO_NET_CTRL_VLAN, - VIRTIO_NET_CTRL_VLAN_ADD, - &data, 1); - if (unlikely(dev_written < 0)) { - return dev_written; - } - if (unlikely(*s->status != VIRTIO_NET_OK)) { - return -EIO; + ssize_t r = vhost_vdpa_net_load_cmd(s, out_cursor, in_cursor, + VIRTIO_NET_CTRL_VLAN, + VIRTIO_NET_CTRL_VLAN_ADD, + &data, 1); + if (unlikely(r < 0)) { + return r; } return 0; @@ -1106,6 +1134,17 @@ static int vhost_vdpa_net_cvq_load(NetClientState *nc) if (unlikely(r)) { return r; } + + /* + * We need to poll and check all pending device's used buffers. + * + * We can poll here since we've had BQL from the time + * we sent the descriptor. + */ + r = vhost_vdpa_net_svq_flush(s, in_cursor.iov_base - (void *)s->status); + if (unlikely(r)) { + return r; + } } for (int i = 0; i < v->dev->vq_index; ++i) { From e6e66b03287331abc6f184456dbc6d25505590ec Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 30 Aug 2023 13:33:54 -0700 Subject: [PATCH 0792/1077] linux-user: Fixes for zero_bss MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The previous change, 2d385be6152, assumed !PAGE_VALID meant that the page would be unmapped by the elf image. However, since we reserved the entire image space via mmap, PAGE_VALID will always be set. Instead, assume PROT_NONE for the same condition. Furthermore, assume bss is only ever present for writable segments, and that there is no page overlap between PT_LOAD segments. Instead of an assert, return false to indicate failure. Cc: qemu-stable@nongnu.org Resolves: https://gitlab.com/qemu-project/qemu/-/issues/1854 Fixes: 2d385be6152 ("linux-user: Do not adjust zero_bss for host page size") Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Richard Henderson --- linux-user/elfload.c | 53 +++++++++++++++++++++++++++++++++----------- 1 file changed, 40 insertions(+), 13 deletions(-) diff --git a/linux-user/elfload.c b/linux-user/elfload.c index f21e2e0c3d..213fd3e584 100644 --- a/linux-user/elfload.c +++ b/linux-user/elfload.c @@ -2362,31 +2362,58 @@ static abi_ulong setup_arg_pages(struct linux_binprm *bprm, * Map and zero the bss. We need to explicitly zero any fractional pages * after the data section (i.e. bss). Return false on mapping failure. */ -static bool zero_bss(abi_ulong start_bss, abi_ulong end_bss, int prot) +static bool zero_bss(abi_ulong start_bss, abi_ulong end_bss, + int prot, Error **errp) { abi_ulong align_bss; + /* We only expect writable bss; the code segment shouldn't need this. */ + if (!(prot & PROT_WRITE)) { + error_setg(errp, "PT_LOAD with non-writable bss"); + return false; + } + align_bss = TARGET_PAGE_ALIGN(start_bss); end_bss = TARGET_PAGE_ALIGN(end_bss); if (start_bss < align_bss) { int flags = page_get_flags(start_bss); - if (!(flags & PAGE_VALID)) { - /* Map the start of the bss. */ + if (!(flags & PAGE_BITS)) { + /* + * The whole address space of the executable was reserved + * at the start, therefore all pages will be VALID. + * But assuming there are no PROT_NONE PT_LOAD segments, + * a PROT_NONE page means no data all bss, and we can + * simply extend the new anon mapping back to the start + * of the page of bss. + */ align_bss -= TARGET_PAGE_SIZE; - } else if (flags & PAGE_WRITE) { - /* The page is already mapped writable. */ - memset(g2h_untagged(start_bss), 0, align_bss - start_bss); } else { - /* Read-only zeros? */ - g_assert_not_reached(); + /* + * The start of the bss shares a page with something. + * The only thing that we expect is the data section, + * which would already be marked writable. + * Overlapping the RX code segment seems malformed. + */ + if (!(flags & PAGE_WRITE)) { + error_setg(errp, "PT_LOAD with bss overlapping " + "non-writable page"); + return false; + } + + /* The page is already mapped and writable. */ + memset(g2h_untagged(start_bss), 0, align_bss - start_bss); } } - return align_bss >= end_bss || - target_mmap(align_bss, end_bss - align_bss, prot, - MAP_FIXED | MAP_PRIVATE | MAP_ANON, -1, 0) != -1; + if (align_bss < end_bss && + target_mmap(align_bss, end_bss - align_bss, prot, + MAP_FIXED | MAP_PRIVATE | MAP_ANON, -1, 0) == -1) { + error_setg_errno(errp, errno, "Error mapping bss"); + return false; + } + return true; } #if defined(TARGET_ARM) @@ -3410,8 +3437,8 @@ static void load_elf_image(const char *image_name, int image_fd, /* If the load segment requests extra zeros (e.g. bss), map it. */ if (vaddr_ef < vaddr_em && - !zero_bss(vaddr_ef, vaddr_em, elf_prot)) { - goto exit_mmap; + !zero_bss(vaddr_ef, vaddr_em, elf_prot, &err)) { + goto exit_errmsg; } /* Find the full program boundaries. */ From 6fad9b4bb91dcc824f9c00a36ee843883b58313b Mon Sep 17 00:00:00 2001 From: Mikulas Patocka Date: Thu, 28 Sep 2023 21:55:20 +0200 Subject: [PATCH 0793/1077] linux-user/mips: fix abort on integer overflow QEMU mips userspace emulation crashes with "qemu: unhandled CPU exception 0x15 - aborting" when one of the integer arithmetic instructions detects an overflow. This patch fixes it so that it delivers SIGFPE with FPE_INTOVF instead. Cc: qemu-stable@nongnu.org Signed-off-by: Mikulas Patocka Message-Id: <3ef979a8-3ee1-eb2d-71f7-d788ff88dd11@redhat.com> Reviewed-by: Richard Henderson Signed-off-by: Richard Henderson --- linux-user/mips/cpu_loop.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/linux-user/mips/cpu_loop.c b/linux-user/mips/cpu_loop.c index 8735e58bad..990b03e727 100644 --- a/linux-user/mips/cpu_loop.c +++ b/linux-user/mips/cpu_loop.c @@ -180,7 +180,9 @@ done_syscall: } force_sig_fault(TARGET_SIGFPE, si_code, env->active_tc.PC); break; - + case EXCP_OVERFLOW: + force_sig_fault(TARGET_SIGFPE, TARGET_FPE_INTOVF, env->active_tc.PC); + break; /* The code below was inspired by the MIPS Linux kernel trap * handling code in arch/mips/kernel/traps.c. */ From 3b894b699c9a9c064466e128c18be80a3f2113bc Mon Sep 17 00:00:00 2001 From: Mikulas Patocka Date: Thu, 28 Sep 2023 18:42:08 +0200 Subject: [PATCH 0794/1077] linux-user/sh4: Fix crashes on signal delivery sh4 uses gUSA (general UserSpace Atomicity) to provide atomicity on CPUs that don't have atomic instructions. A gUSA region that adds 1 to an atomic variable stored in @R2 looks like this: 4004b6: 03 c7 mova 4004c4 ,r0 4004b8: f3 61 mov r15,r1 4004ba: 09 00 nop 4004bc: fa ef mov #-6,r15 4004be: 22 63 mov.l @r2,r3 4004c0: 01 73 add #1,r3 4004c2: 32 22 mov.l r3,@r2 4004c4: 13 6f mov r1,r15 R0 contains a pointer to the end of the gUSA region R1 contains the saved stack pointer R15 contains negative length of the gUSA region When this region is interrupted by a signal, the kernel detects if R15 >= -128U. If yes, the kernel rolls back PC to the beginning of the region and restores SP by copying R1 to R15. The problem happens if we are interrupted by a signal at address 4004c4. R15 still holds the value -6, but the atomic value was already written by an instruction at address 4004c2. In this situation we can't undo the gUSA. The function unwind_gusa does nothing, the signal handler attempts to push a signal frame to the address -6 and crashes. This patch fixes it, so that if we are interrupted at the last instruction in a gUSA region, we copy R1 to R15 to restore the correct stack pointer and avoid crashing. There's another bug: if we are interrupted in a delay slot, we save the address of the instruction in the delay slot. We must save the address of the previous instruction. Cc: qemu-stable@nongnu.org Signed-off-by: Mikulas Patocka Reviewed-by: Yoshinori Sato Message-Id: Reviewed-by: Richard Henderson Signed-off-by: Richard Henderson --- linux-user/sh4/signal.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/linux-user/sh4/signal.c b/linux-user/sh4/signal.c index c4ba962708..c16c2c2d57 100644 --- a/linux-user/sh4/signal.c +++ b/linux-user/sh4/signal.c @@ -104,6 +104,14 @@ static void unwind_gusa(CPUSH4State *regs) /* Reset the SP to the saved version in R1. */ regs->gregs[15] = regs->gregs[1]; + } else if (regs->gregs[15] >= -128u && regs->pc == regs->gregs[0]) { + /* If we are on the last instruction of a gUSA region, we must reset + the SP, otherwise we would be pushing the signal context to + invalid memory. */ + regs->gregs[15] = regs->gregs[1]; + } else if (regs->flags & TB_FLAG_DELAY_SLOT) { + /* If we are in a delay slot, push the previous instruction. */ + regs->pc -= 2; } } From a9f6004f677923f620e0927a626d1bdaa1eb2166 Mon Sep 17 00:00:00 2001 From: Jiajie Chen Date: Sun, 1 Oct 2023 16:53:05 +0800 Subject: [PATCH 0795/1077] linux-user/elfload: Enable LSX/LASX in HWCAP for LoongArch Since support for LSX and LASX is landed in QEMU recently, we can update HWCAPS accordingly. Signed-off-by: Jiajie Chen Reviewed-by: Richard Henderson Message-Id: <20231001085315.1692667-1-c@jia.je> Signed-off-by: Richard Henderson --- linux-user/elfload.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/linux-user/elfload.c b/linux-user/elfload.c index 213fd3e584..2e3809f03c 100644 --- a/linux-user/elfload.c +++ b/linux-user/elfload.c @@ -1237,6 +1237,14 @@ static uint32_t get_elf_hwcap(void) hwcaps |= HWCAP_LOONGARCH_LAM; } + if (FIELD_EX32(cpu->env.cpucfg[2], CPUCFG2, LSX)) { + hwcaps |= HWCAP_LOONGARCH_LSX; + } + + if (FIELD_EX32(cpu->env.cpucfg[2], CPUCFG2, LASX)) { + hwcaps |= HWCAP_LOONGARCH_LASX; + } + return hwcaps; } From 912ff698cae8879d981157fd8cca1354248fddcc Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Tue, 3 Oct 2023 13:59:55 -0700 Subject: [PATCH 0796/1077] linux-user: Propagate failure in mmap_reserve_or_unmap back to target_munmap Do not assert success, but return any failure received. Additionally, fix the method of earlier error return in target_munmap. Reported-by: Andreas Schwab Signed-off-by: Richard Henderson --- linux-user/mmap.c | 30 +++++++++++++++++------------- 1 file changed, 17 insertions(+), 13 deletions(-) diff --git a/linux-user/mmap.c b/linux-user/mmap.c index 8ccaab7859..7b44b9ff49 100644 --- a/linux-user/mmap.c +++ b/linux-user/mmap.c @@ -778,7 +778,7 @@ fail: return -1; } -static void mmap_reserve_or_unmap(abi_ulong start, abi_ulong len) +static int mmap_reserve_or_unmap(abi_ulong start, abi_ulong len) { abi_ulong real_start; abi_ulong real_last; @@ -807,7 +807,7 @@ static void mmap_reserve_or_unmap(abi_ulong start, abi_ulong len) prot |= page_get_flags(a + 1); } if (prot != 0) { - return; + return 0; } } else { for (prot = 0, a = real_start; a < start; a += TARGET_PAGE_SIZE) { @@ -825,7 +825,7 @@ static void mmap_reserve_or_unmap(abi_ulong start, abi_ulong len) } if (real_last < real_start) { - return; + return 0; } } @@ -836,32 +836,36 @@ static void mmap_reserve_or_unmap(abi_ulong start, abi_ulong len) void *ptr = mmap(host_start, real_len, PROT_NONE, MAP_FIXED | MAP_ANONYMOUS | MAP_PRIVATE | MAP_NORESERVE, -1, 0); - assert(ptr == host_start); - } else { - int ret = munmap(host_start, real_len); - assert(ret == 0); + return ptr == host_start ? 0 : -1; } + return munmap(host_start, real_len); } int target_munmap(abi_ulong start, abi_ulong len) { + int ret; + trace_target_munmap(start, len); if (start & ~TARGET_PAGE_MASK) { - return -TARGET_EINVAL; + errno = EINVAL; + return -1; } len = TARGET_PAGE_ALIGN(len); if (len == 0 || !guest_range_valid_untagged(start, len)) { - return -TARGET_EINVAL; + errno = EINVAL; + return -1; } mmap_lock(); - mmap_reserve_or_unmap(start, len); - page_set_flags(start, start + len - 1, 0); - shm_region_rm_complete(start, start + len - 1); + ret = mmap_reserve_or_unmap(start, len); + if (likely(ret == 0)) { + page_set_flags(start, start + len - 1, 0); + shm_region_rm_complete(start, start + len - 1); + } mmap_unlock(); - return 0; + return ret; } abi_long target_mremap(abi_ulong old_addr, abi_ulong old_size, From b8b50f1e9ac8007831c2df1bd0d728f420d5818c Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Tue, 22 Aug 2023 12:53:19 -0700 Subject: [PATCH 0797/1077] linux-user: Split out die_with_signal MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Because we trap so many signals for use by the guest, we have to take extra steps to exit properly. Acked-by: Helge Deller Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Richard Henderson --- linux-user/signal.c | 52 ++++++++++++++++++++++++--------------------- 1 file changed, 28 insertions(+), 24 deletions(-) diff --git a/linux-user/signal.c b/linux-user/signal.c index a67ab47d30..b7a2c47837 100644 --- a/linux-user/signal.c +++ b/linux-user/signal.c @@ -689,13 +689,39 @@ void cpu_loop_exit_sigbus(CPUState *cpu, target_ulong addr, } /* abort execution with signal */ +static G_NORETURN +void die_with_signal(int host_sig) +{ + struct sigaction act = { + .sa_handler = SIG_DFL, + }; + + /* + * The proper exit code for dying from an uncaught signal is -. + * The kernel doesn't allow exit() or _exit() to pass a negative value. + * To get the proper exit code we need to actually die from an uncaught + * signal. Here the default signal handler is installed, we send + * the signal and we wait for it to arrive. + */ + sigfillset(&act.sa_mask); + sigaction(host_sig, &act, NULL); + + kill(getpid(), host_sig); + + /* Make sure the signal isn't masked (reusing the mask inside of act). */ + sigdelset(&act.sa_mask, host_sig); + sigsuspend(&act.sa_mask); + + /* unreachable */ + abort(); +} + static G_NORETURN void dump_core_and_abort(CPUArchState *env, int target_sig) { CPUState *cpu = env_cpu(env); TaskState *ts = (TaskState *)cpu->opaque; int host_sig, core_dumped = 0; - struct sigaction act; host_sig = target_to_host_signal(target_sig); trace_user_dump_core_and_abort(env, target_sig, host_sig); @@ -719,29 +745,7 @@ void dump_core_and_abort(CPUArchState *env, int target_sig) } preexit_cleanup(env, 128 + target_sig); - - /* The proper exit code for dying from an uncaught signal is - * -. The kernel doesn't allow exit() or _exit() to pass - * a negative value. To get the proper exit code we need to - * actually die from an uncaught signal. Here the default signal - * handler is installed, we send ourself a signal and we wait for - * it to arrive. */ - sigfillset(&act.sa_mask); - act.sa_handler = SIG_DFL; - act.sa_flags = 0; - sigaction(host_sig, &act, NULL); - - /* For some reason raise(host_sig) doesn't send the signal when - * statically linked on x86-64. */ - kill(getpid(), host_sig); - - /* Make sure the signal isn't masked (just reuse the mask inside - of act) */ - sigdelset(&act.sa_mask, host_sig); - sigsuspend(&act.sa_mask); - - /* unreachable */ - abort(); + die_with_signal(host_sig); } /* queue a signal so that it will be send to the virtual CPU as soon From ee72c47eebe119575b2bb684912bbb8c9efc9ba7 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Tue, 22 Aug 2023 13:08:11 -0700 Subject: [PATCH 0798/1077] linux-user: Exit not abort in die_with_backtrace MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This line is supposed to be unreachable, but if we're going to have it at all, SIGABRT via abort() is subject to the same signal peril that created this function in the first place. We can _exit immediately without peril. Acked-by: Helge Deller Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Richard Henderson --- linux-user/signal.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/linux-user/signal.c b/linux-user/signal.c index b7a2c47837..84a56b76cc 100644 --- a/linux-user/signal.c +++ b/linux-user/signal.c @@ -713,7 +713,7 @@ void die_with_signal(int host_sig) sigsuspend(&act.sa_mask); /* unreachable */ - abort(); + _exit(EXIT_FAILURE); } static G_NORETURN From 7dfd3ca8d95f9962cdd2ebdfcdd699279b98fa18 Mon Sep 17 00:00:00 2001 From: Helge Deller Date: Sat, 12 Aug 2023 18:43:14 +0200 Subject: [PATCH 0799/1077] linux-user: Detect and report host crashes If there is an internal program error in the qemu source code which raises SIGSEGV or SIGBUS, we currently assume the signal belongs to the guest. With an artificial error introduced, we will now print QEMU internal SIGSEGV {code=MAPERR, addr=(nil)} Signed-off-by: Helge Deller Message-Id: <20230812164314.352131-1-deller@gmx.de> [rth: Use in_code_gen_buffer and die_with_signal; drop backtrace] Signed-off-by: Richard Henderson --- linux-user/signal.c | 69 +++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 63 insertions(+), 6 deletions(-) diff --git a/linux-user/signal.c b/linux-user/signal.c index 84a56b76cc..9fadc51347 100644 --- a/linux-user/signal.c +++ b/linux-user/signal.c @@ -32,6 +32,7 @@ #include "signal-common.h" #include "host-signal.h" #include "user/safe-syscall.h" +#include "tcg/tcg.h" static struct target_sigaction sigact_table[TARGET_NSIG]; @@ -779,6 +780,50 @@ static inline void rewind_if_in_safe_syscall(void *puc) } } +static G_NORETURN +void die_from_signal(siginfo_t *info) +{ + char sigbuf[4], codebuf[12]; + const char *sig, *code = NULL; + + switch (info->si_signo) { + case SIGSEGV: + sig = "SEGV"; + switch (info->si_code) { + case SEGV_MAPERR: + code = "MAPERR"; + break; + case SEGV_ACCERR: + code = "ACCERR"; + break; + } + break; + case SIGBUS: + sig = "BUS"; + switch (info->si_code) { + case BUS_ADRALN: + code = "ADRALN"; + break; + case BUS_ADRERR: + code = "ADRERR"; + break; + } + break; + default: + snprintf(sigbuf, sizeof(sigbuf), "%d", info->si_signo); + sig = sigbuf; + break; + } + if (code == NULL) { + snprintf(codebuf, sizeof(sigbuf), "%d", info->si_code); + code = codebuf; + } + + error_report("QEMU internal SIG%s {code=%s, addr=%p}", + sig, code, info->si_addr); + die_with_signal(info->si_signo); +} + static void host_signal_handler(int host_sig, siginfo_t *info, void *puc) { CPUState *cpu = thread_cpu; @@ -814,16 +859,28 @@ static void host_signal_handler(int host_sig, siginfo_t *info, void *puc) is_write = host_signal_write(info, uc); access_type = adjust_signal_pc(&pc, is_write); + /* If this was a write to a TB protected page, restart. */ + if (is_write + && host_sig == SIGSEGV + && info->si_code == SEGV_ACCERR + && h2g_valid(host_addr) + && handle_sigsegv_accerr_write(cpu, sigmask, pc, guest_addr)) { + return; + } + + /* + * If the access was not on behalf of the guest, within the executable + * mapping of the generated code buffer, then it is a host bug. + */ + if (access_type != MMU_INST_FETCH + && !in_code_gen_buffer((void *)(pc - tcg_splitwx_diff))) { + die_from_signal(info); + } + if (host_sig == SIGSEGV) { bool maperr = true; if (info->si_code == SEGV_ACCERR && h2g_valid(host_addr)) { - /* If this was a write to a TB protected page, restart. */ - if (is_write && - handle_sigsegv_accerr_write(cpu, sigmask, pc, guest_addr)) { - return; - } - /* * With reserved_va, the whole address space is PROT_NONE, * which means that we may get ACCERR when we want MAPERR. From dbde2c0c0eec5f9d6228fd418a127def561ea516 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Tue, 22 Aug 2023 14:55:03 -0700 Subject: [PATCH 0800/1077] linux-user: Only register handlers for core_dump_signal by default The set of fatal signals is really immaterial. If one arrives, and is unhandled, then the qemu process dies and the parent gets the correct signal. It is only for those signals which we would like to perform a guest core dump instead of a host core dump that we need to catch. Acked-by: Helge Deller Signed-off-by: Richard Henderson --- linux-user/signal.c | 43 ++++++++++++++----------------------------- 1 file changed, 14 insertions(+), 29 deletions(-) diff --git a/linux-user/signal.c b/linux-user/signal.c index 9fadc51347..aab05f8eec 100644 --- a/linux-user/signal.c +++ b/linux-user/signal.c @@ -488,26 +488,6 @@ void target_to_host_siginfo(siginfo_t *info, const target_siginfo_t *tinfo) info->si_value.sival_ptr = (void *)(long)sival_ptr; } -static int fatal_signal (int sig) -{ - switch (sig) { - case TARGET_SIGCHLD: - case TARGET_SIGURG: - case TARGET_SIGWINCH: - /* Ignored by default. */ - return 0; - case TARGET_SIGCONT: - case TARGET_SIGSTOP: - case TARGET_SIGTSTP: - case TARGET_SIGTTIN: - case TARGET_SIGTTOU: - /* Job control signals. */ - return 0; - default: - return 1; - } -} - /* returns 1 if given signal should dump core if not handled */ static int core_dump_signal(int sig) { @@ -602,8 +582,9 @@ void signal_init(void) SIGSEGV and SIGBUS, to detect exceptions. We can not just trap all signals because it affects syscall interrupt behavior. But do trap all default-fatal signals. */ - if (fatal_signal (i)) + if (core_dump_signal(i)) { sigaction(host_sig, &act, NULL); + } } } @@ -997,7 +978,6 @@ int do_sigaction(int sig, const struct target_sigaction *act, struct target_sigaction *oact, abi_ulong ka_restorer) { struct target_sigaction *k; - struct sigaction act1; int host_sig; int ret = 0; @@ -1057,22 +1037,27 @@ int do_sigaction(int sig, const struct target_sigaction *act, return 0; } if (host_sig != SIGSEGV && host_sig != SIGBUS) { + struct sigaction act1; + sigfillset(&act1.sa_mask); act1.sa_flags = SA_SIGINFO; - if (k->sa_flags & TARGET_SA_RESTART) - act1.sa_flags |= SA_RESTART; - /* NOTE: it is important to update the host kernel signal - ignore state to avoid getting unexpected interrupted - syscalls */ if (k->_sa_handler == TARGET_SIG_IGN) { + /* + * It is important to update the host kernel signal ignore + * state to avoid getting unexpected interrupted syscalls. + */ act1.sa_sigaction = (void *)SIG_IGN; } else if (k->_sa_handler == TARGET_SIG_DFL) { - if (fatal_signal (sig)) + if (core_dump_signal(sig)) { act1.sa_sigaction = host_signal_handler; - else + } else { act1.sa_sigaction = (void *)SIG_DFL; + } } else { act1.sa_sigaction = host_signal_handler; + if (k->sa_flags & TARGET_SA_RESTART) { + act1.sa_flags |= SA_RESTART; + } } ret = sigaction(host_sig, &act1, NULL); } From b60b91aa8f3f053064ab3c6be4b2e388a82ff6b4 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Tue, 22 Aug 2023 20:45:38 -0700 Subject: [PATCH 0801/1077] linux-user: Map unsupported signals to an out-of-bounds value Do not return a valid signal number in one domain when given an invalid signal number in the other domain. Acked-by: Helge Deller Signed-off-by: Richard Henderson --- linux-user/signal.c | 72 ++++++++++++++++++++++++--------------------- 1 file changed, 38 insertions(+), 34 deletions(-) diff --git a/linux-user/signal.c b/linux-user/signal.c index aab05f8eec..653fd2f9fd 100644 --- a/linux-user/signal.c +++ b/linux-user/signal.c @@ -44,9 +44,8 @@ abi_ulong default_sigreturn; abi_ulong default_rt_sigreturn; /* - * System includes define _NSIG as SIGRTMAX + 1, - * but qemu (like the kernel) defines TARGET_NSIG as TARGET_SIGRTMAX - * and the first signal is SIGHUP defined as 1 + * System includes define _NSIG as SIGRTMAX + 1, but qemu (like the kernel) + * defines TARGET_NSIG as TARGET_SIGRTMAX and the first signal is 1. * Signal number 0 is reserved for use as kill(pid, 0), to test whether * a process exists without sending it a signal. */ @@ -57,7 +56,6 @@ static uint8_t host_to_target_signal_table[_NSIG] = { #define MAKE_SIG_ENTRY(sig) [sig] = TARGET_##sig, MAKE_SIGNAL_LIST #undef MAKE_SIG_ENTRY - /* next signals stay the same */ }; static uint8_t target_to_host_signal_table[TARGET_NSIG + 1]; @@ -65,18 +63,24 @@ static uint8_t target_to_host_signal_table[TARGET_NSIG + 1]; /* valid sig is between 1 and _NSIG - 1 */ int host_to_target_signal(int sig) { - if (sig < 1 || sig >= _NSIG) { + if (sig < 1) { return sig; } + if (sig >= _NSIG) { + return TARGET_NSIG + 1; + } return host_to_target_signal_table[sig]; } /* valid sig is between 1 and TARGET_NSIG */ int target_to_host_signal(int sig) { - if (sig < 1 || sig > TARGET_NSIG) { + if (sig < 1) { return sig; } + if (sig > TARGET_NSIG) { + return _NSIG; + } return target_to_host_signal_table[sig]; } @@ -507,48 +511,48 @@ static int core_dump_signal(int sig) static void signal_table_init(void) { - int host_sig, target_sig, count; + int hsig, tsig, count; /* * Signals are supported starting from TARGET_SIGRTMIN and going up - * until we run out of host realtime signals. - * glibc at least uses only the lower 2 rt signals and probably - * nobody's using the upper ones. - * it's why SIGRTMIN (34) is generally greater than __SIGRTMIN (32) - * To fix this properly we need to do manual signal delivery multiplexed - * over a single host signal. + * until we run out of host realtime signals. Glibc uses the lower 2 + * RT signals and (hopefully) nobody uses the upper ones. + * This is why SIGRTMIN (34) is generally greater than __SIGRTMIN (32). + * To fix this properly we would need to do manual signal delivery + * multiplexed over a single host signal. * Attempts for configure "missing" signals via sigaction will be * silently ignored. */ - for (host_sig = SIGRTMIN; host_sig <= SIGRTMAX; host_sig++) { - target_sig = host_sig - SIGRTMIN + TARGET_SIGRTMIN; - if (target_sig <= TARGET_NSIG) { - host_to_target_signal_table[host_sig] = target_sig; + for (hsig = SIGRTMIN; hsig <= SIGRTMAX; hsig++) { + tsig = hsig - SIGRTMIN + TARGET_SIGRTMIN; + if (tsig <= TARGET_NSIG) { + host_to_target_signal_table[hsig] = tsig; } } - /* generate signal conversion tables */ - for (target_sig = 1; target_sig <= TARGET_NSIG; target_sig++) { - target_to_host_signal_table[target_sig] = _NSIG; /* poison */ - } - for (host_sig = 1; host_sig < _NSIG; host_sig++) { - if (host_to_target_signal_table[host_sig] == 0) { - host_to_target_signal_table[host_sig] = host_sig; - } - target_sig = host_to_target_signal_table[host_sig]; - if (target_sig <= TARGET_NSIG) { - target_to_host_signal_table[target_sig] = host_sig; + /* Invert the mapping that has already been assigned. */ + for (hsig = 1; hsig < _NSIG; hsig++) { + tsig = host_to_target_signal_table[hsig]; + if (tsig) { + assert(target_to_host_signal_table[tsig] == 0); + target_to_host_signal_table[tsig] = hsig; } } - if (trace_event_get_state_backends(TRACE_SIGNAL_TABLE_INIT)) { - for (target_sig = 1, count = 0; target_sig <= TARGET_NSIG; target_sig++) { - if (target_to_host_signal_table[target_sig] == _NSIG) { - count++; - } + /* Map everything else out-of-bounds. */ + for (hsig = 1; hsig < _NSIG; hsig++) { + if (host_to_target_signal_table[hsig] == 0) { + host_to_target_signal_table[hsig] = TARGET_NSIG + 1; } - trace_signal_table_init(count); } + for (count = 0, tsig = 1; tsig <= TARGET_NSIG; tsig++) { + if (target_to_host_signal_table[tsig] == 0) { + target_to_host_signal_table[tsig] = _NSIG; + count++; + } + } + + trace_signal_table_init(count); } void signal_init(void) From 58c4e36c4e7350d2e7c8ba2d72b74a347d687b68 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Tue, 22 Aug 2023 21:20:47 -0700 Subject: [PATCH 0802/1077] linux-user: Simplify signal_init Install the host signal handler at the same time we are probing the target signals for SIG_IGN/SIG_DFL. Ignore unmapped target signals. Acked-by: Helge Deller Signed-off-by: Richard Henderson --- linux-user/signal.c | 42 ++++++++++++++++++++++-------------------- 1 file changed, 22 insertions(+), 20 deletions(-) diff --git a/linux-user/signal.c b/linux-user/signal.c index 653fd2f9fd..09840b0eb0 100644 --- a/linux-user/signal.c +++ b/linux-user/signal.c @@ -558,10 +558,7 @@ static void signal_table_init(void) void signal_init(void) { TaskState *ts = (TaskState *)thread_cpu->opaque; - struct sigaction act; - struct sigaction oact; - int i; - int host_sig; + struct sigaction act, oact; /* initialize signal conversion tables */ signal_table_init(); @@ -572,23 +569,28 @@ void signal_init(void) sigfillset(&act.sa_mask); act.sa_flags = SA_SIGINFO; act.sa_sigaction = host_signal_handler; - for(i = 1; i <= TARGET_NSIG; i++) { - host_sig = target_to_host_signal(i); - sigaction(host_sig, NULL, &oact); - if (oact.sa_sigaction == (void *)SIG_IGN) { - sigact_table[i - 1]._sa_handler = TARGET_SIG_IGN; - } else if (oact.sa_sigaction == (void *)SIG_DFL) { - sigact_table[i - 1]._sa_handler = TARGET_SIG_DFL; - } - /* If there's already a handler installed then something has - gone horribly wrong, so don't even try to handle that case. */ - /* Install some handlers for our own use. We need at least - SIGSEGV and SIGBUS, to detect exceptions. We can not just - trap all signals because it affects syscall interrupt - behavior. But do trap all default-fatal signals. */ - if (core_dump_signal(i)) { - sigaction(host_sig, &act, NULL); + + /* + * A parent process may configure ignored signals, but all other + * signals are default. For any target signals that have no host + * mapping, set to ignore. For all core_dump_signal, install our + * host signal handler so that we may invoke dump_core_and_abort. + * This includes SIGSEGV and SIGBUS, which are also need our signal + * handler for paging and exceptions. + */ + for (int tsig = 1; tsig <= TARGET_NSIG; tsig++) { + int hsig = target_to_host_signal(tsig); + abi_ptr thand = TARGET_SIG_IGN; + + if (hsig < _NSIG) { + struct sigaction *iact = core_dump_signal(tsig) ? &act : NULL; + + sigaction(hsig, iact, &oact); + if (oact.sa_sigaction != (void *)SIG_IGN) { + thand = TARGET_SIG_DFL; + } } + sigact_table[tsig - 1]._sa_handler = thand; } } From f4e1168198a6306c3e337f2b91b1213f5bef52af Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Tue, 22 Aug 2023 21:56:10 -0700 Subject: [PATCH 0803/1077] linux-user: Split out host_sig{segv,bus}_handler Make host_signal_handler slightly easier to read. Acked-by: Helge Deller Signed-off-by: Richard Henderson --- linux-user/signal.c | 145 ++++++++++++++++++++++++++------------------ 1 file changed, 85 insertions(+), 60 deletions(-) diff --git a/linux-user/signal.c b/linux-user/signal.c index 09840b0eb0..706b8ac7a7 100644 --- a/linux-user/signal.c +++ b/linux-user/signal.c @@ -811,6 +811,80 @@ void die_from_signal(siginfo_t *info) die_with_signal(info->si_signo); } +static void host_sigsegv_handler(CPUState *cpu, siginfo_t *info, + host_sigcontext *uc) +{ + uintptr_t host_addr = (uintptr_t)info->si_addr; + /* + * Convert forcefully to guest address space: addresses outside + * reserved_va are still valid to report via SEGV_MAPERR. + */ + bool is_valid = h2g_valid(host_addr); + abi_ptr guest_addr = h2g_nocheck(host_addr); + uintptr_t pc = host_signal_pc(uc); + bool is_write = host_signal_write(info, uc); + MMUAccessType access_type = adjust_signal_pc(&pc, is_write); + bool maperr; + + /* If this was a write to a TB protected page, restart. */ + if (is_write + && is_valid + && info->si_code == SEGV_ACCERR + && handle_sigsegv_accerr_write(cpu, host_signal_mask(uc), + pc, guest_addr)) { + return; + } + + /* + * If the access was not on behalf of the guest, within the executable + * mapping of the generated code buffer, then it is a host bug. + */ + if (access_type != MMU_INST_FETCH + && !in_code_gen_buffer((void *)(pc - tcg_splitwx_diff))) { + die_from_signal(info); + } + + maperr = true; + if (is_valid && info->si_code == SEGV_ACCERR) { + /* + * With reserved_va, the whole address space is PROT_NONE, + * which means that we may get ACCERR when we want MAPERR. + */ + if (page_get_flags(guest_addr) & PAGE_VALID) { + maperr = false; + } else { + info->si_code = SEGV_MAPERR; + } + } + + sigprocmask(SIG_SETMASK, host_signal_mask(uc), NULL); + cpu_loop_exit_sigsegv(cpu, guest_addr, access_type, maperr, pc); +} + +static void host_sigbus_handler(CPUState *cpu, siginfo_t *info, + host_sigcontext *uc) +{ + uintptr_t pc = host_signal_pc(uc); + bool is_write = host_signal_write(info, uc); + MMUAccessType access_type = adjust_signal_pc(&pc, is_write); + + /* + * If the access was not on behalf of the guest, within the executable + * mapping of the generated code buffer, then it is a host bug. + */ + if (!in_code_gen_buffer((void *)(pc - tcg_splitwx_diff))) { + die_from_signal(info); + } + + if (info->si_code == BUS_ADRALN) { + uintptr_t host_addr = (uintptr_t)info->si_addr; + abi_ptr guest_addr = h2g_nocheck(host_addr); + + sigprocmask(SIG_SETMASK, host_signal_mask(uc), NULL); + cpu_loop_exit_sigbus(cpu, guest_addr, access_type, pc); + } +} + static void host_signal_handler(int host_sig, siginfo_t *info, void *puc) { CPUState *cpu = thread_cpu; @@ -822,73 +896,23 @@ static void host_signal_handler(int host_sig, siginfo_t *info, void *puc) int guest_sig; uintptr_t pc = 0; bool sync_sig = false; - void *sigmask = host_signal_mask(uc); + void *sigmask; /* * Non-spoofed SIGSEGV and SIGBUS are synchronous, and need special * handling wrt signal blocking and unwinding. */ - if ((host_sig == SIGSEGV || host_sig == SIGBUS) && info->si_code > 0) { - MMUAccessType access_type; - uintptr_t host_addr; - abi_ptr guest_addr; - bool is_write; - - host_addr = (uintptr_t)info->si_addr; - - /* - * Convert forcefully to guest address space: addresses outside - * reserved_va are still valid to report via SEGV_MAPERR. - */ - guest_addr = h2g_nocheck(host_addr); - - pc = host_signal_pc(uc); - is_write = host_signal_write(info, uc); - access_type = adjust_signal_pc(&pc, is_write); - - /* If this was a write to a TB protected page, restart. */ - if (is_write - && host_sig == SIGSEGV - && info->si_code == SEGV_ACCERR - && h2g_valid(host_addr) - && handle_sigsegv_accerr_write(cpu, sigmask, pc, guest_addr)) { + if (info->si_code > 0) { + switch (host_sig) { + case SIGSEGV: + /* Only returns on handle_sigsegv_accerr_write success. */ + host_sigsegv_handler(cpu, info, uc); return; + case SIGBUS: + host_sigbus_handler(cpu, info, uc); + sync_sig = true; + break; } - - /* - * If the access was not on behalf of the guest, within the executable - * mapping of the generated code buffer, then it is a host bug. - */ - if (access_type != MMU_INST_FETCH - && !in_code_gen_buffer((void *)(pc - tcg_splitwx_diff))) { - die_from_signal(info); - } - - if (host_sig == SIGSEGV) { - bool maperr = true; - - if (info->si_code == SEGV_ACCERR && h2g_valid(host_addr)) { - /* - * With reserved_va, the whole address space is PROT_NONE, - * which means that we may get ACCERR when we want MAPERR. - */ - if (page_get_flags(guest_addr) & PAGE_VALID) { - maperr = false; - } else { - info->si_code = SEGV_MAPERR; - } - } - - sigprocmask(SIG_SETMASK, sigmask, NULL); - cpu_loop_exit_sigsegv(cpu, guest_addr, access_type, maperr, pc); - } else { - sigprocmask(SIG_SETMASK, sigmask, NULL); - if (info->si_code == BUS_ADRALN) { - cpu_loop_exit_sigbus(cpu, guest_addr, access_type, pc); - } - } - - sync_sig = true; } /* get target signal number */ @@ -929,6 +953,7 @@ static void host_signal_handler(int host_sig, siginfo_t *info, void *puc) * would write 0xff bytes off the end of the structure and trash * data on the struct. */ + sigmask = host_signal_mask(uc); memset(sigmask, 0xff, SIGSET_T_SIZE); sigdelset(sigmask, SIGSEGV); sigdelset(sigmask, SIGBUS); From 4a6ebc19a7e2d013a0e2ca79452ea733b1d5b686 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Tue, 22 Aug 2023 22:07:41 -0700 Subject: [PATCH 0804/1077] linux-user: Detect and report host SIGILL, SIGFPE, SIGTRAP These signals, when not spoofed via kill(), are always bugs. Use die_from_signal to report this sensibly. Acked-by: Helge Deller Signed-off-by: Richard Henderson --- linux-user/signal.c | 44 +++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 43 insertions(+), 1 deletion(-) diff --git a/linux-user/signal.c b/linux-user/signal.c index 706b8ac7a7..b67077f320 100644 --- a/linux-user/signal.c +++ b/linux-user/signal.c @@ -796,6 +796,43 @@ void die_from_signal(siginfo_t *info) break; } break; + case SIGILL: + sig = "ILL"; + switch (info->si_code) { + case ILL_ILLOPC: + code = "ILLOPC"; + break; + case ILL_ILLOPN: + code = "ILLOPN"; + break; + case ILL_ILLADR: + code = "ILLADR"; + break; + case ILL_PRVOPC: + code = "PRVOPC"; + break; + case ILL_PRVREG: + code = "PRVREG"; + break; + case ILL_COPROC: + code = "COPROC"; + break; + } + break; + case SIGFPE: + sig = "FPE"; + switch (info->si_code) { + case FPE_INTDIV: + code = "INTDIV"; + break; + case FPE_INTOVF: + code = "INTOVF"; + break; + } + break; + case SIGTRAP: + sig = "TRAP"; + break; default: snprintf(sigbuf, sizeof(sigbuf), "%d", info->si_signo); sig = sigbuf; @@ -900,7 +937,8 @@ static void host_signal_handler(int host_sig, siginfo_t *info, void *puc) /* * Non-spoofed SIGSEGV and SIGBUS are synchronous, and need special - * handling wrt signal blocking and unwinding. + * handling wrt signal blocking and unwinding. Non-spoofed SIGILL, + * SIGFPE, SIGTRAP are always host bugs. */ if (info->si_code > 0) { switch (host_sig) { @@ -912,6 +950,10 @@ static void host_signal_handler(int host_sig, siginfo_t *info, void *puc) host_sigbus_handler(cpu, info, uc); sync_sig = true; break; + case SIGILL: + case SIGFPE: + case SIGTRAP: + die_from_signal(info); } } From 38ee0a7dfb4b15407678df26448e4a18fd9a51d4 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Sat, 30 Sep 2023 12:05:11 -0700 Subject: [PATCH 0805/1077] linux-user: Remap guest SIGABRT Distinguish host SIGABRT from guest SIGABRT by mapping the guest signal onto one of the host RT signals. This prevents a cycle by which a host assertion failure is caught and handled by host_signal_handler, queued for the guest, and then we attempt to continue past the host abort. What happens next depends on the host libc, but is neither good nor helpful. Acked-by: Helge Deller Signed-off-by: Richard Henderson --- linux-user/signal.c | 42 +++++++++++++++++++++++++++++++++++------- 1 file changed, 35 insertions(+), 7 deletions(-) diff --git a/linux-user/signal.c b/linux-user/signal.c index b67077f320..3b8efec89f 100644 --- a/linux-user/signal.c +++ b/linux-user/signal.c @@ -522,8 +522,21 @@ static void signal_table_init(void) * multiplexed over a single host signal. * Attempts for configure "missing" signals via sigaction will be * silently ignored. + * + * Remap the target SIGABRT, so that we can distinguish host abort + * from guest abort. When the guest registers a signal handler or + * calls raise(SIGABRT), the host will raise SIG_RTn. If the guest + * arrives at dump_core_and_abort(), we will map back to host SIGABRT + * so that the parent (native or emulated) sees the correct signal. + * Finally, also map host to guest SIGABRT so that the emulated + * parent sees the correct mapping from wait status. */ - for (hsig = SIGRTMIN; hsig <= SIGRTMAX; hsig++) { + + hsig = SIGRTMIN; + host_to_target_signal_table[SIGABRT] = 0; + host_to_target_signal_table[hsig++] = TARGET_SIGABRT; + + for (; hsig <= SIGRTMAX; hsig++) { tsig = hsig - SIGRTMIN + TARGET_SIGRTMIN; if (tsig <= TARGET_NSIG) { host_to_target_signal_table[hsig] = tsig; @@ -539,6 +552,8 @@ static void signal_table_init(void) } } + host_to_target_signal_table[SIGABRT] = TARGET_SIGABRT; + /* Map everything else out-of-bounds. */ for (hsig = 1; hsig < _NSIG; hsig++) { if (host_to_target_signal_table[hsig] == 0) { @@ -582,13 +597,21 @@ void signal_init(void) int hsig = target_to_host_signal(tsig); abi_ptr thand = TARGET_SIG_IGN; - if (hsig < _NSIG) { - struct sigaction *iact = core_dump_signal(tsig) ? &act : NULL; + if (hsig >= _NSIG) { + continue; + } + /* As we force remap SIGABRT, cannot probe and install in one step. */ + if (tsig == TARGET_SIGABRT) { + sigaction(SIGABRT, NULL, &oact); + sigaction(hsig, &act, NULL); + } else { + struct sigaction *iact = core_dump_signal(tsig) ? &act : NULL; sigaction(hsig, iact, &oact); - if (oact.sa_sigaction != (void *)SIG_IGN) { - thand = TARGET_SIG_DFL; - } + } + + if (oact.sa_sigaction != (void *)SIG_IGN) { + thand = TARGET_SIG_DFL; } sigact_table[tsig - 1]._sa_handler = thand; } @@ -711,7 +734,12 @@ void dump_core_and_abort(CPUArchState *env, int target_sig) TaskState *ts = (TaskState *)cpu->opaque; int host_sig, core_dumped = 0; - host_sig = target_to_host_signal(target_sig); + /* On exit, undo the remapping of SIGABRT. */ + if (target_sig == TARGET_SIGABRT) { + host_sig = SIGABRT; + } else { + host_sig = target_to_host_signal(target_sig); + } trace_user_dump_core_and_abort(env, target_sig, host_sig); gdb_signalled(env, target_sig); From a6c5d159ce8e2f8e4cf5a0cd58de12167dd72311 Mon Sep 17 00:00:00 2001 From: John Snow Date: Wed, 4 Oct 2023 19:05:32 -0400 Subject: [PATCH 0806/1077] qapi: re-establish linting baseline MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Some very minor housekeeping to make the linters happy once more. Signed-off-by: John Snow Message-ID: <20231004230532.3002201-4-jsnow@redhat.com> Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Markus Armbruster --- scripts/qapi/gen.py | 2 +- scripts/qapi/parser.py | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/scripts/qapi/gen.py b/scripts/qapi/gen.py index bf5716b5f3..5412716617 100644 --- a/scripts/qapi/gen.py +++ b/scripts/qapi/gen.py @@ -13,8 +13,8 @@ from contextlib import contextmanager import os -import sys import re +import sys from typing import ( Dict, Iterator, diff --git a/scripts/qapi/parser.py b/scripts/qapi/parser.py index 22e7bcc4b1..bf31018aef 100644 --- a/scripts/qapi/parser.py +++ b/scripts/qapi/parser.py @@ -22,6 +22,7 @@ from typing import ( Dict, List, Mapping, + Match, Optional, Set, Union, @@ -563,11 +564,11 @@ class QAPIDoc: self._switch_section(QAPIDoc.NullSection(self._parser)) @staticmethod - def _match_at_name_colon(string: str): + def _match_at_name_colon(string: str) -> Optional[Match[str]]: return re.match(r'@([^:]*): *', string) @staticmethod - def _match_section_tag(string: str): + def _match_section_tag(string: str) -> Optional[Match[str]]: return re.match(r'(Returns|Since|Notes?|Examples?|TODO): *', string) def _append_body_line(self, line: str) -> None: From 0a59c02b0c4fd4591b010410bdfd423b9e259b03 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Mon, 9 Oct 2023 13:04:49 +0200 Subject: [PATCH 0807/1077] qapi: Belatedly update CompatPolicy documentation for unstable MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Commit 57df0dff1a1 (qapi: Extend -compat to set policy for unstable interfaces) neglected to update the "Limitation" paragraph to mention feature 'unstable' in addition to feature 'deprecated'. Do that now. Signed-off-by: Markus Armbruster Message-ID: <20231009110449.4015601-1-armbru@redhat.com> Reviewed-by: Philippe Mathieu-Daudé --- qapi/compat.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/qapi/compat.json b/qapi/compat.json index f4c19837eb..42034d9368 100644 --- a/qapi/compat.json +++ b/qapi/compat.json @@ -43,8 +43,8 @@ # This is intended for testing users of the management interfaces. # # Limitation: covers only syntactic aspects of QMP, i.e. stuff tagged -# with feature 'deprecated'. We may want to extend it to cover -# semantic aspects and CLI. +# with feature 'deprecated' or 'unstable'. We may want to extend it +# to cover semantic aspects and CLI. # # Limitation: deprecated-output policy @hide is not implemented for # enumeration values. They behave the same as with policy @accept. From e307a8174bb876ba0ac91cf1c2ced01ec4374af9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20P=2E=20Berrang=C3=A9?= Date: Wed, 18 Oct 2023 13:05:00 +0100 Subject: [PATCH 0808/1077] qapi: provide a friendly string representation of QAPI classes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit If printing a QAPI schema object for debugging we get the classname and a hex value for the instance: With this change we instead get the classname and the human friendly name of the QAPI type instance: Signed-off-by: Daniel P. Berrangé Message-ID: <20231018120500.2028642-1-berrange@redhat.com> Reviewed-by: Markus Armbruster [Conditional swapped to avoid negation] Reviewed-by: Philippe Mathieu-Daudé [Tweaked to mollify pylint] Signed-off-by: Markus Armbruster --- scripts/qapi/schema.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/scripts/qapi/schema.py b/scripts/qapi/schema.py index 231ebf61ba..d739e558e9 100644 --- a/scripts/qapi/schema.py +++ b/scripts/qapi/schema.py @@ -73,6 +73,11 @@ class QAPISchemaEntity: self.features = features or [] self._checked = False + def __repr__(self): + if self.name is None: + return "<%s at 0x%x>" % (type(self).__name__, id(self)) + return "<%s:%s at 0x%x>" % type(self).__name__, self.name, id(self) + def c_name(self): return c_name(self.name) From 29ecf2de024b386acc72b53b9eb0c3559883d1b6 Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Thu, 12 Oct 2023 09:34:58 +0200 Subject: [PATCH 0809/1077] hw/arm: Move raspberrypi-fw-defs.h to the include/hw/arm/ folder MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The file is obviously related to the raspberrypi machine, so it should reside in hw/arm/ instead of hw/misc/. And while we're at it, also adjust the wildcard in MAINTAINERS so that it covers this file, too. Signed-off-by: Thomas Huth Reviewed-by: Alex Bennée Acked-by: Philippe Mathieu-Daudé Message-id: 20231012073458.860187-1-thuth@redhat.com Signed-off-by: Peter Maydell --- MAINTAINERS | 2 +- hw/misc/bcm2835_property.c | 2 +- include/hw/{misc => arm}/raspberrypi-fw-defs.h | 0 3 files changed, 2 insertions(+), 2 deletions(-) rename include/hw/{misc => arm}/raspberrypi-fw-defs.h (100%) diff --git a/MAINTAINERS b/MAINTAINERS index 9bd4fe378d..9282b4b0f5 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -885,7 +885,7 @@ S: Odd Fixes F: hw/arm/raspi.c F: hw/arm/raspi_platform.h F: hw/*/bcm283* -F: include/hw/arm/raspi* +F: include/hw/arm/rasp* F: include/hw/*/bcm283* F: docs/system/arm/raspi.rst diff --git a/hw/misc/bcm2835_property.c b/hw/misc/bcm2835_property.c index 4ed9faa54a..ff55a4e2cd 100644 --- a/hw/misc/bcm2835_property.c +++ b/hw/misc/bcm2835_property.c @@ -12,7 +12,7 @@ #include "migration/vmstate.h" #include "hw/irq.h" #include "hw/misc/bcm2835_mbox_defs.h" -#include "hw/misc/raspberrypi-fw-defs.h" +#include "hw/arm/raspberrypi-fw-defs.h" #include "sysemu/dma.h" #include "qemu/log.h" #include "qemu/module.h" diff --git a/include/hw/misc/raspberrypi-fw-defs.h b/include/hw/arm/raspberrypi-fw-defs.h similarity index 100% rename from include/hw/misc/raspberrypi-fw-defs.h rename to include/hw/arm/raspberrypi-fw-defs.h From 85c90d45f6bd0d931af5ff7cc37a8a34ab285489 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Fri, 13 Oct 2023 15:02:14 +0200 Subject: [PATCH 0810/1077] hw/arm/exynos4210: Get arm_boot_info declaration from 'hw/arm/boot.h' MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit struct arm_boot_info is declared in "hw/arm/boot.h". By including the correct header we don't need to declare it again in "target/arm/cpu-qom.h". Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Richard Henderson Message-id: 20231013130214.95742-1-philmd@linaro.org Signed-off-by: Peter Maydell --- include/hw/arm/exynos4210.h | 2 +- target/arm/cpu-qom.h | 2 -- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/include/hw/arm/exynos4210.h b/include/hw/arm/exynos4210.h index 68db19f0cb..d33fe38586 100644 --- a/include/hw/arm/exynos4210.h +++ b/include/hw/arm/exynos4210.h @@ -30,7 +30,7 @@ #include "hw/intc/exynos4210_gic.h" #include "hw/intc/exynos4210_combiner.h" #include "hw/core/split-irq.h" -#include "target/arm/cpu-qom.h" +#include "hw/arm/boot.h" #include "qom/object.h" #define EXYNOS4210_NCPUS 2 diff --git a/target/arm/cpu-qom.h b/target/arm/cpu-qom.h index 514c22ced9..d06c08a734 100644 --- a/target/arm/cpu-qom.h +++ b/target/arm/cpu-qom.h @@ -23,8 +23,6 @@ #include "hw/core/cpu.h" #include "qom/object.h" -struct arm_boot_info; - #define TYPE_ARM_CPU "arm-cpu" OBJECT_DECLARE_CPU_TYPE(ARMCPU, ARMCPUClass, ARM_CPU) From 213bf5c1613e924f905f2cf9499dcf909db54e3e Mon Sep 17 00:00:00 2001 From: Tong Ho Date: Mon, 2 Oct 2023 22:23:45 -0700 Subject: [PATCH 0811/1077] xlnx-bbram: hw/nvram: Remove deprecated device reset MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This change implements the ResettableClass interface for the device. Signed-off-by: Tong Ho Reviewed-by: Philippe Mathieu-Daudé Message-id: 20231003052345.199725-1-tong.ho@amd.com Signed-off-by: Peter Maydell --- hw/nvram/xlnx-bbram.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/hw/nvram/xlnx-bbram.c b/hw/nvram/xlnx-bbram.c index c6b484cc85..e18e7770e1 100644 --- a/hw/nvram/xlnx-bbram.c +++ b/hw/nvram/xlnx-bbram.c @@ -2,6 +2,7 @@ * QEMU model of the Xilinx BBRAM Battery Backed RAM * * Copyright (c) 2014-2021 Xilinx Inc. + * Copyright (c) 2023 Advanced Micro Devices, Inc. * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -416,9 +417,9 @@ static RegisterAccessInfo bbram_ctrl_regs_info[] = { } }; -static void bbram_ctrl_reset(DeviceState *dev) +static void bbram_ctrl_reset_hold(Object *obj) { - XlnxBBRam *s = XLNX_BBRAM(dev); + XlnxBBRam *s = XLNX_BBRAM(obj); unsigned int i; for (i = 0; i < ARRAY_SIZE(s->regs_info); ++i) { @@ -522,8 +523,9 @@ static Property bbram_ctrl_props[] = { static void bbram_ctrl_class_init(ObjectClass *klass, void *data) { DeviceClass *dc = DEVICE_CLASS(klass); + ResettableClass *rc = RESETTABLE_CLASS(klass); - dc->reset = bbram_ctrl_reset; + rc->phases.hold = bbram_ctrl_reset_hold; dc->realize = bbram_ctrl_realize; dc->vmsd = &vmstate_bbram_ctrl; device_class_set_props(dc, bbram_ctrl_props); From 7667b51524c58c73f4fa3ed891bfdfeb870d05be Mon Sep 17 00:00:00 2001 From: Tong Ho Date: Tue, 3 Oct 2023 22:57:13 -0700 Subject: [PATCH 0812/1077] xlnx-zynqmp-efuse: hw/nvram: Remove deprecated device reset This change implements the ResettableClass interface for the device. Signed-off-by: Tong Ho Reviewed-by: Francisco Iglesias Message-id: 20231004055713.324009-1-tong.ho@amd.com Signed-off-by: Peter Maydell --- hw/nvram/xlnx-zynqmp-efuse.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/hw/nvram/xlnx-zynqmp-efuse.c b/hw/nvram/xlnx-zynqmp-efuse.c index 228ba0bbfa..3db5f98ec1 100644 --- a/hw/nvram/xlnx-zynqmp-efuse.c +++ b/hw/nvram/xlnx-zynqmp-efuse.c @@ -2,6 +2,7 @@ * QEMU model of the ZynqMP eFuse * * Copyright (c) 2015 Xilinx Inc. + * Copyright (c) 2023 Advanced Micro Devices, Inc. * * Written by Edgar E. Iglesias * @@ -769,9 +770,9 @@ static void zynqmp_efuse_register_reset(RegisterInfo *reg) register_reset(reg); } -static void zynqmp_efuse_reset(DeviceState *dev) +static void zynqmp_efuse_reset_hold(Object *obj) { - XlnxZynqMPEFuse *s = XLNX_ZYNQMP_EFUSE(dev); + XlnxZynqMPEFuse *s = XLNX_ZYNQMP_EFUSE(obj); unsigned int i; for (i = 0; i < ARRAY_SIZE(s->regs_info); ++i) { @@ -837,8 +838,9 @@ static Property zynqmp_efuse_props[] = { static void zynqmp_efuse_class_init(ObjectClass *klass, void *data) { DeviceClass *dc = DEVICE_CLASS(klass); + ResettableClass *rc = RESETTABLE_CLASS(klass); - dc->reset = zynqmp_efuse_reset; + rc->phases.hold = zynqmp_efuse_reset_hold; dc->realize = zynqmp_efuse_realize; dc->vmsd = &vmstate_efuse; device_class_set_props(dc, zynqmp_efuse_props); From 51244b5911483d12a4cde26b1facd19c8600751d Mon Sep 17 00:00:00 2001 From: Tong Ho Date: Tue, 3 Oct 2023 22:53:39 -0700 Subject: [PATCH 0813/1077] xlnx-versal-efuse: hw/nvram: Remove deprecated device reset This change implements the ResettableClass interface for the device. Signed-off-by: Tong Ho Reviewed-by: Francisco Iglesias Message-id: 20231004055339.323833-1-tong.ho@amd.com Signed-off-by: Peter Maydell --- hw/nvram/xlnx-versal-efuse-ctrl.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/hw/nvram/xlnx-versal-efuse-ctrl.c b/hw/nvram/xlnx-versal-efuse-ctrl.c index b35ba65ab5..beb5661c35 100644 --- a/hw/nvram/xlnx-versal-efuse-ctrl.c +++ b/hw/nvram/xlnx-versal-efuse-ctrl.c @@ -2,6 +2,7 @@ * QEMU model of the Versal eFuse controller * * Copyright (c) 2020 Xilinx Inc. + * Copyright (c) 2023 Advanced Micro Devices, Inc. * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -657,9 +658,9 @@ static void efuse_ctrl_register_reset(RegisterInfo *reg) register_reset(reg); } -static void efuse_ctrl_reset(DeviceState *dev) +static void efuse_ctrl_reset_hold(Object *obj) { - XlnxVersalEFuseCtrl *s = XLNX_VERSAL_EFUSE_CTRL(dev); + XlnxVersalEFuseCtrl *s = XLNX_VERSAL_EFUSE_CTRL(obj); unsigned int i; for (i = 0; i < ARRAY_SIZE(s->regs_info); ++i) { @@ -749,8 +750,9 @@ static Property efuse_ctrl_props[] = { static void efuse_ctrl_class_init(ObjectClass *klass, void *data) { DeviceClass *dc = DEVICE_CLASS(klass); + ResettableClass *rc = RESETTABLE_CLASS(klass); - dc->reset = efuse_ctrl_reset; + rc->phases.hold = efuse_ctrl_reset_hold; dc->realize = efuse_ctrl_realize; dc->vmsd = &vmstate_efuse_ctrl; device_class_set_props(dc, efuse_ctrl_props); From b65b4b7ae3c873dc2f8f4ce65ea5cedc45be3938 Mon Sep 17 00:00:00 2001 From: Tong Ho Date: Mon, 2 Oct 2023 22:21:39 -0700 Subject: [PATCH 0814/1077] xlnx-bbram: hw/nvram: Use dot in device type name This replaces the comma (,) to dot (.) in the device type name so the name can be used with the 'driver=' command line option. Signed-off-by: Tong Ho Reviewed-by: Francisco Iglesias Message-id: 20231003052139.199665-1-tong.ho@amd.com Signed-off-by: Peter Maydell --- include/hw/nvram/xlnx-bbram.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/hw/nvram/xlnx-bbram.h b/include/hw/nvram/xlnx-bbram.h index 87d59ef3c0..6fc13f8cc1 100644 --- a/include/hw/nvram/xlnx-bbram.h +++ b/include/hw/nvram/xlnx-bbram.h @@ -34,7 +34,7 @@ #define RMAX_XLNX_BBRAM ((0x4c / 4) + 1) -#define TYPE_XLNX_BBRAM "xlnx,bbram-ctrl" +#define TYPE_XLNX_BBRAM "xlnx.bbram-ctrl" OBJECT_DECLARE_SIMPLE_TYPE(XlnxBBRam, XLNX_BBRAM); struct XlnxBBRam { From 8b01683e857a80425ea67dc44505b4983fc11a8e Mon Sep 17 00:00:00 2001 From: Viktor Prutyanov Date: Sun, 1 Oct 2023 02:53:16 +0300 Subject: [PATCH 0815/1077] elf2dmp: limit print length for sign_rsds String sign_rsds isn't terminated, so the print length must be limited. Fixes: Coverity CID 1521598 Signed-off-by: Viktor Prutyanov Reviewed-by: Akihiko Odaki Message-id: 20230930235317.11469-2-viktor@daynix.com Signed-off-by: Peter Maydell --- contrib/elf2dmp/main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contrib/elf2dmp/main.c b/contrib/elf2dmp/main.c index 5db163bdbe..6de5c9808e 100644 --- a/contrib/elf2dmp/main.c +++ b/contrib/elf2dmp/main.c @@ -478,7 +478,7 @@ static bool pe_check_pdb_name(uint64_t base, void *start_addr, } if (memcmp(&rsds->Signature, sign_rsds, sizeof(sign_rsds))) { - eprintf("CodeView signature is \'%.4s\', \'%s\' expected\n", + eprintf("CodeView signature is \'%.4s\', \'%.4s\' expected\n", rsds->Signature, sign_rsds); return false; } From 9d9c06b144da340b9a937ed01d45a936810715be Mon Sep 17 00:00:00 2001 From: Viktor Prutyanov Date: Sun, 1 Oct 2023 02:53:17 +0300 Subject: [PATCH 0816/1077] elf2dmp: check array bounds in pdb_get_file_size MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Index in file_size array must be checked against num_files, because the entries we are looking for may be absent in the PDB. Fixes: Coverity CID 1521597 Signed-off-by: Viktor Prutyanov Reviewed-by: Akihiko Odaki Reviewed-by: Philippe Mathieu-Daudé Message-id: 20230930235317.11469-3-viktor@daynix.com Signed-off-by: Peter Maydell --- contrib/elf2dmp/pdb.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/contrib/elf2dmp/pdb.c b/contrib/elf2dmp/pdb.c index 6ca5086f02..8e3c18c82f 100644 --- a/contrib/elf2dmp/pdb.c +++ b/contrib/elf2dmp/pdb.c @@ -25,6 +25,10 @@ static uint32_t pdb_get_file_size(const struct pdb_reader *r, unsigned idx) { + if (idx >= r->ds.toc->num_files) { + return 0; + } + return r->ds.toc->file_size[idx]; } @@ -159,16 +163,17 @@ static void *pdb_ds_read_file(struct pdb_reader* r, uint32_t file_number) static int pdb_init_segments(struct pdb_reader *r) { - char *segs; unsigned stream_idx = r->segments; - segs = pdb_ds_read_file(r, stream_idx); - if (!segs) { + r->segs = pdb_ds_read_file(r, stream_idx); + if (!r->segs) { return 1; } - r->segs = segs; r->segs_size = pdb_get_file_size(r, stream_idx); + if (!r->segs_size) { + return 1; + } return 0; } From d01448c79d89cfdc86228081b1dd1dfaf85fb4c3 Mon Sep 17 00:00:00 2001 From: Michal Orzel Date: Thu, 28 Sep 2023 11:44:04 +0200 Subject: [PATCH 0817/1077] target/arm: Fix CNTPCT_EL0 trapping from EL0 when HCR_EL2.E2H is 0 On an attempt to access CNTPCT_EL0 from EL0 using a guest running on top of Xen, a trap from EL2 was observed which is something not reproducible on HW (also, Xen does not trap accesses to physical counter). This is because gt_counter_access() checks for an incorrect bit (1 instead of 0) of CNTHCTL_EL2 if HCR_EL2.E2H is 0 and access is made to physical counter. Refer ARM ARM DDI 0487J.a, D19.12.2: When HCR_EL2.E2H is 0: - EL1PCTEN, bit [0]: refers to physical counter - EL1PCEN, bit [1]: refers to physical timer registers Drop entire block "if (hcr & HCR_E2H) {...} else {...}" from EL0 case and fall through to EL1 case, given that after fixing checking for the correct bit, the handling is the same. Fixes: 5bc8437136fb ("target/arm: Update timer access for VHE") Signed-off-by: Michal Orzel Tested-by: Oleksandr Tyshchenko Message-id: 20230928094404.20802-1-michal.orzel@amd.com Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- target/arm/helper.c | 17 +---------------- 1 file changed, 1 insertion(+), 16 deletions(-) diff --git a/target/arm/helper.c b/target/arm/helper.c index 74fbb6e1d7..01cd147456 100644 --- a/target/arm/helper.c +++ b/target/arm/helper.c @@ -2475,22 +2475,7 @@ static CPAccessResult gt_counter_access(CPUARMState *env, int timeridx, if (!extract32(env->cp15.c14_cntkctl, timeridx, 1)) { return CP_ACCESS_TRAP; } - - /* If HCR_EL2. == '10': check CNTHCTL_EL2.EL1PCTEN. */ - if (hcr & HCR_E2H) { - if (timeridx == GTIMER_PHYS && - !extract32(env->cp15.cnthctl_el2, 10, 1)) { - return CP_ACCESS_TRAP_EL2; - } - } else { - /* If HCR_EL2. == 0: check CNTHCTL_EL2.EL1PCEN. */ - if (has_el2 && timeridx == GTIMER_PHYS && - !extract32(env->cp15.cnthctl_el2, 1, 1)) { - return CP_ACCESS_TRAP_EL2; - } - } - break; - + /* fall through */ case 1: /* Check CNTHCTL_EL2.EL1PCTEN, which changes location based on E2H. */ if (has_el2 && timeridx == GTIMER_PHYS && From 9036e917f8357f4e5965ebfecdab5964d40e6a40 Mon Sep 17 00:00:00 2001 From: Leif Lindholm Date: Tue, 19 Sep 2023 10:02:27 +0100 Subject: [PATCH 0818/1077] {include/}hw/arm: refactor virt PPI logic GIC Private Peripheral Interrupts (PPI) are defined as GIC INTID 16-31. As in, PPI0 is INTID16 .. PPI15 is INTID31. Arm's Base System Architecture specification (BSA) lists the mandated and recommended private interrupt IDs by INTID, not by PPI index. But current definitions in virt define them by PPI index, complicating cross referencing. Meanwhile, the PPI(x) macro counterintuitively adds 16 to the input value, converting a PPI index to an INTID. Resolve this by redefining the BSA-allocated PPIs by their INTIDs, and replacing the PPI(x) macro with an INTID_TO_PPI(x) one where required. Signed-off-by: Leif Lindholm Message-id: 20230919090229.188092-2-quic_llindhol@quicinc.com Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- hw/arm/virt-acpi-build.c | 12 ++++++------ hw/arm/virt.c | 24 ++++++++++++++---------- include/hw/arm/virt.h | 14 +++++++------- 3 files changed, 27 insertions(+), 23 deletions(-) diff --git a/hw/arm/virt-acpi-build.c b/hw/arm/virt-acpi-build.c index 6b674231c2..9ce136cd88 100644 --- a/hw/arm/virt-acpi-build.c +++ b/hw/arm/virt-acpi-build.c @@ -601,21 +601,21 @@ build_gtdt(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms) * The interrupt values are the same with the device tree when adding 16 */ /* Secure EL1 timer GSIV */ - build_append_int_noprefix(table_data, ARCH_TIMER_S_EL1_IRQ + 16, 4); + build_append_int_noprefix(table_data, ARCH_TIMER_S_EL1_IRQ, 4); /* Secure EL1 timer Flags */ build_append_int_noprefix(table_data, irqflags, 4); /* Non-Secure EL1 timer GSIV */ - build_append_int_noprefix(table_data, ARCH_TIMER_NS_EL1_IRQ + 16, 4); + build_append_int_noprefix(table_data, ARCH_TIMER_NS_EL1_IRQ, 4); /* Non-Secure EL1 timer Flags */ build_append_int_noprefix(table_data, irqflags | 1UL << 2, /* Always-on Capability */ 4); /* Virtual timer GSIV */ - build_append_int_noprefix(table_data, ARCH_TIMER_VIRT_IRQ + 16, 4); + build_append_int_noprefix(table_data, ARCH_TIMER_VIRT_IRQ, 4); /* Virtual Timer Flags */ build_append_int_noprefix(table_data, irqflags, 4); /* Non-Secure EL2 timer GSIV */ - build_append_int_noprefix(table_data, ARCH_TIMER_NS_EL2_IRQ + 16, 4); + build_append_int_noprefix(table_data, ARCH_TIMER_NS_EL2_IRQ, 4); /* Non-Secure EL2 timer Flags */ build_append_int_noprefix(table_data, irqflags, 4); /* CntReadBase Physical address */ @@ -729,9 +729,9 @@ build_madt(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms) for (i = 0; i < MACHINE(vms)->smp.cpus; i++) { ARMCPU *armcpu = ARM_CPU(qemu_get_cpu(i)); uint64_t physical_base_address = 0, gich = 0, gicv = 0; - uint32_t vgic_interrupt = vms->virt ? PPI(ARCH_GIC_MAINT_IRQ) : 0; + uint32_t vgic_interrupt = vms->virt ? ARCH_GIC_MAINT_IRQ : 0; uint32_t pmu_interrupt = arm_feature(&armcpu->env, ARM_FEATURE_PMU) ? - PPI(VIRTUAL_PMU_IRQ) : 0; + VIRTUAL_PMU_IRQ : 0; if (vms->gic_version == VIRT_GIC_VERSION_2) { physical_base_address = memmap[VIRT_GIC_CPU].base; diff --git a/hw/arm/virt.c b/hw/arm/virt.c index 15e74249f9..ebc9f3fdb1 100644 --- a/hw/arm/virt.c +++ b/hw/arm/virt.c @@ -366,10 +366,14 @@ static void fdt_add_timer_nodes(const VirtMachineState *vms) } qemu_fdt_setprop(ms->fdt, "/timer", "always-on", NULL, 0); qemu_fdt_setprop_cells(ms->fdt, "/timer", "interrupts", - GIC_FDT_IRQ_TYPE_PPI, ARCH_TIMER_S_EL1_IRQ, irqflags, - GIC_FDT_IRQ_TYPE_PPI, ARCH_TIMER_NS_EL1_IRQ, irqflags, - GIC_FDT_IRQ_TYPE_PPI, ARCH_TIMER_VIRT_IRQ, irqflags, - GIC_FDT_IRQ_TYPE_PPI, ARCH_TIMER_NS_EL2_IRQ, irqflags); + GIC_FDT_IRQ_TYPE_PPI, + INTID_TO_PPI(ARCH_TIMER_S_EL1_IRQ), irqflags, + GIC_FDT_IRQ_TYPE_PPI, + INTID_TO_PPI(ARCH_TIMER_NS_EL1_IRQ), irqflags, + GIC_FDT_IRQ_TYPE_PPI, + INTID_TO_PPI(ARCH_TIMER_VIRT_IRQ), irqflags, + GIC_FDT_IRQ_TYPE_PPI, + INTID_TO_PPI(ARCH_TIMER_NS_EL2_IRQ), irqflags); } static void fdt_add_cpu_nodes(const VirtMachineState *vms) @@ -800,7 +804,7 @@ static void create_gic(VirtMachineState *vms, MemoryRegion *mem) */ for (i = 0; i < smp_cpus; i++) { DeviceState *cpudev = DEVICE(qemu_get_cpu(i)); - int ppibase = NUM_IRQS + i * GIC_INTERNAL + GIC_NR_SGIS; + int intidbase = NUM_IRQS + i * GIC_INTERNAL; /* Mapping from the output timer irq lines from the CPU to the * GIC PPI inputs we use for the virt board. */ @@ -814,22 +818,22 @@ static void create_gic(VirtMachineState *vms, MemoryRegion *mem) for (unsigned irq = 0; irq < ARRAY_SIZE(timer_irq); irq++) { qdev_connect_gpio_out(cpudev, irq, qdev_get_gpio_in(vms->gic, - ppibase + timer_irq[irq])); + intidbase + timer_irq[irq])); } if (vms->gic_version != VIRT_GIC_VERSION_2) { qemu_irq irq = qdev_get_gpio_in(vms->gic, - ppibase + ARCH_GIC_MAINT_IRQ); + intidbase + ARCH_GIC_MAINT_IRQ); qdev_connect_gpio_out_named(cpudev, "gicv3-maintenance-interrupt", 0, irq); } else if (vms->virt) { qemu_irq irq = qdev_get_gpio_in(vms->gic, - ppibase + ARCH_GIC_MAINT_IRQ); + intidbase + ARCH_GIC_MAINT_IRQ); sysbus_connect_irq(gicbusdev, i + 4 * smp_cpus, irq); } qdev_connect_gpio_out_named(cpudev, "pmu-interrupt", 0, - qdev_get_gpio_in(vms->gic, ppibase + qdev_get_gpio_in(vms->gic, intidbase + VIRTUAL_PMU_IRQ)); sysbus_connect_irq(gicbusdev, i, qdev_get_gpio_in(cpudev, ARM_CPU_IRQ)); @@ -1989,7 +1993,7 @@ static void virt_cpu_post_init(VirtMachineState *vms, MemoryRegion *sysmem) if (pmu) { assert(arm_feature(&ARM_CPU(cpu)->env, ARM_FEATURE_PMU)); if (kvm_irqchip_in_kernel()) { - kvm_arm_pmu_set_irq(cpu, PPI(VIRTUAL_PMU_IRQ)); + kvm_arm_pmu_set_irq(cpu, VIRTUAL_PMU_IRQ); } kvm_arm_pmu_init(cpu); } diff --git a/include/hw/arm/virt.h b/include/hw/arm/virt.h index e1ddbea96b..5704d95736 100644 --- a/include/hw/arm/virt.h +++ b/include/hw/arm/virt.h @@ -43,16 +43,16 @@ #define NUM_VIRTIO_TRANSPORTS 32 #define NUM_SMMU_IRQS 4 -#define ARCH_GIC_MAINT_IRQ 9 +#define ARCH_GIC_MAINT_IRQ 25 -#define ARCH_TIMER_VIRT_IRQ 11 -#define ARCH_TIMER_S_EL1_IRQ 13 -#define ARCH_TIMER_NS_EL1_IRQ 14 -#define ARCH_TIMER_NS_EL2_IRQ 10 +#define ARCH_TIMER_VIRT_IRQ 27 +#define ARCH_TIMER_S_EL1_IRQ 29 +#define ARCH_TIMER_NS_EL1_IRQ 30 +#define ARCH_TIMER_NS_EL2_IRQ 26 -#define VIRTUAL_PMU_IRQ 7 +#define VIRTUAL_PMU_IRQ 23 -#define PPI(irq) ((irq) + 16) +#define INTID_TO_PPI(irq) ((irq) - 16) /* See Linux kernel arch/arm64/include/asm/pvclock-abi.h */ #define PVTIME_SIZE_PER_CPU 64 From 2419ce83fce2300e61b5e6df256caddaa07a2ae0 Mon Sep 17 00:00:00 2001 From: Leif Lindholm Date: Tue, 19 Sep 2023 10:02:28 +0100 Subject: [PATCH 0819/1077] include/hw/arm: move BSA definitions to bsa.h virt.h defines a number of IRQs that are ultimately described by Arm's Base System Architecture specification. Move these to a dedicated header so that they can be reused by other platforms that do the same. Include that header from virt.h to minimise churn. While we're moving the definitions, sort them into numerical order, and add the ARCH_TIMER_NS_EL2_VIRT_IRQ definition used by sbsa-ref and which will eventually be needed by virt also. Signed-off-by: Leif Lindholm Message-id: 20230919090229.188092-3-quic_llindhol@quicinc.com [PMM: Remove unused PPI_TO_INTID macro; sort numerically; add ARCH_TIMER_NS_EL2_VIRT_IRQ] Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- include/hw/arm/bsa.h | 35 +++++++++++++++++++++++++++++++++++ include/hw/arm/virt.h | 12 +----------- 2 files changed, 36 insertions(+), 11 deletions(-) create mode 100644 include/hw/arm/bsa.h diff --git a/include/hw/arm/bsa.h b/include/hw/arm/bsa.h new file mode 100644 index 0000000000..8eaab603c0 --- /dev/null +++ b/include/hw/arm/bsa.h @@ -0,0 +1,35 @@ +/* + * Common definitions for Arm Base System Architecture (BSA) platforms. + * + * Copyright (c) 2015 Linaro Limited + * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2 or later, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program. If not, see . + * + */ + +#ifndef QEMU_ARM_BSA_H +#define QEMU_ARM_BSA_H + +/* These are architectural INTID values */ +#define VIRTUAL_PMU_IRQ 23 +#define ARCH_GIC_MAINT_IRQ 25 +#define ARCH_TIMER_NS_EL2_IRQ 26 +#define ARCH_TIMER_VIRT_IRQ 27 +#define ARCH_TIMER_NS_EL2_VIRT_IRQ 28 +#define ARCH_TIMER_S_EL1_IRQ 29 +#define ARCH_TIMER_NS_EL1_IRQ 30 + +#define INTID_TO_PPI(irq) ((irq) - 16) + +#endif /* QEMU_ARM_BSA_H */ diff --git a/include/hw/arm/virt.h b/include/hw/arm/virt.h index 5704d95736..f69239850e 100644 --- a/include/hw/arm/virt.h +++ b/include/hw/arm/virt.h @@ -34,6 +34,7 @@ #include "qemu/notify.h" #include "hw/boards.h" #include "hw/arm/boot.h" +#include "hw/arm/bsa.h" #include "hw/block/flash.h" #include "sysemu/kvm.h" #include "hw/intc/arm_gicv3_common.h" @@ -43,17 +44,6 @@ #define NUM_VIRTIO_TRANSPORTS 32 #define NUM_SMMU_IRQS 4 -#define ARCH_GIC_MAINT_IRQ 25 - -#define ARCH_TIMER_VIRT_IRQ 27 -#define ARCH_TIMER_S_EL1_IRQ 29 -#define ARCH_TIMER_NS_EL1_IRQ 30 -#define ARCH_TIMER_NS_EL2_IRQ 26 - -#define VIRTUAL_PMU_IRQ 23 - -#define INTID_TO_PPI(irq) ((irq) - 16) - /* See Linux kernel arch/arm64/include/asm/pvclock-abi.h */ #define PVTIME_SIZE_PER_CPU 64 From d40ab068c07d924af5001ba4670651696ec9664e Mon Sep 17 00:00:00 2001 From: Leif Lindholm Date: Tue, 19 Sep 2023 10:02:29 +0100 Subject: [PATCH 0820/1077] hw/arm/sbsa-ref: use bsa.h for PPI definitions Use the private peripheral interrupt definitions from bsa.h instead of defining them locally. Refactor to use the INTIDs defined there instead of the PPI# used previously. Signed-off-by: Leif Lindholm Message-id: 20230919090229.188092-4-quic_llindhol@quicinc.com Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- hw/arm/sbsa-ref.c | 21 +++++++++------------ 1 file changed, 9 insertions(+), 12 deletions(-) diff --git a/hw/arm/sbsa-ref.c b/hw/arm/sbsa-ref.c index 3c7dfcd6dc..e8a82618f0 100644 --- a/hw/arm/sbsa-ref.c +++ b/hw/arm/sbsa-ref.c @@ -2,6 +2,7 @@ * ARM SBSA Reference Platform emulation * * Copyright (c) 2018 Linaro Limited + * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved. * Written by Hongbo Zhang * * This program is free software; you can redistribute it and/or modify it @@ -30,6 +31,7 @@ #include "exec/hwaddr.h" #include "kvm_arm.h" #include "hw/arm/boot.h" +#include "hw/arm/bsa.h" #include "hw/arm/fdt.h" #include "hw/arm/smmuv3.h" #include "hw/block/flash.h" @@ -55,14 +57,6 @@ #define NUM_SMMU_IRQS 4 #define NUM_SATA_PORTS 6 -#define VIRTUAL_PMU_IRQ 7 -#define ARCH_GIC_MAINT_IRQ 9 -#define ARCH_TIMER_VIRT_IRQ 11 -#define ARCH_TIMER_S_EL1_IRQ 13 -#define ARCH_TIMER_NS_EL1_IRQ 14 -#define ARCH_TIMER_NS_EL2_IRQ 10 -#define ARCH_TIMER_NS_EL2_VIRT_IRQ 12 - enum { SBSA_FLASH, SBSA_MEM, @@ -479,7 +473,7 @@ static void create_gic(SBSAMachineState *sms, MemoryRegion *mem) */ for (i = 0; i < smp_cpus; i++) { DeviceState *cpudev = DEVICE(qemu_get_cpu(i)); - int ppibase = NUM_IRQS + i * GIC_INTERNAL + GIC_NR_SGIS; + int intidbase = NUM_IRQS + i * GIC_INTERNAL; int irq; /* * Mapping from the output timer irq lines from the CPU to the @@ -496,14 +490,17 @@ static void create_gic(SBSAMachineState *sms, MemoryRegion *mem) for (irq = 0; irq < ARRAY_SIZE(timer_irq); irq++) { qdev_connect_gpio_out(cpudev, irq, qdev_get_gpio_in(sms->gic, - ppibase + timer_irq[irq])); + intidbase + timer_irq[irq])); } qdev_connect_gpio_out_named(cpudev, "gicv3-maintenance-interrupt", 0, - qdev_get_gpio_in(sms->gic, ppibase + qdev_get_gpio_in(sms->gic, + intidbase + ARCH_GIC_MAINT_IRQ)); + qdev_connect_gpio_out_named(cpudev, "pmu-interrupt", 0, - qdev_get_gpio_in(sms->gic, ppibase + qdev_get_gpio_in(sms->gic, + intidbase + VIRTUAL_PMU_IRQ)); sysbus_connect_irq(gicbusdev, i, qdev_get_gpio_in(cpudev, ARM_CPU_IRQ)); From 6c8b9a74bf76f4fc98246671de9acfdfa2c227c4 Mon Sep 17 00:00:00 2001 From: Cornelia Huck Date: Tue, 10 Oct 2023 16:24:51 +0200 Subject: [PATCH 0821/1077] arm/kvm: convert to kvm_set_one_reg MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We can neaten the code by switching to the kvm_set_one_reg function. Reviewed-by: Gavin Shan Signed-off-by: Cornelia Huck Reviewed-by: Philippe Mathieu-Daudé Message-id: 20231010142453.224369-2-cohuck@redhat.com Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- target/arm/kvm.c | 13 +++------ target/arm/kvm64.c | 66 +++++++++++++--------------------------------- 2 files changed, 21 insertions(+), 58 deletions(-) diff --git a/target/arm/kvm.c b/target/arm/kvm.c index b66b936a95..1a8084c460 100644 --- a/target/arm/kvm.c +++ b/target/arm/kvm.c @@ -589,7 +589,6 @@ bool write_list_to_kvmstate(ARMCPU *cpu, int level) bool ok = true; for (i = 0; i < cpu->cpreg_array_len; i++) { - struct kvm_one_reg r; uint64_t regidx = cpu->cpreg_indexes[i]; uint32_t v32; int ret; @@ -598,19 +597,17 @@ bool write_list_to_kvmstate(ARMCPU *cpu, int level) continue; } - r.id = regidx; switch (regidx & KVM_REG_SIZE_MASK) { case KVM_REG_SIZE_U32: v32 = cpu->cpreg_values[i]; - r.addr = (uintptr_t)&v32; + ret = kvm_set_one_reg(cs, regidx, &v32); break; case KVM_REG_SIZE_U64: - r.addr = (uintptr_t)(cpu->cpreg_values + i); + ret = kvm_set_one_reg(cs, regidx, cpu->cpreg_values + i); break; default: g_assert_not_reached(); } - ret = kvm_vcpu_ioctl(cs, KVM_SET_ONE_REG, &r); if (ret) { /* We might fail for "unknown register" and also for * "you tried to set a register which is constant with @@ -731,17 +728,13 @@ void kvm_arm_get_virtual_time(CPUState *cs) void kvm_arm_put_virtual_time(CPUState *cs) { ARMCPU *cpu = ARM_CPU(cs); - struct kvm_one_reg reg = { - .id = KVM_REG_ARM_TIMER_CNT, - .addr = (uintptr_t)&cpu->kvm_vtime, - }; int ret; if (!cpu->kvm_vtime_dirty) { return; } - ret = kvm_vcpu_ioctl(cs, KVM_SET_ONE_REG, ®); + ret = kvm_set_one_reg(cs, KVM_REG_ARM_TIMER_CNT, &cpu->kvm_vtime); if (ret) { error_report("Failed to set KVM_REG_ARM_TIMER_CNT"); abort(); diff --git a/target/arm/kvm64.c b/target/arm/kvm64.c index 5e95c496bb..047b269a79 100644 --- a/target/arm/kvm64.c +++ b/target/arm/kvm64.c @@ -540,14 +540,10 @@ static int kvm_arm_sve_set_vls(CPUState *cs) { ARMCPU *cpu = ARM_CPU(cs); uint64_t vls[KVM_ARM64_SVE_VLS_WORDS] = { cpu->sve_vq.map }; - struct kvm_one_reg reg = { - .id = KVM_REG_ARM64_SVE_VLS, - .addr = (uint64_t)&vls[0], - }; assert(cpu->sve_max_vq <= KVM_ARM64_SVE_VQ_MAX); - return kvm_vcpu_ioctl(cs, KVM_SET_ONE_REG, ®); + return kvm_set_one_reg(cs, KVM_REG_ARM64_SVE_VLS, &vls[0]); } #define ARM_CPU_ID_MPIDR 3, 0, 0, 0, 5 @@ -726,19 +722,17 @@ static void kvm_inject_arm_sea(CPUState *c) static int kvm_arch_put_fpsimd(CPUState *cs) { CPUARMState *env = &ARM_CPU(cs)->env; - struct kvm_one_reg reg; int i, ret; for (i = 0; i < 32; i++) { uint64_t *q = aa64_vfp_qreg(env, i); #if HOST_BIG_ENDIAN uint64_t fp_val[2] = { q[1], q[0] }; - reg.addr = (uintptr_t)fp_val; + ret = kvm_set_one_reg(cs, AARCH64_SIMD_CORE_REG(fp_regs.vregs[i]), + fp_val); #else - reg.addr = (uintptr_t)q; + ret = kvm_set_one_reg(cs, AARCH64_SIMD_CORE_REG(fp_regs.vregs[i]), q); #endif - reg.id = AARCH64_SIMD_CORE_REG(fp_regs.vregs[i]); - ret = kvm_vcpu_ioctl(cs, KVM_SET_ONE_REG, ®); if (ret) { return ret; } @@ -759,14 +753,11 @@ static int kvm_arch_put_sve(CPUState *cs) CPUARMState *env = &cpu->env; uint64_t tmp[ARM_MAX_VQ * 2]; uint64_t *r; - struct kvm_one_reg reg; int n, ret; for (n = 0; n < KVM_ARM64_SVE_NUM_ZREGS; ++n) { r = sve_bswap64(tmp, &env->vfp.zregs[n].d[0], cpu->sve_max_vq * 2); - reg.addr = (uintptr_t)r; - reg.id = KVM_REG_ARM64_SVE_ZREG(n, 0); - ret = kvm_vcpu_ioctl(cs, KVM_SET_ONE_REG, ®); + ret = kvm_set_one_reg(cs, KVM_REG_ARM64_SVE_ZREG(n, 0), r); if (ret) { return ret; } @@ -775,9 +766,7 @@ static int kvm_arch_put_sve(CPUState *cs) for (n = 0; n < KVM_ARM64_SVE_NUM_PREGS; ++n) { r = sve_bswap64(tmp, r = &env->vfp.pregs[n].p[0], DIV_ROUND_UP(cpu->sve_max_vq * 2, 8)); - reg.addr = (uintptr_t)r; - reg.id = KVM_REG_ARM64_SVE_PREG(n, 0); - ret = kvm_vcpu_ioctl(cs, KVM_SET_ONE_REG, ®); + ret = kvm_set_one_reg(cs, KVM_REG_ARM64_SVE_PREG(n, 0), r); if (ret) { return ret; } @@ -785,9 +774,7 @@ static int kvm_arch_put_sve(CPUState *cs) r = sve_bswap64(tmp, &env->vfp.pregs[FFR_PRED_NUM].p[0], DIV_ROUND_UP(cpu->sve_max_vq * 2, 8)); - reg.addr = (uintptr_t)r; - reg.id = KVM_REG_ARM64_SVE_FFR(0); - ret = kvm_vcpu_ioctl(cs, KVM_SET_ONE_REG, ®); + ret = kvm_set_one_reg(cs, KVM_REG_ARM64_SVE_FFR(0), r); if (ret) { return ret; } @@ -797,7 +784,6 @@ static int kvm_arch_put_sve(CPUState *cs) int kvm_arch_put_registers(CPUState *cs, int level) { - struct kvm_one_reg reg; uint64_t val; uint32_t fpr; int i, ret; @@ -814,9 +800,8 @@ int kvm_arch_put_registers(CPUState *cs, int level) } for (i = 0; i < 31; i++) { - reg.id = AARCH64_CORE_REG(regs.regs[i]); - reg.addr = (uintptr_t) &env->xregs[i]; - ret = kvm_vcpu_ioctl(cs, KVM_SET_ONE_REG, ®); + ret = kvm_set_one_reg(cs, AARCH64_CORE_REG(regs.regs[i]), + &env->xregs[i]); if (ret) { return ret; } @@ -827,16 +812,12 @@ int kvm_arch_put_registers(CPUState *cs, int level) */ aarch64_save_sp(env, 1); - reg.id = AARCH64_CORE_REG(regs.sp); - reg.addr = (uintptr_t) &env->sp_el[0]; - ret = kvm_vcpu_ioctl(cs, KVM_SET_ONE_REG, ®); + ret = kvm_set_one_reg(cs, AARCH64_CORE_REG(regs.sp), &env->sp_el[0]); if (ret) { return ret; } - reg.id = AARCH64_CORE_REG(sp_el1); - reg.addr = (uintptr_t) &env->sp_el[1]; - ret = kvm_vcpu_ioctl(cs, KVM_SET_ONE_REG, ®); + ret = kvm_set_one_reg(cs, AARCH64_CORE_REG(sp_el1), &env->sp_el[1]); if (ret) { return ret; } @@ -847,23 +828,17 @@ int kvm_arch_put_registers(CPUState *cs, int level) } else { val = cpsr_read(env); } - reg.id = AARCH64_CORE_REG(regs.pstate); - reg.addr = (uintptr_t) &val; - ret = kvm_vcpu_ioctl(cs, KVM_SET_ONE_REG, ®); + ret = kvm_set_one_reg(cs, AARCH64_CORE_REG(regs.pstate), &val); if (ret) { return ret; } - reg.id = AARCH64_CORE_REG(regs.pc); - reg.addr = (uintptr_t) &env->pc; - ret = kvm_vcpu_ioctl(cs, KVM_SET_ONE_REG, ®); + ret = kvm_set_one_reg(cs, AARCH64_CORE_REG(regs.pc), &env->pc); if (ret) { return ret; } - reg.id = AARCH64_CORE_REG(elr_el1); - reg.addr = (uintptr_t) &env->elr_el[1]; - ret = kvm_vcpu_ioctl(cs, KVM_SET_ONE_REG, ®); + ret = kvm_set_one_reg(cs, AARCH64_CORE_REG(elr_el1), &env->elr_el[1]); if (ret) { return ret; } @@ -882,9 +857,8 @@ int kvm_arch_put_registers(CPUState *cs, int level) /* KVM 0-4 map to QEMU banks 1-5 */ for (i = 0; i < KVM_NR_SPSR; i++) { - reg.id = AARCH64_CORE_REG(spsr[i]); - reg.addr = (uintptr_t) &env->banked_spsr[i + 1]; - ret = kvm_vcpu_ioctl(cs, KVM_SET_ONE_REG, ®); + ret = kvm_set_one_reg(cs, AARCH64_CORE_REG(spsr[i]), + &env->banked_spsr[i + 1]); if (ret) { return ret; } @@ -899,18 +873,14 @@ int kvm_arch_put_registers(CPUState *cs, int level) return ret; } - reg.addr = (uintptr_t)(&fpr); fpr = vfp_get_fpsr(env); - reg.id = AARCH64_SIMD_CTRL_REG(fp_regs.fpsr); - ret = kvm_vcpu_ioctl(cs, KVM_SET_ONE_REG, ®); + ret = kvm_set_one_reg(cs, AARCH64_SIMD_CTRL_REG(fp_regs.fpsr), &fpr); if (ret) { return ret; } - reg.addr = (uintptr_t)(&fpr); fpr = vfp_get_fpcr(env); - reg.id = AARCH64_SIMD_CTRL_REG(fp_regs.fpcr); - ret = kvm_vcpu_ioctl(cs, KVM_SET_ONE_REG, ®); + ret = kvm_set_one_reg(cs, AARCH64_SIMD_CTRL_REG(fp_regs.fpcr), &fpr); if (ret) { return ret; } From 40d45b85e045501a3d3d3301f8554ff30adef3ee Mon Sep 17 00:00:00 2001 From: Cornelia Huck Date: Tue, 10 Oct 2023 16:24:52 +0200 Subject: [PATCH 0822/1077] arm/kvm: convert to kvm_get_one_reg MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We can neaten the code by switching the callers that work on a CPUstate to the kvm_get_one_reg function. Reviewed-by: Gavin Shan Signed-off-by: Cornelia Huck Reviewed-by: Philippe Mathieu-Daudé Message-id: 20231010142453.224369-3-cohuck@redhat.com Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- target/arm/kvm.c | 15 +++--------- target/arm/kvm64.c | 57 ++++++++++++---------------------------------- 2 files changed, 18 insertions(+), 54 deletions(-) diff --git a/target/arm/kvm.c b/target/arm/kvm.c index 1a8084c460..7903e2ddde 100644 --- a/target/arm/kvm.c +++ b/target/arm/kvm.c @@ -553,24 +553,19 @@ bool write_kvmstate_to_list(ARMCPU *cpu) bool ok = true; for (i = 0; i < cpu->cpreg_array_len; i++) { - struct kvm_one_reg r; uint64_t regidx = cpu->cpreg_indexes[i]; uint32_t v32; int ret; - r.id = regidx; - switch (regidx & KVM_REG_SIZE_MASK) { case KVM_REG_SIZE_U32: - r.addr = (uintptr_t)&v32; - ret = kvm_vcpu_ioctl(cs, KVM_GET_ONE_REG, &r); + ret = kvm_get_one_reg(cs, regidx, &v32); if (!ret) { cpu->cpreg_values[i] = v32; } break; case KVM_REG_SIZE_U64: - r.addr = (uintptr_t)(cpu->cpreg_values + i); - ret = kvm_vcpu_ioctl(cs, KVM_GET_ONE_REG, &r); + ret = kvm_get_one_reg(cs, regidx, cpu->cpreg_values + i); break; default: g_assert_not_reached(); @@ -706,17 +701,13 @@ int kvm_arm_sync_mpstate_to_qemu(ARMCPU *cpu) void kvm_arm_get_virtual_time(CPUState *cs) { ARMCPU *cpu = ARM_CPU(cs); - struct kvm_one_reg reg = { - .id = KVM_REG_ARM_TIMER_CNT, - .addr = (uintptr_t)&cpu->kvm_vtime, - }; int ret; if (cpu->kvm_vtime_dirty) { return; } - ret = kvm_vcpu_ioctl(cs, KVM_GET_ONE_REG, ®); + ret = kvm_get_one_reg(cs, KVM_REG_ARM_TIMER_CNT, &cpu->kvm_vtime); if (ret) { error_report("Failed to get KVM_REG_ARM_TIMER_CNT"); abort(); diff --git a/target/arm/kvm64.c b/target/arm/kvm64.c index 047b269a79..558c0b88dd 100644 --- a/target/arm/kvm64.c +++ b/target/arm/kvm64.c @@ -909,14 +909,11 @@ int kvm_arch_put_registers(CPUState *cs, int level) static int kvm_arch_get_fpsimd(CPUState *cs) { CPUARMState *env = &ARM_CPU(cs)->env; - struct kvm_one_reg reg; int i, ret; for (i = 0; i < 32; i++) { uint64_t *q = aa64_vfp_qreg(env, i); - reg.id = AARCH64_SIMD_CORE_REG(fp_regs.vregs[i]); - reg.addr = (uintptr_t)q; - ret = kvm_vcpu_ioctl(cs, KVM_GET_ONE_REG, ®); + ret = kvm_get_one_reg(cs, AARCH64_SIMD_CORE_REG(fp_regs.vregs[i]), q); if (ret) { return ret; } else { @@ -940,15 +937,12 @@ static int kvm_arch_get_sve(CPUState *cs) { ARMCPU *cpu = ARM_CPU(cs); CPUARMState *env = &cpu->env; - struct kvm_one_reg reg; uint64_t *r; int n, ret; for (n = 0; n < KVM_ARM64_SVE_NUM_ZREGS; ++n) { r = &env->vfp.zregs[n].d[0]; - reg.addr = (uintptr_t)r; - reg.id = KVM_REG_ARM64_SVE_ZREG(n, 0); - ret = kvm_vcpu_ioctl(cs, KVM_GET_ONE_REG, ®); + ret = kvm_get_one_reg(cs, KVM_REG_ARM64_SVE_ZREG(n, 0), r); if (ret) { return ret; } @@ -957,9 +951,7 @@ static int kvm_arch_get_sve(CPUState *cs) for (n = 0; n < KVM_ARM64_SVE_NUM_PREGS; ++n) { r = &env->vfp.pregs[n].p[0]; - reg.addr = (uintptr_t)r; - reg.id = KVM_REG_ARM64_SVE_PREG(n, 0); - ret = kvm_vcpu_ioctl(cs, KVM_GET_ONE_REG, ®); + ret = kvm_get_one_reg(cs, KVM_REG_ARM64_SVE_PREG(n, 0), r); if (ret) { return ret; } @@ -967,9 +959,7 @@ static int kvm_arch_get_sve(CPUState *cs) } r = &env->vfp.pregs[FFR_PRED_NUM].p[0]; - reg.addr = (uintptr_t)r; - reg.id = KVM_REG_ARM64_SVE_FFR(0); - ret = kvm_vcpu_ioctl(cs, KVM_GET_ONE_REG, ®); + ret = kvm_get_one_reg(cs, KVM_REG_ARM64_SVE_FFR(0), r); if (ret) { return ret; } @@ -980,7 +970,6 @@ static int kvm_arch_get_sve(CPUState *cs) int kvm_arch_get_registers(CPUState *cs) { - struct kvm_one_reg reg; uint64_t val; unsigned int el; uint32_t fpr; @@ -990,31 +979,24 @@ int kvm_arch_get_registers(CPUState *cs) CPUARMState *env = &cpu->env; for (i = 0; i < 31; i++) { - reg.id = AARCH64_CORE_REG(regs.regs[i]); - reg.addr = (uintptr_t) &env->xregs[i]; - ret = kvm_vcpu_ioctl(cs, KVM_GET_ONE_REG, ®); + ret = kvm_get_one_reg(cs, AARCH64_CORE_REG(regs.regs[i]), + &env->xregs[i]); if (ret) { return ret; } } - reg.id = AARCH64_CORE_REG(regs.sp); - reg.addr = (uintptr_t) &env->sp_el[0]; - ret = kvm_vcpu_ioctl(cs, KVM_GET_ONE_REG, ®); + ret = kvm_get_one_reg(cs, AARCH64_CORE_REG(regs.sp), &env->sp_el[0]); if (ret) { return ret; } - reg.id = AARCH64_CORE_REG(sp_el1); - reg.addr = (uintptr_t) &env->sp_el[1]; - ret = kvm_vcpu_ioctl(cs, KVM_GET_ONE_REG, ®); + ret = kvm_get_one_reg(cs, AARCH64_CORE_REG(sp_el1), &env->sp_el[1]); if (ret) { return ret; } - reg.id = AARCH64_CORE_REG(regs.pstate); - reg.addr = (uintptr_t) &val; - ret = kvm_vcpu_ioctl(cs, KVM_GET_ONE_REG, ®); + ret = kvm_get_one_reg(cs, AARCH64_CORE_REG(regs.pstate), &val); if (ret) { return ret; } @@ -1031,9 +1013,7 @@ int kvm_arch_get_registers(CPUState *cs) */ aarch64_restore_sp(env, 1); - reg.id = AARCH64_CORE_REG(regs.pc); - reg.addr = (uintptr_t) &env->pc; - ret = kvm_vcpu_ioctl(cs, KVM_GET_ONE_REG, ®); + ret = kvm_get_one_reg(cs, AARCH64_CORE_REG(regs.pc), &env->pc); if (ret) { return ret; } @@ -1047,9 +1027,7 @@ int kvm_arch_get_registers(CPUState *cs) aarch64_sync_64_to_32(env); } - reg.id = AARCH64_CORE_REG(elr_el1); - reg.addr = (uintptr_t) &env->elr_el[1]; - ret = kvm_vcpu_ioctl(cs, KVM_GET_ONE_REG, ®); + ret = kvm_get_one_reg(cs, AARCH64_CORE_REG(elr_el1), &env->elr_el[1]); if (ret) { return ret; } @@ -1059,9 +1037,8 @@ int kvm_arch_get_registers(CPUState *cs) * KVM SPSRs 0-4 map to QEMU banks 1-5 */ for (i = 0; i < KVM_NR_SPSR; i++) { - reg.id = AARCH64_CORE_REG(spsr[i]); - reg.addr = (uintptr_t) &env->banked_spsr[i + 1]; - ret = kvm_vcpu_ioctl(cs, KVM_GET_ONE_REG, ®); + ret = kvm_get_one_reg(cs, AARCH64_CORE_REG(spsr[i]), + &env->banked_spsr[i + 1]); if (ret) { return ret; } @@ -1082,17 +1059,13 @@ int kvm_arch_get_registers(CPUState *cs) return ret; } - reg.addr = (uintptr_t)(&fpr); - reg.id = AARCH64_SIMD_CTRL_REG(fp_regs.fpsr); - ret = kvm_vcpu_ioctl(cs, KVM_GET_ONE_REG, ®); + ret = kvm_get_one_reg(cs, AARCH64_SIMD_CTRL_REG(fp_regs.fpsr), &fpr); if (ret) { return ret; } vfp_set_fpsr(env, fpr); - reg.addr = (uintptr_t)(&fpr); - reg.id = AARCH64_SIMD_CTRL_REG(fp_regs.fpcr); - ret = kvm_vcpu_ioctl(cs, KVM_GET_ONE_REG, ®); + ret = kvm_get_one_reg(cs, AARCH64_SIMD_CTRL_REG(fp_regs.fpcr), &fpr); if (ret) { return ret; } From a530e470ea4f70d1207ef62273e43a7d178f53ac Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Wed, 27 Sep 2023 11:18:53 +0100 Subject: [PATCH 0823/1077] target/arm: Permit T32 LDM with single register MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit For the Thumb T32 encoding of LDM, if only a single register is specified in the register list this instruction is UNPREDICTABLE, with the following choices: * instruction UNDEFs * instruction is a NOP * instruction loads a single register * instruction loads an unspecified set of registers Currently we choose to UNDEF (a behaviour chosen in commit 4b222545dbf30 in 2019; previously we treated it as "load the specified single register"). Unfortunately there is real world code out there (which shipped in at least Android 11, 12 and 13) which incorrectly uses this UNPREDICTABLE insn on the assumption that it does a single register load, which is (presumably) what it happens to do on real hardware, and is also what it does on the equivalent A32 encoding. Revert to the pre-4b222545dbf30 behaviour of not UNDEFing for this T32 encoding. Resolves: https://gitlab.com/qemu-project/qemu/-/issues/1799 Signed-off-by: Peter Maydell Reviewed-by: Alex Bennée Reviewed-by: Richard Henderson Message-id: 20230927101853.39288-1-peter.maydell@linaro.org --- target/arm/tcg/translate.c | 37 +++++++++++++++++++++++-------------- 1 file changed, 23 insertions(+), 14 deletions(-) diff --git a/target/arm/tcg/translate.c b/target/arm/tcg/translate.c index 48927fbb8c..b3660173d1 100644 --- a/target/arm/tcg/translate.c +++ b/target/arm/tcg/translate.c @@ -7882,7 +7882,7 @@ static void op_addr_block_post(DisasContext *s, arg_ldst_block *a, } } -static bool op_stm(DisasContext *s, arg_ldst_block *a, int min_n) +static bool op_stm(DisasContext *s, arg_ldst_block *a) { int i, j, n, list, mem_idx; bool user = a->u; @@ -7899,7 +7899,14 @@ static bool op_stm(DisasContext *s, arg_ldst_block *a, int min_n) list = a->list; n = ctpop16(list); - if (n < min_n || a->rn == 15) { + /* + * This is UNPREDICTABLE for n < 1 in all encodings, and we choose + * to UNDEF. In the T32 STM encoding n == 1 is also UNPREDICTABLE, + * but hardware treats it like the A32 version and implements the + * single-register-store, and some in-the-wild (buggy) software + * assumes that, so we don't UNDEF on that case. + */ + if (n < 1 || a->rn == 15) { unallocated_encoding(s); return true; } @@ -7935,8 +7942,7 @@ static bool op_stm(DisasContext *s, arg_ldst_block *a, int min_n) static bool trans_STM(DisasContext *s, arg_ldst_block *a) { - /* BitCount(list) < 1 is UNPREDICTABLE */ - return op_stm(s, a, 1); + return op_stm(s, a); } static bool trans_STM_t32(DisasContext *s, arg_ldst_block *a) @@ -7946,11 +7952,10 @@ static bool trans_STM_t32(DisasContext *s, arg_ldst_block *a) unallocated_encoding(s); return true; } - /* BitCount(list) < 2 is UNPREDICTABLE */ - return op_stm(s, a, 2); + return op_stm(s, a); } -static bool do_ldm(DisasContext *s, arg_ldst_block *a, int min_n) +static bool do_ldm(DisasContext *s, arg_ldst_block *a) { int i, j, n, list, mem_idx; bool loaded_base; @@ -7979,7 +7984,14 @@ static bool do_ldm(DisasContext *s, arg_ldst_block *a, int min_n) list = a->list; n = ctpop16(list); - if (n < min_n || a->rn == 15) { + /* + * This is UNPREDICTABLE for n < 1 in all encodings, and we choose + * to UNDEF. In the T32 LDM encoding n == 1 is also UNPREDICTABLE, + * but hardware treats it like the A32 version and implements the + * single-register-load, and some in-the-wild (buggy) software + * assumes that, so we don't UNDEF on that case. + */ + if (n < 1 || a->rn == 15) { unallocated_encoding(s); return true; } @@ -8045,8 +8057,7 @@ static bool trans_LDM_a32(DisasContext *s, arg_ldst_block *a) unallocated_encoding(s); return true; } - /* BitCount(list) < 1 is UNPREDICTABLE */ - return do_ldm(s, a, 1); + return do_ldm(s, a); } static bool trans_LDM_t32(DisasContext *s, arg_ldst_block *a) @@ -8056,16 +8067,14 @@ static bool trans_LDM_t32(DisasContext *s, arg_ldst_block *a) unallocated_encoding(s); return true; } - /* BitCount(list) < 2 is UNPREDICTABLE */ - return do_ldm(s, a, 2); + return do_ldm(s, a); } static bool trans_LDM_t16(DisasContext *s, arg_ldst_block *a) { /* Writeback is conditional on the base register not being loaded. */ a->w = !(a->list & (1 << a->rn)); - /* BitCount(list) < 1 is UNPREDICTABLE */ - return do_ldm(s, a, 1); + return do_ldm(s, a); } static bool trans_CLRM(DisasContext *s, arg_CLRM *a) From cbaf9404f031a39342dee4d3183488a763f149e4 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Thu, 14 Sep 2023 15:57:03 +0100 Subject: [PATCH 0824/1077] hw/arm/smmuv3: Update ID register bit field definitions Update the SMMUv3 ID register bit field definitions to the set in the most recent specification (IHI0700 F.a). Signed-off-by: Peter Maydell Reviewed-by: Richard Henderson Reviewed-by: Mostafa Saleh Reviewed-by: Eric Auger Message-id: 20230914145705.1648377-2-peter.maydell@linaro.org --- hw/arm/smmuv3-internal.h | 38 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/hw/arm/smmuv3-internal.h b/hw/arm/smmuv3-internal.h index 648c2e37a2..6076025ad6 100644 --- a/hw/arm/smmuv3-internal.h +++ b/hw/arm/smmuv3-internal.h @@ -38,33 +38,71 @@ REG32(IDR0, 0x0) FIELD(IDR0, S1P, 1 , 1) FIELD(IDR0, TTF, 2 , 2) FIELD(IDR0, COHACC, 4 , 1) + FIELD(IDR0, BTM, 5 , 1) + FIELD(IDR0, HTTU, 6 , 2) + FIELD(IDR0, DORMHINT, 8 , 1) + FIELD(IDR0, HYP, 9 , 1) + FIELD(IDR0, ATS, 10, 1) + FIELD(IDR0, NS1ATS, 11, 1) FIELD(IDR0, ASID16, 12, 1) + FIELD(IDR0, MSI, 13, 1) + FIELD(IDR0, SEV, 14, 1) + FIELD(IDR0, ATOS, 15, 1) + FIELD(IDR0, PRI, 16, 1) + FIELD(IDR0, VMW, 17, 1) FIELD(IDR0, VMID16, 18, 1) + FIELD(IDR0, CD2L, 19, 1) + FIELD(IDR0, VATOS, 20, 1) FIELD(IDR0, TTENDIAN, 21, 2) + FIELD(IDR0, ATSRECERR, 23, 1) FIELD(IDR0, STALL_MODEL, 24, 2) FIELD(IDR0, TERM_MODEL, 26, 1) FIELD(IDR0, STLEVEL, 27, 2) + FIELD(IDR0, RME_IMPL, 30, 1) REG32(IDR1, 0x4) FIELD(IDR1, SIDSIZE, 0 , 6) + FIELD(IDR1, SSIDSIZE, 6 , 5) + FIELD(IDR1, PRIQS, 11, 5) FIELD(IDR1, EVENTQS, 16, 5) FIELD(IDR1, CMDQS, 21, 5) + FIELD(IDR1, ATTR_PERMS_OVR, 26, 1) + FIELD(IDR1, ATTR_TYPES_OVR, 27, 1) + FIELD(IDR1, REL, 28, 1) + FIELD(IDR1, QUEUES_PRESET, 29, 1) + FIELD(IDR1, TABLES_PRESET, 30, 1) + FIELD(IDR1, ECMDQ, 31, 1) #define SMMU_IDR1_SIDSIZE 16 #define SMMU_CMDQS 19 #define SMMU_EVENTQS 19 REG32(IDR2, 0x8) + FIELD(IDR2, BA_VATOS, 0, 10) + REG32(IDR3, 0xc) FIELD(IDR3, HAD, 2, 1); + FIELD(IDR3, PBHA, 3, 1); + FIELD(IDR3, XNX, 4, 1); + FIELD(IDR3, PPS, 5, 1); + FIELD(IDR3, MPAM, 7, 1); + FIELD(IDR3, FWB, 8, 1); + FIELD(IDR3, STT, 9, 1); FIELD(IDR3, RIL, 10, 1); FIELD(IDR3, BBML, 11, 2); + FIELD(IDR3, E0PD, 13, 1); + FIELD(IDR3, PTWNNC, 14, 1); + FIELD(IDR3, DPT, 15, 1); + REG32(IDR4, 0x10) + REG32(IDR5, 0x14) FIELD(IDR5, OAS, 0, 3); FIELD(IDR5, GRAN4K, 4, 1); FIELD(IDR5, GRAN16K, 5, 1); FIELD(IDR5, GRAN64K, 6, 1); + FIELD(IDR5, VAX, 10, 2); + FIELD(IDR5, STALL_MAX, 16, 16); #define SMMU_IDR5_OAS 4 From 27fd85d35b7bb05a7b939bf36de33b6aa68005f6 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Thu, 14 Sep 2023 15:57:04 +0100 Subject: [PATCH 0825/1077] hw/arm/smmuv3: Sort ID register setting into field order In smmuv3_init_regs() when we set the various bits in the ID registers, we do this almost in order of the fields in the registers, but not quite. Move the initialization of SMMU_IDR3.RIL and SMMU_IDR5.OAS into their correct places. Signed-off-by: Peter Maydell Reviewed-by: Richard Henderson Reviewed-by: Mostafa Saleh Reviewed-by: Eric Auger Message-id: 20230914145705.1648377-3-peter.maydell@linaro.org --- hw/arm/smmuv3.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/hw/arm/smmuv3.c b/hw/arm/smmuv3.c index 6f2b2bd45f..f03d58300f 100644 --- a/hw/arm/smmuv3.c +++ b/hw/arm/smmuv3.c @@ -278,15 +278,15 @@ static void smmuv3_init_regs(SMMUv3State *s) s->idr[1] = FIELD_DP32(s->idr[1], IDR1, EVENTQS, SMMU_EVENTQS); s->idr[1] = FIELD_DP32(s->idr[1], IDR1, CMDQS, SMMU_CMDQS); - s->idr[3] = FIELD_DP32(s->idr[3], IDR3, RIL, 1); s->idr[3] = FIELD_DP32(s->idr[3], IDR3, HAD, 1); + s->idr[3] = FIELD_DP32(s->idr[3], IDR3, RIL, 1); s->idr[3] = FIELD_DP32(s->idr[3], IDR3, BBML, 2); + s->idr[5] = FIELD_DP32(s->idr[5], IDR5, OAS, SMMU_IDR5_OAS); /* 44 bits */ /* 4K, 16K and 64K granule support */ s->idr[5] = FIELD_DP32(s->idr[5], IDR5, GRAN4K, 1); s->idr[5] = FIELD_DP32(s->idr[5], IDR5, GRAN16K, 1); s->idr[5] = FIELD_DP32(s->idr[5], IDR5, GRAN64K, 1); - s->idr[5] = FIELD_DP32(s->idr[5], IDR5, OAS, SMMU_IDR5_OAS); /* 44 bits */ s->cmdq.base = deposit64(s->cmdq.base, 0, 5, SMMU_CMDQS); s->cmdq.prod = 0; From 4cdd146d8bb72117b10ff22afe3a730dc4df4913 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Thu, 14 Sep 2023 15:57:05 +0100 Subject: [PATCH 0826/1077] hw/arm/smmuv3: Advertise SMMUv3.1-XNX feature The SMMUv3.1-XNX feature is mandatory for an SMMUv3.1 if S2P is supported, so we should theoretically have implemented it as part of the recent S2P work. Fortunately, for us the implementation is a no-op. This feature is about interpretation of the stage 2 page table descriptor XN bits, which control execute permissions. For QEMU, the permission bits passed to an IOMMU (via MemTxAttrs and IOMMUAccessFlags) only indicate read and write; we do not distinguish data reads from instruction reads outside the CPU proper. In the SMMU architecture's terms, our interconnect between the client device and the SMMU doesn't have the ability to convey the INST attribute, and we therefore use the default value of "data" for this attribute. We also do not support the bits in the Stream Table Entry that can override the on-the-bus transaction attribute permissions (we do not set SMMU_IDR1.ATTR_PERMS_OVR=1). These two things together mean that for our implementation, it never has to deal with transactions with the INST attribute, and so it can correctly ignore the XN bits entirely. So we already implement FEAT_XNX's "XN field is now 2 bits, not 1" behaviour to the extent that we need to. Advertise the presence of the feature in SMMU_IDR3.XNX. Signed-off-by: Peter Maydell Reviewed-by: Richard Henderson Reviewed-by: Mostafa Saleh Reviewed-by: Eric Auger Message-id: 20230914145705.1648377-4-peter.maydell@linaro.org --- hw/arm/smmuv3.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/hw/arm/smmuv3.c b/hw/arm/smmuv3.c index f03d58300f..c3871ae067 100644 --- a/hw/arm/smmuv3.c +++ b/hw/arm/smmuv3.c @@ -279,6 +279,10 @@ static void smmuv3_init_regs(SMMUv3State *s) s->idr[1] = FIELD_DP32(s->idr[1], IDR1, CMDQS, SMMU_CMDQS); s->idr[3] = FIELD_DP32(s->idr[3], IDR3, HAD, 1); + if (FIELD_EX32(s->idr[0], IDR0, S2P)) { + /* XNX is a stage-2-specific feature */ + s->idr[3] = FIELD_DP32(s->idr[3], IDR3, XNX, 1); + } s->idr[3] = FIELD_DP32(s->idr[3], IDR3, RIL, 1); s->idr[3] = FIELD_DP32(s->idr[3], IDR3, BBML, 2); From 3d80bbf1f619ad1a0db85bb385ce4f5f74e4b0a3 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Thu, 21 Sep 2023 19:54:45 +0100 Subject: [PATCH 0827/1077] target/arm: Implement FEAT_HPMN0 FEAT_HPMN0 is a small feature which defines that it is valid for MDCR_EL2.HPMN to be set to 0, meaning "no PMU event counters provided to an EL1 guest" (previously this setting was reserved). QEMU's implementation almost gets HPMN == 0 right, but we need to fix one check in pmevcntr_is_64_bit(). That is enough for us to advertise the feature in the 'max' CPU. (We don't need to make the behaviour conditional on feature presence, because the FEAT_HPMN0 behaviour is within the range of permitted UNPREDICTABLE behaviour for a non-FEAT_HPMN0 implementation.) Signed-off-by: Peter Maydell Reviewed-by: Richard Henderson Message-id: 20230921185445.3339214-1-peter.maydell@linaro.org --- docs/system/arm/emulation.rst | 1 + target/arm/helper.c | 2 +- target/arm/tcg/cpu32.c | 4 ++++ target/arm/tcg/cpu64.c | 1 + 4 files changed, 7 insertions(+), 1 deletion(-) diff --git a/docs/system/arm/emulation.rst b/docs/system/arm/emulation.rst index 965cbf84c5..47fd648035 100644 --- a/docs/system/arm/emulation.rst +++ b/docs/system/arm/emulation.rst @@ -46,6 +46,7 @@ the following architecture extensions: - FEAT_HCX (Support for the HCRX_EL2 register) - FEAT_HPDS (Hierarchical permission disables) - FEAT_HPDS2 (Translation table page-based hardware attributes) +- FEAT_HPMN0 (Setting of MDCR_EL2.HPMN to zero) - FEAT_I8MM (AArch64 Int8 matrix multiplication instructions) - FEAT_IDST (ID space trap handling) - FEAT_IESB (Implicit error synchronization event) diff --git a/target/arm/helper.c b/target/arm/helper.c index 01cd147456..b29edb26af 100644 --- a/target/arm/helper.c +++ b/target/arm/helper.c @@ -1283,7 +1283,7 @@ static bool pmevcntr_is_64_bit(CPUARMState *env, int counter) bool hlp = env->cp15.mdcr_el2 & MDCR_HLP; int hpmn = env->cp15.mdcr_el2 & MDCR_HPMN; - if (hpmn != 0 && counter >= hpmn) { + if (counter >= hpmn) { return hlp; } } diff --git a/target/arm/tcg/cpu32.c b/target/arm/tcg/cpu32.c index 1f918ff537..0d5d8e307d 100644 --- a/target/arm/tcg/cpu32.c +++ b/target/arm/tcg/cpu32.c @@ -89,6 +89,10 @@ void aa32_max_features(ARMCPU *cpu) t = FIELD_DP32(t, ID_DFR0, COPSDBG, 9); /* FEAT_Debugv8p4 */ t = FIELD_DP32(t, ID_DFR0, PERFMON, 6); /* FEAT_PMUv3p5 */ cpu->isar.id_dfr0 = t; + + t = cpu->isar.id_dfr1; + t = FIELD_DP32(t, ID_DFR1, HPMN0, 1); /* FEAT_HPMN0 */ + cpu->isar.id_dfr1 = t; } /* CPU models. These are not needed for the AArch64 linux-user build. */ diff --git a/target/arm/tcg/cpu64.c b/target/arm/tcg/cpu64.c index 68928e5127..d978aa5f7a 100644 --- a/target/arm/tcg/cpu64.c +++ b/target/arm/tcg/cpu64.c @@ -1109,6 +1109,7 @@ void aarch64_max_tcg_initfn(Object *obj) t = cpu->isar.id_aa64dfr0; t = FIELD_DP64(t, ID_AA64DFR0, DEBUGVER, 9); /* FEAT_Debugv8p4 */ t = FIELD_DP64(t, ID_AA64DFR0, PMUVER, 6); /* FEAT_PMUv3p5 */ + t = FIELD_DP64(t, ID_AA64DFR0, HPMN0, 1); /* FEAT_HPMN0 */ cpu->isar.id_aa64dfr0 = t; t = cpu->isar.id_aa64smfr0; From 4fd79a96ea9149a7ea8fba5c0ea74ff5f9f02139 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Mon, 25 Sep 2023 12:04:29 +0100 Subject: [PATCH 0828/1077] target/arm/kvm64.c: Remove unused include MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The include of hw/arm/virt.h in kvm64.c is unnecessary and also a layering violation since the generic KVM code shouldn't need to know anything about board-specifics. The include line is an accidental leftover from commit 15613357ba53a4763, where we cleaned up the code to not depend on virt board internals but forgot to also remove the now-redundant include line. Signed-off-by: Peter Maydell Reviewed-by: Gavin Shan Reviewed-by: Philippe Mathieu-Daudé Message-id: 20230925110429.3917202-1-peter.maydell@linaro.org --- target/arm/kvm64.c | 1 - 1 file changed, 1 deletion(-) diff --git a/target/arm/kvm64.c b/target/arm/kvm64.c index 558c0b88dd..4bb68646e4 100644 --- a/target/arm/kvm64.c +++ b/target/arm/kvm64.c @@ -30,7 +30,6 @@ #include "internals.h" #include "hw/acpi/acpi.h" #include "hw/acpi/ghes.h" -#include "hw/arm/virt.h" static bool have_guest_debug; From 30722e0445908d3cf2d366d7bee69d0ae57401be Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Mon, 25 Sep 2023 12:22:19 +0100 Subject: [PATCH 0829/1077] target/arm/common-semi-target.h: Remove unnecessary boot.h include The hw/arm/boot.h include in common-semi-target.h is not actually needed, and it's a bit odd because it pulls a hw/arm header into a target/arm file. This include was originally needed because the semihosting code used the arm_boot_info struct to get the base address of the RAM in system emulation, to use in a (bad) heuristic for the return values for the SYS_HEAPINFO semihosting call. We've since overhauled how we calculate the HEAPINFO values in system emulation, and the code no longer uses the arm_boot_info struct. Remove the now-redundant include line, and instead directly include the cpu-qom.h header that we were previously getting via boot.h. Signed-off-by: Peter Maydell Reviewed-by: Richard Henderson Message-id: 20230925112219.3919261-1-peter.maydell@linaro.org --- target/arm/common-semi-target.h | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/target/arm/common-semi-target.h b/target/arm/common-semi-target.h index 19438ed8cd..da51f2d7f5 100644 --- a/target/arm/common-semi-target.h +++ b/target/arm/common-semi-target.h @@ -10,9 +10,7 @@ #ifndef TARGET_ARM_COMMON_SEMI_TARGET_H #define TARGET_ARM_COMMON_SEMI_TARGET_H -#ifndef CONFIG_USER_ONLY -#include "hw/arm/boot.h" -#endif +#include "target/arm/cpu-qom.h" static inline target_ulong common_semi_arg(CPUState *cs, int argno) { From 3a45f4f5376cad9489e1608f2e4960fd34805546 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Tue, 26 Sep 2023 16:56:19 +0100 Subject: [PATCH 0830/1077] target/arm/arm-powerctl: Correctly init CPUs when powered on to lower EL The code for powering on a CPU in arm-powerctl.c has two separate use cases: * emulation of a real hardware power controller * emulation of firmware interfaces (primarily PSCI) with CPU on/off APIs For the first case, we only need to reset the CPU and set its starting PC and X0. For the second case, because we're emulating the firmware we need to ensure that it's in the state that the firmware provides. In particular, when we reset to a lower EL than the highest one we are emulating, we need to put the CPU into a state that permits correct running at that lower EL. We already do a little of this in arm-powerctl.c (for instance we set SCR_HCE to enable the HVC insn) but we don't do enough of it. This means that in the case where we are emulating EL3 but also providing emulated PSCI the guest will crash when a secondary core tries to use a feature that needs an SCR_EL3 bit to be set, such as MTE or PAuth. The hw/arm/boot.c code also has to support this "start guest code in an EL that's lower than the highest emulated EL" case in order to do direct guest kernel booting; it has all the necessary initialization code to set the SCR_EL3 bits. Pull the relevant boot.c code out into a separate function so we can share it between there and arm-powerctl.c. This refactoring has a few code changes that look like they might be behaviour changes but aren't: * if info->secure_boot is false and info->secure_board_setup is true, then the old code would start the first CPU in Hyp mode but without changing SCR.NS and NSACR.{CP11,CP10}. This was wrong behaviour because there's no such thing as Secure Hyp mode. The new code will leave the CPU in SVC. (There is no board which sets secure_boot to false and secure_board_setup to true, so this isn't a behaviour change for any of our boards.) * we don't explicitly clear SCR.NS when arm-powerctl.c does a CPU-on to EL3. This was a no-op because CPU reset will reset to NS == 0. And some real behaviour changes: * we no longer set HCR_EL2.RW when booting into EL2: the guest can and should do that themselves before dropping into their EL1 code. (arm-powerctl and boot did this differently; I opted to use the logic from arm-powerctl, which only sets HCR_EL2.RW when it's directly starting the guest in EL1, because it's more correct, and I don't expect guests to be accidentally depending on our having set the RW bit for them.) * if we are booting a CPU into AArch32 Secure SVC then we won't set SCR.HCE any more. This affects only the vexpress-a15 and raspi2b machine types. Guests booting in this case will either: - be able to set SCR.HCE themselves as part of moving from Secure SVC into NS Hyp mode - will move from Secure SVC to NS SVC, and won't care about behaviour of the HVC insn - will stay in Secure SVC, and won't care about HVC * on an arm-powerctl CPU-on we will now set the SCR bits for pauth/mte/sve/sme/hcx/fgt features The first two of these are very minor and I don't expect guest code to trip over them, so I didn't judge it worth convoluting the code in an attempt to keep exactly the same boot.c behaviour. The third change fixes issue 1899. Resolves: https://gitlab.com/qemu-project/qemu/-/issues/1899 Signed-off-by: Peter Maydell Reviewed-by: Richard Henderson Message-id: 20230926155619.4028618-1-peter.maydell@linaro.org --- hw/arm/boot.c | 95 ++++++++++----------------------------- target/arm/arm-powerctl.c | 53 +--------------------- target/arm/cpu.c | 95 +++++++++++++++++++++++++++++++++++++++ target/arm/cpu.h | 22 +++++++++ 4 files changed, 141 insertions(+), 124 deletions(-) diff --git a/hw/arm/boot.c b/hw/arm/boot.c index 24fa169060..84ea6a807a 100644 --- a/hw/arm/boot.c +++ b/hw/arm/boot.c @@ -722,84 +722,35 @@ static void do_cpu_reset(void *opaque) cpu_set_pc(cs, entry); } else { - /* If we are booting Linux then we need to check whether we are - * booting into secure or non-secure state and adjust the state - * accordingly. Out of reset, ARM is defined to be in secure state - * (SCR.NS = 0), we change that here if non-secure boot has been - * requested. + /* + * If we are booting Linux then we might need to do so at: + * - AArch64 NS EL2 or NS EL1 + * - AArch32 Secure SVC (EL3) + * - AArch32 NS Hyp (EL2) + * - AArch32 NS SVC (EL1) + * Configure the CPU in the way boot firmware would do to + * drop us down to the appropriate level. */ - if (arm_feature(env, ARM_FEATURE_EL3)) { - /* AArch64 is defined to come out of reset into EL3 if enabled. - * If we are booting Linux then we need to adjust our EL as - * Linux expects us to be in EL2 or EL1. AArch32 resets into - * SVC, which Linux expects, so no privilege/exception level to - * adjust. - */ - if (env->aarch64) { - env->cp15.scr_el3 |= SCR_RW; - if (arm_feature(env, ARM_FEATURE_EL2)) { - env->cp15.hcr_el2 |= HCR_RW; - env->pstate = PSTATE_MODE_EL2h; - } else { - env->pstate = PSTATE_MODE_EL1h; - } - if (cpu_isar_feature(aa64_pauth, cpu)) { - env->cp15.scr_el3 |= SCR_API | SCR_APK; - } - if (cpu_isar_feature(aa64_mte, cpu)) { - env->cp15.scr_el3 |= SCR_ATA; - } - if (cpu_isar_feature(aa64_sve, cpu)) { - env->cp15.cptr_el[3] |= R_CPTR_EL3_EZ_MASK; - env->vfp.zcr_el[3] = 0xf; - } - if (cpu_isar_feature(aa64_sme, cpu)) { - env->cp15.cptr_el[3] |= R_CPTR_EL3_ESM_MASK; - env->cp15.scr_el3 |= SCR_ENTP2; - env->vfp.smcr_el[3] = 0xf; - } - if (cpu_isar_feature(aa64_hcx, cpu)) { - env->cp15.scr_el3 |= SCR_HXEN; - } - if (cpu_isar_feature(aa64_fgt, cpu)) { - env->cp15.scr_el3 |= SCR_FGTEN; - } + int target_el = arm_feature(env, ARM_FEATURE_EL2) ? 2 : 1; - /* AArch64 kernels never boot in secure mode */ - assert(!info->secure_boot); - /* This hook is only supported for AArch32 currently: - * bootloader_aarch64[] will not call the hook, and - * the code above has already dropped us into EL2 or EL1. - */ - assert(!info->secure_board_setup); - } - - if (arm_feature(env, ARM_FEATURE_EL2)) { - /* If we have EL2 then Linux expects the HVC insn to work */ - env->cp15.scr_el3 |= SCR_HCE; - } - - /* Set to non-secure if not a secure boot */ - if (!info->secure_boot && - (cs != first_cpu || !info->secure_board_setup)) { - /* Linux expects non-secure state */ - env->cp15.scr_el3 |= SCR_NS; - /* Set NSACR.{CP11,CP10} so NS can access the FPU */ - env->cp15.nsacr |= 3 << 10; - } - } - - if (!env->aarch64 && !info->secure_boot && - arm_feature(env, ARM_FEATURE_EL2)) { + if (env->aarch64) { /* - * This is an AArch32 boot not to Secure state, and - * we have Hyp mode available, so boot the kernel into - * Hyp mode. This is not how the CPU comes out of reset, - * so we need to manually put it there. + * AArch64 kernels never boot in secure mode, and we don't + * support the secure_board_setup hook for AArch64. */ - cpsr_write(env, ARM_CPU_MODE_HYP, CPSR_M, CPSRWriteRaw); + assert(!info->secure_boot); + assert(!info->secure_board_setup); + } else { + if (arm_feature(env, ARM_FEATURE_EL3) && + (info->secure_boot || + (info->secure_board_setup && cs == first_cpu))) { + /* Start this CPU in Secure SVC */ + target_el = 3; + } } + arm_emulate_firmware_reset(cs, target_el); + if (cs == first_cpu) { AddressSpace *as = arm_boot_address_space(cpu, info); diff --git a/target/arm/arm-powerctl.c b/target/arm/arm-powerctl.c index 326a03153d..c078849403 100644 --- a/target/arm/arm-powerctl.c +++ b/target/arm/arm-powerctl.c @@ -65,60 +65,9 @@ static void arm_set_cpu_on_async_work(CPUState *target_cpu_state, /* Initialize the cpu we are turning on */ cpu_reset(target_cpu_state); + arm_emulate_firmware_reset(target_cpu_state, info->target_el); target_cpu_state->halted = 0; - if (info->target_aa64) { - if ((info->target_el < 3) && arm_feature(&target_cpu->env, - ARM_FEATURE_EL3)) { - /* - * As target mode is AArch64, we need to set lower - * exception level (the requested level 2) to AArch64 - */ - target_cpu->env.cp15.scr_el3 |= SCR_RW; - } - - if ((info->target_el < 2) && arm_feature(&target_cpu->env, - ARM_FEATURE_EL2)) { - /* - * As target mode is AArch64, we need to set lower - * exception level (the requested level 1) to AArch64 - */ - target_cpu->env.cp15.hcr_el2 |= HCR_RW; - } - - target_cpu->env.pstate = aarch64_pstate_mode(info->target_el, true); - } else { - /* We are requested to boot in AArch32 mode */ - static const uint32_t mode_for_el[] = { 0, - ARM_CPU_MODE_SVC, - ARM_CPU_MODE_HYP, - ARM_CPU_MODE_SVC }; - - cpsr_write(&target_cpu->env, mode_for_el[info->target_el], CPSR_M, - CPSRWriteRaw); - } - - if (info->target_el == 3) { - /* Processor is in secure mode */ - target_cpu->env.cp15.scr_el3 &= ~SCR_NS; - } else { - /* Processor is not in secure mode */ - target_cpu->env.cp15.scr_el3 |= SCR_NS; - - /* Set NSACR.{CP11,CP10} so NS can access the FPU */ - target_cpu->env.cp15.nsacr |= 3 << 10; - - /* - * If QEMU is providing the equivalent of EL3 firmware, then we need - * to make sure a CPU targeting EL2 comes out of reset with a - * functional HVC insn. - */ - if (arm_feature(&target_cpu->env, ARM_FEATURE_EL3) - && info->target_el == 2) { - target_cpu->env.cp15.scr_el3 |= SCR_HCE; - } - } - /* We check if the started CPU is now at the correct level */ assert(info->target_el == arm_current_el(&target_cpu->env)); diff --git a/target/arm/cpu.c b/target/arm/cpu.c index 6c6c551573..aa4e006f21 100644 --- a/target/arm/cpu.c +++ b/target/arm/cpu.c @@ -553,6 +553,101 @@ static void arm_cpu_reset_hold(Object *obj) } } +void arm_emulate_firmware_reset(CPUState *cpustate, int target_el) +{ + ARMCPU *cpu = ARM_CPU(cpustate); + CPUARMState *env = &cpu->env; + bool have_el3 = arm_feature(env, ARM_FEATURE_EL3); + bool have_el2 = arm_feature(env, ARM_FEATURE_EL2); + + /* + * Check we have the EL we're aiming for. If that is the + * highest implemented EL, then cpu_reset has already done + * all the work. + */ + switch (target_el) { + case 3: + assert(have_el3); + return; + case 2: + assert(have_el2); + if (!have_el3) { + return; + } + break; + case 1: + if (!have_el3 && !have_el2) { + return; + } + break; + default: + g_assert_not_reached(); + } + + if (have_el3) { + /* + * Set the EL3 state so code can run at EL2. This should match + * the requirements set by Linux in its booting spec. + */ + if (env->aarch64) { + env->cp15.scr_el3 |= SCR_RW; + if (cpu_isar_feature(aa64_pauth, cpu)) { + env->cp15.scr_el3 |= SCR_API | SCR_APK; + } + if (cpu_isar_feature(aa64_mte, cpu)) { + env->cp15.scr_el3 |= SCR_ATA; + } + if (cpu_isar_feature(aa64_sve, cpu)) { + env->cp15.cptr_el[3] |= R_CPTR_EL3_EZ_MASK; + env->vfp.zcr_el[3] = 0xf; + } + if (cpu_isar_feature(aa64_sme, cpu)) { + env->cp15.cptr_el[3] |= R_CPTR_EL3_ESM_MASK; + env->cp15.scr_el3 |= SCR_ENTP2; + env->vfp.smcr_el[3] = 0xf; + } + if (cpu_isar_feature(aa64_hcx, cpu)) { + env->cp15.scr_el3 |= SCR_HXEN; + } + if (cpu_isar_feature(aa64_fgt, cpu)) { + env->cp15.scr_el3 |= SCR_FGTEN; + } + } + + if (target_el == 2) { + /* If the guest is at EL2 then Linux expects the HVC insn to work */ + env->cp15.scr_el3 |= SCR_HCE; + } + + /* Put CPU into non-secure state */ + env->cp15.scr_el3 |= SCR_NS; + /* Set NSACR.{CP11,CP10} so NS can access the FPU */ + env->cp15.nsacr |= 3 << 10; + } + + if (have_el2 && target_el < 2) { + /* Set EL2 state so code can run at EL1. */ + if (env->aarch64) { + env->cp15.hcr_el2 |= HCR_RW; + } + } + + /* Set the CPU to the desired state */ + if (env->aarch64) { + env->pstate = aarch64_pstate_mode(target_el, true); + } else { + static const uint32_t mode_for_el[] = { + 0, + ARM_CPU_MODE_SVC, + ARM_CPU_MODE_HYP, + ARM_CPU_MODE_SVC, + }; + + cpsr_write(env, mode_for_el[target_el], CPSR_M, CPSRWriteRaw); + } +} + + #if defined(CONFIG_TCG) && !defined(CONFIG_USER_ONLY) static inline bool arm_excp_unmasked(CPUState *cs, unsigned int excp_idx, diff --git a/target/arm/cpu.h b/target/arm/cpu.h index a9edfb8353..76d4cef9e3 100644 --- a/target/arm/cpu.h +++ b/target/arm/cpu.h @@ -1149,6 +1149,28 @@ int arm_cpu_write_elf64_note(WriteCoreDumpFunction f, CPUState *cs, int arm_cpu_write_elf32_note(WriteCoreDumpFunction f, CPUState *cs, int cpuid, DumpState *s); +/** + * arm_emulate_firmware_reset: Emulate firmware CPU reset handling + * @cpu: CPU (which must have been freshly reset) + * @target_el: exception level to put the CPU into + * @secure: whether to put the CPU in secure state + * + * When QEMU is directly running a guest kernel at a lower level than + * EL3 it implicitly emulates some aspects of the guest firmware. + * This includes that on reset we need to configure the parts of the + * CPU corresponding to EL3 so that the real guest code can run at its + * lower exception level. This function does that post-reset CPU setup, + * for when we do direct boot of a guest kernel, and for when we + * emulate PSCI and similar firmware interfaces starting a CPU at a + * lower exception level. + * + * @target_el must be an EL implemented by the CPU between 1 and 3. + * We do not support dropping into a Secure EL other than 3. + * + * It is the responsibility of the caller to call arm_rebuild_hflags(). + */ +void arm_emulate_firmware_reset(CPUState *cpustate, int target_el); + #ifdef TARGET_AARCH64 int aarch64_cpu_gdb_read_register(CPUState *cpu, GByteArray *buf, int reg); int aarch64_cpu_gdb_write_register(CPUState *cpu, uint8_t *buf, int reg); From 9ef2629712680e70cbf39d8b6cb1ec0e0e2e72fa Mon Sep 17 00:00:00 2001 From: Chris Rauer Date: Fri, 22 Sep 2023 18:14:11 +0000 Subject: [PATCH 0831/1077] hw/timer/npcm7xx_timer: Prevent timer from counting down past zero The counter register is only 24-bits and counts down. If the timer is running but the qtimer to reset it hasn't fired off yet, there is a chance the regster read can return an invalid result. Signed-off-by: Chris Rauer Message-id: 20230922181411.2697135-1-crauer@google.com Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- hw/timer/npcm7xx_timer.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/hw/timer/npcm7xx_timer.c b/hw/timer/npcm7xx_timer.c index 32f5e021f8..a8bd93aeb2 100644 --- a/hw/timer/npcm7xx_timer.c +++ b/hw/timer/npcm7xx_timer.c @@ -138,6 +138,9 @@ static int64_t npcm7xx_timer_count_to_ns(NPCM7xxTimer *t, uint32_t count) /* Convert a time interval in nanoseconds to a timer cycle count. */ static uint32_t npcm7xx_timer_ns_to_count(NPCM7xxTimer *t, int64_t ns) { + if (ns < 0) { + return 0; + } return clock_ns_to_ticks(t->ctrl->clock, ns) / npcm7xx_tcsr_prescaler(t->tcsr); } From 2a052b4ee01b3c413cef2ef49cb780cde17d4ba1 Mon Sep 17 00:00:00 2001 From: Suraj Shirvankar Date: Tue, 3 Oct 2023 14:45:14 +0200 Subject: [PATCH 0832/1077] contrib/elf2dmp: Use g_malloc(), g_new() and g_free() QEMU coding style uses the glib memory allocation APIs, not the raw libc malloc/free. Switch the allocation and free calls in elf2dmp to use these functions (dropping the now-unneeded checks for failure). Signed-off-by: Suraj Shirvankar Message-id: 169753938460.23804.11418813007617535750-1@git.sr.ht [PMM: also remove NULL checks from g_malloc() calls; beef up commit message] Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- contrib/elf2dmp/addrspace.c | 7 ++----- contrib/elf2dmp/main.c | 9 +++------ contrib/elf2dmp/pdb.c | 19 ++++++++----------- contrib/elf2dmp/qemu_elf.c | 7 ++----- 4 files changed, 15 insertions(+), 27 deletions(-) diff --git a/contrib/elf2dmp/addrspace.c b/contrib/elf2dmp/addrspace.c index 64b5d680ad..6f608a517b 100644 --- a/contrib/elf2dmp/addrspace.c +++ b/contrib/elf2dmp/addrspace.c @@ -72,10 +72,7 @@ int pa_space_create(struct pa_space *ps, QEMU_Elf *qemu_elf) } } - ps->block = malloc(sizeof(*ps->block) * ps->block_nr); - if (!ps->block) { - return 1; - } + ps->block = g_new(struct pa_block, ps->block_nr); for (i = 0; i < phdr_nr; i++) { if (phdr[i].p_type == PT_LOAD) { @@ -97,7 +94,7 @@ int pa_space_create(struct pa_space *ps, QEMU_Elf *qemu_elf) void pa_space_destroy(struct pa_space *ps) { ps->block_nr = 0; - free(ps->block); + g_free(ps->block); } void va_space_set_dtb(struct va_space *vs, uint64_t dtb) diff --git a/contrib/elf2dmp/main.c b/contrib/elf2dmp/main.c index 6de5c9808e..cbc38a7c10 100644 --- a/contrib/elf2dmp/main.c +++ b/contrib/elf2dmp/main.c @@ -120,14 +120,11 @@ static KDDEBUGGER_DATA64 *get_kdbg(uint64_t KernBase, struct pdb_reader *pdb, } } - kdbg = malloc(kdbg_hdr.Size); - if (!kdbg) { - return NULL; - } + kdbg = g_malloc(kdbg_hdr.Size); if (va_space_rw(vs, KdDebuggerDataBlock, kdbg, kdbg_hdr.Size, 0)) { eprintf("Failed to extract entire KDBG\n"); - free(kdbg); + g_free(kdbg); return NULL; } @@ -643,7 +640,7 @@ int main(int argc, char *argv[]) } out_kdbg: - free(kdbg); + g_free(kdbg); out_pdb: pdb_exit(&pdb); out_pdb_file: diff --git a/contrib/elf2dmp/pdb.c b/contrib/elf2dmp/pdb.c index 8e3c18c82f..40991f5f4c 100644 --- a/contrib/elf2dmp/pdb.c +++ b/contrib/elf2dmp/pdb.c @@ -94,18 +94,18 @@ uint64_t pdb_resolve(uint64_t img_base, struct pdb_reader *r, const char *name) static void pdb_reader_ds_exit(struct pdb_reader *r) { - free(r->ds.toc); + g_free(r->ds.toc); } static void pdb_exit_symbols(struct pdb_reader *r) { - free(r->modimage); - free(r->symbols); + g_free(r->modimage); + g_free(r->symbols); } static void pdb_exit_segments(struct pdb_reader *r) { - free(r->segs); + g_free(r->segs); } static void *pdb_ds_read(const PDB_DS_HEADER *header, @@ -120,10 +120,7 @@ static void *pdb_ds_read(const PDB_DS_HEADER *header, nBlocks = (size + header->block_size - 1) / header->block_size; - buffer = malloc(nBlocks * header->block_size); - if (!buffer) { - return NULL; - } + buffer = g_malloc(nBlocks * header->block_size); for (i = 0; i < nBlocks; i++) { memcpy(buffer + i * header->block_size, (const char *)header + @@ -206,7 +203,7 @@ static int pdb_init_symbols(struct pdb_reader *r) return 0; out_symbols: - free(symbols); + g_free(symbols); return err; } @@ -263,7 +260,7 @@ static int pdb_reader_init(struct pdb_reader *r, void *data) out_sym: pdb_exit_symbols(r); out_root: - free(r->ds.root); + g_free(r->ds.root); out_ds: pdb_reader_ds_exit(r); @@ -274,7 +271,7 @@ static void pdb_reader_exit(struct pdb_reader *r) { pdb_exit_segments(r); pdb_exit_symbols(r); - free(r->ds.root); + g_free(r->ds.root); pdb_reader_ds_exit(r); } diff --git a/contrib/elf2dmp/qemu_elf.c b/contrib/elf2dmp/qemu_elf.c index de6ad744c6..055e6f8792 100644 --- a/contrib/elf2dmp/qemu_elf.c +++ b/contrib/elf2dmp/qemu_elf.c @@ -94,10 +94,7 @@ static int init_states(QEMU_Elf *qe) printf("%zu CPU states has been found\n", cpu_nr); - qe->state = malloc(sizeof(*qe->state) * cpu_nr); - if (!qe->state) { - return 1; - } + qe->state = g_new(QEMUCPUState*, cpu_nr); cpu_nr = 0; @@ -115,7 +112,7 @@ static int init_states(QEMU_Elf *qe) static void exit_states(QEMU_Elf *qe) { - free(qe->state); + g_free(qe->state); } static bool check_ehdr(QEMU_Elf *qe) From dfd3bb0a99ae9627b4cc9b310ecef1b214188f71 Mon Sep 17 00:00:00 2001 From: Akihiko Odaki Date: Thu, 5 Oct 2023 15:47:25 +0900 Subject: [PATCH 0833/1077] cutils: Fix get_relocated_path on Windows MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit get_relocated_path() did not have error handling for PathCchSkipRoot() because a path given to get_relocated_path() was expected to be a valid path containing a drive letter or UNC server/share path elements on Windows, but sometimes it turned out otherwise. The paths passed to get_relocated_path() are defined by macros generated by Meson. Meson in turn uses a prefix given by the configure script to generate them. For Windows, the script passes /qemu as a prefix to Meson by default. As documented in docs/about/build-platforms.rst, typically MSYS2 is used for the build system, but it is also possible to use Linux as well. When MSYS2 is used, its Bash variant recognizes /qemu as a MSYS2 path, and converts it to a Windows path, adding the MSYS2 prefix including a drive letter or UNC server/share path elements. Such a conversion does not happen on a shell on Linux however, and /qemu will be passed as is in the case. Implement a proper error handling of PathCchSkipRoot() in get_relocated_path() so that it can handle a path without a drive letter or UNC server/share path elements. Reported-by: Stefan Weil Signed-off-by: Akihiko Odaki Reviewed-by: Philippe Mathieu-Daudé Message-ID: <20231005064726.6945-1-akihiko.odaki@daynix.com> Signed-off-by: Philippe Mathieu-Daudé --- util/cutils.c | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/util/cutils.c b/util/cutils.c index 64f817b477..42364039a5 100644 --- a/util/cutils.c +++ b/util/cutils.c @@ -1163,17 +1163,21 @@ char *get_relocated_path(const char *dir) g_string_append(result, "/qemu-bundle"); if (access(result->str, R_OK) == 0) { #ifdef G_OS_WIN32 - size_t size = mbsrtowcs(NULL, &dir, 0, &(mbstate_t){0}) + 1; + const char *src = dir; + size_t size = mbsrtowcs(NULL, &src, 0, &(mbstate_t){0}) + 1; PWSTR wdir = g_new(WCHAR, size); - mbsrtowcs(wdir, &dir, size, &(mbstate_t){0}); + mbsrtowcs(wdir, &src, size, &(mbstate_t){0}); PCWSTR wdir_skipped_root; - PathCchSkipRoot(wdir, &wdir_skipped_root); + if (PathCchSkipRoot(wdir, &wdir_skipped_root) == S_OK) { + size = wcsrtombs(NULL, &wdir_skipped_root, 0, &(mbstate_t){0}); + char *cursor = result->str + result->len; + g_string_set_size(result, result->len + size); + wcsrtombs(cursor, &wdir_skipped_root, size + 1, &(mbstate_t){0}); + } else { + g_string_append(result, dir); + } - size = wcsrtombs(NULL, &wdir_skipped_root, 0, &(mbstate_t){0}); - char *cursor = result->str + result->len; - g_string_set_size(result, result->len + size); - wcsrtombs(cursor, &wdir_skipped_root, size + 1, &(mbstate_t){0}); g_free(wdir); #else g_string_append(result, dir); From da6f5544ce0ba351ffaeeac1c0c900d808774ad5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Mon, 9 Oct 2023 08:51:29 +0200 Subject: [PATCH 0834/1077] buildsys: Only display Objective-C information when Objective-C is used MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When configuring with '--disable-cocoa --disable-coreaudio' on Darwin, we get: meson.build:4081:58: ERROR: Tried to access compiler for language "objc", not specified for host machine. meson.build:4097:47: ERROR: Tried to access unknown option 'objc_args'. Instead of unconditionally display Objective-C informations on Darwin, display them when Objective-C is discovered. Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Akihiko Odaki Message-Id: <20231009093812.52915-1-philmd@linaro.org> --- meson.build | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/meson.build b/meson.build index 259dc5f308..4961c82a6b 100644 --- a/meson.build +++ b/meson.build @@ -4087,8 +4087,10 @@ if 'cpp' in all_languages else summary_info += {'C++ compiler': false} endif -if targetos == 'darwin' +if 'objc' in all_languages summary_info += {'Objective-C compiler': ' '.join(meson.get_compiler('objc').cmd_array())} +else + summary_info += {'Objective-C compiler': false} endif option_cflags = (get_option('debug') ? ['-g'] : []) if get_option('optimization') != 'plain' @@ -4098,7 +4100,7 @@ summary_info += {'CFLAGS': ' '.join(get_option('c_args') + option_cfl if 'cpp' in all_languages summary_info += {'CXXFLAGS': ' '.join(get_option('cpp_args') + option_cflags)} endif -if targetos == 'darwin' +if 'objc' in all_languages summary_info += {'OBJCFLAGS': ' '.join(get_option('objc_args') + option_cflags)} endif link_args = get_option('c_link_args') From 47538e44d6e7a3aa04873d84cf620345fd29a366 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= Date: Mon, 9 Oct 2023 11:52:31 +0400 Subject: [PATCH 0835/1077] memory: drop needless argument MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The argument is unused since commit bdc44640c ("cpu: Use QTAILQ for CPU list"). Signed-off-by: Marc-André Lureau Reviewed-by: David Hildenbrand Reviewed-by: Philippe Mathieu-Daudé Message-ID: <20231009075231.150568-1-marcandre.lureau@redhat.com> Signed-off-by: Philippe Mathieu-Daudé --- system/memory_mapping.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/system/memory_mapping.c b/system/memory_mapping.c index d7f1d096e0..8ba9968f8c 100644 --- a/system/memory_mapping.c +++ b/system/memory_mapping.c @@ -291,7 +291,7 @@ void guest_phys_blocks_append(GuestPhysBlockList *list) memory_listener_unregister(&g.listener); } -static CPUState *find_paging_enabled_cpu(CPUState *start_cpu) +static CPUState *find_paging_enabled_cpu(void) { CPUState *cpu; @@ -312,7 +312,7 @@ void qemu_get_guest_memory_mapping(MemoryMappingList *list, GuestPhysBlock *block; ram_addr_t offset, length; - first_paging_enabled_cpu = find_paging_enabled_cpu(first_cpu); + first_paging_enabled_cpu = find_paging_enabled_cpu(); if (first_paging_enabled_cpu) { for (cpu = first_paging_enabled_cpu; cpu != NULL; cpu = CPU_NEXT(cpu)) { From 8a5b974b981725019c31faa156c36d8141517e15 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= Date: Mon, 9 Oct 2023 11:53:10 +0400 Subject: [PATCH 0836/1077] memory: follow Error API guidelines MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Return true/false on success/failure. Signed-off-by: Marc-André Lureau Reviewed-by: David Hildenbrand Reviewed-by: Philippe Mathieu-Daudé Message-ID: <20231009075310.153617-1-marcandre.lureau@redhat.com> Signed-off-by: Philippe Mathieu-Daudé --- hw/core/cpu-sysemu.c | 6 +++--- include/hw/core/cpu.h | 4 +++- include/hw/core/sysemu-cpu-ops.h | 2 +- include/sysemu/memory_mapping.h | 2 +- system/memory_mapping.c | 13 ++++++------- target/i386/arch_memory_mapping.c | 6 ++++-- target/i386/cpu.h | 2 +- 7 files changed, 19 insertions(+), 16 deletions(-) diff --git a/hw/core/cpu-sysemu.c b/hw/core/cpu-sysemu.c index 5eaf2e79e6..d0d6a910f9 100644 --- a/hw/core/cpu-sysemu.c +++ b/hw/core/cpu-sysemu.c @@ -34,17 +34,17 @@ bool cpu_paging_enabled(const CPUState *cpu) return false; } -void cpu_get_memory_mapping(CPUState *cpu, MemoryMappingList *list, +bool cpu_get_memory_mapping(CPUState *cpu, MemoryMappingList *list, Error **errp) { CPUClass *cc = CPU_GET_CLASS(cpu); if (cc->sysemu_ops->get_memory_mapping) { - cc->sysemu_ops->get_memory_mapping(cpu, list, errp); - return; + return cc->sysemu_ops->get_memory_mapping(cpu, list, errp); } error_setg(errp, "Obtaining memory mappings is unsupported on this CPU."); + return false; } hwaddr cpu_get_phys_page_attrs_debug(CPUState *cpu, vaddr addr, diff --git a/include/hw/core/cpu.h b/include/hw/core/cpu.h index 3968369554..18593db5b2 100644 --- a/include/hw/core/cpu.h +++ b/include/hw/core/cpu.h @@ -618,8 +618,10 @@ bool cpu_paging_enabled(const CPUState *cpu); * @cpu: The CPU whose memory mappings are to be obtained. * @list: Where to write the memory mappings to. * @errp: Pointer for reporting an #Error. + * + * Returns: %true on success, %false otherwise. */ -void cpu_get_memory_mapping(CPUState *cpu, MemoryMappingList *list, +bool cpu_get_memory_mapping(CPUState *cpu, MemoryMappingList *list, Error **errp); #if !defined(CONFIG_USER_ONLY) diff --git a/include/hw/core/sysemu-cpu-ops.h b/include/hw/core/sysemu-cpu-ops.h index ee169b872c..24d003fe04 100644 --- a/include/hw/core/sysemu-cpu-ops.h +++ b/include/hw/core/sysemu-cpu-ops.h @@ -19,7 +19,7 @@ typedef struct SysemuCPUOps { /** * @get_memory_mapping: Callback for obtaining the memory mappings. */ - void (*get_memory_mapping)(CPUState *cpu, MemoryMappingList *list, + bool (*get_memory_mapping)(CPUState *cpu, MemoryMappingList *list, Error **errp); /** * @get_paging_enabled: Callback for inquiring whether paging is enabled. diff --git a/include/sysemu/memory_mapping.h b/include/sysemu/memory_mapping.h index 3bbeb1bcb4..021e0a6230 100644 --- a/include/sysemu/memory_mapping.h +++ b/include/sysemu/memory_mapping.h @@ -71,7 +71,7 @@ void guest_phys_blocks_free(GuestPhysBlockList *list); void guest_phys_blocks_init(GuestPhysBlockList *list); void guest_phys_blocks_append(GuestPhysBlockList *list); -void qemu_get_guest_memory_mapping(MemoryMappingList *list, +bool qemu_get_guest_memory_mapping(MemoryMappingList *list, const GuestPhysBlockList *guest_phys_blocks, Error **errp); diff --git a/system/memory_mapping.c b/system/memory_mapping.c index 8ba9968f8c..6f884c5b90 100644 --- a/system/memory_mapping.c +++ b/system/memory_mapping.c @@ -304,10 +304,11 @@ static CPUState *find_paging_enabled_cpu(void) return NULL; } -void qemu_get_guest_memory_mapping(MemoryMappingList *list, +bool qemu_get_guest_memory_mapping(MemoryMappingList *list, const GuestPhysBlockList *guest_phys_blocks, Error **errp) { + ERRP_GUARD(); CPUState *cpu, *first_paging_enabled_cpu; GuestPhysBlock *block; ram_addr_t offset, length; @@ -316,14 +317,11 @@ void qemu_get_guest_memory_mapping(MemoryMappingList *list, if (first_paging_enabled_cpu) { for (cpu = first_paging_enabled_cpu; cpu != NULL; cpu = CPU_NEXT(cpu)) { - Error *err = NULL; - cpu_get_memory_mapping(cpu, list, &err); - if (err) { - error_propagate(errp, err); - return; + if (!cpu_get_memory_mapping(cpu, list, errp)) { + return false; } } - return; + return true; } /* @@ -335,6 +333,7 @@ void qemu_get_guest_memory_mapping(MemoryMappingList *list, length = block->target_end - block->target_start; create_new_memory_mapping(list, offset, offset, length); } + return true; } void qemu_get_guest_simple_memory_mapping(MemoryMappingList *list, diff --git a/target/i386/arch_memory_mapping.c b/target/i386/arch_memory_mapping.c index 271cb5e41b..d1ff659128 100644 --- a/target/i386/arch_memory_mapping.c +++ b/target/i386/arch_memory_mapping.c @@ -266,7 +266,7 @@ static void walk_pml5e(MemoryMappingList *list, AddressSpace *as, } #endif -void x86_cpu_get_memory_mapping(CPUState *cs, MemoryMappingList *list, +bool x86_cpu_get_memory_mapping(CPUState *cs, MemoryMappingList *list, Error **errp) { X86CPU *cpu = X86_CPU(cs); @@ -275,7 +275,7 @@ void x86_cpu_get_memory_mapping(CPUState *cs, MemoryMappingList *list, if (!cpu_paging_enabled(cs)) { /* paging is disabled */ - return; + return true; } a20_mask = x86_get_a20_mask(env); @@ -310,5 +310,7 @@ void x86_cpu_get_memory_mapping(CPUState *cs, MemoryMappingList *list, pse = !!(env->cr[4] & CR4_PSE_MASK); walk_pde2(list, cs->as, pde_addr, a20_mask, pse); } + + return true; } diff --git a/target/i386/cpu.h b/target/i386/cpu.h index e1875466b9..471e71dbc5 100644 --- a/target/i386/cpu.h +++ b/target/i386/cpu.h @@ -2055,7 +2055,7 @@ int x86_cpu_write_elf64_qemunote(WriteCoreDumpFunction f, CPUState *cpu, int x86_cpu_write_elf32_qemunote(WriteCoreDumpFunction f, CPUState *cpu, DumpState *s); -void x86_cpu_get_memory_mapping(CPUState *cpu, MemoryMappingList *list, +bool x86_cpu_get_memory_mapping(CPUState *cpu, MemoryMappingList *list, Error **errp); void x86_cpu_dump_state(CPUState *cs, FILE *f, int flags); From 946df4d500888c8ddad580b28fa72b138f106823 Mon Sep 17 00:00:00 2001 From: Lu Gao Date: Mon, 21 Mar 2022 13:56:18 +0800 Subject: [PATCH 0837/1077] hw/sd/sdhci: Block Size Register bits [14:12] is lost MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Block Size Register bits [14:12] is SDMA Buffer Boundary, it is missed in register write, but it is needed in SDMA transfer. e.g. it will be used in sdhci_sdma_transfer_multi_blocks to calculate boundary_ variables. Missing this field will cause wrong operation for different SDMA Buffer Boundary settings. Fixes: d7dfca0807 ("hw/sdhci: introduce standard SD host controller") Fixes: dfba99f17f ("hw/sdhci: Fix DMA Transfer Block Size field") Signed-off-by: Lu Gao Signed-off-by: Jianxian Wen Reviewed-by: Philippe Mathieu-Daudé Message-ID: <20220321055618.4026-1-lu.gao@verisilicon.com> Signed-off-by: Philippe Mathieu-Daudé --- hw/sd/sdhci.c | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/hw/sd/sdhci.c b/hw/sd/sdhci.c index 5564765a9b..40473b0db0 100644 --- a/hw/sd/sdhci.c +++ b/hw/sd/sdhci.c @@ -321,6 +321,8 @@ static void sdhci_poweron_reset(DeviceState *dev) static void sdhci_data_transfer(void *opaque); +#define BLOCK_SIZE_MASK (4 * KiB - 1) + static void sdhci_send_command(SDHCIState *s) { SDRequest request; @@ -371,7 +373,8 @@ static void sdhci_send_command(SDHCIState *s) sdhci_update_irq(s); - if (!timeout && s->blksize && (s->cmdreg & SDHC_CMD_DATA_PRESENT)) { + if (!timeout && (s->blksize & BLOCK_SIZE_MASK) && + (s->cmdreg & SDHC_CMD_DATA_PRESENT)) { s->data_count = 0; sdhci_data_transfer(s); } @@ -406,7 +409,6 @@ static void sdhci_end_transfer(SDHCIState *s) /* * Programmed i/o data transfer */ -#define BLOCK_SIZE_MASK (4 * KiB - 1) /* Fill host controller's read buffer with BLKSIZE bytes of data from card */ static void sdhci_read_block_from_card(SDHCIState *s) @@ -1154,7 +1156,8 @@ sdhci_write(void *opaque, hwaddr offset, uint64_t val, unsigned size) s->sdmasysad = (s->sdmasysad & mask) | value; MASKED_WRITE(s->sdmasysad, mask, value); /* Writing to last byte of sdmasysad might trigger transfer */ - if (!(mask & 0xFF000000) && s->blkcnt && s->blksize && + if (!(mask & 0xFF000000) && s->blkcnt && + (s->blksize & BLOCK_SIZE_MASK) && SDHC_DMA_TYPE(s->hostctl1) == SDHC_CTRL_SDMA) { if (s->trnmod & SDHC_TRNS_MULTI) { sdhci_sdma_transfer_multi_blocks(s); @@ -1168,7 +1171,11 @@ sdhci_write(void *opaque, hwaddr offset, uint64_t val, unsigned size) if (!TRANSFERRING_DATA(s->prnsts)) { uint16_t blksize = s->blksize; - MASKED_WRITE(s->blksize, mask, extract32(value, 0, 12)); + /* + * [14:12] SDMA Buffer Boundary + * [11:00] Transfer Block Size + */ + MASKED_WRITE(s->blksize, mask, extract32(value, 0, 15)); MASKED_WRITE(s->blkcnt, mask >> 16, value >> 16); /* Limit block size to the maximum buffer size */ From 9ce8c6ddd302d23df503e89e03544c5e832b4dc3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Mon, 9 Oct 2023 10:21:22 +0200 Subject: [PATCH 0838/1077] hw/mips/malta: Use sdram_type enum from 'hw/i2c/smbus_eeprom.h' MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Since commit 93198b6cad ("i2c: Split smbus into parts") the SDRAM types are enumerated as sdram_type in "hw/i2c/smbus_eeprom.h". Using the enum removes this global shadow warning: hw/mips/malta.c:209:12: error: declaration shadows a variable in the global scope [-Werror,-Wshadow] enum { SDR = 0x4, DDR2 = 0x8 } type; ^ include/hw/i2c/smbus_eeprom.h:33:19: note: previous declaration is here enum sdram_type { SDR = 0x4, DDR = 0x7, DDR2 = 0x8 }; ^ Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: BALATON Zoltan Reviewed-by: Richard Henderson Message-Id: <20231009092127.49778-1-philmd@linaro.org> --- hw/mips/malta.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/mips/malta.c b/hw/mips/malta.c index dac27fad9d..62d04ed113 100644 --- a/hw/mips/malta.c +++ b/hw/mips/malta.c @@ -206,7 +206,7 @@ static eeprom24c0x_t spd_eeprom = { static void generate_eeprom_spd(uint8_t *eeprom, ram_addr_t ram_size) { - enum { SDR = 0x4, DDR2 = 0x8 } type; + enum sdram_type type; uint8_t *spd = spd_eeprom.contents; uint8_t nbanks = 0; uint16_t density = 0; From deb1ef950bace69c204a9e9de3893fcff0e37fee Mon Sep 17 00:00:00 2001 From: Luc Michel Date: Fri, 29 Sep 2023 16:03:27 +0200 Subject: [PATCH 0839/1077] mailmap: update email addresses for Luc Michel MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Map my old and now invalid work email addresses to my personal one. Signed-off-by: Luc Michel Reviewed-by: Philippe Mathieu-Daudé Message-ID: <20230929140326.2056658-2-luc@lmichel.fr> Signed-off-by: Philippe Mathieu-Daudé --- .mailmap | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.mailmap b/.mailmap index d214959288..94f19a0ac9 100644 --- a/.mailmap +++ b/.mailmap @@ -81,6 +81,9 @@ Huacai Chen James Hogan Leif Lindholm Leif Lindholm +Luc Michel +Luc Michel +Luc Michel Radoslaw Biernacki Paul Brook Paul Burton From 30a8d3a14216e31f2539b00ff4e5df7f3a08ce89 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Mon, 9 Oct 2023 13:58:39 +0200 Subject: [PATCH 0840/1077] hw/mips: Merge 'hw/mips/cpudevs.h' with 'target/mips/cpu.h' MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit "hw/mips/cpudevs.h" contains declarations which are specific to the MIPS architecture; it doesn't make sense for these to be called from a non-MIPS architecture. Move the declarations to "target/mips/cpu.h". Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Richard Henderson Message-Id: <20231009171443.12145-2-philmd@linaro.org> --- hw/mips/cps.c | 1 - hw/mips/fuloong2e.c | 1 - hw/mips/jazz.c | 1 - hw/mips/loongson3_virt.c | 1 - hw/mips/malta.c | 1 - hw/mips/mips_int.c | 1 - hw/mips/mipssim.c | 1 - include/hw/mips/cpudevs.h | 14 -------------- target/mips/cpu.h | 4 +++- target/mips/sysemu/cp0_timer.c | 1 - target/mips/tcg/sysemu/tlb_helper.c | 1 - 11 files changed, 3 insertions(+), 24 deletions(-) delete mode 100644 include/hw/mips/cpudevs.h diff --git a/hw/mips/cps.c b/hw/mips/cps.c index 2b5269ebf1..b6612c1762 100644 --- a/hw/mips/cps.c +++ b/hw/mips/cps.c @@ -24,7 +24,6 @@ #include "hw/mips/mips.h" #include "hw/qdev-clock.h" #include "hw/qdev-properties.h" -#include "hw/mips/cpudevs.h" #include "sysemu/kvm.h" #include "sysemu/reset.h" diff --git a/hw/mips/fuloong2e.c b/hw/mips/fuloong2e.c index c6109633fe..97b2c8ed8e 100644 --- a/hw/mips/fuloong2e.c +++ b/hw/mips/fuloong2e.c @@ -30,7 +30,6 @@ #include "hw/block/flash.h" #include "hw/mips/mips.h" #include "hw/mips/bootloader.h" -#include "hw/mips/cpudevs.h" #include "hw/pci/pci.h" #include "hw/loader.h" #include "hw/ide/pci.h" diff --git a/hw/mips/jazz.c b/hw/mips/jazz.c index c32d2b0b0a..86dfe05ea8 100644 --- a/hw/mips/jazz.c +++ b/hw/mips/jazz.c @@ -26,7 +26,6 @@ #include "qemu/datadir.h" #include "hw/clock.h" #include "hw/mips/mips.h" -#include "hw/mips/cpudevs.h" #include "hw/intc/i8259.h" #include "hw/dma/i8257.h" #include "hw/char/serial.h" diff --git a/hw/mips/loongson3_virt.c b/hw/mips/loongson3_virt.c index b74b358874..33eae01eca 100644 --- a/hw/mips/loongson3_virt.c +++ b/hw/mips/loongson3_virt.c @@ -32,7 +32,6 @@ #include "hw/char/serial.h" #include "hw/intc/loongson_liointc.h" #include "hw/mips/mips.h" -#include "hw/mips/cpudevs.h" #include "hw/mips/fw_cfg.h" #include "hw/mips/loongson3_bootp.h" #include "hw/misc/unimp.h" diff --git a/hw/mips/malta.c b/hw/mips/malta.c index 62d04ed113..4fa5b33fd9 100644 --- a/hw/mips/malta.c +++ b/hw/mips/malta.c @@ -37,7 +37,6 @@ #include "hw/block/flash.h" #include "hw/mips/mips.h" #include "hw/mips/bootloader.h" -#include "hw/mips/cpudevs.h" #include "hw/pci/pci.h" #include "hw/pci/pci_bus.h" #include "qemu/log.h" diff --git a/hw/mips/mips_int.c b/hw/mips/mips_int.c index 73437cd90f..6c32e466a3 100644 --- a/hw/mips/mips_int.c +++ b/hw/mips/mips_int.c @@ -23,7 +23,6 @@ #include "qemu/osdep.h" #include "qemu/main-loop.h" #include "hw/irq.h" -#include "hw/mips/cpudevs.h" #include "sysemu/kvm.h" #include "kvm_mips.h" diff --git a/hw/mips/mipssim.c b/hw/mips/mipssim.c index 2f951f7fc6..4f743f37eb 100644 --- a/hw/mips/mipssim.c +++ b/hw/mips/mipssim.c @@ -30,7 +30,6 @@ #include "qemu/datadir.h" #include "hw/clock.h" #include "hw/mips/mips.h" -#include "hw/mips/cpudevs.h" #include "hw/char/serial.h" #include "hw/isa/isa.h" #include "net/net.h" diff --git a/include/hw/mips/cpudevs.h b/include/hw/mips/cpudevs.h deleted file mode 100644 index f7c9728fa9..0000000000 --- a/include/hw/mips/cpudevs.h +++ /dev/null @@ -1,14 +0,0 @@ -#ifndef HW_MIPS_CPUDEVS_H -#define HW_MIPS_CPUDEVS_H - -#include "target/mips/cpu-qom.h" - -/* Definitions for MIPS CPU internal devices. */ - -/* mips_int.c */ -void cpu_mips_irq_init_cpu(MIPSCPU *cpu); - -/* mips_timer.c */ -void cpu_mips_clock_init(MIPSCPU *cpu); - -#endif diff --git a/target/mips/cpu.h b/target/mips/cpu.h index 67f8e8b988..fb44defc93 100644 --- a/target/mips/cpu.h +++ b/target/mips/cpu.h @@ -1345,8 +1345,10 @@ uint64_t cpu_mips_phys_to_kseg1(void *opaque, uint64_t addr); #if !defined(CONFIG_USER_ONLY) -/* mips_int.c */ +/* HW declaration specific to the MIPS target */ void cpu_mips_soft_irq(CPUMIPSState *env, int irq, int level); +void cpu_mips_irq_init_cpu(MIPSCPU *cpu); +void cpu_mips_clock_init(MIPSCPU *cpu); /* mips_itu.c */ void itc_reconfigure(struct MIPSITUState *tag); diff --git a/target/mips/sysemu/cp0_timer.c b/target/mips/sysemu/cp0_timer.c index 9d2bcb0dea..62de502caa 100644 --- a/target/mips/sysemu/cp0_timer.c +++ b/target/mips/sysemu/cp0_timer.c @@ -22,7 +22,6 @@ #include "qemu/osdep.h" #include "hw/irq.h" -#include "hw/mips/cpudevs.h" #include "qemu/timer.h" #include "sysemu/kvm.h" #include "internal.h" diff --git a/target/mips/tcg/sysemu/tlb_helper.c b/target/mips/tcg/sysemu/tlb_helper.c index 7dbc2e24c4..4ede904800 100644 --- a/target/mips/tcg/sysemu/tlb_helper.c +++ b/target/mips/tcg/sysemu/tlb_helper.c @@ -24,7 +24,6 @@ #include "exec/exec-all.h" #include "exec/cpu_ldst.h" #include "exec/log.h" -#include "hw/mips/cpudevs.h" #include "exec/helper-proto.h" /* TLB management */ From 28900f9b2c23870915f8a5df90ae23af6a663965 Mon Sep 17 00:00:00 2001 From: BALATON Zoltan Date: Sun, 15 Oct 2023 16:15:17 +0200 Subject: [PATCH 0841/1077] MAINTAINERS: Split vt82c686 out of fuloong2e MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The VIA south bridges are now mostly used by other machines not just fuloong2e so split off into a separate section and take maintainership. Signed-off-by: BALATON Zoltan Message-ID: <20231015141517.219317456A7@zero.eik.bme.hu> Signed-off-by: Philippe Mathieu-Daudé --- MAINTAINERS | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/MAINTAINERS b/MAINTAINERS index 9bd4fe378d..5f7d8ed866 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1322,10 +1322,7 @@ M: Philippe Mathieu-Daudé R: Jiaxun Yang S: Odd Fixes F: hw/mips/fuloong2e.c -F: hw/isa/vt82c686.c F: hw/pci-host/bonito.c -F: hw/usb/vt82c686-uhci-pci.c -F: include/hw/isa/vt82c686.h F: include/hw/pci-host/bonito.h F: tests/avocado/machine_mips_fuloong2e.py @@ -2481,6 +2478,15 @@ S: Maintained F: hw/isa/piix4.c F: include/hw/southbridge/piix.h +VIA South Bridges (VT82C686B, VT8231) +M: BALATON Zoltan +M: Philippe Mathieu-Daudé +R: Jiaxun Yang +S: Maintained +F: hw/isa/vt82c686.c +F: hw/usb/vt82c686-uhci-pci.c +F: include/hw/isa/vt82c686.h + Firmware configuration (fw_cfg) M: Philippe Mathieu-Daudé R: Gerd Hoffmann From db646e830e58f611a112210972332711f9c28af9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Fri, 6 Oct 2023 09:15:34 +0200 Subject: [PATCH 0842/1077] hw/misc/mips_itu: Declare itc_reconfigure() in 'hw/misc/mips_itu.h' MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We already provide "hw/misc/mips_itu.h" to declare prototype related to MIPSITUState. Move itc_reconfigure() declaration there. Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Richard Henderson Message-Id: <20231009171443.12145-3-philmd@linaro.org> --- include/hw/misc/mips_itu.h | 2 ++ target/mips/cpu.h | 3 --- target/mips/tcg/sysemu/cp0_helper.c | 1 + 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/include/hw/misc/mips_itu.h b/include/hw/misc/mips_itu.h index 35218b2d14..a413789151 100644 --- a/include/hw/misc/mips_itu.h +++ b/include/hw/misc/mips_itu.h @@ -79,4 +79,6 @@ struct MIPSITUState { /* Get ITC Configuration Tag memory region. */ MemoryRegion *mips_itu_get_tag_region(MIPSITUState *itu); +void itc_reconfigure(struct MIPSITUState *tag); + #endif /* MIPS_ITU_H */ diff --git a/target/mips/cpu.h b/target/mips/cpu.h index fb44defc93..5fddceff3a 100644 --- a/target/mips/cpu.h +++ b/target/mips/cpu.h @@ -1350,9 +1350,6 @@ void cpu_mips_soft_irq(CPUMIPSState *env, int irq, int level); void cpu_mips_irq_init_cpu(MIPSCPU *cpu); void cpu_mips_clock_init(MIPSCPU *cpu); -/* mips_itu.c */ -void itc_reconfigure(struct MIPSITUState *tag); - #endif /* !CONFIG_USER_ONLY */ /* helper.c */ diff --git a/target/mips/tcg/sysemu/cp0_helper.c b/target/mips/tcg/sysemu/cp0_helper.c index 5da1124589..d349548743 100644 --- a/target/mips/tcg/sysemu/cp0_helper.c +++ b/target/mips/tcg/sysemu/cp0_helper.c @@ -28,6 +28,7 @@ #include "qemu/host-utils.h" #include "exec/helper-proto.h" #include "exec/exec-all.h" +#include "hw/misc/mips_itu.h" /* SMP helpers. */ From 8db0760354eb0bab5005dd0d9115cc6650033326 Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Tue, 17 Oct 2023 17:19:33 +0200 Subject: [PATCH 0843/1077] MAINTAINERS: Add hw/input/lasips2.c to the HPPA machine section MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit hw/input/lasips2.c and the corresponding header include/hw/input/lasips2.h are only used by the HPPA machine, so add them to the corresponding section in the MAINTAINERS file. Signed-off-by: Thomas Huth Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Mark Cave-Ayland Message-ID: <20231017151933.213780-1-thuth@redhat.com> Signed-off-by: Philippe Mathieu-Daudé --- MAINTAINERS | 2 ++ 1 file changed, 2 insertions(+) diff --git a/MAINTAINERS b/MAINTAINERS index 5f7d8ed866..29b350f819 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1179,9 +1179,11 @@ R: Helge Deller S: Odd Fixes F: configs/devices/hppa-softmmu/default.mak F: hw/hppa/ +F: hw/input/lasips2.c F: hw/net/*i82596* F: hw/misc/lasi.c F: hw/pci-host/dino.c +F: include/hw/input/lasips2.h F: include/hw/misc/lasi.h F: include/hw/net/lasi_82596.h F: include/hw/pci-host/dino.h From 53af33a5b4e799d92e6687984349a098c3d37732 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Mon, 18 Sep 2023 07:25:49 +0200 Subject: [PATCH 0844/1077] hw/misc/mips_itu: Make MIPSITUState target agnostic MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When prototyping a heterogenous machine including the ITU, we get: include/hw/misc/mips_itu.h:76:5: error: unknown type name 'MIPSCPU' MIPSCPU *cpu0; ^ MIPSCPU is declared in the target specific "cpu.h" header, but we don't want to include it, because "cpu.h" is target specific and its inclusion taints all files including "mips_itu.h", which become target specific too. We can however use the 'ArchCPU *' type in the public header. By keeping the TYPE_MIPS_CPU QOM type check in the link property declaration, QOM core code will still check the property is a correct MIPS CPU. TYPE_MIPS_ITU is still built per-(MIPS)target, but its header can now be included by other targets. Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Richard Henderson Message-Id: <20231009171443.12145-4-philmd@linaro.org> --- hw/misc/mips_itu.c | 4 ++-- include/hw/misc/mips_itu.h | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/hw/misc/mips_itu.c b/hw/misc/mips_itu.c index 0eda302db4..5a83ccc4e8 100644 --- a/hw/misc/mips_itu.c +++ b/hw/misc/mips_itu.c @@ -532,7 +532,7 @@ static void mips_itu_realize(DeviceState *dev, Error **errp) return; } - env = &s->cpu0->env; + env = &MIPS_CPU(s->cpu0)->env; if (env->saarp) { s->saar = env->CP0_SAAR; } @@ -563,7 +563,7 @@ static Property mips_itu_properties[] = { ITC_FIFO_NUM_MAX), DEFINE_PROP_UINT32("num-semaphores", MIPSITUState, num_semaphores, ITC_SEMAPH_NUM_MAX), - DEFINE_PROP_LINK("cpu[0]", MIPSITUState, cpu0, TYPE_MIPS_CPU, MIPSCPU *), + DEFINE_PROP_LINK("cpu[0]", MIPSITUState, cpu0, TYPE_MIPS_CPU, ArchCPU *), DEFINE_PROP_END_OF_LIST(), }; diff --git a/include/hw/misc/mips_itu.h b/include/hw/misc/mips_itu.h index a413789151..5caed6cc36 100644 --- a/include/hw/misc/mips_itu.h +++ b/include/hw/misc/mips_itu.h @@ -73,7 +73,7 @@ struct MIPSITUState { /* SAAR */ uint64_t *saar; - MIPSCPU *cpu0; + ArchCPU *cpu0; }; /* Get ITC Configuration Tag memory region. */ From b5b47424b4676cbbc6c1bd8dbe8409c4c0124a8e Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Tue, 17 Oct 2023 17:33:45 +0200 Subject: [PATCH 0845/1077] MAINTAINERS: Add include/hw/intc/loongson_liointc.h to the Loongson-3 virt section MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The corresponding .c file is already listed here, so we should mention the header here, too. Signed-off-by: Thomas Huth Reviewed-by: Philippe Mathieu-Daudé Acked-by: Song Gao Message-ID: <20231017153345.233807-1-thuth@redhat.com> Signed-off-by: Philippe Mathieu-Daudé --- MAINTAINERS | 1 + 1 file changed, 1 insertion(+) diff --git a/MAINTAINERS b/MAINTAINERS index 29b350f819..91ca93328a 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1336,6 +1336,7 @@ F: hw/intc/loongson_liointc.c F: hw/mips/loongson3_bootp.c F: hw/mips/loongson3_bootp.h F: hw/mips/loongson3_virt.c +F: include/hw/intc/loongson_liointc.h F: tests/avocado/machine_mips_loongson3v.py Boston From bf9e5c1f22f6b4995672b72dd96bb363317fe574 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Thu, 12 Oct 2023 04:51:12 +0200 Subject: [PATCH 0846/1077] hw/pci-host/sh_pcic: Declare CPU QOM types using DEFINE_TYPES() macro MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When multiple QOM types are registered in the same file, it is simpler to use the the DEFINE_TYPES() macro. In particular because type array declared with such macro are easier to review. Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Yoshinori Sato Message-Id: <20231012041237.22281-2-philmd@linaro.org> --- hw/pci-host/sh_pci.c | 40 +++++++++++++++++----------------------- 1 file changed, 17 insertions(+), 23 deletions(-) diff --git a/hw/pci-host/sh_pci.c b/hw/pci-host/sh_pci.c index 77e7bbc65f..41aed48c85 100644 --- a/hw/pci-host/sh_pci.c +++ b/hw/pci-host/sh_pci.c @@ -167,17 +167,6 @@ static void sh_pci_host_class_init(ObjectClass *klass, void *data) dc->user_creatable = false; } -static const TypeInfo sh_pci_host_info = { - .name = "sh_pci_host", - .parent = TYPE_PCI_DEVICE, - .instance_size = sizeof(PCIDevice), - .class_init = sh_pci_host_class_init, - .interfaces = (InterfaceInfo[]) { - { INTERFACE_CONVENTIONAL_PCI_DEVICE }, - { }, - }, -}; - static void sh_pci_device_class_init(ObjectClass *klass, void *data) { DeviceClass *dc = DEVICE_CLASS(klass); @@ -185,17 +174,22 @@ static void sh_pci_device_class_init(ObjectClass *klass, void *data) dc->realize = sh_pci_device_realize; } -static const TypeInfo sh_pci_device_info = { - .name = TYPE_SH_PCI_HOST_BRIDGE, - .parent = TYPE_PCI_HOST_BRIDGE, - .instance_size = sizeof(SHPCIState), - .class_init = sh_pci_device_class_init, +static const TypeInfo sh_pcic_types[] = { + { + .name = TYPE_SH_PCI_HOST_BRIDGE, + .parent = TYPE_PCI_HOST_BRIDGE, + .instance_size = sizeof(SHPCIState), + .class_init = sh_pci_device_class_init, + }, { + .name = "sh_pci_host", + .parent = TYPE_PCI_DEVICE, + .instance_size = sizeof(PCIDevice), + .class_init = sh_pci_host_class_init, + .interfaces = (InterfaceInfo[]) { + { INTERFACE_CONVENTIONAL_PCI_DEVICE }, + { }, + }, + }, }; -static void sh_pci_register_types(void) -{ - type_register_static(&sh_pci_device_info); - type_register_static(&sh_pci_host_info); -} - -type_init(sh_pci_register_types) +DEFINE_TYPES(sh_pcic_types) From e257b8ca49388a0ad1728b4dfcd04803d694db77 Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Tue, 17 Oct 2023 17:42:42 +0200 Subject: [PATCH 0847/1077] MAINTAINERS: Add include/hw/openrisc/ to the OpenRISC section MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit hw/openrisc/ is already listed here, so we should mention the folder for the headers here, too. Signed-off-by: Thomas Huth Reviewed-by: Philippe Mathieu-Daudé Message-ID: <20231017154242.234133-1-thuth@redhat.com> Signed-off-by: Philippe Mathieu-Daudé --- MAINTAINERS | 1 + 1 file changed, 1 insertion(+) diff --git a/MAINTAINERS b/MAINTAINERS index 91ca93328a..fe11c98669 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -295,6 +295,7 @@ S: Odd Fixes F: docs/system/openrisc/cpu-features.rst F: target/openrisc/ F: hw/openrisc/ +F: include/hw/openrisc/ F: tests/tcg/openrisc/ PowerPC TCG CPUs From 6db7f62b34150162b76be5b9f54caa89af0f6c7d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Thu, 12 Oct 2023 04:53:19 +0200 Subject: [PATCH 0848/1077] hw/pci-host/sh_pcic: Correct PCI host / devfn#0 function names MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Host bridge device and PCI function #0 are inverted. Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Yoshinori Sato Message-Id: <20231012041237.22281-3-philmd@linaro.org> --- hw/pci-host/sh_pci.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/hw/pci-host/sh_pci.c b/hw/pci-host/sh_pci.c index 41aed48c85..580e273d96 100644 --- a/hw/pci-host/sh_pci.c +++ b/hw/pci-host/sh_pci.c @@ -116,7 +116,7 @@ static void sh_pci_set_irq(void *opaque, int irq_num, int level) qemu_set_irq(pic[irq_num], level); } -static void sh_pci_device_realize(DeviceState *dev, Error **errp) +static void sh_pcic_host_realize(DeviceState *dev, Error **errp) { SysBusDevice *sbd = SYS_BUS_DEVICE(dev); SHPCIState *s = SH_PCI_HOST_BRIDGE(dev); @@ -145,19 +145,19 @@ static void sh_pci_device_realize(DeviceState *dev, Error **errp) s->dev = pci_create_simple(phb->bus, PCI_DEVFN(0, 0), "sh_pci_host"); } -static void sh_pci_host_realize(PCIDevice *d, Error **errp) +static void sh_pcic_pci_realize(PCIDevice *d, Error **errp) { pci_set_word(d->config + PCI_COMMAND, PCI_COMMAND_WAIT); pci_set_word(d->config + PCI_STATUS, PCI_STATUS_CAP_LIST | PCI_STATUS_FAST_BACK | PCI_STATUS_DEVSEL_MEDIUM); } -static void sh_pci_host_class_init(ObjectClass *klass, void *data) +static void sh_pcic_pci_class_init(ObjectClass *klass, void *data) { PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); DeviceClass *dc = DEVICE_CLASS(klass); - k->realize = sh_pci_host_realize; + k->realize = sh_pcic_pci_realize; k->vendor_id = PCI_VENDOR_ID_HITACHI; k->device_id = PCI_DEVICE_ID_HITACHI_SH7751R; /* @@ -167,11 +167,11 @@ static void sh_pci_host_class_init(ObjectClass *klass, void *data) dc->user_creatable = false; } -static void sh_pci_device_class_init(ObjectClass *klass, void *data) +static void sh_pcic_host_class_init(ObjectClass *klass, void *data) { DeviceClass *dc = DEVICE_CLASS(klass); - dc->realize = sh_pci_device_realize; + dc->realize = sh_pcic_host_realize; } static const TypeInfo sh_pcic_types[] = { @@ -179,12 +179,12 @@ static const TypeInfo sh_pcic_types[] = { .name = TYPE_SH_PCI_HOST_BRIDGE, .parent = TYPE_PCI_HOST_BRIDGE, .instance_size = sizeof(SHPCIState), - .class_init = sh_pci_device_class_init, + .class_init = sh_pcic_host_class_init, }, { .name = "sh_pci_host", .parent = TYPE_PCI_DEVICE, .instance_size = sizeof(PCIDevice), - .class_init = sh_pci_host_class_init, + .class_init = sh_pcic_pci_class_init, .interfaces = (InterfaceInfo[]) { { INTERFACE_CONVENTIONAL_PCI_DEVICE }, { }, From f158d3befe25bef38a2ff364318076466c47a114 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Thu, 12 Oct 2023 04:56:17 +0200 Subject: [PATCH 0849/1077] hw/pci-host/sh_pcic: Replace magic value by proper definition MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Yoshinori Sato Message-Id: <20231012041237.22281-4-philmd@linaro.org> --- hw/pci-host/sh_pci.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/hw/pci-host/sh_pci.c b/hw/pci-host/sh_pci.c index 580e273d96..4edebced5e 100644 --- a/hw/pci-host/sh_pci.c +++ b/hw/pci-host/sh_pci.c @@ -40,7 +40,7 @@ struct SHPCIState { PCIHostState parent_obj; PCIDevice *dev; - qemu_irq irq[4]; + qemu_irq irq[PCI_NUM_PINS]; MemoryRegion memconfig_p4; MemoryRegion memconfig_a7; MemoryRegion isa; @@ -131,7 +131,8 @@ static void sh_pcic_host_realize(DeviceState *dev, Error **errp) s->irq, get_system_memory(), get_system_io(), - PCI_DEVFN(0, 0), 4, TYPE_PCI_BUS); + PCI_DEVFN(0, 0), PCI_NUM_PINS, + TYPE_PCI_BUS); memory_region_init_io(&s->memconfig_p4, OBJECT(s), &sh_pci_reg_ops, s, "sh_pci", 0x224); memory_region_init_alias(&s->memconfig_a7, OBJECT(s), "sh_pci.2", From 4aa07e864911b77dc7fb4704554bb041776b8ec7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Wed, 11 Oct 2023 15:30:35 +0200 Subject: [PATCH 0850/1077] hw/sparc64/ebus: Access memory regions via pci_address_space_io() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit PCI functions are plugged on a PCI bus. They can only access external memory regions via the bus. Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Mark Cave-Ayland Message-Id: <20231011185954.10337-5-philmd@linaro.org> --- hw/sparc64/sun4u.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/hw/sparc64/sun4u.c b/hw/sparc64/sun4u.c index d908a38f73..c871170378 100644 --- a/hw/sparc64/sun4u.c +++ b/hw/sparc64/sun4u.c @@ -360,11 +360,11 @@ static void ebus_realize(PCIDevice *pci_dev, Error **errp) pci_dev->config[0x09] = 0x00; // programming i/f pci_dev->config[0x0D] = 0x0a; // latency_timer - memory_region_init_alias(&s->bar0, OBJECT(s), "bar0", get_system_io(), - 0, 0x1000000); + memory_region_init_alias(&s->bar0, OBJECT(s), "bar0", + pci_address_space_io(pci_dev), 0, 0x1000000); pci_register_bar(pci_dev, 0, PCI_BASE_ADDRESS_SPACE_MEMORY, &s->bar0); - memory_region_init_alias(&s->bar1, OBJECT(s), "bar1", get_system_io(), - 0, 0x8000); + memory_region_init_alias(&s->bar1, OBJECT(s), "bar1", + pci_address_space_io(pci_dev), 0, 0x8000); pci_register_bar(pci_dev, 1, PCI_BASE_ADDRESS_SPACE_IO, &s->bar1); } From 305ab2b9716551e486cbdcff111610a2cf8da095 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Mon, 9 Oct 2023 10:13:41 +0200 Subject: [PATCH 0851/1077] hw/acpi/pcihp: Clean up global variable shadowing in acpi_pcihp_init() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fix: hw/acpi/pcihp.c:499:36: error: declaration shadows a variable in the global scope [-Werror,-Wshadow] MemoryRegion *address_space_io, ^ include/exec/address-spaces.h:35:21: note: previous declaration is here extern AddressSpace address_space_io; ^ Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Ani Sinha Acked-by: Michael S. Tsirkin Message-Id: <20231010115048.11856-5-philmd@linaro.org> --- hw/acpi/pcihp.c | 5 ++--- include/hw/acpi/pcihp.h | 2 +- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/hw/acpi/pcihp.c b/hw/acpi/pcihp.c index cdd6f775a1..4f75c873e2 100644 --- a/hw/acpi/pcihp.c +++ b/hw/acpi/pcihp.c @@ -496,8 +496,7 @@ static const MemoryRegionOps acpi_pcihp_io_ops = { }; void acpi_pcihp_init(Object *owner, AcpiPciHpState *s, PCIBus *root_bus, - MemoryRegion *address_space_io, - uint16_t io_base) + MemoryRegion *io, uint16_t io_base) { s->io_len = ACPI_PCIHP_SIZE; s->io_base = io_base; @@ -506,7 +505,7 @@ void acpi_pcihp_init(Object *owner, AcpiPciHpState *s, PCIBus *root_bus, memory_region_init_io(&s->io, owner, &acpi_pcihp_io_ops, s, "acpi-pci-hotplug", s->io_len); - memory_region_add_subregion(address_space_io, s->io_base, &s->io); + memory_region_add_subregion(io, s->io_base, &s->io); object_property_add_uint16_ptr(owner, ACPI_PCIHP_IO_BASE_PROP, &s->io_base, OBJ_PROP_FLAG_READ); diff --git a/include/hw/acpi/pcihp.h b/include/hw/acpi/pcihp.h index ef59810c17..ac21a95913 100644 --- a/include/hw/acpi/pcihp.h +++ b/include/hw/acpi/pcihp.h @@ -56,7 +56,7 @@ typedef struct AcpiPciHpState { } AcpiPciHpState; void acpi_pcihp_init(Object *owner, AcpiPciHpState *, PCIBus *root, - MemoryRegion *address_space_io, uint16_t io_base); + MemoryRegion *io, uint16_t io_base); bool acpi_pcihp_is_hotpluggbale_bus(AcpiPciHpState *s, BusState *bus); void acpi_pcihp_device_pre_plug_cb(HotplugHandler *hotplug_dev, From 49909a0d0336fa682049544f284bbeda6f02c4ac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Mon, 9 Oct 2023 09:33:29 +0200 Subject: [PATCH 0852/1077] hw/pci: Clean up global variable shadowing of address_space_io variable MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fix: hw/pci/pci.c:504:54: error: declaration shadows a variable in the global scope [-Werror,-Wshadow] MemoryRegion *address_space_io, ^ hw/pci/pci.c:533:38: error: declaration shadows a variable in the global scope [-Werror,-Wshadow] MemoryRegion *address_space_io, ^ hw/pci/pci.c:543:40: error: declaration shadows a variable in the global scope [-Werror,-Wshadow] MemoryRegion *address_space_io, ^ hw/pci/pci.c:590:45: error: declaration shadows a variable in the global scope [-Werror,-Wshadow] MemoryRegion *address_space_io, ^ include/exec/address-spaces.h:35:21: note: previous declaration is here extern AddressSpace address_space_io; ^ Signed-off-by: Philippe Mathieu-Daudé Acked-by: Michael S. Tsirkin Message-Id: <20231010115048.11856-6-philmd@linaro.org> --- hw/pci/pci.c | 25 +++++++++---------------- include/hw/pci/pci.h | 9 +++------ 2 files changed, 12 insertions(+), 22 deletions(-) diff --git a/hw/pci/pci.c b/hw/pci/pci.c index b0d21bf43a..7d09e1a39d 100644 --- a/hw/pci/pci.c +++ b/hw/pci/pci.c @@ -500,15 +500,14 @@ bool pci_bus_bypass_iommu(PCIBus *bus) } static void pci_root_bus_internal_init(PCIBus *bus, DeviceState *parent, - MemoryRegion *address_space_mem, - MemoryRegion *address_space_io, + MemoryRegion *mem, MemoryRegion *io, uint8_t devfn_min) { assert(PCI_FUNC(devfn_min) == 0); bus->devfn_min = devfn_min; bus->slot_reserved_mask = 0x0; - bus->address_space_mem = address_space_mem; - bus->address_space_io = address_space_io; + bus->address_space_mem = mem; + bus->address_space_io = io; bus->flags |= PCI_BUS_IS_ROOT; /* host bridge */ @@ -529,25 +528,21 @@ bool pci_bus_is_express(const PCIBus *bus) void pci_root_bus_init(PCIBus *bus, size_t bus_size, DeviceState *parent, const char *name, - MemoryRegion *address_space_mem, - MemoryRegion *address_space_io, + MemoryRegion *mem, MemoryRegion *io, uint8_t devfn_min, const char *typename) { qbus_init(bus, bus_size, typename, parent, name); - pci_root_bus_internal_init(bus, parent, address_space_mem, - address_space_io, devfn_min); + pci_root_bus_internal_init(bus, parent, mem, io, devfn_min); } PCIBus *pci_root_bus_new(DeviceState *parent, const char *name, - MemoryRegion *address_space_mem, - MemoryRegion *address_space_io, + MemoryRegion *mem, MemoryRegion *io, uint8_t devfn_min, const char *typename) { PCIBus *bus; bus = PCI_BUS(qbus_new(typename, parent, name)); - pci_root_bus_internal_init(bus, parent, address_space_mem, - address_space_io, devfn_min); + pci_root_bus_internal_init(bus, parent, mem, io, devfn_min); return bus; } @@ -586,15 +581,13 @@ void pci_bus_irqs_cleanup(PCIBus *bus) PCIBus *pci_register_root_bus(DeviceState *parent, const char *name, pci_set_irq_fn set_irq, pci_map_irq_fn map_irq, void *irq_opaque, - MemoryRegion *address_space_mem, - MemoryRegion *address_space_io, + MemoryRegion *mem, MemoryRegion *io, uint8_t devfn_min, int nirq, const char *typename) { PCIBus *bus; - bus = pci_root_bus_new(parent, name, address_space_mem, - address_space_io, devfn_min, typename); + bus = pci_root_bus_new(parent, name, mem, io, devfn_min, typename); pci_bus_irqs(bus, set_irq, irq_opaque, nirq); pci_bus_map_irqs(bus, map_irq); return bus; diff --git a/include/hw/pci/pci.h b/include/hw/pci/pci.h index b70a0b95ff..ea5aff118b 100644 --- a/include/hw/pci/pci.h +++ b/include/hw/pci/pci.h @@ -279,12 +279,10 @@ bool pci_bus_is_express(const PCIBus *bus); void pci_root_bus_init(PCIBus *bus, size_t bus_size, DeviceState *parent, const char *name, - MemoryRegion *address_space_mem, - MemoryRegion *address_space_io, + MemoryRegion *mem, MemoryRegion *io, uint8_t devfn_min, const char *typename); PCIBus *pci_root_bus_new(DeviceState *parent, const char *name, - MemoryRegion *address_space_mem, - MemoryRegion *address_space_io, + MemoryRegion *mem, MemoryRegion *io, uint8_t devfn_min, const char *typename); void pci_root_bus_cleanup(PCIBus *bus); void pci_bus_irqs(PCIBus *bus, pci_set_irq_fn set_irq, @@ -304,8 +302,7 @@ int pci_swizzle_map_irq_fn(PCIDevice *pci_dev, int pin); PCIBus *pci_register_root_bus(DeviceState *parent, const char *name, pci_set_irq_fn set_irq, pci_map_irq_fn map_irq, void *irq_opaque, - MemoryRegion *address_space_mem, - MemoryRegion *address_space_io, + MemoryRegion *mem, MemoryRegion *io, uint8_t devfn_min, int nirq, const char *typename); void pci_unregister_root_bus(PCIBus *bus); From b2b5b09045e61798d5454f6b32721172d736c828 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Mon, 9 Oct 2023 10:25:58 +0200 Subject: [PATCH 0853/1077] hw/s390x: Clean up global variable shadowing in quiesce_powerdown_req() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fix: hw/s390x/sclpquiesce.c:90:22: error: declaration shadows a variable in the global scope [-Werror,-Wshadow] QuiesceNotifier *qn = container_of(n, QuiesceNotifier, notifier); ^ hw/s390x/sclpquiesce.c:86:3: note: previous declaration is here } qn; ^ Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Thomas Huth Reviewed-by: David Hildenbrand Message-Id: <20231010115048.11856-7-philmd@linaro.org> --- hw/s390x/sclpquiesce.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/hw/s390x/sclpquiesce.c b/hw/s390x/sclpquiesce.c index ce07b16884..a641089929 100644 --- a/hw/s390x/sclpquiesce.c +++ b/hw/s390x/sclpquiesce.c @@ -78,12 +78,10 @@ static const VMStateDescription vmstate_sclpquiesce = { } }; -typedef struct QuiesceNotifier QuiesceNotifier; - -static struct QuiesceNotifier { +typedef struct QuiesceNotifier { Notifier notifier; SCLPEvent *event; -} qn; +} QuiesceNotifier; static void quiesce_powerdown_req(Notifier *n, void *opaque) { @@ -97,6 +95,8 @@ static void quiesce_powerdown_req(Notifier *n, void *opaque) static int quiesce_init(SCLPEvent *event) { + static QuiesceNotifier qn; + qn.notifier.notify = quiesce_powerdown_req; qn.event = event; From 0459c141f8d9dc99274ca3cffe632a37a0575c9e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Tue, 3 Oct 2023 09:58:14 +0200 Subject: [PATCH 0854/1077] hw/intc/apic: Use ERRP_GUARD() in apic_common_realize() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit APICCommonClass::realize() is a DeviceRealize() handler which take an Error** parameter and can fail. Do not proceed further on failure. Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Peter Xu Message-Id: <20231003082728.83496-2-philmd@linaro.org> --- hw/intc/apic_common.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/hw/intc/apic_common.c b/hw/intc/apic_common.c index 68ad30e2f5..bccb4241c2 100644 --- a/hw/intc/apic_common.c +++ b/hw/intc/apic_common.c @@ -257,6 +257,7 @@ static const VMStateDescription vmstate_apic_common; static void apic_common_realize(DeviceState *dev, Error **errp) { + ERRP_GUARD(); APICCommonState *s = APIC_COMMON(dev); APICCommonClass *info; static DeviceState *vapic; @@ -267,6 +268,9 @@ static void apic_common_realize(DeviceState *dev, Error **errp) info = APIC_COMMON_GET_CLASS(s); info->realize(dev, errp); + if (*errp) { + return; + } /* Note: We need at least 1M to map the VAPIC option ROM */ if (!vapic && s->vapic_control & VAPIC_ENABLE_MASK && From 880e26074c271e88235b453107fdfd40b0940f7f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Thu, 19 Oct 2023 12:01:59 +0200 Subject: [PATCH 0855/1077] hw/ppc/spapr_vio: Realize SPAPR_VIO_BRIDGE device before accessing it MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit qbus_new() should not be called on unrealized device. Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Cédric Le Goater Reviewed-by: Thomas Huth Message-Id: <20231019131647.19690-2-philmd@linaro.org> --- hw/ppc/spapr_vio.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/hw/ppc/spapr_vio.c b/hw/ppc/spapr_vio.c index 9d4fec2c04..f8ef2b6fa8 100644 --- a/hw/ppc/spapr_vio.c +++ b/hw/ppc/spapr_vio.c @@ -574,13 +574,14 @@ SpaprVioBus *spapr_vio_bus_init(void) /* Create bridge device */ dev = qdev_new(TYPE_SPAPR_VIO_BRIDGE); - sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal); /* Create bus on bridge device */ qbus = qbus_new(TYPE_SPAPR_VIO_BUS, dev, "spapr-vio"); bus = SPAPR_VIO_BUS(qbus); bus->next_reg = SPAPR_VIO_REG_BASE; + sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal); + /* hcall-vio */ spapr_register_hypercall(H_VIO_SIGNAL, h_vio_signal); From 90ac3862ff59a31563f81915dcc709d1eec52cdb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Wed, 18 Oct 2023 09:45:43 +0200 Subject: [PATCH 0856/1077] hw/ppc/pnv_xscom: Rename pnv_xscom_realize(Error **) -> pnv_xscom_init() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit pnv_xscom_realize() is not used to *realize* QDev object, rename it as pnv_xscom_init(). The Error** argument is unused: remove it. Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Richard Henderson Reviewed-by: Thomas Huth Reviewed-by: LIU Zhiwei Reviewed-by: Cédric Le Goater Message-Id: <20231019131647.19690-3-philmd@linaro.org> --- hw/ppc/pnv.c | 18 +++--------------- hw/ppc/pnv_xscom.c | 2 +- include/hw/ppc/pnv_xscom.h | 2 +- 3 files changed, 5 insertions(+), 17 deletions(-) diff --git a/hw/ppc/pnv.c b/hw/ppc/pnv.c index eb54f93986..456631c9dc 100644 --- a/hw/ppc/pnv.c +++ b/hw/ppc/pnv.c @@ -1249,11 +1249,7 @@ static void pnv_chip_power8_realize(DeviceState *dev, Error **errp) assert(chip8->xics); /* XSCOM bridge is first */ - pnv_xscom_realize(chip, PNV_XSCOM_SIZE, &local_err); - if (local_err) { - error_propagate(errp, local_err); - return; - } + pnv_xscom_init(chip, PNV_XSCOM_SIZE); sysbus_mmio_map(SYS_BUS_DEVICE(chip), 0, PNV_XSCOM_BASE(chip)); pcc->parent_realize(dev, &local_err); @@ -1512,11 +1508,7 @@ static void pnv_chip_power9_realize(DeviceState *dev, Error **errp) Error *local_err = NULL; /* XSCOM bridge is first */ - pnv_xscom_realize(chip, PNV9_XSCOM_SIZE, &local_err); - if (local_err) { - error_propagate(errp, local_err); - return; - } + pnv_xscom_init(chip, PNV9_XSCOM_SIZE); sysbus_mmio_map(SYS_BUS_DEVICE(chip), 0, PNV9_XSCOM_BASE(chip)); pcc->parent_realize(dev, &local_err); @@ -1727,11 +1719,7 @@ static void pnv_chip_power10_realize(DeviceState *dev, Error **errp) Error *local_err = NULL; /* XSCOM bridge is first */ - pnv_xscom_realize(chip, PNV10_XSCOM_SIZE, &local_err); - if (local_err) { - error_propagate(errp, local_err); - return; - } + pnv_xscom_init(chip, PNV10_XSCOM_SIZE); sysbus_mmio_map(SYS_BUS_DEVICE(chip), 0, PNV10_XSCOM_BASE(chip)); pcc->parent_realize(dev, &local_err); diff --git a/hw/ppc/pnv_xscom.c b/hw/ppc/pnv_xscom.c index d820e05e40..af57b55863 100644 --- a/hw/ppc/pnv_xscom.c +++ b/hw/ppc/pnv_xscom.c @@ -221,7 +221,7 @@ const MemoryRegionOps pnv_xscom_ops = { .endianness = DEVICE_BIG_ENDIAN, }; -void pnv_xscom_realize(PnvChip *chip, uint64_t size, Error **errp) +void pnv_xscom_init(PnvChip *chip, uint64_t size) { SysBusDevice *sbd = SYS_BUS_DEVICE(chip); char *name; diff --git a/include/hw/ppc/pnv_xscom.h b/include/hw/ppc/pnv_xscom.h index 9bc6463547..41671001da 100644 --- a/include/hw/ppc/pnv_xscom.h +++ b/include/hw/ppc/pnv_xscom.h @@ -170,7 +170,7 @@ struct PnvXScomInterfaceClass { #define PNV10_XSCOM_PEC_PCI_BASE 0x8010800 /* index goes upwards ... */ #define PNV10_XSCOM_PEC_PCI_SIZE 0x200 -void pnv_xscom_realize(PnvChip *chip, uint64_t size, Error **errp); +void pnv_xscom_init(PnvChip *chip, uint64_t size); int pnv_dt_xscom(PnvChip *chip, void *fdt, int root_offset, uint64_t xscom_base, uint64_t xscom_size, const char *compat, int compat_size); From 326f7acb81fd75eb7cb5aaa49139b1586a94c624 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Wed, 18 Oct 2023 09:49:06 +0200 Subject: [PATCH 0857/1077] hw/ppc/pnv_xscom: Move sysbus_mmio_map() call within pnv_xscom_init() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In order to make the next commit trivial, move sysbus_init_mmio() calls just before the corresponding sysbus_mmio_map() calls. Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Richard Henderson Reviewed-by: Thomas Huth Reviewed-by: LIU Zhiwei Reviewed-by: Cédric Le Goater Message-Id: <20231019131647.19690-4-philmd@linaro.org> --- hw/ppc/pnv.c | 9 +++------ hw/ppc/pnv_xscom.c | 3 ++- include/hw/ppc/pnv_xscom.h | 2 +- 3 files changed, 6 insertions(+), 8 deletions(-) diff --git a/hw/ppc/pnv.c b/hw/ppc/pnv.c index 456631c9dc..10158f7684 100644 --- a/hw/ppc/pnv.c +++ b/hw/ppc/pnv.c @@ -1249,8 +1249,7 @@ static void pnv_chip_power8_realize(DeviceState *dev, Error **errp) assert(chip8->xics); /* XSCOM bridge is first */ - pnv_xscom_init(chip, PNV_XSCOM_SIZE); - sysbus_mmio_map(SYS_BUS_DEVICE(chip), 0, PNV_XSCOM_BASE(chip)); + pnv_xscom_init(chip, PNV_XSCOM_SIZE, PNV_XSCOM_BASE(chip)); pcc->parent_realize(dev, &local_err); if (local_err) { @@ -1508,8 +1507,7 @@ static void pnv_chip_power9_realize(DeviceState *dev, Error **errp) Error *local_err = NULL; /* XSCOM bridge is first */ - pnv_xscom_init(chip, PNV9_XSCOM_SIZE); - sysbus_mmio_map(SYS_BUS_DEVICE(chip), 0, PNV9_XSCOM_BASE(chip)); + pnv_xscom_init(chip, PNV9_XSCOM_SIZE, PNV9_XSCOM_BASE(chip)); pcc->parent_realize(dev, &local_err); if (local_err) { @@ -1719,8 +1717,7 @@ static void pnv_chip_power10_realize(DeviceState *dev, Error **errp) Error *local_err = NULL; /* XSCOM bridge is first */ - pnv_xscom_init(chip, PNV10_XSCOM_SIZE); - sysbus_mmio_map(SYS_BUS_DEVICE(chip), 0, PNV10_XSCOM_BASE(chip)); + pnv_xscom_init(chip, PNV10_XSCOM_SIZE, PNV10_XSCOM_BASE(chip)); pcc->parent_realize(dev, &local_err); if (local_err) { diff --git a/hw/ppc/pnv_xscom.c b/hw/ppc/pnv_xscom.c index af57b55863..cf892c9fe8 100644 --- a/hw/ppc/pnv_xscom.c +++ b/hw/ppc/pnv_xscom.c @@ -221,7 +221,7 @@ const MemoryRegionOps pnv_xscom_ops = { .endianness = DEVICE_BIG_ENDIAN, }; -void pnv_xscom_init(PnvChip *chip, uint64_t size) +void pnv_xscom_init(PnvChip *chip, uint64_t size, hwaddr addr) { SysBusDevice *sbd = SYS_BUS_DEVICE(chip); char *name; @@ -230,6 +230,7 @@ void pnv_xscom_init(PnvChip *chip, uint64_t size) memory_region_init_io(&chip->xscom_mmio, OBJECT(chip), &pnv_xscom_ops, chip, name, size); sysbus_init_mmio(sbd, &chip->xscom_mmio); + sysbus_mmio_map(sbd, 0, addr); memory_region_init(&chip->xscom, OBJECT(chip), name, size); address_space_init(&chip->xscom_as, &chip->xscom, name); diff --git a/include/hw/ppc/pnv_xscom.h b/include/hw/ppc/pnv_xscom.h index 41671001da..35b19610f7 100644 --- a/include/hw/ppc/pnv_xscom.h +++ b/include/hw/ppc/pnv_xscom.h @@ -170,7 +170,7 @@ struct PnvXScomInterfaceClass { #define PNV10_XSCOM_PEC_PCI_BASE 0x8010800 /* index goes upwards ... */ #define PNV10_XSCOM_PEC_PCI_SIZE 0x200 -void pnv_xscom_init(PnvChip *chip, uint64_t size); +void pnv_xscom_init(PnvChip *chip, uint64_t size, hwaddr addr); int pnv_dt_xscom(PnvChip *chip, void *fdt, int root_offset, uint64_t xscom_base, uint64_t xscom_size, const char *compat, int compat_size); From bddb677544986abed53fe9a538d207dbef8aff88 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Wed, 18 Oct 2023 09:53:43 +0200 Subject: [PATCH 0858/1077] hw/ppc/pnv_xscom: Do not use SysBus API to map local MMIO region MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit There is no point in exposing an internal MMIO region via SysBus and directly mapping it in the very same device. Just map it without using the SysBus API. Transformation done using the following coccinelle script: @@ expression sbdev; expression index; expression addr; expression subregion; @@ - sysbus_init_mmio(sbdev, subregion); ... when != sbdev - sysbus_mmio_map(sbdev, index, addr); + memory_region_add_subregion(get_system_memory(), addr, subregion); Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Richard Henderson Reviewed-by: Thomas Huth Reviewed-by: LIU Zhiwei Reviewed-by: Cédric Le Goater Message-Id: <20231019131647.19690-5-philmd@linaro.org> --- hw/ppc/pnv_xscom.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/hw/ppc/pnv_xscom.c b/hw/ppc/pnv_xscom.c index cf892c9fe8..805b1d0c87 100644 --- a/hw/ppc/pnv_xscom.c +++ b/hw/ppc/pnv_xscom.c @@ -223,14 +223,12 @@ const MemoryRegionOps pnv_xscom_ops = { void pnv_xscom_init(PnvChip *chip, uint64_t size, hwaddr addr) { - SysBusDevice *sbd = SYS_BUS_DEVICE(chip); char *name; name = g_strdup_printf("xscom-%x", chip->chip_id); memory_region_init_io(&chip->xscom_mmio, OBJECT(chip), &pnv_xscom_ops, chip, name, size); - sysbus_init_mmio(sbd, &chip->xscom_mmio); - sysbus_mmio_map(sbd, 0, addr); + memory_region_add_subregion(get_system_memory(), addr, &chip->xscom_mmio); memory_region_init(&chip->xscom, OBJECT(chip), name, size); address_space_init(&chip->xscom_as, &chip->xscom, name); From bf3b9754b7cd8ae493b186e8da2ab8d6d7145c77 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Wed, 18 Oct 2023 07:48:11 +0200 Subject: [PATCH 0859/1077] hw/ppc/pnv: Do not use SysBus API to map local MMIO region MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit There is no point in exposing an internal MMIO region via SysBus and directly mapping it in the very same device. Just map it without using the SysBus API. Transformation done using the following coccinelle script: @@ expression sbdev; expression index; expression addr; expression subregion; @@ - sysbus_init_mmio(sbdev, subregion); ... when != sbdev - sysbus_mmio_map(sbdev, index, addr); + memory_region_add_subregion(get_system_memory(), addr, subregion); Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Richard Henderson Reviewed-by: Thomas Huth Reviewed-by: LIU Zhiwei Reviewed-by: Cédric Le Goater Message-Id: <20231019131647.19690-6-philmd@linaro.org> --- hw/ppc/pnv.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/hw/ppc/pnv.c b/hw/ppc/pnv.c index 10158f7684..c0e34fffbc 100644 --- a/hw/ppc/pnv.c +++ b/hw/ppc/pnv.c @@ -1217,10 +1217,9 @@ static void pnv_chip_icp_realize(Pnv8Chip *chip8, Error **errp) name = g_strdup_printf("icp-%x", chip->chip_id); memory_region_init(&chip8->icp_mmio, OBJECT(chip), name, PNV_ICP_SIZE); - sysbus_init_mmio(SYS_BUS_DEVICE(chip), &chip8->icp_mmio); g_free(name); - - sysbus_mmio_map(SYS_BUS_DEVICE(chip), 1, PNV_ICP_BASE(chip)); + memory_region_add_subregion(get_system_memory(), PNV_ICP_BASE(chip), + &chip8->icp_mmio); /* Map the ICP registers for each thread */ for (i = 0; i < chip->nr_cores; i++) { From e061eed80263a3de929871098f01bd28fb758dfb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Wed, 18 Oct 2023 07:53:30 +0200 Subject: [PATCH 0860/1077] hw/intc/spapr_xive: Move sysbus_init_mmio() calls around MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In order to make the next commit trivial, move sysbus_init_mmio() calls just before the corresponding sysbus_mmio_map() calls. Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Richard Henderson Reviewed-by: Thomas Huth Reviewed-by: LIU Zhiwei Reviewed-by: Cédric Le Goater Message-Id: <20231019131647.19690-7-philmd@linaro.org> --- hw/intc/spapr_xive.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/hw/intc/spapr_xive.c b/hw/intc/spapr_xive.c index 7f701d414b..12057ffe5b 100644 --- a/hw/intc/spapr_xive.c +++ b/hw/intc/spapr_xive.c @@ -316,7 +316,6 @@ static void spapr_xive_realize(DeviceState *dev, Error **errp) if (!qdev_realize(DEVICE(xsrc), NULL, errp)) { return; } - sysbus_init_mmio(SYS_BUS_DEVICE(xive), &xsrc->esb_mmio); /* * Initialize the END ESB source @@ -328,7 +327,6 @@ static void spapr_xive_realize(DeviceState *dev, Error **errp) if (!qdev_realize(DEVICE(end_xsrc), NULL, errp)) { return; } - sysbus_init_mmio(SYS_BUS_DEVICE(xive), &end_xsrc->esb_mmio); /* Set the mapping address of the END ESB pages after the source ESBs */ xive->end_base = xive->vc_base + xive_source_esb_len(xsrc); @@ -347,14 +345,16 @@ static void spapr_xive_realize(DeviceState *dev, Error **errp) /* TIMA initialization */ memory_region_init_io(&xive->tm_mmio, OBJECT(xive), &spapr_xive_tm_ops, xive, "xive.tima", 4ull << TM_SHIFT); - sysbus_init_mmio(SYS_BUS_DEVICE(xive), &xive->tm_mmio); /* * Map all regions. These will be enabled or disabled at reset and * can also be overridden by KVM memory regions if active */ + sysbus_init_mmio(SYS_BUS_DEVICE(xive), &xsrc->esb_mmio); sysbus_mmio_map(SYS_BUS_DEVICE(xive), 0, xive->vc_base); + sysbus_init_mmio(SYS_BUS_DEVICE(xive), &end_xsrc->esb_mmio); sysbus_mmio_map(SYS_BUS_DEVICE(xive), 1, xive->end_base); + sysbus_init_mmio(SYS_BUS_DEVICE(xive), &xive->tm_mmio); sysbus_mmio_map(SYS_BUS_DEVICE(xive), 2, xive->tm_base); } From 6c9dcd8760092e455f86f6afb05d87ea827da8f3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Wed, 18 Oct 2023 07:53:54 +0200 Subject: [PATCH 0861/1077] hw/intc/spapr_xive: Do not use SysBus API to map local MMIO region MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit There is no point in exposing an internal MMIO region via SysBus and directly mapping it in the very same device. Just map it without using the SysBus API. Transformation done using the following coccinelle script: @@ expression sbdev; expression index; expression addr; expression subregion; @@ - sysbus_init_mmio(sbdev, subregion); ... when != sbdev - sysbus_mmio_map(sbdev, index, addr); + memory_region_add_subregion(get_system_memory(), addr, subregion); Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Richard Henderson Reviewed-by: Thomas Huth Reviewed-by: LIU Zhiwei Reviewed-by: Cédric Le Goater Message-Id: <20231019131647.19690-8-philmd@linaro.org> --- hw/intc/spapr_xive.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/hw/intc/spapr_xive.c b/hw/intc/spapr_xive.c index 12057ffe5b..199c261b07 100644 --- a/hw/intc/spapr_xive.c +++ b/hw/intc/spapr_xive.c @@ -350,12 +350,12 @@ static void spapr_xive_realize(DeviceState *dev, Error **errp) * Map all regions. These will be enabled or disabled at reset and * can also be overridden by KVM memory regions if active */ - sysbus_init_mmio(SYS_BUS_DEVICE(xive), &xsrc->esb_mmio); - sysbus_mmio_map(SYS_BUS_DEVICE(xive), 0, xive->vc_base); - sysbus_init_mmio(SYS_BUS_DEVICE(xive), &end_xsrc->esb_mmio); - sysbus_mmio_map(SYS_BUS_DEVICE(xive), 1, xive->end_base); - sysbus_init_mmio(SYS_BUS_DEVICE(xive), &xive->tm_mmio); - sysbus_mmio_map(SYS_BUS_DEVICE(xive), 2, xive->tm_base); + memory_region_add_subregion(get_system_memory(), xive->vc_base, + &xsrc->esb_mmio); + memory_region_add_subregion(get_system_memory(), xive->end_base, + &end_xsrc->esb_mmio); + memory_region_add_subregion(get_system_memory(), xive->tm_base, + &xive->tm_mmio); } static int spapr_xive_get_eas(XiveRouter *xrtr, uint8_t eas_blk, From 40f8214fcde40bab3ef6d1ab0b2353c7f8bc62aa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Mon, 16 Oct 2023 12:12:39 +0200 Subject: [PATCH 0862/1077] hw/audio/pcspk: Inline pcspk_init() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit pcspk_init() is a legacy init function, inline and remove it. Since the device is realized using &error_fatal, use the same error for setting the "pit" link. Reviewed-by: Mark Cave-Ayland Signed-off-by: Philippe Mathieu-Daudé Message-Id: <20231019073307.99608-1-philmd@linaro.org> --- hw/i386/pc.c | 4 +++- hw/isa/i82378.c | 5 ++++- hw/mips/jazz.c | 5 ++++- include/hw/audio/pcspk.h | 10 ---------- 4 files changed, 11 insertions(+), 13 deletions(-) diff --git a/hw/i386/pc.c b/hw/i386/pc.c index bb3854d1d0..f7ee638bec 100644 --- a/hw/i386/pc.c +++ b/hw/i386/pc.c @@ -1283,7 +1283,9 @@ void pc_basic_device_init(struct PCMachineState *pcms, /* connect PIT to output control line of the HPET */ qdev_connect_gpio_out(hpet, 0, qdev_get_gpio_in(DEVICE(pit), 0)); } - pcspk_init(pcms->pcspk, isa_bus, pit); + object_property_set_link(OBJECT(pcms->pcspk), "pit", + OBJECT(pit), &error_fatal); + isa_realize_and_unref(pcms->pcspk, isa_bus, &error_fatal); } /* Super I/O */ diff --git a/hw/isa/i82378.c b/hw/isa/i82378.c index 63e0857208..79ffbb52a0 100644 --- a/hw/isa/i82378.c +++ b/hw/isa/i82378.c @@ -67,6 +67,7 @@ static void i82378_realize(PCIDevice *pci, Error **errp) uint8_t *pci_conf; ISABus *isabus; ISADevice *pit; + ISADevice *pcspk; pci_conf = pci->config; pci_set_word(pci_conf + PCI_COMMAND, @@ -102,7 +103,9 @@ static void i82378_realize(PCIDevice *pci, Error **errp) pit = i8254_pit_init(isabus, 0x40, 0, NULL); /* speaker */ - pcspk_init(isa_new(TYPE_PC_SPEAKER), isabus, pit); + pcspk = isa_new(TYPE_PC_SPEAKER); + object_property_set_link(OBJECT(pcspk), "pit", OBJECT(pit), &error_fatal); + isa_realize_and_unref(pcspk, isabus, &error_fatal); /* 2 82C37 (dma) */ isa_create_simple(isabus, "i82374"); diff --git a/hw/mips/jazz.c b/hw/mips/jazz.c index 86dfe05ea8..d33a76ad4d 100644 --- a/hw/mips/jazz.c +++ b/hw/mips/jazz.c @@ -176,6 +176,7 @@ static void mips_jazz_init(MachineState *machine, SysBusDevice *sysbus; ISABus *isa_bus; ISADevice *pit; + ISADevice *pcspk; DriveInfo *fds[MAX_FD]; MemoryRegion *bios = g_new(MemoryRegion, 1); MemoryRegion *bios2 = g_new(MemoryRegion, 1); @@ -278,7 +279,9 @@ static void mips_jazz_init(MachineState *machine, isa_bus_register_input_irqs(isa_bus, i8259); i8257_dma_init(isa_bus, 0); pit = i8254_pit_init(isa_bus, 0x40, 0, NULL); - pcspk_init(isa_new(TYPE_PC_SPEAKER), isa_bus, pit); + pcspk = isa_new(TYPE_PC_SPEAKER); + object_property_set_link(OBJECT(pcspk), "pit", OBJECT(pit), &error_fatal); + isa_realize_and_unref(pcspk, isa_bus, &error_fatal); /* Video card */ switch (jazz_model) { diff --git a/include/hw/audio/pcspk.h b/include/hw/audio/pcspk.h index 9506179587..6be75a6b86 100644 --- a/include/hw/audio/pcspk.h +++ b/include/hw/audio/pcspk.h @@ -25,16 +25,6 @@ #ifndef HW_PCSPK_H #define HW_PCSPK_H -#include "hw/isa/isa.h" -#include "hw/qdev-properties.h" -#include "qapi/error.h" - #define TYPE_PC_SPEAKER "isa-pcspk" -static inline void pcspk_init(ISADevice *isadev, ISABus *bus, ISADevice *pit) -{ - object_property_set_link(OBJECT(isadev), "pit", OBJECT(pit), NULL); - isa_realize_and_unref(isadev, bus, &error_fatal); -} - #endif /* HW_PCSPK_H */ From 544f07f6394ab940021f3b512d8bb1b34380dcd6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Wed, 18 Oct 2023 07:50:20 +0200 Subject: [PATCH 0863/1077] hw/i386/amd_iommu: Do not use SysBus API to map local MMIO region MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit There is no point in exposing an internal MMIO region via SysBus and directly mapping it in the very same device. Just map it without using the SysBus API. Transformation done using the following coccinelle script: @@ expression sbdev; expression index; expression addr; expression subregion; @@ - sysbus_init_mmio(sbdev, subregion); ... when != sbdev - sysbus_mmio_map(sbdev, index, addr); + memory_region_add_subregion(get_system_memory(), addr, subregion); Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Michael S. Tsirkin Message-Id: <20231018141151.87466-2-philmd@linaro.org> --- hw/i386/amd_iommu.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/hw/i386/amd_iommu.c b/hw/i386/amd_iommu.c index 8d0f2f99dd..7965415b47 100644 --- a/hw/i386/amd_iommu.c +++ b/hw/i386/amd_iommu.c @@ -1579,9 +1579,8 @@ static void amdvi_sysbus_realize(DeviceState *dev, Error **errp) /* set up MMIO */ memory_region_init_io(&s->mmio, OBJECT(s), &mmio_mem_ops, s, "amdvi-mmio", AMDVI_MMIO_SIZE); - - sysbus_init_mmio(SYS_BUS_DEVICE(s), &s->mmio); - sysbus_mmio_map(SYS_BUS_DEVICE(s), 0, AMDVI_BASE_ADDR); + memory_region_add_subregion(get_system_memory(), AMDVI_BASE_ADDR, + &s->mmio); pci_setup_iommu(bus, amdvi_host_dma_iommu, s); amdvi_init(s); } From a540087f608f1996e3581ddb39456be23db577a8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Wed, 18 Oct 2023 07:50:31 +0200 Subject: [PATCH 0864/1077] hw/i386/intel_iommu: Do not use SysBus API to map local MMIO region MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit There is no point in exposing an internal MMIO region via SysBus and directly mapping it in the very same device. Just map it without using the SysBus API. Transformation done using the following coccinelle script: @@ expression sbdev; expression index; expression addr; expression subregion; @@ - sysbus_init_mmio(sbdev, subregion); ... when != sbdev - sysbus_mmio_map(sbdev, index, addr); + memory_region_add_subregion(get_system_memory(), addr, subregion); Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Michael S. Tsirkin Message-Id: <20231018141151.87466-3-philmd@linaro.org> --- hw/i386/intel_iommu.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/hw/i386/intel_iommu.c b/hw/i386/intel_iommu.c index 2c832ab68b..e4f6cedcb1 100644 --- a/hw/i386/intel_iommu.c +++ b/hw/i386/intel_iommu.c @@ -4134,6 +4134,8 @@ static void vtd_realize(DeviceState *dev, Error **errp) qemu_mutex_init(&s->iommu_lock); memory_region_init_io(&s->csrmem, OBJECT(s), &vtd_mem_ops, s, "intel_iommu", DMAR_REG_SIZE); + memory_region_add_subregion(get_system_memory(), + Q35_HOST_BRIDGE_IOMMU_ADDR, &s->csrmem); /* Create the shared memory regions by all devices */ memory_region_init(&s->mr_nodmar, OBJECT(s), "vtd-nodmar", @@ -4148,15 +4150,12 @@ static void vtd_realize(DeviceState *dev, Error **errp) memory_region_add_subregion_overlap(&s->mr_nodmar, VTD_INTERRUPT_ADDR_FIRST, &s->mr_ir, 1); - - sysbus_init_mmio(SYS_BUS_DEVICE(s), &s->csrmem); /* No corresponding destroy */ s->iotlb = g_hash_table_new_full(vtd_iotlb_hash, vtd_iotlb_equal, g_free, g_free); s->vtd_address_spaces = g_hash_table_new_full(vtd_as_hash, vtd_as_equal, g_free, g_free); vtd_init(s); - sysbus_mmio_map(SYS_BUS_DEVICE(s), 0, Q35_HOST_BRIDGE_IOMMU_ADDR); pci_setup_iommu(bus, vtd_host_dma_iommu, dev); /* Pseudo address space under root PCI bus. */ x86ms->ioapic_as = vtd_host_dma_iommu(bus, s, Q35_PSEUDO_DEVFN_IOAPIC); From d71af7c83eb4a6adbaf3ce0afba1d3dfbf4a6e2c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Wed, 18 Oct 2023 08:20:43 +0200 Subject: [PATCH 0865/1077] hw/misc/allwinner-dramc: Move sysbus_mmio_map call from init -> realize MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In order to make the next commit trivial, move the sysbus_init_mmio() call in allwinner_r40_dramc_init() just before the corresponding sysbus_mmio_map_overlap() call in allwinner_r40_dramc_realize(). Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Thomas Huth Message-Id: <20231019071611.98885-4-philmd@linaro.org> --- hw/misc/allwinner-r40-dramc.c | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/hw/misc/allwinner-r40-dramc.c b/hw/misc/allwinner-r40-dramc.c index 6944f84455..2cc0254a55 100644 --- a/hw/misc/allwinner-r40-dramc.c +++ b/hw/misc/allwinner-r40-dramc.c @@ -414,6 +414,7 @@ static void allwinner_r40_dramc_reset(DeviceState *dev) static void allwinner_r40_dramc_realize(DeviceState *dev, Error **errp) { AwR40DramCtlState *s = AW_R40_DRAMC(dev); + SysBusDevice *sbd = SYS_BUS_DEVICE(dev); if (!get_match_ddr(s->ram_size)) { error_report("%s: ram-size %u MiB is not supported", @@ -421,8 +422,12 @@ static void allwinner_r40_dramc_realize(DeviceState *dev, Error **errp) exit(1); } - /* detect_cells */ - sysbus_mmio_map_overlap(SYS_BUS_DEVICE(s), 3, s->ram_addr, 10); + /* R40 support max 2G memory but we only support up to 1G now. index 3 */ + memory_region_init_io(&s->detect_cells, OBJECT(s), + &allwinner_r40_detect_ops, s, + "DRAMCELLS", 1 * GiB); + sysbus_init_mmio(sbd, &s->detect_cells); + sysbus_mmio_map_overlap(sbd, 3, s->ram_addr, 10); memory_region_set_enabled(&s->detect_cells, false); /* @@ -458,12 +463,6 @@ static void allwinner_r40_dramc_init(Object *obj) &allwinner_r40_dramphy_ops, s, "DRAMPHY", 4 * KiB); sysbus_init_mmio(sbd, &s->dramphy_iomem); - - /* R40 support max 2G memory but we only support up to 1G now. index 3 */ - memory_region_init_io(&s->detect_cells, OBJECT(s), - &allwinner_r40_detect_ops, s, - "DRAMCELLS", 1 * GiB); - sysbus_init_mmio(sbd, &s->detect_cells); } static Property allwinner_r40_dramc_properties[] = { From faef398291598e39a4484947d44bb177b4596120 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Wed, 18 Oct 2023 10:13:54 +0200 Subject: [PATCH 0866/1077] hw/misc/allwinner-dramc: Do not use SysBus API to map local MMIO region MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit There is no point in exposing an internal MMIO region via SysBus and directly mapping it in the very same device. Just map it without using the SysBus API. Transformation done using the following coccinelle script: @@ expression sbdev; expression index; expression addr; expression subregion; @@ - sysbus_init_mmio(sbdev, subregion); ... when != sbdev - sysbus_mmio_map(sbdev, index, addr); + memory_region_add_subregion(get_system_memory(), + addr, subregion); @@ expression priority; @@ - sysbus_init_mmio(sbdev, subregion); ... when != sbdev - sysbus_mmio_map_overlap(sbdev, index, addr, priority); + memory_region_add_subregion_overlap(get_system_memory(), + addr, + subregion, priority); Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Thomas Huth Message-Id: <20231019071611.98885-5-philmd@linaro.org> --- hw/misc/allwinner-r40-dramc.c | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/hw/misc/allwinner-r40-dramc.c b/hw/misc/allwinner-r40-dramc.c index 2cc0254a55..3d81ddb2e1 100644 --- a/hw/misc/allwinner-r40-dramc.c +++ b/hw/misc/allwinner-r40-dramc.c @@ -414,7 +414,6 @@ static void allwinner_r40_dramc_reset(DeviceState *dev) static void allwinner_r40_dramc_realize(DeviceState *dev, Error **errp) { AwR40DramCtlState *s = AW_R40_DRAMC(dev); - SysBusDevice *sbd = SYS_BUS_DEVICE(dev); if (!get_match_ddr(s->ram_size)) { error_report("%s: ram-size %u MiB is not supported", @@ -422,23 +421,23 @@ static void allwinner_r40_dramc_realize(DeviceState *dev, Error **errp) exit(1); } - /* R40 support max 2G memory but we only support up to 1G now. index 3 */ + /* R40 support max 2G memory but we only support up to 1G now. */ memory_region_init_io(&s->detect_cells, OBJECT(s), &allwinner_r40_detect_ops, s, "DRAMCELLS", 1 * GiB); - sysbus_init_mmio(sbd, &s->detect_cells); - sysbus_mmio_map_overlap(sbd, 3, s->ram_addr, 10); + memory_region_add_subregion_overlap(get_system_memory(), s->ram_addr, + &s->detect_cells, 10); memory_region_set_enabled(&s->detect_cells, false); /* * We only support DRAM size up to 1G now, so prepare a high memory page - * after 1G for dualrank detect. index = 4 + * after 1G for dualrank detect. */ memory_region_init_io(&s->dram_high, OBJECT(s), &allwinner_r40_dualrank_detect_ops, s, "DRAMHIGH", KiB); - sysbus_init_mmio(SYS_BUS_DEVICE(s), &s->dram_high); - sysbus_mmio_map(SYS_BUS_DEVICE(s), 4, s->ram_addr + GiB); + memory_region_add_subregion(get_system_memory(), s->ram_addr + GiB, + &s->dram_high); } static void allwinner_r40_dramc_init(Object *obj) From 0493aafb1abbe6256522c32b5686418b5b192e7e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Wed, 18 Oct 2023 07:51:09 +0200 Subject: [PATCH 0867/1077] hw/pci-host/bonito: Do not use SysBus API to map local MMIO region MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit There is no point in exposing an internal MMIO region via SysBus and directly mapping it in the very same device. Just map it without using the SysBus API. Transformation done using the following coccinelle script: @@ expression sbdev; expression index; expression addr; expression subregion; @@ - sysbus_init_mmio(sbdev, subregion); ... when != sbdev - sysbus_mmio_map(sbdev, index, addr); + memory_region_add_subregion(get_system_memory(), addr, subregion); and manually adding the local 'host_mem' variable to avoid multiple calls to get_system_memory(). Reviewed-by: Thomas Huth Signed-off-by: Philippe Mathieu-Daudé Message-Id: <20231019071611.98885-6-philmd@linaro.org> --- hw/pci-host/bonito.c | 30 +++++++++++++----------------- 1 file changed, 13 insertions(+), 17 deletions(-) diff --git a/hw/pci-host/bonito.c b/hw/pci-host/bonito.c index ee6cb85e97..bab661f3ce 100644 --- a/hw/pci-host/bonito.c +++ b/hw/pci-host/bonito.c @@ -654,7 +654,7 @@ static void bonito_host_realize(DeviceState *dev, Error **errp) static void bonito_pci_realize(PCIDevice *dev, Error **errp) { PCIBonitoState *s = PCI_BONITO(dev); - SysBusDevice *sysbus = SYS_BUS_DEVICE(s->pcihost); + MemoryRegion *host_mem = get_system_memory(); PCIHostState *phb = PCI_HOST_BRIDGE(s->pcihost); BonitoState *bs = s->pcihost; MemoryRegion *pcimem_alias = g_new(MemoryRegion, 1); @@ -668,48 +668,45 @@ static void bonito_pci_realize(PCIDevice *dev, Error **errp) /* set the north bridge register mapping */ memory_region_init_io(&s->iomem, OBJECT(s), &bonito_ops, s, "north-bridge-register", BONITO_INTERNAL_REG_SIZE); - sysbus_init_mmio(sysbus, &s->iomem); - sysbus_mmio_map(sysbus, 0, BONITO_INTERNAL_REG_BASE); + memory_region_add_subregion(host_mem, BONITO_INTERNAL_REG_BASE, &s->iomem); /* set the north bridge pci configure mapping */ memory_region_init_io(&phb->conf_mem, OBJECT(s), &bonito_pciconf_ops, s, "north-bridge-pci-config", BONITO_PCICONFIG_SIZE); - sysbus_init_mmio(sysbus, &phb->conf_mem); - sysbus_mmio_map(sysbus, 1, BONITO_PCICONFIG_BASE); + memory_region_add_subregion(host_mem, BONITO_PCICONFIG_BASE, + &phb->conf_mem); /* set the south bridge pci configure mapping */ memory_region_init_io(&phb->data_mem, OBJECT(s), &bonito_spciconf_ops, s, "south-bridge-pci-config", BONITO_SPCICONFIG_SIZE); - sysbus_init_mmio(sysbus, &phb->data_mem); - sysbus_mmio_map(sysbus, 2, BONITO_SPCICONFIG_BASE); + memory_region_add_subregion(host_mem, BONITO_SPCICONFIG_BASE, + &phb->data_mem); create_unimplemented_device("bonito", BONITO_REG_BASE, BONITO_REG_SIZE); memory_region_init_io(&s->iomem_ldma, OBJECT(s), &bonito_ldma_ops, s, "ldma", 0x100); - sysbus_init_mmio(sysbus, &s->iomem_ldma); - sysbus_mmio_map(sysbus, 3, 0x1fe00200); + memory_region_add_subregion(host_mem, 0x1fe00200, &s->iomem_ldma); /* PCI copier */ memory_region_init_io(&s->iomem_cop, OBJECT(s), &bonito_cop_ops, s, "cop", 0x100); - sysbus_init_mmio(sysbus, &s->iomem_cop); - sysbus_mmio_map(sysbus, 4, 0x1fe00300); + memory_region_add_subregion(host_mem, 0x1fe00300, &s->iomem_cop); create_unimplemented_device("ROMCS", BONITO_FLASH_BASE, 60 * MiB); /* Map PCI IO Space 0x1fd0 0000 - 0x1fd1 0000 */ memory_region_init_alias(&s->bonito_pciio, OBJECT(s), "isa_mmio", get_system_io(), 0, BONITO_PCIIO_SIZE); - sysbus_init_mmio(sysbus, &s->bonito_pciio); - sysbus_mmio_map(sysbus, 5, BONITO_PCIIO_BASE); + memory_region_add_subregion(host_mem, BONITO_PCIIO_BASE, + &s->bonito_pciio); /* add pci local io mapping */ memory_region_init_alias(&s->bonito_localio, OBJECT(s), "IOCS[0]", get_system_io(), 0, 256 * KiB); - sysbus_init_mmio(sysbus, &s->bonito_localio); - sysbus_mmio_map(sysbus, 6, BONITO_DEV_BASE); + memory_region_add_subregion(host_mem, BONITO_DEV_BASE, + &s->bonito_localio); create_unimplemented_device("IOCS[1]", BONITO_DEV_BASE + 1 * 256 * KiB, 256 * KiB); create_unimplemented_device("IOCS[2]", BONITO_DEV_BASE + 2 * 256 * KiB, @@ -719,8 +716,7 @@ static void bonito_pci_realize(PCIDevice *dev, Error **errp) memory_region_init_alias(pcimem_alias, NULL, "pci.mem.alias", &bs->pci_mem, 0, BONITO_PCIHI_SIZE); - memory_region_add_subregion(get_system_memory(), - BONITO_PCIHI_BASE, pcimem_alias); + memory_region_add_subregion(host_mem, BONITO_PCIHI_BASE, pcimem_alias); create_unimplemented_device("PCI_2", (hwaddr)BONITO_PCIHI_BASE + BONITO_PCIHI_SIZE, 2 * GiB); From bec4be77ea18feb9d50a6c2ee42b6c3ffe4ae78b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Wed, 18 Oct 2023 08:37:06 +0200 Subject: [PATCH 0868/1077] hw/acpi: Realize ACPI_GED sysbus device before accessing it MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit sysbus_mmio_map() should not be called on unrealized device. Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Thomas Huth Reviewed-by: Michael S. Tsirkin Message-Id: <20231018141151.87466-7-philmd@linaro.org> --- hw/arm/virt.c | 3 +-- hw/i386/microvm.c | 2 +- hw/loongarch/virt.c | 2 +- 3 files changed, 3 insertions(+), 4 deletions(-) diff --git a/hw/arm/virt.c b/hw/arm/virt.c index 15e74249f9..02c7a7ff3c 100644 --- a/hw/arm/virt.c +++ b/hw/arm/virt.c @@ -647,13 +647,12 @@ static inline DeviceState *create_acpi_ged(VirtMachineState *vms) dev = qdev_new(TYPE_ACPI_GED); qdev_prop_set_uint32(dev, "ged-event", event); + sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal); sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, vms->memmap[VIRT_ACPI_GED].base); sysbus_mmio_map(SYS_BUS_DEVICE(dev), 1, vms->memmap[VIRT_PCDIMM_ACPI].base); sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, qdev_get_gpio_in(vms->gic, irq)); - sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal); - return dev; } diff --git a/hw/i386/microvm.c b/hw/i386/microvm.c index b9c93039e2..ca55aecc3b 100644 --- a/hw/i386/microvm.c +++ b/hw/i386/microvm.c @@ -206,12 +206,12 @@ static void microvm_devices_init(MicrovmMachineState *mms) if (x86_machine_is_acpi_enabled(x86ms)) { DeviceState *dev = qdev_new(TYPE_ACPI_GED); qdev_prop_set_uint32(dev, "ged-event", ACPI_GED_PWR_DOWN_EVT); + sysbus_realize(SYS_BUS_DEVICE(dev), &error_fatal); sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, GED_MMIO_BASE); /* sysbus_mmio_map(SYS_BUS_DEVICE(dev), 1, GED_MMIO_BASE_MEMHP); */ sysbus_mmio_map(SYS_BUS_DEVICE(dev), 2, GED_MMIO_BASE_REGS); sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, x86ms->gsi[GED_MMIO_IRQ]); - sysbus_realize(SYS_BUS_DEVICE(dev), &error_fatal); x86ms->acpi_dev = HOTPLUG_HANDLER(dev); } diff --git a/hw/loongarch/virt.c b/hw/loongarch/virt.c index 2952fe452e..4b7dc67a2d 100644 --- a/hw/loongarch/virt.c +++ b/hw/loongarch/virt.c @@ -412,6 +412,7 @@ static DeviceState *create_acpi_ged(DeviceState *pch_pic, LoongArchMachineState } dev = qdev_new(TYPE_ACPI_GED); qdev_prop_set_uint32(dev, "ged-event", event); + sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal); /* ged event */ sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, VIRT_GED_EVT_ADDR); @@ -422,7 +423,6 @@ static DeviceState *create_acpi_ged(DeviceState *pch_pic, LoongArchMachineState sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, qdev_get_gpio_in(pch_pic, VIRT_SCI_IRQ - VIRT_GSI_BASE)); - sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal); return dev; } From 8a89bb060765e26e0f0d55a495caf3c0fd8615ba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Wed, 18 Oct 2023 08:16:31 +0200 Subject: [PATCH 0869/1077] hw/arm/virt: Realize ARM_GICV2M sysbus device before accessing it MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit sysbus_mmio_map() should not be called on unrealized device. Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Thomas Huth Message-Id: <20231018141151.87466-8-philmd@linaro.org> --- hw/arm/virt.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/arm/virt.c b/hw/arm/virt.c index 02c7a7ff3c..5b08a98f07 100644 --- a/hw/arm/virt.c +++ b/hw/arm/virt.c @@ -690,10 +690,10 @@ static void create_v2m(VirtMachineState *vms) DeviceState *dev; dev = qdev_new("arm-gicv2m"); - sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, vms->memmap[VIRT_GIC_V2M].base); qdev_prop_set_uint32(dev, "base-spi", irq); qdev_prop_set_uint32(dev, "num-spi", NUM_GICV2M_SPIS); sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal); + sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, vms->memmap[VIRT_GIC_V2M].base); for (i = 0; i < NUM_GICV2M_SPIS; i++) { sysbus_connect_irq(SYS_BUS_DEVICE(dev), i, From 675d717b9ee2d8dea9cfdca9aa69ed97d8bc54d3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Wed, 18 Oct 2023 14:41:33 +0200 Subject: [PATCH 0870/1077] hw/isa: Realize ISA bridge device before accessing it MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit qbus_new() should not be called on unrealized device. Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Michael S. Tsirkin Message-Id: <20231019071611.98885-9-philmd@linaro.org> --- hw/isa/isa-bus.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/hw/isa/isa-bus.c b/hw/isa/isa-bus.c index a289eccfb1..f1e0f14007 100644 --- a/hw/isa/isa-bus.c +++ b/hw/isa/isa-bus.c @@ -52,18 +52,25 @@ static const TypeInfo isa_bus_info = { ISABus *isa_bus_new(DeviceState *dev, MemoryRegion* address_space, MemoryRegion *address_space_io, Error **errp) { + DeviceState *bridge = NULL; + if (isabus) { error_setg(errp, "Can't create a second ISA bus"); return NULL; } if (!dev) { - dev = qdev_new("isabus-bridge"); - sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal); + bridge = qdev_new("isabus-bridge"); + dev = bridge; } isabus = ISA_BUS(qbus_new(TYPE_ISA_BUS, dev, NULL)); isabus->address_space = address_space; isabus->address_space_io = address_space_io; + + if (bridge) { + sysbus_realize_and_unref(SYS_BUS_DEVICE(bridge), &error_fatal); + } + return isabus; } From 840b4495ef5c2d90d75f3f0d00d9018146f27d8e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Wed, 18 Oct 2023 14:34:42 +0200 Subject: [PATCH 0871/1077] hw/s390x/css-bridge: Realize sysbus device before accessing it MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit qbus_new() should not be called on unrealized device. Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Thomas Huth Message-Id: <20231019071611.98885-10-philmd@linaro.org> --- hw/s390x/css-bridge.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/hw/s390x/css-bridge.c b/hw/s390x/css-bridge.c index 4017081d49..15d26efc95 100644 --- a/hw/s390x/css-bridge.c +++ b/hw/s390x/css-bridge.c @@ -95,7 +95,6 @@ static const TypeInfo virtual_css_bus_info = { VirtualCssBus *virtual_css_bus_init(void) { - VirtualCssBus *cbus; BusState *bus; DeviceState *dev; @@ -103,19 +102,19 @@ VirtualCssBus *virtual_css_bus_init(void) dev = qdev_new(TYPE_VIRTUAL_CSS_BRIDGE); object_property_add_child(qdev_get_machine(), TYPE_VIRTUAL_CSS_BRIDGE, OBJECT(dev)); - sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal); /* Create bus on bridge device */ bus = qbus_new(TYPE_VIRTUAL_CSS_BUS, dev, "virtual-css"); - cbus = VIRTUAL_CSS_BUS(bus); /* Enable hotplugging */ qbus_set_hotplug_handler(bus, OBJECT(dev)); + sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal); + css_register_io_adapters(CSS_IO_ADAPTER_VIRTIO, true, false, 0, &error_abort); - return cbus; + return VIRTUAL_CSS_BUS(bus); } /***************** Virtual-css Bus Bridge Device ********************/ From 5960f254dbb46f0c7a9f5f44bf4d27c19c34cb97 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Mon, 16 Oct 2023 17:00:53 +0200 Subject: [PATCH 0872/1077] hw/virtio/virtio-pmem: Replace impossible check by assertion MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The get_memory_region() handler is used when (un)plugging the device, which can only occur *after* it is realized. virtio_pmem_realize() ensure the instance can not be realized without 'memdev'. Remove the superfluous check, replacing it by an assertion. Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Michael S. Tsirkin Reviewed-by: Manos Pitsidianakis Message-Id: <20231017140150.44995-2-philmd@linaro.org> --- hw/virtio/virtio-pmem.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/hw/virtio/virtio-pmem.c b/hw/virtio/virtio-pmem.c index c3512c2dae..cc24812d2e 100644 --- a/hw/virtio/virtio-pmem.c +++ b/hw/virtio/virtio-pmem.c @@ -147,10 +147,7 @@ static void virtio_pmem_fill_device_info(const VirtIOPMEM *pmem, static MemoryRegion *virtio_pmem_get_memory_region(VirtIOPMEM *pmem, Error **errp) { - if (!pmem->memdev) { - error_setg(errp, "'%s' property must be set", VIRTIO_PMEM_MEMDEV_PROP); - return NULL; - } + assert(pmem->memdev); return &pmem->memdev->mr; } From 11591b586620ae62155d6bc36650283e7c05efa9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Mon, 16 Oct 2023 17:00:13 +0200 Subject: [PATCH 0873/1077] hw/block/vhost-user-blk: Use DEVICE() / VIRTIO_DEVICE() macros MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Access QOM parent with the proper QOM [VIRTIO_]DEVICE() macros. Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Manos Pitsidianakis Reviewed-by: Mark Cave-Ayland Message-Id: <20231017140150.44995-3-philmd@linaro.org> --- hw/block/vhost-user-blk.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/hw/block/vhost-user-blk.c b/hw/block/vhost-user-blk.c index eecf3f7a81..4b37e26120 100644 --- a/hw/block/vhost-user-blk.c +++ b/hw/block/vhost-user-blk.c @@ -405,7 +405,7 @@ static void vhost_user_blk_event(void *opaque, QEMUChrEvent event) static int vhost_user_blk_realize_connect(VHostUserBlk *s, Error **errp) { - DeviceState *dev = &s->parent_obj.parent_obj; + DeviceState *dev = DEVICE(s); int ret; s->connected = false; @@ -423,7 +423,7 @@ static int vhost_user_blk_realize_connect(VHostUserBlk *s, Error **errp) assert(s->connected); ret = vhost_dev_get_config(&s->dev, (uint8_t *)&s->blkcfg, - s->parent_obj.config_len, errp); + VIRTIO_DEVICE(s)->config_len, errp); if (ret < 0) { qemu_chr_fe_disconnect(&s->chardev); vhost_dev_cleanup(&s->dev); From 3daccfff75dd536117abde15169bede707646977 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Tue, 17 Oct 2023 15:53:54 +0200 Subject: [PATCH 0874/1077] hw/display/virtio-gpu: Use VIRTIO_DEVICE() macro MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Access QOM parent with the proper QOM VIRTIO_DEVICE() macro. Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Michael S. Tsirkin Reviewed-by: Manos Pitsidianakis Reviewed-by: Mark Cave-Ayland Message-Id: <20231017140150.44995-4-philmd@linaro.org> --- hw/display/virtio-gpu.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/display/virtio-gpu.c b/hw/display/virtio-gpu.c index 6efd15b6ae..4265316cbb 100644 --- a/hw/display/virtio-gpu.c +++ b/hw/display/virtio-gpu.c @@ -1128,7 +1128,7 @@ static void virtio_gpu_ctrl_bh(void *opaque) VirtIOGPU *g = opaque; VirtIOGPUClass *vgc = VIRTIO_GPU_GET_CLASS(g); - vgc->handle_ctrl(&g->parent_obj.parent_obj, g->ctrl_vq); + vgc->handle_ctrl(VIRTIO_DEVICE(g), g->ctrl_vq); } static void virtio_gpu_handle_cursor(VirtIODevice *vdev, VirtQueue *vq) From 7794fc9799afb32436d9927900a63f7f73d2ebce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Mon, 16 Oct 2023 17:00:29 +0200 Subject: [PATCH 0875/1077] hw/scsi/virtio-scsi: Use VIRTIO_SCSI_COMMON() macro MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Access QOM parent with the proper QOM VIRTIO_SCSI_COMMON() macro. Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Michael S. Tsirkin Reviewed-by: Manos Pitsidianakis Reviewed-by: Mark Cave-Ayland Message-Id: <20231017140150.44995-5-philmd@linaro.org> --- hw/scsi/virtio-scsi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/scsi/virtio-scsi.c b/hw/scsi/virtio-scsi.c index 45b95ea070..fa53f0902c 100644 --- a/hw/scsi/virtio-scsi.c +++ b/hw/scsi/virtio-scsi.c @@ -761,7 +761,7 @@ static void virtio_scsi_fail_cmd_req(VirtIOSCSIReq *req) static int virtio_scsi_handle_cmd_req_prepare(VirtIOSCSI *s, VirtIOSCSIReq *req) { - VirtIOSCSICommon *vs = &s->parent_obj; + VirtIOSCSICommon *vs = VIRTIO_SCSI_COMMON(s); SCSIDevice *d; int rc; From 1f9d714e9a92d382f5f7c054de647d3dde4ba803 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Mon, 16 Oct 2023 16:18:05 +0200 Subject: [PATCH 0876/1077] hw/dma: Declare link using static DEFINE_PROP_LINK() macro MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Declare link statically using DEFINE_PROP_LINK(). Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Mark Cave-Ayland Message-Id: <20231017140150.44995-6-philmd@linaro.org> --- hw/dma/xilinx_axidma.c | 6 ++---- hw/dma/xlnx-zdma.c | 7 ++----- hw/dma/xlnx_csu_dma.c | 13 ++++--------- 3 files changed, 8 insertions(+), 18 deletions(-) diff --git a/hw/dma/xilinx_axidma.c b/hw/dma/xilinx_axidma.c index 12c90267df..0ae056ed06 100644 --- a/hw/dma/xilinx_axidma.c +++ b/hw/dma/xilinx_axidma.c @@ -577,10 +577,6 @@ static void xilinx_axidma_init(Object *obj) object_initialize_child(OBJECT(s), "axistream-control-connected-target", &s->rx_control_dev, TYPE_XILINX_AXI_DMA_CONTROL_STREAM); - object_property_add_link(obj, "dma", TYPE_MEMORY_REGION, - (Object **)&s->dma_mr, - qdev_prop_allow_set_link_before_realize, - OBJ_PROP_LINK_STRONG); sysbus_init_irq(sbd, &s->streams[0].irq); sysbus_init_irq(sbd, &s->streams[1].irq); @@ -596,6 +592,8 @@ static Property axidma_properties[] = { tx_data_dev, TYPE_STREAM_SINK, StreamSink *), DEFINE_PROP_LINK("axistream-control-connected", XilinxAXIDMA, tx_control_dev, TYPE_STREAM_SINK, StreamSink *), + DEFINE_PROP_LINK("dma", XilinxAXIDMA, dma_mr, + TYPE_MEMORY_REGION, MemoryRegion *), DEFINE_PROP_END_OF_LIST(), }; diff --git a/hw/dma/xlnx-zdma.c b/hw/dma/xlnx-zdma.c index 4eb7f66e9f..84c0083013 100644 --- a/hw/dma/xlnx-zdma.c +++ b/hw/dma/xlnx-zdma.c @@ -795,11 +795,6 @@ static void zdma_init(Object *obj) TYPE_XLNX_ZDMA, ZDMA_R_MAX * 4); sysbus_init_mmio(sbd, &s->iomem); sysbus_init_irq(sbd, &s->irq_zdma_ch_imr); - - object_property_add_link(obj, "dma", TYPE_MEMORY_REGION, - (Object **)&s->dma_mr, - qdev_prop_allow_set_link_before_realize, - OBJ_PROP_LINK_STRONG); } static const VMStateDescription vmstate_zdma = { @@ -817,6 +812,8 @@ static const VMStateDescription vmstate_zdma = { static Property zdma_props[] = { DEFINE_PROP_UINT32("bus-width", XlnxZDMA, cfg.bus_width, 64), + DEFINE_PROP_LINK("dma", XlnxZDMA, dma_mr, + TYPE_MEMORY_REGION, MemoryRegion *), DEFINE_PROP_END_OF_LIST(), }; diff --git a/hw/dma/xlnx_csu_dma.c b/hw/dma/xlnx_csu_dma.c index 88002698a1..e89089821a 100644 --- a/hw/dma/xlnx_csu_dma.c +++ b/hw/dma/xlnx_csu_dma.c @@ -702,6 +702,10 @@ static Property xlnx_csu_dma_properties[] = { * which channel the device is connected to. */ DEFINE_PROP_BOOL("is-dst", XlnxCSUDMA, is_dst, true), + DEFINE_PROP_LINK("stream-connected-dma", XlnxCSUDMA, tx_dev, + TYPE_STREAM_SINK, StreamSink *), + DEFINE_PROP_LINK("dma", XlnxCSUDMA, dma_mr, + TYPE_MEMORY_REGION, MemoryRegion *), DEFINE_PROP_END_OF_LIST(), }; @@ -728,15 +732,6 @@ static void xlnx_csu_dma_init(Object *obj) memory_region_init(&s->iomem, obj, TYPE_XLNX_CSU_DMA, XLNX_CSU_DMA_R_MAX * 4); - - object_property_add_link(obj, "stream-connected-dma", TYPE_STREAM_SINK, - (Object **)&s->tx_dev, - qdev_prop_allow_set_link_before_realize, - OBJ_PROP_LINK_STRONG); - object_property_add_link(obj, "dma", TYPE_MEMORY_REGION, - (Object **)&s->dma_mr, - qdev_prop_allow_set_link_before_realize, - OBJ_PROP_LINK_STRONG); } static const TypeInfo xlnx_csu_dma_info = { From 08d45942972ada0e4d051799fb8ba1b47225a6b3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Mon, 16 Oct 2023 16:18:10 +0200 Subject: [PATCH 0877/1077] hw/net: Declare link using static DEFINE_PROP_LINK() macro MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Declare link statically using DEFINE_PROP_LINK(). Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Mark Cave-Ayland Message-Id: <20231017140150.44995-7-philmd@linaro.org> --- hw/net/cadence_gem.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/hw/net/cadence_gem.c b/hw/net/cadence_gem.c index f445d8bb5e..37e209cda6 100644 --- a/hw/net/cadence_gem.c +++ b/hw/net/cadence_gem.c @@ -1654,11 +1654,6 @@ static void gem_init(Object *obj) "enet", sizeof(s->regs)); sysbus_init_mmio(SYS_BUS_DEVICE(dev), &s->iomem); - - object_property_add_link(obj, "dma", TYPE_MEMORY_REGION, - (Object **)&s->dma_mr, - qdev_prop_allow_set_link_before_realize, - OBJ_PROP_LINK_STRONG); } static const VMStateDescription vmstate_cadence_gem = { @@ -1691,6 +1686,8 @@ static Property gem_properties[] = { num_type2_screeners, 4), DEFINE_PROP_UINT16("jumbo-max-len", CadenceGEMState, jumbo_max_len, 10240), + DEFINE_PROP_LINK("dma", CadenceGEMState, dma_mr, + TYPE_MEMORY_REGION, MemoryRegion *), DEFINE_PROP_END_OF_LIST(), }; From b1be65f6436f53618408d9c6fc6959054f5afed6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Tue, 17 Oct 2023 15:05:00 +0200 Subject: [PATCH 0878/1077] ui/input: Constify QemuInputHandler structure MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Access to QemuInputHandlerState::handler are read-only. Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Marc-André Lureau Reviewed-by: Mark Cave-Ayland Message-Id: <20231017131251.43708-1-philmd@linaro.org> --- chardev/msmouse.c | 2 +- chardev/wctablet.c | 2 +- hw/char/escc.c | 2 +- hw/display/xenfb.c | 6 +++--- hw/input/adb-kbd.c | 2 +- hw/input/hid.c | 6 +++--- hw/input/ps2.c | 4 ++-- hw/input/virtio-input-hid.c | 8 ++++---- include/hw/virtio/virtio-input.h | 2 +- include/ui/input.h | 2 +- ui/input-legacy.c | 2 +- ui/input.c | 4 ++-- ui/vdagent.c | 2 +- 13 files changed, 22 insertions(+), 22 deletions(-) diff --git a/chardev/msmouse.c b/chardev/msmouse.c index ab8fe981d6..a774c397b4 100644 --- a/chardev/msmouse.c +++ b/chardev/msmouse.c @@ -171,7 +171,7 @@ static int msmouse_chr_write(struct Chardev *s, const uint8_t *buf, int len) return len; } -static QemuInputHandler msmouse_handler = { +static const QemuInputHandler msmouse_handler = { .name = "QEMU Microsoft Mouse", .mask = INPUT_EVENT_MASK_BTN | INPUT_EVENT_MASK_REL, .event = msmouse_input_event, diff --git a/chardev/wctablet.c b/chardev/wctablet.c index 43bdf6b608..f4008bf35b 100644 --- a/chardev/wctablet.c +++ b/chardev/wctablet.c @@ -178,7 +178,7 @@ static void wctablet_input_sync(DeviceState *dev) } } -static QemuInputHandler wctablet_handler = { +static const QemuInputHandler wctablet_handler = { .name = "QEMU Wacom Pen Tablet", .mask = INPUT_EVENT_MASK_BTN | INPUT_EVENT_MASK_ABS, .event = wctablet_input_event, diff --git a/hw/char/escc.c b/hw/char/escc.c index 4be66053c1..48b30ee760 100644 --- a/hw/char/escc.c +++ b/hw/char/escc.c @@ -845,7 +845,7 @@ static void sunkbd_handle_event(DeviceState *dev, QemuConsole *src, put_queue(s, keycode); } -static QemuInputHandler sunkbd_handler = { +static const QemuInputHandler sunkbd_handler = { .name = "sun keyboard", .mask = INPUT_EVENT_MASK_KEY, .event = sunkbd_handle_event, diff --git a/hw/display/xenfb.c b/hw/display/xenfb.c index 0074a9b6f8..b2130a0d70 100644 --- a/hw/display/xenfb.c +++ b/hw/display/xenfb.c @@ -321,20 +321,20 @@ static void xenfb_mouse_sync(DeviceState *dev) xenfb->wheel = 0; } -static QemuInputHandler xenfb_keyboard = { +static const QemuInputHandler xenfb_keyboard = { .name = "Xen PV Keyboard", .mask = INPUT_EVENT_MASK_KEY, .event = xenfb_key_event, }; -static QemuInputHandler xenfb_abs_mouse = { +static const QemuInputHandler xenfb_abs_mouse = { .name = "Xen PV Mouse", .mask = INPUT_EVENT_MASK_BTN | INPUT_EVENT_MASK_ABS, .event = xenfb_mouse_event, .sync = xenfb_mouse_sync, }; -static QemuInputHandler xenfb_rel_mouse = { +static const QemuInputHandler xenfb_rel_mouse = { .name = "Xen PV Mouse", .mask = INPUT_EVENT_MASK_BTN | INPUT_EVENT_MASK_REL, .event = xenfb_mouse_event, diff --git a/hw/input/adb-kbd.c b/hw/input/adb-kbd.c index a9088c910c..e21edf9acd 100644 --- a/hw/input/adb-kbd.c +++ b/hw/input/adb-kbd.c @@ -355,7 +355,7 @@ static void adb_kbd_reset(DeviceState *dev) s->count = 0; } -static QemuInputHandler adb_keyboard_handler = { +static const QemuInputHandler adb_keyboard_handler = { .name = "QEMU ADB Keyboard", .mask = INPUT_EVENT_MASK_KEY, .event = adb_keyboard_event, diff --git a/hw/input/hid.c b/hw/input/hid.c index a9c7dd1ce1..b8e85374ca 100644 --- a/hw/input/hid.c +++ b/hw/input/hid.c @@ -510,20 +510,20 @@ void hid_free(HIDState *hs) hid_del_idle_timer(hs); } -static QemuInputHandler hid_keyboard_handler = { +static const QemuInputHandler hid_keyboard_handler = { .name = "QEMU HID Keyboard", .mask = INPUT_EVENT_MASK_KEY, .event = hid_keyboard_event, }; -static QemuInputHandler hid_mouse_handler = { +static const QemuInputHandler hid_mouse_handler = { .name = "QEMU HID Mouse", .mask = INPUT_EVENT_MASK_BTN | INPUT_EVENT_MASK_REL, .event = hid_pointer_event, .sync = hid_pointer_sync, }; -static QemuInputHandler hid_tablet_handler = { +static const QemuInputHandler hid_tablet_handler = { .name = "QEMU HID Tablet", .mask = INPUT_EVENT_MASK_BTN | INPUT_EVENT_MASK_ABS, .event = hid_pointer_event, diff --git a/hw/input/ps2.c b/hw/input/ps2.c index 45af76a837..c8fd23cf36 100644 --- a/hw/input/ps2.c +++ b/hw/input/ps2.c @@ -1231,7 +1231,7 @@ static const VMStateDescription vmstate_ps2_mouse = { } }; -static QemuInputHandler ps2_keyboard_handler = { +static const QemuInputHandler ps2_keyboard_handler = { .name = "QEMU PS/2 Keyboard", .mask = INPUT_EVENT_MASK_KEY, .event = ps2_keyboard_event, @@ -1242,7 +1242,7 @@ static void ps2_kbd_realize(DeviceState *dev, Error **errp) qemu_input_handler_register(dev, &ps2_keyboard_handler); } -static QemuInputHandler ps2_mouse_handler = { +static const QemuInputHandler ps2_mouse_handler = { .name = "QEMU PS/2 Mouse", .mask = INPUT_EVENT_MASK_BTN | INPUT_EVENT_MASK_REL, .event = ps2_mouse_event, diff --git a/hw/input/virtio-input-hid.c b/hw/input/virtio-input-hid.c index 7053ad72d4..45e4d4c75d 100644 --- a/hw/input/virtio-input-hid.c +++ b/hw/input/virtio-input-hid.c @@ -265,7 +265,7 @@ static const TypeInfo virtio_input_hid_info = { /* ----------------------------------------------------------------- */ -static QemuInputHandler virtio_keyboard_handler = { +static const QemuInputHandler virtio_keyboard_handler = { .name = VIRTIO_ID_NAME_KEYBOARD, .mask = INPUT_EVENT_MASK_KEY, .event = virtio_input_handle_event, @@ -322,7 +322,7 @@ static const TypeInfo virtio_keyboard_info = { /* ----------------------------------------------------------------- */ -static QemuInputHandler virtio_mouse_handler = { +static const QemuInputHandler virtio_mouse_handler = { .name = VIRTIO_ID_NAME_MOUSE, .mask = INPUT_EVENT_MASK_BTN | INPUT_EVENT_MASK_REL, .event = virtio_input_handle_event, @@ -416,7 +416,7 @@ static const TypeInfo virtio_mouse_info = { /* ----------------------------------------------------------------- */ -static QemuInputHandler virtio_tablet_handler = { +static const QemuInputHandler virtio_tablet_handler = { .name = VIRTIO_ID_NAME_TABLET, .mask = INPUT_EVENT_MASK_BTN | INPUT_EVENT_MASK_ABS, .event = virtio_input_handle_event, @@ -541,7 +541,7 @@ static const TypeInfo virtio_tablet_info = { /* ----------------------------------------------------------------- */ -static QemuInputHandler virtio_multitouch_handler = { +static const QemuInputHandler virtio_multitouch_handler = { .name = VIRTIO_ID_NAME_MULTITOUCH, .mask = INPUT_EVENT_MASK_BTN | INPUT_EVENT_MASK_MTT, .event = virtio_input_handle_event, diff --git a/include/hw/virtio/virtio-input.h b/include/hw/virtio/virtio-input.h index 08f1591424..a6c9703644 100644 --- a/include/hw/virtio/virtio-input.h +++ b/include/hw/virtio/virtio-input.h @@ -84,7 +84,7 @@ struct VirtIOInputHID { VirtIOInput parent_obj; char *display; uint32_t head; - QemuInputHandler *handler; + const QemuInputHandler *handler; QemuInputHandlerState *hs; int ledstate; bool wheel_axis; diff --git a/include/ui/input.h b/include/ui/input.h index 24d8e4579e..8f9aac562e 100644 --- a/include/ui/input.h +++ b/include/ui/input.h @@ -30,7 +30,7 @@ struct QemuInputHandler { }; QemuInputHandlerState *qemu_input_handler_register(DeviceState *dev, - QemuInputHandler *handler); + const QemuInputHandler *handler); void qemu_input_handler_activate(QemuInputHandlerState *s); void qemu_input_handler_deactivate(QemuInputHandlerState *s); void qemu_input_handler_unregister(QemuInputHandlerState *s); diff --git a/ui/input-legacy.c b/ui/input-legacy.c index 46ea74e44d..210ae5eaca 100644 --- a/ui/input-legacy.c +++ b/ui/input-legacy.c @@ -127,7 +127,7 @@ static void legacy_kbd_event(DeviceState *dev, QemuConsole *src, } } -static QemuInputHandler legacy_kbd_handler = { +static const QemuInputHandler legacy_kbd_handler = { .name = "legacy-kbd", .mask = INPUT_EVENT_MASK_KEY, .event = legacy_kbd_event, diff --git a/ui/input.c b/ui/input.c index cbe8573c5c..dc745860f4 100644 --- a/ui/input.c +++ b/ui/input.c @@ -10,7 +10,7 @@ struct QemuInputHandlerState { DeviceState *dev; - QemuInputHandler *handler; + const QemuInputHandler *handler; int id; int events; QemuConsole *con; @@ -46,7 +46,7 @@ static uint32_t queue_count; static uint32_t queue_limit = 1024; QemuInputHandlerState *qemu_input_handler_register(DeviceState *dev, - QemuInputHandler *handler) + const QemuInputHandler *handler) { QemuInputHandlerState *s = g_new0(QemuInputHandlerState, 1); static int id = 1; diff --git a/ui/vdagent.c b/ui/vdagent.c index 00d36a8677..706d6d97bd 100644 --- a/ui/vdagent.c +++ b/ui/vdagent.c @@ -297,7 +297,7 @@ static void vdagent_pointer_sync(DeviceState *dev) } } -static QemuInputHandler vdagent_mouse_handler = { +static const QemuInputHandler vdagent_mouse_handler = { .name = "vdagent mouse", .mask = INPUT_EVENT_MASK_BTN | INPUT_EVENT_MASK_ABS, .event = vdagent_pointer_event, From e029bb00a79bea226477749f9b10a2ff9e7930ef Mon Sep 17 00:00:00 2001 From: Helge Deller Date: Sat, 14 Oct 2023 06:45:59 +0200 Subject: [PATCH 0879/1077] hw/pci-host: Add Astro system bus adapter found on PA-RISC machines The 64-bit PA-RISC machines use a Astro system bus adapter (SBA) with Elroy PCI host chips. Later generation Astro chips were named Pluto, Ike and REO. Signed-off-by: Helge Deller --- hw/pci-host/astro.c | 885 ++++++++++++++++++++++++++++++++++++ hw/pci-host/trace-events | 11 + include/hw/pci-host/astro.h | 92 ++++ 3 files changed, 988 insertions(+) create mode 100644 hw/pci-host/astro.c create mode 100644 include/hw/pci-host/astro.h diff --git a/hw/pci-host/astro.c b/hw/pci-host/astro.c new file mode 100644 index 0000000000..4b2d7caf2d --- /dev/null +++ b/hw/pci-host/astro.c @@ -0,0 +1,885 @@ +/* + * HP-PARISC Astro/Pluto/Ike/REO system bus adapter (SBA) + * with Elroy PCI bus (LBA) adapter emulation + * Found in C3000 and similar machines + * + * (C) 2023 by Helge Deller + * + * This work is licensed under the GNU GPL license version 2 or later. + * + * Chip documentation is available at: + * https://parisc.wiki.kernel.org/index.php/Technical_Documentation + * + * TODO: + * - All user-added devices are currently attached to the first + * Elroy (PCI bus) only for now. To fix this additional work in + * SeaBIOS and this driver is needed. See "user_creatable" flag below. + * - GMMIO (Greater than 4 GB MMIO) register + */ + +#define TYPE_ASTRO_IOMMU_MEMORY_REGION "astro-iommu-memory-region" + +#include "qemu/osdep.h" +#include "qemu/module.h" +#include "qemu/units.h" +#include "qapi/error.h" +#include "hw/irq.h" +#include "hw/pci/pci_device.h" +#include "hw/pci/pci_bus.h" +#include "hw/qdev-properties.h" +#include "hw/pci-host/astro.h" +#include "hw/hppa/hppa_hardware.h" +#include "migration/vmstate.h" +#include "trace.h" +#include "qom/object.h" + +/* + * Helper functions + */ + +static uint64_t mask_32bit_val(hwaddr addr, unsigned size, uint64_t val) +{ + if (size == 8) { + return val; + } + if (addr & 4) { + val >>= 32; + } else { + val = (uint32_t) val; + } + return val; +} + +static void put_val_in_int64(uint64_t *p, hwaddr addr, unsigned size, + uint64_t val) +{ + if (size == 8) { + *p = val; + } else if (size == 4) { + if (addr & 4) { + *p = ((*p << 32) >> 32) | (val << 32); + } else { + *p = ((*p >> 32) << 32) | (uint32_t) val; + } + } +} + +static void put_val_in_arrary(uint64_t *array, hwaddr start_addr, + hwaddr addr, unsigned size, uint64_t val) +{ + int index; + + index = (addr - start_addr) / 8; + put_val_in_int64(&array[index], addr, size, val); +} + + +/* + * The Elroy PCI host bridge. We have at least 4 of those under Astro. + */ + +static MemTxResult elroy_chip_read_with_attrs(void *opaque, hwaddr addr, + uint64_t *data, unsigned size, + MemTxAttrs attrs) +{ + MemTxResult ret = MEMTX_OK; + ElroyState *s = opaque; + uint64_t val = -1; + int index; + + switch ((addr >> 3) << 3) { + case 0x0008: + val = 0x6000005; /* func_class */ + break; + case 0x0058: + /* + * Scratch register, but firmware initializes it with the + * PCI BUS number and Linux/HP-UX uses it then. + */ + val = s->pci_bus_num; + /* Upper byte holds the end of this bus number */ + val |= s->pci_bus_num << 8; + break; + case 0x0080: + val = s->arb_mask; /* set ARB mask */ + break; + case 0x0108: + val = s->status_control; + break; + case 0x200 ... 0x250 - 1: /* LMMIO, GMMIO, WLMMIO, WGMMIO, ... */ + index = (addr - 0x200) / 8; + val = s->mmio_base[index]; + break; + case 0x0680: + val = s->error_config; + break; + case 0x0688: + val = 0; /* ERROR_STATUS */ + break; + case 0x0800: /* IOSAPIC_REG_SELECT */ + val = s->iosapic_reg_select; + break; + case 0x0808: + val = UINT64_MAX; /* XXX: tbc. */ + g_assert_not_reached(); + break; + case 0x0810: /* IOSAPIC_REG_WINDOW */ + switch (s->iosapic_reg_select) { + case 0x01: /* IOSAPIC_REG_VERSION */ + val = (32 << 16) | 1; /* upper 16bit holds max entries */ + break; + default: + if (s->iosapic_reg_select < ARRAY_SIZE(s->iosapic_reg)) { + val = s->iosapic_reg[s->iosapic_reg_select]; + } else { + trace_iosapic_reg_read(s->iosapic_reg_select, size, val); + g_assert_not_reached(); + } + } + trace_iosapic_reg_read(s->iosapic_reg_select, size, val); + break; + default: + trace_elroy_read(addr, size, val); + g_assert_not_reached(); + } + trace_elroy_read(addr, size, val); + + /* for 32-bit accesses mask return value */ + val = mask_32bit_val(addr, size, val); + + trace_astro_chip_read(addr, size, val); + *data = val; + return ret; +} + + +static MemTxResult elroy_chip_write_with_attrs(void *opaque, hwaddr addr, + uint64_t val, unsigned size, + MemTxAttrs attrs) +{ + ElroyState *s = opaque; + int i; + + trace_elroy_write(addr, size, val); + + switch ((addr >> 3) << 3) { + case 0x080: + put_val_in_int64(&s->arb_mask, addr, size, val); + break; + case 0x0108: + put_val_in_int64(&s->status_control, addr, size, val); + break; + case 0x200 ... 0x250 - 1: /* LMMIO, GMMIO, WLMMIO, WGMMIO, ... */ + put_val_in_arrary(s->mmio_base, 0x200, addr, size, val); + break; + case 0x0680: + put_val_in_int64(&s->error_config, addr, size, val); + break; + case 0x0800: /* IOSAPIC_REG_SELECT */ + s->iosapic_reg_select = val; + break; + case 0x0810: /* IOSAPIC_REG_WINDOW */ + trace_iosapic_reg_write(s->iosapic_reg_select, size, val); + if (s->iosapic_reg_select < ARRAY_SIZE(s->iosapic_reg)) { + s->iosapic_reg[s->iosapic_reg_select] = val; + } else { + g_assert_not_reached(); + } + break; + case 0x0840: /* IOSAPIC_REG_EOI */ + val = le64_to_cpu(val); + val &= 63; + for (i = 0; i < ELROY_IRQS; i++) { + if ((s->iosapic_reg[0x10 + 2 * i] & 63) == val) { + s->ilr &= ~(1ull << i); + } + } + break; + default: + g_assert_not_reached(); + } + return MEMTX_OK; +} + +static const MemoryRegionOps elroy_chip_ops = { + .read_with_attrs = elroy_chip_read_with_attrs, + .write_with_attrs = elroy_chip_write_with_attrs, + .endianness = DEVICE_LITTLE_ENDIAN, + .valid = { + .min_access_size = 4, + .max_access_size = 8, + }, + .impl = { + .min_access_size = 4, + .max_access_size = 8, + }, +}; + + +/* Unlike pci_config_data_le_ops, no check of high bit set in config_reg. */ + +static uint64_t elroy_config_data_read(void *opaque, hwaddr addr, unsigned len) +{ + uint64_t val; + + PCIHostState *s = opaque; + val = pci_data_read(s->bus, s->config_reg | (addr & 3), len); + trace_elroy_pci_config_data_read(s->config_reg | (addr & 3), len, val); + return val; +} + +static void elroy_config_data_write(void *opaque, hwaddr addr, + uint64_t val, unsigned len) +{ + PCIHostState *s = opaque; + pci_data_write(s->bus, s->config_reg | (addr & 3), val, len); + trace_elroy_pci_config_data_write(s->config_reg | (addr & 3), len, val); +} + +static const MemoryRegionOps elroy_config_data_ops = { + .read = elroy_config_data_read, + .write = elroy_config_data_write, + .endianness = DEVICE_LITTLE_ENDIAN, +}; + +static uint64_t elroy_config_addr_read(void *opaque, hwaddr addr, unsigned len) +{ + ElroyState *s = opaque; + return s->config_reg_elroy; +} + +static void elroy_config_addr_write(void *opaque, hwaddr addr, + uint64_t val, unsigned len) +{ + PCIHostState *s = opaque; + ElroyState *es = opaque; + es->config_reg_elroy = val; /* keep a copy of original value */ + s->config_reg = val; +} + +static const MemoryRegionOps elroy_config_addr_ops = { + .read = elroy_config_addr_read, + .write = elroy_config_addr_write, + .valid.min_access_size = 4, + .valid.max_access_size = 8, + .endianness = DEVICE_LITTLE_ENDIAN, +}; + + +/* + * A subroutine of astro_translate_iommu that builds an IOMMUTLBEntry using the + * given translated address and mask. + */ +static bool make_iommu_tlbe(hwaddr addr, hwaddr taddr, hwaddr mask, + IOMMUTLBEntry *ret) +{ + hwaddr tce_mask = ~((1ull << 12) - 1); + ret->target_as = &address_space_memory; + ret->iova = addr & tce_mask; + ret->translated_addr = taddr & tce_mask; + ret->addr_mask = ~tce_mask; + ret->perm = IOMMU_RW; + return true; +} + +/* Handle PCI-to-system address translation. */ +static IOMMUTLBEntry astro_translate_iommu(IOMMUMemoryRegion *iommu, + hwaddr addr, + IOMMUAccessFlags flag, + int iommu_idx) +{ + AstroState *s = container_of(iommu, AstroState, iommu); + IOMMUTLBEntry ret = { + .target_as = &address_space_memory, + .iova = addr, + .translated_addr = 0, + .addr_mask = ~(hwaddr)0, + .perm = IOMMU_NONE, + }; + hwaddr pdir_ptr, index, a, ibase; + hwaddr addr_mask = 0xfff; /* 4k translation */ + uint64_t entry; + +#define IOVP_SHIFT 12 /* equals PAGE_SHIFT */ +#define PDIR_INDEX(iovp) ((iovp) >> IOVP_SHIFT) +#define IOVP_MASK PAGE_MASK +#define SBA_PDIR_VALID_BIT 0x8000000000000000ULL + + /* "range enable" flag cleared? */ + if ((s->tlb_ibase & 1) == 0) { + make_iommu_tlbe(addr, addr, addr_mask, &ret); + return ret; + } + + a = addr; + ibase = s->tlb_ibase & ~1ULL; + if ((a & s->tlb_imask) != ibase) { + /* do not translate this one! */ + make_iommu_tlbe(addr, addr, addr_mask, &ret); + return ret; + } + index = PDIR_INDEX(a); + pdir_ptr = s->tlb_pdir_base + index * sizeof(entry); + entry = ldq_le_phys(&address_space_memory, pdir_ptr); + if (!(entry & SBA_PDIR_VALID_BIT)) { /* I/O PDIR entry valid ? */ + g_assert_not_reached(); + goto failure; + } + entry &= ~SBA_PDIR_VALID_BIT; + entry >>= IOVP_SHIFT; + entry <<= 12; + entry |= addr & 0xfff; + make_iommu_tlbe(addr, entry, addr_mask, &ret); + goto success; + + failure: + ret = (IOMMUTLBEntry) { .perm = IOMMU_NONE }; + success: + return ret; +} + +static AddressSpace *elroy_pcihost_set_iommu(PCIBus *bus, void *opaque, + int devfn) +{ + ElroyState *s = opaque; + return &s->astro->iommu_as; +} + +/* + * Encoding in IOSAPIC: + * base_addr == 0xfffa0000, we want to get 0xa0ff0000. + * eid 0x0ff00000 -> 0x00ff0000 + * id 0x000ff000 -> 0xff000000 + */ +#define SWIZZLE_HPA(a) \ + ((((a) & 0x0ff00000) >> 4) | (((a) & 0x000ff000) << 12)) +#define UNSWIZZLE_HPA(a) \ + (((((a) << 4) & 0x0ff00000) | (((a) >> 12) & 0x000ff000) | 0xf0000000)) + +/* bits in the "low" I/O Sapic IRdT entry */ +#define IOSAPIC_IRDT_DISABLE 0x10000 /* if bit is set, mask this irq */ +#define IOSAPIC_IRDT_PO_LOW 0x02000 +#define IOSAPIC_IRDT_LEVEL_TRIG 0x08000 +#define IOSAPIC_IRDT_MODE_LPRI 0x00100 + +#define CPU_IRQ_OFFSET 2 + +static void elroy_set_irq(void *opaque, int irq, int level) +{ + ElroyState *s = opaque; + uint32_t bit; + uint32_t old_ilr = s->ilr; + hwaddr cpu_hpa; + uint32_t val; + + val = s->iosapic_reg[0x10 + 2 * irq]; + cpu_hpa = s->iosapic_reg[0x11 + 2 * irq]; + /* low nibble of val has value to write into CPU irq reg */ + bit = 1u << (val & (ELROY_IRQS - 1)); + cpu_hpa = UNSWIZZLE_HPA(cpu_hpa); + + if (level && (!(val & IOSAPIC_IRDT_DISABLE)) && cpu_hpa) { + uint32_t ena = bit & ~old_ilr; + s->ilr = old_ilr | bit; + if (ena != 0) { + stl_be_phys(&address_space_memory, cpu_hpa, val & 63); + } + } else { + s->ilr = old_ilr & ~bit; + } +} + +static int elroy_pci_map_irq(PCIDevice *d, int irq_num) +{ + int slot = PCI_SLOT(d->devfn); + + assert(irq_num >= 0 && irq_num < ELROY_IRQS); + return slot & (ELROY_IRQS - 1); +} + +static void elroy_reset(DeviceState *dev) +{ + ElroyState *s = ELROY_PCI_HOST_BRIDGE(dev); + int irq; + + /* + * Make sure to disable interrupts at reboot, otherwise the Linux kernel + * serial8250_config_port() in drivers/tty/serial/8250/8250_port.c + * will hang during autoconfig(). + */ + s->ilr = 0; + for (irq = 0; irq < ELROY_IRQS; irq++) { + s->iosapic_reg[0x10 + 2 * irq] = IOSAPIC_IRDT_PO_LOW | + IOSAPIC_IRDT_LEVEL_TRIG | (irq + CPU_IRQ_OFFSET) | + IOSAPIC_IRDT_DISABLE; + s->iosapic_reg[0x11 + 2 * irq] = SWIZZLE_HPA(CPU_HPA); + } +} + +static void elroy_pcihost_init(Object *obj) +{ + ElroyState *s = ELROY_PCI_HOST_BRIDGE(obj); + PCIHostState *phb = PCI_HOST_BRIDGE(obj); + SysBusDevice *sbd = SYS_BUS_DEVICE(obj); + + /* Elroy config access from CPU. */ + memory_region_init_io(&s->this_mem, OBJECT(s), &elroy_chip_ops, + s, "elroy", 0x2000); + + /* Elroy PCI config. */ + memory_region_init_io(&phb->conf_mem, OBJECT(phb), + &elroy_config_addr_ops, DEVICE(s), + "pci-conf-idx", 8); + memory_region_init_io(&phb->data_mem, OBJECT(phb), + &elroy_config_data_ops, DEVICE(s), + "pci-conf-data", 8); + memory_region_add_subregion(&s->this_mem, 0x40, + &phb->conf_mem); + memory_region_add_subregion(&s->this_mem, 0x48, + &phb->data_mem); + + /* Elroy PCI bus memory. */ + memory_region_init(&s->pci_mmio, OBJECT(s), "pci-mmio", UINT64_MAX); + memory_region_init_io(&s->pci_io, OBJECT(s), &unassigned_io_ops, obj, + "pci-isa-mmio", + ((uint32_t) IOS_DIST_BASE_SIZE) / ROPES_PER_IOC); + + phb->bus = pci_register_root_bus(DEVICE(s), "pci", + elroy_set_irq, elroy_pci_map_irq, s, + &s->pci_mmio, &s->pci_io, + PCI_DEVFN(0, 0), ELROY_IRQS, TYPE_PCI_BUS); + + sysbus_init_mmio(sbd, &s->this_mem); + + qdev_init_gpio_in(DEVICE(obj), elroy_set_irq, ELROY_IRQS); +} + +static Property elroy_pcihost_properties[] = { + DEFINE_PROP_END_OF_LIST(), +}; + +static const VMStateDescription vmstate_elroy = { + .name = "Elroy", + .version_id = 1, + .minimum_version_id = 1, + .fields = (VMStateField[]) { + VMSTATE_UINT64(hpa, ElroyState), + VMSTATE_UINT32(pci_bus_num, ElroyState), + VMSTATE_UINT64(config_address, ElroyState), + VMSTATE_UINT64(config_reg_elroy, ElroyState), + VMSTATE_UINT64(status_control, ElroyState), + VMSTATE_UINT64(arb_mask, ElroyState), + VMSTATE_UINT64_ARRAY(mmio_base, ElroyState, (0x0250 - 0x200) / 8), + VMSTATE_UINT64(error_config, ElroyState), + VMSTATE_UINT32(iosapic_reg_select, ElroyState), + VMSTATE_UINT64_ARRAY(iosapic_reg, ElroyState, 0x20), + VMSTATE_UINT32(ilr, ElroyState), + VMSTATE_END_OF_LIST() + } +}; + +static void elroy_pcihost_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + + dc->reset = elroy_reset; + device_class_set_props(dc, elroy_pcihost_properties); + dc->vmsd = &vmstate_elroy; + dc->user_creatable = false; +} + +static const TypeInfo elroy_pcihost_info = { + .name = TYPE_ELROY_PCI_HOST_BRIDGE, + .parent = TYPE_PCI_HOST_BRIDGE, + .instance_init = elroy_pcihost_init, + .instance_size = sizeof(ElroyState), + .class_init = elroy_pcihost_class_init, +}; + +static void elroy_register_types(void) +{ + type_register_static(&elroy_pcihost_info); +} + +type_init(elroy_register_types) + + +static ElroyState *elroy_init(int num) +{ + DeviceState *dev; + + dev = qdev_new(TYPE_ELROY_PCI_HOST_BRIDGE); + dev->id = g_strdup_printf("elroy%d", num); + sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal); + + return ELROY_PCI_HOST_BRIDGE(dev); +} + +/* + * Astro Runway chip. + */ + +static MemTxResult astro_chip_read_with_attrs(void *opaque, hwaddr addr, + uint64_t *data, unsigned size, + MemTxAttrs attrs) +{ + AstroState *s = opaque; + MemTxResult ret = MEMTX_OK; + uint64_t val = -1; + int index; + + switch ((addr >> 3) << 3) { + /* R2I registers */ + case 0x0000: /* ID */ + val = (0x01 << 3) | 0x01ULL; + break; + case 0x0008: /* IOC_CTRL */ + val = s->ioc_ctrl; + break; + case 0x0010: /* TOC_CLIENT_ID */ + break; + case 0x0030: /* HP-UX 10.20 and 11.11 reads it. No idea. */ + val = -1; + break; + case 0x0300 ... 0x03d8: /* LMMIO_DIRECT0_BASE... */ + index = (addr - 0x300) / 8; + val = s->ioc_ranges[index]; + break; + case 0x10200: + val = 0; + break; + case 0x10220: + case 0x10230: /* HP-UX 11.11 reads it. No idea. */ + val = -1; + break; + case 0x22108: /* IOC STATUS_CONTROL */ + val = s->ioc_status_ctrl; + break; + case 0x20200 ... 0x20240 - 1: /* IOC Rope0_Control ... */ + index = (addr - 0x20200) / 8; + val = s->ioc_rope_control[index]; + break; + case 0x20040: /* IOC Rope config */ + val = s->ioc_rope_config; + break; + case 0x20050: /* IOC Rope debug */ + val = 0; + break; + case 0x20108: /* IOC STATUS_CONTROL */ + val = s->ioc_status_control; + break; + case 0x20310: /* IOC_PCOM */ + val = s->tlb_pcom; + /* TODO: flush iommu */ + break; + case 0x20400: + val = s->ioc_flush_control; + break; + /* empty placeholders for non-existent elroys */ +#define EMPTY_PORT(x) case x: case x+8: val = 0; break; \ + case x+40: case x+48: val = UINT64_MAX; break; + EMPTY_PORT(0x30000) + EMPTY_PORT(0x32000) + EMPTY_PORT(0x34000) + EMPTY_PORT(0x36000) + EMPTY_PORT(0x38000) + EMPTY_PORT(0x3a000) + EMPTY_PORT(0x3c000) + EMPTY_PORT(0x3e000) +#undef EMPTY_PORT + + default: + trace_astro_chip_read(addr, size, val); + g_assert_not_reached(); + } + + /* for 32-bit accesses mask return value */ + val = mask_32bit_val(addr, size, val); + + trace_astro_chip_read(addr, size, val); + *data = val; + return ret; +} + +static MemTxResult astro_chip_write_with_attrs(void *opaque, hwaddr addr, + uint64_t val, unsigned size, + MemTxAttrs attrs) +{ + AstroState *s = opaque; + + trace_astro_chip_write(addr, size, val); + + switch ((addr >> 3) << 3) { + case 0x0000: /* ID */ + break; + case 0x0008: /* IOC_CTRL */ + val &= 0x0ffffff; + put_val_in_int64(&s->ioc_ctrl, addr, size, val); + break; + case 0x0010: /* TOC_CLIENT_ID */ + break; + case 0x0030: /* HP-UX 10.20 and 11.11 reads it. No idea. */ + break; + case 0x0300 ... 0x03d8 - 1: /* LMMIO_DIRECT0_BASE... */ + put_val_in_arrary(s->ioc_ranges, 0x300, addr, size, val); + break; + case 0x10200: + case 0x10220: + case 0x10230: /* HP-UX 11.11 reads it. No idea. */ + break; + case 0x22108: /* IOC STATUS_CONTROL */ + put_val_in_int64(&s->ioc_status_ctrl, addr, size, val); + break; + case 0x20200 ... 0x20240 - 1: /* IOC Rope0_Control ... */ + put_val_in_arrary(s->ioc_rope_control, 0x20200, addr, size, val); + break; + case 0x20040: /* IOC Rope config */ + put_val_in_int64(&s->ioc_rope_config, addr, size, val); + break; + case 0x20300: + put_val_in_int64(&s->tlb_ibase, addr, size, val); + break; + case 0x20308: + put_val_in_int64(&s->tlb_imask, addr, size, val); + break; + case 0x20310: + put_val_in_int64(&s->tlb_pcom, addr, size, val); + /* TODO: flush iommu */ + break; + case 0x20318: + put_val_in_int64(&s->tlb_tcnfg, addr, size, val); + break; + case 0x20320: + put_val_in_int64(&s->tlb_pdir_base, addr, size, val); + break; + /* + * empty placeholders for non-existent elroys, e.g. + * func_class, pci config & data + */ +#define EMPTY_PORT(x) case x: case x+8: case x+0x40: case x+0x48: + EMPTY_PORT(0x30000) + EMPTY_PORT(0x32000) + EMPTY_PORT(0x34000) + EMPTY_PORT(0x36000) + EMPTY_PORT(0x38000) + EMPTY_PORT(0x3a000) + EMPTY_PORT(0x3c000) + EMPTY_PORT(0x3e000) + break; +#undef EMPTY_PORT + + default: + /* Controlled by astro_chip_mem_valid above. */ + trace_astro_chip_write(addr, size, val); + g_assert_not_reached(); + } + return MEMTX_OK; +} + +static const MemoryRegionOps astro_chip_ops = { + .read_with_attrs = astro_chip_read_with_attrs, + .write_with_attrs = astro_chip_write_with_attrs, + .endianness = DEVICE_LITTLE_ENDIAN, + .valid = { + .min_access_size = 4, + .max_access_size = 8, + }, + .impl = { + .min_access_size = 4, + .max_access_size = 8, + }, +}; + +static const VMStateDescription vmstate_astro = { + .name = "Astro", + .version_id = 1, + .minimum_version_id = 1, + .fields = (VMStateField[]) { + VMSTATE_UINT64(ioc_ctrl, AstroState), + VMSTATE_UINT64(ioc_status_ctrl, AstroState), + VMSTATE_UINT64_ARRAY(ioc_ranges, AstroState, (0x03d8 - 0x300) / 8), + VMSTATE_UINT64(ioc_rope_config, AstroState), + VMSTATE_UINT64(ioc_status_control, AstroState), + VMSTATE_UINT64(ioc_flush_control, AstroState), + VMSTATE_UINT64_ARRAY(ioc_rope_control, AstroState, 8), + VMSTATE_UINT64(tlb_ibase, AstroState), + VMSTATE_UINT64(tlb_imask, AstroState), + VMSTATE_UINT64(tlb_pcom, AstroState), + VMSTATE_UINT64(tlb_tcnfg, AstroState), + VMSTATE_UINT64(tlb_pdir_base, AstroState), + VMSTATE_END_OF_LIST() + } +}; + +static void astro_reset(DeviceState *dev) +{ + AstroState *s = ASTRO_CHIP(dev); + int i; + + s->ioc_ctrl = 0x29cf; + s->ioc_rope_config = 0xc5f; + s->ioc_flush_control = 0xb03; + s->ioc_status_control = 0; + memset(&s->ioc_rope_control, 0, sizeof(s->ioc_rope_control)); + + /* + * The SBA BASE/MASK registers control CPU -> IO routing. + * The LBA BASE/MASK registers control IO -> System routing (in Elroy) + */ + memset(&s->ioc_ranges, 0, sizeof(s->ioc_ranges)); + s->ioc_ranges[(0x360 - 0x300) / 8] = LMMIO_DIST_BASE_ADDR | 0x01; /* LMMIO_DIST_BASE (SBA) */ + s->ioc_ranges[(0x368 - 0x300) / 8] = 0xfc000000; /* LMMIO_DIST_MASK */ + s->ioc_ranges[(0x370 - 0x300) / 8] = 0; /* LMMIO_DIST_ROUTE */ + s->ioc_ranges[(0x390 - 0x300) / 8] = IOS_DIST_BASE_ADDR | 0x01; /* IOS_DIST_BASE */ + s->ioc_ranges[(0x398 - 0x300) / 8] = 0xffffff0000; /* IOS_DIST_MASK */ + s->ioc_ranges[(0x3a0 - 0x300) / 8] = 0x3400000000000000ULL; /* IOS_DIST_ROUTE */ + s->ioc_ranges[(0x3c0 - 0x300) / 8] = 0xfffee00000; /* IOS_DIRECT_BASE */ + s->ioc_ranges[(0x3c8 - 0x300) / 8] = 0xffffff0000; /* IOS_DIRECT_MASK */ + s->ioc_ranges[(0x3d0 - 0x300) / 8] = 0x0; /* IOS_DIRECT_ROUTE */ + + s->tlb_ibase = 0; + s->tlb_imask = 0; + s->tlb_pcom = 0; + s->tlb_tcnfg = 0; + s->tlb_pdir_base = 0; + + for (i = 0; i < ELROY_NUM; i++) { + elroy_reset(DEVICE(s->elroy[i])); + } +} + +static void astro_init(Object *obj) +{ +} + +static void astro_realize(DeviceState *obj, Error **errp) +{ + AstroState *s = ASTRO_CHIP(obj); + SysBusDevice *sbd = SYS_BUS_DEVICE(obj); + int i; + + memory_region_init_io(&s->this_mem, OBJECT(s), &astro_chip_ops, + s, "astro", 0x40000); + sysbus_init_mmio(sbd, &s->this_mem); + + /* Host memory as seen from Elroys PCI side, via the IOMMU. */ + memory_region_init_iommu(&s->iommu, sizeof(s->iommu), + TYPE_ASTRO_IOMMU_MEMORY_REGION, OBJECT(s), + "iommu-astro", UINT64_MAX); + address_space_init(&s->iommu_as, MEMORY_REGION(&s->iommu), + "bm-pci"); + + /* Create Elroys (PCI host bus chips). */ + for (i = 0; i < ELROY_NUM; i++) { + static const int elroy_hpa_offsets[ELROY_NUM] = { + 0x30000, 0x32000, 0x38000, 0x3c000 }; + static const char elroy_rope_nr[ELROY_NUM] = { + 0, 1, 4, 6 }; /* busnum path, e.g. [10:6] */ + int addr_offset; + ElroyState *elroy; + hwaddr map_addr; + uint64_t map_size; + int rope; + + addr_offset = elroy_hpa_offsets[i]; + rope = elroy_rope_nr[i]; + + elroy = elroy_init(i); + s->elroy[i] = elroy; + elroy->hpa = ASTRO_HPA + addr_offset; + elroy->pci_bus_num = i; + elroy->astro = s; + + /* + * NOTE: we only allow PCI devices on first Elroy for now. + * SeaBIOS will not find devices on the other busses. + */ + if (i > 0) { + qbus_mark_full(&PCI_HOST_BRIDGE(elroy)->bus->qbus); + } + + /* map elroy config addresses into Astro space */ + memory_region_add_subregion(&s->this_mem, addr_offset, + &elroy->this_mem); + + /* LMMIO */ + elroy->mmio_base[(0x0200 - 0x200) / 8] = 0xf0000001; + elroy->mmio_base[(0x0208 - 0x200) / 8] = 0xf8000000; + /* GMMIO */ + elroy->mmio_base[(0x0210 - 0x200) / 8] = 0x000000f800000001; + elroy->mmio_base[(0x0218 - 0x200) / 8] = 0x000000ff80000000; + /* WLMMIO */ + elroy->mmio_base[(0x0220 - 0x200) / 8] = 0xf0000001; + elroy->mmio_base[(0x0228 - 0x200) / 8] = 0xf0000000; + /* WGMMIO */ + elroy->mmio_base[(0x0230 - 0x200) / 8] = 0x000000f800000001; + elroy->mmio_base[(0x0238 - 0x200) / 8] = 0x000000fc00000000; + /* IOS_BASE */ + map_size = IOS_DIST_BASE_SIZE / ROPES_PER_IOC; + elroy->mmio_base[(0x0240 - 0x200) / 8] = rope * map_size | 0x01; + elroy->mmio_base[(0x0248 - 0x200) / 8] = 0x0000e000; + + /* map elroys mmio */ + map_size = LMMIO_DIST_BASE_SIZE / ROPES_PER_IOC; + map_addr = (uint32_t) (LMMIO_DIST_BASE_ADDR + rope * map_size); + memory_region_init_alias(&elroy->pci_mmio_alias, OBJECT(elroy), + "pci-mmio-alias", + &elroy->pci_mmio, map_addr, map_size); + memory_region_add_subregion(get_system_memory(), map_addr, + &elroy->pci_mmio_alias); + + map_size = IOS_DIST_BASE_SIZE / ROPES_PER_IOC; + map_addr = (uint32_t) (IOS_DIST_BASE_ADDR + rope * map_size); + memory_region_add_subregion(get_system_memory(), map_addr, + &elroy->pci_io); + + /* Host memory as seen from the PCI side, via the IOMMU. */ + pci_setup_iommu(PCI_HOST_BRIDGE(elroy)->bus, elroy_pcihost_set_iommu, + elroy); + } +} + +static void astro_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + + dc->reset = astro_reset; + dc->vmsd = &vmstate_astro; + dc->realize = astro_realize; + /* + * astro with elroys are hard part of the newer PA2.0 machines and can not + * be created without that hardware + */ + dc->user_creatable = false; +} + +static const TypeInfo astro_chip_info = { + .name = TYPE_ASTRO_CHIP, + .parent = TYPE_SYS_BUS_DEVICE, + .instance_init = astro_init, + .instance_size = sizeof(AstroState), + .class_init = astro_class_init, +}; + +static void astro_iommu_memory_region_class_init(ObjectClass *klass, + void *data) +{ + IOMMUMemoryRegionClass *imrc = IOMMU_MEMORY_REGION_CLASS(klass); + + imrc->translate = astro_translate_iommu; +} + +static const TypeInfo astro_iommu_memory_region_info = { + .parent = TYPE_IOMMU_MEMORY_REGION, + .name = TYPE_ASTRO_IOMMU_MEMORY_REGION, + .class_init = astro_iommu_memory_region_class_init, +}; + + +static void astro_register_types(void) +{ + type_register_static(&astro_chip_info); + type_register_static(&astro_iommu_memory_region_info); +} + +type_init(astro_register_types) diff --git a/hw/pci-host/trace-events b/hw/pci-host/trace-events index 9d216bb89f..b2f47e6335 100644 --- a/hw/pci-host/trace-events +++ b/hw/pci-host/trace-events @@ -46,3 +46,14 @@ pnv_phb4_xive_notify_abt(uint64_t notif_port, uint64_t data) "notif=@0x%"PRIx64" dino_chip_mem_valid(uint64_t addr, uint32_t val) "access to addr 0x%"PRIx64" is %d" dino_chip_read(uint64_t addr, uint32_t val) "addr 0x%"PRIx64" val 0x%08x" dino_chip_write(uint64_t addr, uint32_t val) "addr 0x%"PRIx64" val 0x%08x" + +# astro.c +astro_chip_mem_valid(uint64_t addr, uint32_t val) "access to addr 0x%"PRIx64" is %d" +astro_chip_read(uint64_t addr, int size, uint64_t val) "addr 0x%"PRIx64" size %d val 0x%"PRIx64 +astro_chip_write(uint64_t addr, int size, uint64_t val) "addr 0x%"PRIx64" size %d val 0x%"PRIx64 +elroy_read(uint64_t addr, int size, uint64_t val) "addr 0x%"PRIx64" size %d val 0x%"PRIx64 +elroy_write(uint64_t addr, int size, uint64_t val) "addr 0x%"PRIx64" size %d val 0x%"PRIx64 +elroy_pci_config_data_read(uint64_t addr, int size, uint64_t val) "addr 0x%"PRIx64" size %d val 0x%"PRIx64 +elroy_pci_config_data_write(uint64_t addr, int size, uint64_t val) "addr 0x%"PRIx64" size %d val 0x%"PRIx64 +iosapic_reg_write(uint64_t reg_select, int size, uint64_t val) "reg_select 0x%"PRIx64" size %d val 0x%"PRIx64 +iosapic_reg_read(uint64_t reg_select, int size, uint64_t val) "reg_select 0x%"PRIx64" size %d val 0x%"PRIx64 diff --git a/include/hw/pci-host/astro.h b/include/hw/pci-host/astro.h new file mode 100644 index 0000000000..f63fd220f3 --- /dev/null +++ b/include/hw/pci-host/astro.h @@ -0,0 +1,92 @@ +/* + * HP-PARISC Astro Bus connector with Elroy PCI host bridges + */ + +#ifndef ASTRO_H +#define ASTRO_H + +#include "hw/pci/pci_host.h" + +#define ASTRO_HPA 0xfed00000 + +#define ROPES_PER_IOC 8 /* per Ike half or Pluto/Astro */ + +#define TYPE_ASTRO_CHIP "astro-chip" +OBJECT_DECLARE_SIMPLE_TYPE(AstroState, ASTRO_CHIP) + +#define TYPE_ELROY_PCI_HOST_BRIDGE "elroy-pcihost" +OBJECT_DECLARE_SIMPLE_TYPE(ElroyState, ELROY_PCI_HOST_BRIDGE) + +#define ELROY_NUM 4 /* # of Elroys */ +#define ELROY_IRQS 8 /* IOSAPIC IRQs */ + +/* ASTRO Memory and I/O regions */ +#define LMMIO_DIST_BASE_ADDR 0xf4000000ULL +#define LMMIO_DIST_BASE_SIZE 0x4000000ULL + +#define IOS_DIST_BASE_ADDR 0xfffee00000ULL +#define IOS_DIST_BASE_SIZE 0x10000ULL + +struct AstroState; + +struct ElroyState { + PCIHostState parent_obj; + + /* parent Astro device */ + struct AstroState *astro; + + /* HPA of this Elroy */ + hwaddr hpa; + + /* PCI bus number (Elroy number) */ + unsigned int pci_bus_num; + + uint64_t config_address; + uint64_t config_reg_elroy; + + uint64_t status_control; + uint64_t arb_mask; + uint64_t mmio_base[(0x0250 - 0x200) / 8]; + uint64_t error_config; + + uint32_t iosapic_reg_select; + uint64_t iosapic_reg[0x20]; + + uint32_t ilr; + + MemoryRegion this_mem; + + MemoryRegion pci_mmio; + MemoryRegion pci_mmio_alias; + MemoryRegion pci_hole; + MemoryRegion pci_io; +}; + +struct AstroState { + PCIHostState parent_obj; + + uint64_t ioc_ctrl; + uint64_t ioc_status_ctrl; + uint64_t ioc_ranges[(0x03d8 - 0x300) / 8]; + uint64_t ioc_rope_config; + uint64_t ioc_status_control; + uint64_t ioc_flush_control; + uint64_t ioc_rope_control[8]; + uint64_t tlb_ibase; + uint64_t tlb_imask; + uint64_t tlb_pcom; + uint64_t tlb_tcnfg; + uint64_t tlb_pdir_base; + + struct ElroyState *elroy[ELROY_NUM]; + + MemoryRegion this_mem; + + MemoryRegion pci_mmio; + MemoryRegion pci_io; + + IOMMUMemoryRegion iommu; + AddressSpace iommu_as; +}; + +#endif From 1a960c8915ff3d8827d09a4afacf15b1f12c5e04 Mon Sep 17 00:00:00 2001 From: Helge Deller Date: Sat, 14 Oct 2023 06:55:16 +0200 Subject: [PATCH 0880/1077] pci-host: Wire up new Astro/Elroy PCI bridge Allow the Astro source to be built. Signed-off-by: Helge Deller --- hw/hppa/Kconfig | 1 + hw/pci-host/Kconfig | 4 ++++ hw/pci-host/meson.build | 1 + 3 files changed, 6 insertions(+) diff --git a/hw/hppa/Kconfig b/hw/hppa/Kconfig index 5dd8b5b21e..ff8528aaa8 100644 --- a/hw/hppa/Kconfig +++ b/hw/hppa/Kconfig @@ -3,6 +3,7 @@ config HPPA_B160L imply PCI_DEVICES imply E1000_PCI imply VIRTIO_VGA + select ASTRO select DINO select LASI select SERIAL diff --git a/hw/pci-host/Kconfig b/hw/pci-host/Kconfig index a07070eddf..54a609d2ca 100644 --- a/hw/pci-host/Kconfig +++ b/hw/pci-host/Kconfig @@ -82,6 +82,10 @@ config DINO bool select PCI +config ASTRO + bool + select PCI + config GT64120 bool select PCI diff --git a/hw/pci-host/meson.build b/hw/pci-host/meson.build index 64eada76fe..f891f026cb 100644 --- a/hw/pci-host/meson.build +++ b/hw/pci-host/meson.build @@ -27,6 +27,7 @@ pci_ss.add(when: 'CONFIG_MV64361', if_true: files('mv64361.c')) pci_ss.add(when: 'CONFIG_VERSATILE_PCI', if_true: files('versatile.c')) # HPPA devices +pci_ss.add(when: 'CONFIG_ASTRO', if_true: files('astro.c')) pci_ss.add(when: 'CONFIG_DINO', if_true: files('dino.c')) system_ss.add_all(when: 'CONFIG_PCI', if_true: pci_ss) From ae759c96c3174ccbc1438b2b9ee265bee6a167a5 Mon Sep 17 00:00:00 2001 From: Helge Deller Date: Sat, 14 Oct 2023 19:48:27 +0200 Subject: [PATCH 0881/1077] MAINTAINERS: Update HP-PARISC entries Add the new HP C3700 machine, the new Astro PCI host and add the missing entry for the seabios-hppa directory. Signed-off-by: Helge Deller --- MAINTAINERS | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/MAINTAINERS b/MAINTAINERS index ceea4c2bf2..68d086a0f3 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1174,7 +1174,7 @@ F: hw/*/etraxfs_*.c HP-PARISC Machines ------------------ -HP B160L +HP B160L, HP C3700 M: Richard Henderson R: Helge Deller S: Odd Fixes @@ -1182,11 +1182,14 @@ F: configs/devices/hppa-softmmu/default.mak F: hw/hppa/ F: hw/net/*i82596* F: hw/misc/lasi.c +F: hw/pci-host/astro.c F: hw/pci-host/dino.c F: include/hw/misc/lasi.h F: include/hw/net/lasi_82596.h +F: include/hw/pci-host/astro.h F: include/hw/pci-host/dino.h F: pc-bios/hppa-firmware.img +F: roms/seabios-hppa/ LoongArch Machines ------------------ From bcd4dd4c22f2df17def72668c75cdf01fb47b6ff Mon Sep 17 00:00:00 2001 From: Helge Deller Date: Sat, 14 Oct 2023 07:15:10 +0200 Subject: [PATCH 0882/1077] hw/hppa: Export machine name, BTLBs, power-button address via fw_cfg Provide necessary info to SeaBIOS-hppa. Signed-off-by: Helge Deller --- hw/hppa/machine.c | 22 +++++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) diff --git a/hw/hppa/machine.c b/hw/hppa/machine.c index c6d8deffcf..de925259ea 100644 --- a/hw/hppa/machine.c +++ b/hw/hppa/machine.c @@ -118,11 +118,13 @@ static void fw_cfg_boot_set(void *opaque, const char *boot_device, fw_cfg_modify_i16(opaque, FW_CFG_BOOT_DEVICE, boot_device[0]); } -static FWCfgState *create_fw_cfg(MachineState *ms) +static FWCfgState *create_fw_cfg(MachineState *ms, PCIBus *pci_bus) { FWCfgState *fw_cfg; uint64_t val; const char qemu_version[] = QEMU_VERSION; + MachineClass *mc = MACHINE_GET_CLASS(ms); + int len; fw_cfg = fw_cfg_init_mem(FW_CFG_IO_BASE, FW_CFG_IO_BASE + 4); fw_cfg_add_i16(fw_cfg, FW_CFG_NB_CPUS, ms->smp.cpus); @@ -137,8 +139,20 @@ static FWCfgState *create_fw_cfg(MachineState *ms) fw_cfg_add_file(fw_cfg, "/etc/cpu/tlb_entries", g_memdup(&val, sizeof(val)), sizeof(val)); + val = cpu_to_le64(HPPA_BTLB_ENTRIES); + fw_cfg_add_file(fw_cfg, "/etc/cpu/btlb_entries", + g_memdup(&val, sizeof(val)), sizeof(val)); + + len = strlen(mc->name) + 1; + fw_cfg_add_file(fw_cfg, "/etc/hppa/machine", + g_memdup(mc->name, len), len); + val = cpu_to_le64(HPA_POWER_BUTTON); - fw_cfg_add_file(fw_cfg, "/etc/power-button-addr", + fw_cfg_add_file(fw_cfg, "/etc/hppa/power-button-addr", + g_memdup(&val, sizeof(val)), sizeof(val)); + + val = cpu_to_le64(CPU_HPA + 24); + fw_cfg_add_file(fw_cfg, "/etc/hppa/DebugOutputPort", g_memdup(&val, sizeof(val)), sizeof(val)); fw_cfg_add_i16(fw_cfg, FW_CFG_BOOT_DEVICE, ms->boot_config.order[0]); @@ -148,6 +162,8 @@ static FWCfgState *create_fw_cfg(MachineState *ms) g_memdup(qemu_version, sizeof(qemu_version)), sizeof(qemu_version)); + fw_cfg_add_extra_pci_roots(pci_bus, fw_cfg); + return fw_cfg; } @@ -250,7 +266,7 @@ static void machine_hppa_init(MachineState *machine) parallel_hds[0]); /* fw_cfg configuration interface */ - create_fw_cfg(machine); + create_fw_cfg(machine, pci_bus); /* SCSI disk setup. */ dev = DEVICE(pci_create_simple(pci_bus, -1, "lsi53c895a")); From e2c41ee557f4389d577ad54b1c131d2e0b558558 Mon Sep 17 00:00:00 2001 From: Helge Deller Date: Sat, 14 Oct 2023 07:25:02 +0200 Subject: [PATCH 0883/1077] hw/hppa: Provide RTC and DebugOutputPort on CPU #0 For SeaBIOS-hppa, the RTC and DebugOutputPort were in the I/O area of the LASI chip of the emulated B160L machine. Since we will add other machines without a LASI chip, move the emulated devices into the I/O area of CPU#0 instead. Signed-off-by: Helge Deller --- hw/hppa/hppa_hardware.h | 1 - hw/hppa/machine.c | 67 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 67 insertions(+), 1 deletion(-) diff --git a/hw/hppa/hppa_hardware.h b/hw/hppa/hppa_hardware.h index a5ac3dd0fd..a9be7bb851 100644 --- a/hw/hppa/hppa_hardware.h +++ b/hw/hppa/hppa_hardware.h @@ -18,7 +18,6 @@ #define LASI_UART_HPA 0xffd05000 #define LASI_SCSI_HPA 0xffd06000 #define LASI_LAN_HPA 0xffd07000 -#define LASI_RTC_HPA 0xffd09000 #define LASI_LPT_HPA 0xffd02000 #define LASI_AUDIO_HPA 0xffd04000 #define LASI_PS2KBD_HPA 0xffd08000 diff --git a/hw/hppa/machine.c b/hw/hppa/machine.c index de925259ea..d459ba631b 100644 --- a/hw/hppa/machine.c +++ b/hw/hppa/machine.c @@ -103,6 +103,63 @@ static ISABus *hppa_isa_bus(void) return isa_bus; } +/* + * Helper functions to emulate RTC clock and DebugOutputPort + */ +static time_t rtc_ref; + +static uint64_t io_cpu_read(void *opaque, hwaddr addr, unsigned size) +{ + uint64_t val = 0; + + switch (addr) { + case 0: /* RTC clock */ + val = time(NULL); + val += rtc_ref; + break; + case 8: /* DebugOutputPort */ + return 0xe9; /* readback */ + } + return val; +} + +static void io_cpu_write(void *opaque, hwaddr addr, + uint64_t val, unsigned size) +{ + unsigned char ch; + Chardev *debugout; + + switch (addr) { + case 0: /* RTC clock */ + rtc_ref = val - time(NULL); + break; + case 8: /* DebugOutputPort */ + ch = val; + debugout = serial_hd(0); + if (debugout) { + qemu_chr_fe_write_all(debugout->be, &ch, 1); + } else { + fprintf(stderr, "%c", ch); + } + break; + } +} + +static const MemoryRegionOps hppa_io_helper_ops = { + .read = io_cpu_read, + .write = io_cpu_write, + .endianness = DEVICE_BIG_ENDIAN, + .valid = { + .min_access_size = 1, + .max_access_size = 8, + }, + .impl = { + .min_access_size = 1, + .max_access_size = 8, + }, +}; + + static uint64_t cpu_hppa_to_phys(void *opaque, uint64_t addr) { addr &= (0x10000000 - 1); @@ -151,6 +208,10 @@ static FWCfgState *create_fw_cfg(MachineState *ms, PCIBus *pci_bus) fw_cfg_add_file(fw_cfg, "/etc/hppa/power-button-addr", g_memdup(&val, sizeof(val)), sizeof(val)); + val = cpu_to_le64(CPU_HPA + 16); + fw_cfg_add_file(fw_cfg, "/etc/hppa/rtc-addr", + g_memdup(&val, sizeof(val)), sizeof(val)); + val = cpu_to_le64(CPU_HPA + 24); fw_cfg_add_file(fw_cfg, "/etc/hppa/DebugOutputPort", g_memdup(&val, sizeof(val)), sizeof(val)); @@ -222,6 +283,12 @@ static void machine_hppa_init(MachineState *machine) g_free(name); } + /* RTC and DebugOutputPort on CPU #0 */ + cpu_region = g_new(MemoryRegion, 1); + memory_region_init_io(cpu_region, OBJECT(cpu[0]), &hppa_io_helper_ops, + cpu[0], "cpu0-io-rtc", 2 * sizeof(uint64_t)); + memory_region_add_subregion(addr_space, CPU_HPA + 16, cpu_region); + /* Main memory region. */ if (machine->ram_size > 3 * GiB) { error_report("RAM size is currently restricted to 3GB"); From 7df6f7511769af63c209d2fdcd6c7638f680e35a Mon Sep 17 00:00:00 2001 From: Helge Deller Date: Sat, 14 Oct 2023 07:41:18 +0200 Subject: [PATCH 0884/1077] hw/hppa: Split out machine creation This is a preparation patch to allow the creation of additional hppa machine. It splits out the creation of the machine into a - machine_HP_common_init_cpus(), and a - machine_HP_common_init_tail() function. This will allow to reuse the basic functions which are common to all parisc machines. Signed-off-by: Helge Deller --- hw/hppa/machine.c | 171 +++++++++++++++++++++++++++------------------- 1 file changed, 99 insertions(+), 72 deletions(-) diff --git a/hw/hppa/machine.c b/hw/hppa/machine.c index d459ba631b..2bd02508a9 100644 --- a/hw/hppa/machine.c +++ b/hw/hppa/machine.c @@ -23,6 +23,7 @@ #include "hw/net/lasi_82596.h" #include "hw/nmi.h" #include "hw/pci/pci.h" +#include "hw/pci/pci_device.h" #include "hw/pci-host/dino.h" #include "hw/misc/lasi.h" #include "hppa_hardware.h" @@ -37,6 +38,7 @@ #define enable_lasi_lan() 0 +static DeviceState *lasi_dev; static void hppa_powerdown_req(Notifier *n, void *opaque) { @@ -250,29 +252,20 @@ static DinoState *dino_init(MemoryRegion *addr_space) return DINO_PCI_HOST_BRIDGE(dev); } -static void machine_hppa_init(MachineState *machine) +/* + * Step 1: Create CPUs and Memory + */ +static void machine_HP_common_init_cpus(MachineState *machine) { - const char *kernel_filename = machine->kernel_filename; - const char *kernel_cmdline = machine->kernel_cmdline; - const char *initrd_filename = machine->initrd_filename; - MachineClass *mc = MACHINE_GET_CLASS(machine); - DeviceState *dev, *dino_dev, *lasi_dev; - PCIBus *pci_bus; - ISABus *isa_bus; - char *firmware_filename; - uint64_t firmware_low, firmware_high; - long size; - uint64_t kernel_entry = 0, kernel_low, kernel_high; MemoryRegion *addr_space = get_system_memory(); - MemoryRegion *rom_region; MemoryRegion *cpu_region; long i; unsigned int smp_cpus = machine->smp.cpus; - SysBusDevice *s; + char *name; /* Create CPUs. */ for (i = 0; i < smp_cpus; i++) { - char *name = g_strdup_printf("cpu%ld-io-eir", i); + name = g_strdup_printf("cpu%ld-io-eir", i); cpu[i] = HPPA_CPU(cpu_create(machine->cpu_type)); cpu_region = g_new(MemoryRegion, 1); @@ -295,45 +288,27 @@ static void machine_hppa_init(MachineState *machine) exit(EXIT_FAILURE); } memory_region_add_subregion_overlap(addr_space, 0, machine->ram, -1); +} - - /* Init Lasi chip */ - lasi_dev = DEVICE(lasi_init()); - memory_region_add_subregion(addr_space, LASI_HPA, - sysbus_mmio_get_region( - SYS_BUS_DEVICE(lasi_dev), 0)); - - /* Init Dino (PCI host bus chip). */ - dino_dev = DEVICE(dino_init(addr_space)); - memory_region_add_subregion(addr_space, DINO_HPA, - sysbus_mmio_get_region( - SYS_BUS_DEVICE(dino_dev), 0)); - pci_bus = PCI_BUS(qdev_get_child_bus(dino_dev, "pci")); - assert(pci_bus); - - /* Create ISA bus. */ - isa_bus = hppa_isa_bus(); - assert(isa_bus); - - /* Realtime clock, used by firmware for PDC_TOD call. */ - mc146818_rtc_init(isa_bus, 2000, NULL); - - /* Serial ports: Lasi and Dino use a 7.272727 MHz clock. */ - serial_mm_init(addr_space, LASI_UART_HPA + 0x800, 0, - qdev_get_gpio_in(lasi_dev, LASI_IRQ_UART_HPA), 7272727 / 16, - serial_hd(0), DEVICE_BIG_ENDIAN); - - serial_mm_init(addr_space, DINO_UART_HPA + 0x800, 0, - qdev_get_gpio_in(dino_dev, DINO_IRQ_RS232INT), 7272727 / 16, - serial_hd(1), DEVICE_BIG_ENDIAN); - - /* Parallel port */ - parallel_mm_init(addr_space, LASI_LPT_HPA + 0x800, 0, - qdev_get_gpio_in(lasi_dev, LASI_IRQ_LAN_HPA), - parallel_hds[0]); - - /* fw_cfg configuration interface */ - create_fw_cfg(machine, pci_bus); +/* + * Last creation step: Add SCSI discs, NICs, graphics & load firmware + */ +static void machine_HP_common_init_tail(MachineState *machine, PCIBus *pci_bus) +{ + const char *kernel_filename = machine->kernel_filename; + const char *kernel_cmdline = machine->kernel_cmdline; + const char *initrd_filename = machine->initrd_filename; + MachineClass *mc = MACHINE_GET_CLASS(machine); + DeviceState *dev; + char *firmware_filename; + uint64_t firmware_low, firmware_high; + long size; + uint64_t kernel_entry = 0, kernel_low, kernel_high; + MemoryRegion *addr_space = get_system_memory(); + MemoryRegion *rom_region; + long i; + unsigned int smp_cpus = machine->smp.cpus; + SysBusDevice *s; /* SCSI disk setup. */ dev = DEVICE(pci_create_simple(pci_bus, -1, "lsi53c895a")); @@ -361,21 +336,12 @@ static void machine_hppa_init(MachineState *machine) } } - /* PS/2 Keyboard/Mouse */ - dev = qdev_new(TYPE_LASIPS2); - sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal); - sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, - qdev_get_gpio_in(lasi_dev, LASI_IRQ_PS2KBD_HPA)); - memory_region_add_subregion(addr_space, LASI_PS2KBD_HPA, - sysbus_mmio_get_region(SYS_BUS_DEVICE(dev), - 0)); - memory_region_add_subregion(addr_space, LASI_PS2KBD_HPA + 0x100, - sysbus_mmio_get_region(SYS_BUS_DEVICE(dev), - 1)); - /* register power switch emulation */ qemu_register_powerdown_notifier(&hppa_system_powerdown_notifier); + /* fw_cfg configuration interface */ + create_fw_cfg(machine, pci_bus); + /* Load firmware. Given that this is not "real" firmware, but one explicitly written for the emulation, we might as well load it directly from an ELF image. */ @@ -493,6 +459,67 @@ static void machine_hppa_init(MachineState *machine) cpu[0]->env.gr[19] = FW_CFG_IO_BASE; } +/* + * Create HP B160L workstation + */ +static void machine_HP_B160L_init(MachineState *machine) +{ + DeviceState *dev, *dino_dev; + MemoryRegion *addr_space = get_system_memory(); + ISABus *isa_bus; + PCIBus *pci_bus; + + /* Create CPUs and RAM. */ + machine_HP_common_init_cpus(machine); + + /* Init Lasi chip */ + lasi_dev = DEVICE(lasi_init()); + memory_region_add_subregion(addr_space, LASI_HPA, + sysbus_mmio_get_region( + SYS_BUS_DEVICE(lasi_dev), 0)); + + /* Init Dino (PCI host bus chip). */ + dino_dev = DEVICE(dino_init(addr_space)); + memory_region_add_subregion(addr_space, DINO_HPA, + sysbus_mmio_get_region( + SYS_BUS_DEVICE(dino_dev), 0)); + pci_bus = PCI_BUS(qdev_get_child_bus(dino_dev, "pci")); + assert(pci_bus); + + /* Create ISA bus, needed for PS/2 kbd/mouse port emulation */ + isa_bus = hppa_isa_bus(); + assert(isa_bus); + + /* Serial ports: Lasi and Dino use a 7.272727 MHz clock. */ + serial_mm_init(addr_space, LASI_UART_HPA + 0x800, 0, + qdev_get_gpio_in(lasi_dev, LASI_IRQ_UART_HPA), 7272727 / 16, + serial_hd(0), DEVICE_BIG_ENDIAN); + + serial_mm_init(addr_space, DINO_UART_HPA + 0x800, 0, + qdev_get_gpio_in(dino_dev, DINO_IRQ_RS232INT), 7272727 / 16, + serial_hd(1), DEVICE_BIG_ENDIAN); + + /* Parallel port */ + parallel_mm_init(addr_space, LASI_LPT_HPA + 0x800, 0, + qdev_get_gpio_in(lasi_dev, LASI_IRQ_LAN_HPA), + parallel_hds[0]); + + /* PS/2 Keyboard/Mouse */ + dev = qdev_new(TYPE_LASIPS2); + sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal); + sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, + qdev_get_gpio_in(lasi_dev, LASI_IRQ_PS2KBD_HPA)); + memory_region_add_subregion(addr_space, LASI_PS2KBD_HPA, + sysbus_mmio_get_region(SYS_BUS_DEVICE(dev), + 0)); + memory_region_add_subregion(addr_space, LASI_PS2KBD_HPA + 0x100, + sysbus_mmio_get_region(SYS_BUS_DEVICE(dev), + 1)); + + /* Add SCSI discs, NICs, graphics & load firmware */ + machine_HP_common_init_tail(machine, pci_bus); +} + static void hppa_machine_reset(MachineState *ms, ShutdownCause reason) { unsigned int smp_cpus = ms->smp.cpus; @@ -541,14 +568,14 @@ static void hppa_nmi(NMIState *n, int cpu_index, Error **errp) } } -static void hppa_machine_init_class_init(ObjectClass *oc, void *data) +static void HP_B160L_machine_init_class_init(ObjectClass *oc, void *data) { MachineClass *mc = MACHINE_CLASS(oc); NMIClass *nc = NMI_CLASS(oc); - mc->desc = "HPPA B160L machine"; + mc->desc = "HP B160L workstation"; mc->default_cpu_type = TYPE_HPPA_CPU; - mc->init = machine_hppa_init; + mc->init = machine_HP_B160L_init; mc->reset = hppa_machine_reset; mc->block_default_type = IF_SCSI; mc->max_cpus = HPPA_MAX_CPUS; @@ -562,10 +589,10 @@ static void hppa_machine_init_class_init(ObjectClass *oc, void *data) nc->nmi_monitor_handler = hppa_nmi; } -static const TypeInfo hppa_machine_init_typeinfo = { - .name = MACHINE_TYPE_NAME("hppa"), +static const TypeInfo HP_B160L_machine_init_typeinfo = { + .name = MACHINE_TYPE_NAME("B160L"), .parent = TYPE_MACHINE, - .class_init = hppa_machine_init_class_init, + .class_init = HP_B160L_machine_init_class_init, .interfaces = (InterfaceInfo[]) { { TYPE_NMI }, { } @@ -574,7 +601,7 @@ static const TypeInfo hppa_machine_init_typeinfo = { static void hppa_machine_init_register_types(void) { - type_register_static(&hppa_machine_init_typeinfo); + type_register_static(&HP_B160L_machine_init_typeinfo); } type_init(hppa_machine_init_register_types) From 2ed4faa03fa92e3ab9160c09f3eb866fbdd60ecc Mon Sep 17 00:00:00 2001 From: Helge Deller Date: Sat, 14 Oct 2023 07:47:05 +0200 Subject: [PATCH 0885/1077] hw/hppa: Add new HP C3700 machine Add code to create an emulated C3700 machine. It includes the following components: - HP Powerbar SP2 Diva BMC card (serial port only) - PCI 4x serial card (for serial ports #1-#4) - USB OHCI controller with USB keyboard and USB mouse Signed-off-by: Helge Deller --- hw/hppa/machine.c | 101 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 101 insertions(+) diff --git a/hw/hppa/machine.c b/hw/hppa/machine.c index 2bd02508a9..67d4d1b5e0 100644 --- a/hw/hppa/machine.c +++ b/hw/hppa/machine.c @@ -22,8 +22,10 @@ #include "hw/input/lasips2.h" #include "hw/net/lasi_82596.h" #include "hw/nmi.h" +#include "hw/usb.h" #include "hw/pci/pci.h" #include "hw/pci/pci_device.h" +#include "hw/pci-host/astro.h" #include "hw/pci-host/dino.h" #include "hw/misc/lasi.h" #include "hppa_hardware.h" @@ -300,6 +302,7 @@ static void machine_HP_common_init_tail(MachineState *machine, PCIBus *pci_bus) const char *initrd_filename = machine->initrd_filename; MachineClass *mc = MACHINE_GET_CLASS(machine); DeviceState *dev; + PCIDevice *pci_dev; char *firmware_filename; uint64_t firmware_low, firmware_high; long size; @@ -336,6 +339,36 @@ static void machine_HP_common_init_tail(MachineState *machine, PCIBus *pci_bus) } } + /* BMC board: HP Powerbar SP2 Diva (with console only) */ + pci_dev = pci_new(-1, "pci-serial"); + if (!lasi_dev) { + /* bind default keyboard/serial to Diva card */ + qdev_prop_set_chr(DEVICE(pci_dev), "chardev", serial_hd(0)); + } + qdev_prop_set_uint8(DEVICE(pci_dev), "prog_if", 0); + pci_realize_and_unref(pci_dev, pci_bus, &error_fatal); + pci_config_set_vendor_id(pci_dev->config, PCI_VENDOR_ID_HP); + pci_config_set_device_id(pci_dev->config, 0x1048); + pci_set_word(&pci_dev->config[PCI_SUBSYSTEM_VENDOR_ID], PCI_VENDOR_ID_HP); + pci_set_word(&pci_dev->config[PCI_SUBSYSTEM_ID], 0x1227); /* Powerbar */ + + /* create a second serial PCI card when running Astro */ + if (!lasi_dev) { + pci_dev = pci_new(-1, "pci-serial-4x"); + qdev_prop_set_chr(DEVICE(pci_dev), "chardev1", serial_hd(1)); + qdev_prop_set_chr(DEVICE(pci_dev), "chardev2", serial_hd(2)); + qdev_prop_set_chr(DEVICE(pci_dev), "chardev3", serial_hd(3)); + qdev_prop_set_chr(DEVICE(pci_dev), "chardev4", serial_hd(4)); + pci_realize_and_unref(pci_dev, pci_bus, &error_fatal); + } + + /* create USB OHCI controller for USB keyboard & mouse on Astro machines */ + if (!lasi_dev && machine->enable_graphics) { + pci_create_simple(pci_bus, -1, "pci-ohci"); + usb_create_simple(usb_bus_find(-1), "usb-kbd"); + usb_create_simple(usb_bus_find(-1), "usb-mouse"); + } + /* register power switch emulation */ qemu_register_powerdown_notifier(&hppa_system_powerdown_notifier); @@ -520,6 +553,42 @@ static void machine_HP_B160L_init(MachineState *machine) machine_HP_common_init_tail(machine, pci_bus); } +static AstroState *astro_init(void) +{ + DeviceState *dev; + + dev = qdev_new(TYPE_ASTRO_CHIP); + sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal); + + return ASTRO_CHIP(dev); +} + +/* + * Create HP C3700 workstation + */ +static void machine_HP_C3700_init(MachineState *machine) +{ + PCIBus *pci_bus; + AstroState *astro; + DeviceState *astro_dev; + MemoryRegion *addr_space = get_system_memory(); + + /* Create CPUs and RAM. */ + machine_HP_common_init_cpus(machine); + + /* Init Astro and the Elroys (PCI host bus chips). */ + astro = astro_init(); + astro_dev = DEVICE(astro); + memory_region_add_subregion(addr_space, ASTRO_HPA, + sysbus_mmio_get_region( + SYS_BUS_DEVICE(astro_dev), 0)); + pci_bus = PCI_BUS(qdev_get_child_bus(DEVICE(astro->elroy[0]), "pci")); + assert(pci_bus); + + /* Add SCSI discs, NICs, graphics & load firmware */ + machine_HP_common_init_tail(machine, pci_bus); +} + static void hppa_machine_reset(MachineState *ms, ShutdownCause reason) { unsigned int smp_cpus = ms->smp.cpus; @@ -599,9 +668,41 @@ static const TypeInfo HP_B160L_machine_init_typeinfo = { }, }; +static void HP_C3700_machine_init_class_init(ObjectClass *oc, void *data) +{ + MachineClass *mc = MACHINE_CLASS(oc); + NMIClass *nc = NMI_CLASS(oc); + + mc->desc = "HP C3700 workstation"; + mc->default_cpu_type = TYPE_HPPA_CPU; + mc->init = machine_HP_C3700_init; + mc->reset = hppa_machine_reset; + mc->block_default_type = IF_SCSI; + mc->max_cpus = HPPA_MAX_CPUS; + mc->default_cpus = 1; + mc->is_default = false; + mc->default_ram_size = 1024 * MiB; + mc->default_boot_order = "cd"; + mc->default_ram_id = "ram"; + mc->default_nic = "tulip"; + + nc->nmi_monitor_handler = hppa_nmi; +} + +static const TypeInfo HP_C3700_machine_init_typeinfo = { + .name = MACHINE_TYPE_NAME("C3700"), + .parent = TYPE_MACHINE, + .class_init = HP_C3700_machine_init_class_init, + .interfaces = (InterfaceInfo[]) { + { TYPE_NMI }, + { } + }, +}; + static void hppa_machine_init_register_types(void) { type_register_static(&HP_B160L_machine_init_typeinfo); + type_register_static(&HP_C3700_machine_init_typeinfo); } type_init(hppa_machine_init_register_types) From 3da4aef81ca61c82c67b86af369ccd251607622e Mon Sep 17 00:00:00 2001 From: Nina Schoetterl-Glausch Date: Mon, 16 Oct 2023 20:39:05 +0200 Subject: [PATCH 0886/1077] qapi: machine.json: change docs regarding CPU topology Clarify roles of different architectures. Also change things a bit in anticipation of additional members being added. Suggested-by: Markus Armbruster Signed-off-by: Nina Schoetterl-Glausch Message-ID: <20231016183925.2384704-2-nsg@linux.ibm.com> Acked-by: Markus Armbruster [thuth: Updated some comments according to suggestions from Markus] Signed-off-by: Thomas Huth --- qapi/machine.json | 65 ++++++++++++++++++++++++++++++----------------- 1 file changed, 41 insertions(+), 24 deletions(-) diff --git a/qapi/machine.json b/qapi/machine.json index a08b6576ca..f053245756 100644 --- a/qapi/machine.json +++ b/qapi/machine.json @@ -71,8 +71,7 @@ # # @thread-id: ID of the underlying host thread # -# @props: properties describing to which node/socket/core/thread -# virtual CPU belongs to, provided if supported by board +# @props: properties associated with a virtual CPU, e.g. the socket id # # @target: the QEMU system emulation target, which determines which # additional fields will be listed (since 3.0) @@ -899,28 +898,35 @@ # should be passed by management with device_add command when a CPU is # being hotplugged. # +# Which members are optional and which mandatory depends on the +# architecture and board. +# +# The ids other than the node-id specify the position of the CPU +# within the CPU topology (as defined by the machine property "smp", +# thus see also type @SMPConfiguration) +# # @node-id: NUMA node ID the CPU belongs to # -# @socket-id: socket number within node/board the CPU belongs to +# @socket-id: socket number within CPU topology the CPU belongs to # -# @die-id: die number within socket the CPU belongs to (since 4.1) +# @die-id: die number within the parent container the CPU belongs to +# (since 4.1) # -# @cluster-id: cluster number within die the CPU belongs to (since -# 7.1) +# @cluster-id: cluster number within the parent container the CPU +# belongs to (since 7.1) # -# @core-id: core number within cluster the CPU belongs to +# @core-id: core number within the parent container the CPU +# belongs to # -# @thread-id: thread number within core the CPU belongs to +# @thread-id: thread number within the core the CPU belongs to # -# Note: currently there are 6 properties that could be present but -# management should be prepared to pass through other properties -# with device_add command to allow for future interface extension. -# This also requires the filed names to be kept in sync with the -# properties passed to -device/device_add. +# Note: management should be prepared to pass through additional +# properties with device_add. # # Since: 2.7 ## { 'struct': 'CpuInstanceProperties', + # Keep these in sync with the properties device_add accepts 'data': { '*node-id': 'int', '*socket-id': 'int', '*die-id': 'int', @@ -1478,22 +1484,33 @@ # Schema for CPU topology configuration. A missing value lets QEMU # figure out a suitable value based on the ones that are provided. # +# The members other than @cpus and @maxcpus define a topology of +# containers. +# +# The ordering from highest/coarsest to lowest/finest is: +# @sockets, @dies, @clusters, @cores, @threads. +# +# Different architectures support different subsets of topology +# containers. +# +# For example, s390x does not have clusters and dies, and the socket +# is the parent container of cores. +# # @cpus: number of virtual CPUs in the virtual machine # -# @sockets: number of sockets in the CPU topology -# -# @dies: number of dies per socket in the CPU topology -# -# @clusters: number of clusters per die in the CPU topology (since -# 7.0) -# -# @cores: number of cores per cluster in the CPU topology -# -# @threads: number of threads per core in the CPU topology -# # @maxcpus: maximum number of hotpluggable virtual CPUs in the virtual # machine # +# @sockets: number of sockets in the CPU topology +# +# @dies: number of dies per parent container +# +# @clusters: number of clusters per parent container (since 7.0) +# +# @cores: number of cores per parent container +# +# @threads: number of threads per core +# # Since: 6.1 ## { 'struct': 'SMPConfiguration', 'data': { From 5de1aff2555275ef182197eddcadb276364ace38 Mon Sep 17 00:00:00 2001 From: Pierre Morel Date: Mon, 16 Oct 2023 20:39:06 +0200 Subject: [PATCH 0887/1077] CPU topology: extend with s390 specifics S390 adds two new SMP levels, drawers and books to the CPU topology. S390 CPUs have specific topology features like dedication and entitlement. These indicate to the guest information on host vCPU scheduling and help the guest make better scheduling decisions. Add the new levels to the relevant QAPI structs. Add all the supported topology levels, dedication and entitlement as properties to S390 CPUs. Create machine-common.json so we can later include it in machine-target.json also. Signed-off-by: Pierre Morel Reviewed-by: Nina Schoetterl-Glausch Co-developed-by: Nina Schoetterl-Glausch Reviewed-by: Thomas Huth Signed-off-by: Nina Schoetterl-Glausch Message-ID: <20231016183925.2384704-3-nsg@linux.ibm.com> Signed-off-by: Thomas Huth --- MAINTAINERS | 1 + hw/core/machine-smp.c | 48 ++++++++++++++++++++++++----- hw/core/machine.c | 4 +++ hw/core/qdev-properties-system.c | 13 ++++++++ hw/s390x/s390-virtio-ccw.c | 4 +++ include/hw/boards.h | 10 +++++- include/hw/qdev-properties-system.h | 4 +++ qapi/machine-common.json | 21 +++++++++++++ qapi/machine.json | 21 +++++++++++-- qapi/meson.build | 1 + qapi/qapi-schema.json | 1 + qemu-options.hx | 7 +++-- system/vl.c | 6 ++++ target/s390x/cpu.c | 7 +++++ target/s390x/cpu.h | 6 ++++ 15 files changed, 141 insertions(+), 13 deletions(-) create mode 100644 qapi/machine-common.json diff --git a/MAINTAINERS b/MAINTAINERS index 9bd4fe378d..2bf3399b3b 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1793,6 +1793,7 @@ F: hw/core/null-machine.c F: hw/core/numa.c F: hw/cpu/cluster.c F: qapi/machine.json +F: qapi/machine-common.json F: qapi/machine-target.json F: include/hw/boards.h F: include/hw/core/cpu.h diff --git a/hw/core/machine-smp.c b/hw/core/machine-smp.c index 0f4d9b6f7a..25019c91ee 100644 --- a/hw/core/machine-smp.c +++ b/hw/core/machine-smp.c @@ -33,6 +33,14 @@ static char *cpu_hierarchy_to_string(MachineState *ms) MachineClass *mc = MACHINE_GET_CLASS(ms); GString *s = g_string_new(NULL); + if (mc->smp_props.drawers_supported) { + g_string_append_printf(s, "drawers (%u) * ", ms->smp.drawers); + } + + if (mc->smp_props.books_supported) { + g_string_append_printf(s, "books (%u) * ", ms->smp.books); + } + g_string_append_printf(s, "sockets (%u)", ms->smp.sockets); if (mc->smp_props.dies_supported) { @@ -75,6 +83,8 @@ void machine_parse_smp_config(MachineState *ms, { MachineClass *mc = MACHINE_GET_CLASS(ms); unsigned cpus = config->has_cpus ? config->cpus : 0; + unsigned drawers = config->has_drawers ? config->drawers : 0; + unsigned books = config->has_books ? config->books : 0; unsigned sockets = config->has_sockets ? config->sockets : 0; unsigned dies = config->has_dies ? config->dies : 0; unsigned clusters = config->has_clusters ? config->clusters : 0; @@ -87,6 +97,8 @@ void machine_parse_smp_config(MachineState *ms, * explicit configuration like "cpus=0" is not allowed. */ if ((config->has_cpus && config->cpus == 0) || + (config->has_drawers && config->drawers == 0) || + (config->has_books && config->books == 0) || (config->has_sockets && config->sockets == 0) || (config->has_dies && config->dies == 0) || (config->has_clusters && config->clusters == 0) || @@ -113,6 +125,19 @@ void machine_parse_smp_config(MachineState *ms, dies = dies > 0 ? dies : 1; clusters = clusters > 0 ? clusters : 1; + if (!mc->smp_props.books_supported && books > 1) { + error_setg(errp, "books not supported by this machine's CPU topology"); + return; + } + books = books > 0 ? books : 1; + + if (!mc->smp_props.drawers_supported && drawers > 1) { + error_setg(errp, + "drawers not supported by this machine's CPU topology"); + return; + } + drawers = drawers > 0 ? drawers : 1; + /* compute missing values based on the provided ones */ if (cpus == 0 && maxcpus == 0) { sockets = sockets > 0 ? sockets : 1; @@ -126,33 +151,41 @@ void machine_parse_smp_config(MachineState *ms, if (sockets == 0) { cores = cores > 0 ? cores : 1; threads = threads > 0 ? threads : 1; - sockets = maxcpus / (dies * clusters * cores * threads); + sockets = maxcpus / + (drawers * books * dies * clusters * cores * threads); } else if (cores == 0) { threads = threads > 0 ? threads : 1; - cores = maxcpus / (sockets * dies * clusters * threads); + cores = maxcpus / + (drawers * books * sockets * dies * clusters * threads); } } else { /* prefer cores over sockets since 6.2 */ if (cores == 0) { sockets = sockets > 0 ? sockets : 1; threads = threads > 0 ? threads : 1; - cores = maxcpus / (sockets * dies * clusters * threads); + cores = maxcpus / + (drawers * books * sockets * dies * clusters * threads); } else if (sockets == 0) { threads = threads > 0 ? threads : 1; - sockets = maxcpus / (dies * clusters * cores * threads); + sockets = maxcpus / + (drawers * books * dies * clusters * cores * threads); } } /* try to calculate omitted threads at last */ if (threads == 0) { - threads = maxcpus / (sockets * dies * clusters * cores); + threads = maxcpus / + (drawers * books * sockets * dies * clusters * cores); } } - maxcpus = maxcpus > 0 ? maxcpus : sockets * dies * clusters * cores * threads; + maxcpus = maxcpus > 0 ? maxcpus : drawers * books * sockets * dies * + clusters * cores * threads; cpus = cpus > 0 ? cpus : maxcpus; ms->smp.cpus = cpus; + ms->smp.drawers = drawers; + ms->smp.books = books; ms->smp.sockets = sockets; ms->smp.dies = dies; ms->smp.clusters = clusters; @@ -163,7 +196,8 @@ void machine_parse_smp_config(MachineState *ms, mc->smp_props.has_clusters = config->has_clusters; /* sanity-check of the computed topology */ - if (sockets * dies * clusters * cores * threads != maxcpus) { + if (drawers * books * sockets * dies * clusters * cores * threads != + maxcpus) { g_autofree char *topo_msg = cpu_hierarchy_to_string(ms); error_setg(errp, "Invalid CPU topology: " "product of the hierarchy must match maxcpus: " diff --git a/hw/core/machine.c b/hw/core/machine.c index 05aef2cf9f..50edaab737 100644 --- a/hw/core/machine.c +++ b/hw/core/machine.c @@ -863,6 +863,8 @@ static void machine_get_smp(Object *obj, Visitor *v, const char *name, MachineState *ms = MACHINE(obj); SMPConfiguration *config = &(SMPConfiguration){ .has_cpus = true, .cpus = ms->smp.cpus, + .has_drawers = true, .drawers = ms->smp.drawers, + .has_books = true, .books = ms->smp.books, .has_sockets = true, .sockets = ms->smp.sockets, .has_dies = true, .dies = ms->smp.dies, .has_clusters = true, .clusters = ms->smp.clusters, @@ -1137,6 +1139,8 @@ static void machine_initfn(Object *obj) /* default to mc->default_cpus */ ms->smp.cpus = mc->default_cpus; ms->smp.max_cpus = mc->default_cpus; + ms->smp.drawers = 1; + ms->smp.books = 1; ms->smp.sockets = 1; ms->smp.dies = 1; ms->smp.clusters = 1; diff --git a/hw/core/qdev-properties-system.c b/hw/core/qdev-properties-system.c index 688340610e..7c6dfab128 100644 --- a/hw/core/qdev-properties-system.c +++ b/hw/core/qdev-properties-system.c @@ -1139,3 +1139,16 @@ const PropertyInfo qdev_prop_uuid = { .set = set_uuid, .set_default_value = set_default_uuid_auto, }; + +/* --- s390 cpu entitlement policy --- */ + +QEMU_BUILD_BUG_ON(sizeof(CpuS390Entitlement) != sizeof(int)); + +const PropertyInfo qdev_prop_cpus390entitlement = { + .name = "CpuS390Entitlement", + .description = "low/medium (default)/high", + .enum_table = &CpuS390Entitlement_lookup, + .get = qdev_propinfo_get_enum, + .set = qdev_propinfo_set_enum, + .set_default_value = qdev_propinfo_set_default_value_enum, +}; diff --git a/hw/s390x/s390-virtio-ccw.c b/hw/s390x/s390-virtio-ccw.c index 2d75f2131f..c1123a9b45 100644 --- a/hw/s390x/s390-virtio-ccw.c +++ b/hw/s390x/s390-virtio-ccw.c @@ -744,6 +744,8 @@ static void ccw_machine_class_init(ObjectClass *oc, void *data) mc->no_sdcard = 1; mc->max_cpus = S390_MAX_CPUS; mc->has_hotpluggable_cpus = true; + mc->smp_props.books_supported = true; + mc->smp_props.drawers_supported = true; assert(!mc->get_hotplug_handler); mc->get_hotplug_handler = s390_get_hotplug_handler; mc->cpu_index_to_instance_props = s390_cpu_index_to_props; @@ -853,6 +855,8 @@ static void ccw_machine_8_1_class_options(MachineClass *mc) { ccw_machine_8_2_class_options(mc); compat_props_add(mc->compat_props, hw_compat_8_1, hw_compat_8_1_len); + mc->smp_props.drawers_supported = false; + mc->smp_props.books_supported = false; } DEFINE_CCW_MACHINE(8_1, "8.1", false); diff --git a/include/hw/boards.h b/include/hw/boards.h index 43a56dc51e..a735999298 100644 --- a/include/hw/boards.h +++ b/include/hw/boards.h @@ -135,12 +135,16 @@ typedef struct { * @clusters_supported - whether clusters are supported by the machine * @has_clusters - whether clusters are explicitly specified in the user * provided SMP configuration + * @books_supported - whether books are supported by the machine + * @drawers_supported - whether drawers are supported by the machine */ typedef struct { bool prefer_sockets; bool dies_supported; bool clusters_supported; bool has_clusters; + bool books_supported; + bool drawers_supported; } SMPCompatProps; /** @@ -323,7 +327,9 @@ typedef struct DeviceMemoryState { /** * CpuTopology: * @cpus: the number of present logical processors on the machine - * @sockets: the number of sockets on the machine + * @drawers: the number of drawers on the machine + * @books: the number of books in one drawer + * @sockets: the number of sockets in one book * @dies: the number of dies in one socket * @clusters: the number of clusters in one die * @cores: the number of cores in one cluster @@ -332,6 +338,8 @@ typedef struct DeviceMemoryState { */ typedef struct CpuTopology { unsigned int cpus; + unsigned int drawers; + unsigned int books; unsigned int sockets; unsigned int dies; unsigned int clusters; diff --git a/include/hw/qdev-properties-system.h b/include/hw/qdev-properties-system.h index 0ac327ae60..e4f8a13afc 100644 --- a/include/hw/qdev-properties-system.h +++ b/include/hw/qdev-properties-system.h @@ -22,6 +22,7 @@ extern const PropertyInfo qdev_prop_audiodev; extern const PropertyInfo qdev_prop_off_auto_pcibar; extern const PropertyInfo qdev_prop_pcie_link_speed; extern const PropertyInfo qdev_prop_pcie_link_width; +extern const PropertyInfo qdev_prop_cpus390entitlement; #define DEFINE_PROP_PCI_DEVFN(_n, _s, _f, _d) \ DEFINE_PROP_SIGNED(_n, _s, _f, _d, qdev_prop_pci_devfn, int32_t) @@ -73,5 +74,8 @@ extern const PropertyInfo qdev_prop_pcie_link_width; #define DEFINE_PROP_UUID_NODEFAULT(_name, _state, _field) \ DEFINE_PROP(_name, _state, _field, qdev_prop_uuid, QemuUUID) +#define DEFINE_PROP_CPUS390ENTITLEMENT(_n, _s, _f, _d) \ + DEFINE_PROP_SIGNED(_n, _s, _f, _d, qdev_prop_cpus390entitlement, \ + CpuS390Entitlement) #endif diff --git a/qapi/machine-common.json b/qapi/machine-common.json new file mode 100644 index 0000000000..fa6bd71d12 --- /dev/null +++ b/qapi/machine-common.json @@ -0,0 +1,21 @@ +# -*- Mode: Python -*- +# vim: filetype=python +# +# This work is licensed under the terms of the GNU GPL, version 2 or later. +# See the COPYING file in the top-level directory. + +## +# = Machines S390 data types +## + +## +# @CpuS390Entitlement: +# +# An enumeration of CPU entitlements that can be assumed by a virtual +# S390 CPU +# +# Since: 8.2 +## +{ 'enum': 'CpuS390Entitlement', + 'prefix': 'S390_CPU_ENTITLEMENT', + 'data': [ 'auto', 'low', 'medium', 'high' ] } diff --git a/qapi/machine.json b/qapi/machine.json index f053245756..17b69a6aea 100644 --- a/qapi/machine.json +++ b/qapi/machine.json @@ -9,6 +9,7 @@ ## { 'include': 'common.json' } +{ 'include': 'machine-common.json' } ## # @SysEmuTarget: @@ -907,7 +908,13 @@ # # @node-id: NUMA node ID the CPU belongs to # -# @socket-id: socket number within CPU topology the CPU belongs to +# @drawer-id: drawer number within CPU topology the CPU belongs to +# (since 8.2) +# +# @book-id: book number within parent container the CPU belongs to +# (since 8.2) +# +# @socket-id: socket number within parent container the CPU belongs to # # @die-id: die number within the parent container the CPU belongs to # (since 4.1) @@ -928,6 +935,8 @@ { 'struct': 'CpuInstanceProperties', # Keep these in sync with the properties device_add accepts 'data': { '*node-id': 'int', + '*drawer-id': 'int', + '*book-id': 'int', '*socket-id': 'int', '*die-id': 'int', '*cluster-id': 'int', @@ -1488,7 +1497,7 @@ # containers. # # The ordering from highest/coarsest to lowest/finest is: -# @sockets, @dies, @clusters, @cores, @threads. +# @drawers, @books, @sockets, @dies, @clusters, @cores, @threads. # # Different architectures support different subsets of topology # containers. @@ -1501,7 +1510,11 @@ # @maxcpus: maximum number of hotpluggable virtual CPUs in the virtual # machine # -# @sockets: number of sockets in the CPU topology +# @drawers: number of drawers in the CPU topology (since 8.2) +# +# @books: number of books in the CPU topology (since 8.2) +# +# @sockets: number of sockets per parent container # # @dies: number of dies per parent container # @@ -1515,6 +1528,8 @@ ## { 'struct': 'SMPConfiguration', 'data': { '*cpus': 'int', + '*drawers': 'int', + '*books': 'int', '*sockets': 'int', '*dies': 'int', '*clusters': 'int', diff --git a/qapi/meson.build b/qapi/meson.build index 60a668b343..f81a37565c 100644 --- a/qapi/meson.build +++ b/qapi/meson.build @@ -36,6 +36,7 @@ qapi_all_modules = [ 'error', 'introspect', 'job', + 'machine-common', 'machine', 'machine-target', 'migration', diff --git a/qapi/qapi-schema.json b/qapi/qapi-schema.json index 6594afba31..c01ec335e6 100644 --- a/qapi/qapi-schema.json +++ b/qapi/qapi-schema.json @@ -66,6 +66,7 @@ { 'include': 'introspect.json' } { 'include': 'qom.json' } { 'include': 'qdev.json' } +{ 'include': 'machine-common.json' } { 'include': 'machine.json' } { 'include': 'machine-target.json' } { 'include': 'replay.json' } diff --git a/qemu-options.hx b/qemu-options.hx index 54a7e94970..e26230bac5 100644 --- a/qemu-options.hx +++ b/qemu-options.hx @@ -272,11 +272,14 @@ SRST ERST DEF("smp", HAS_ARG, QEMU_OPTION_smp, - "-smp [[cpus=]n][,maxcpus=maxcpus][,sockets=sockets][,dies=dies][,clusters=clusters][,cores=cores][,threads=threads]\n" + "-smp [[cpus=]n][,maxcpus=maxcpus][,drawers=drawers][,books=books][,sockets=sockets]\n" + " [,dies=dies][,clusters=clusters][,cores=cores][,threads=threads]\n" " set the number of initial CPUs to 'n' [default=1]\n" " maxcpus= maximum number of total CPUs, including\n" " offline CPUs for hotplug, etc\n" - " sockets= number of sockets on the machine board\n" + " drawers= number of drawers on the machine board\n" + " books= number of books in one drawer\n" + " sockets= number of sockets in one book\n" " dies= number of dies in one socket\n" " clusters= number of clusters in one die\n" " cores= number of cores in one cluster\n" diff --git a/system/vl.c b/system/vl.c index 3100ac01ed..92d29bf521 100644 --- a/system/vl.c +++ b/system/vl.c @@ -726,6 +726,12 @@ static QemuOptsList qemu_smp_opts = { { .name = "cpus", .type = QEMU_OPT_NUMBER, + }, { + .name = "drawers", + .type = QEMU_OPT_NUMBER, + }, { + .name = "books", + .type = QEMU_OPT_NUMBER, }, { .name = "sockets", .type = QEMU_OPT_NUMBER, diff --git a/target/s390x/cpu.c b/target/s390x/cpu.c index 6093ab0a12..ba646461a1 100644 --- a/target/s390x/cpu.c +++ b/target/s390x/cpu.c @@ -31,6 +31,7 @@ #include "qapi/qapi-types-machine.h" #include "sysemu/hw_accel.h" #include "hw/qdev-properties.h" +#include "hw/qdev-properties-system.h" #include "fpu/softfloat-helpers.h" #include "disas/capstone.h" #include "sysemu/tcg.h" @@ -290,6 +291,12 @@ static const gchar *s390_gdb_arch_name(CPUState *cs) static Property s390x_cpu_properties[] = { #if !defined(CONFIG_USER_ONLY) DEFINE_PROP_UINT32("core-id", S390CPU, env.core_id, 0), + DEFINE_PROP_INT32("socket-id", S390CPU, env.socket_id, -1), + DEFINE_PROP_INT32("book-id", S390CPU, env.book_id, -1), + DEFINE_PROP_INT32("drawer-id", S390CPU, env.drawer_id, -1), + DEFINE_PROP_BOOL("dedicated", S390CPU, env.dedicated, false), + DEFINE_PROP_CPUS390ENTITLEMENT("entitlement", S390CPU, env.entitlement, + S390_CPU_ENTITLEMENT_AUTO), #endif DEFINE_PROP_END_OF_LIST() }; diff --git a/target/s390x/cpu.h b/target/s390x/cpu.h index 7bea7075e1..56f9340914 100644 --- a/target/s390x/cpu.h +++ b/target/s390x/cpu.h @@ -30,6 +30,7 @@ #include "exec/cpu-defs.h" #include "qemu/cpu-float.h" #include "tcg/tcg_s390x.h" +#include "qapi/qapi-types-machine-common.h" #define ELF_MACHINE_UNAME "S390X" @@ -132,6 +133,11 @@ struct CPUArchState { #if !defined(CONFIG_USER_ONLY) uint32_t core_id; /* PoP "CPU address", same as cpu_index */ + int32_t socket_id; + int32_t book_id; + int32_t drawer_id; + bool dedicated; + CpuS390Entitlement entitlement; /* Used only for vertical polarization */ uint64_t cpuid; #endif From c809bbc8e98cf7fa254fac91084ade0a22877dec Mon Sep 17 00:00:00 2001 From: Pierre Morel Date: Mon, 16 Oct 2023 20:39:07 +0200 Subject: [PATCH 0888/1077] s390x/cpu topology: add topology entries on CPU hotplug The topology information are attributes of the CPU and are specified during the CPU device creation. On hot plug we: - calculate the default values for the topology for drawers, books and sockets in the case they are not specified. - verify the CPU attributes - check that we have still room on the desired socket The possibility to insert a CPU in a mask is dependent on the number of cores allowed in a socket, a book or a drawer, the checking is done during the hot plug of the CPU to have an immediate answer. If the complete topology is not specified, the core is added in the physical topology based on its core ID and it gets defaults values for the modifier attributes. This way, starting QEMU without specifying the topology can still get some advantage of the CPU topology. Signed-off-by: Pierre Morel Reviewed-by: Nina Schoetterl-Glausch Co-developed-by: Nina Schoetterl-Glausch Reviewed-by: Thomas Huth Signed-off-by: Nina Schoetterl-Glausch Message-ID: <20231016183925.2384704-4-nsg@linux.ibm.com> Signed-off-by: Thomas Huth --- MAINTAINERS | 6 + hw/s390x/cpu-topology.c | 259 ++++++++++++++++++++++++++++++++ hw/s390x/meson.build | 1 + hw/s390x/s390-virtio-ccw.c | 22 ++- include/hw/s390x/cpu-topology.h | 54 +++++++ 5 files changed, 340 insertions(+), 2 deletions(-) create mode 100644 hw/s390x/cpu-topology.c create mode 100644 include/hw/s390x/cpu-topology.h diff --git a/MAINTAINERS b/MAINTAINERS index 2bf3399b3b..8e2e828f7c 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1710,6 +1710,12 @@ F: hw/s390x/event-facility.c F: hw/s390x/sclp*.c L: qemu-s390x@nongnu.org +S390 CPU topology +M: Nina Schoetterl-Glausch +S: Supported +F: include/hw/s390x/cpu-topology.h +F: hw/s390x/cpu-topology.c + X86 Machines ------------ PC diff --git a/hw/s390x/cpu-topology.c b/hw/s390x/cpu-topology.c new file mode 100644 index 0000000000..cabd42e779 --- /dev/null +++ b/hw/s390x/cpu-topology.c @@ -0,0 +1,259 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * CPU Topology + * + * Copyright IBM Corp. 2022, 2023 + * Author(s): Pierre Morel + * + * S390 topology handling can be divided in two parts: + * + * - The first part in this file is taking care of all common functions + * used by KVM and TCG to create and modify the topology. + * + * - The second part, building the topology information data for the + * guest with CPU and KVM specificity will be implemented inside + * the target/s390/kvm sub tree. + */ + +#include "qemu/osdep.h" +#include "qapi/error.h" +#include "qemu/error-report.h" +#include "hw/qdev-properties.h" +#include "hw/boards.h" +#include "target/s390x/cpu.h" +#include "hw/s390x/s390-virtio-ccw.h" +#include "hw/s390x/cpu-topology.h" + +/* + * s390_topology is used to keep the topology information. + * .cores_per_socket: tracks information on the count of cores + * per socket. + */ +S390Topology s390_topology = { + /* will be initialized after the CPU model is realized */ + .cores_per_socket = NULL, +}; + +/** + * s390_socket_nb: + * @cpu: s390x CPU + * + * Returns the socket number used inside the cores_per_socket array + * for a topology tree entry + */ +static int s390_socket_nb_from_ids(int drawer_id, int book_id, int socket_id) +{ + return (drawer_id * current_machine->smp.books + book_id) * + current_machine->smp.sockets + socket_id; +} + +/** + * s390_socket_nb: + * @cpu: s390x CPU + * + * Returns the socket number used inside the cores_per_socket array + * for a cpu. + */ +static int s390_socket_nb(S390CPU *cpu) +{ + return s390_socket_nb_from_ids(cpu->env.drawer_id, cpu->env.book_id, + cpu->env.socket_id); +} + +/** + * s390_has_topology: + * + * Return: true if the topology is supported by the machine. + */ +bool s390_has_topology(void) +{ + return false; +} + +/** + * s390_topology_init: + * @ms: the machine state where the machine topology is defined + * + * Keep track of the machine topology. + * + * Allocate an array to keep the count of cores per socket. + * The index of the array starts at socket 0 from book 0 and + * drawer 0 up to the maximum allowed by the machine topology. + */ +static void s390_topology_init(MachineState *ms) +{ + CpuTopology *smp = &ms->smp; + + s390_topology.cores_per_socket = g_new0(uint8_t, smp->sockets * + smp->books * smp->drawers); +} + +/** + * s390_topology_cpu_default: + * @cpu: pointer to a S390CPU + * @errp: Error pointer + * + * Setup the default topology if no attributes are already set. + * Passing a CPU with some, but not all, attributes set is considered + * an error. + * + * The function calculates the (drawer_id, book_id, socket_id) + * topology by filling the cores starting from the first socket + * (0, 0, 0) up to the last (smp->drawers, smp->books, smp->sockets). + * + * CPU type and dedication have defaults values set in the + * s390x_cpu_properties, entitlement must be adjust depending on the + * dedication. + * + * Returns false if it is impossible to setup a default topology + * true otherwise. + */ +static bool s390_topology_cpu_default(S390CPU *cpu, Error **errp) +{ + CpuTopology *smp = ¤t_machine->smp; + CPUS390XState *env = &cpu->env; + + /* All geometry topology attributes must be set or all unset */ + if ((env->socket_id < 0 || env->book_id < 0 || env->drawer_id < 0) && + (env->socket_id >= 0 || env->book_id >= 0 || env->drawer_id >= 0)) { + error_setg(errp, + "Please define all or none of the topology geometry attributes"); + return false; + } + + /* If one value is unset all are unset -> calculate defaults */ + if (env->socket_id < 0) { + env->socket_id = s390_std_socket(env->core_id, smp); + env->book_id = s390_std_book(env->core_id, smp); + env->drawer_id = s390_std_drawer(env->core_id, smp); + } + + /* + * When the user specifies the entitlement as 'auto' on the command line, + * QEMU will set the entitlement as: + * Medium when the CPU is not dedicated. + * High when dedicated is true. + */ + if (env->entitlement == S390_CPU_ENTITLEMENT_AUTO) { + if (env->dedicated) { + env->entitlement = S390_CPU_ENTITLEMENT_HIGH; + } else { + env->entitlement = S390_CPU_ENTITLEMENT_MEDIUM; + } + } + return true; +} + +/** + * s390_topology_check: + * @socket_id: socket to check + * @book_id: book to check + * @drawer_id: drawer to check + * @entitlement: entitlement to check + * @dedicated: dedication to check + * @errp: Error pointer + * + * The function checks if the topology + * attributes fits inside the system topology. + * + * Returns false if the specified topology does not match with + * the machine topology. + */ +static bool s390_topology_check(uint16_t socket_id, uint16_t book_id, + uint16_t drawer_id, uint16_t entitlement, + bool dedicated, Error **errp) +{ + CpuTopology *smp = ¤t_machine->smp; + + if (socket_id >= smp->sockets) { + error_setg(errp, "Unavailable socket: %d", socket_id); + return false; + } + if (book_id >= smp->books) { + error_setg(errp, "Unavailable book: %d", book_id); + return false; + } + if (drawer_id >= smp->drawers) { + error_setg(errp, "Unavailable drawer: %d", drawer_id); + return false; + } + if (entitlement >= S390_CPU_ENTITLEMENT__MAX) { + error_setg(errp, "Unknown entitlement: %d", entitlement); + return false; + } + if (dedicated && (entitlement == S390_CPU_ENTITLEMENT_LOW || + entitlement == S390_CPU_ENTITLEMENT_MEDIUM)) { + error_setg(errp, "A dedicated CPU implies high entitlement"); + return false; + } + return true; +} + +/** + * s390_update_cpu_props: + * @ms: the machine state + * @cpu: the CPU for which to update the properties from the environment. + * + */ +static void s390_update_cpu_props(MachineState *ms, S390CPU *cpu) +{ + CpuInstanceProperties *props; + + props = &ms->possible_cpus->cpus[cpu->env.core_id].props; + + props->socket_id = cpu->env.socket_id; + props->book_id = cpu->env.book_id; + props->drawer_id = cpu->env.drawer_id; +} + +/** + * s390_topology_setup_cpu: + * @ms: MachineState used to initialize the topology structure on + * first call. + * @cpu: the new S390CPU to insert in the topology structure + * @errp: the error pointer + * + * Called from CPU hotplug to check and setup the CPU attributes + * before the CPU is inserted in the topology. + * There is no need to update the MTCR explicitly here because it + * will be updated by KVM on creation of the new CPU. + */ +void s390_topology_setup_cpu(MachineState *ms, S390CPU *cpu, Error **errp) +{ + int entry; + + /* + * We do not want to initialize the topology if the CPU model + * does not support topology, consequently, we have to wait for + * the first CPU to be realized, which realizes the CPU model + * to initialize the topology structures. + * + * s390_topology_setup_cpu() is called from the CPU hotplug. + */ + if (!s390_topology.cores_per_socket) { + s390_topology_init(ms); + } + + if (!s390_topology_cpu_default(cpu, errp)) { + return; + } + + if (!s390_topology_check(cpu->env.socket_id, cpu->env.book_id, + cpu->env.drawer_id, cpu->env.entitlement, + cpu->env.dedicated, errp)) { + return; + } + + /* Do we still have space in the socket */ + entry = s390_socket_nb(cpu); + if (s390_topology.cores_per_socket[entry] >= ms->smp.cores) { + error_setg(errp, "No more space on this socket"); + return; + } + + /* Update the count of cores in sockets */ + s390_topology.cores_per_socket[entry] += 1; + + /* topology tree is reflected in props */ + s390_update_cpu_props(ms, cpu); +} diff --git a/hw/s390x/meson.build b/hw/s390x/meson.build index 6fd096813a..482fd13420 100644 --- a/hw/s390x/meson.build +++ b/hw/s390x/meson.build @@ -23,6 +23,7 @@ s390x_ss.add(when: 'CONFIG_KVM', if_true: files( 's390-skeys-kvm.c', 's390-stattrib-kvm.c', 's390-pci-kvm.c', + 'cpu-topology.c', )) s390x_ss.add(when: 'CONFIG_TCG', if_true: files( 'tod-tcg.c', diff --git a/hw/s390x/s390-virtio-ccw.c b/hw/s390x/s390-virtio-ccw.c index c1123a9b45..7fe2bce20c 100644 --- a/hw/s390x/s390-virtio-ccw.c +++ b/hw/s390x/s390-virtio-ccw.c @@ -45,6 +45,7 @@ #include "target/s390x/kvm/pv.h" #include "migration/blocker.h" #include "qapi/visitor.h" +#include "hw/s390x/cpu-topology.h" static Error *pv_mig_blocker; @@ -309,10 +310,18 @@ static void s390_cpu_plug(HotplugHandler *hotplug_dev, { MachineState *ms = MACHINE(hotplug_dev); S390CPU *cpu = S390_CPU(dev); + ERRP_GUARD(); g_assert(!ms->possible_cpus->cpus[cpu->env.core_id].cpu); ms->possible_cpus->cpus[cpu->env.core_id].cpu = OBJECT(dev); + if (s390_has_topology()) { + s390_topology_setup_cpu(ms, cpu, errp); + if (*errp) { + return; + } + } + if (dev->hotplugged) { raise_irq_cpu_hotplug(); } @@ -562,11 +571,20 @@ static const CPUArchIdList *s390_possible_cpu_arch_ids(MachineState *ms) sizeof(CPUArchId) * max_cpus); ms->possible_cpus->len = max_cpus; for (i = 0; i < ms->possible_cpus->len; i++) { + CpuInstanceProperties *props = &ms->possible_cpus->cpus[i].props; + ms->possible_cpus->cpus[i].type = ms->cpu_type; ms->possible_cpus->cpus[i].vcpus_count = 1; ms->possible_cpus->cpus[i].arch_id = i; - ms->possible_cpus->cpus[i].props.has_core_id = true; - ms->possible_cpus->cpus[i].props.core_id = i; + + props->has_core_id = true; + props->core_id = i; + props->has_socket_id = true; + props->socket_id = s390_std_socket(i, &ms->smp); + props->has_book_id = true; + props->book_id = s390_std_book(i, &ms->smp); + props->has_drawer_id = true; + props->drawer_id = s390_std_drawer(i, &ms->smp); } return ms->possible_cpus; diff --git a/include/hw/s390x/cpu-topology.h b/include/hw/s390x/cpu-topology.h new file mode 100644 index 0000000000..afef70a66d --- /dev/null +++ b/include/hw/s390x/cpu-topology.h @@ -0,0 +1,54 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * CPU Topology + * + * Copyright IBM Corp. 2022, 2023 + * Author(s): Pierre Morel + * + */ +#ifndef HW_S390X_CPU_TOPOLOGY_H +#define HW_S390X_CPU_TOPOLOGY_H + +#ifndef CONFIG_USER_ONLY + +#include "qemu/queue.h" +#include "hw/boards.h" +#include "qapi/qapi-types-machine-target.h" + +typedef struct S390Topology { + uint8_t *cores_per_socket; +} S390Topology; + +#ifdef CONFIG_KVM +bool s390_has_topology(void); +void s390_topology_setup_cpu(MachineState *ms, S390CPU *cpu, Error **errp); +#else +static inline bool s390_has_topology(void) +{ + return false; +} +static inline void s390_topology_setup_cpu(MachineState *ms, + S390CPU *cpu, + Error **errp) {} +#endif + +extern S390Topology s390_topology; + +static inline int s390_std_socket(int n, CpuTopology *smp) +{ + return (n / smp->cores) % smp->sockets; +} + +static inline int s390_std_book(int n, CpuTopology *smp) +{ + return (n / (smp->cores * smp->sockets)) % smp->books; +} + +static inline int s390_std_drawer(int n, CpuTopology *smp) +{ + return (n / (smp->cores * smp->sockets * smp->books)) % smp->drawers; +} + +#endif /* CONFIG_USER_ONLY */ + +#endif From f4f54b582f4b78f4cfd5a6912e88aef4f11e3e3c Mon Sep 17 00:00:00 2001 From: Pierre Morel Date: Mon, 16 Oct 2023 20:39:08 +0200 Subject: [PATCH 0889/1077] target/s390x/cpu topology: handle STSI(15) and build the SYSIB On interception of STSI(15.1.x) the System Information Block (SYSIB) is built from the list of pre-ordered topology entries. Signed-off-by: Pierre Morel Reviewed-by: Nina Schoetterl-Glausch Co-developed-by: Nina Schoetterl-Glausch Reviewed-by: Thomas Huth Acked-by: Markus Armbruster Signed-off-by: Nina Schoetterl-Glausch Message-ID: <20231016183925.2384704-5-nsg@linux.ibm.com> Signed-off-by: Thomas Huth --- MAINTAINERS | 1 + hw/s390x/cpu-topology.c | 2 + include/hw/s390x/cpu-topology.h | 23 +++ include/hw/s390x/sclp.h | 1 + qapi/machine-target.json | 14 ++ target/s390x/cpu.h | 75 +++++++ target/s390x/kvm/kvm.c | 5 +- target/s390x/kvm/meson.build | 3 +- target/s390x/kvm/stsi-topology.c | 334 +++++++++++++++++++++++++++++++ 9 files changed, 456 insertions(+), 2 deletions(-) create mode 100644 target/s390x/kvm/stsi-topology.c diff --git a/MAINTAINERS b/MAINTAINERS index 8e2e828f7c..cfc37e9af7 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1715,6 +1715,7 @@ M: Nina Schoetterl-Glausch S: Supported F: include/hw/s390x/cpu-topology.h F: hw/s390x/cpu-topology.c +F: target/s390x/kvm/stsi-topology.c X86 Machines ------------ diff --git a/hw/s390x/cpu-topology.c b/hw/s390x/cpu-topology.c index cabd42e779..13168341b6 100644 --- a/hw/s390x/cpu-topology.c +++ b/hw/s390x/cpu-topology.c @@ -28,10 +28,12 @@ * s390_topology is used to keep the topology information. * .cores_per_socket: tracks information on the count of cores * per socket. + * .polarization: tracks machine polarization. */ S390Topology s390_topology = { /* will be initialized after the CPU model is realized */ .cores_per_socket = NULL, + .polarization = S390_CPU_POLARIZATION_HORIZONTAL, }; /** diff --git a/include/hw/s390x/cpu-topology.h b/include/hw/s390x/cpu-topology.h index afef70a66d..85499fea3e 100644 --- a/include/hw/s390x/cpu-topology.h +++ b/include/hw/s390x/cpu-topology.h @@ -15,10 +15,33 @@ #include "hw/boards.h" #include "qapi/qapi-types-machine-target.h" +#define S390_TOPOLOGY_CPU_IFL 0x03 + +typedef struct S390TopologyId { + uint8_t sentinel; + uint8_t drawer; + uint8_t book; + uint8_t socket; + uint8_t type; + uint8_t vertical:1; + uint8_t entitlement:2; + uint8_t dedicated; + uint8_t origin; +} S390TopologyId; + +typedef struct S390TopologyEntry { + QTAILQ_ENTRY(S390TopologyEntry) next; + S390TopologyId id; + uint64_t mask; +} S390TopologyEntry; + typedef struct S390Topology { uint8_t *cores_per_socket; + CpuS390Polarization polarization; } S390Topology; +typedef QTAILQ_HEAD(, S390TopologyEntry) S390TopologyList; + #ifdef CONFIG_KVM bool s390_has_topology(void); void s390_topology_setup_cpu(MachineState *ms, S390CPU *cpu, Error **errp); diff --git a/include/hw/s390x/sclp.h b/include/hw/s390x/sclp.h index cf1f2efae2..c49051e17e 100644 --- a/include/hw/s390x/sclp.h +++ b/include/hw/s390x/sclp.h @@ -112,6 +112,7 @@ typedef struct CPUEntry { } QEMU_PACKED CPUEntry; #define SCLP_READ_SCP_INFO_FIXED_CPU_OFFSET 128 +#define SCLP_READ_SCP_INFO_MNEST 2 typedef struct ReadInfo { SCCBHeader h; uint16_t rnmax; diff --git a/qapi/machine-target.json b/qapi/machine-target.json index f0a6b72414..93cbf1c128 100644 --- a/qapi/machine-target.json +++ b/qapi/machine-target.json @@ -361,3 +361,17 @@ 'TARGET_MIPS', 'TARGET_LOONGARCH64', 'TARGET_RISCV' ] } } + +## +# @CpuS390Polarization: +# +# An enumeration of CPU polarization that can be assumed by a virtual +# S390 CPU +# +# Since: 8.2 +## +{ 'enum': 'CpuS390Polarization', + 'prefix': 'S390_CPU_POLARIZATION', + 'data': [ 'horizontal', 'vertical' ], + 'if': 'TARGET_S390X' +} diff --git a/target/s390x/cpu.h b/target/s390x/cpu.h index 56f9340914..09bff39fe4 100644 --- a/target/s390x/cpu.h +++ b/target/s390x/cpu.h @@ -570,6 +570,29 @@ typedef struct SysIB_322 { } SysIB_322; QEMU_BUILD_BUG_ON(sizeof(SysIB_322) != 4096); +/* + * Topology Magnitude fields (MAG) indicates the maximum number of + * topology list entries (TLE) at the corresponding nesting level. + */ +#define S390_TOPOLOGY_MAG 6 +#define S390_TOPOLOGY_MAG6 0 +#define S390_TOPOLOGY_MAG5 1 +#define S390_TOPOLOGY_MAG4 2 +#define S390_TOPOLOGY_MAG3 3 +#define S390_TOPOLOGY_MAG2 4 +#define S390_TOPOLOGY_MAG1 5 +/* Configuration topology */ +typedef struct SysIB_151x { + uint8_t reserved0[2]; + uint16_t length; + uint8_t mag[S390_TOPOLOGY_MAG]; + uint8_t reserved1; + uint8_t mnest; + uint32_t reserved2; + char tle[]; +} SysIB_151x; +QEMU_BUILD_BUG_ON(sizeof(SysIB_151x) != 16); + typedef union SysIB { SysIB_111 sysib_111; SysIB_121 sysib_121; @@ -577,9 +600,61 @@ typedef union SysIB { SysIB_221 sysib_221; SysIB_222 sysib_222; SysIB_322 sysib_322; + SysIB_151x sysib_151x; } SysIB; QEMU_BUILD_BUG_ON(sizeof(SysIB) != 4096); +/* + * CPU Topology List provided by STSI with fc=15 provides a list + * of two different Topology List Entries (TLE) types to specify + * the topology hierarchy. + * + * - Container Topology List Entry + * Defines a container to contain other Topology List Entries + * of any type, nested containers or CPU. + * - CPU Topology List Entry + * Specifies the CPUs position, type, entitlement and polarization + * of the CPUs contained in the last container TLE. + * + * There can be theoretically up to five levels of containers, QEMU + * uses only three levels, the drawer's, book's and socket's level. + * + * A container with a nesting level (NL) greater than 1 can only + * contain another container of nesting level NL-1. + * + * A container of nesting level 1 (socket), contains as many CPU TLE + * as needed to describe the position and qualities of all CPUs inside + * the container. + * The qualities of a CPU are polarization, entitlement and type. + * + * The CPU TLE defines the position of the CPUs of identical qualities + * using a 64bits mask which first bit has its offset defined by + * the CPU address origin field of the CPU TLE like in: + * CPU address = origin * 64 + bit position within the mask + */ +/* Container type Topology List Entry */ +typedef struct SYSIBContainerListEntry { + uint8_t nl; + uint8_t reserved[6]; + uint8_t id; +} SYSIBContainerListEntry; +QEMU_BUILD_BUG_ON(sizeof(SYSIBContainerListEntry) != 8); + +/* CPU type Topology List Entry */ +typedef struct SysIBCPUListEntry { + uint8_t nl; + uint8_t reserved0[3]; +#define SYSIB_TLE_POLARITY_MASK 0x03 +#define SYSIB_TLE_DEDICATED 0x04 + uint8_t flags; + uint8_t type; + uint16_t origin; + uint64_t mask; +} SysIBCPUListEntry; +QEMU_BUILD_BUG_ON(sizeof(SysIBCPUListEntry) != 16); + +void insert_stsi_15_1_x(S390CPU *cpu, int sel2, uint64_t addr, uint8_t ar, uintptr_t ra); + /* MMU defines */ #define ASCE_ORIGIN (~0xfffULL) /* segment table origin */ #define ASCE_SUBSPACE 0x200 /* subspace group control */ diff --git a/target/s390x/kvm/kvm.c b/target/s390x/kvm/kvm.c index bc5c56a305..53d6300809 100644 --- a/target/s390x/kvm/kvm.c +++ b/target/s390x/kvm/kvm.c @@ -1911,9 +1911,12 @@ static int handle_stsi(S390CPU *cpu) if (run->s390_stsi.sel1 != 2 || run->s390_stsi.sel2 != 2) { return 0; } - /* Only sysib 3.2.2 needs post-handling for now. */ insert_stsi_3_2_2(cpu, run->s390_stsi.addr, run->s390_stsi.ar); return 0; + case 15: + insert_stsi_15_1_x(cpu, run->s390_stsi.sel2, run->s390_stsi.addr, + run->s390_stsi.ar, RA_IGNORED); + return 0; default: return 0; } diff --git a/target/s390x/kvm/meson.build b/target/s390x/kvm/meson.build index d6aca590ae..588a9aa737 100644 --- a/target/s390x/kvm/meson.build +++ b/target/s390x/kvm/meson.build @@ -1,7 +1,8 @@ s390x_ss.add(when: 'CONFIG_KVM', if_true: files( 'pv.c', - 'kvm.c' + 'kvm.c', + 'stsi-topology.c' ), if_false: files( 'stubs.c' )) diff --git a/target/s390x/kvm/stsi-topology.c b/target/s390x/kvm/stsi-topology.c new file mode 100644 index 0000000000..efd2aa71f1 --- /dev/null +++ b/target/s390x/kvm/stsi-topology.c @@ -0,0 +1,334 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * QEMU S390x CPU Topology + * + * Copyright IBM Corp. 2022, 2023 + * Author(s): Pierre Morel + * + */ +#include "qemu/osdep.h" +#include "cpu.h" +#include "hw/s390x/sclp.h" +#include "hw/s390x/cpu-topology.h" + +QEMU_BUILD_BUG_ON(S390_CPU_ENTITLEMENT_LOW != 1); +QEMU_BUILD_BUG_ON(S390_CPU_ENTITLEMENT_MEDIUM != 2); +QEMU_BUILD_BUG_ON(S390_CPU_ENTITLEMENT_HIGH != 3); + +/** + * fill_container: + * @p: The address of the container TLE to fill + * @level: The level of nesting for this container + * @id: The container receives a unique ID inside its own container + * + * Returns the next free TLE entry. + */ +static char *fill_container(char *p, int level, int id) +{ + SYSIBContainerListEntry *tle = (SYSIBContainerListEntry *)p; + + tle->nl = level; + tle->id = id; + return p + sizeof(*tle); +} + +/** + * fill_tle_cpu: + * @p: The address of the CPU TLE to fill + * @entry: a pointer to the S390TopologyEntry defining this + * CPU container. + * + * Returns the next free TLE entry. + */ +static char *fill_tle_cpu(char *p, S390TopologyEntry *entry) +{ + SysIBCPUListEntry *tle = (SysIBCPUListEntry *)p; + S390TopologyId topology_id = entry->id; + + tle->nl = 0; + tle->flags = 0; + if (topology_id.vertical) { + tle->flags |= topology_id.entitlement; + } + if (topology_id.dedicated) { + tle->flags |= SYSIB_TLE_DEDICATED; + } + tle->type = topology_id.type; + tle->origin = cpu_to_be16(topology_id.origin * 64); + tle->mask = cpu_to_be64(entry->mask); + return p + sizeof(*tle); +} + +/* + * Macro to check that the size of data after increment + * will not get bigger than the size of the SysIB. + */ +#define SYSIB_GUARD(data, x) do { \ + data += x; \ + if (data > sizeof(SysIB)) { \ + return 0; \ + } \ + } while (0) + +/** + * stsi_topology_fill_sysib: + * @p: A pointer to the position of the first TLE + * @level: The nested level wanted by the guest + * + * Fill the SYSIB with the topology information as described in + * the PoP, nesting containers as appropriate, with the maximum + * nesting limited by @level. + * + * Return value: + * On success: the size of the SysIB_15x after being filled with TLE. + * On error: 0 in the case we would overrun the end of the SysIB. + */ +static int stsi_topology_fill_sysib(S390TopologyList *topology_list, + char *p, int level) +{ + S390TopologyEntry *entry; + int last_drawer = -1; + int last_book = -1; + int last_socket = -1; + int drawer_id = 0; + int book_id = 0; + int socket_id = 0; + int n = sizeof(SysIB_151x); + + QTAILQ_FOREACH(entry, topology_list, next) { + bool drawer_change = last_drawer != entry->id.drawer; + bool book_change = drawer_change || last_book != entry->id.book; + bool socket_change = book_change || last_socket != entry->id.socket; + + if (level > 3 && drawer_change) { + SYSIB_GUARD(n, sizeof(SYSIBContainerListEntry)); + p = fill_container(p, 3, drawer_id++); + book_id = 0; + } + if (level > 2 && book_change) { + SYSIB_GUARD(n, sizeof(SYSIBContainerListEntry)); + p = fill_container(p, 2, book_id++); + socket_id = 0; + } + if (socket_change) { + SYSIB_GUARD(n, sizeof(SYSIBContainerListEntry)); + p = fill_container(p, 1, socket_id++); + } + + SYSIB_GUARD(n, sizeof(SysIBCPUListEntry)); + p = fill_tle_cpu(p, entry); + last_drawer = entry->id.drawer; + last_book = entry->id.book; + last_socket = entry->id.socket; + } + + return n; +} + +/** + * setup_stsi: + * @topology_list: ordered list of groups of CPUs with same properties + * @sysib: pointer to a SysIB to be filled with SysIB_151x data + * @level: Nested level specified by the guest + * + * Setup the SYSIB for STSI 15.1, the header as well as the description + * of the topology. + */ +static int setup_stsi(S390TopologyList *topology_list, SysIB_151x *sysib, + int level) +{ + sysib->mnest = level; + switch (level) { + case 4: + sysib->mag[S390_TOPOLOGY_MAG4] = current_machine->smp.drawers; + sysib->mag[S390_TOPOLOGY_MAG3] = current_machine->smp.books; + sysib->mag[S390_TOPOLOGY_MAG2] = current_machine->smp.sockets; + sysib->mag[S390_TOPOLOGY_MAG1] = current_machine->smp.cores; + break; + case 3: + sysib->mag[S390_TOPOLOGY_MAG3] = current_machine->smp.drawers * + current_machine->smp.books; + sysib->mag[S390_TOPOLOGY_MAG2] = current_machine->smp.sockets; + sysib->mag[S390_TOPOLOGY_MAG1] = current_machine->smp.cores; + break; + case 2: + sysib->mag[S390_TOPOLOGY_MAG2] = current_machine->smp.drawers * + current_machine->smp.books * + current_machine->smp.sockets; + sysib->mag[S390_TOPOLOGY_MAG1] = current_machine->smp.cores; + break; + } + + return stsi_topology_fill_sysib(topology_list, sysib->tle, level); +} + +/** + * s390_topology_add_cpu_to_entry: + * @entry: Topology entry to setup + * @cpu: the S390CPU to add + * + * Set the core bit inside the topology mask. + */ +static void s390_topology_add_cpu_to_entry(S390TopologyEntry *entry, + S390CPU *cpu) +{ + set_bit(63 - (cpu->env.core_id % 64), &entry->mask); +} + +/** + * s390_topology_from_cpu: + * @cpu: S390CPU to calculate the topology id + * + * Initialize the topology id from the CPU environment. + */ +static S390TopologyId s390_topology_from_cpu(S390CPU *cpu) +{ + S390TopologyId topology_id = { + .drawer = cpu->env.drawer_id, + .book = cpu->env.book_id, + .socket = cpu->env.socket_id, + .type = S390_TOPOLOGY_CPU_IFL, + .vertical = s390_topology.polarization == S390_CPU_POLARIZATION_VERTICAL, + .entitlement = cpu->env.entitlement, + .dedicated = cpu->env.dedicated, + .origin = cpu->env.core_id / 64, + }; + + return topology_id; +} + +/** + * s390_topology_id_cmp: + * @l: first S390TopologyId + * @r: second S390TopologyId + * + * Compare two topology ids according to the sorting order specified by the PoP. + * + * Returns a negative number if the first id is less than, 0 if it is equal to + * and positive if it is larger than the second id. + */ +static int s390_topology_id_cmp(const S390TopologyId *l, + const S390TopologyId *r) +{ + /* + * lexical order, compare less significant values only if more significant + * ones are equal + */ + return l->sentinel - r->sentinel ?: + l->drawer - r->drawer ?: + l->book - r->book ?: + l->socket - r->socket ?: + l->type - r->type ?: + /* logic is inverted for the next three */ + r->vertical - l->vertical ?: + r->entitlement - l->entitlement ?: + r->dedicated - l->dedicated ?: + l->origin - r->origin; +} + +static bool s390_topology_id_eq(const S390TopologyId *l, + const S390TopologyId *r) +{ + return !s390_topology_id_cmp(l, r); +} + +static bool s390_topology_id_lt(const S390TopologyId *l, + const S390TopologyId *r) +{ + return s390_topology_id_cmp(l, r) < 0; +} + +/** + * s390_topology_fill_list_sorted: + * @topology_list: list to fill + * + * Create S390TopologyEntrys as appropriate from all CPUs and fill the + * topology_list with the entries according to the order specified by the PoP. + */ +static void s390_topology_fill_list_sorted(S390TopologyList *topology_list) +{ + CPUState *cs; + S390TopologyEntry sentinel = { .id.sentinel = 1 }; + + QTAILQ_INIT(topology_list); + + QTAILQ_INSERT_HEAD(topology_list, &sentinel, next); + + CPU_FOREACH(cs) { + S390TopologyId id = s390_topology_from_cpu(S390_CPU(cs)); + S390TopologyEntry *entry = NULL, *tmp; + + QTAILQ_FOREACH(tmp, topology_list, next) { + if (s390_topology_id_eq(&id, &tmp->id)) { + entry = tmp; + break; + } else if (s390_topology_id_lt(&id, &tmp->id)) { + entry = g_malloc0(sizeof(*entry)); + entry->id = id; + QTAILQ_INSERT_BEFORE(tmp, entry, next); + break; + } + } + assert(entry); + s390_topology_add_cpu_to_entry(entry, S390_CPU(cs)); + } + + QTAILQ_REMOVE(topology_list, &sentinel, next); +} + +/** + * s390_topology_empty_list: + * + * Clear all entries in the S390Topology list. + */ +static void s390_topology_empty_list(S390TopologyList *topology_list) +{ + S390TopologyEntry *entry = NULL; + S390TopologyEntry *tmp = NULL; + + QTAILQ_FOREACH_SAFE(entry, topology_list, next, tmp) { + QTAILQ_REMOVE(topology_list, entry, next); + g_free(entry); + } +} + +/** + * insert_stsi_15_1_x: + * @cpu: the CPU doing the call for which we set CC + * @sel2: the selector 2, containing the nested level + * @addr: Guest logical address of the guest SysIB + * @ar: the access register number + * @ra: the return address + * + * Emulate STSI 15.1.x, that is, perform all necessary checks and + * fill the SYSIB. + * In case the topology description is too long to fit into the SYSIB, + * set CC=3 and abort without writing the SYSIB. + */ +void insert_stsi_15_1_x(S390CPU *cpu, int sel2, uint64_t addr, uint8_t ar, uintptr_t ra) +{ + S390TopologyList topology_list; + SysIB sysib = {0}; + int length; + + if (!s390_has_topology() || sel2 < 2 || sel2 > SCLP_READ_SCP_INFO_MNEST) { + setcc(cpu, 3); + return; + } + + s390_topology_fill_list_sorted(&topology_list); + length = setup_stsi(&topology_list, &sysib.sysib_151x, sel2); + s390_topology_empty_list(&topology_list); + + if (!length) { + setcc(cpu, 3); + return; + } + + sysib.sysib_151x.length = cpu_to_be16(length); + if (!s390_cpu_virt_mem_write(cpu, addr, ar, &sysib, length)) { + setcc(cpu, 0); + } else { + s390_cpu_virt_mem_handle_exc(cpu, ra); + } +} From a67f05b39106bf3477475297d8508bcb7d8eb0d8 Mon Sep 17 00:00:00 2001 From: Pierre Morel Date: Mon, 16 Oct 2023 20:39:09 +0200 Subject: [PATCH 0890/1077] s390x/sclp: reporting the maximum nested topology entries The maximum nested topology entries is used by the guest to know how many nested topology are available on the machine. Let change the MNEST value from 2 to 4 in the SCLP READ INFO structure now that we support books and drawers. Signed-off-by: Pierre Morel Reviewed-by: Nina Schoetterl-Glausch Reviewed-by: Thomas Huth Message-ID: <20231016183925.2384704-6-nsg@linux.ibm.com> Signed-off-by: Thomas Huth --- hw/s390x/sclp.c | 5 +++++ include/hw/s390x/sclp.h | 5 +++-- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/hw/s390x/sclp.c b/hw/s390x/sclp.c index eff74479f4..d339cbb7e4 100644 --- a/hw/s390x/sclp.c +++ b/hw/s390x/sclp.c @@ -20,6 +20,7 @@ #include "hw/s390x/event-facility.h" #include "hw/s390x/s390-pci-bus.h" #include "hw/s390x/ipl.h" +#include "hw/s390x/cpu-topology.h" static inline SCLPDevice *get_sclp_device(void) { @@ -123,6 +124,10 @@ static void read_SCP_info(SCLPDevice *sclp, SCCB *sccb) return; } + if (s390_has_topology()) { + read_info->stsi_parm = SCLP_READ_SCP_INFO_MNEST; + } + /* CPU information */ prepare_cpu_entries(machine, entries_start, &cpu_count); read_info->entries_cpu = cpu_to_be16(cpu_count); diff --git a/include/hw/s390x/sclp.h b/include/hw/s390x/sclp.h index c49051e17e..9aef6d9370 100644 --- a/include/hw/s390x/sclp.h +++ b/include/hw/s390x/sclp.h @@ -112,12 +112,13 @@ typedef struct CPUEntry { } QEMU_PACKED CPUEntry; #define SCLP_READ_SCP_INFO_FIXED_CPU_OFFSET 128 -#define SCLP_READ_SCP_INFO_MNEST 2 +#define SCLP_READ_SCP_INFO_MNEST 4 typedef struct ReadInfo { SCCBHeader h; uint16_t rnmax; uint8_t rnsize; - uint8_t _reserved1[16 - 11]; /* 11-15 */ + uint8_t _reserved1[15 - 11]; /* 11-14 */ + uint8_t stsi_parm; /* 15-15 */ uint16_t entries_cpu; /* 16-17 */ uint16_t offset_cpu; /* 18-19 */ uint8_t _reserved2[24 - 20]; /* 20-23 */ From 3d6e75f4df67980479cc0912b842202f2093aeeb Mon Sep 17 00:00:00 2001 From: Pierre Morel Date: Mon, 16 Oct 2023 20:39:10 +0200 Subject: [PATCH 0891/1077] s390x/cpu topology: resetting the Topology-Change-Report During a subsystem reset the Topology-Change-Report is cleared by the machine. Let's ask KVM to clear the Modified Topology Change Report (MTCR) bit of the SCA in the case of a subsystem reset. Signed-off-by: Pierre Morel Reviewed-by: Thomas Huth Reviewed-by: Nina Schoetterl-Glausch Co-developed-by: Nina Schoetterl-Glausch Signed-off-by: Nina Schoetterl-Glausch Message-ID: <20231016183925.2384704-7-nsg@linux.ibm.com> Signed-off-by: Thomas Huth --- hw/s390x/cpu-topology.c | 11 +++++++++++ hw/s390x/s390-virtio-ccw.c | 3 +++ include/hw/s390x/cpu-topology.h | 6 ++++++ target/s390x/cpu-sysemu.c | 13 +++++++++++++ target/s390x/cpu.h | 1 + target/s390x/kvm/kvm.c | 17 +++++++++++++++++ target/s390x/kvm/kvm_s390x.h | 1 + 7 files changed, 52 insertions(+) diff --git a/hw/s390x/cpu-topology.c b/hw/s390x/cpu-topology.c index 13168341b6..7ec9319272 100644 --- a/hw/s390x/cpu-topology.c +++ b/hw/s390x/cpu-topology.c @@ -90,6 +90,17 @@ static void s390_topology_init(MachineState *ms) smp->books * smp->drawers); } +/** + * s390_topology_reset: + * + * Generic reset for CPU topology, calls s390_topology_reset() + * to reset the kernel Modified Topology Change Record. + */ +void s390_topology_reset(void) +{ + s390_cpu_topology_set_changed(false); +} + /** * s390_topology_cpu_default: * @cpu: pointer to a S390CPU diff --git a/hw/s390x/s390-virtio-ccw.c b/hw/s390x/s390-virtio-ccw.c index 7fe2bce20c..6012165d41 100644 --- a/hw/s390x/s390-virtio-ccw.c +++ b/hw/s390x/s390-virtio-ccw.c @@ -124,6 +124,9 @@ static void subsystem_reset(void) device_cold_reset(dev); } } + if (s390_has_topology()) { + s390_topology_reset(); + } } static int virtio_ccw_hcall_notify(const uint64_t *args) diff --git a/include/hw/s390x/cpu-topology.h b/include/hw/s390x/cpu-topology.h index 85499fea3e..c064f427e9 100644 --- a/include/hw/s390x/cpu-topology.h +++ b/include/hw/s390x/cpu-topology.h @@ -45,6 +45,7 @@ typedef QTAILQ_HEAD(, S390TopologyEntry) S390TopologyList; #ifdef CONFIG_KVM bool s390_has_topology(void); void s390_topology_setup_cpu(MachineState *ms, S390CPU *cpu, Error **errp); +void s390_topology_reset(void); #else static inline bool s390_has_topology(void) { @@ -53,6 +54,11 @@ static inline bool s390_has_topology(void) static inline void s390_topology_setup_cpu(MachineState *ms, S390CPU *cpu, Error **errp) {} +static inline void s390_topology_reset(void) +{ + /* Unreachable, CPU topology not implemented for TCG */ + assert(false); +} #endif extern S390Topology s390_topology; diff --git a/target/s390x/cpu-sysemu.c b/target/s390x/cpu-sysemu.c index 8112561e5e..1cd30c1d84 100644 --- a/target/s390x/cpu-sysemu.c +++ b/target/s390x/cpu-sysemu.c @@ -307,3 +307,16 @@ void s390_do_cpu_set_diag318(CPUState *cs, run_on_cpu_data arg) kvm_s390_set_diag318(cs, arg.host_ulong); } } + +void s390_cpu_topology_set_changed(bool changed) +{ + int ret; + + if (kvm_enabled()) { + ret = kvm_s390_topology_set_mtcr(changed); + if (ret) { + error_report("Failed to set Modified Topology Change Report: %s", + strerror(-ret)); + } + } +} diff --git a/target/s390x/cpu.h b/target/s390x/cpu.h index 09bff39fe4..40c5cedd0e 100644 --- a/target/s390x/cpu.h +++ b/target/s390x/cpu.h @@ -654,6 +654,7 @@ typedef struct SysIBCPUListEntry { QEMU_BUILD_BUG_ON(sizeof(SysIBCPUListEntry) != 16); void insert_stsi_15_1_x(S390CPU *cpu, int sel2, uint64_t addr, uint8_t ar, uintptr_t ra); +void s390_cpu_topology_set_changed(bool changed); /* MMU defines */ #define ASCE_ORIGIN (~0xfffULL) /* segment table origin */ diff --git a/target/s390x/kvm/kvm.c b/target/s390x/kvm/kvm.c index 53d6300809..d6bda3a2a8 100644 --- a/target/s390x/kvm/kvm.c +++ b/target/s390x/kvm/kvm.c @@ -2664,6 +2664,23 @@ int kvm_s390_get_zpci_op(void) return cap_zpci_op; } +int kvm_s390_topology_set_mtcr(uint64_t attr) +{ + struct kvm_device_attr attribute = { + .group = KVM_S390_VM_CPU_TOPOLOGY, + .attr = attr, + }; + + if (!s390_has_feat(S390_FEAT_CONFIGURATION_TOPOLOGY)) { + return 0; + } + if (!kvm_vm_check_attr(kvm_state, KVM_S390_VM_CPU_TOPOLOGY, attr)) { + return -ENOTSUP; + } + + return kvm_vm_ioctl(kvm_state, KVM_SET_DEVICE_ATTR, &attribute); +} + void kvm_arch_accel_class_init(ObjectClass *oc) { } diff --git a/target/s390x/kvm/kvm_s390x.h b/target/s390x/kvm/kvm_s390x.h index f9785564d0..649dae5948 100644 --- a/target/s390x/kvm/kvm_s390x.h +++ b/target/s390x/kvm/kvm_s390x.h @@ -47,5 +47,6 @@ void kvm_s390_crypto_reset(void); void kvm_s390_restart_interrupt(S390CPU *cpu); void kvm_s390_stop_interrupt(S390CPU *cpu); void kvm_s390_set_diag318(CPUState *cs, uint64_t diag318_info); +int kvm_s390_topology_set_mtcr(uint64_t attr); #endif /* KVM_S390X_H */ From af37bad52e7c216c044f919d6254c77be0eacbc6 Mon Sep 17 00:00:00 2001 From: Pierre Morel Date: Mon, 16 Oct 2023 20:39:11 +0200 Subject: [PATCH 0892/1077] s390x/cpu topology: interception of PTF instruction When the host supports the CPU topology facility, the PTF instruction with function code 2 is interpreted by the SIE, provided that the userland hypervisor activates the interpretation by using the KVM_CAP_S390_CPU_TOPOLOGY KVM extension. The PTF instructions with function code 0 and 1 are intercepted and must be emulated by the userland hypervisor. During RESET all CPU of the configuration are placed in horizontal polarity. Signed-off-by: Pierre Morel Reviewed-by: Nina Schoetterl-Glausch Reviewed-by: Thomas Huth Co-developed-by: Nina Schoetterl-Glausch Signed-off-by: Nina Schoetterl-Glausch Message-ID: <20231016183925.2384704-8-nsg@linux.ibm.com> Signed-off-by: Thomas Huth --- hw/s390x/cpu-topology.c | 55 ++++++++++++++++++++++++++++++ include/hw/s390x/s390-virtio-ccw.h | 6 ++++ target/s390x/kvm/kvm.c | 11 ++++++ 3 files changed, 72 insertions(+) diff --git a/hw/s390x/cpu-topology.c b/hw/s390x/cpu-topology.c index 7ec9319272..a00a4ce4df 100644 --- a/hw/s390x/cpu-topology.c +++ b/hw/s390x/cpu-topology.c @@ -90,6 +90,60 @@ static void s390_topology_init(MachineState *ms) smp->books * smp->drawers); } +/* + * s390_handle_ptf: + * + * @register 1: contains the function code + * + * Function codes 0 (horizontal) and 1 (vertical) define the CPU + * polarization requested by the guest. + * + * Function code 2 is handling topology changes and is interpreted + * by the SIE. + */ +void s390_handle_ptf(S390CPU *cpu, uint8_t r1, uintptr_t ra) +{ + CpuS390Polarization polarization; + CPUS390XState *env = &cpu->env; + uint64_t reg = env->regs[r1]; + int fc = reg & S390_TOPO_FC_MASK; + + if (!s390_has_feat(S390_FEAT_CONFIGURATION_TOPOLOGY)) { + s390_program_interrupt(env, PGM_OPERATION, ra); + return; + } + + if (env->psw.mask & PSW_MASK_PSTATE) { + s390_program_interrupt(env, PGM_PRIVILEGED, ra); + return; + } + + if (reg & ~S390_TOPO_FC_MASK) { + s390_program_interrupt(env, PGM_SPECIFICATION, ra); + return; + } + + polarization = S390_CPU_POLARIZATION_VERTICAL; + switch (fc) { + case 0: + polarization = S390_CPU_POLARIZATION_HORIZONTAL; + /* fallthrough */ + case 1: + if (s390_topology.polarization == polarization) { + env->regs[r1] |= S390_PTF_REASON_DONE; + setcc(cpu, 2); + } else { + s390_topology.polarization = polarization; + s390_cpu_topology_set_changed(true); + setcc(cpu, 0); + } + break; + default: + /* Note that fc == 2 is interpreted by the SIE */ + s390_program_interrupt(env, PGM_SPECIFICATION, ra); + } +} + /** * s390_topology_reset: * @@ -99,6 +153,7 @@ static void s390_topology_init(MachineState *ms) void s390_topology_reset(void) { s390_cpu_topology_set_changed(false); + s390_topology.polarization = S390_CPU_POLARIZATION_HORIZONTAL; } /** diff --git a/include/hw/s390x/s390-virtio-ccw.h b/include/hw/s390x/s390-virtio-ccw.h index 9bba21a916..c1d46e78af 100644 --- a/include/hw/s390x/s390-virtio-ccw.h +++ b/include/hw/s390x/s390-virtio-ccw.h @@ -30,6 +30,12 @@ struct S390CcwMachineState { uint8_t loadparm[8]; }; +#define S390_PTF_REASON_NONE (0x00 << 8) +#define S390_PTF_REASON_DONE (0x01 << 8) +#define S390_PTF_REASON_BUSY (0x02 << 8) +#define S390_TOPO_FC_MASK 0xffUL +void s390_handle_ptf(S390CPU *cpu, uint8_t r1, uintptr_t ra); + struct S390CcwMachineClass { /*< private >*/ MachineClass parent_class; diff --git a/target/s390x/kvm/kvm.c b/target/s390x/kvm/kvm.c index d6bda3a2a8..4d84dcc018 100644 --- a/target/s390x/kvm/kvm.c +++ b/target/s390x/kvm/kvm.c @@ -86,6 +86,7 @@ #define PRIV_B9_EQBS 0x9c #define PRIV_B9_CLP 0xa0 +#define PRIV_B9_PTF 0xa2 #define PRIV_B9_PCISTG 0xd0 #define PRIV_B9_PCILG 0xd2 #define PRIV_B9_RPCIT 0xd3 @@ -1457,6 +1458,13 @@ static int kvm_mpcifc_service_call(S390CPU *cpu, struct kvm_run *run) } } +static void kvm_handle_ptf(S390CPU *cpu, struct kvm_run *run) +{ + uint8_t r1 = (run->s390_sieic.ipb >> 20) & 0x0f; + + s390_handle_ptf(cpu, r1, RA_IGNORED); +} + static int handle_b9(S390CPU *cpu, struct kvm_run *run, uint8_t ipa1) { int r = 0; @@ -1474,6 +1482,9 @@ static int handle_b9(S390CPU *cpu, struct kvm_run *run, uint8_t ipa1) case PRIV_B9_RPCIT: r = kvm_rpcit_service_call(cpu, run); break; + case PRIV_B9_PTF: + kvm_handle_ptf(cpu, run); + break; case PRIV_B9_EQBS: /* just inject exception */ r = -1; From f530b9e7dad69511f79bbeb3e6683f854ebf703c Mon Sep 17 00:00:00 2001 From: Pierre Morel Date: Mon, 16 Oct 2023 20:39:12 +0200 Subject: [PATCH 0893/1077] target/s390x/cpu topology: activate CPU topology The KVM capability KVM_CAP_S390_CPU_TOPOLOGY is used to activate the S390_FEAT_CONFIGURATION_TOPOLOGY feature and the topology facility in the host CPU model for the guest in the case the topology is available in QEMU and in KVM. The feature is disabled by default and fenced for SE (secure execution). Signed-off-by: Pierre Morel Reviewed-by: Thomas Huth Message-ID: <20231016183925.2384704-9-nsg@linux.ibm.com> Signed-off-by: Thomas Huth --- hw/s390x/cpu-topology.c | 2 +- target/s390x/cpu_models.c | 1 + target/s390x/kvm/kvm.c | 9 +++++++++ 3 files changed, 11 insertions(+), 1 deletion(-) diff --git a/hw/s390x/cpu-topology.c b/hw/s390x/cpu-topology.c index a00a4ce4df..4e4c35f6da 100644 --- a/hw/s390x/cpu-topology.c +++ b/hw/s390x/cpu-topology.c @@ -69,7 +69,7 @@ static int s390_socket_nb(S390CPU *cpu) */ bool s390_has_topology(void) { - return false; + return s390_has_feat(S390_FEAT_CONFIGURATION_TOPOLOGY); } /** diff --git a/target/s390x/cpu_models.c b/target/s390x/cpu_models.c index 98f14c09c2..4dead48650 100644 --- a/target/s390x/cpu_models.c +++ b/target/s390x/cpu_models.c @@ -255,6 +255,7 @@ bool s390_has_feat(S390Feat feat) case S390_FEAT_SIE_CMMA: case S390_FEAT_SIE_PFMFI: case S390_FEAT_SIE_IBS: + case S390_FEAT_CONFIGURATION_TOPOLOGY: return false; break; default: diff --git a/target/s390x/kvm/kvm.c b/target/s390x/kvm/kvm.c index 4d84dcc018..2e43dc746f 100644 --- a/target/s390x/kvm/kvm.c +++ b/target/s390x/kvm/kvm.c @@ -366,6 +366,7 @@ int kvm_arch_init(MachineState *ms, KVMState *s) kvm_vm_enable_cap(s, KVM_CAP_S390_USER_SIGP, 0); kvm_vm_enable_cap(s, KVM_CAP_S390_VECTOR_REGISTERS, 0); kvm_vm_enable_cap(s, KVM_CAP_S390_USER_STSI, 0); + kvm_vm_enable_cap(s, KVM_CAP_S390_CPU_TOPOLOGY, 0); if (ri_allowed()) { if (kvm_vm_enable_cap(s, KVM_CAP_S390_RI, 0) == 0) { cap_ri = 1; @@ -2509,6 +2510,14 @@ void kvm_s390_get_host_cpu_model(S390CPUModel *model, Error **errp) set_bit(S390_FEAT_UNPACK, model->features); } + /* + * If we have kernel support for CPU Topology indicate the + * configuration-topology facility. + */ + if (kvm_check_extension(kvm_state, KVM_CAP_S390_CPU_TOPOLOGY)) { + set_bit(S390_FEAT_CONFIGURATION_TOPOLOGY, model->features); + } + /* We emulate a zPCI bus and AEN, therefore we don't need HW support */ set_bit(S390_FEAT_ZPCI, model->features); set_bit(S390_FEAT_ADAPTER_EVENT_NOTIFICATION, model->features); From a457c2ab5af7d69fd96f0aef2d33800bdc082b8c Mon Sep 17 00:00:00 2001 From: Pierre Morel Date: Mon, 16 Oct 2023 20:39:13 +0200 Subject: [PATCH 0894/1077] qapi/s390x/cpu topology: set-cpu-topology qmp command The modification of the CPU attributes are done through a monitor command. It allows to move the core inside the topology tree to optimize the cache usage in the case the host's hypervisor previously moved the CPU. The same command allows to modify the CPU attributes modifiers like polarization entitlement and the dedicated attribute to notify the guest if the host admin modified scheduling or dedication of a vCPU. With this knowledge the guest has the possibility to optimize the usage of the vCPUs. The command has a feature unstable for the moment. Signed-off-by: Pierre Morel Reviewed-by: Nina Schoetterl-Glausch Co-developed-by: Nina Schoetterl-Glausch Reviewed-by: Thomas Huth Signed-off-by: Nina Schoetterl-Glausch Acked-by: Markus Armbruster Message-ID: <20231016183925.2384704-10-nsg@linux.ibm.com> Signed-off-by: Thomas Huth --- hw/s390x/cpu-topology.c | 132 +++++++++++++++++++++++++++++++++++++++ qapi/machine-target.json | 42 +++++++++++++ 2 files changed, 174 insertions(+) diff --git a/hw/s390x/cpu-topology.c b/hw/s390x/cpu-topology.c index 4e4c35f6da..f3771f5045 100644 --- a/hw/s390x/cpu-topology.c +++ b/hw/s390x/cpu-topology.c @@ -23,6 +23,7 @@ #include "target/s390x/cpu.h" #include "hw/s390x/s390-virtio-ccw.h" #include "hw/s390x/cpu-topology.h" +#include "qapi/qapi-commands-machine-target.h" /* * s390_topology is used to keep the topology information. @@ -257,6 +258,29 @@ static bool s390_topology_check(uint16_t socket_id, uint16_t book_id, return true; } +/** + * s390_topology_need_report + * @cpu: Current cpu + * @drawer_id: future drawer ID + * @book_id: future book ID + * @socket_id: future socket ID + * @entitlement: future entitlement + * @dedicated: future dedicated + * + * A modified topology change report is needed if the topology + * tree or the topology attributes change. + */ +static bool s390_topology_need_report(S390CPU *cpu, int drawer_id, + int book_id, int socket_id, + uint16_t entitlement, bool dedicated) +{ + return cpu->env.drawer_id != drawer_id || + cpu->env.book_id != book_id || + cpu->env.socket_id != socket_id || + cpu->env.entitlement != entitlement || + cpu->env.dedicated != dedicated; +} + /** * s390_update_cpu_props: * @ms: the machine state @@ -325,3 +349,111 @@ void s390_topology_setup_cpu(MachineState *ms, S390CPU *cpu, Error **errp) /* topology tree is reflected in props */ s390_update_cpu_props(ms, cpu); } + +static void s390_change_topology(uint16_t core_id, + bool has_socket_id, uint16_t socket_id, + bool has_book_id, uint16_t book_id, + bool has_drawer_id, uint16_t drawer_id, + bool has_entitlement, + CpuS390Entitlement entitlement, + bool has_dedicated, bool dedicated, + Error **errp) +{ + MachineState *ms = current_machine; + int old_socket_entry; + int new_socket_entry; + bool report_needed; + S390CPU *cpu; + + cpu = s390_cpu_addr2state(core_id); + if (!cpu) { + error_setg(errp, "Core-id %d does not exist!", core_id); + return; + } + + /* Get attributes not provided from cpu and verify the new topology */ + if (!has_socket_id) { + socket_id = cpu->env.socket_id; + } + if (!has_book_id) { + book_id = cpu->env.book_id; + } + if (!has_drawer_id) { + drawer_id = cpu->env.drawer_id; + } + if (!has_dedicated) { + dedicated = cpu->env.dedicated; + } + + /* + * When the user specifies the entitlement as 'auto' on the command line, + * QEMU will set the entitlement as: + * Medium when the CPU is not dedicated. + * High when dedicated is true. + */ + if (!has_entitlement || entitlement == S390_CPU_ENTITLEMENT_AUTO) { + if (dedicated) { + entitlement = S390_CPU_ENTITLEMENT_HIGH; + } else { + entitlement = S390_CPU_ENTITLEMENT_MEDIUM; + } + } + + if (!s390_topology_check(socket_id, book_id, drawer_id, + entitlement, dedicated, errp)) { + return; + } + + /* Check for space on new socket */ + old_socket_entry = s390_socket_nb(cpu); + new_socket_entry = s390_socket_nb_from_ids(drawer_id, book_id, socket_id); + + if (new_socket_entry != old_socket_entry) { + if (s390_topology.cores_per_socket[new_socket_entry] >= + ms->smp.cores) { + error_setg(errp, "No more space on this socket"); + return; + } + /* Update the count of cores in sockets */ + s390_topology.cores_per_socket[new_socket_entry] += 1; + s390_topology.cores_per_socket[old_socket_entry] -= 1; + } + + /* Check if we will need to report the modified topology */ + report_needed = s390_topology_need_report(cpu, drawer_id, book_id, + socket_id, entitlement, + dedicated); + + /* All checks done, report new topology into the vCPU */ + cpu->env.drawer_id = drawer_id; + cpu->env.book_id = book_id; + cpu->env.socket_id = socket_id; + cpu->env.dedicated = dedicated; + cpu->env.entitlement = entitlement; + + /* topology tree is reflected in props */ + s390_update_cpu_props(ms, cpu); + + /* Advertise the topology change */ + if (report_needed) { + s390_cpu_topology_set_changed(true); + } +} + +void qmp_set_cpu_topology(uint16_t core, + bool has_socket, uint16_t socket, + bool has_book, uint16_t book, + bool has_drawer, uint16_t drawer, + bool has_entitlement, CpuS390Entitlement entitlement, + bool has_dedicated, bool dedicated, + Error **errp) +{ + if (!s390_has_topology()) { + error_setg(errp, "This machine doesn't support topology"); + return; + } + + s390_change_topology(core, has_socket, socket, has_book, book, + has_drawer, drawer, has_entitlement, entitlement, + has_dedicated, dedicated, errp); +} diff --git a/qapi/machine-target.json b/qapi/machine-target.json index 93cbf1c128..7688f32ffa 100644 --- a/qapi/machine-target.json +++ b/qapi/machine-target.json @@ -4,6 +4,8 @@ # This work is licensed under the terms of the GNU GPL, version 2 or later. # See the COPYING file in the top-level directory. +{ 'include': 'machine-common.json' } + ## # @CpuModelInfo: # @@ -375,3 +377,43 @@ 'data': [ 'horizontal', 'vertical' ], 'if': 'TARGET_S390X' } + +## +# @set-cpu-topology: +# +# Modify the topology by moving the CPU inside the topology tree, +# or by changing a modifier attribute of a CPU. +# Absent values will not be modified. +# +# @core-id: the vCPU ID to be moved +# +# @socket-id: destination socket to move the vCPU to +# +# @book-id: destination book to move the vCPU to +# +# @drawer-id: destination drawer to move the vCPU to +# +# @entitlement: entitlement to set +# +# @dedicated: whether the provisioning of real to virtual CPU is dedicated +# +# Features: +# +# @unstable: This command is experimental. +# +# Returns: Nothing on success. +# +# Since: 8.2 +## +{ 'command': 'set-cpu-topology', + 'data': { + 'core-id': 'uint16', + '*socket-id': 'uint16', + '*book-id': 'uint16', + '*drawer-id': 'uint16', + '*entitlement': 'CpuS390Entitlement', + '*dedicated': 'bool' + }, + 'features': [ 'unstable' ], + 'if': { 'all': [ 'TARGET_S390X' , 'CONFIG_KVM' ] } +} From ad2d1afc1d7158e1d94f6f7a3efe6efc15dca51c Mon Sep 17 00:00:00 2001 From: Pierre Morel Date: Mon, 16 Oct 2023 20:39:14 +0200 Subject: [PATCH 0895/1077] machine: adding s390 topology to query-cpu-fast S390x provides two more topology attributes, entitlement and dedication. Let's add these CPU attributes to the QAPI command query-cpu-fast. Signed-off-by: Pierre Morel Reviewed-by: Nina Schoetterl-Glausch Co-developed-by: Nina Schoetterl-Glausch Reviewed-by: Thomas Huth Acked-by: Markus Armbruster Signed-off-by: Nina Schoetterl-Glausch Message-ID: <20231016183925.2384704-11-nsg@linux.ibm.com> Signed-off-by: Thomas Huth --- qapi/machine.json | 9 ++++++++- target/s390x/cpu.c | 9 +++++++++ 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/qapi/machine.json b/qapi/machine.json index 17b69a6aea..b4bd26f716 100644 --- a/qapi/machine.json +++ b/qapi/machine.json @@ -57,9 +57,16 @@ # # @cpu-state: the virtual CPU's state # +# @dedicated: the virtual CPU's dedication (since 8.2) +# +# @entitlement: the virtual CPU's entitlement (since 8.2) +# # Since: 2.12 ## -{ 'struct': 'CpuInfoS390', 'data': { 'cpu-state': 'CpuS390State' } } +{ 'struct': 'CpuInfoS390', + 'data': { 'cpu-state': 'CpuS390State', + '*dedicated': 'bool', + '*entitlement': 'CpuS390Entitlement' } } ## # @CpuInfoFast: diff --git a/target/s390x/cpu.c b/target/s390x/cpu.c index ba646461a1..6acfa1c91b 100644 --- a/target/s390x/cpu.c +++ b/target/s390x/cpu.c @@ -38,6 +38,7 @@ #ifndef CONFIG_USER_ONLY #include "sysemu/reset.h" #endif +#include "hw/s390x/cpu-topology.h" #define CR0_RESET 0xE0UL #define CR14_RESET 0xC2000000UL; @@ -146,6 +147,14 @@ static void s390_query_cpu_fast(CPUState *cpu, CpuInfoFast *value) S390CPU *s390_cpu = S390_CPU(cpu); value->u.s390x.cpu_state = s390_cpu->env.cpu_state; +#if !defined(CONFIG_USER_ONLY) + if (s390_has_topology()) { + value->u.s390x.has_dedicated = true; + value->u.s390x.dedicated = s390_cpu->env.dedicated; + value->u.s390x.has_entitlement = true; + value->u.s390x.entitlement = s390_cpu->env.entitlement; + } +#endif } /* S390CPUClass::reset() */ From bb2df37a6286e24edd6bbad162bc3eef07c97c34 Mon Sep 17 00:00:00 2001 From: Pierre Morel Date: Mon, 16 Oct 2023 20:39:15 +0200 Subject: [PATCH 0896/1077] machine: adding s390 topology to info hotpluggable-cpus S390 topology adds books and drawers topology containers. Let's add these to the HMP information for hotpluggable cpus. Signed-off-by: Pierre Morel Reviewed-by: Nina Schoetterl-Glausch Reviewed-by: Thomas Huth Message-ID: <20231016183925.2384704-12-nsg@linux.ibm.com> Signed-off-by: Thomas Huth --- hw/core/machine-hmp-cmds.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/hw/core/machine-hmp-cmds.c b/hw/core/machine-hmp-cmds.c index c3e55ef9e9..9a4b59c6f2 100644 --- a/hw/core/machine-hmp-cmds.c +++ b/hw/core/machine-hmp-cmds.c @@ -71,6 +71,12 @@ void hmp_hotpluggable_cpus(Monitor *mon, const QDict *qdict) if (c->has_node_id) { monitor_printf(mon, " node-id: \"%" PRIu64 "\"\n", c->node_id); } + if (c->has_drawer_id) { + monitor_printf(mon, " drawer-id: \"%" PRIu64 "\"\n", c->drawer_id); + } + if (c->has_book_id) { + monitor_printf(mon, " book-id: \"%" PRIu64 "\"\n", c->book_id); + } if (c->has_socket_id) { monitor_printf(mon, " socket-id: \"%" PRIu64 "\"\n", c->socket_id); } From 1cfe52b7824067962357493475f0c36c7900f799 Mon Sep 17 00:00:00 2001 From: Pierre Morel Date: Mon, 16 Oct 2023 20:39:16 +0200 Subject: [PATCH 0897/1077] qapi/s390x/cpu topology: CPU_POLARIZATION_CHANGE QAPI event When the guest asks to change the polarization this change is forwarded to the upper layer using QAPI. The upper layer is supposed to take according decisions concerning CPU provisioning. Signed-off-by: Pierre Morel Reviewed-by: Thomas Huth Reviewed-by: Nina Schoetterl-Glausch Co-developed-by: Nina Schoetterl-Glausch Acked-by: Markus Armbruster Signed-off-by: Nina Schoetterl-Glausch Message-ID: <20231016183925.2384704-13-nsg@linux.ibm.com> Signed-off-by: Thomas Huth --- hw/s390x/cpu-topology.c | 2 ++ qapi/machine-target.json | 35 +++++++++++++++++++++++++++++++++++ 2 files changed, 37 insertions(+) diff --git a/hw/s390x/cpu-topology.c b/hw/s390x/cpu-topology.c index f3771f5045..327bccea4f 100644 --- a/hw/s390x/cpu-topology.c +++ b/hw/s390x/cpu-topology.c @@ -24,6 +24,7 @@ #include "hw/s390x/s390-virtio-ccw.h" #include "hw/s390x/cpu-topology.h" #include "qapi/qapi-commands-machine-target.h" +#include "qapi/qapi-events-machine-target.h" /* * s390_topology is used to keep the topology information. @@ -136,6 +137,7 @@ void s390_handle_ptf(S390CPU *cpu, uint8_t r1, uintptr_t ra) } else { s390_topology.polarization = polarization; s390_cpu_topology_set_changed(true); + qapi_event_send_cpu_polarization_change(polarization); setcc(cpu, 0); } break; diff --git a/qapi/machine-target.json b/qapi/machine-target.json index 7688f32ffa..ac93a5f82c 100644 --- a/qapi/machine-target.json +++ b/qapi/machine-target.json @@ -417,3 +417,38 @@ 'features': [ 'unstable' ], 'if': { 'all': [ 'TARGET_S390X' , 'CONFIG_KVM' ] } } + +## +# @CPU_POLARIZATION_CHANGE: +# +# Emitted when the guest asks to change the polarization. +# +# The guest can tell the host (via the PTF instruction) whether the +# CPUs should be provisioned using horizontal or vertical polarization. +# +# On horizontal polarization the host is expected to provision all vCPUs +# equally. +# +# On vertical polarization the host can provision each vCPU differently. +# The guest will get information on the details of the provisioning +# the next time it uses the STSI(15) instruction. +# +# @polarization: polarization specified by the guest +# +# Features: +# +# @unstable: This event is experimental. +# +# Since: 8.2 +# +# Example: +# +# <- { "event": "CPU_POLARIZATION_CHANGE", +# "data": { "polarization": "horizontal" }, +# "timestamp": { "seconds": 1401385907, "microseconds": 422329 } } +## +{ 'event': 'CPU_POLARIZATION_CHANGE', + 'data': { 'polarization': 'CpuS390Polarization' }, + 'features': [ 'unstable' ], + 'if': { 'all': [ 'TARGET_S390X', 'CONFIG_KVM' ] } +} From 154893a784cb3f1349fce65ab6038e0bc462d218 Mon Sep 17 00:00:00 2001 From: Pierre Morel Date: Mon, 16 Oct 2023 20:39:17 +0200 Subject: [PATCH 0898/1077] qapi/s390x/cpu topology: add query-s390x-cpu-polarization command The query-s390x-cpu-polarization qmp command returns the current CPU polarization of the machine. Signed-off-by: Pierre Morel Reviewed-by: Thomas Huth Reviewed-by: Nina Schoetterl-Glausch Co-developed-by: Nina Schoetterl-Glausch Acked-by: Markus Armbruster Signed-off-by: Nina Schoetterl-Glausch Message-ID: <20231016183925.2384704-14-nsg@linux.ibm.com> Signed-off-by: Thomas Huth --- hw/s390x/cpu-topology.c | 8 ++++++++ qapi/machine-target.json | 30 ++++++++++++++++++++++++++++++ 2 files changed, 38 insertions(+) diff --git a/hw/s390x/cpu-topology.c b/hw/s390x/cpu-topology.c index 327bccea4f..f16bdf65fa 100644 --- a/hw/s390x/cpu-topology.c +++ b/hw/s390x/cpu-topology.c @@ -459,3 +459,11 @@ void qmp_set_cpu_topology(uint16_t core, has_drawer, drawer, has_entitlement, entitlement, has_dedicated, dedicated, errp); } + +CpuPolarizationInfo *qmp_query_s390x_cpu_polarization(Error **errp) +{ + CpuPolarizationInfo *info = g_new0(CpuPolarizationInfo, 1); + + info->polarization = s390_topology.polarization; + return info; +} diff --git a/qapi/machine-target.json b/qapi/machine-target.json index ac93a5f82c..4e55adbe00 100644 --- a/qapi/machine-target.json +++ b/qapi/machine-target.json @@ -452,3 +452,33 @@ 'features': [ 'unstable' ], 'if': { 'all': [ 'TARGET_S390X', 'CONFIG_KVM' ] } } + +## +# @CpuPolarizationInfo: +# +# The result of a CPU polarization query. +# +# @polarization: the CPU polarization +# +# Since: 8.2 +## +{ 'struct': 'CpuPolarizationInfo', + 'data': { 'polarization': 'CpuS390Polarization' }, + 'if': { 'all': [ 'TARGET_S390X', 'CONFIG_KVM' ] } +} + +## +# @query-s390x-cpu-polarization: +# +# Features: +# +# @unstable: This command is experimental. +# +# Returns: the machine's CPU polarization +# +# Since: 8.2 +## +{ 'command': 'query-s390x-cpu-polarization', 'returns': 'CpuPolarizationInfo', + 'features': [ 'unstable' ], + 'if': { 'all': [ 'TARGET_S390X', 'CONFIG_KVM' ] } +} From 0d177cdd2ba402f7f0aee301e56037311c7a8781 Mon Sep 17 00:00:00 2001 From: Pierre Morel Date: Mon, 16 Oct 2023 20:39:18 +0200 Subject: [PATCH 0899/1077] docs/s390x/cpu topology: document s390x cpu topology Add some basic examples for the definition of cpu topology in s390x. Signed-off-by: Pierre Morel Co-developed-by: Nina Schoetterl-Glausch Reviewed-by: Thomas Huth Signed-off-by: Nina Schoetterl-Glausch Message-ID: <20231016183925.2384704-15-nsg@linux.ibm.com> Signed-off-by: Thomas Huth --- MAINTAINERS | 2 + docs/devel/index-internals.rst | 1 + docs/devel/s390-cpu-topology.rst | 170 ++++++++++++++++++++ docs/system/s390x/cpu-topology.rst | 244 +++++++++++++++++++++++++++++ docs/system/target-s390x.rst | 1 + qapi/machine.json | 2 + 6 files changed, 420 insertions(+) create mode 100644 docs/devel/s390-cpu-topology.rst create mode 100644 docs/system/s390x/cpu-topology.rst diff --git a/MAINTAINERS b/MAINTAINERS index cfc37e9af7..de8d9f5104 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1716,6 +1716,8 @@ S: Supported F: include/hw/s390x/cpu-topology.h F: hw/s390x/cpu-topology.c F: target/s390x/kvm/stsi-topology.c +F: docs/devel/s390-cpu-topology.rst +F: docs/system/s390x/cpu-topology.rst X86 Machines ------------ diff --git a/docs/devel/index-internals.rst b/docs/devel/index-internals.rst index e1a93df263..6f81df92bc 100644 --- a/docs/devel/index-internals.rst +++ b/docs/devel/index-internals.rst @@ -14,6 +14,7 @@ Details about QEMU's various subsystems including how to add features to them. migration multi-process reset + s390-cpu-topology s390-dasd-ipl tracing vfio-migration diff --git a/docs/devel/s390-cpu-topology.rst b/docs/devel/s390-cpu-topology.rst new file mode 100644 index 0000000000..9eab28d5e5 --- /dev/null +++ b/docs/devel/s390-cpu-topology.rst @@ -0,0 +1,170 @@ +QAPI interface for S390 CPU topology +==================================== + +The following sections will explain the QAPI interface for S390 CPU topology +with the help of exemplary output. +For this, let's assume that QEMU has been started with the following +command, defining 4 CPUs, where CPU[0] is defined by the -smp argument and will +have default values: + +.. code-block:: bash + + qemu-system-s390x \ + -enable-kvm \ + -cpu z14,ctop=on \ + -smp 1,drawers=3,books=3,sockets=2,cores=2,maxcpus=36 \ + -device z14-s390x-cpu,core-id=19,entitlement=high \ + -device z14-s390x-cpu,core-id=11,entitlement=low \ + -device z14-s390x-cpu,core-id=112,entitlement=high \ + ... + +Additions to query-cpus-fast +---------------------------- + +The command query-cpus-fast allows querying the topology tree and +modifiers for all configured vCPUs. + +.. code-block:: QMP + + { "execute": "query-cpus-fast" } + { + "return": [ + { + "dedicated": false, + "thread-id": 536993, + "props": { + "core-id": 0, + "socket-id": 0, + "drawer-id": 0, + "book-id": 0 + }, + "cpu-state": "operating", + "entitlement": "medium", + "qom-path": "/machine/unattached/device[0]", + "cpu-index": 0, + "target": "s390x" + }, + { + "dedicated": false, + "thread-id": 537003, + "props": { + "core-id": 19, + "socket-id": 1, + "drawer-id": 0, + "book-id": 2 + }, + "cpu-state": "operating", + "entitlement": "high", + "qom-path": "/machine/peripheral-anon/device[0]", + "cpu-index": 19, + "target": "s390x" + }, + { + "dedicated": false, + "thread-id": 537004, + "props": { + "core-id": 11, + "socket-id": 1, + "drawer-id": 0, + "book-id": 1 + }, + "cpu-state": "operating", + "entitlement": "low", + "qom-path": "/machine/peripheral-anon/device[1]", + "cpu-index": 11, + "target": "s390x" + }, + { + "dedicated": true, + "thread-id": 537005, + "props": { + "core-id": 112, + "socket-id": 0, + "drawer-id": 3, + "book-id": 2 + }, + "cpu-state": "operating", + "entitlement": "high", + "qom-path": "/machine/peripheral-anon/device[2]", + "cpu-index": 112, + "target": "s390x" + } + ] + } + + +QAPI command: set-cpu-topology +------------------------------ + +The command set-cpu-topology allows modifying the topology tree +or the topology modifiers of a vCPU in the configuration. + +.. code-block:: QMP + + { "execute": "set-cpu-topology", + "arguments": { + "core-id": 11, + "socket-id": 0, + "book-id": 0, + "drawer-id": 0, + "entitlement": "low", + "dedicated": false + } + } + {"return": {}} + +The core-id parameter is the only mandatory parameter and every +unspecified parameter keeps its previous value. + +QAPI event CPU_POLARIZATION_CHANGE +---------------------------------- + +When a guest requests a modification of the polarization, +QEMU sends a CPU_POLARIZATION_CHANGE event. + +When requesting the change, the guest only specifies horizontal or +vertical polarization. +It is the job of the entity administrating QEMU to set the dedication and fine +grained vertical entitlement in response to this event. + +Note that a vertical polarized dedicated vCPU can only have a high +entitlement, giving 6 possibilities for vCPU polarization: + +- Horizontal +- Horizontal dedicated +- Vertical low +- Vertical medium +- Vertical high +- Vertical high dedicated + +Example of the event received when the guest issues the CPU instruction +Perform Topology Function PTF(0) to request an horizontal polarization: + +.. code-block:: QMP + + { + "timestamp": { + "seconds": 1687870305, + "microseconds": 566299 + }, + "event": "CPU_POLARIZATION_CHANGE", + "data": { + "polarization": "horizontal" + } + } + +QAPI query command: query-s390x-cpu-polarization +------------------------------------------------ + +The query command query-s390x-cpu-polarization returns the current +CPU polarization of the machine. +In this case the guest previously issued a PTF(1) to request vertical polarization: + +.. code-block:: QMP + + { "execute": "query-s390x-cpu-polarization" } + { + "return": { + "polarization": "vertical" + } + } diff --git a/docs/system/s390x/cpu-topology.rst b/docs/system/s390x/cpu-topology.rst new file mode 100644 index 0000000000..5133fdc362 --- /dev/null +++ b/docs/system/s390x/cpu-topology.rst @@ -0,0 +1,244 @@ +.. _cpu-topology-s390x: + +CPU topology on s390x +===================== + +Since QEMU 8.2, CPU topology on s390x provides up to 3 levels of +topology containers: drawers, books and sockets. They define a +tree-shaped hierarchy. + +The socket container has one or more CPU entries. +Each of these CPU entries consists of a bitmap and three CPU attributes: + +- CPU type +- entitlement +- dedication + +Each bit set in the bitmap correspond to a core-id of a vCPU with matching +attributes. + +This documentation provides general information on S390 CPU topology, +how to enable it and explains the new CPU attributes. +For information on how to modify the S390 CPU topology and how to +monitor polarization changes, see ``docs/devel/s390-cpu-topology.rst``. + +Prerequisites +------------- + +To use the CPU topology, you need to run with KVM on a s390x host that +uses the Linux kernel v6.0 or newer (which provide the so-called +``KVM_CAP_S390_CPU_TOPOLOGY`` capability that allows QEMU to signal the +CPU topology facility via the so-called STFLE bit 11 to the VM). + +Enabling CPU topology +--------------------- + +Currently, CPU topology is only enabled in the host model by default. + +Enabling CPU topology in a CPU model is done by setting the CPU flag +``ctop`` to ``on`` as in: + +.. code-block:: bash + + -cpu gen16b,ctop=on + +Having the topology disabled by default allows migration between +old and new QEMU without adding new flags. + +Default topology usage +---------------------- + +The CPU topology can be specified on the QEMU command line +with the ``-smp`` or the ``-device`` QEMU command arguments. + +Note also that since 7.2 threads are no longer supported in the topology +and the ``-smp`` command line argument accepts only ``threads=1``. + +If none of the containers attributes (drawers, books, sockets) are +specified for the ``-smp`` flag, the number of these containers +is 1. + +Thus the following two options will result in the same topology: + +.. code-block:: bash + + -smp cpus=5,drawer=1,books=1,sockets=8,cores=4,maxcpus=32 + +and + +.. code-block:: bash + + -smp cpus=5,sockets=8,cores=4,maxcpus=32 + +When a CPU is defined by the ``-smp`` command argument, its position +inside the topology is calculated by adding the CPUs to the topology +based on the core-id starting with core-0 at position 0 of socket-0, +book-0, drawer-0 and filling all CPUs of socket-0 before filling socket-1 +of book-0 and so on up to the last socket of the last book of the last +drawer. + +When a CPU is defined by the ``-device`` command argument, the +tree topology attributes must all be defined or all not defined. + +.. code-block:: bash + + -device gen16b-s390x-cpu,drawer-id=1,book-id=1,socket-id=2,core-id=1 + +or + +.. code-block:: bash + + -device gen16b-s390x-cpu,core-id=1,dedicated=true + +If none of the tree attributes (drawer, book, sockets), are specified +for the ``-device`` argument, like for all CPUs defined with the ``-smp`` +command argument the topology tree attributes will be set by simply +adding the CPUs to the topology based on the core-id. + +QEMU will not try to resolve collisions and will report an error if the +CPU topology defined explicitly or implicitly on a ``-device`` +argument collides with the definition of a CPU implicitly defined +on the ``-smp`` argument. + +When the topology modifier attributes are not defined for the +``-device`` command argument they takes following default values: + +- dedicated: ``false`` +- entitlement: ``medium`` + + +Hot plug +++++++++ + +New CPUs can be plugged using the device_add hmp command as in: + +.. code-block:: bash + + (qemu) device_add gen16b-s390x-cpu,core-id=9 + +The placement of the CPU is derived from the core-id as described above. + +The topology can of course also be fully defined: + +.. code-block:: bash + + (qemu) device_add gen16b-s390x-cpu,drawer-id=1,book-id=1,socket-id=2,core-id=1 + + +Examples +++++++++ + +In the following machine we define 8 sockets with 4 cores each. + +.. code-block:: bash + + $ qemu-system-s390x -m 2G \ + -cpu gen16b,ctop=on \ + -smp cpus=5,sockets=8,cores=4,maxcpus=32 \ + -device host-s390x-cpu,core-id=14 \ + +A new CPUs can be plugged using the device_add hmp command as before: + +.. code-block:: bash + + (qemu) device_add gen16b-s390x-cpu,core-id=9 + +The core-id defines the placement of the core in the topology by +starting with core 0 in socket 0 up to maxcpus. + +In the example above: + +* There are 5 CPUs provided to the guest with the ``-smp`` command line + They will take the core-ids 0,1,2,3,4 + As we have 4 cores in a socket, we have 4 CPUs provided + to the guest in socket 0, with core-ids 0,1,2,3. + The last CPU, with core-id 4, will be on socket 1. + +* the core with ID 14 provided by the ``-device`` command line will + be placed in socket 3, with core-id 14 + +* the core with ID 9 provided by the ``device_add`` qmp command will + be placed in socket 2, with core-id 9 + + +Polarization, entitlement and dedication +---------------------------------------- + +Polarization +++++++++++++ + +The polarization affects how the CPUs of a shared host are utilized/distributed +among guests. +The guest determines the polarization by using the PTF instruction. + +Polarization defines two models of CPU provisioning: horizontal +and vertical. + +The horizontal polarization is the default model on boot and after +subsystem reset. When horizontal polarization is in effect all vCPUs should +have about equal resource provisioning. + +In the vertical polarization model vCPUs are unequal, but overall more resources +might be available. +The guest can make use of the vCPU entitlement information provided by the host +to optimize kernel thread scheduling. + +A subsystem reset puts all vCPU of the configuration into the +horizontal polarization. + +Entitlement ++++++++++++ + +The vertical polarization specifies that the guest's vCPU can get +different real CPU provisioning: + +- a vCPU with vertical high entitlement specifies that this + vCPU gets 100% of the real CPU provisioning. + +- a vCPU with vertical medium entitlement specifies that this + vCPU shares the real CPU with other vCPUs. + +- a vCPU with vertical low entitlement specifies that this + vCPU only gets real CPU provisioning when no other vCPUs needs it. + +In the case a vCPU with vertical high entitlement does not use +the real CPU, the unused "slack" can be dispatched to other vCPU +with medium or low entitlement. + +A vCPU can be "dedicated" in which case the vCPU is fully dedicated to a single +real CPU. + +The dedicated bit is an indication of affinity of a vCPU for a real CPU +while the entitlement indicates the sharing or exclusivity of use. + +Defining the topology on the command line +----------------------------------------- + +The topology can entirely be defined using -device cpu statements, +with the exception of CPU 0 which must be defined with the -smp +argument. + +For example, here we set the position of the cores 1,2,3 to +drawer 1, book 1, socket 2 and cores 0,9 and 14 to drawer 0, +book 0, socket 0 without defining entitlement or dedication. +Core 4 will be set on its default position on socket 1 +(since we have 4 core per socket) and we define it as dedicated and +with vertical high entitlement. + +.. code-block:: bash + + $ qemu-system-s390x -m 2G \ + -cpu gen16b,ctop=on \ + -smp cpus=1,sockets=8,cores=4,maxcpus=32 \ + \ + -device gen16b-s390x-cpu,drawer-id=1,book-id=1,socket-id=2,core-id=1 \ + -device gen16b-s390x-cpu,drawer-id=1,book-id=1,socket-id=2,core-id=2 \ + -device gen16b-s390x-cpu,drawer-id=1,book-id=1,socket-id=2,core-id=3 \ + \ + -device gen16b-s390x-cpu,drawer-id=0,book-id=0,socket-id=0,core-id=9 \ + -device gen16b-s390x-cpu,drawer-id=0,book-id=0,socket-id=0,core-id=14 \ + \ + -device gen16b-s390x-cpu,core-id=4,dedicated=on,entitlement=high + +The entitlement defined for the CPU 4 will only be used after the guest +successfully enables vertical polarization by using the PTF instruction. diff --git a/docs/system/target-s390x.rst b/docs/system/target-s390x.rst index f6f11433c7..94c981e732 100644 --- a/docs/system/target-s390x.rst +++ b/docs/system/target-s390x.rst @@ -34,3 +34,4 @@ Architectural features .. toctree:: s390x/bootdevices s390x/protvirt + s390x/cpu-topology diff --git a/qapi/machine.json b/qapi/machine.json index b4bd26f716..6c9d2f6dcf 100644 --- a/qapi/machine.json +++ b/qapi/machine.json @@ -909,6 +909,8 @@ # Which members are optional and which mandatory depends on the # architecture and board. # +# For s390x see :ref:`cpu-topology-s390x`. +# # The ids other than the node-id specify the position of the CPU # within the CPU topology (as defined by the machine property "smp", # thus see also type @SMPConfiguration) From e5bc49d54d94fb680b0f200ae0529dda2c91c8db Mon Sep 17 00:00:00 2001 From: Pierre Morel Date: Mon, 16 Oct 2023 20:39:19 +0200 Subject: [PATCH 0900/1077] tests/avocado: s390x cpu topology core Introduction of the s390x cpu topology core functions and basic tests. We test the correlation between the command line and the QMP results in query-cpus-fast for various CPU topology. Signed-off-by: Pierre Morel Reviewed-by: Nina Schoetterl-Glausch Co-developed-by: Nina Schoetterl-Glausch Tested-by: Thomas Huth Signed-off-by: Nina Schoetterl-Glausch Message-ID: <20231016183925.2384704-16-nsg@linux.ibm.com> Signed-off-by: Thomas Huth --- MAINTAINERS | 1 + tests/avocado/s390_topology.py | 200 +++++++++++++++++++++++++++++++++ 2 files changed, 201 insertions(+) create mode 100644 tests/avocado/s390_topology.py diff --git a/MAINTAINERS b/MAINTAINERS index de8d9f5104..9ad32e20f4 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1718,6 +1718,7 @@ F: hw/s390x/cpu-topology.c F: target/s390x/kvm/stsi-topology.c F: docs/devel/s390-cpu-topology.rst F: docs/system/s390x/cpu-topology.rst +F: tests/avocado/s390_topology.py X86 Machines ------------ diff --git a/tests/avocado/s390_topology.py b/tests/avocado/s390_topology.py new file mode 100644 index 0000000000..9078b45281 --- /dev/null +++ b/tests/avocado/s390_topology.py @@ -0,0 +1,200 @@ +# Functional test that boots a Linux kernel and checks the console +# +# Copyright IBM Corp. 2023 +# +# Author: +# Pierre Morel +# +# This work is licensed under the terms of the GNU GPL, version 2 or +# later. See the COPYING file in the top-level directory. + +import os +import shutil +import time + +from avocado_qemu import QemuSystemTest +from avocado_qemu import exec_command +from avocado_qemu import exec_command_and_wait_for_pattern +from avocado_qemu import interrupt_interactive_console_until_pattern +from avocado_qemu import wait_for_console_pattern +from avocado.utils import process +from avocado.utils import archive + + +class S390CPUTopology(QemuSystemTest): + """ + S390x CPU topology consists of 4 topology layers, from bottom to top, + the cores, sockets, books and drawers and 2 modifiers attributes, + the entitlement and the dedication. + See: docs/system/s390x/cpu-topology.rst. + + S390x CPU topology is setup in different ways: + - implicitly from the '-smp' argument by completing each topology + level one after the other beginning with drawer 0, book 0 and + socket 0. + - explicitly from the '-device' argument on the QEMU command line + - explicitly by hotplug of a new CPU using QMP or HMP + - it is modified by using QMP 'set-cpu-topology' + + The S390x modifier attribute entitlement depends on the machine + polarization, which can be horizontal or vertical. + The polarization is changed on a request from the guest. + """ + timeout = 90 + + KERNEL_COMMON_COMMAND_LINE = ('printk.time=0 ' + 'root=/dev/ram ' + 'selinux=0 ' + 'rdinit=/bin/sh') + + def wait_until_booted(self): + wait_for_console_pattern(self, 'no job control', + failure_message='Kernel panic - not syncing', + vm=None) + + def check_topology(self, c, s, b, d, e, t): + res = self.vm.qmp('query-cpus-fast') + cpus = res['return'] + for cpu in cpus: + core = cpu['props']['core-id'] + socket = cpu['props']['socket-id'] + book = cpu['props']['book-id'] + drawer = cpu['props']['drawer-id'] + entitlement = cpu.get('entitlement') + dedicated = cpu.get('dedicated') + if core == c: + self.assertEqual(drawer, d) + self.assertEqual(book, b) + self.assertEqual(socket, s) + self.assertEqual(entitlement, e) + self.assertEqual(dedicated, t) + + def kernel_init(self): + """ + We need a VM that supports CPU topology, + currently this only the case when using KVM, not TCG. + We need a kernel supporting the CPU topology. + We need a minimal root filesystem with a shell. + """ + self.require_accelerator("kvm") + kernel_url = ('https://archives.fedoraproject.org/pub/archive' + '/fedora-secondary/releases/35/Server/s390x/os' + '/images/kernel.img') + kernel_hash = '0d1aaaf303f07cf0160c8c48e56fe638' + kernel_path = self.fetch_asset(kernel_url, algorithm='md5', + asset_hash=kernel_hash) + + initrd_url = ('https://archives.fedoraproject.org/pub/archive' + '/fedora-secondary/releases/35/Server/s390x/os' + '/images/initrd.img') + initrd_hash = 'a122057d95725ac030e2ec51df46e172' + initrd_path_xz = self.fetch_asset(initrd_url, algorithm='md5', + asset_hash=initrd_hash) + initrd_path = os.path.join(self.workdir, 'initrd-raw.img') + archive.lzma_uncompress(initrd_path_xz, initrd_path) + + self.vm.set_console() + kernel_command_line = self.KERNEL_COMMON_COMMAND_LINE + self.vm.add_args('-nographic', + '-enable-kvm', + '-cpu', 'max,ctop=on', + '-m', '512', + '-kernel', kernel_path, + '-initrd', initrd_path, + '-append', kernel_command_line) + + def test_single(self): + """ + This test checks the simplest topology with a single CPU. + + :avocado: tags=arch:s390x + :avocado: tags=machine:s390-ccw-virtio + """ + self.kernel_init() + self.vm.launch() + self.wait_until_booted() + self.check_topology(0, 0, 0, 0, 'medium', False) + + def test_default(self): + """ + This test checks the implicit topology. + + :avocado: tags=arch:s390x + :avocado: tags=machine:s390-ccw-virtio + """ + self.kernel_init() + self.vm.add_args('-smp', + '13,drawers=2,books=2,sockets=3,cores=2,maxcpus=24') + self.vm.launch() + self.wait_until_booted() + self.check_topology(0, 0, 0, 0, 'medium', False) + self.check_topology(1, 0, 0, 0, 'medium', False) + self.check_topology(2, 1, 0, 0, 'medium', False) + self.check_topology(3, 1, 0, 0, 'medium', False) + self.check_topology(4, 2, 0, 0, 'medium', False) + self.check_topology(5, 2, 0, 0, 'medium', False) + self.check_topology(6, 0, 1, 0, 'medium', False) + self.check_topology(7, 0, 1, 0, 'medium', False) + self.check_topology(8, 1, 1, 0, 'medium', False) + self.check_topology(9, 1, 1, 0, 'medium', False) + self.check_topology(10, 2, 1, 0, 'medium', False) + self.check_topology(11, 2, 1, 0, 'medium', False) + self.check_topology(12, 0, 0, 1, 'medium', False) + + def test_move(self): + """ + This test checks the topology modification by moving a CPU + to another socket: CPU 0 is moved from socket 0 to socket 2. + + :avocado: tags=arch:s390x + :avocado: tags=machine:s390-ccw-virtio + """ + self.kernel_init() + self.vm.add_args('-smp', + '1,drawers=2,books=2,sockets=3,cores=2,maxcpus=24') + self.vm.launch() + self.wait_until_booted() + + self.check_topology(0, 0, 0, 0, 'medium', False) + res = self.vm.qmp('set-cpu-topology', + {'core-id': 0, 'socket-id': 2, 'entitlement': 'low'}) + self.assertEqual(res['return'], {}) + self.check_topology(0, 2, 0, 0, 'low', False) + + def test_dash_device(self): + """ + This test verifies that a CPU defined with the '-device' + command line option finds its right place inside the topology. + + :avocado: tags=arch:s390x + :avocado: tags=machine:s390-ccw-virtio + """ + self.kernel_init() + self.vm.add_args('-smp', + '1,drawers=2,books=2,sockets=3,cores=2,maxcpus=24') + self.vm.add_args('-device', 'max-s390x-cpu,core-id=10') + self.vm.add_args('-device', + 'max-s390x-cpu,' + 'core-id=1,socket-id=0,book-id=1,drawer-id=1,entitlement=low') + self.vm.add_args('-device', + 'max-s390x-cpu,' + 'core-id=2,socket-id=0,book-id=1,drawer-id=1,entitlement=medium') + self.vm.add_args('-device', + 'max-s390x-cpu,' + 'core-id=3,socket-id=1,book-id=1,drawer-id=1,entitlement=high') + self.vm.add_args('-device', + 'max-s390x-cpu,' + 'core-id=4,socket-id=1,book-id=1,drawer-id=1') + self.vm.add_args('-device', + 'max-s390x-cpu,' + 'core-id=5,socket-id=2,book-id=1,drawer-id=1,dedicated=true') + + self.vm.launch() + self.wait_until_booted() + + self.check_topology(10, 2, 1, 0, 'medium', False) + self.check_topology(1, 0, 1, 1, 'low', False) + self.check_topology(2, 0, 1, 1, 'medium', False) + self.check_topology(3, 1, 1, 1, 'high', False) + self.check_topology(4, 1, 1, 1, 'medium', False) + self.check_topology(5, 2, 1, 1, 'high', True) From cb042c73f37e820fe8fe5bdc71cb92836aea5955 Mon Sep 17 00:00:00 2001 From: Pierre Morel Date: Mon, 16 Oct 2023 20:39:20 +0200 Subject: [PATCH 0901/1077] tests/avocado: s390x cpu topology polarization Polarization is changed on a request from the guest. Let's verify the polarization is accordingly set by QEMU. Signed-off-by: Pierre Morel Co-developed-by: Nina Schoetterl-Glausch Reviewed-by: Thomas Huth Reviewed-by: Nina Schoetterl-Glausch Signed-off-by: Nina Schoetterl-Glausch Message-ID: <20231016183925.2384704-17-nsg@linux.ibm.com> Signed-off-by: Thomas Huth --- tests/avocado/s390_topology.py | 45 ++++++++++++++++++++++++++++++++++ 1 file changed, 45 insertions(+) diff --git a/tests/avocado/s390_topology.py b/tests/avocado/s390_topology.py index 9078b45281..8166cee134 100644 --- a/tests/avocado/s390_topology.py +++ b/tests/avocado/s390_topology.py @@ -41,6 +41,7 @@ class S390CPUTopology(QemuSystemTest): The polarization is changed on a request from the guest. """ timeout = 90 + event_timeout = 10 KERNEL_COMMON_COMMAND_LINE = ('printk.time=0 ' 'root=/dev/ram ' @@ -103,6 +104,14 @@ class S390CPUTopology(QemuSystemTest): '-initrd', initrd_path, '-append', kernel_command_line) + def system_init(self): + self.log.info("System init") + exec_command_and_wait_for_pattern(self, + """ mount proc -t proc /proc; + mount sys -t sysfs /sys; + cat /sys/devices/system/cpu/dispatching """, + '0') + def test_single(self): """ This test checks the simplest topology with a single CPU. @@ -198,3 +207,39 @@ class S390CPUTopology(QemuSystemTest): self.check_topology(3, 1, 1, 1, 'high', False) self.check_topology(4, 1, 1, 1, 'medium', False) self.check_topology(5, 2, 1, 1, 'high', True) + + + def guest_set_dispatching(self, dispatching): + exec_command(self, + f'echo {dispatching} > /sys/devices/system/cpu/dispatching') + self.vm.event_wait('CPU_POLARIZATION_CHANGE', self.event_timeout) + exec_command_and_wait_for_pattern(self, + 'cat /sys/devices/system/cpu/dispatching', dispatching) + + + def test_polarization(self): + """ + This test verifies that QEMU modifies the entitlement change after + several guest polarization change requests. + + :avocado: tags=arch:s390x + :avocado: tags=machine:s390-ccw-virtio + """ + self.kernel_init() + self.vm.launch() + self.wait_until_booted() + + self.system_init() + res = self.vm.qmp('query-s390x-cpu-polarization') + self.assertEqual(res['return']['polarization'], 'horizontal') + self.check_topology(0, 0, 0, 0, 'medium', False) + + self.guest_set_dispatching('1'); + res = self.vm.qmp('query-s390x-cpu-polarization') + self.assertEqual(res['return']['polarization'], 'vertical') + self.check_topology(0, 0, 0, 0, 'medium', False) + + self.guest_set_dispatching('0'); + res = self.vm.qmp('query-s390x-cpu-polarization') + self.assertEqual(res['return']['polarization'], 'horizontal') + self.check_topology(0, 0, 0, 0, 'medium', False) From 16ab722edb0c308e18364b70a84ef9f7dfd0a946 Mon Sep 17 00:00:00 2001 From: Pierre Morel Date: Mon, 16 Oct 2023 20:39:21 +0200 Subject: [PATCH 0902/1077] tests/avocado: s390x cpu topology entitlement tests Test changes in the entitlement from both a guest and a host point of view, depending on the polarization. Signed-off-by: Pierre Morel Reviewed-by: Nina Schoetterl-Glausch Co-developed-by: Nina Schoetterl-Glausch Tested-by: Thomas Huth Signed-off-by: Nina Schoetterl-Glausch Message-ID: <20231016183925.2384704-18-nsg@linux.ibm.com> Signed-off-by: Thomas Huth --- tests/avocado/s390_topology.py | 62 ++++++++++++++++++++++++++++++++++ 1 file changed, 62 insertions(+) diff --git a/tests/avocado/s390_topology.py b/tests/avocado/s390_topology.py index 8166cee134..24fac9a54d 100644 --- a/tests/avocado/s390_topology.py +++ b/tests/avocado/s390_topology.py @@ -243,3 +243,65 @@ class S390CPUTopology(QemuSystemTest): res = self.vm.qmp('query-s390x-cpu-polarization') self.assertEqual(res['return']['polarization'], 'horizontal') self.check_topology(0, 0, 0, 0, 'medium', False) + + + def check_polarization(self, polarization): + #We need to wait for the change to have been propagated to the kernel + exec_command_and_wait_for_pattern(self, + "\n".join([ + "timeout 1 sh -c 'while true", + 'do', + ' syspath="/sys/devices/system/cpu/cpu0/polarization"', + ' polarization="$(cat "$syspath")" || exit', + f' if [ "$polarization" = "{polarization}" ]; then', + ' exit 0', + ' fi', + ' sleep 0.01', + #searched for strings mustn't show up in command, '' to obfuscate + "done' && echo succ''ess || echo fail''ure", + ]), + "success", "failure") + + + def test_entitlement(self): + """ + This test verifies that QEMU modifies the entitlement + after a guest request and that the guest sees the change. + + :avocado: tags=arch:s390x + :avocado: tags=machine:s390-ccw-virtio + """ + self.kernel_init() + self.vm.launch() + self.wait_until_booted() + + self.system_init() + + self.check_polarization('horizontal') + self.check_topology(0, 0, 0, 0, 'medium', False) + + self.guest_set_dispatching('1') + self.check_polarization('vertical:medium') + self.check_topology(0, 0, 0, 0, 'medium', False) + + res = self.vm.qmp('set-cpu-topology', + {'core-id': 0, 'entitlement': 'low'}) + self.assertEqual(res['return'], {}) + self.check_polarization('vertical:low') + self.check_topology(0, 0, 0, 0, 'low', False) + + res = self.vm.qmp('set-cpu-topology', + {'core-id': 0, 'entitlement': 'medium'}) + self.assertEqual(res['return'], {}) + self.check_polarization('vertical:medium') + self.check_topology(0, 0, 0, 0, 'medium', False) + + res = self.vm.qmp('set-cpu-topology', + {'core-id': 0, 'entitlement': 'high'}) + self.assertEqual(res['return'], {}) + self.check_polarization('vertical:high') + self.check_topology(0, 0, 0, 0, 'high', False) + + self.guest_set_dispatching('0'); + self.check_polarization("horizontal") + self.check_topology(0, 0, 0, 0, 'high', False) From 471676bfd2e182746b9bb0ff4e613908dc4c8842 Mon Sep 17 00:00:00 2001 From: Pierre Morel Date: Mon, 16 Oct 2023 20:39:22 +0200 Subject: [PATCH 0903/1077] tests/avocado: s390x cpu topology test dedicated CPU A dedicated CPU in vertical polarization can only have a high entitlement. Let's check this from both host and guest point of view. Signed-off-by: Pierre Morel Co-developed-by: Nina Schoetterl-Glausch Reviewed-by: Thomas Huth Reviewed-by: Nina Schoetterl-Glausch Signed-off-by: Nina Schoetterl-Glausch Message-ID: <20231016183925.2384704-19-nsg@linux.ibm.com> Signed-off-by: Thomas Huth --- tests/avocado/s390_topology.py | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/tests/avocado/s390_topology.py b/tests/avocado/s390_topology.py index 24fac9a54d..3661048f4c 100644 --- a/tests/avocado/s390_topology.py +++ b/tests/avocado/s390_topology.py @@ -305,3 +305,36 @@ class S390CPUTopology(QemuSystemTest): self.guest_set_dispatching('0'); self.check_polarization("horizontal") self.check_topology(0, 0, 0, 0, 'high', False) + + + def test_dedicated(self): + """ + This test verifies that QEMU adjusts the entitlement correctly when a + CPU is made dedicated. + QEMU retains the entitlement value when horizontal polarization is in effect. + For the guest, the field shows the effective value of the entitlement. + + :avocado: tags=arch:s390x + :avocado: tags=machine:s390-ccw-virtio + """ + self.kernel_init() + self.vm.launch() + self.wait_until_booted() + + self.system_init() + + self.check_polarization("horizontal") + + res = self.vm.qmp('set-cpu-topology', + {'core-id': 0, 'dedicated': True}) + self.assertEqual(res['return'], {}) + self.check_topology(0, 0, 0, 0, 'high', True) + self.check_polarization("horizontal") + + self.guest_set_dispatching('1'); + self.check_topology(0, 0, 0, 0, 'high', True) + self.check_polarization("vertical:high") + + self.guest_set_dispatching('0'); + self.check_topology(0, 0, 0, 0, 'high', True) + self.check_polarization("horizontal") From 944e03006d0fa17332d4cbf82e26d63c10d320d2 Mon Sep 17 00:00:00 2001 From: Pierre Morel Date: Mon, 16 Oct 2023 20:39:23 +0200 Subject: [PATCH 0904/1077] tests/avocado: s390x cpu topology test socket full This test verifies that QMP set-cpu-topology does not accept to overload a socket. Signed-off-by: Pierre Morel Reviewed-by: Thomas Huth Message-ID: <20231016183925.2384704-20-nsg@linux.ibm.com> Signed-off-by: Thomas Huth --- tests/avocado/s390_topology.py | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/tests/avocado/s390_topology.py b/tests/avocado/s390_topology.py index 3661048f4c..a63c2b2923 100644 --- a/tests/avocado/s390_topology.py +++ b/tests/avocado/s390_topology.py @@ -338,3 +338,29 @@ class S390CPUTopology(QemuSystemTest): self.guest_set_dispatching('0'); self.check_topology(0, 0, 0, 0, 'high', True) self.check_polarization("horizontal") + + + def test_socket_full(self): + """ + This test verifies that QEMU does not accept to overload a socket. + The socket-id 0 on book-id 0 already contains CPUs 0 and 1 and can + not accept any new CPU while socket-id 0 on book-id 1 is free. + + :avocado: tags=arch:s390x + :avocado: tags=machine:s390-ccw-virtio + """ + self.kernel_init() + self.vm.add_args('-smp', + '3,drawers=2,books=2,sockets=3,cores=2,maxcpus=24') + self.vm.launch() + self.wait_until_booted() + + self.system_init() + + res = self.vm.qmp('set-cpu-topology', + {'core-id': 2, 'socket-id': 0, 'book-id': 0}) + self.assertEqual(res['error']['class'], 'GenericError') + + res = self.vm.qmp('set-cpu-topology', + {'core-id': 2, 'socket-id': 0, 'book-id': 1}) + self.assertEqual(res['return'], {}) From 22ac7809bbd0dc338836ac9f0e5330c18e13e08c Mon Sep 17 00:00:00 2001 From: Pierre Morel Date: Mon, 16 Oct 2023 20:39:24 +0200 Subject: [PATCH 0905/1077] tests/avocado: s390x cpu topology dedicated errors Let's test that QEMU refuses to setup a dedicated CPU with low or medium entitlement. Signed-off-by: Pierre Morel Reviewed-by: Thomas Huth Message-ID: <20231016183925.2384704-21-nsg@linux.ibm.com> Signed-off-by: Thomas Huth --- tests/avocado/s390_topology.py | 48 ++++++++++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) diff --git a/tests/avocado/s390_topology.py b/tests/avocado/s390_topology.py index a63c2b2923..d3e6556c0f 100644 --- a/tests/avocado/s390_topology.py +++ b/tests/avocado/s390_topology.py @@ -364,3 +364,51 @@ class S390CPUTopology(QemuSystemTest): res = self.vm.qmp('set-cpu-topology', {'core-id': 2, 'socket-id': 0, 'book-id': 1}) self.assertEqual(res['return'], {}) + + def test_dedicated_error(self): + """ + This test verifies that QEMU refuses to lower the entitlement + of a dedicated CPU + + :avocado: tags=arch:s390x + :avocado: tags=machine:s390-ccw-virtio + """ + self.kernel_init() + self.vm.launch() + self.wait_until_booted() + + self.system_init() + + res = self.vm.qmp('set-cpu-topology', + {'core-id': 0, 'dedicated': True}) + self.assertEqual(res['return'], {}) + + self.check_topology(0, 0, 0, 0, 'high', True) + + self.guest_set_dispatching('1'); + + self.check_topology(0, 0, 0, 0, 'high', True) + + res = self.vm.qmp('set-cpu-topology', + {'core-id': 0, 'entitlement': 'low', 'dedicated': True}) + self.assertEqual(res['error']['class'], 'GenericError') + + res = self.vm.qmp('set-cpu-topology', + {'core-id': 0, 'entitlement': 'low'}) + self.assertEqual(res['error']['class'], 'GenericError') + + res = self.vm.qmp('set-cpu-topology', + {'core-id': 0, 'entitlement': 'medium', 'dedicated': True}) + self.assertEqual(res['error']['class'], 'GenericError') + + res = self.vm.qmp('set-cpu-topology', + {'core-id': 0, 'entitlement': 'medium'}) + self.assertEqual(res['error']['class'], 'GenericError') + + res = self.vm.qmp('set-cpu-topology', + {'core-id': 0, 'entitlement': 'low', 'dedicated': False}) + self.assertEqual(res['return'], {}) + + res = self.vm.qmp('set-cpu-topology', + {'core-id': 0, 'entitlement': 'medium', 'dedicated': False}) + self.assertEqual(res['return'], {}) From 219922ef9b7af4b425c85a7c14c79c2f68f1a19b Mon Sep 17 00:00:00 2001 From: Pierre Morel Date: Mon, 16 Oct 2023 20:39:25 +0200 Subject: [PATCH 0906/1077] tests/avocado: s390x cpu topology bad move This test verifies that QEMU refuses to move a CPU to an nonexistent location. Signed-off-by: Pierre Morel Reviewed-by: Thomas Huth Message-ID: <20231016183925.2384704-22-nsg@linux.ibm.com> Signed-off-by: Thomas Huth --- tests/avocado/s390_topology.py | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/tests/avocado/s390_topology.py b/tests/avocado/s390_topology.py index d3e6556c0f..9154ac8776 100644 --- a/tests/avocado/s390_topology.py +++ b/tests/avocado/s390_topology.py @@ -412,3 +412,28 @@ class S390CPUTopology(QemuSystemTest): res = self.vm.qmp('set-cpu-topology', {'core-id': 0, 'entitlement': 'medium', 'dedicated': False}) self.assertEqual(res['return'], {}) + + def test_move_error(self): + """ + This test verifies that QEMU refuses to move a CPU to an + nonexistent location + + :avocado: tags=arch:s390x + :avocado: tags=machine:s390-ccw-virtio + """ + self.kernel_init() + self.vm.launch() + self.wait_until_booted() + + self.system_init() + + res = self.vm.qmp('set-cpu-topology', {'core-id': 0, 'drawer-id': 1}) + self.assertEqual(res['error']['class'], 'GenericError') + + res = self.vm.qmp('set-cpu-topology', {'core-id': 0, 'book-id': 1}) + self.assertEqual(res['error']['class'], 'GenericError') + + res = self.vm.qmp('set-cpu-topology', {'core-id': 0, 'socket-id': 1}) + self.assertEqual(res['error']['class'], 'GenericError') + + self.check_topology(0, 0, 0, 0, 'medium', False) From c35a79cbd7dc2ff3435355177290b7b31b589993 Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Wed, 11 Oct 2023 10:05:37 +0200 Subject: [PATCH 0907/1077] target/s390x/kvm: Turn KVM_CAP_SYNC_REGS into a hard requirement Since we already require at least kernel 3.15 in the s390x KVM code, we can assume that the KVM_CAP_SYNC_REGS capability is always there. Thus turn this into a hard requirement now. Reviewed-by: Christian Borntraeger Message-ID: <20231011080538.796999-2-thuth@redhat.com> Signed-off-by: Thomas Huth --- target/s390x/kvm/kvm.c | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/target/s390x/kvm/kvm.c b/target/s390x/kvm/kvm.c index 2e43dc746f..068e9826e1 100644 --- a/target/s390x/kvm/kvm.c +++ b/target/s390x/kvm/kvm.c @@ -338,21 +338,29 @@ int kvm_arch_get_default_type(MachineState *ms) int kvm_arch_init(MachineState *ms, KVMState *s) { + int required_caps[] = { + KVM_CAP_DEVICE_CTRL, + KVM_CAP_SYNC_REGS, + }; + + for (int i = 0; i < ARRAY_SIZE(required_caps); i++) { + if (!kvm_check_extension(s, required_caps[i])) { + error_report("KVM is missing capability #%d - " + "please use kernel 3.15 or newer", required_caps[i]); + return -1; + } + } + object_class_foreach(ccw_machine_class_foreach, TYPE_S390_CCW_MACHINE, false, NULL); - if (!kvm_check_extension(kvm_state, KVM_CAP_DEVICE_CTRL)) { - error_report("KVM is missing capability KVM_CAP_DEVICE_CTRL - " - "please use kernel 3.15 or newer"); - return -1; - } if (!kvm_check_extension(s, KVM_CAP_S390_COW)) { error_report("KVM is missing capability KVM_CAP_S390_COW - " "unsupported environment"); return -1; } - cap_sync_regs = kvm_check_extension(s, KVM_CAP_SYNC_REGS); + cap_sync_regs = true; cap_async_pf = kvm_check_extension(s, KVM_CAP_ASYNC_PF); cap_mem_op = kvm_check_extension(s, KVM_CAP_S390_MEM_OP); cap_mem_op_extension = kvm_check_extension(s, KVM_CAP_S390_MEM_OP_EXTENSION); From 1d1071665012e378510494e99466c042b3ac1be0 Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Wed, 11 Oct 2023 10:05:38 +0200 Subject: [PATCH 0908/1077] target/s390x/kvm: Simplify the GPRs, ACRs, CRs and prefix synchronization code KVM_SYNC_GPRS, KVM_SYNC_ACRS, KVM_SYNC_CRS and KVM_SYNC_PREFIX are available since kernel 3.10. Since we already require at least kernel 3.15 in the s390x KVM code, we can also assume that the KVM_CAP_SYNC_REGS sync code is always possible for these registers, and remove the related checks and fallbacks via KVM_SET_REGS and KVM_GET_REGS. Message-ID: <20231011080538.796999-3-thuth@redhat.com> Signed-off-by: Thomas Huth --- target/s390x/kvm/kvm.c | 106 ++++++++++------------------------------- 1 file changed, 24 insertions(+), 82 deletions(-) diff --git a/target/s390x/kvm/kvm.c b/target/s390x/kvm/kvm.c index 068e9826e1..0f0e784b2a 100644 --- a/target/s390x/kvm/kvm.c +++ b/target/s390x/kvm/kvm.c @@ -139,7 +139,6 @@ const KVMCapabilityInfo kvm_arch_required_capabilities[] = { KVM_CAP_LAST_INFO }; -static int cap_sync_regs; static int cap_async_pf; static int cap_mem_op; static int cap_mem_op_extension; @@ -360,7 +359,6 @@ int kvm_arch_init(MachineState *ms, KVMState *s) return -1; } - cap_sync_regs = true; cap_async_pf = kvm_check_extension(s, KVM_CAP_ASYNC_PF); cap_mem_op = kvm_check_extension(s, KVM_CAP_S390_MEM_OP); cap_mem_op_extension = kvm_check_extension(s, KVM_CAP_S390_MEM_OP_EXTENSION); @@ -468,37 +466,28 @@ void kvm_s390_reset_vcpu_normal(S390CPU *cpu) static int can_sync_regs(CPUState *cs, int regs) { - return cap_sync_regs && (cs->kvm_run->kvm_valid_regs & regs) == regs; + return (cs->kvm_run->kvm_valid_regs & regs) == regs; } +#define KVM_SYNC_REQUIRED_REGS (KVM_SYNC_GPRS | KVM_SYNC_ACRS | \ + KVM_SYNC_CRS | KVM_SYNC_PREFIX) + int kvm_arch_put_registers(CPUState *cs, int level) { S390CPU *cpu = S390_CPU(cs); CPUS390XState *env = &cpu->env; - struct kvm_sregs sregs; - struct kvm_regs regs; struct kvm_fpu fpu = {}; int r; int i; + g_assert(can_sync_regs(cs, KVM_SYNC_REQUIRED_REGS)); + /* always save the PSW and the GPRS*/ cs->kvm_run->psw_addr = env->psw.addr; cs->kvm_run->psw_mask = env->psw.mask; - if (can_sync_regs(cs, KVM_SYNC_GPRS)) { - for (i = 0; i < 16; i++) { - cs->kvm_run->s.regs.gprs[i] = env->regs[i]; - cs->kvm_run->kvm_dirty_regs |= KVM_SYNC_GPRS; - } - } else { - for (i = 0; i < 16; i++) { - regs.gprs[i] = env->regs[i]; - } - r = kvm_vcpu_ioctl(cs, KVM_SET_REGS, ®s); - if (r < 0) { - return r; - } - } + memcpy(cs->kvm_run->s.regs.gprs, env->regs, sizeof(cs->kvm_run->s.regs.gprs)); + cs->kvm_run->kvm_dirty_regs |= KVM_SYNC_GPRS; if (can_sync_regs(cs, KVM_SYNC_VRS)) { for (i = 0; i < 32; i++) { @@ -531,6 +520,15 @@ int kvm_arch_put_registers(CPUState *cs, int level) return 0; } + /* + * Access registers, control registers and the prefix - these are + * always available via kvm_sync_regs in the kernels that we support + */ + memcpy(cs->kvm_run->s.regs.acrs, env->aregs, sizeof(cs->kvm_run->s.regs.acrs)); + memcpy(cs->kvm_run->s.regs.crs, env->cregs, sizeof(cs->kvm_run->s.regs.crs)); + cs->kvm_run->s.regs.prefix = env->psa; + cs->kvm_run->kvm_dirty_regs |= KVM_SYNC_ACRS | KVM_SYNC_CRS | KVM_SYNC_PREFIX; + if (can_sync_regs(cs, KVM_SYNC_ARCH0)) { cs->kvm_run->s.regs.cputm = env->cputm; cs->kvm_run->s.regs.ckc = env->ckc; @@ -577,25 +575,6 @@ int kvm_arch_put_registers(CPUState *cs, int level) } } - /* access registers and control registers*/ - if (can_sync_regs(cs, KVM_SYNC_ACRS | KVM_SYNC_CRS)) { - for (i = 0; i < 16; i++) { - cs->kvm_run->s.regs.acrs[i] = env->aregs[i]; - cs->kvm_run->s.regs.crs[i] = env->cregs[i]; - } - cs->kvm_run->kvm_dirty_regs |= KVM_SYNC_ACRS; - cs->kvm_run->kvm_dirty_regs |= KVM_SYNC_CRS; - } else { - for (i = 0; i < 16; i++) { - sregs.acrs[i] = env->aregs[i]; - sregs.crs[i] = env->cregs[i]; - } - r = kvm_vcpu_ioctl(cs, KVM_SET_SREGS, &sregs); - if (r < 0) { - return r; - } - } - if (can_sync_regs(cs, KVM_SYNC_GSCB)) { memcpy(cs->kvm_run->s.regs.gscb, env->gscb, 32); cs->kvm_run->kvm_dirty_regs |= KVM_SYNC_GSCB; @@ -617,13 +596,6 @@ int kvm_arch_put_registers(CPUState *cs, int level) cs->kvm_run->kvm_dirty_regs |= KVM_SYNC_DIAG318; } - /* Finally the prefix */ - if (can_sync_regs(cs, KVM_SYNC_PREFIX)) { - cs->kvm_run->s.regs.prefix = env->psa; - cs->kvm_run->kvm_dirty_regs |= KVM_SYNC_PREFIX; - } else { - /* prefix is only supported via sync regs */ - } return 0; } @@ -631,8 +603,6 @@ int kvm_arch_get_registers(CPUState *cs) { S390CPU *cpu = S390_CPU(cs); CPUS390XState *env = &cpu->env; - struct kvm_sregs sregs; - struct kvm_regs regs; struct kvm_fpu fpu; int i, r; @@ -640,37 +610,14 @@ int kvm_arch_get_registers(CPUState *cs) env->psw.addr = cs->kvm_run->psw_addr; env->psw.mask = cs->kvm_run->psw_mask; - /* the GPRS */ - if (can_sync_regs(cs, KVM_SYNC_GPRS)) { - for (i = 0; i < 16; i++) { - env->regs[i] = cs->kvm_run->s.regs.gprs[i]; - } - } else { - r = kvm_vcpu_ioctl(cs, KVM_GET_REGS, ®s); - if (r < 0) { - return r; - } - for (i = 0; i < 16; i++) { - env->regs[i] = regs.gprs[i]; - } - } + /* the GPRS, ACRS and CRS */ + g_assert(can_sync_regs(cs, KVM_SYNC_REQUIRED_REGS)); + memcpy(env->regs, cs->kvm_run->s.regs.gprs, sizeof(env->regs)); + memcpy(env->aregs, cs->kvm_run->s.regs.acrs, sizeof(env->aregs)); + memcpy(env->cregs, cs->kvm_run->s.regs.crs, sizeof(env->cregs)); - /* The ACRS and CRS */ - if (can_sync_regs(cs, KVM_SYNC_ACRS | KVM_SYNC_CRS)) { - for (i = 0; i < 16; i++) { - env->aregs[i] = cs->kvm_run->s.regs.acrs[i]; - env->cregs[i] = cs->kvm_run->s.regs.crs[i]; - } - } else { - r = kvm_vcpu_ioctl(cs, KVM_GET_SREGS, &sregs); - if (r < 0) { - return r; - } - for (i = 0; i < 16; i++) { - env->aregs[i] = sregs.acrs[i]; - env->cregs[i] = sregs.crs[i]; - } - } + /* The prefix */ + env->psa = cs->kvm_run->s.regs.prefix; /* Floating point and vector registers */ if (can_sync_regs(cs, KVM_SYNC_VRS)) { @@ -695,11 +642,6 @@ int kvm_arch_get_registers(CPUState *cs) env->fpc = fpu.fpc; } - /* The prefix */ - if (can_sync_regs(cs, KVM_SYNC_PREFIX)) { - env->psa = cs->kvm_run->s.regs.prefix; - } - if (can_sync_regs(cs, KVM_SYNC_ARCH0)) { env->cputm = cs->kvm_run->s.regs.cputm; env->ckc = cs->kvm_run->s.regs.ckc; From 18424d9591c73178bdfd6a4518091064db22e1d9 Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Wed, 18 Oct 2023 11:08:46 +0200 Subject: [PATCH 0909/1077] tests/qtest/migration-test: Disable the analyze-migration.py test on s390x The analyze-migration.py script fails on s390x hosts: Traceback (most recent call last): File "scripts/analyze-migration.py", line 662, in dump.read(dump_memory = args.memory) File "scripts/analyze-migration.py", line 596, in read classdesc = self.section_classes[section_key] KeyError: ('s390-storage_attributes', 0) It obviously never has been adapted to s390x yet, so until this has been done, disable this test on s390x. Message-ID: <20231018091239.164452-1-thuth@redhat.com> Reviewed-by: Juan Quintela Signed-off-by: Thomas Huth --- tests/qtest/migration-test.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tests/qtest/migration-test.c b/tests/qtest/migration-test.c index e1c110537b..241b409857 100644 --- a/tests/qtest/migration-test.c +++ b/tests/qtest/migration-test.c @@ -3034,7 +3034,9 @@ int main(int argc, char **argv) qtest_add_func("/migration/bad_dest", test_baddest); #ifndef _WIN32 - qtest_add_func("/migration/analyze-script", test_analyze_script); + if (!g_str_equal(arch, "s390x")) { + qtest_add_func("/migration/analyze-script", test_analyze_script); + } #endif qtest_add_func("/migration/precopy/unix/plain", test_precopy_unix_plain); qtest_add_func("/migration/precopy/unix/xbzrle", test_precopy_unix_xbzrle); From 04131e00097c5b85f96af6a66b1c009446c90ec1 Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Wed, 18 Oct 2023 11:12:39 +0200 Subject: [PATCH 0910/1077] tests/qtest/migration-test: Disable the analyze-migration.py test on s390x The analyze-migration.py script fails on s390x hosts: Traceback (most recent call last): File "scripts/analyze-migration.py", line 662, in dump.read(dump_memory = args.memory) File "scripts/analyze-migration.py", line 596, in read classdesc = self.section_classes[section_key] KeyError: ('s390-storage_attributes', 0) It obviously never has been adapted to s390x yet, so until this has been done, disable this test on s390x. Signed-off-by: Thomas Huth Reviewed-by: Juan Quintela Signed-off-by: Juan Quintela Message-ID: <20231018091239.164452-1-thuth@redhat.com> --- tests/qtest/migration-test.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tests/qtest/migration-test.c b/tests/qtest/migration-test.c index e1c110537b..241b409857 100644 --- a/tests/qtest/migration-test.c +++ b/tests/qtest/migration-test.c @@ -3034,7 +3034,9 @@ int main(int argc, char **argv) qtest_add_func("/migration/bad_dest", test_baddest); #ifndef _WIN32 - qtest_add_func("/migration/analyze-script", test_analyze_script); + if (!g_str_equal(arch, "s390x")) { + qtest_add_func("/migration/analyze-script", test_analyze_script); + } #endif qtest_add_func("/migration/precopy/unix/plain", test_precopy_unix_plain); qtest_add_func("/migration/precopy/unix/xbzrle", test_precopy_unix_xbzrle); From c8a7fc5179c649eed1d4286776a23e8a1a183cdc Mon Sep 17 00:00:00 2001 From: Steve Sistare Date: Wed, 18 Oct 2023 06:03:36 -0700 Subject: [PATCH 0911/1077] migration: simplify blockers Modify migrate_add_blocker and migrate_del_blocker to take an Error ** reason. This allows migration to own the Error object, so that if an error occurs in migrate_add_blocker, migration code can free the Error and clear the client handle, simplifying client code. It also simplifies the migrate_del_blocker call site. In addition, this is a pre-requisite for a proposed future patch that would add a mode argument to migration requests to support live update, and maintain a list of blockers for each mode. A blocker may apply to a single mode or to multiple modes, and passing Error** will allow one Error object to be registered for multiple modes. No functional change. Signed-off-by: Steve Sistare Tested-by: Michael Galaxy Reviewed-by: Michael Galaxy Reviewed-by: Peter Xu Reviewed-by: Juan Quintela Signed-off-by: Juan Quintela Message-ID: <1697634216-84215-1-git-send-email-steven.sistare@oracle.com> --- backends/tpm/tpm_emulator.c | 10 ++-------- block/parallels.c | 9 +++------ block/qcow.c | 6 ++---- block/vdi.c | 6 ++---- block/vhdx.c | 6 ++---- block/vmdk.c | 6 ++---- block/vpc.c | 6 ++---- block/vvfat.c | 6 ++---- dump/dump.c | 4 ++-- hw/9pfs/9p.c | 10 ++-------- hw/display/virtio-gpu-base.c | 8 ++------ hw/intc/arm_gic_kvm.c | 3 +-- hw/intc/arm_gicv3_its_kvm.c | 3 +-- hw/intc/arm_gicv3_kvm.c | 3 +-- hw/misc/ivshmem.c | 8 ++------ hw/ppc/pef.c | 2 +- hw/ppc/spapr.c | 9 +-------- hw/ppc/spapr_events.c | 6 +++++- hw/ppc/spapr_rtas.c | 2 +- hw/remote/proxy.c | 7 ++----- hw/s390x/s390-virtio-ccw.c | 9 +++------ hw/scsi/vhost-scsi.c | 8 +++----- hw/vfio/common.c | 10 ++-------- hw/vfio/migration.c | 16 ++-------------- hw/virtio/vhost.c | 8 ++------ include/migration/blocker.h | 24 +++++++++++++++++------- migration/migration.c | 22 ++++++++++++++-------- stubs/migr-blocker.c | 4 ++-- target/i386/kvm/kvm.c | 8 ++++---- target/i386/nvmm/nvmm-all.c | 3 +-- target/i386/sev.c | 2 +- target/i386/whpx/whpx-all.c | 3 +-- ui/vdagent.c | 5 ++--- 33 files changed, 92 insertions(+), 150 deletions(-) diff --git a/backends/tpm/tpm_emulator.c b/backends/tpm/tpm_emulator.c index 402a2d6312..bf1a90f5d7 100644 --- a/backends/tpm/tpm_emulator.c +++ b/backends/tpm/tpm_emulator.c @@ -534,11 +534,8 @@ static int tpm_emulator_block_migration(TPMEmulator *tpm_emu) error_setg(&tpm_emu->migration_blocker, "Migration disabled: TPM emulator does not support " "migration"); - if (migrate_add_blocker(tpm_emu->migration_blocker, &err) < 0) { + if (migrate_add_blocker(&tpm_emu->migration_blocker, &err) < 0) { error_report_err(err); - error_free(tpm_emu->migration_blocker); - tpm_emu->migration_blocker = NULL; - return -1; } } @@ -1016,10 +1013,7 @@ static void tpm_emulator_inst_finalize(Object *obj) qapi_free_TPMEmulatorOptions(tpm_emu->options); - if (tpm_emu->migration_blocker) { - migrate_del_blocker(tpm_emu->migration_blocker); - error_free(tpm_emu->migration_blocker); - } + migrate_del_blocker(&tpm_emu->migration_blocker); tpm_sized_buffer_reset(&state_blobs->volatil); tpm_sized_buffer_reset(&state_blobs->permanent); diff --git a/block/parallels.c b/block/parallels.c index 6b46623241..1d695ce7fb 100644 --- a/block/parallels.c +++ b/block/parallels.c @@ -1369,9 +1369,8 @@ static int parallels_open(BlockDriverState *bs, QDict *options, int flags, bdrv_get_device_or_node_name(bs)); bdrv_graph_rdunlock_main_loop(); - ret = migrate_add_blocker(s->migration_blocker, errp); + ret = migrate_add_blocker(&s->migration_blocker, errp); if (ret < 0) { - error_setg(errp, "Migration blocker error"); goto fail; } qemu_co_mutex_init(&s->lock); @@ -1406,7 +1405,7 @@ static int parallels_open(BlockDriverState *bs, QDict *options, int flags, ret = bdrv_check(bs, &res, BDRV_FIX_ERRORS | BDRV_FIX_LEAKS); if (ret < 0) { error_setg_errno(errp, -ret, "Could not repair corrupted image"); - migrate_del_blocker(s->migration_blocker); + migrate_del_blocker(&s->migration_blocker); goto fail; } } @@ -1423,7 +1422,6 @@ fail: */ parallels_free_used_bitmap(bs); - error_free(s->migration_blocker); g_free(s->bat_dirty_bmap); qemu_vfree(s->header); return ret; @@ -1448,8 +1446,7 @@ static void parallels_close(BlockDriverState *bs) g_free(s->bat_dirty_bmap); qemu_vfree(s->header); - migrate_del_blocker(s->migration_blocker); - error_free(s->migration_blocker); + migrate_del_blocker(&s->migration_blocker); } static bool parallels_is_support_dirty_bitmaps(BlockDriverState *bs) diff --git a/block/qcow.c b/block/qcow.c index 38a16253b8..fdd4c83948 100644 --- a/block/qcow.c +++ b/block/qcow.c @@ -307,9 +307,8 @@ static int qcow_open(BlockDriverState *bs, QDict *options, int flags, bdrv_get_device_or_node_name(bs)); bdrv_graph_rdunlock_main_loop(); - ret = migrate_add_blocker(s->migration_blocker, errp); + ret = migrate_add_blocker(&s->migration_blocker, errp); if (ret < 0) { - error_free(s->migration_blocker); goto fail; } @@ -802,8 +801,7 @@ static void qcow_close(BlockDriverState *bs) g_free(s->cluster_cache); g_free(s->cluster_data); - migrate_del_blocker(s->migration_blocker); - error_free(s->migration_blocker); + migrate_del_blocker(&s->migration_blocker); } static int coroutine_fn GRAPH_UNLOCKED diff --git a/block/vdi.c b/block/vdi.c index 3ed43b6f35..fd7e365383 100644 --- a/block/vdi.c +++ b/block/vdi.c @@ -498,9 +498,8 @@ static int vdi_open(BlockDriverState *bs, QDict *options, int flags, bdrv_get_device_or_node_name(bs)); bdrv_graph_rdunlock_main_loop(); - ret = migrate_add_blocker(s->migration_blocker, errp); + ret = migrate_add_blocker(&s->migration_blocker, errp); if (ret < 0) { - error_free(s->migration_blocker); goto fail_free_bmap; } @@ -988,8 +987,7 @@ static void vdi_close(BlockDriverState *bs) qemu_vfree(s->bmap); - migrate_del_blocker(s->migration_blocker); - error_free(s->migration_blocker); + migrate_del_blocker(&s->migration_blocker); } static int vdi_has_zero_init(BlockDriverState *bs) diff --git a/block/vhdx.c b/block/vhdx.c index 73cb214fb4..e37f8c0926 100644 --- a/block/vhdx.c +++ b/block/vhdx.c @@ -985,8 +985,7 @@ static void vhdx_close(BlockDriverState *bs) s->bat = NULL; qemu_vfree(s->parent_entries); s->parent_entries = NULL; - migrate_del_blocker(s->migration_blocker); - error_free(s->migration_blocker); + migrate_del_blocker(&s->migration_blocker); qemu_vfree(s->log.hdr); s->log.hdr = NULL; vhdx_region_unregister_all(s); @@ -1097,9 +1096,8 @@ static int vhdx_open(BlockDriverState *bs, QDict *options, int flags, error_setg(&s->migration_blocker, "The vhdx format used by node '%s' " "does not support live migration", bdrv_get_device_or_node_name(bs)); - ret = migrate_add_blocker(s->migration_blocker, errp); + ret = migrate_add_blocker(&s->migration_blocker, errp); if (ret < 0) { - error_free(s->migration_blocker); goto fail; } diff --git a/block/vmdk.c b/block/vmdk.c index 8a3b152798..1335d39e16 100644 --- a/block/vmdk.c +++ b/block/vmdk.c @@ -1386,9 +1386,8 @@ static int vmdk_open(BlockDriverState *bs, QDict *options, int flags, error_setg(&s->migration_blocker, "The vmdk format used by node '%s' " "does not support live migration", bdrv_get_device_or_node_name(bs)); - ret = migrate_add_blocker(s->migration_blocker, errp); + ret = migrate_add_blocker(&s->migration_blocker, errp); if (ret < 0) { - error_free(s->migration_blocker); goto fail; } @@ -2867,8 +2866,7 @@ static void vmdk_close(BlockDriverState *bs) vmdk_free_extents(bs); g_free(s->create_type); - migrate_del_blocker(s->migration_blocker); - error_free(s->migration_blocker); + migrate_del_blocker(&s->migration_blocker); } static int64_t coroutine_fn GRAPH_RDLOCK diff --git a/block/vpc.c b/block/vpc.c index 945847fe4a..c30cf8689a 100644 --- a/block/vpc.c +++ b/block/vpc.c @@ -452,9 +452,8 @@ static int vpc_open(BlockDriverState *bs, QDict *options, int flags, bdrv_get_device_or_node_name(bs)); bdrv_graph_rdunlock_main_loop(); - ret = migrate_add_blocker(s->migration_blocker, errp); + ret = migrate_add_blocker(&s->migration_blocker, errp); if (ret < 0) { - error_free(s->migration_blocker); goto fail; } @@ -1190,8 +1189,7 @@ static void vpc_close(BlockDriverState *bs) g_free(s->pageentry_u8); #endif - migrate_del_blocker(s->migration_blocker); - error_free(s->migration_blocker); + migrate_del_blocker(&s->migration_blocker); } static QemuOptsList vpc_create_opts = { diff --git a/block/vvfat.c b/block/vvfat.c index b0415798c0..266e036dcd 100644 --- a/block/vvfat.c +++ b/block/vvfat.c @@ -1268,9 +1268,8 @@ static int vvfat_open(BlockDriverState *bs, QDict *options, int flags, "The vvfat (rw) format used by node '%s' " "does not support live migration", bdrv_get_device_or_node_name(bs)); - ret = migrate_add_blocker(s->migration_blocker, errp); + ret = migrate_add_blocker(&s->migration_blocker, errp); if (ret < 0) { - error_free(s->migration_blocker); goto fail; } } @@ -3239,8 +3238,7 @@ static void vvfat_close(BlockDriverState *bs) g_free(s->cluster_buffer); if (s->qcow) { - migrate_del_blocker(s->migration_blocker); - error_free(s->migration_blocker); + migrate_del_blocker(&s->migration_blocker); } } diff --git a/dump/dump.c b/dump/dump.c index d3578ddc62..d355ada62e 100644 --- a/dump/dump.c +++ b/dump/dump.c @@ -111,7 +111,7 @@ static int dump_cleanup(DumpState *s) qemu_mutex_unlock_iothread(); } } - migrate_del_blocker(dump_migration_blocker); + migrate_del_blocker(&dump_migration_blocker); return 0; } @@ -2158,7 +2158,7 @@ void qmp_dump_guest_memory(bool paging, const char *file, * Allows even for -only-migratable, but forbid migration during the * process of dump guest memory. */ - if (migrate_add_blocker_internal(dump_migration_blocker, errp)) { + if (migrate_add_blocker_internal(&dump_migration_blocker, errp)) { /* Remember to release the fd before passing it over to dump state */ close(fd); return; diff --git a/hw/9pfs/9p.c b/hw/9pfs/9p.c index 323f042e65..af636cfb2d 100644 --- a/hw/9pfs/9p.c +++ b/hw/9pfs/9p.c @@ -406,11 +406,7 @@ static int coroutine_fn put_fid(V9fsPDU *pdu, V9fsFidState *fidp) * delete the migration blocker. Ideally, this * should be hooked to transport close notification */ - if (pdu->s->migration_blocker) { - migrate_del_blocker(pdu->s->migration_blocker); - error_free(pdu->s->migration_blocker); - pdu->s->migration_blocker = NULL; - } + migrate_del_blocker(&pdu->s->migration_blocker); } return free_fid(pdu, fidp); } @@ -1505,10 +1501,8 @@ static void coroutine_fn v9fs_attach(void *opaque) error_setg(&s->migration_blocker, "Migration is disabled when VirtFS export path '%s' is mounted in the guest using mount_tag '%s'", s->ctx.fs_root ? s->ctx.fs_root : "NULL", s->tag); - err = migrate_add_blocker(s->migration_blocker, NULL); + err = migrate_add_blocker(&s->migration_blocker, NULL); if (err < 0) { - error_free(s->migration_blocker); - s->migration_blocker = NULL; clunk_fid(s, fid); goto out; } diff --git a/hw/display/virtio-gpu-base.c b/hw/display/virtio-gpu-base.c index 50c5373b65..37af256219 100644 --- a/hw/display/virtio-gpu-base.c +++ b/hw/display/virtio-gpu-base.c @@ -184,8 +184,7 @@ virtio_gpu_base_device_realize(DeviceState *qdev, if (virtio_gpu_virgl_enabled(g->conf)) { error_setg(&g->migration_blocker, "virgl is not yet migratable"); - if (migrate_add_blocker(g->migration_blocker, errp) < 0) { - error_free(g->migration_blocker); + if (migrate_add_blocker(&g->migration_blocker, errp) < 0) { return false; } } @@ -253,10 +252,7 @@ virtio_gpu_base_device_unrealize(DeviceState *qdev) { VirtIOGPUBase *g = VIRTIO_GPU_BASE(qdev); - if (g->migration_blocker) { - migrate_del_blocker(g->migration_blocker); - error_free(g->migration_blocker); - } + migrate_del_blocker(&g->migration_blocker); } static void diff --git a/hw/intc/arm_gic_kvm.c b/hw/intc/arm_gic_kvm.c index 1d588946bc..e0d9e512a3 100644 --- a/hw/intc/arm_gic_kvm.c +++ b/hw/intc/arm_gic_kvm.c @@ -516,8 +516,7 @@ static void kvm_arm_gic_realize(DeviceState *dev, Error **errp) if (!kvm_arm_gic_can_save_restore(s)) { error_setg(&s->migration_blocker, "This operating system kernel does " "not support vGICv2 migration"); - if (migrate_add_blocker(s->migration_blocker, errp) < 0) { - error_free(s->migration_blocker); + if (migrate_add_blocker(&s->migration_blocker, errp) < 0) { return; } } diff --git a/hw/intc/arm_gicv3_its_kvm.c b/hw/intc/arm_gicv3_its_kvm.c index 7eda9fb86e..61c1cc7bdb 100644 --- a/hw/intc/arm_gicv3_its_kvm.c +++ b/hw/intc/arm_gicv3_its_kvm.c @@ -114,8 +114,7 @@ static void kvm_arm_its_realize(DeviceState *dev, Error **errp) GITS_CTLR)) { error_setg(&s->migration_blocker, "This operating system kernel " "does not support vITS migration"); - if (migrate_add_blocker(s->migration_blocker, errp) < 0) { - error_free(s->migration_blocker); + if (migrate_add_blocker(&s->migration_blocker, errp) < 0) { return; } } else { diff --git a/hw/intc/arm_gicv3_kvm.c b/hw/intc/arm_gicv3_kvm.c index 72ad916d3d..77eb37e131 100644 --- a/hw/intc/arm_gicv3_kvm.c +++ b/hw/intc/arm_gicv3_kvm.c @@ -878,8 +878,7 @@ static void kvm_arm_gicv3_realize(DeviceState *dev, Error **errp) GICD_CTLR)) { error_setg(&s->migration_blocker, "This operating system kernel does " "not support vGICv3 migration"); - if (migrate_add_blocker(s->migration_blocker, errp) < 0) { - error_free(s->migration_blocker); + if (migrate_add_blocker(&s->migration_blocker, errp) < 0) { return; } } diff --git a/hw/misc/ivshmem.c b/hw/misc/ivshmem.c index d66d912172..0447888029 100644 --- a/hw/misc/ivshmem.c +++ b/hw/misc/ivshmem.c @@ -903,8 +903,7 @@ static void ivshmem_common_realize(PCIDevice *dev, Error **errp) if (!ivshmem_is_master(s)) { error_setg(&s->migration_blocker, "Migration is disabled when using feature 'peer mode' in device 'ivshmem'"); - if (migrate_add_blocker(s->migration_blocker, errp) < 0) { - error_free(s->migration_blocker); + if (migrate_add_blocker(&s->migration_blocker, errp) < 0) { return; } } @@ -922,10 +921,7 @@ static void ivshmem_exit(PCIDevice *dev) IVShmemState *s = IVSHMEM_COMMON(dev); int i; - if (s->migration_blocker) { - migrate_del_blocker(s->migration_blocker); - error_free(s->migration_blocker); - } + migrate_del_blocker(&s->migration_blocker); if (memory_region_is_mapped(s->ivshmem_bar2)) { if (!s->hostmem) { diff --git a/hw/ppc/pef.c b/hw/ppc/pef.c index cc44d5e339..d28ed3ba73 100644 --- a/hw/ppc/pef.c +++ b/hw/ppc/pef.c @@ -63,7 +63,7 @@ static int kvmppc_svm_init(ConfidentialGuestSupport *cgs, Error **errp) /* add migration blocker */ error_setg(&pef_mig_blocker, "PEF: Migration is not implemented"); /* NB: This can fail if --only-migratable is used */ - migrate_add_blocker(pef_mig_blocker, &error_fatal); + migrate_add_blocker(&pef_mig_blocker, &error_fatal); cgs->ready = true; diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c index cb840676d3..b25093be28 100644 --- a/hw/ppc/spapr.c +++ b/hw/ppc/spapr.c @@ -1761,7 +1761,7 @@ static void spapr_machine_reset(MachineState *machine, ShutdownCause reason) /* Signal all vCPUs waiting on this condition */ qemu_cond_broadcast(&spapr->fwnmi_machine_check_interlock_cond); - migrate_del_blocker(spapr->fwnmi_migration_blocker); + migrate_del_blocker(&spapr->fwnmi_migration_blocker); } static void spapr_create_nvram(SpaprMachineState *spapr) @@ -2937,13 +2937,6 @@ static void spapr_machine_init(MachineState *machine) spapr_create_lmb_dr_connectors(spapr); } - if (spapr_get_cap(spapr, SPAPR_CAP_FWNMI) == SPAPR_CAP_ON) { - /* Create the error string for live migration blocker */ - error_setg(&spapr->fwnmi_migration_blocker, - "A machine check is being handled during migration. The handler" - "may run and log hardware error on the destination"); - } - if (mc->nvdimm_supported) { spapr_create_nvdimm_dr_connectors(spapr); } diff --git a/hw/ppc/spapr_events.c b/hw/ppc/spapr_events.c index 4508e40814..deb4641505 100644 --- a/hw/ppc/spapr_events.c +++ b/hw/ppc/spapr_events.c @@ -920,7 +920,11 @@ void spapr_mce_req_event(PowerPCCPU *cpu, bool recovered) * fails when running with -only-migrate. A proper interface to * delay migration completion for a bit could avoid that. */ - ret = migrate_add_blocker(spapr->fwnmi_migration_blocker, NULL); + error_setg(&spapr->fwnmi_migration_blocker, + "A machine check is being handled during migration. The handler" + "may run and log hardware error on the destination"); + + ret = migrate_add_blocker(&spapr->fwnmi_migration_blocker, NULL); if (ret == -EBUSY) { warn_report("Received a fwnmi while migration was in progress"); } diff --git a/hw/ppc/spapr_rtas.c b/hw/ppc/spapr_rtas.c index 7df21581c2..26c384b261 100644 --- a/hw/ppc/spapr_rtas.c +++ b/hw/ppc/spapr_rtas.c @@ -496,7 +496,7 @@ static void rtas_ibm_nmi_interlock(PowerPCCPU *cpu, spapr->fwnmi_machine_check_interlock = -1; qemu_cond_signal(&spapr->fwnmi_machine_check_interlock_cond); rtas_st(rets, 0, RTAS_OUT_SUCCESS); - migrate_del_blocker(spapr->fwnmi_migration_blocker); + migrate_del_blocker(&spapr->fwnmi_migration_blocker); } static struct rtas_call { diff --git a/hw/remote/proxy.c b/hw/remote/proxy.c index 2052d721e5..fbc85a8d36 100644 --- a/hw/remote/proxy.c +++ b/hw/remote/proxy.c @@ -107,8 +107,7 @@ static void pci_proxy_dev_realize(PCIDevice *device, Error **errp) error_setg(&dev->migration_blocker, "%s does not support migration", TYPE_PCI_PROXY_DEV); - if (migrate_add_blocker(dev->migration_blocker, errp) < 0) { - error_free(dev->migration_blocker); + if (migrate_add_blocker(&dev->migration_blocker, errp) < 0) { object_unref(dev->ioc); return; } @@ -134,9 +133,7 @@ static void pci_proxy_dev_exit(PCIDevice *pdev) qio_channel_close(dev->ioc, NULL); } - migrate_del_blocker(dev->migration_blocker); - - error_free(dev->migration_blocker); + migrate_del_blocker(&dev->migration_blocker); proxy_memory_listener_deconfigure(&dev->proxy_listener); diff --git a/hw/s390x/s390-virtio-ccw.c b/hw/s390x/s390-virtio-ccw.c index 2d75f2131f..07a5157c0f 100644 --- a/hw/s390x/s390-virtio-ccw.c +++ b/hw/s390x/s390-virtio-ccw.c @@ -332,8 +332,7 @@ static void s390_machine_unprotect(S390CcwMachineState *ms) s390_pv_vm_disable(); } ms->pv = false; - migrate_del_blocker(pv_mig_blocker); - error_free_or_abort(&pv_mig_blocker); + migrate_del_blocker(&pv_mig_blocker); ram_block_discard_disable(false); } @@ -356,11 +355,10 @@ static int s390_machine_protect(S390CcwMachineState *ms) error_setg(&pv_mig_blocker, "protected VMs are currently not migratable."); - rc = migrate_add_blocker(pv_mig_blocker, &local_err); + rc = migrate_add_blocker(&pv_mig_blocker, &local_err); if (rc) { ram_block_discard_disable(false); error_report_err(local_err); - error_free_or_abort(&pv_mig_blocker); return rc; } @@ -368,8 +366,7 @@ static int s390_machine_protect(S390CcwMachineState *ms) rc = s390_pv_vm_enable(); if (rc) { ram_block_discard_disable(false); - migrate_del_blocker(pv_mig_blocker); - error_free_or_abort(&pv_mig_blocker); + migrate_del_blocker(&pv_mig_blocker); return rc; } diff --git a/hw/scsi/vhost-scsi.c b/hw/scsi/vhost-scsi.c index 443f67daa4..14e23cc5b4 100644 --- a/hw/scsi/vhost-scsi.c +++ b/hw/scsi/vhost-scsi.c @@ -208,7 +208,7 @@ static void vhost_scsi_realize(DeviceState *dev, Error **errp) "When external environment supports it (Orchestrator migrates " "target SCSI device state or use shared storage over network), " "set 'migratable' property to true to enable migration."); - if (migrate_add_blocker(vsc->migration_blocker, errp) < 0) { + if (migrate_add_blocker(&vsc->migration_blocker, errp) < 0) { goto free_virtio; } } @@ -241,10 +241,9 @@ static void vhost_scsi_realize(DeviceState *dev, Error **errp) free_vqs: g_free(vqs); if (!vsc->migratable) { - migrate_del_blocker(vsc->migration_blocker); + migrate_del_blocker(&vsc->migration_blocker); } free_virtio: - error_free(vsc->migration_blocker); virtio_scsi_common_unrealize(dev); close_fd: if (vhostfd >= 0) { @@ -260,8 +259,7 @@ static void vhost_scsi_unrealize(DeviceState *dev) struct vhost_virtqueue *vqs = vsc->dev.vqs; if (!vsc->migratable) { - migrate_del_blocker(vsc->migration_blocker); - error_free(vsc->migration_blocker); + migrate_del_blocker(&vsc->migration_blocker); } /* This will stop vhost backend. */ diff --git a/hw/vfio/common.c b/hw/vfio/common.c index 5ff5acf1d8..d806057b40 100644 --- a/hw/vfio/common.c +++ b/hw/vfio/common.c @@ -129,11 +129,7 @@ int vfio_block_multiple_devices_migration(VFIODevice *vbasedev, Error **errp) error_setg(&multiple_devices_migration_blocker, "Multiple VFIO devices migration is supported only if all of " "them support P2P migration"); - ret = migrate_add_blocker(multiple_devices_migration_blocker, errp); - if (ret < 0) { - error_free(multiple_devices_migration_blocker); - multiple_devices_migration_blocker = NULL; - } + ret = migrate_add_blocker(&multiple_devices_migration_blocker, errp); return ret; } @@ -145,9 +141,7 @@ void vfio_unblock_multiple_devices_migration(void) return; } - migrate_del_blocker(multiple_devices_migration_blocker); - error_free(multiple_devices_migration_blocker); - multiple_devices_migration_blocker = NULL; + migrate_del_blocker(&multiple_devices_migration_blocker); } bool vfio_viommu_preset(VFIODevice *vbasedev) diff --git a/hw/vfio/migration.c b/hw/vfio/migration.c index da43dcd2fe..0aaad65c06 100644 --- a/hw/vfio/migration.c +++ b/hw/vfio/migration.c @@ -891,8 +891,6 @@ static void vfio_migration_deinit(VFIODevice *vbasedev) static int vfio_block_migration(VFIODevice *vbasedev, Error *err, Error **errp) { - int ret; - if (vbasedev->enable_migration == ON_OFF_AUTO_ON) { error_propagate(errp, err); return -EINVAL; @@ -901,13 +899,7 @@ static int vfio_block_migration(VFIODevice *vbasedev, Error *err, Error **errp) vbasedev->migration_blocker = error_copy(err); error_free(err); - ret = migrate_add_blocker(vbasedev->migration_blocker, errp); - if (ret < 0) { - error_free(vbasedev->migration_blocker); - vbasedev->migration_blocker = NULL; - } - - return ret; + return migrate_add_blocker(&vbasedev->migration_blocker, errp); } /* ---------------------------------------------------------------------- */ @@ -994,9 +986,5 @@ void vfio_migration_exit(VFIODevice *vbasedev) vfio_migration_deinit(vbasedev); } - if (vbasedev->migration_blocker) { - migrate_del_blocker(vbasedev->migration_blocker); - error_free(vbasedev->migration_blocker); - vbasedev->migration_blocker = NULL; - } + migrate_del_blocker(&vbasedev->migration_blocker); } diff --git a/hw/virtio/vhost.c b/hw/virtio/vhost.c index 9f37206ba0..d737671028 100644 --- a/hw/virtio/vhost.c +++ b/hw/virtio/vhost.c @@ -1527,9 +1527,8 @@ int vhost_dev_init(struct vhost_dev *hdev, void *opaque, } if (hdev->migration_blocker != NULL) { - r = migrate_add_blocker(hdev->migration_blocker, errp); + r = migrate_add_blocker(&hdev->migration_blocker, errp); if (r < 0) { - error_free(hdev->migration_blocker); goto fail_busyloop; } } @@ -1597,10 +1596,7 @@ void vhost_dev_cleanup(struct vhost_dev *hdev) memory_listener_unregister(&hdev->memory_listener); QLIST_REMOVE(hdev, entry); } - if (hdev->migration_blocker) { - migrate_del_blocker(hdev->migration_blocker); - error_free(hdev->migration_blocker); - } + migrate_del_blocker(&hdev->migration_blocker); g_free(hdev->mem); g_free(hdev->mem_sections); if (hdev->vhost_ops) { diff --git a/include/migration/blocker.h b/include/migration/blocker.h index 9cebe2ba06..b048f301b4 100644 --- a/include/migration/blocker.h +++ b/include/migration/blocker.h @@ -17,19 +17,23 @@ /** * @migrate_add_blocker - prevent migration from proceeding * - * @reason - an error to be returned whenever migration is attempted + * @reasonp - address of an error to be returned whenever migration is attempted * * @errp - [out] The reason (if any) we cannot block migration right now. * * @returns - 0 on success, -EBUSY/-EACCES on failure, with errp set. + * + * *@reasonp is freed and set to NULL if failure is returned. + * On success, the caller must not free @reasonp, except by + * calling migrate_del_blocker. */ -int migrate_add_blocker(Error *reason, Error **errp); +int migrate_add_blocker(Error **reasonp, Error **errp); /** * @migrate_add_blocker_internal - prevent migration from proceeding without * only-migrate implications * - * @reason - an error to be returned whenever migration is attempted + * @reasonp - address of an error to be returned whenever migration is attempted * * @errp - [out] The reason (if any) we cannot block migration right now. * @@ -38,14 +42,20 @@ int migrate_add_blocker(Error *reason, Error **errp); * Some of the migration blockers can be temporary (e.g., for a few seconds), * so it shouldn't need to conflict with "-only-migratable". For those cases, * we can call this function rather than @migrate_add_blocker(). + * + * *@reasonp is freed and set to NULL if failure is returned. + * On success, the caller must not free @reasonp, except by + * calling migrate_del_blocker. */ -int migrate_add_blocker_internal(Error *reason, Error **errp); +int migrate_add_blocker_internal(Error **reasonp, Error **errp); /** - * @migrate_del_blocker - remove a blocking error from migration + * @migrate_del_blocker - remove a blocking error from migration and free it. * - * @reason - the error blocking migration + * @reasonp - address of the error blocking migration + * + * This function frees *@reasonp and sets it to NULL. */ -void migrate_del_blocker(Error *reason); +void migrate_del_blocker(Error **reasonp); #endif diff --git a/migration/migration.c b/migration/migration.c index 05c0b801ba..818b02b707 100644 --- a/migration/migration.c +++ b/migration/migration.c @@ -1465,35 +1465,41 @@ int migrate_init(MigrationState *s, Error **errp) return 0; } -int migrate_add_blocker_internal(Error *reason, Error **errp) +int migrate_add_blocker_internal(Error **reasonp, Error **errp) { /* Snapshots are similar to migrations, so check RUN_STATE_SAVE_VM too. */ if (runstate_check(RUN_STATE_SAVE_VM) || !migration_is_idle()) { - error_propagate_prepend(errp, error_copy(reason), + error_propagate_prepend(errp, *reasonp, "disallowing migration blocker " "(migration/snapshot in progress) for: "); + *reasonp = NULL; return -EBUSY; } - migration_blockers = g_slist_prepend(migration_blockers, reason); + migration_blockers = g_slist_prepend(migration_blockers, *reasonp); return 0; } -int migrate_add_blocker(Error *reason, Error **errp) +int migrate_add_blocker(Error **reasonp, Error **errp) { if (only_migratable) { - error_propagate_prepend(errp, error_copy(reason), + error_propagate_prepend(errp, *reasonp, "disallowing migration blocker " "(--only-migratable) for: "); + *reasonp = NULL; return -EACCES; } - return migrate_add_blocker_internal(reason, errp); + return migrate_add_blocker_internal(reasonp, errp); } -void migrate_del_blocker(Error *reason) +void migrate_del_blocker(Error **reasonp) { - migration_blockers = g_slist_remove(migration_blockers, reason); + if (*reasonp) { + migration_blockers = g_slist_remove(migration_blockers, *reasonp); + error_free(*reasonp); + *reasonp = NULL; + } } void qmp_migrate_incoming(const char *uri, Error **errp) diff --git a/stubs/migr-blocker.c b/stubs/migr-blocker.c index 5676a2f93c..17a5dbf87b 100644 --- a/stubs/migr-blocker.c +++ b/stubs/migr-blocker.c @@ -1,11 +1,11 @@ #include "qemu/osdep.h" #include "migration/blocker.h" -int migrate_add_blocker(Error *reason, Error **errp) +int migrate_add_blocker(Error **reasonp, Error **errp) { return 0; } -void migrate_del_blocker(Error *reason) +void migrate_del_blocker(Error **reasonp) { } diff --git a/target/i386/kvm/kvm.c b/target/i386/kvm/kvm.c index ab72bcdfad..e7c054cc16 100644 --- a/target/i386/kvm/kvm.c +++ b/target/i386/kvm/kvm.c @@ -1603,7 +1603,7 @@ static int hyperv_init_vcpu(X86CPU *cpu) error_setg(&hv_passthrough_mig_blocker, "'hv-passthrough' CPU flag prevents migration, use explicit" " set of hv-* flags instead"); - ret = migrate_add_blocker(hv_passthrough_mig_blocker, &local_err); + ret = migrate_add_blocker(&hv_passthrough_mig_blocker, &local_err); if (ret < 0) { error_report_err(local_err); return ret; @@ -1617,7 +1617,7 @@ static int hyperv_init_vcpu(X86CPU *cpu) " use explicit 'hv-no-nonarch-coresharing=on' instead (but" " make sure SMT is disabled and/or that vCPUs are properly" " pinned)"); - ret = migrate_add_blocker(hv_no_nonarch_cs_mig_blocker, &local_err); + ret = migrate_add_blocker(&hv_no_nonarch_cs_mig_blocker, &local_err); if (ret < 0) { error_report_err(local_err); return ret; @@ -2213,7 +2213,7 @@ int kvm_arch_init_vcpu(CPUState *cs) error_setg(&invtsc_mig_blocker, "State blocked by non-migratable CPU device" " (invtsc flag)"); - r = migrate_add_blocker(invtsc_mig_blocker, &local_err); + r = migrate_add_blocker(&invtsc_mig_blocker, &local_err); if (r < 0) { error_report_err(local_err); return r; @@ -2271,7 +2271,7 @@ int kvm_arch_init_vcpu(CPUState *cs) return 0; fail: - migrate_del_blocker(invtsc_mig_blocker); + migrate_del_blocker(&invtsc_mig_blocker); return r; } diff --git a/target/i386/nvmm/nvmm-all.c b/target/i386/nvmm/nvmm-all.c index fb769868f2..7d752bc5e0 100644 --- a/target/i386/nvmm/nvmm-all.c +++ b/target/i386/nvmm/nvmm-all.c @@ -929,9 +929,8 @@ nvmm_init_vcpu(CPUState *cpu) error_setg(&nvmm_migration_blocker, "NVMM: Migration not supported"); - if (migrate_add_blocker(nvmm_migration_blocker, &local_error) < 0) { + if (migrate_add_blocker(&nvmm_migration_blocker, &local_error) < 0) { error_report_err(local_error); - error_free(nvmm_migration_blocker); return -EINVAL; } } diff --git a/target/i386/sev.c b/target/i386/sev.c index fe2144c038..9a71246682 100644 --- a/target/i386/sev.c +++ b/target/i386/sev.c @@ -891,7 +891,7 @@ sev_launch_finish(SevGuestState *sev) /* add migration blocker */ error_setg(&sev_mig_blocker, "SEV: Migration is not implemented"); - migrate_add_blocker(sev_mig_blocker, &error_fatal); + migrate_add_blocker(&sev_mig_blocker, &error_fatal); } static void diff --git a/target/i386/whpx/whpx-all.c b/target/i386/whpx/whpx-all.c index df3aba2642..d29ba916a0 100644 --- a/target/i386/whpx/whpx-all.c +++ b/target/i386/whpx/whpx-all.c @@ -2160,9 +2160,8 @@ int whpx_init_vcpu(CPUState *cpu) "State blocked due to non-migratable CPUID feature support," "dirty memory tracking support, and XSAVE/XRSTOR support"); - if (migrate_add_blocker(whpx_migration_blocker, &local_error) < 0) { + if (migrate_add_blocker(&whpx_migration_blocker, &local_error) < 0) { error_report_err(local_error); - error_free(whpx_migration_blocker); ret = -EINVAL; goto error; } diff --git a/ui/vdagent.c b/ui/vdagent.c index 00d36a8677..d8f2f95432 100644 --- a/ui/vdagent.c +++ b/ui/vdagent.c @@ -671,7 +671,7 @@ static void vdagent_chr_open(Chardev *chr, return; #endif - if (migrate_add_blocker(vd->migration_blocker, errp) != 0) { + if (migrate_add_blocker(&vd->migration_blocker, errp) != 0) { return; } @@ -924,13 +924,12 @@ static void vdagent_chr_fini(Object *obj) { VDAgentChardev *vd = QEMU_VDAGENT_CHARDEV(obj); - migrate_del_blocker(vd->migration_blocker); + migrate_del_blocker(&vd->migration_blocker); vdagent_disconnect(vd); if (vd->mouse_hs) { qemu_input_handler_unregister(vd->mouse_hs); } buffer_free(&vd->outbuf); - error_free(vd->migration_blocker); } static const TypeInfo vdagent_chr_type_info = { From 2c36076a1153e321e32a28b735f5c0fe70d8d10f Mon Sep 17 00:00:00 2001 From: Peter Xu Date: Tue, 17 Oct 2023 16:38:55 -0400 Subject: [PATCH 0912/1077] migration: Fix parse_ramblock() on overwritten retvals It's possible that some errors can be overwritten with success retval later on, and then ignored. Always capture all errors and report. Reported by Coverity 1522861, but actually I spot one more in the same function. Fixes: CID 1522861 Signed-off-by: Peter Xu Reviewed-by: Fabiano Rosas Reviewed-by: Juan Quintela Signed-off-by: Juan Quintela Message-ID: <20231017203855.298260-1-peterx@redhat.com> --- migration/ram.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/migration/ram.c b/migration/ram.c index 16c30a9d7a..92769902bb 100644 --- a/migration/ram.c +++ b/migration/ram.c @@ -3873,6 +3873,7 @@ static int parse_ramblock(QEMUFile *f, RAMBlock *block, ram_addr_t length) ret = qemu_ram_resize(block, length, &local_err); if (local_err) { error_report_err(local_err); + return ret; } } /* For postcopy we need to check hugepage sizes match */ @@ -3883,7 +3884,7 @@ static int parse_ramblock(QEMUFile *f, RAMBlock *block, ram_addr_t length) error_report("Mismatched RAM page size %s " "(local) %zd != %" PRId64, block->idstr, block->page_size, remote_page_size); - ret = -EINVAL; + return -EINVAL; } } if (migrate_ignore_shared()) { @@ -3893,7 +3894,7 @@ static int parse_ramblock(QEMUFile *f, RAMBlock *block, ram_addr_t length) error_report("Mismatched GPAs for block %s " "%" PRId64 "!= %" PRId64, block->idstr, (uint64_t)addr, (uint64_t)block->mr->addr); - ret = -EINVAL; + return -EINVAL; } } ret = rdma_block_notification_handle(f, block->idstr); From d9cda21303a2b92cf3be48b75d4201896aa06857 Mon Sep 17 00:00:00 2001 From: Steve Sistare Date: Wed, 7 Jun 2023 07:42:34 -0700 Subject: [PATCH 0913/1077] migration: simplify notifiers Pass the callback function to add_migration_state_change_notifier so that migration can initialize the notifier on add and clear it on delete, which simplifies the call sites. Shorten the function names so the extra arg can be added more legibly. Hide the global notifier list in a new function migration_call_notifiers, and make it externally visible so future live update code can call it. No functional change. Signed-off-by: Steve Sistare Reviewed-by: Peter Xu Tested-by: Michael Galaxy Reviewed-by: Michael Galaxy Reviewed-by: Juan Quintela Signed-off-by: Juan Quintela Message-ID: <1686148954-250144-1-git-send-email-steven.sistare@oracle.com> --- hw/net/virtio-net.c | 6 +++--- hw/vfio/migration.c | 6 +++--- include/migration/misc.h | 6 ++++-- migration/migration.c | 22 ++++++++++++++++------ net/vhost-vdpa.c | 7 ++++--- ui/spice-core.c | 3 +-- 6 files changed, 31 insertions(+), 19 deletions(-) diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c index 29e33ea5ed..b85c7946a7 100644 --- a/hw/net/virtio-net.c +++ b/hw/net/virtio-net.c @@ -3624,8 +3624,8 @@ static void virtio_net_device_realize(DeviceState *dev, Error **errp) n->primary_listener.hide_device = failover_hide_primary_device; qatomic_set(&n->failover_primary_hidden, true); device_listener_register(&n->primary_listener); - n->migration_state.notify = virtio_net_migration_state_notifier; - add_migration_state_change_notifier(&n->migration_state); + migration_add_notifier(&n->migration_state, + virtio_net_migration_state_notifier); n->host_features |= (1ULL << VIRTIO_NET_F_STANDBY); } @@ -3788,7 +3788,7 @@ static void virtio_net_device_unrealize(DeviceState *dev) if (n->failover) { qobject_unref(n->primary_opts); device_listener_unregister(&n->primary_listener); - remove_migration_state_change_notifier(&n->migration_state); + migration_remove_notifier(&n->migration_state); } else { assert(n->primary_opts == NULL); } diff --git a/hw/vfio/migration.c b/hw/vfio/migration.c index 0aaad65c06..28d422b39f 100644 --- a/hw/vfio/migration.c +++ b/hw/vfio/migration.c @@ -872,8 +872,8 @@ static int vfio_migration_init(VFIODevice *vbasedev) NULL; migration->vm_state = qdev_add_vm_change_state_handler_full( vbasedev->dev, vfio_vmstate_change, prepare_cb, vbasedev); - migration->migration_state.notify = vfio_migration_state_notifier; - add_migration_state_change_notifier(&migration->migration_state); + migration_add_notifier(&migration->migration_state, + vfio_migration_state_notifier); return 0; } @@ -882,7 +882,7 @@ static void vfio_migration_deinit(VFIODevice *vbasedev) { VFIOMigration *migration = vbasedev->migration; - remove_migration_state_change_notifier(&migration->migration_state); + migration_remove_notifier(&migration->migration_state); qemu_del_vm_change_state_handler(migration->vm_state); unregister_savevm(VMSTATE_IF(vbasedev->dev), "vfio", vbasedev); vfio_migration_free(vbasedev); diff --git a/include/migration/misc.h b/include/migration/misc.h index 7dcc0b5c2c..673ac490fb 100644 --- a/include/migration/misc.h +++ b/include/migration/misc.h @@ -60,8 +60,10 @@ void migration_object_init(void); void migration_shutdown(void); bool migration_is_idle(void); bool migration_is_active(MigrationState *); -void add_migration_state_change_notifier(Notifier *notify); -void remove_migration_state_change_notifier(Notifier *notify); +void migration_add_notifier(Notifier *notify, + void (*func)(Notifier *notifier, void *data)); +void migration_remove_notifier(Notifier *notify); +void migration_call_notifiers(MigrationState *s); bool migration_in_setup(MigrationState *); bool migration_has_finished(MigrationState *); bool migration_has_failed(MigrationState *); diff --git a/migration/migration.c b/migration/migration.c index 818b02b707..67547eb6a1 100644 --- a/migration/migration.c +++ b/migration/migration.c @@ -1207,7 +1207,7 @@ static void migrate_fd_cleanup(MigrationState *s) /* It is used on info migrate. We can't free it */ error_report_err(error_copy(s->error)); } - notifier_list_notify(&migration_state_notifiers, s); + migration_call_notifiers(s); block_cleanup_parameters(); yank_unregister_instance(MIGRATION_YANK_INSTANCE); } @@ -1311,14 +1311,24 @@ static void migrate_fd_cancel(MigrationState *s) } } -void add_migration_state_change_notifier(Notifier *notify) +void migration_add_notifier(Notifier *notify, + void (*func)(Notifier *notifier, void *data)) { + notify->notify = func; notifier_list_add(&migration_state_notifiers, notify); } -void remove_migration_state_change_notifier(Notifier *notify) +void migration_remove_notifier(Notifier *notify) { - notifier_remove(notify); + if (notify->notify) { + notifier_remove(notify); + notify->notify = NULL; + } +} + +void migration_call_notifiers(MigrationState *s) +{ + notifier_list_notify(&migration_state_notifiers, s); } bool migration_in_setup(MigrationState *s) @@ -2233,7 +2243,7 @@ static int postcopy_start(MigrationState *ms, Error **errp) * spice needs to trigger a transition now */ ms->postcopy_after_devices = true; - notifier_list_notify(&migration_state_notifiers, ms); + migration_call_notifiers(ms); ms->downtime = qemu_clock_get_ms(QEMU_CLOCK_REALTIME) - time_at_stop; @@ -3313,7 +3323,7 @@ void migrate_fd_connect(MigrationState *s, Error *error_in) rate_limit = migrate_max_bandwidth(); /* Notify before starting migration thread */ - notifier_list_notify(&migration_state_notifiers, s); + migration_call_notifiers(s); } migration_rate_set(rate_limit); diff --git a/net/vhost-vdpa.c b/net/vhost-vdpa.c index 939c984d5b..0f2e6fc58e 100644 --- a/net/vhost-vdpa.c +++ b/net/vhost-vdpa.c @@ -339,7 +339,8 @@ static void vhost_vdpa_net_data_start_first(VhostVDPAState *s) { struct vhost_vdpa *v = &s->vhost_vdpa; - add_migration_state_change_notifier(&s->migration_state); + migration_add_notifier(&s->migration_state, + vdpa_net_migration_state_notifier); if (v->shadow_vqs_enabled) { v->iova_tree = vhost_iova_tree_new(v->iova_range.first, v->iova_range.last); @@ -399,7 +400,7 @@ static void vhost_vdpa_net_client_stop(NetClientState *nc) assert(nc->info->type == NET_CLIENT_DRIVER_VHOST_VDPA); if (s->vhost_vdpa.index == 0) { - remove_migration_state_change_notifier(&s->migration_state); + migration_remove_notifier(&s->migration_state); } dev = s->vhost_vdpa.dev; @@ -1456,7 +1457,7 @@ static NetClientState *net_vhost_vdpa_init(NetClientState *peer, s->vhost_vdpa.device_fd = vdpa_device_fd; s->vhost_vdpa.index = queue_pair_index; s->always_svq = svq; - s->migration_state.notify = vdpa_net_migration_state_notifier; + s->migration_state.notify = NULL; s->vhost_vdpa.shadow_vqs_enabled = svq; s->vhost_vdpa.iova_range = iova_range; s->vhost_vdpa.shadow_data = svq; diff --git a/ui/spice-core.c b/ui/spice-core.c index 52a59386d7..db21db2c94 100644 --- a/ui/spice-core.c +++ b/ui/spice-core.c @@ -821,8 +821,7 @@ static void qemu_spice_init(void) }; using_spice = 1; - migration_state.notify = migration_state_notifier; - add_migration_state_change_notifier(&migration_state); + migration_add_notifier(&migration_state, migration_state_notifier); spice_migrate.base.sif = &migrate_interface.base; qemu_spice.add_interface(&spice_migrate.base); From 175e63c9829f9887c04bed8e0c4906e1166c9a87 Mon Sep 17 00:00:00 2001 From: Fabiano Rosas Date: Thu, 12 Oct 2023 11:06:47 -0300 Subject: [PATCH 0914/1077] migration/multifd: Stop checking p->quit in multifd_send_thread We don't need to check p->quit in the multifd_send_thread() because it is shadowed by the 'exiting' flag. Ever since that flag was added p->quit became obsolete as a way to stop the thread. Since p->quit is set at multifd_send_terminate_threads() under the p->mutex lock, the thread will only see it once it loops, so 'exiting' will always be seen first. Note that setting p->quit at multifd_send_terminate_threads() still makes sense because we need a way to inform multifd_send_pages() that the channel has stopped. Signed-off-by: Fabiano Rosas Reviewed-by: Juan Quintela Signed-off-by: Juan Quintela Message-ID: <20231012140651.13122-3-farosas@suse.de> --- migration/multifd.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/migration/multifd.c b/migration/multifd.c index 1fe53d3b98..e2a45c667a 100644 --- a/migration/multifd.c +++ b/migration/multifd.c @@ -743,9 +743,6 @@ static void *multifd_send_thread(void *opaque) if (flags & MULTIFD_FLAG_SYNC) { qemu_sem_post(&p->sem_sync); } - } else if (p->quit) { - qemu_mutex_unlock(&p->mutex); - break; } else { qemu_mutex_unlock(&p->mutex); /* sometimes there are spurious wakeups */ From f4a7b30fcd5b60ca9b0215f9a6fa1faf9bd73f7b Mon Sep 17 00:00:00 2001 From: Fabiano Rosas Date: Wed, 18 Oct 2023 16:27:30 -0300 Subject: [PATCH 0915/1077] tests/qtest: Allow qtest_qemu_binary to use a custom environment variable We're adding support for testing migration using two different QEMU binaries. We'll provide the second binary in a new environment variable. Allow qtest_qemu_binary() to receive the name of the new variable. If the new environment variable is not set, that's not an error, we use QTEST_QEMU_BINARY as a fallback. Reviewed-by: Juan Quintela Reviewed-by: Thomas Huth Signed-off-by: Fabiano Rosas Signed-off-by: Juan Quintela Message-ID: <20231018192741.25885-2-farosas@suse.de> --- tests/qtest/libqtest.c | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/tests/qtest/libqtest.c b/tests/qtest/libqtest.c index dc7a55634c..03fa644663 100644 --- a/tests/qtest/libqtest.c +++ b/tests/qtest/libqtest.c @@ -336,10 +336,17 @@ void qtest_remove_abrt_handler(void *data) } } -static const char *qtest_qemu_binary(void) +static const char *qtest_qemu_binary(const char *var) { const char *qemu_bin; + if (var) { + qemu_bin = getenv(var); + if (qemu_bin) { + return qemu_bin; + } + } + qemu_bin = getenv("QTEST_QEMU_BINARY"); if (!qemu_bin) { fprintf(stderr, "Environment variable QTEST_QEMU_BINARY required\n"); @@ -392,7 +399,7 @@ static QTestState *G_GNUC_PRINTF(1, 2) qtest_spawn_qemu(const char *fmt, ...) va_start(ap, fmt); g_string_append_printf(command, CMD_EXEC "%s %s", - qtest_qemu_binary(), tracearg); + qtest_qemu_binary(NULL), tracearg); g_string_append_vprintf(command, fmt, ap); va_end(ap); @@ -905,7 +912,7 @@ char *qtest_hmp(QTestState *s, const char *fmt, ...) const char *qtest_get_arch(void) { - const char *qemu = qtest_qemu_binary(); + const char *qemu = qtest_qemu_binary(NULL); const char *end = strrchr(qemu, '-'); if (!end) { From 9931215bd33b640dcc824e07431e67e6ddb6b1e1 Mon Sep 17 00:00:00 2001 From: Fabiano Rosas Date: Wed, 18 Oct 2023 16:27:31 -0300 Subject: [PATCH 0916/1077] tests/qtest: Introduce qtest_init_with_env Add a version of qtest_init() that takes an environment variable containing the path of the QEMU binary. This allows tests to use more than one QEMU binary. If no variable is provided or the environment variable does not exist, that is not an error. Fallback to using QTEST_QEMU_BINARY. Signed-off-by: Fabiano Rosas Reviewed-by: Juan Quintela Reviewed-by: Thomas Huth Signed-off-by: Juan Quintela Message-ID: <20231018192741.25885-3-farosas@suse.de> --- tests/qtest/libqtest.c | 26 +++++++++++++++++++------- tests/qtest/libqtest.h | 13 +++++++++++++ 2 files changed, 32 insertions(+), 7 deletions(-) diff --git a/tests/qtest/libqtest.c b/tests/qtest/libqtest.c index 03fa644663..9eebba8767 100644 --- a/tests/qtest/libqtest.c +++ b/tests/qtest/libqtest.c @@ -388,7 +388,8 @@ static pid_t qtest_create_process(char *cmd) } #endif /* _WIN32 */ -static QTestState *G_GNUC_PRINTF(1, 2) qtest_spawn_qemu(const char *fmt, ...) +static QTestState *G_GNUC_PRINTF(2, 3) qtest_spawn_qemu(const char *qemu_bin, + const char *fmt, ...) { va_list ap; QTestState *s = g_new0(QTestState, 1); @@ -398,8 +399,7 @@ static QTestState *G_GNUC_PRINTF(1, 2) qtest_spawn_qemu(const char *fmt, ...) g_autoptr(GString) command = g_string_new(""); va_start(ap, fmt); - g_string_append_printf(command, CMD_EXEC "%s %s", - qtest_qemu_binary(NULL), tracearg); + g_string_append_printf(command, CMD_EXEC "%s %s", qemu_bin, tracearg); g_string_append_vprintf(command, fmt, ap); va_end(ap); @@ -438,7 +438,8 @@ static QTestState *G_GNUC_PRINTF(1, 2) qtest_spawn_qemu(const char *fmt, ...) return s; } -QTestState *qtest_init_without_qmp_handshake(const char *extra_args) +static QTestState *qtest_init_internal(const char *qemu_bin, + const char *extra_args) { QTestState *s; int sock, qmpsock, i; @@ -463,7 +464,8 @@ QTestState *qtest_init_without_qmp_handshake(const char *extra_args) sock = init_socket(socket_path); qmpsock = init_socket(qmp_socket_path); - s = qtest_spawn_qemu("-qtest unix:%s " + s = qtest_spawn_qemu(qemu_bin, + "-qtest unix:%s " "-qtest-log %s " "-chardev socket,path=%s,id=char0 " "-mon chardev=char0,mode=control " @@ -516,9 +518,14 @@ QTestState *qtest_init_without_qmp_handshake(const char *extra_args) return s; } -QTestState *qtest_init(const char *extra_args) +QTestState *qtest_init_without_qmp_handshake(const char *extra_args) { - QTestState *s = qtest_init_without_qmp_handshake(extra_args); + return qtest_init_internal(qtest_qemu_binary(NULL), extra_args); +} + +QTestState *qtest_init_with_env(const char *var, const char *extra_args) +{ + QTestState *s = qtest_init_internal(qtest_qemu_binary(var), extra_args); QDict *greeting; /* Read the QMP greeting and then do the handshake */ @@ -529,6 +536,11 @@ QTestState *qtest_init(const char *extra_args) return s; } +QTestState *qtest_init(const char *extra_args) +{ + return qtest_init_with_env(NULL, extra_args); +} + QTestState *qtest_vinitf(const char *fmt, va_list ap) { char *args = g_strdup_vprintf(fmt, ap); diff --git a/tests/qtest/libqtest.h b/tests/qtest/libqtest.h index 5fe3d13466..76fc195f1c 100644 --- a/tests/qtest/libqtest.h +++ b/tests/qtest/libqtest.h @@ -55,6 +55,19 @@ QTestState *qtest_vinitf(const char *fmt, va_list ap) G_GNUC_PRINTF(1, 0); */ QTestState *qtest_init(const char *extra_args); +/** + * qtest_init_with_env: + * @var: Environment variable from where to take the QEMU binary + * @extra_args: Other arguments to pass to QEMU. CAUTION: these + * arguments are subject to word splitting and shell evaluation. + * + * Like qtest_init(), but use a different environment variable for the + * QEMU binary. + * + * Returns: #QTestState instance. + */ +QTestState *qtest_init_with_env(const char *var, const char *extra_args); + /** * qtest_init_without_qmp_handshake: * @extra_args: other arguments to pass to QEMU. CAUTION: these From 41b2eba4e5c480b8515db60f23b0cb5eeae0dc50 Mon Sep 17 00:00:00 2001 From: Fabiano Rosas Date: Wed, 18 Oct 2023 16:27:32 -0300 Subject: [PATCH 0917/1077] tests/qtest: Allow qtest_get_machines to use an alternate QEMU binary We're adding support for using more than one QEMU binary in tests. Modify qtest_get_machines() to take an environment variable that contains the QEMU binary path. Since the function keeps a cache of the machines list in the form of a static variable, refresh it any time the environment variable changes. Reviewed-by: Juan Quintela Reviewed-by: Thomas Huth Signed-off-by: Fabiano Rosas Signed-off-by: Juan Quintela Message-ID: <20231018192741.25885-4-farosas@suse.de> --- tests/qtest/libqtest.c | 29 +++++++++++++++++++++++++---- 1 file changed, 25 insertions(+), 4 deletions(-) diff --git a/tests/qtest/libqtest.c b/tests/qtest/libqtest.c index 9eebba8767..3cc7bf3076 100644 --- a/tests/qtest/libqtest.c +++ b/tests/qtest/libqtest.c @@ -1468,13 +1468,26 @@ struct MachInfo { char *alias; }; +static void qtest_free_machine_list(struct MachInfo *machines) +{ + if (machines) { + for (int i = 0; machines[i].name != NULL; i++) { + g_free(machines[i].name); + g_free(machines[i].alias); + } + + g_free(machines); + } +} + /* * Returns an array with pointers to the available machine names. * The terminating entry has the name set to NULL. */ -static struct MachInfo *qtest_get_machines(void) +static struct MachInfo *qtest_get_machines(const char *var) { static struct MachInfo *machines; + static char *qemu_var; QDict *response, *minfo; QList *list; const QListEntry *p; @@ -1483,11 +1496,19 @@ static struct MachInfo *qtest_get_machines(void) QTestState *qts; int idx; + if (g_strcmp0(qemu_var, var)) { + qemu_var = g_strdup(var); + + /* new qemu, clear the cache */ + qtest_free_machine_list(machines); + machines = NULL; + } + if (machines) { return machines; } - qts = qtest_init("-machine none"); + qts = qtest_init_with_env(qemu_var, "-machine none"); response = qtest_qmp(qts, "{ 'execute': 'query-machines' }"); g_assert(response); list = qdict_get_qlist(response, "return"); @@ -1528,7 +1549,7 @@ void qtest_cb_for_every_machine(void (*cb)(const char *machine), struct MachInfo *machines; int i; - machines = qtest_get_machines(); + machines = qtest_get_machines(NULL); for (i = 0; machines[i].name != NULL; i++) { /* Ignore machines that cannot be used for qtests */ @@ -1549,7 +1570,7 @@ bool qtest_has_machine(const char *machine) struct MachInfo *machines; int i; - machines = qtest_get_machines(); + machines = qtest_get_machines(NULL); for (i = 0; machines[i].name != NULL; i++) { if (g_str_equal(machine, machines[i].name) || From 1027fc0ae4fcd24c11a43d1f217a1d11579a574b Mon Sep 17 00:00:00 2001 From: Fabiano Rosas Date: Wed, 18 Oct 2023 16:27:33 -0300 Subject: [PATCH 0918/1077] tests/qtest: Introduce qtest_has_machine_with_env Add a variant of qtest_has_machine() that receives an environment variable containing an alternate QEMU binary path. Reviewed-by: Juan Quintela Reviewed-by: Thomas Huth Signed-off-by: Fabiano Rosas Signed-off-by: Juan Quintela Message-ID: <20231018192741.25885-5-farosas@suse.de> --- tests/qtest/libqtest.c | 9 +++++++-- tests/qtest/libqtest.h | 9 +++++++++ 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/tests/qtest/libqtest.c b/tests/qtest/libqtest.c index 3cc7bf3076..603d900e7d 100644 --- a/tests/qtest/libqtest.c +++ b/tests/qtest/libqtest.c @@ -1565,12 +1565,12 @@ void qtest_cb_for_every_machine(void (*cb)(const char *machine), } } -bool qtest_has_machine(const char *machine) +bool qtest_has_machine_with_env(const char *var, const char *machine) { struct MachInfo *machines; int i; - machines = qtest_get_machines(NULL); + machines = qtest_get_machines(var); for (i = 0; machines[i].name != NULL; i++) { if (g_str_equal(machine, machines[i].name) || @@ -1582,6 +1582,11 @@ bool qtest_has_machine(const char *machine) return false; } +bool qtest_has_machine(const char *machine) +{ + return qtest_has_machine_with_env(NULL, machine); +} + bool qtest_has_device(const char *device) { static QList *list; diff --git a/tests/qtest/libqtest.h b/tests/qtest/libqtest.h index 76fc195f1c..d16deb9891 100644 --- a/tests/qtest/libqtest.h +++ b/tests/qtest/libqtest.h @@ -930,6 +930,15 @@ void qtest_cb_for_every_machine(void (*cb)(const char *machine), */ bool qtest_has_machine(const char *machine); +/** + * qtest_has_machine_with_env: + * @var: Environment variable from where to take the QEMU binary + * @machine: The machine to look for + * + * Returns: true if the machine is available in the specified binary. + */ +bool qtest_has_machine_with_env(const char *var, const char *machine); + /** * qtest_has_device: * @device: The device to look for From a3c0ebc9b09cb15cac35690412eb66aaa5eb4f23 Mon Sep 17 00:00:00 2001 From: Fabiano Rosas Date: Wed, 18 Oct 2023 16:27:34 -0300 Subject: [PATCH 0919/1077] tests/qtest: Introduce qtest_resolve_machine_alias The migration tests are being enhanced to test migration between different QEMU versions. A requirement of migration is that the machine type between source and destination matches, including the version. We cannot hardcode machine types in the tests because those change with each release. QEMU provides a machine type alias that has a fixed name, but points to the latest machine type at each release. Add a helper to resolve the alias into the exact machine type. E.g. "-machine pc" resolves to "pc-i440fx-8.2" Reviewed-by: Juan Quintela Reviewed-by: Thomas Huth Signed-off-by: Fabiano Rosas Signed-off-by: Juan Quintela Message-ID: <20231018192741.25885-6-farosas@suse.de> --- tests/qtest/libqtest.c | 16 ++++++++++++++++ tests/qtest/libqtest.h | 10 ++++++++++ 2 files changed, 26 insertions(+) diff --git a/tests/qtest/libqtest.c b/tests/qtest/libqtest.c index 603d900e7d..c843c41188 100644 --- a/tests/qtest/libqtest.c +++ b/tests/qtest/libqtest.c @@ -1565,6 +1565,22 @@ void qtest_cb_for_every_machine(void (*cb)(const char *machine), } } +char *qtest_resolve_machine_alias(const char *var, const char *alias) +{ + struct MachInfo *machines; + int i; + + machines = qtest_get_machines(var); + + for (i = 0; machines[i].name != NULL; i++) { + if (machines[i].alias && g_str_equal(alias, machines[i].alias)) { + return g_strdup(machines[i].name); + } + } + + return NULL; +} + bool qtest_has_machine_with_env(const char *var, const char *machine) { struct MachInfo *machines; diff --git a/tests/qtest/libqtest.h b/tests/qtest/libqtest.h index d16deb9891..6e3d3525bf 100644 --- a/tests/qtest/libqtest.h +++ b/tests/qtest/libqtest.h @@ -922,6 +922,16 @@ void qtest_qmp_fds_assert_success(QTestState *qts, int *fds, size_t nfds, void qtest_cb_for_every_machine(void (*cb)(const char *machine), bool skip_old_versioned); +/** + * qtest_resolve_machine_alias: + * @var: Environment variable from where to take the QEMU binary + * @alias: The alias to resolve + * + * Returns: the machine type corresponding to the alias if any, + * otherwise NULL. + */ +char *qtest_resolve_machine_alias(const char *var, const char *alias); + /** * qtest_has_machine: * @machine: The machine to look for From dcf389cbc84c2b714d49887775918c5f03f73864 Mon Sep 17 00:00:00 2001 From: Fabiano Rosas Date: Wed, 18 Oct 2023 16:27:35 -0300 Subject: [PATCH 0920/1077] tests/qtest/migration: Introduce find_common_machine_version When using two different QEMU binaries for migration testing, we'll need to find what is the machine version that will work with both binaries. Add a helper for that. Reviewed-by: Juan Quintela Reviewed-by: Thomas Huth Signed-off-by: Fabiano Rosas Signed-off-by: Juan Quintela Message-ID: <20231018192741.25885-7-farosas@suse.de> --- tests/qtest/migration-helpers.c | 26 ++++++++++++++++++++++++++ tests/qtest/migration-helpers.h | 2 ++ 2 files changed, 28 insertions(+) diff --git a/tests/qtest/migration-helpers.c b/tests/qtest/migration-helpers.c index 0c185db450..13449c1fe1 100644 --- a/tests/qtest/migration-helpers.c +++ b/tests/qtest/migration-helpers.c @@ -240,3 +240,29 @@ void wait_for_migration_fail(QTestState *from, bool allow_active) g_assert(qdict_get_bool(rsp_return, "running")); qobject_unref(rsp_return); } + +char *find_common_machine_version(const char *mtype, const char *var1, + const char *var2) +{ + g_autofree char *type1 = qtest_resolve_machine_alias(var1, mtype); + g_autofree char *type2 = qtest_resolve_machine_alias(var2, mtype); + + g_assert(type1 && type2); + + if (g_str_equal(type1, type2)) { + /* either can be used */ + return g_strdup(type1); + } + + if (qtest_has_machine_with_env(var2, type1)) { + return g_strdup(type1); + } + + if (qtest_has_machine_with_env(var1, type2)) { + return g_strdup(type2); + } + + g_test_message("No common machine version for machine type '%s' between " + "binaries %s and %s", mtype, getenv(var1), getenv(var2)); + g_assert_not_reached(); +} diff --git a/tests/qtest/migration-helpers.h b/tests/qtest/migration-helpers.h index 4f51d0f8bc..d1c2351d33 100644 --- a/tests/qtest/migration-helpers.h +++ b/tests/qtest/migration-helpers.h @@ -43,4 +43,6 @@ void wait_for_migration_complete(QTestState *who); void wait_for_migration_fail(QTestState *from, bool allow_active); +char *find_common_machine_version(const char *mtype, const char *var1, + const char *var2); #endif /* MIGRATION_HELPERS_H */ From c99613910106fd9a79005a3e8f47b1ce7d46dbc4 Mon Sep 17 00:00:00 2001 From: Fabiano Rosas Date: Wed, 18 Oct 2023 16:27:36 -0300 Subject: [PATCH 0921/1077] tests/qtest/migration: Define a machine for all architectures Stop relying on defaults and select a machine explicitly for every architecture. This is a prerequisite for being able to select machine types for migration using different QEMU binaries for source and destination. Signed-off-by: Fabiano Rosas Reviewed-by: Thomas Huth Reviewed-by: Juan Quintela Signed-off-by: Juan Quintela Message-ID: <20231018192741.25885-8-farosas@suse.de> --- tests/qtest/migration-test.c | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/tests/qtest/migration-test.c b/tests/qtest/migration-test.c index 241b409857..dfea75b76f 100644 --- a/tests/qtest/migration-test.c +++ b/tests/qtest/migration-test.c @@ -743,6 +743,7 @@ static int test_migrate_start(QTestState **from, QTestState **to, const char *kvm_opts = NULL; const char *arch = qtest_get_arch(); const char *memory_size; + const char *machine_alias, *machine_opts = ""; if (args->use_shmem) { if (!g_file_test("/dev/shm", G_FILE_TEST_IS_DIR)) { @@ -755,11 +756,13 @@ static int test_migrate_start(QTestState **from, QTestState **to, got_dst_resume = false; if (strcmp(arch, "i386") == 0 || strcmp(arch, "x86_64") == 0) { memory_size = "150M"; + machine_alias = "pc"; arch_opts = g_strdup_printf("-drive file=%s,format=raw", bootpath); start_address = X86_TEST_MEM_START; end_address = X86_TEST_MEM_END; } else if (g_str_equal(arch, "s390x")) { memory_size = "128M"; + machine_alias = "s390-ccw-virtio"; arch_opts = g_strdup_printf("-bios %s", bootpath); start_address = S390_TEST_MEM_START; end_address = S390_TEST_MEM_END; @@ -771,11 +774,14 @@ static int test_migrate_start(QTestState **from, QTestState **to, "'nvramrc=hex .\" _\" begin %x %x " "do i c@ 1 + i c! 1000 +loop .\" B\" 0 " "until'", end_address, start_address); - arch_opts = g_strdup("-nodefaults -machine vsmt=8"); + machine_alias = "pseries"; + machine_opts = "vsmt=8"; + arch_opts = g_strdup("-nodefaults"); } else if (strcmp(arch, "aarch64") == 0) { memory_size = "150M"; - arch_opts = g_strdup_printf("-machine virt,gic-version=max -cpu max " - "-kernel %s", bootpath); + machine_alias = "virt"; + machine_opts = "gic-version=max"; + arch_opts = g_strdup_printf("-cpu max -kernel %s", bootpath); start_address = ARM_TEST_MEM_START; end_address = ARM_TEST_MEM_END; } else { @@ -810,11 +816,13 @@ static int test_migrate_start(QTestState **from, QTestState **to, } cmd_source = g_strdup_printf("-accel kvm%s -accel tcg " + "-machine %s,%s " "-name source,debug-threads=on " "-m %s " "-serial file:%s/src_serial " "%s %s %s %s %s", kvm_opts ? kvm_opts : "", + machine_alias, machine_opts, memory_size, tmpfs, arch_opts ? arch_opts : "", arch_source ? arch_source : "", @@ -829,12 +837,14 @@ static int test_migrate_start(QTestState **from, QTestState **to, } cmd_target = g_strdup_printf("-accel kvm%s -accel tcg " + "-machine %s,%s " "-name target,debug-threads=on " "-m %s " "-serial file:%s/dest_serial " "-incoming %s " "%s %s %s %s %s", kvm_opts ? kvm_opts : "", + machine_alias, machine_opts, memory_size, tmpfs, uri, arch_opts ? arch_opts : "", arch_target ? arch_target : "", From 3cb9c6553be28b01761c97768abb41c4b5aaa333 Mon Sep 17 00:00:00 2001 From: Fabiano Rosas Date: Wed, 18 Oct 2023 16:27:37 -0300 Subject: [PATCH 0922/1077] tests/qtest/migration: Specify the geometry of the bootsector We're about to enable the x86_64 tests to run with the q35 machine, but that machine does not work with the program we use to dirty the memory for the tests. The issue is that QEMU needs to guess the geometry of the "disk" we give to it and the guessed geometry doesn't pass the sanity checks done by SeaBIOS. This causes SeaBIOS to interpret the geometry as if needing a translation from LBA to CHS and SeaBIOS ends up miscomputing the number of cylinders and aborting due to that. The reason things work with the "pc" machine is that is uses ATA instead of AHCI like q35 and SeaBIOS has an exception for ATA that ends up skipping the sanity checks and ignoring translation altogether. Workaround this situation by specifying a geometry in the command line. Signed-off-by: Fabiano Rosas Acked-by: Thomas Huth Reviewed-by: Juan Quintela Signed-off-by: Juan Quintela Message-ID: <20231018192741.25885-9-farosas@suse.de> --- tests/qtest/migration-test.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tests/qtest/migration-test.c b/tests/qtest/migration-test.c index dfea75b76f..9959a0dc12 100644 --- a/tests/qtest/migration-test.c +++ b/tests/qtest/migration-test.c @@ -757,7 +757,9 @@ static int test_migrate_start(QTestState **from, QTestState **to, if (strcmp(arch, "i386") == 0 || strcmp(arch, "x86_64") == 0) { memory_size = "150M"; machine_alias = "pc"; - arch_opts = g_strdup_printf("-drive file=%s,format=raw", bootpath); + arch_opts = g_strdup_printf( + "-drive if=none,id=d0,file=%s,format=raw " + "-device ide-hd,drive=d0,secs=1,cyls=1,heads=1", bootpath); start_address = X86_TEST_MEM_START; end_address = X86_TEST_MEM_END; } else if (g_str_equal(arch, "s390x")) { From fa35b0cb25775abb95f61e219b14b63084fb7c5a Mon Sep 17 00:00:00 2001 From: Fabiano Rosas Date: Wed, 18 Oct 2023 16:27:38 -0300 Subject: [PATCH 0923/1077] tests/qtest/migration: Set q35 as the default machine for x86_86 Change the x86_64 to use the q35 machines in tests from now on. Keep testing the pc macine on 32bit. Signed-off-by: Fabiano Rosas Reviewed-by: Thomas Huth Reviewed-by: Juan Quintela Signed-off-by: Juan Quintela Message-ID: <20231018192741.25885-10-farosas@suse.de> --- tests/qtest/migration-test.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/tests/qtest/migration-test.c b/tests/qtest/migration-test.c index 9959a0dc12..03f3feac7b 100644 --- a/tests/qtest/migration-test.c +++ b/tests/qtest/migration-test.c @@ -756,7 +756,12 @@ static int test_migrate_start(QTestState **from, QTestState **to, got_dst_resume = false; if (strcmp(arch, "i386") == 0 || strcmp(arch, "x86_64") == 0) { memory_size = "150M"; - machine_alias = "pc"; + + if (g_str_equal(arch, "i386")) { + machine_alias = "pc"; + } else { + machine_alias = "q35"; + } arch_opts = g_strdup_printf( "-drive if=none,id=d0,file=%s,format=raw " "-device ide-hd,drive=d0,secs=1,cyls=1,heads=1", bootpath); From 5050ad2a380832a62c7dedda147bbee06c8fe924 Mon Sep 17 00:00:00 2001 From: Fabiano Rosas Date: Wed, 18 Oct 2023 16:27:39 -0300 Subject: [PATCH 0924/1077] tests/qtest/migration: Support more than one QEMU binary We have strict rules around migration compatibility between different QEMU versions but no test to validate the migration state between different binaries. Add infrastructure to allow running the migration tests with two different QEMU binaries as migration source and destination. The code now recognizes two new environment variables QTEST_QEMU_BINARY_SRC and QTEST_QEMU_BINARY_DST. In the absence of either of them, the test will use the QTEST_QEMU_BINARY variable. If both are missing then the tests are run with single binary as previously. The machine type is selected automatically as the latest machine type version that works with both binaries. Usage (only one of SRC|DST is allowed): QTEST_QEMU_BINARY_SRC=../build-8.2.0/qemu-system-x86_64 \ QTEST_QEMU_BINARY=../build-8.1.0/qemu-system-x86_64 \ ./tests/qtest/migration-test Reviewed-by: Juan Quintela Signed-off-by: Fabiano Rosas Reviewed-by: Thomas Huth Signed-off-by: Juan Quintela Message-ID: <20231018192741.25885-11-farosas@suse.de> --- tests/qtest/migration-test.c | 28 ++++++++++++++++++++++++---- 1 file changed, 24 insertions(+), 4 deletions(-) diff --git a/tests/qtest/migration-test.c b/tests/qtest/migration-test.c index 03f3feac7b..4a5d37317a 100644 --- a/tests/qtest/migration-test.c +++ b/tests/qtest/migration-test.c @@ -71,6 +71,8 @@ static bool got_dst_resume; #define QEMU_VM_FILE_MAGIC 0x5145564d #define FILE_TEST_FILENAME "migfile" #define FILE_TEST_OFFSET 0x1000 +#define QEMU_ENV_SRC "QTEST_QEMU_BINARY_SRC" +#define QEMU_ENV_DST "QTEST_QEMU_BINARY_DST" #if defined(__linux__) #include @@ -744,6 +746,7 @@ static int test_migrate_start(QTestState **from, QTestState **to, const char *arch = qtest_get_arch(); const char *memory_size; const char *machine_alias, *machine_opts = ""; + g_autofree char *machine = NULL; if (args->use_shmem) { if (!g_file_test("/dev/shm", G_FILE_TEST_IS_DIR)) { @@ -822,6 +825,10 @@ static int test_migrate_start(QTestState **from, QTestState **to, kvm_opts = ",dirty-ring-size=4096"; } + machine = find_common_machine_version(machine_alias, QEMU_ENV_SRC, + QEMU_ENV_DST); + g_test_message("Using machine type: %s", machine); + cmd_source = g_strdup_printf("-accel kvm%s -accel tcg " "-machine %s,%s " "-name source,debug-threads=on " @@ -829,7 +836,7 @@ static int test_migrate_start(QTestState **from, QTestState **to, "-serial file:%s/src_serial " "%s %s %s %s %s", kvm_opts ? kvm_opts : "", - machine_alias, machine_opts, + machine, machine_opts, memory_size, tmpfs, arch_opts ? arch_opts : "", arch_source ? arch_source : "", @@ -837,7 +844,7 @@ static int test_migrate_start(QTestState **from, QTestState **to, args->opts_source ? args->opts_source : "", ignore_stderr); if (!args->only_target) { - *from = qtest_init(cmd_source); + *from = qtest_init_with_env(QEMU_ENV_SRC, cmd_source); qtest_qmp_set_event_callback(*from, migrate_watch_for_stop, &got_src_stop); @@ -851,14 +858,14 @@ static int test_migrate_start(QTestState **from, QTestState **to, "-incoming %s " "%s %s %s %s %s", kvm_opts ? kvm_opts : "", - machine_alias, machine_opts, + machine, machine_opts, memory_size, tmpfs, uri, arch_opts ? arch_opts : "", arch_target ? arch_target : "", shmem_opts ? shmem_opts : "", args->opts_target ? args->opts_target : "", ignore_stderr); - *to = qtest_init(cmd_target); + *to = qtest_init_with_env(QEMU_ENV_DST, cmd_target); qtest_qmp_set_event_callback(*to, migrate_watch_for_resume, &got_dst_resume); @@ -2989,10 +2996,23 @@ int main(int argc, char **argv) bool has_uffd; const char *arch; g_autoptr(GError) err = NULL; + const char *qemu_src = getenv(QEMU_ENV_SRC); + const char *qemu_dst = getenv(QEMU_ENV_DST); int ret; g_test_init(&argc, &argv, NULL); + /* + * The default QTEST_QEMU_BINARY must always be provided because + * that is what helpers use to query the accel type and + * architecture. + */ + if (qemu_src && qemu_dst) { + g_test_message("Only one of %s, %s is allowed", + QEMU_ENV_SRC, QEMU_ENV_DST); + exit(1); + } + has_kvm = qtest_has_accel("kvm"); has_tcg = qtest_has_accel("tcg"); From 6c6d2330a07d8a1ba1c1613d8631599a072c5544 Mon Sep 17 00:00:00 2001 From: Fabiano Rosas Date: Wed, 18 Oct 2023 16:27:40 -0300 Subject: [PATCH 0925/1077] tests/qtest/migration: Allow user to specify a machine type Accept the QTEST_QEMU_MACHINE_TYPE environment variable to take a machine type to use in the tests. The full machine type is recognized (e.g. pc-q35-8.2). Aliases (e.g. pc) are also allowed and resolve to the latest machine version for that alias, or, if using two QEMU binaries, to the latest common machine version between the two. Signed-off-by: Fabiano Rosas Reviewed-by: Thomas Huth Reviewed-by: Juan Quintela Signed-off-by: Juan Quintela Message-ID: <20231018192741.25885-12-farosas@suse.de> --- tests/qtest/migration-helpers.c | 26 ++++++++++++++++++++++++++ tests/qtest/migration-helpers.h | 2 ++ tests/qtest/migration-test.c | 5 +++-- 3 files changed, 31 insertions(+), 2 deletions(-) diff --git a/tests/qtest/migration-helpers.c b/tests/qtest/migration-helpers.c index 13449c1fe1..24fb7b3525 100644 --- a/tests/qtest/migration-helpers.c +++ b/tests/qtest/migration-helpers.c @@ -11,6 +11,7 @@ */ #include "qemu/osdep.h" +#include "qemu/ctype.h" #include "qapi/qmp/qjson.h" #include "migration-helpers.h" @@ -266,3 +267,28 @@ char *find_common_machine_version(const char *mtype, const char *var1, "binaries %s and %s", mtype, getenv(var1), getenv(var2)); g_assert_not_reached(); } + +char *resolve_machine_version(const char *alias, const char *var1, + const char *var2) +{ + const char *mname = g_getenv("QTEST_QEMU_MACHINE_TYPE"); + g_autofree char *machine_name = NULL; + + if (mname) { + const char *dash = strrchr(mname, '-'); + const char *dot = strrchr(mname, '.'); + + machine_name = g_strdup(mname); + + if (dash && dot) { + assert(qtest_has_machine(machine_name)); + return g_steal_pointer(&machine_name); + } + /* else: probably an alias, let it be resolved below */ + } else { + /* use the hardcoded alias */ + machine_name = g_strdup(alias); + } + + return find_common_machine_version(machine_name, var1, var2); +} diff --git a/tests/qtest/migration-helpers.h b/tests/qtest/migration-helpers.h index d1c2351d33..e31dc85cc7 100644 --- a/tests/qtest/migration-helpers.h +++ b/tests/qtest/migration-helpers.h @@ -45,4 +45,6 @@ void wait_for_migration_fail(QTestState *from, bool allow_active); char *find_common_machine_version(const char *mtype, const char *var1, const char *var2); +char *resolve_machine_version(const char *alias, const char *var1, + const char *var2); #endif /* MIGRATION_HELPERS_H */ diff --git a/tests/qtest/migration-test.c b/tests/qtest/migration-test.c index 4a5d37317a..bc70a14642 100644 --- a/tests/qtest/migration-test.c +++ b/tests/qtest/migration-test.c @@ -825,8 +825,9 @@ static int test_migrate_start(QTestState **from, QTestState **to, kvm_opts = ",dirty-ring-size=4096"; } - machine = find_common_machine_version(machine_alias, QEMU_ENV_SRC, - QEMU_ENV_DST); + machine = resolve_machine_version(machine_alias, QEMU_ENV_SRC, + QEMU_ENV_DST); + g_test_message("Using machine type: %s", machine); cmd_source = g_strdup_printf("-accel kvm%s -accel tcg " From 7789331b03ae3bffcb2de925a093796b3b9907ff Mon Sep 17 00:00:00 2001 From: Fabiano Rosas Date: Wed, 18 Oct 2023 16:27:41 -0300 Subject: [PATCH 0926/1077] tests/qtest: Don't print messages from query instances Now that we can query more than one binary, the "starting QEMU..." message can get a little noisy. Mute those messages unless we're running with --verbose. Only affects qtest_init() calls from within libqtest. The tests continue to output as usual. Reviewed-by: Juan Quintela Reviewed-by: Thomas Huth Signed-off-by: Fabiano Rosas Message-ID: <20231018192741.25885-13-farosas@suse.de> Signed-off-by: Juan Quintela --- tests/qtest/libqtest.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/tests/qtest/libqtest.c b/tests/qtest/libqtest.c index c843c41188..f33a210861 100644 --- a/tests/qtest/libqtest.c +++ b/tests/qtest/libqtest.c @@ -91,6 +91,7 @@ struct QTestState static GHookList abrt_hooks; static void (*sighandler_old)(int); +static bool silence_spawn_log; static int qtest_query_target_endianness(QTestState *s); @@ -405,7 +406,9 @@ static QTestState *G_GNUC_PRINTF(2, 3) qtest_spawn_qemu(const char *qemu_bin, qtest_add_abrt_handler(kill_qemu_hook_func, s); - g_test_message("starting QEMU: %s", command->str); + if (!silence_spawn_log) { + g_test_message("starting QEMU: %s", command->str); + } #ifndef _WIN32 s->qemu_pid = fork(); @@ -1508,6 +1511,8 @@ static struct MachInfo *qtest_get_machines(const char *var) return machines; } + silence_spawn_log = !g_test_verbose(); + qts = qtest_init_with_env(qemu_var, "-machine none"); response = qtest_qmp(qts, "{ 'execute': 'query-machines' }"); g_assert(response); @@ -1539,6 +1544,8 @@ static struct MachInfo *qtest_get_machines(const char *var) qtest_quit(qts); qobject_unref(response); + silence_spawn_log = false; + memset(&machines[idx], 0, sizeof(struct MachInfo)); /* Terminating entry */ return machines; } From 8993351412de6a0b5e17b725141bfd8cb35c9e65 Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Fri, 20 Oct 2023 08:21:42 +0200 Subject: [PATCH 0927/1077] MAINTAINERS: Extend entry to cover util/qemu-timer-common.c, too MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We already cover util/qemu-timer.c in MAINTAINERS - change this entry to util/qemu-timer*.c so that it covers util/qemu-timer-common.c, too. Signed-off-by: Thomas Huth Reviewed-by: Philippe Mathieu-Daudé Message-ID: <20231020062142.525405-1-thuth@redhat.com> Signed-off-by: Philippe Mathieu-Daudé --- MAINTAINERS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MAINTAINERS b/MAINTAINERS index fe11c98669..1b2c5b9e76 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -2937,7 +2937,7 @@ F: include/qemu/main-loop.h F: include/sysemu/runstate.h F: include/sysemu/runstate-action.h F: util/main-loop.c -F: util/qemu-timer.c +F: util/qemu-timer*.c F: system/vl.c F: system/main.c F: system/cpus.c From 401766e043f25fd7cef111c53d701a2fc95d249f Mon Sep 17 00:00:00 2001 From: Akihiko Odaki Date: Thu, 5 Oct 2023 15:47:25 +0900 Subject: [PATCH 0928/1077] cutils: Fix get_relocated_path on Windows MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit get_relocated_path() did not have error handling for PathCchSkipRoot() because a path given to get_relocated_path() was expected to be a valid path containing a drive letter or UNC server/share path elements on Windows, but sometimes it turned out otherwise. The paths passed to get_relocated_path() are defined by macros generated by Meson. Meson in turn uses a prefix given by the configure script to generate them. For Windows, the script passes /qemu as a prefix to Meson by default. As documented in docs/about/build-platforms.rst, typically MSYS2 is used for the build system, but it is also possible to use Linux as well. When MSYS2 is used, its Bash variant recognizes /qemu as a MSYS2 path, and converts it to a Windows path, adding the MSYS2 prefix including a drive letter or UNC server/share path elements. Such a conversion does not happen on a shell on Linux however, and /qemu will be passed as is in the case. Implement a proper error handling of PathCchSkipRoot() in get_relocated_path() so that it can handle a path without a drive letter or UNC server/share path elements. Reported-by: Stefan Weil Signed-off-by: Akihiko Odaki Reviewed-by: Philippe Mathieu-Daudé Message-ID: <20231005064726.6945-1-akihiko.odaki@daynix.com> Signed-off-by: Philippe Mathieu-Daudé --- util/cutils.c | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/util/cutils.c b/util/cutils.c index 64f817b477..42364039a5 100644 --- a/util/cutils.c +++ b/util/cutils.c @@ -1163,17 +1163,21 @@ char *get_relocated_path(const char *dir) g_string_append(result, "/qemu-bundle"); if (access(result->str, R_OK) == 0) { #ifdef G_OS_WIN32 - size_t size = mbsrtowcs(NULL, &dir, 0, &(mbstate_t){0}) + 1; + const char *src = dir; + size_t size = mbsrtowcs(NULL, &src, 0, &(mbstate_t){0}) + 1; PWSTR wdir = g_new(WCHAR, size); - mbsrtowcs(wdir, &dir, size, &(mbstate_t){0}); + mbsrtowcs(wdir, &src, size, &(mbstate_t){0}); PCWSTR wdir_skipped_root; - PathCchSkipRoot(wdir, &wdir_skipped_root); + if (PathCchSkipRoot(wdir, &wdir_skipped_root) == S_OK) { + size = wcsrtombs(NULL, &wdir_skipped_root, 0, &(mbstate_t){0}); + char *cursor = result->str + result->len; + g_string_set_size(result, result->len + size); + wcsrtombs(cursor, &wdir_skipped_root, size + 1, &(mbstate_t){0}); + } else { + g_string_append(result, dir); + } - size = wcsrtombs(NULL, &wdir_skipped_root, 0, &(mbstate_t){0}); - char *cursor = result->str + result->len; - g_string_set_size(result, result->len + size); - wcsrtombs(cursor, &wdir_skipped_root, size + 1, &(mbstate_t){0}); g_free(wdir); #else g_string_append(result, dir); From d3b88b9cf6872b4dd9dcc39efefbe6d937d04057 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Mon, 9 Oct 2023 08:51:29 +0200 Subject: [PATCH 0929/1077] buildsys: Only display Objective-C information when Objective-C is used MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When configuring with '--disable-cocoa --disable-coreaudio' on Darwin, we get: meson.build:4081:58: ERROR: Tried to access compiler for language "objc", not specified for host machine. meson.build:4097:47: ERROR: Tried to access unknown option 'objc_args'. Instead of unconditionally display Objective-C informations on Darwin, display them when Objective-C is discovered. Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Akihiko Odaki Message-Id: <20231009093812.52915-1-philmd@linaro.org> --- meson.build | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/meson.build b/meson.build index 259dc5f308..4961c82a6b 100644 --- a/meson.build +++ b/meson.build @@ -4087,8 +4087,10 @@ if 'cpp' in all_languages else summary_info += {'C++ compiler': false} endif -if targetos == 'darwin' +if 'objc' in all_languages summary_info += {'Objective-C compiler': ' '.join(meson.get_compiler('objc').cmd_array())} +else + summary_info += {'Objective-C compiler': false} endif option_cflags = (get_option('debug') ? ['-g'] : []) if get_option('optimization') != 'plain' @@ -4098,7 +4100,7 @@ summary_info += {'CFLAGS': ' '.join(get_option('c_args') + option_cfl if 'cpp' in all_languages summary_info += {'CXXFLAGS': ' '.join(get_option('cpp_args') + option_cflags)} endif -if targetos == 'darwin' +if 'objc' in all_languages summary_info += {'OBJCFLAGS': ' '.join(get_option('objc_args') + option_cflags)} endif link_args = get_option('c_link_args') From 85f3d509b2bed0d9d994fca70ebd3be010fca72b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= Date: Mon, 9 Oct 2023 11:52:31 +0400 Subject: [PATCH 0930/1077] memory: drop needless argument MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The argument is unused since commit bdc44640c ("cpu: Use QTAILQ for CPU list"). Signed-off-by: Marc-André Lureau Reviewed-by: David Hildenbrand Reviewed-by: Philippe Mathieu-Daudé Message-ID: <20231009075231.150568-1-marcandre.lureau@redhat.com> Signed-off-by: Philippe Mathieu-Daudé --- system/memory_mapping.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/system/memory_mapping.c b/system/memory_mapping.c index d7f1d096e0..8ba9968f8c 100644 --- a/system/memory_mapping.c +++ b/system/memory_mapping.c @@ -291,7 +291,7 @@ void guest_phys_blocks_append(GuestPhysBlockList *list) memory_listener_unregister(&g.listener); } -static CPUState *find_paging_enabled_cpu(CPUState *start_cpu) +static CPUState *find_paging_enabled_cpu(void) { CPUState *cpu; @@ -312,7 +312,7 @@ void qemu_get_guest_memory_mapping(MemoryMappingList *list, GuestPhysBlock *block; ram_addr_t offset, length; - first_paging_enabled_cpu = find_paging_enabled_cpu(first_cpu); + first_paging_enabled_cpu = find_paging_enabled_cpu(); if (first_paging_enabled_cpu) { for (cpu = first_paging_enabled_cpu; cpu != NULL; cpu = CPU_NEXT(cpu)) { From 1ff5f4d29456387eca09b171e3a46ffefa015733 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= Date: Mon, 9 Oct 2023 11:53:10 +0400 Subject: [PATCH 0931/1077] memory: follow Error API guidelines MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Return true/false on success/failure. Signed-off-by: Marc-André Lureau Reviewed-by: David Hildenbrand Reviewed-by: Philippe Mathieu-Daudé Message-ID: <20231009075310.153617-1-marcandre.lureau@redhat.com> Signed-off-by: Philippe Mathieu-Daudé --- hw/core/cpu-sysemu.c | 6 +++--- include/hw/core/cpu.h | 4 +++- include/hw/core/sysemu-cpu-ops.h | 2 +- include/sysemu/memory_mapping.h | 2 +- system/memory_mapping.c | 13 ++++++------- target/i386/arch_memory_mapping.c | 6 ++++-- target/i386/cpu.h | 2 +- 7 files changed, 19 insertions(+), 16 deletions(-) diff --git a/hw/core/cpu-sysemu.c b/hw/core/cpu-sysemu.c index 5eaf2e79e6..d0d6a910f9 100644 --- a/hw/core/cpu-sysemu.c +++ b/hw/core/cpu-sysemu.c @@ -34,17 +34,17 @@ bool cpu_paging_enabled(const CPUState *cpu) return false; } -void cpu_get_memory_mapping(CPUState *cpu, MemoryMappingList *list, +bool cpu_get_memory_mapping(CPUState *cpu, MemoryMappingList *list, Error **errp) { CPUClass *cc = CPU_GET_CLASS(cpu); if (cc->sysemu_ops->get_memory_mapping) { - cc->sysemu_ops->get_memory_mapping(cpu, list, errp); - return; + return cc->sysemu_ops->get_memory_mapping(cpu, list, errp); } error_setg(errp, "Obtaining memory mappings is unsupported on this CPU."); + return false; } hwaddr cpu_get_phys_page_attrs_debug(CPUState *cpu, vaddr addr, diff --git a/include/hw/core/cpu.h b/include/hw/core/cpu.h index 3968369554..18593db5b2 100644 --- a/include/hw/core/cpu.h +++ b/include/hw/core/cpu.h @@ -618,8 +618,10 @@ bool cpu_paging_enabled(const CPUState *cpu); * @cpu: The CPU whose memory mappings are to be obtained. * @list: Where to write the memory mappings to. * @errp: Pointer for reporting an #Error. + * + * Returns: %true on success, %false otherwise. */ -void cpu_get_memory_mapping(CPUState *cpu, MemoryMappingList *list, +bool cpu_get_memory_mapping(CPUState *cpu, MemoryMappingList *list, Error **errp); #if !defined(CONFIG_USER_ONLY) diff --git a/include/hw/core/sysemu-cpu-ops.h b/include/hw/core/sysemu-cpu-ops.h index ee169b872c..24d003fe04 100644 --- a/include/hw/core/sysemu-cpu-ops.h +++ b/include/hw/core/sysemu-cpu-ops.h @@ -19,7 +19,7 @@ typedef struct SysemuCPUOps { /** * @get_memory_mapping: Callback for obtaining the memory mappings. */ - void (*get_memory_mapping)(CPUState *cpu, MemoryMappingList *list, + bool (*get_memory_mapping)(CPUState *cpu, MemoryMappingList *list, Error **errp); /** * @get_paging_enabled: Callback for inquiring whether paging is enabled. diff --git a/include/sysemu/memory_mapping.h b/include/sysemu/memory_mapping.h index 3bbeb1bcb4..021e0a6230 100644 --- a/include/sysemu/memory_mapping.h +++ b/include/sysemu/memory_mapping.h @@ -71,7 +71,7 @@ void guest_phys_blocks_free(GuestPhysBlockList *list); void guest_phys_blocks_init(GuestPhysBlockList *list); void guest_phys_blocks_append(GuestPhysBlockList *list); -void qemu_get_guest_memory_mapping(MemoryMappingList *list, +bool qemu_get_guest_memory_mapping(MemoryMappingList *list, const GuestPhysBlockList *guest_phys_blocks, Error **errp); diff --git a/system/memory_mapping.c b/system/memory_mapping.c index 8ba9968f8c..6f884c5b90 100644 --- a/system/memory_mapping.c +++ b/system/memory_mapping.c @@ -304,10 +304,11 @@ static CPUState *find_paging_enabled_cpu(void) return NULL; } -void qemu_get_guest_memory_mapping(MemoryMappingList *list, +bool qemu_get_guest_memory_mapping(MemoryMappingList *list, const GuestPhysBlockList *guest_phys_blocks, Error **errp) { + ERRP_GUARD(); CPUState *cpu, *first_paging_enabled_cpu; GuestPhysBlock *block; ram_addr_t offset, length; @@ -316,14 +317,11 @@ void qemu_get_guest_memory_mapping(MemoryMappingList *list, if (first_paging_enabled_cpu) { for (cpu = first_paging_enabled_cpu; cpu != NULL; cpu = CPU_NEXT(cpu)) { - Error *err = NULL; - cpu_get_memory_mapping(cpu, list, &err); - if (err) { - error_propagate(errp, err); - return; + if (!cpu_get_memory_mapping(cpu, list, errp)) { + return false; } } - return; + return true; } /* @@ -335,6 +333,7 @@ void qemu_get_guest_memory_mapping(MemoryMappingList *list, length = block->target_end - block->target_start; create_new_memory_mapping(list, offset, offset, length); } + return true; } void qemu_get_guest_simple_memory_mapping(MemoryMappingList *list, diff --git a/target/i386/arch_memory_mapping.c b/target/i386/arch_memory_mapping.c index 271cb5e41b..d1ff659128 100644 --- a/target/i386/arch_memory_mapping.c +++ b/target/i386/arch_memory_mapping.c @@ -266,7 +266,7 @@ static void walk_pml5e(MemoryMappingList *list, AddressSpace *as, } #endif -void x86_cpu_get_memory_mapping(CPUState *cs, MemoryMappingList *list, +bool x86_cpu_get_memory_mapping(CPUState *cs, MemoryMappingList *list, Error **errp) { X86CPU *cpu = X86_CPU(cs); @@ -275,7 +275,7 @@ void x86_cpu_get_memory_mapping(CPUState *cs, MemoryMappingList *list, if (!cpu_paging_enabled(cs)) { /* paging is disabled */ - return; + return true; } a20_mask = x86_get_a20_mask(env); @@ -310,5 +310,7 @@ void x86_cpu_get_memory_mapping(CPUState *cs, MemoryMappingList *list, pse = !!(env->cr[4] & CR4_PSE_MASK); walk_pde2(list, cs->as, pde_addr, a20_mask, pse); } + + return true; } diff --git a/target/i386/cpu.h b/target/i386/cpu.h index e1875466b9..471e71dbc5 100644 --- a/target/i386/cpu.h +++ b/target/i386/cpu.h @@ -2055,7 +2055,7 @@ int x86_cpu_write_elf64_qemunote(WriteCoreDumpFunction f, CPUState *cpu, int x86_cpu_write_elf32_qemunote(WriteCoreDumpFunction f, CPUState *cpu, DumpState *s); -void x86_cpu_get_memory_mapping(CPUState *cpu, MemoryMappingList *list, +bool x86_cpu_get_memory_mapping(CPUState *cpu, MemoryMappingList *list, Error **errp); void x86_cpu_dump_state(CPUState *cs, FILE *f, int flags); From ae5f70baf549925080fcdbc6c1939c98a4a39246 Mon Sep 17 00:00:00 2001 From: Lu Gao Date: Mon, 21 Mar 2022 13:56:18 +0800 Subject: [PATCH 0932/1077] hw/sd/sdhci: Block Size Register bits [14:12] is lost MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Block Size Register bits [14:12] is SDMA Buffer Boundary, it is missed in register write, but it is needed in SDMA transfer. e.g. it will be used in sdhci_sdma_transfer_multi_blocks to calculate boundary_ variables. Missing this field will cause wrong operation for different SDMA Buffer Boundary settings. Fixes: d7dfca0807 ("hw/sdhci: introduce standard SD host controller") Fixes: dfba99f17f ("hw/sdhci: Fix DMA Transfer Block Size field") Signed-off-by: Lu Gao Signed-off-by: Jianxian Wen Reviewed-by: Philippe Mathieu-Daudé Message-ID: <20220321055618.4026-1-lu.gao@verisilicon.com> Signed-off-by: Philippe Mathieu-Daudé --- hw/sd/sdhci.c | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/hw/sd/sdhci.c b/hw/sd/sdhci.c index 5564765a9b..40473b0db0 100644 --- a/hw/sd/sdhci.c +++ b/hw/sd/sdhci.c @@ -321,6 +321,8 @@ static void sdhci_poweron_reset(DeviceState *dev) static void sdhci_data_transfer(void *opaque); +#define BLOCK_SIZE_MASK (4 * KiB - 1) + static void sdhci_send_command(SDHCIState *s) { SDRequest request; @@ -371,7 +373,8 @@ static void sdhci_send_command(SDHCIState *s) sdhci_update_irq(s); - if (!timeout && s->blksize && (s->cmdreg & SDHC_CMD_DATA_PRESENT)) { + if (!timeout && (s->blksize & BLOCK_SIZE_MASK) && + (s->cmdreg & SDHC_CMD_DATA_PRESENT)) { s->data_count = 0; sdhci_data_transfer(s); } @@ -406,7 +409,6 @@ static void sdhci_end_transfer(SDHCIState *s) /* * Programmed i/o data transfer */ -#define BLOCK_SIZE_MASK (4 * KiB - 1) /* Fill host controller's read buffer with BLKSIZE bytes of data from card */ static void sdhci_read_block_from_card(SDHCIState *s) @@ -1154,7 +1156,8 @@ sdhci_write(void *opaque, hwaddr offset, uint64_t val, unsigned size) s->sdmasysad = (s->sdmasysad & mask) | value; MASKED_WRITE(s->sdmasysad, mask, value); /* Writing to last byte of sdmasysad might trigger transfer */ - if (!(mask & 0xFF000000) && s->blkcnt && s->blksize && + if (!(mask & 0xFF000000) && s->blkcnt && + (s->blksize & BLOCK_SIZE_MASK) && SDHC_DMA_TYPE(s->hostctl1) == SDHC_CTRL_SDMA) { if (s->trnmod & SDHC_TRNS_MULTI) { sdhci_sdma_transfer_multi_blocks(s); @@ -1168,7 +1171,11 @@ sdhci_write(void *opaque, hwaddr offset, uint64_t val, unsigned size) if (!TRANSFERRING_DATA(s->prnsts)) { uint16_t blksize = s->blksize; - MASKED_WRITE(s->blksize, mask, extract32(value, 0, 12)); + /* + * [14:12] SDMA Buffer Boundary + * [11:00] Transfer Block Size + */ + MASKED_WRITE(s->blksize, mask, extract32(value, 0, 15)); MASKED_WRITE(s->blkcnt, mask >> 16, value >> 16); /* Limit block size to the maximum buffer size */ From faf026b2a22da1044baf7f1f3ab1280b2a448399 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Mon, 9 Oct 2023 10:21:22 +0200 Subject: [PATCH 0933/1077] hw/mips/malta: Use sdram_type enum from 'hw/i2c/smbus_eeprom.h' MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Since commit 93198b6cad ("i2c: Split smbus into parts") the SDRAM types are enumerated as sdram_type in "hw/i2c/smbus_eeprom.h". Using the enum removes this global shadow warning: hw/mips/malta.c:209:12: error: declaration shadows a variable in the global scope [-Werror,-Wshadow] enum { SDR = 0x4, DDR2 = 0x8 } type; ^ include/hw/i2c/smbus_eeprom.h:33:19: note: previous declaration is here enum sdram_type { SDR = 0x4, DDR = 0x7, DDR2 = 0x8 }; ^ Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: BALATON Zoltan Reviewed-by: Richard Henderson Message-Id: <20231009092127.49778-1-philmd@linaro.org> --- hw/mips/malta.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/mips/malta.c b/hw/mips/malta.c index dac27fad9d..62d04ed113 100644 --- a/hw/mips/malta.c +++ b/hw/mips/malta.c @@ -206,7 +206,7 @@ static eeprom24c0x_t spd_eeprom = { static void generate_eeprom_spd(uint8_t *eeprom, ram_addr_t ram_size) { - enum { SDR = 0x4, DDR2 = 0x8 } type; + enum sdram_type type; uint8_t *spd = spd_eeprom.contents; uint8_t nbanks = 0; uint16_t density = 0; From 2d4651641f611d2a4b5457ec25e39f2a0de953b4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Mon, 9 Oct 2023 13:58:39 +0200 Subject: [PATCH 0934/1077] hw/mips: Merge 'hw/mips/cpudevs.h' with 'target/mips/cpu.h' MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit "hw/mips/cpudevs.h" contains declarations which are specific to the MIPS architecture; it doesn't make sense for these to be called from a non-MIPS architecture. Move the declarations to "target/mips/cpu.h". Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Richard Henderson Message-Id: <20231009171443.12145-2-philmd@linaro.org> --- hw/mips/cps.c | 1 - hw/mips/fuloong2e.c | 1 - hw/mips/jazz.c | 1 - hw/mips/loongson3_virt.c | 1 - hw/mips/malta.c | 1 - hw/mips/mips_int.c | 1 - hw/mips/mipssim.c | 1 - include/hw/mips/cpudevs.h | 14 -------------- target/mips/cpu.h | 4 +++- target/mips/sysemu/cp0_timer.c | 1 - target/mips/tcg/sysemu/tlb_helper.c | 1 - 11 files changed, 3 insertions(+), 24 deletions(-) delete mode 100644 include/hw/mips/cpudevs.h diff --git a/hw/mips/cps.c b/hw/mips/cps.c index 2b5269ebf1..b6612c1762 100644 --- a/hw/mips/cps.c +++ b/hw/mips/cps.c @@ -24,7 +24,6 @@ #include "hw/mips/mips.h" #include "hw/qdev-clock.h" #include "hw/qdev-properties.h" -#include "hw/mips/cpudevs.h" #include "sysemu/kvm.h" #include "sysemu/reset.h" diff --git a/hw/mips/fuloong2e.c b/hw/mips/fuloong2e.c index c6109633fe..97b2c8ed8e 100644 --- a/hw/mips/fuloong2e.c +++ b/hw/mips/fuloong2e.c @@ -30,7 +30,6 @@ #include "hw/block/flash.h" #include "hw/mips/mips.h" #include "hw/mips/bootloader.h" -#include "hw/mips/cpudevs.h" #include "hw/pci/pci.h" #include "hw/loader.h" #include "hw/ide/pci.h" diff --git a/hw/mips/jazz.c b/hw/mips/jazz.c index c32d2b0b0a..86dfe05ea8 100644 --- a/hw/mips/jazz.c +++ b/hw/mips/jazz.c @@ -26,7 +26,6 @@ #include "qemu/datadir.h" #include "hw/clock.h" #include "hw/mips/mips.h" -#include "hw/mips/cpudevs.h" #include "hw/intc/i8259.h" #include "hw/dma/i8257.h" #include "hw/char/serial.h" diff --git a/hw/mips/loongson3_virt.c b/hw/mips/loongson3_virt.c index b74b358874..33eae01eca 100644 --- a/hw/mips/loongson3_virt.c +++ b/hw/mips/loongson3_virt.c @@ -32,7 +32,6 @@ #include "hw/char/serial.h" #include "hw/intc/loongson_liointc.h" #include "hw/mips/mips.h" -#include "hw/mips/cpudevs.h" #include "hw/mips/fw_cfg.h" #include "hw/mips/loongson3_bootp.h" #include "hw/misc/unimp.h" diff --git a/hw/mips/malta.c b/hw/mips/malta.c index 62d04ed113..4fa5b33fd9 100644 --- a/hw/mips/malta.c +++ b/hw/mips/malta.c @@ -37,7 +37,6 @@ #include "hw/block/flash.h" #include "hw/mips/mips.h" #include "hw/mips/bootloader.h" -#include "hw/mips/cpudevs.h" #include "hw/pci/pci.h" #include "hw/pci/pci_bus.h" #include "qemu/log.h" diff --git a/hw/mips/mips_int.c b/hw/mips/mips_int.c index 73437cd90f..6c32e466a3 100644 --- a/hw/mips/mips_int.c +++ b/hw/mips/mips_int.c @@ -23,7 +23,6 @@ #include "qemu/osdep.h" #include "qemu/main-loop.h" #include "hw/irq.h" -#include "hw/mips/cpudevs.h" #include "sysemu/kvm.h" #include "kvm_mips.h" diff --git a/hw/mips/mipssim.c b/hw/mips/mipssim.c index 2f951f7fc6..4f743f37eb 100644 --- a/hw/mips/mipssim.c +++ b/hw/mips/mipssim.c @@ -30,7 +30,6 @@ #include "qemu/datadir.h" #include "hw/clock.h" #include "hw/mips/mips.h" -#include "hw/mips/cpudevs.h" #include "hw/char/serial.h" #include "hw/isa/isa.h" #include "net/net.h" diff --git a/include/hw/mips/cpudevs.h b/include/hw/mips/cpudevs.h deleted file mode 100644 index f7c9728fa9..0000000000 --- a/include/hw/mips/cpudevs.h +++ /dev/null @@ -1,14 +0,0 @@ -#ifndef HW_MIPS_CPUDEVS_H -#define HW_MIPS_CPUDEVS_H - -#include "target/mips/cpu-qom.h" - -/* Definitions for MIPS CPU internal devices. */ - -/* mips_int.c */ -void cpu_mips_irq_init_cpu(MIPSCPU *cpu); - -/* mips_timer.c */ -void cpu_mips_clock_init(MIPSCPU *cpu); - -#endif diff --git a/target/mips/cpu.h b/target/mips/cpu.h index 67f8e8b988..fb44defc93 100644 --- a/target/mips/cpu.h +++ b/target/mips/cpu.h @@ -1345,8 +1345,10 @@ uint64_t cpu_mips_phys_to_kseg1(void *opaque, uint64_t addr); #if !defined(CONFIG_USER_ONLY) -/* mips_int.c */ +/* HW declaration specific to the MIPS target */ void cpu_mips_soft_irq(CPUMIPSState *env, int irq, int level); +void cpu_mips_irq_init_cpu(MIPSCPU *cpu); +void cpu_mips_clock_init(MIPSCPU *cpu); /* mips_itu.c */ void itc_reconfigure(struct MIPSITUState *tag); diff --git a/target/mips/sysemu/cp0_timer.c b/target/mips/sysemu/cp0_timer.c index 9d2bcb0dea..62de502caa 100644 --- a/target/mips/sysemu/cp0_timer.c +++ b/target/mips/sysemu/cp0_timer.c @@ -22,7 +22,6 @@ #include "qemu/osdep.h" #include "hw/irq.h" -#include "hw/mips/cpudevs.h" #include "qemu/timer.h" #include "sysemu/kvm.h" #include "internal.h" diff --git a/target/mips/tcg/sysemu/tlb_helper.c b/target/mips/tcg/sysemu/tlb_helper.c index 7dbc2e24c4..4ede904800 100644 --- a/target/mips/tcg/sysemu/tlb_helper.c +++ b/target/mips/tcg/sysemu/tlb_helper.c @@ -24,7 +24,6 @@ #include "exec/exec-all.h" #include "exec/cpu_ldst.h" #include "exec/log.h" -#include "hw/mips/cpudevs.h" #include "exec/helper-proto.h" /* TLB management */ From 43e61fc8953bc2e40c3549368b2600787fbd53a9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Fri, 6 Oct 2023 09:15:34 +0200 Subject: [PATCH 0935/1077] hw/misc/mips_itu: Declare itc_reconfigure() in 'hw/misc/mips_itu.h' MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We already provide "hw/misc/mips_itu.h" to declare prototype related to MIPSITUState. Move itc_reconfigure() declaration there. Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Richard Henderson Message-Id: <20231009171443.12145-3-philmd@linaro.org> --- include/hw/misc/mips_itu.h | 2 ++ target/mips/cpu.h | 3 --- target/mips/tcg/sysemu/cp0_helper.c | 1 + 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/include/hw/misc/mips_itu.h b/include/hw/misc/mips_itu.h index 35218b2d14..a413789151 100644 --- a/include/hw/misc/mips_itu.h +++ b/include/hw/misc/mips_itu.h @@ -79,4 +79,6 @@ struct MIPSITUState { /* Get ITC Configuration Tag memory region. */ MemoryRegion *mips_itu_get_tag_region(MIPSITUState *itu); +void itc_reconfigure(struct MIPSITUState *tag); + #endif /* MIPS_ITU_H */ diff --git a/target/mips/cpu.h b/target/mips/cpu.h index fb44defc93..5fddceff3a 100644 --- a/target/mips/cpu.h +++ b/target/mips/cpu.h @@ -1350,9 +1350,6 @@ void cpu_mips_soft_irq(CPUMIPSState *env, int irq, int level); void cpu_mips_irq_init_cpu(MIPSCPU *cpu); void cpu_mips_clock_init(MIPSCPU *cpu); -/* mips_itu.c */ -void itc_reconfigure(struct MIPSITUState *tag); - #endif /* !CONFIG_USER_ONLY */ /* helper.c */ diff --git a/target/mips/tcg/sysemu/cp0_helper.c b/target/mips/tcg/sysemu/cp0_helper.c index 5da1124589..d349548743 100644 --- a/target/mips/tcg/sysemu/cp0_helper.c +++ b/target/mips/tcg/sysemu/cp0_helper.c @@ -28,6 +28,7 @@ #include "qemu/host-utils.h" #include "exec/helper-proto.h" #include "exec/exec-all.h" +#include "hw/misc/mips_itu.h" /* SMP helpers. */ From 454c1e1dd834b992f4021607f84e85ed9cccb26c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Mon, 18 Sep 2023 07:25:49 +0200 Subject: [PATCH 0936/1077] hw/misc/mips_itu: Make MIPSITUState target agnostic MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When prototyping a heterogenous machine including the ITU, we get: include/hw/misc/mips_itu.h:76:5: error: unknown type name 'MIPSCPU' MIPSCPU *cpu0; ^ MIPSCPU is declared in the target specific "cpu.h" header, but we don't want to include it, because "cpu.h" is target specific and its inclusion taints all files including "mips_itu.h", which become target specific too. We can however use the 'ArchCPU *' type in the public header. By keeping the TYPE_MIPS_CPU QOM type check in the link property declaration, QOM core code will still check the property is a correct MIPS CPU. TYPE_MIPS_ITU is still built per-(MIPS)target, but its header can now be included by other targets. Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Richard Henderson Message-Id: <20231009171443.12145-4-philmd@linaro.org> --- hw/misc/mips_itu.c | 4 ++-- include/hw/misc/mips_itu.h | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/hw/misc/mips_itu.c b/hw/misc/mips_itu.c index 0eda302db4..5a83ccc4e8 100644 --- a/hw/misc/mips_itu.c +++ b/hw/misc/mips_itu.c @@ -532,7 +532,7 @@ static void mips_itu_realize(DeviceState *dev, Error **errp) return; } - env = &s->cpu0->env; + env = &MIPS_CPU(s->cpu0)->env; if (env->saarp) { s->saar = env->CP0_SAAR; } @@ -563,7 +563,7 @@ static Property mips_itu_properties[] = { ITC_FIFO_NUM_MAX), DEFINE_PROP_UINT32("num-semaphores", MIPSITUState, num_semaphores, ITC_SEMAPH_NUM_MAX), - DEFINE_PROP_LINK("cpu[0]", MIPSITUState, cpu0, TYPE_MIPS_CPU, MIPSCPU *), + DEFINE_PROP_LINK("cpu[0]", MIPSITUState, cpu0, TYPE_MIPS_CPU, ArchCPU *), DEFINE_PROP_END_OF_LIST(), }; diff --git a/include/hw/misc/mips_itu.h b/include/hw/misc/mips_itu.h index a413789151..5caed6cc36 100644 --- a/include/hw/misc/mips_itu.h +++ b/include/hw/misc/mips_itu.h @@ -73,7 +73,7 @@ struct MIPSITUState { /* SAAR */ uint64_t *saar; - MIPSCPU *cpu0; + ArchCPU *cpu0; }; /* Get ITC Configuration Tag memory region. */ From f30c755f0cefbf2e3100a6ecc1b45c2460b3bbd5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Thu, 12 Oct 2023 04:51:12 +0200 Subject: [PATCH 0937/1077] hw/pci-host/sh_pcic: Declare CPU QOM types using DEFINE_TYPES() macro MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When multiple QOM types are registered in the same file, it is simpler to use the the DEFINE_TYPES() macro. In particular because type array declared with such macro are easier to review. Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Yoshinori Sato Message-Id: <20231012041237.22281-2-philmd@linaro.org> --- hw/pci-host/sh_pci.c | 40 +++++++++++++++++----------------------- 1 file changed, 17 insertions(+), 23 deletions(-) diff --git a/hw/pci-host/sh_pci.c b/hw/pci-host/sh_pci.c index 77e7bbc65f..41aed48c85 100644 --- a/hw/pci-host/sh_pci.c +++ b/hw/pci-host/sh_pci.c @@ -167,17 +167,6 @@ static void sh_pci_host_class_init(ObjectClass *klass, void *data) dc->user_creatable = false; } -static const TypeInfo sh_pci_host_info = { - .name = "sh_pci_host", - .parent = TYPE_PCI_DEVICE, - .instance_size = sizeof(PCIDevice), - .class_init = sh_pci_host_class_init, - .interfaces = (InterfaceInfo[]) { - { INTERFACE_CONVENTIONAL_PCI_DEVICE }, - { }, - }, -}; - static void sh_pci_device_class_init(ObjectClass *klass, void *data) { DeviceClass *dc = DEVICE_CLASS(klass); @@ -185,17 +174,22 @@ static void sh_pci_device_class_init(ObjectClass *klass, void *data) dc->realize = sh_pci_device_realize; } -static const TypeInfo sh_pci_device_info = { - .name = TYPE_SH_PCI_HOST_BRIDGE, - .parent = TYPE_PCI_HOST_BRIDGE, - .instance_size = sizeof(SHPCIState), - .class_init = sh_pci_device_class_init, +static const TypeInfo sh_pcic_types[] = { + { + .name = TYPE_SH_PCI_HOST_BRIDGE, + .parent = TYPE_PCI_HOST_BRIDGE, + .instance_size = sizeof(SHPCIState), + .class_init = sh_pci_device_class_init, + }, { + .name = "sh_pci_host", + .parent = TYPE_PCI_DEVICE, + .instance_size = sizeof(PCIDevice), + .class_init = sh_pci_host_class_init, + .interfaces = (InterfaceInfo[]) { + { INTERFACE_CONVENTIONAL_PCI_DEVICE }, + { }, + }, + }, }; -static void sh_pci_register_types(void) -{ - type_register_static(&sh_pci_device_info); - type_register_static(&sh_pci_host_info); -} - -type_init(sh_pci_register_types) +DEFINE_TYPES(sh_pcic_types) From 701fed594577b17b27542a6f278c2babb20b3ba6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Thu, 12 Oct 2023 04:53:19 +0200 Subject: [PATCH 0938/1077] hw/pci-host/sh_pcic: Correct PCI host / devfn#0 function names MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Host bridge device and PCI function #0 are inverted. Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Yoshinori Sato Message-Id: <20231012041237.22281-3-philmd@linaro.org> --- hw/pci-host/sh_pci.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/hw/pci-host/sh_pci.c b/hw/pci-host/sh_pci.c index 41aed48c85..580e273d96 100644 --- a/hw/pci-host/sh_pci.c +++ b/hw/pci-host/sh_pci.c @@ -116,7 +116,7 @@ static void sh_pci_set_irq(void *opaque, int irq_num, int level) qemu_set_irq(pic[irq_num], level); } -static void sh_pci_device_realize(DeviceState *dev, Error **errp) +static void sh_pcic_host_realize(DeviceState *dev, Error **errp) { SysBusDevice *sbd = SYS_BUS_DEVICE(dev); SHPCIState *s = SH_PCI_HOST_BRIDGE(dev); @@ -145,19 +145,19 @@ static void sh_pci_device_realize(DeviceState *dev, Error **errp) s->dev = pci_create_simple(phb->bus, PCI_DEVFN(0, 0), "sh_pci_host"); } -static void sh_pci_host_realize(PCIDevice *d, Error **errp) +static void sh_pcic_pci_realize(PCIDevice *d, Error **errp) { pci_set_word(d->config + PCI_COMMAND, PCI_COMMAND_WAIT); pci_set_word(d->config + PCI_STATUS, PCI_STATUS_CAP_LIST | PCI_STATUS_FAST_BACK | PCI_STATUS_DEVSEL_MEDIUM); } -static void sh_pci_host_class_init(ObjectClass *klass, void *data) +static void sh_pcic_pci_class_init(ObjectClass *klass, void *data) { PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); DeviceClass *dc = DEVICE_CLASS(klass); - k->realize = sh_pci_host_realize; + k->realize = sh_pcic_pci_realize; k->vendor_id = PCI_VENDOR_ID_HITACHI; k->device_id = PCI_DEVICE_ID_HITACHI_SH7751R; /* @@ -167,11 +167,11 @@ static void sh_pci_host_class_init(ObjectClass *klass, void *data) dc->user_creatable = false; } -static void sh_pci_device_class_init(ObjectClass *klass, void *data) +static void sh_pcic_host_class_init(ObjectClass *klass, void *data) { DeviceClass *dc = DEVICE_CLASS(klass); - dc->realize = sh_pci_device_realize; + dc->realize = sh_pcic_host_realize; } static const TypeInfo sh_pcic_types[] = { @@ -179,12 +179,12 @@ static const TypeInfo sh_pcic_types[] = { .name = TYPE_SH_PCI_HOST_BRIDGE, .parent = TYPE_PCI_HOST_BRIDGE, .instance_size = sizeof(SHPCIState), - .class_init = sh_pci_device_class_init, + .class_init = sh_pcic_host_class_init, }, { .name = "sh_pci_host", .parent = TYPE_PCI_DEVICE, .instance_size = sizeof(PCIDevice), - .class_init = sh_pci_host_class_init, + .class_init = sh_pcic_pci_class_init, .interfaces = (InterfaceInfo[]) { { INTERFACE_CONVENTIONAL_PCI_DEVICE }, { }, From 191a1e14b95e6f1e23d6e31b3d2fdac875ed6a9e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Thu, 12 Oct 2023 04:56:17 +0200 Subject: [PATCH 0939/1077] hw/pci-host/sh_pcic: Replace magic value by proper definition MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Yoshinori Sato Message-Id: <20231012041237.22281-4-philmd@linaro.org> --- hw/pci-host/sh_pci.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/hw/pci-host/sh_pci.c b/hw/pci-host/sh_pci.c index 580e273d96..4edebced5e 100644 --- a/hw/pci-host/sh_pci.c +++ b/hw/pci-host/sh_pci.c @@ -40,7 +40,7 @@ struct SHPCIState { PCIHostState parent_obj; PCIDevice *dev; - qemu_irq irq[4]; + qemu_irq irq[PCI_NUM_PINS]; MemoryRegion memconfig_p4; MemoryRegion memconfig_a7; MemoryRegion isa; @@ -131,7 +131,8 @@ static void sh_pcic_host_realize(DeviceState *dev, Error **errp) s->irq, get_system_memory(), get_system_io(), - PCI_DEVFN(0, 0), 4, TYPE_PCI_BUS); + PCI_DEVFN(0, 0), PCI_NUM_PINS, + TYPE_PCI_BUS); memory_region_init_io(&s->memconfig_p4, OBJECT(s), &sh_pci_reg_ops, s, "sh_pci", 0x224); memory_region_init_alias(&s->memconfig_a7, OBJECT(s), "sh_pci.2", From 203713b581e6b1d5095a2703e41172b9f2211d66 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Wed, 11 Oct 2023 15:30:35 +0200 Subject: [PATCH 0940/1077] hw/sparc64/ebus: Access memory regions via pci_address_space_io() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit PCI functions are plugged on a PCI bus. They can only access external memory regions via the bus. Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Mark Cave-Ayland Message-Id: <20231011185954.10337-5-philmd@linaro.org> --- hw/sparc64/sun4u.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/hw/sparc64/sun4u.c b/hw/sparc64/sun4u.c index d908a38f73..c871170378 100644 --- a/hw/sparc64/sun4u.c +++ b/hw/sparc64/sun4u.c @@ -360,11 +360,11 @@ static void ebus_realize(PCIDevice *pci_dev, Error **errp) pci_dev->config[0x09] = 0x00; // programming i/f pci_dev->config[0x0D] = 0x0a; // latency_timer - memory_region_init_alias(&s->bar0, OBJECT(s), "bar0", get_system_io(), - 0, 0x1000000); + memory_region_init_alias(&s->bar0, OBJECT(s), "bar0", + pci_address_space_io(pci_dev), 0, 0x1000000); pci_register_bar(pci_dev, 0, PCI_BASE_ADDRESS_SPACE_MEMORY, &s->bar0); - memory_region_init_alias(&s->bar1, OBJECT(s), "bar1", get_system_io(), - 0, 0x8000); + memory_region_init_alias(&s->bar1, OBJECT(s), "bar1", + pci_address_space_io(pci_dev), 0, 0x8000); pci_register_bar(pci_dev, 1, PCI_BASE_ADDRESS_SPACE_IO, &s->bar1); } From 2277fbfde16582b76254f8bbbebfb969d0dbef3c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Mon, 9 Oct 2023 10:13:41 +0200 Subject: [PATCH 0941/1077] hw/acpi/pcihp: Clean up global variable shadowing in acpi_pcihp_init() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fix: hw/acpi/pcihp.c:499:36: error: declaration shadows a variable in the global scope [-Werror,-Wshadow] MemoryRegion *address_space_io, ^ include/exec/address-spaces.h:35:21: note: previous declaration is here extern AddressSpace address_space_io; ^ Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Ani Sinha Acked-by: Michael S. Tsirkin Message-Id: <20231010115048.11856-5-philmd@linaro.org> --- hw/acpi/pcihp.c | 5 ++--- include/hw/acpi/pcihp.h | 2 +- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/hw/acpi/pcihp.c b/hw/acpi/pcihp.c index cdd6f775a1..4f75c873e2 100644 --- a/hw/acpi/pcihp.c +++ b/hw/acpi/pcihp.c @@ -496,8 +496,7 @@ static const MemoryRegionOps acpi_pcihp_io_ops = { }; void acpi_pcihp_init(Object *owner, AcpiPciHpState *s, PCIBus *root_bus, - MemoryRegion *address_space_io, - uint16_t io_base) + MemoryRegion *io, uint16_t io_base) { s->io_len = ACPI_PCIHP_SIZE; s->io_base = io_base; @@ -506,7 +505,7 @@ void acpi_pcihp_init(Object *owner, AcpiPciHpState *s, PCIBus *root_bus, memory_region_init_io(&s->io, owner, &acpi_pcihp_io_ops, s, "acpi-pci-hotplug", s->io_len); - memory_region_add_subregion(address_space_io, s->io_base, &s->io); + memory_region_add_subregion(io, s->io_base, &s->io); object_property_add_uint16_ptr(owner, ACPI_PCIHP_IO_BASE_PROP, &s->io_base, OBJ_PROP_FLAG_READ); diff --git a/include/hw/acpi/pcihp.h b/include/hw/acpi/pcihp.h index ef59810c17..ac21a95913 100644 --- a/include/hw/acpi/pcihp.h +++ b/include/hw/acpi/pcihp.h @@ -56,7 +56,7 @@ typedef struct AcpiPciHpState { } AcpiPciHpState; void acpi_pcihp_init(Object *owner, AcpiPciHpState *, PCIBus *root, - MemoryRegion *address_space_io, uint16_t io_base); + MemoryRegion *io, uint16_t io_base); bool acpi_pcihp_is_hotpluggbale_bus(AcpiPciHpState *s, BusState *bus); void acpi_pcihp_device_pre_plug_cb(HotplugHandler *hotplug_dev, From a7e6186810f9389bb3aaa9209f548052651bc11d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Mon, 9 Oct 2023 09:33:29 +0200 Subject: [PATCH 0942/1077] hw/pci: Clean up global variable shadowing of address_space_io variable MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fix: hw/pci/pci.c:504:54: error: declaration shadows a variable in the global scope [-Werror,-Wshadow] MemoryRegion *address_space_io, ^ hw/pci/pci.c:533:38: error: declaration shadows a variable in the global scope [-Werror,-Wshadow] MemoryRegion *address_space_io, ^ hw/pci/pci.c:543:40: error: declaration shadows a variable in the global scope [-Werror,-Wshadow] MemoryRegion *address_space_io, ^ hw/pci/pci.c:590:45: error: declaration shadows a variable in the global scope [-Werror,-Wshadow] MemoryRegion *address_space_io, ^ include/exec/address-spaces.h:35:21: note: previous declaration is here extern AddressSpace address_space_io; ^ Signed-off-by: Philippe Mathieu-Daudé Acked-by: Michael S. Tsirkin Message-Id: <20231010115048.11856-6-philmd@linaro.org> --- hw/pci/pci.c | 25 +++++++++---------------- include/hw/pci/pci.h | 9 +++------ 2 files changed, 12 insertions(+), 22 deletions(-) diff --git a/hw/pci/pci.c b/hw/pci/pci.c index b0d21bf43a..7d09e1a39d 100644 --- a/hw/pci/pci.c +++ b/hw/pci/pci.c @@ -500,15 +500,14 @@ bool pci_bus_bypass_iommu(PCIBus *bus) } static void pci_root_bus_internal_init(PCIBus *bus, DeviceState *parent, - MemoryRegion *address_space_mem, - MemoryRegion *address_space_io, + MemoryRegion *mem, MemoryRegion *io, uint8_t devfn_min) { assert(PCI_FUNC(devfn_min) == 0); bus->devfn_min = devfn_min; bus->slot_reserved_mask = 0x0; - bus->address_space_mem = address_space_mem; - bus->address_space_io = address_space_io; + bus->address_space_mem = mem; + bus->address_space_io = io; bus->flags |= PCI_BUS_IS_ROOT; /* host bridge */ @@ -529,25 +528,21 @@ bool pci_bus_is_express(const PCIBus *bus) void pci_root_bus_init(PCIBus *bus, size_t bus_size, DeviceState *parent, const char *name, - MemoryRegion *address_space_mem, - MemoryRegion *address_space_io, + MemoryRegion *mem, MemoryRegion *io, uint8_t devfn_min, const char *typename) { qbus_init(bus, bus_size, typename, parent, name); - pci_root_bus_internal_init(bus, parent, address_space_mem, - address_space_io, devfn_min); + pci_root_bus_internal_init(bus, parent, mem, io, devfn_min); } PCIBus *pci_root_bus_new(DeviceState *parent, const char *name, - MemoryRegion *address_space_mem, - MemoryRegion *address_space_io, + MemoryRegion *mem, MemoryRegion *io, uint8_t devfn_min, const char *typename) { PCIBus *bus; bus = PCI_BUS(qbus_new(typename, parent, name)); - pci_root_bus_internal_init(bus, parent, address_space_mem, - address_space_io, devfn_min); + pci_root_bus_internal_init(bus, parent, mem, io, devfn_min); return bus; } @@ -586,15 +581,13 @@ void pci_bus_irqs_cleanup(PCIBus *bus) PCIBus *pci_register_root_bus(DeviceState *parent, const char *name, pci_set_irq_fn set_irq, pci_map_irq_fn map_irq, void *irq_opaque, - MemoryRegion *address_space_mem, - MemoryRegion *address_space_io, + MemoryRegion *mem, MemoryRegion *io, uint8_t devfn_min, int nirq, const char *typename) { PCIBus *bus; - bus = pci_root_bus_new(parent, name, address_space_mem, - address_space_io, devfn_min, typename); + bus = pci_root_bus_new(parent, name, mem, io, devfn_min, typename); pci_bus_irqs(bus, set_irq, irq_opaque, nirq); pci_bus_map_irqs(bus, map_irq); return bus; diff --git a/include/hw/pci/pci.h b/include/hw/pci/pci.h index b70a0b95ff..ea5aff118b 100644 --- a/include/hw/pci/pci.h +++ b/include/hw/pci/pci.h @@ -279,12 +279,10 @@ bool pci_bus_is_express(const PCIBus *bus); void pci_root_bus_init(PCIBus *bus, size_t bus_size, DeviceState *parent, const char *name, - MemoryRegion *address_space_mem, - MemoryRegion *address_space_io, + MemoryRegion *mem, MemoryRegion *io, uint8_t devfn_min, const char *typename); PCIBus *pci_root_bus_new(DeviceState *parent, const char *name, - MemoryRegion *address_space_mem, - MemoryRegion *address_space_io, + MemoryRegion *mem, MemoryRegion *io, uint8_t devfn_min, const char *typename); void pci_root_bus_cleanup(PCIBus *bus); void pci_bus_irqs(PCIBus *bus, pci_set_irq_fn set_irq, @@ -304,8 +302,7 @@ int pci_swizzle_map_irq_fn(PCIDevice *pci_dev, int pin); PCIBus *pci_register_root_bus(DeviceState *parent, const char *name, pci_set_irq_fn set_irq, pci_map_irq_fn map_irq, void *irq_opaque, - MemoryRegion *address_space_mem, - MemoryRegion *address_space_io, + MemoryRegion *mem, MemoryRegion *io, uint8_t devfn_min, int nirq, const char *typename); void pci_unregister_root_bus(PCIBus *bus); From ea08e72eb0288c40816c4b3a14688345d2eb0707 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Mon, 9 Oct 2023 10:25:58 +0200 Subject: [PATCH 0943/1077] hw/s390x: Clean up global variable shadowing in quiesce_powerdown_req() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fix: hw/s390x/sclpquiesce.c:90:22: error: declaration shadows a variable in the global scope [-Werror,-Wshadow] QuiesceNotifier *qn = container_of(n, QuiesceNotifier, notifier); ^ hw/s390x/sclpquiesce.c:86:3: note: previous declaration is here } qn; ^ Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Thomas Huth Reviewed-by: David Hildenbrand Message-Id: <20231010115048.11856-7-philmd@linaro.org> --- hw/s390x/sclpquiesce.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/hw/s390x/sclpquiesce.c b/hw/s390x/sclpquiesce.c index ce07b16884..a641089929 100644 --- a/hw/s390x/sclpquiesce.c +++ b/hw/s390x/sclpquiesce.c @@ -78,12 +78,10 @@ static const VMStateDescription vmstate_sclpquiesce = { } }; -typedef struct QuiesceNotifier QuiesceNotifier; - -static struct QuiesceNotifier { +typedef struct QuiesceNotifier { Notifier notifier; SCLPEvent *event; -} qn; +} QuiesceNotifier; static void quiesce_powerdown_req(Notifier *n, void *opaque) { @@ -97,6 +95,8 @@ static void quiesce_powerdown_req(Notifier *n, void *opaque) static int quiesce_init(SCLPEvent *event) { + static QuiesceNotifier qn; + qn.notifier.notify = quiesce_powerdown_req; qn.event = event; From 705000674b9df27cc80328e83d3825dc5ee3d6d6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Tue, 3 Oct 2023 09:58:14 +0200 Subject: [PATCH 0944/1077] hw/intc/apic: Use ERRP_GUARD() in apic_common_realize() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit APICCommonClass::realize() is a DeviceRealize() handler which take an Error** parameter and can fail. Do not proceed further on failure. Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Peter Xu Message-Id: <20231003082728.83496-2-philmd@linaro.org> --- hw/intc/apic_common.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/hw/intc/apic_common.c b/hw/intc/apic_common.c index 68ad30e2f5..bccb4241c2 100644 --- a/hw/intc/apic_common.c +++ b/hw/intc/apic_common.c @@ -257,6 +257,7 @@ static const VMStateDescription vmstate_apic_common; static void apic_common_realize(DeviceState *dev, Error **errp) { + ERRP_GUARD(); APICCommonState *s = APIC_COMMON(dev); APICCommonClass *info; static DeviceState *vapic; @@ -267,6 +268,9 @@ static void apic_common_realize(DeviceState *dev, Error **errp) info = APIC_COMMON_GET_CLASS(s); info->realize(dev, errp); + if (*errp) { + return; + } /* Note: We need at least 1M to map the VAPIC option ROM */ if (!vapic && s->vapic_control & VAPIC_ENABLE_MASK && From e45abc2bb958d4780fa56bc10049f604408c2c96 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Thu, 19 Oct 2023 12:01:59 +0200 Subject: [PATCH 0945/1077] hw/ppc/spapr_vio: Realize SPAPR_VIO_BRIDGE device before accessing it MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit qbus_new() should not be called on unrealized device. Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Cédric Le Goater Reviewed-by: Thomas Huth Message-Id: <20231019131647.19690-2-philmd@linaro.org> --- hw/ppc/spapr_vio.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/hw/ppc/spapr_vio.c b/hw/ppc/spapr_vio.c index 9d4fec2c04..f8ef2b6fa8 100644 --- a/hw/ppc/spapr_vio.c +++ b/hw/ppc/spapr_vio.c @@ -574,13 +574,14 @@ SpaprVioBus *spapr_vio_bus_init(void) /* Create bridge device */ dev = qdev_new(TYPE_SPAPR_VIO_BRIDGE); - sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal); /* Create bus on bridge device */ qbus = qbus_new(TYPE_SPAPR_VIO_BUS, dev, "spapr-vio"); bus = SPAPR_VIO_BUS(qbus); bus->next_reg = SPAPR_VIO_REG_BASE; + sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal); + /* hcall-vio */ spapr_register_hypercall(H_VIO_SIGNAL, h_vio_signal); From 59561e827b9c5a13bdf5e099ee2b045c8144b0c2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Wed, 18 Oct 2023 09:45:43 +0200 Subject: [PATCH 0946/1077] hw/ppc/pnv_xscom: Rename pnv_xscom_realize(Error **) -> pnv_xscom_init() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit pnv_xscom_realize() is not used to *realize* QDev object, rename it as pnv_xscom_init(). The Error** argument is unused: remove it. Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Richard Henderson Reviewed-by: Thomas Huth Reviewed-by: LIU Zhiwei Reviewed-by: Cédric Le Goater Message-Id: <20231019131647.19690-3-philmd@linaro.org> --- hw/ppc/pnv.c | 18 +++--------------- hw/ppc/pnv_xscom.c | 2 +- include/hw/ppc/pnv_xscom.h | 2 +- 3 files changed, 5 insertions(+), 17 deletions(-) diff --git a/hw/ppc/pnv.c b/hw/ppc/pnv.c index eb54f93986..456631c9dc 100644 --- a/hw/ppc/pnv.c +++ b/hw/ppc/pnv.c @@ -1249,11 +1249,7 @@ static void pnv_chip_power8_realize(DeviceState *dev, Error **errp) assert(chip8->xics); /* XSCOM bridge is first */ - pnv_xscom_realize(chip, PNV_XSCOM_SIZE, &local_err); - if (local_err) { - error_propagate(errp, local_err); - return; - } + pnv_xscom_init(chip, PNV_XSCOM_SIZE); sysbus_mmio_map(SYS_BUS_DEVICE(chip), 0, PNV_XSCOM_BASE(chip)); pcc->parent_realize(dev, &local_err); @@ -1512,11 +1508,7 @@ static void pnv_chip_power9_realize(DeviceState *dev, Error **errp) Error *local_err = NULL; /* XSCOM bridge is first */ - pnv_xscom_realize(chip, PNV9_XSCOM_SIZE, &local_err); - if (local_err) { - error_propagate(errp, local_err); - return; - } + pnv_xscom_init(chip, PNV9_XSCOM_SIZE); sysbus_mmio_map(SYS_BUS_DEVICE(chip), 0, PNV9_XSCOM_BASE(chip)); pcc->parent_realize(dev, &local_err); @@ -1727,11 +1719,7 @@ static void pnv_chip_power10_realize(DeviceState *dev, Error **errp) Error *local_err = NULL; /* XSCOM bridge is first */ - pnv_xscom_realize(chip, PNV10_XSCOM_SIZE, &local_err); - if (local_err) { - error_propagate(errp, local_err); - return; - } + pnv_xscom_init(chip, PNV10_XSCOM_SIZE); sysbus_mmio_map(SYS_BUS_DEVICE(chip), 0, PNV10_XSCOM_BASE(chip)); pcc->parent_realize(dev, &local_err); diff --git a/hw/ppc/pnv_xscom.c b/hw/ppc/pnv_xscom.c index d820e05e40..af57b55863 100644 --- a/hw/ppc/pnv_xscom.c +++ b/hw/ppc/pnv_xscom.c @@ -221,7 +221,7 @@ const MemoryRegionOps pnv_xscom_ops = { .endianness = DEVICE_BIG_ENDIAN, }; -void pnv_xscom_realize(PnvChip *chip, uint64_t size, Error **errp) +void pnv_xscom_init(PnvChip *chip, uint64_t size) { SysBusDevice *sbd = SYS_BUS_DEVICE(chip); char *name; diff --git a/include/hw/ppc/pnv_xscom.h b/include/hw/ppc/pnv_xscom.h index 9bc6463547..41671001da 100644 --- a/include/hw/ppc/pnv_xscom.h +++ b/include/hw/ppc/pnv_xscom.h @@ -170,7 +170,7 @@ struct PnvXScomInterfaceClass { #define PNV10_XSCOM_PEC_PCI_BASE 0x8010800 /* index goes upwards ... */ #define PNV10_XSCOM_PEC_PCI_SIZE 0x200 -void pnv_xscom_realize(PnvChip *chip, uint64_t size, Error **errp); +void pnv_xscom_init(PnvChip *chip, uint64_t size); int pnv_dt_xscom(PnvChip *chip, void *fdt, int root_offset, uint64_t xscom_base, uint64_t xscom_size, const char *compat, int compat_size); From e29c4cb05ed9858f408db6b8fa775bc76f27a541 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Wed, 18 Oct 2023 09:49:06 +0200 Subject: [PATCH 0947/1077] hw/ppc/pnv_xscom: Move sysbus_mmio_map() call within pnv_xscom_init() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In order to make the next commit trivial, move sysbus_init_mmio() calls just before the corresponding sysbus_mmio_map() calls. Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Richard Henderson Reviewed-by: Thomas Huth Reviewed-by: LIU Zhiwei Reviewed-by: Cédric Le Goater Message-Id: <20231019131647.19690-4-philmd@linaro.org> --- hw/ppc/pnv.c | 9 +++------ hw/ppc/pnv_xscom.c | 3 ++- include/hw/ppc/pnv_xscom.h | 2 +- 3 files changed, 6 insertions(+), 8 deletions(-) diff --git a/hw/ppc/pnv.c b/hw/ppc/pnv.c index 456631c9dc..10158f7684 100644 --- a/hw/ppc/pnv.c +++ b/hw/ppc/pnv.c @@ -1249,8 +1249,7 @@ static void pnv_chip_power8_realize(DeviceState *dev, Error **errp) assert(chip8->xics); /* XSCOM bridge is first */ - pnv_xscom_init(chip, PNV_XSCOM_SIZE); - sysbus_mmio_map(SYS_BUS_DEVICE(chip), 0, PNV_XSCOM_BASE(chip)); + pnv_xscom_init(chip, PNV_XSCOM_SIZE, PNV_XSCOM_BASE(chip)); pcc->parent_realize(dev, &local_err); if (local_err) { @@ -1508,8 +1507,7 @@ static void pnv_chip_power9_realize(DeviceState *dev, Error **errp) Error *local_err = NULL; /* XSCOM bridge is first */ - pnv_xscom_init(chip, PNV9_XSCOM_SIZE); - sysbus_mmio_map(SYS_BUS_DEVICE(chip), 0, PNV9_XSCOM_BASE(chip)); + pnv_xscom_init(chip, PNV9_XSCOM_SIZE, PNV9_XSCOM_BASE(chip)); pcc->parent_realize(dev, &local_err); if (local_err) { @@ -1719,8 +1717,7 @@ static void pnv_chip_power10_realize(DeviceState *dev, Error **errp) Error *local_err = NULL; /* XSCOM bridge is first */ - pnv_xscom_init(chip, PNV10_XSCOM_SIZE); - sysbus_mmio_map(SYS_BUS_DEVICE(chip), 0, PNV10_XSCOM_BASE(chip)); + pnv_xscom_init(chip, PNV10_XSCOM_SIZE, PNV10_XSCOM_BASE(chip)); pcc->parent_realize(dev, &local_err); if (local_err) { diff --git a/hw/ppc/pnv_xscom.c b/hw/ppc/pnv_xscom.c index af57b55863..cf892c9fe8 100644 --- a/hw/ppc/pnv_xscom.c +++ b/hw/ppc/pnv_xscom.c @@ -221,7 +221,7 @@ const MemoryRegionOps pnv_xscom_ops = { .endianness = DEVICE_BIG_ENDIAN, }; -void pnv_xscom_init(PnvChip *chip, uint64_t size) +void pnv_xscom_init(PnvChip *chip, uint64_t size, hwaddr addr) { SysBusDevice *sbd = SYS_BUS_DEVICE(chip); char *name; @@ -230,6 +230,7 @@ void pnv_xscom_init(PnvChip *chip, uint64_t size) memory_region_init_io(&chip->xscom_mmio, OBJECT(chip), &pnv_xscom_ops, chip, name, size); sysbus_init_mmio(sbd, &chip->xscom_mmio); + sysbus_mmio_map(sbd, 0, addr); memory_region_init(&chip->xscom, OBJECT(chip), name, size); address_space_init(&chip->xscom_as, &chip->xscom, name); diff --git a/include/hw/ppc/pnv_xscom.h b/include/hw/ppc/pnv_xscom.h index 41671001da..35b19610f7 100644 --- a/include/hw/ppc/pnv_xscom.h +++ b/include/hw/ppc/pnv_xscom.h @@ -170,7 +170,7 @@ struct PnvXScomInterfaceClass { #define PNV10_XSCOM_PEC_PCI_BASE 0x8010800 /* index goes upwards ... */ #define PNV10_XSCOM_PEC_PCI_SIZE 0x200 -void pnv_xscom_init(PnvChip *chip, uint64_t size); +void pnv_xscom_init(PnvChip *chip, uint64_t size, hwaddr addr); int pnv_dt_xscom(PnvChip *chip, void *fdt, int root_offset, uint64_t xscom_base, uint64_t xscom_size, const char *compat, int compat_size); From 6a7f9f6f90dd7ecb137c1772cb98134d7606cdc3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Wed, 18 Oct 2023 09:53:43 +0200 Subject: [PATCH 0948/1077] hw/ppc/pnv_xscom: Do not use SysBus API to map local MMIO region MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit There is no point in exposing an internal MMIO region via SysBus and directly mapping it in the very same device. Just map it without using the SysBus API. Transformation done using the following coccinelle script: @@ expression sbdev; expression index; expression addr; expression subregion; @@ - sysbus_init_mmio(sbdev, subregion); ... when != sbdev - sysbus_mmio_map(sbdev, index, addr); + memory_region_add_subregion(get_system_memory(), addr, subregion); Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Richard Henderson Reviewed-by: Thomas Huth Reviewed-by: LIU Zhiwei Reviewed-by: Cédric Le Goater Message-Id: <20231019131647.19690-5-philmd@linaro.org> --- hw/ppc/pnv_xscom.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/hw/ppc/pnv_xscom.c b/hw/ppc/pnv_xscom.c index cf892c9fe8..805b1d0c87 100644 --- a/hw/ppc/pnv_xscom.c +++ b/hw/ppc/pnv_xscom.c @@ -223,14 +223,12 @@ const MemoryRegionOps pnv_xscom_ops = { void pnv_xscom_init(PnvChip *chip, uint64_t size, hwaddr addr) { - SysBusDevice *sbd = SYS_BUS_DEVICE(chip); char *name; name = g_strdup_printf("xscom-%x", chip->chip_id); memory_region_init_io(&chip->xscom_mmio, OBJECT(chip), &pnv_xscom_ops, chip, name, size); - sysbus_init_mmio(sbd, &chip->xscom_mmio); - sysbus_mmio_map(sbd, 0, addr); + memory_region_add_subregion(get_system_memory(), addr, &chip->xscom_mmio); memory_region_init(&chip->xscom, OBJECT(chip), name, size); address_space_init(&chip->xscom_as, &chip->xscom, name); From a92771ce8dd5b217ae59c3654d39963e1bd27f95 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Wed, 18 Oct 2023 07:48:11 +0200 Subject: [PATCH 0949/1077] hw/ppc/pnv: Do not use SysBus API to map local MMIO region MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit There is no point in exposing an internal MMIO region via SysBus and directly mapping it in the very same device. Just map it without using the SysBus API. Transformation done using the following coccinelle script: @@ expression sbdev; expression index; expression addr; expression subregion; @@ - sysbus_init_mmio(sbdev, subregion); ... when != sbdev - sysbus_mmio_map(sbdev, index, addr); + memory_region_add_subregion(get_system_memory(), addr, subregion); Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Richard Henderson Reviewed-by: Thomas Huth Reviewed-by: LIU Zhiwei Reviewed-by: Cédric Le Goater Message-Id: <20231019131647.19690-6-philmd@linaro.org> --- hw/ppc/pnv.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/hw/ppc/pnv.c b/hw/ppc/pnv.c index 10158f7684..c0e34fffbc 100644 --- a/hw/ppc/pnv.c +++ b/hw/ppc/pnv.c @@ -1217,10 +1217,9 @@ static void pnv_chip_icp_realize(Pnv8Chip *chip8, Error **errp) name = g_strdup_printf("icp-%x", chip->chip_id); memory_region_init(&chip8->icp_mmio, OBJECT(chip), name, PNV_ICP_SIZE); - sysbus_init_mmio(SYS_BUS_DEVICE(chip), &chip8->icp_mmio); g_free(name); - - sysbus_mmio_map(SYS_BUS_DEVICE(chip), 1, PNV_ICP_BASE(chip)); + memory_region_add_subregion(get_system_memory(), PNV_ICP_BASE(chip), + &chip8->icp_mmio); /* Map the ICP registers for each thread */ for (i = 0; i < chip->nr_cores; i++) { From 9c33e2a8acf0d91f420fabf858ba018d80af5c0d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Wed, 18 Oct 2023 07:53:30 +0200 Subject: [PATCH 0950/1077] hw/intc/spapr_xive: Move sysbus_init_mmio() calls around MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In order to make the next commit trivial, move sysbus_init_mmio() calls just before the corresponding sysbus_mmio_map() calls. Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Richard Henderson Reviewed-by: Thomas Huth Reviewed-by: LIU Zhiwei Reviewed-by: Cédric Le Goater Message-Id: <20231019131647.19690-7-philmd@linaro.org> --- hw/intc/spapr_xive.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/hw/intc/spapr_xive.c b/hw/intc/spapr_xive.c index 7f701d414b..12057ffe5b 100644 --- a/hw/intc/spapr_xive.c +++ b/hw/intc/spapr_xive.c @@ -316,7 +316,6 @@ static void spapr_xive_realize(DeviceState *dev, Error **errp) if (!qdev_realize(DEVICE(xsrc), NULL, errp)) { return; } - sysbus_init_mmio(SYS_BUS_DEVICE(xive), &xsrc->esb_mmio); /* * Initialize the END ESB source @@ -328,7 +327,6 @@ static void spapr_xive_realize(DeviceState *dev, Error **errp) if (!qdev_realize(DEVICE(end_xsrc), NULL, errp)) { return; } - sysbus_init_mmio(SYS_BUS_DEVICE(xive), &end_xsrc->esb_mmio); /* Set the mapping address of the END ESB pages after the source ESBs */ xive->end_base = xive->vc_base + xive_source_esb_len(xsrc); @@ -347,14 +345,16 @@ static void spapr_xive_realize(DeviceState *dev, Error **errp) /* TIMA initialization */ memory_region_init_io(&xive->tm_mmio, OBJECT(xive), &spapr_xive_tm_ops, xive, "xive.tima", 4ull << TM_SHIFT); - sysbus_init_mmio(SYS_BUS_DEVICE(xive), &xive->tm_mmio); /* * Map all regions. These will be enabled or disabled at reset and * can also be overridden by KVM memory regions if active */ + sysbus_init_mmio(SYS_BUS_DEVICE(xive), &xsrc->esb_mmio); sysbus_mmio_map(SYS_BUS_DEVICE(xive), 0, xive->vc_base); + sysbus_init_mmio(SYS_BUS_DEVICE(xive), &end_xsrc->esb_mmio); sysbus_mmio_map(SYS_BUS_DEVICE(xive), 1, xive->end_base); + sysbus_init_mmio(SYS_BUS_DEVICE(xive), &xive->tm_mmio); sysbus_mmio_map(SYS_BUS_DEVICE(xive), 2, xive->tm_base); } From 05af744babc44a99a5043082805b34e591e5a39e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Wed, 18 Oct 2023 07:53:54 +0200 Subject: [PATCH 0951/1077] hw/intc/spapr_xive: Do not use SysBus API to map local MMIO region MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit There is no point in exposing an internal MMIO region via SysBus and directly mapping it in the very same device. Just map it without using the SysBus API. Transformation done using the following coccinelle script: @@ expression sbdev; expression index; expression addr; expression subregion; @@ - sysbus_init_mmio(sbdev, subregion); ... when != sbdev - sysbus_mmio_map(sbdev, index, addr); + memory_region_add_subregion(get_system_memory(), addr, subregion); Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Richard Henderson Reviewed-by: Thomas Huth Reviewed-by: LIU Zhiwei Reviewed-by: Cédric Le Goater Message-Id: <20231019131647.19690-8-philmd@linaro.org> --- hw/intc/spapr_xive.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/hw/intc/spapr_xive.c b/hw/intc/spapr_xive.c index 12057ffe5b..199c261b07 100644 --- a/hw/intc/spapr_xive.c +++ b/hw/intc/spapr_xive.c @@ -350,12 +350,12 @@ static void spapr_xive_realize(DeviceState *dev, Error **errp) * Map all regions. These will be enabled or disabled at reset and * can also be overridden by KVM memory regions if active */ - sysbus_init_mmio(SYS_BUS_DEVICE(xive), &xsrc->esb_mmio); - sysbus_mmio_map(SYS_BUS_DEVICE(xive), 0, xive->vc_base); - sysbus_init_mmio(SYS_BUS_DEVICE(xive), &end_xsrc->esb_mmio); - sysbus_mmio_map(SYS_BUS_DEVICE(xive), 1, xive->end_base); - sysbus_init_mmio(SYS_BUS_DEVICE(xive), &xive->tm_mmio); - sysbus_mmio_map(SYS_BUS_DEVICE(xive), 2, xive->tm_base); + memory_region_add_subregion(get_system_memory(), xive->vc_base, + &xsrc->esb_mmio); + memory_region_add_subregion(get_system_memory(), xive->end_base, + &end_xsrc->esb_mmio); + memory_region_add_subregion(get_system_memory(), xive->tm_base, + &xive->tm_mmio); } static int spapr_xive_get_eas(XiveRouter *xrtr, uint8_t eas_blk, From f79a525d8d0fe9d6fe4c1925600aa69eb82acbff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Wed, 18 Oct 2023 07:50:20 +0200 Subject: [PATCH 0952/1077] hw/i386/amd_iommu: Do not use SysBus API to map local MMIO region MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit There is no point in exposing an internal MMIO region via SysBus and directly mapping it in the very same device. Just map it without using the SysBus API. Transformation done using the following coccinelle script: @@ expression sbdev; expression index; expression addr; expression subregion; @@ - sysbus_init_mmio(sbdev, subregion); ... when != sbdev - sysbus_mmio_map(sbdev, index, addr); + memory_region_add_subregion(get_system_memory(), addr, subregion); Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Michael S. Tsirkin Reviewed-by: Zhao Liu Message-Id: <20231018141151.87466-2-philmd@linaro.org> --- hw/i386/amd_iommu.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/hw/i386/amd_iommu.c b/hw/i386/amd_iommu.c index 8d0f2f99dd..7965415b47 100644 --- a/hw/i386/amd_iommu.c +++ b/hw/i386/amd_iommu.c @@ -1579,9 +1579,8 @@ static void amdvi_sysbus_realize(DeviceState *dev, Error **errp) /* set up MMIO */ memory_region_init_io(&s->mmio, OBJECT(s), &mmio_mem_ops, s, "amdvi-mmio", AMDVI_MMIO_SIZE); - - sysbus_init_mmio(SYS_BUS_DEVICE(s), &s->mmio); - sysbus_mmio_map(SYS_BUS_DEVICE(s), 0, AMDVI_BASE_ADDR); + memory_region_add_subregion(get_system_memory(), AMDVI_BASE_ADDR, + &s->mmio); pci_setup_iommu(bus, amdvi_host_dma_iommu, s); amdvi_init(s); } From 77dbaccefd7c5e1f985f96a49412aa3b378fbadd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Wed, 18 Oct 2023 07:50:31 +0200 Subject: [PATCH 0953/1077] hw/i386/intel_iommu: Do not use SysBus API to map local MMIO region MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit There is no point in exposing an internal MMIO region via SysBus and directly mapping it in the very same device. Just map it without using the SysBus API. Transformation done using the following coccinelle script: @@ expression sbdev; expression index; expression addr; expression subregion; @@ - sysbus_init_mmio(sbdev, subregion); ... when != sbdev - sysbus_mmio_map(sbdev, index, addr); + memory_region_add_subregion(get_system_memory(), addr, subregion); Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Michael S. Tsirkin Reviewed-by: Zhao Liu Message-Id: <20231018141151.87466-3-philmd@linaro.org> --- hw/i386/intel_iommu.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/hw/i386/intel_iommu.c b/hw/i386/intel_iommu.c index 2c832ab68b..e4f6cedcb1 100644 --- a/hw/i386/intel_iommu.c +++ b/hw/i386/intel_iommu.c @@ -4134,6 +4134,8 @@ static void vtd_realize(DeviceState *dev, Error **errp) qemu_mutex_init(&s->iommu_lock); memory_region_init_io(&s->csrmem, OBJECT(s), &vtd_mem_ops, s, "intel_iommu", DMAR_REG_SIZE); + memory_region_add_subregion(get_system_memory(), + Q35_HOST_BRIDGE_IOMMU_ADDR, &s->csrmem); /* Create the shared memory regions by all devices */ memory_region_init(&s->mr_nodmar, OBJECT(s), "vtd-nodmar", @@ -4148,15 +4150,12 @@ static void vtd_realize(DeviceState *dev, Error **errp) memory_region_add_subregion_overlap(&s->mr_nodmar, VTD_INTERRUPT_ADDR_FIRST, &s->mr_ir, 1); - - sysbus_init_mmio(SYS_BUS_DEVICE(s), &s->csrmem); /* No corresponding destroy */ s->iotlb = g_hash_table_new_full(vtd_iotlb_hash, vtd_iotlb_equal, g_free, g_free); s->vtd_address_spaces = g_hash_table_new_full(vtd_as_hash, vtd_as_equal, g_free, g_free); vtd_init(s); - sysbus_mmio_map(SYS_BUS_DEVICE(s), 0, Q35_HOST_BRIDGE_IOMMU_ADDR); pci_setup_iommu(bus, vtd_host_dma_iommu, dev); /* Pseudo address space under root PCI bus. */ x86ms->ioapic_as = vtd_host_dma_iommu(bus, s, Q35_PSEUDO_DEVFN_IOAPIC); From a4a81a2d57a4bac4efd482a1589b007702f92901 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Wed, 18 Oct 2023 08:20:43 +0200 Subject: [PATCH 0954/1077] hw/misc/allwinner-dramc: Move sysbus_mmio_map call from init -> realize MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In order to make the next commit trivial, move the sysbus_init_mmio() call in allwinner_r40_dramc_init() just before the corresponding sysbus_mmio_map_overlap() call in allwinner_r40_dramc_realize(). Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Thomas Huth Message-Id: <20231019071611.98885-4-philmd@linaro.org> --- hw/misc/allwinner-r40-dramc.c | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/hw/misc/allwinner-r40-dramc.c b/hw/misc/allwinner-r40-dramc.c index 6944f84455..2cc0254a55 100644 --- a/hw/misc/allwinner-r40-dramc.c +++ b/hw/misc/allwinner-r40-dramc.c @@ -414,6 +414,7 @@ static void allwinner_r40_dramc_reset(DeviceState *dev) static void allwinner_r40_dramc_realize(DeviceState *dev, Error **errp) { AwR40DramCtlState *s = AW_R40_DRAMC(dev); + SysBusDevice *sbd = SYS_BUS_DEVICE(dev); if (!get_match_ddr(s->ram_size)) { error_report("%s: ram-size %u MiB is not supported", @@ -421,8 +422,12 @@ static void allwinner_r40_dramc_realize(DeviceState *dev, Error **errp) exit(1); } - /* detect_cells */ - sysbus_mmio_map_overlap(SYS_BUS_DEVICE(s), 3, s->ram_addr, 10); + /* R40 support max 2G memory but we only support up to 1G now. index 3 */ + memory_region_init_io(&s->detect_cells, OBJECT(s), + &allwinner_r40_detect_ops, s, + "DRAMCELLS", 1 * GiB); + sysbus_init_mmio(sbd, &s->detect_cells); + sysbus_mmio_map_overlap(sbd, 3, s->ram_addr, 10); memory_region_set_enabled(&s->detect_cells, false); /* @@ -458,12 +463,6 @@ static void allwinner_r40_dramc_init(Object *obj) &allwinner_r40_dramphy_ops, s, "DRAMPHY", 4 * KiB); sysbus_init_mmio(sbd, &s->dramphy_iomem); - - /* R40 support max 2G memory but we only support up to 1G now. index 3 */ - memory_region_init_io(&s->detect_cells, OBJECT(s), - &allwinner_r40_detect_ops, s, - "DRAMCELLS", 1 * GiB); - sysbus_init_mmio(sbd, &s->detect_cells); } static Property allwinner_r40_dramc_properties[] = { From 403b50fd3c78037f85aef76845056f8aecbb25e2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Wed, 18 Oct 2023 10:13:54 +0200 Subject: [PATCH 0955/1077] hw/misc/allwinner-dramc: Do not use SysBus API to map local MMIO region MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit There is no point in exposing an internal MMIO region via SysBus and directly mapping it in the very same device. Just map it without using the SysBus API. Transformation done using the following coccinelle script: @@ expression sbdev; expression index; expression addr; expression subregion; @@ - sysbus_init_mmio(sbdev, subregion); ... when != sbdev - sysbus_mmio_map(sbdev, index, addr); + memory_region_add_subregion(get_system_memory(), + addr, subregion); @@ expression priority; @@ - sysbus_init_mmio(sbdev, subregion); ... when != sbdev - sysbus_mmio_map_overlap(sbdev, index, addr, priority); + memory_region_add_subregion_overlap(get_system_memory(), + addr, + subregion, priority); Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Thomas Huth Message-Id: <20231019071611.98885-5-philmd@linaro.org> --- hw/misc/allwinner-r40-dramc.c | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/hw/misc/allwinner-r40-dramc.c b/hw/misc/allwinner-r40-dramc.c index 2cc0254a55..3d81ddb2e1 100644 --- a/hw/misc/allwinner-r40-dramc.c +++ b/hw/misc/allwinner-r40-dramc.c @@ -414,7 +414,6 @@ static void allwinner_r40_dramc_reset(DeviceState *dev) static void allwinner_r40_dramc_realize(DeviceState *dev, Error **errp) { AwR40DramCtlState *s = AW_R40_DRAMC(dev); - SysBusDevice *sbd = SYS_BUS_DEVICE(dev); if (!get_match_ddr(s->ram_size)) { error_report("%s: ram-size %u MiB is not supported", @@ -422,23 +421,23 @@ static void allwinner_r40_dramc_realize(DeviceState *dev, Error **errp) exit(1); } - /* R40 support max 2G memory but we only support up to 1G now. index 3 */ + /* R40 support max 2G memory but we only support up to 1G now. */ memory_region_init_io(&s->detect_cells, OBJECT(s), &allwinner_r40_detect_ops, s, "DRAMCELLS", 1 * GiB); - sysbus_init_mmio(sbd, &s->detect_cells); - sysbus_mmio_map_overlap(sbd, 3, s->ram_addr, 10); + memory_region_add_subregion_overlap(get_system_memory(), s->ram_addr, + &s->detect_cells, 10); memory_region_set_enabled(&s->detect_cells, false); /* * We only support DRAM size up to 1G now, so prepare a high memory page - * after 1G for dualrank detect. index = 4 + * after 1G for dualrank detect. */ memory_region_init_io(&s->dram_high, OBJECT(s), &allwinner_r40_dualrank_detect_ops, s, "DRAMHIGH", KiB); - sysbus_init_mmio(SYS_BUS_DEVICE(s), &s->dram_high); - sysbus_mmio_map(SYS_BUS_DEVICE(s), 4, s->ram_addr + GiB); + memory_region_add_subregion(get_system_memory(), s->ram_addr + GiB, + &s->dram_high); } static void allwinner_r40_dramc_init(Object *obj) From 52d97058e871106c19a98f7d6202b061f2ee7c93 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Wed, 18 Oct 2023 07:51:09 +0200 Subject: [PATCH 0956/1077] hw/pci-host/bonito: Do not use SysBus API to map local MMIO region MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit There is no point in exposing an internal MMIO region via SysBus and directly mapping it in the very same device. Just map it without using the SysBus API. Transformation done using the following coccinelle script: @@ expression sbdev; expression index; expression addr; expression subregion; @@ - sysbus_init_mmio(sbdev, subregion); ... when != sbdev - sysbus_mmio_map(sbdev, index, addr); + memory_region_add_subregion(get_system_memory(), addr, subregion); and manually adding the local 'host_mem' variable to avoid multiple calls to get_system_memory(). Reviewed-by: Thomas Huth Signed-off-by: Philippe Mathieu-Daudé Message-Id: <20231019071611.98885-6-philmd@linaro.org> --- hw/pci-host/bonito.c | 30 +++++++++++++----------------- 1 file changed, 13 insertions(+), 17 deletions(-) diff --git a/hw/pci-host/bonito.c b/hw/pci-host/bonito.c index ee6cb85e97..bab661f3ce 100644 --- a/hw/pci-host/bonito.c +++ b/hw/pci-host/bonito.c @@ -654,7 +654,7 @@ static void bonito_host_realize(DeviceState *dev, Error **errp) static void bonito_pci_realize(PCIDevice *dev, Error **errp) { PCIBonitoState *s = PCI_BONITO(dev); - SysBusDevice *sysbus = SYS_BUS_DEVICE(s->pcihost); + MemoryRegion *host_mem = get_system_memory(); PCIHostState *phb = PCI_HOST_BRIDGE(s->pcihost); BonitoState *bs = s->pcihost; MemoryRegion *pcimem_alias = g_new(MemoryRegion, 1); @@ -668,48 +668,45 @@ static void bonito_pci_realize(PCIDevice *dev, Error **errp) /* set the north bridge register mapping */ memory_region_init_io(&s->iomem, OBJECT(s), &bonito_ops, s, "north-bridge-register", BONITO_INTERNAL_REG_SIZE); - sysbus_init_mmio(sysbus, &s->iomem); - sysbus_mmio_map(sysbus, 0, BONITO_INTERNAL_REG_BASE); + memory_region_add_subregion(host_mem, BONITO_INTERNAL_REG_BASE, &s->iomem); /* set the north bridge pci configure mapping */ memory_region_init_io(&phb->conf_mem, OBJECT(s), &bonito_pciconf_ops, s, "north-bridge-pci-config", BONITO_PCICONFIG_SIZE); - sysbus_init_mmio(sysbus, &phb->conf_mem); - sysbus_mmio_map(sysbus, 1, BONITO_PCICONFIG_BASE); + memory_region_add_subregion(host_mem, BONITO_PCICONFIG_BASE, + &phb->conf_mem); /* set the south bridge pci configure mapping */ memory_region_init_io(&phb->data_mem, OBJECT(s), &bonito_spciconf_ops, s, "south-bridge-pci-config", BONITO_SPCICONFIG_SIZE); - sysbus_init_mmio(sysbus, &phb->data_mem); - sysbus_mmio_map(sysbus, 2, BONITO_SPCICONFIG_BASE); + memory_region_add_subregion(host_mem, BONITO_SPCICONFIG_BASE, + &phb->data_mem); create_unimplemented_device("bonito", BONITO_REG_BASE, BONITO_REG_SIZE); memory_region_init_io(&s->iomem_ldma, OBJECT(s), &bonito_ldma_ops, s, "ldma", 0x100); - sysbus_init_mmio(sysbus, &s->iomem_ldma); - sysbus_mmio_map(sysbus, 3, 0x1fe00200); + memory_region_add_subregion(host_mem, 0x1fe00200, &s->iomem_ldma); /* PCI copier */ memory_region_init_io(&s->iomem_cop, OBJECT(s), &bonito_cop_ops, s, "cop", 0x100); - sysbus_init_mmio(sysbus, &s->iomem_cop); - sysbus_mmio_map(sysbus, 4, 0x1fe00300); + memory_region_add_subregion(host_mem, 0x1fe00300, &s->iomem_cop); create_unimplemented_device("ROMCS", BONITO_FLASH_BASE, 60 * MiB); /* Map PCI IO Space 0x1fd0 0000 - 0x1fd1 0000 */ memory_region_init_alias(&s->bonito_pciio, OBJECT(s), "isa_mmio", get_system_io(), 0, BONITO_PCIIO_SIZE); - sysbus_init_mmio(sysbus, &s->bonito_pciio); - sysbus_mmio_map(sysbus, 5, BONITO_PCIIO_BASE); + memory_region_add_subregion(host_mem, BONITO_PCIIO_BASE, + &s->bonito_pciio); /* add pci local io mapping */ memory_region_init_alias(&s->bonito_localio, OBJECT(s), "IOCS[0]", get_system_io(), 0, 256 * KiB); - sysbus_init_mmio(sysbus, &s->bonito_localio); - sysbus_mmio_map(sysbus, 6, BONITO_DEV_BASE); + memory_region_add_subregion(host_mem, BONITO_DEV_BASE, + &s->bonito_localio); create_unimplemented_device("IOCS[1]", BONITO_DEV_BASE + 1 * 256 * KiB, 256 * KiB); create_unimplemented_device("IOCS[2]", BONITO_DEV_BASE + 2 * 256 * KiB, @@ -719,8 +716,7 @@ static void bonito_pci_realize(PCIDevice *dev, Error **errp) memory_region_init_alias(pcimem_alias, NULL, "pci.mem.alias", &bs->pci_mem, 0, BONITO_PCIHI_SIZE); - memory_region_add_subregion(get_system_memory(), - BONITO_PCIHI_BASE, pcimem_alias); + memory_region_add_subregion(host_mem, BONITO_PCIHI_BASE, pcimem_alias); create_unimplemented_device("PCI_2", (hwaddr)BONITO_PCIHI_BASE + BONITO_PCIHI_SIZE, 2 * GiB); From 74b253585de2def439cc400bc699b37de3e20727 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Wed, 18 Oct 2023 08:37:06 +0200 Subject: [PATCH 0957/1077] hw/acpi: Realize ACPI_GED sysbus device before accessing it MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit sysbus_mmio_map() should not be called on unrealized device. Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Thomas Huth Reviewed-by: Michael S. Tsirkin Message-Id: <20231018141151.87466-7-philmd@linaro.org> --- hw/arm/virt.c | 3 +-- hw/i386/microvm.c | 2 +- hw/loongarch/virt.c | 2 +- 3 files changed, 3 insertions(+), 4 deletions(-) diff --git a/hw/arm/virt.c b/hw/arm/virt.c index 15e74249f9..02c7a7ff3c 100644 --- a/hw/arm/virt.c +++ b/hw/arm/virt.c @@ -647,13 +647,12 @@ static inline DeviceState *create_acpi_ged(VirtMachineState *vms) dev = qdev_new(TYPE_ACPI_GED); qdev_prop_set_uint32(dev, "ged-event", event); + sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal); sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, vms->memmap[VIRT_ACPI_GED].base); sysbus_mmio_map(SYS_BUS_DEVICE(dev), 1, vms->memmap[VIRT_PCDIMM_ACPI].base); sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, qdev_get_gpio_in(vms->gic, irq)); - sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal); - return dev; } diff --git a/hw/i386/microvm.c b/hw/i386/microvm.c index b9c93039e2..ca55aecc3b 100644 --- a/hw/i386/microvm.c +++ b/hw/i386/microvm.c @@ -206,12 +206,12 @@ static void microvm_devices_init(MicrovmMachineState *mms) if (x86_machine_is_acpi_enabled(x86ms)) { DeviceState *dev = qdev_new(TYPE_ACPI_GED); qdev_prop_set_uint32(dev, "ged-event", ACPI_GED_PWR_DOWN_EVT); + sysbus_realize(SYS_BUS_DEVICE(dev), &error_fatal); sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, GED_MMIO_BASE); /* sysbus_mmio_map(SYS_BUS_DEVICE(dev), 1, GED_MMIO_BASE_MEMHP); */ sysbus_mmio_map(SYS_BUS_DEVICE(dev), 2, GED_MMIO_BASE_REGS); sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, x86ms->gsi[GED_MMIO_IRQ]); - sysbus_realize(SYS_BUS_DEVICE(dev), &error_fatal); x86ms->acpi_dev = HOTPLUG_HANDLER(dev); } diff --git a/hw/loongarch/virt.c b/hw/loongarch/virt.c index 2952fe452e..4b7dc67a2d 100644 --- a/hw/loongarch/virt.c +++ b/hw/loongarch/virt.c @@ -412,6 +412,7 @@ static DeviceState *create_acpi_ged(DeviceState *pch_pic, LoongArchMachineState } dev = qdev_new(TYPE_ACPI_GED); qdev_prop_set_uint32(dev, "ged-event", event); + sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal); /* ged event */ sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, VIRT_GED_EVT_ADDR); @@ -422,7 +423,6 @@ static DeviceState *create_acpi_ged(DeviceState *pch_pic, LoongArchMachineState sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, qdev_get_gpio_in(pch_pic, VIRT_SCI_IRQ - VIRT_GSI_BASE)); - sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal); return dev; } From c85b843d177e48bb5367946ac6731073d32f831e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Wed, 18 Oct 2023 08:16:31 +0200 Subject: [PATCH 0958/1077] hw/arm/virt: Realize ARM_GICV2M sysbus device before accessing it MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit sysbus_mmio_map() should not be called on unrealized device. Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Thomas Huth Message-Id: <20231018141151.87466-8-philmd@linaro.org> --- hw/arm/virt.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/arm/virt.c b/hw/arm/virt.c index 02c7a7ff3c..5b08a98f07 100644 --- a/hw/arm/virt.c +++ b/hw/arm/virt.c @@ -690,10 +690,10 @@ static void create_v2m(VirtMachineState *vms) DeviceState *dev; dev = qdev_new("arm-gicv2m"); - sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, vms->memmap[VIRT_GIC_V2M].base); qdev_prop_set_uint32(dev, "base-spi", irq); qdev_prop_set_uint32(dev, "num-spi", NUM_GICV2M_SPIS); sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal); + sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, vms->memmap[VIRT_GIC_V2M].base); for (i = 0; i < NUM_GICV2M_SPIS; i++) { sysbus_connect_irq(SYS_BUS_DEVICE(dev), i, From 5a93fcfeeba7f0a4c766e7999fb778a2452d273e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Wed, 18 Oct 2023 14:41:33 +0200 Subject: [PATCH 0959/1077] hw/isa: Realize ISA bridge device before accessing it MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit qbus_new() should not be called on unrealized device. Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Michael S. Tsirkin Message-Id: <20231019071611.98885-9-philmd@linaro.org> --- hw/isa/isa-bus.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/hw/isa/isa-bus.c b/hw/isa/isa-bus.c index a289eccfb1..f1e0f14007 100644 --- a/hw/isa/isa-bus.c +++ b/hw/isa/isa-bus.c @@ -52,18 +52,25 @@ static const TypeInfo isa_bus_info = { ISABus *isa_bus_new(DeviceState *dev, MemoryRegion* address_space, MemoryRegion *address_space_io, Error **errp) { + DeviceState *bridge = NULL; + if (isabus) { error_setg(errp, "Can't create a second ISA bus"); return NULL; } if (!dev) { - dev = qdev_new("isabus-bridge"); - sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal); + bridge = qdev_new("isabus-bridge"); + dev = bridge; } isabus = ISA_BUS(qbus_new(TYPE_ISA_BUS, dev, NULL)); isabus->address_space = address_space; isabus->address_space_io = address_space_io; + + if (bridge) { + sysbus_realize_and_unref(SYS_BUS_DEVICE(bridge), &error_fatal); + } + return isabus; } From 7892e7cd916436a763705ba627619ca96b140ed6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Wed, 18 Oct 2023 14:34:42 +0200 Subject: [PATCH 0960/1077] hw/s390x/css-bridge: Realize sysbus device before accessing it MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit qbus_new() should not be called on unrealized device. Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Thomas Huth Message-Id: <20231019071611.98885-10-philmd@linaro.org> --- hw/s390x/css-bridge.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/hw/s390x/css-bridge.c b/hw/s390x/css-bridge.c index 4017081d49..15d26efc95 100644 --- a/hw/s390x/css-bridge.c +++ b/hw/s390x/css-bridge.c @@ -95,7 +95,6 @@ static const TypeInfo virtual_css_bus_info = { VirtualCssBus *virtual_css_bus_init(void) { - VirtualCssBus *cbus; BusState *bus; DeviceState *dev; @@ -103,19 +102,19 @@ VirtualCssBus *virtual_css_bus_init(void) dev = qdev_new(TYPE_VIRTUAL_CSS_BRIDGE); object_property_add_child(qdev_get_machine(), TYPE_VIRTUAL_CSS_BRIDGE, OBJECT(dev)); - sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal); /* Create bus on bridge device */ bus = qbus_new(TYPE_VIRTUAL_CSS_BUS, dev, "virtual-css"); - cbus = VIRTUAL_CSS_BUS(bus); /* Enable hotplugging */ qbus_set_hotplug_handler(bus, OBJECT(dev)); + sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal); + css_register_io_adapters(CSS_IO_ADAPTER_VIRTIO, true, false, 0, &error_abort); - return cbus; + return VIRTUAL_CSS_BUS(bus); } /***************** Virtual-css Bus Bridge Device ********************/ From 184256d261cfc773360f14a80092ace5a716bb8f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Mon, 16 Oct 2023 17:00:53 +0200 Subject: [PATCH 0961/1077] hw/virtio/virtio-pmem: Replace impossible check by assertion MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The get_memory_region() handler is used when (un)plugging the device, which can only occur *after* it is realized. virtio_pmem_realize() ensure the instance can not be realized without 'memdev'. Remove the superfluous check, replacing it by an assertion. Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Michael S. Tsirkin Reviewed-by: Manos Pitsidianakis Message-Id: <20231017140150.44995-2-philmd@linaro.org> --- hw/virtio/virtio-pmem.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/hw/virtio/virtio-pmem.c b/hw/virtio/virtio-pmem.c index c3512c2dae..cc24812d2e 100644 --- a/hw/virtio/virtio-pmem.c +++ b/hw/virtio/virtio-pmem.c @@ -147,10 +147,7 @@ static void virtio_pmem_fill_device_info(const VirtIOPMEM *pmem, static MemoryRegion *virtio_pmem_get_memory_region(VirtIOPMEM *pmem, Error **errp) { - if (!pmem->memdev) { - error_setg(errp, "'%s' property must be set", VIRTIO_PMEM_MEMDEV_PROP); - return NULL; - } + assert(pmem->memdev); return &pmem->memdev->mr; } From 312ecbe364defed43fb981f21e00cd24552272d6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Mon, 16 Oct 2023 17:00:13 +0200 Subject: [PATCH 0962/1077] hw/block/vhost-user-blk: Use DEVICE() / VIRTIO_DEVICE() macros MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Access QOM parent with the proper QOM [VIRTIO_]DEVICE() macros. Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Manos Pitsidianakis Reviewed-by: Mark Cave-Ayland Message-Id: <20231017140150.44995-3-philmd@linaro.org> --- hw/block/vhost-user-blk.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/hw/block/vhost-user-blk.c b/hw/block/vhost-user-blk.c index eecf3f7a81..4b37e26120 100644 --- a/hw/block/vhost-user-blk.c +++ b/hw/block/vhost-user-blk.c @@ -405,7 +405,7 @@ static void vhost_user_blk_event(void *opaque, QEMUChrEvent event) static int vhost_user_blk_realize_connect(VHostUserBlk *s, Error **errp) { - DeviceState *dev = &s->parent_obj.parent_obj; + DeviceState *dev = DEVICE(s); int ret; s->connected = false; @@ -423,7 +423,7 @@ static int vhost_user_blk_realize_connect(VHostUserBlk *s, Error **errp) assert(s->connected); ret = vhost_dev_get_config(&s->dev, (uint8_t *)&s->blkcfg, - s->parent_obj.config_len, errp); + VIRTIO_DEVICE(s)->config_len, errp); if (ret < 0) { qemu_chr_fe_disconnect(&s->chardev); vhost_dev_cleanup(&s->dev); From 9d7985a6bcff45d253d5551d965de636bf6a3b97 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Tue, 17 Oct 2023 15:53:54 +0200 Subject: [PATCH 0963/1077] hw/display/virtio-gpu: Use VIRTIO_DEVICE() macro MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Access QOM parent with the proper QOM VIRTIO_DEVICE() macro. Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Michael S. Tsirkin Reviewed-by: Manos Pitsidianakis Reviewed-by: Mark Cave-Ayland Message-Id: <20231017140150.44995-4-philmd@linaro.org> --- hw/display/virtio-gpu.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/display/virtio-gpu.c b/hw/display/virtio-gpu.c index 6efd15b6ae..4265316cbb 100644 --- a/hw/display/virtio-gpu.c +++ b/hw/display/virtio-gpu.c @@ -1128,7 +1128,7 @@ static void virtio_gpu_ctrl_bh(void *opaque) VirtIOGPU *g = opaque; VirtIOGPUClass *vgc = VIRTIO_GPU_GET_CLASS(g); - vgc->handle_ctrl(&g->parent_obj.parent_obj, g->ctrl_vq); + vgc->handle_ctrl(VIRTIO_DEVICE(g), g->ctrl_vq); } static void virtio_gpu_handle_cursor(VirtIODevice *vdev, VirtQueue *vq) From e84deec8b8ff45e1f118fc739f80a66046ae08e4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Mon, 16 Oct 2023 17:00:29 +0200 Subject: [PATCH 0964/1077] hw/scsi/virtio-scsi: Use VIRTIO_SCSI_COMMON() macro MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Access QOM parent with the proper QOM VIRTIO_SCSI_COMMON() macro. Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Michael S. Tsirkin Reviewed-by: Manos Pitsidianakis Reviewed-by: Mark Cave-Ayland Message-Id: <20231017140150.44995-5-philmd@linaro.org> --- hw/scsi/virtio-scsi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/scsi/virtio-scsi.c b/hw/scsi/virtio-scsi.c index 45b95ea070..fa53f0902c 100644 --- a/hw/scsi/virtio-scsi.c +++ b/hw/scsi/virtio-scsi.c @@ -761,7 +761,7 @@ static void virtio_scsi_fail_cmd_req(VirtIOSCSIReq *req) static int virtio_scsi_handle_cmd_req_prepare(VirtIOSCSI *s, VirtIOSCSIReq *req) { - VirtIOSCSICommon *vs = &s->parent_obj; + VirtIOSCSICommon *vs = VIRTIO_SCSI_COMMON(s); SCSIDevice *d; int rc; From 8802881e4d8d38c11e31c6b270686e4a0f874883 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Mon, 16 Oct 2023 16:18:05 +0200 Subject: [PATCH 0965/1077] hw/dma: Declare link using static DEFINE_PROP_LINK() macro MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Declare link statically using DEFINE_PROP_LINK(). Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Mark Cave-Ayland Message-Id: <20231017140150.44995-6-philmd@linaro.org> --- hw/dma/xilinx_axidma.c | 6 ++---- hw/dma/xlnx-zdma.c | 7 ++----- hw/dma/xlnx_csu_dma.c | 13 ++++--------- 3 files changed, 8 insertions(+), 18 deletions(-) diff --git a/hw/dma/xilinx_axidma.c b/hw/dma/xilinx_axidma.c index 12c90267df..0ae056ed06 100644 --- a/hw/dma/xilinx_axidma.c +++ b/hw/dma/xilinx_axidma.c @@ -577,10 +577,6 @@ static void xilinx_axidma_init(Object *obj) object_initialize_child(OBJECT(s), "axistream-control-connected-target", &s->rx_control_dev, TYPE_XILINX_AXI_DMA_CONTROL_STREAM); - object_property_add_link(obj, "dma", TYPE_MEMORY_REGION, - (Object **)&s->dma_mr, - qdev_prop_allow_set_link_before_realize, - OBJ_PROP_LINK_STRONG); sysbus_init_irq(sbd, &s->streams[0].irq); sysbus_init_irq(sbd, &s->streams[1].irq); @@ -596,6 +592,8 @@ static Property axidma_properties[] = { tx_data_dev, TYPE_STREAM_SINK, StreamSink *), DEFINE_PROP_LINK("axistream-control-connected", XilinxAXIDMA, tx_control_dev, TYPE_STREAM_SINK, StreamSink *), + DEFINE_PROP_LINK("dma", XilinxAXIDMA, dma_mr, + TYPE_MEMORY_REGION, MemoryRegion *), DEFINE_PROP_END_OF_LIST(), }; diff --git a/hw/dma/xlnx-zdma.c b/hw/dma/xlnx-zdma.c index 4eb7f66e9f..84c0083013 100644 --- a/hw/dma/xlnx-zdma.c +++ b/hw/dma/xlnx-zdma.c @@ -795,11 +795,6 @@ static void zdma_init(Object *obj) TYPE_XLNX_ZDMA, ZDMA_R_MAX * 4); sysbus_init_mmio(sbd, &s->iomem); sysbus_init_irq(sbd, &s->irq_zdma_ch_imr); - - object_property_add_link(obj, "dma", TYPE_MEMORY_REGION, - (Object **)&s->dma_mr, - qdev_prop_allow_set_link_before_realize, - OBJ_PROP_LINK_STRONG); } static const VMStateDescription vmstate_zdma = { @@ -817,6 +812,8 @@ static const VMStateDescription vmstate_zdma = { static Property zdma_props[] = { DEFINE_PROP_UINT32("bus-width", XlnxZDMA, cfg.bus_width, 64), + DEFINE_PROP_LINK("dma", XlnxZDMA, dma_mr, + TYPE_MEMORY_REGION, MemoryRegion *), DEFINE_PROP_END_OF_LIST(), }; diff --git a/hw/dma/xlnx_csu_dma.c b/hw/dma/xlnx_csu_dma.c index 88002698a1..e89089821a 100644 --- a/hw/dma/xlnx_csu_dma.c +++ b/hw/dma/xlnx_csu_dma.c @@ -702,6 +702,10 @@ static Property xlnx_csu_dma_properties[] = { * which channel the device is connected to. */ DEFINE_PROP_BOOL("is-dst", XlnxCSUDMA, is_dst, true), + DEFINE_PROP_LINK("stream-connected-dma", XlnxCSUDMA, tx_dev, + TYPE_STREAM_SINK, StreamSink *), + DEFINE_PROP_LINK("dma", XlnxCSUDMA, dma_mr, + TYPE_MEMORY_REGION, MemoryRegion *), DEFINE_PROP_END_OF_LIST(), }; @@ -728,15 +732,6 @@ static void xlnx_csu_dma_init(Object *obj) memory_region_init(&s->iomem, obj, TYPE_XLNX_CSU_DMA, XLNX_CSU_DMA_R_MAX * 4); - - object_property_add_link(obj, "stream-connected-dma", TYPE_STREAM_SINK, - (Object **)&s->tx_dev, - qdev_prop_allow_set_link_before_realize, - OBJ_PROP_LINK_STRONG); - object_property_add_link(obj, "dma", TYPE_MEMORY_REGION, - (Object **)&s->dma_mr, - qdev_prop_allow_set_link_before_realize, - OBJ_PROP_LINK_STRONG); } static const TypeInfo xlnx_csu_dma_info = { From 4f472537fa9842ad7facb76b63ea9b625033e40e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Mon, 16 Oct 2023 16:18:10 +0200 Subject: [PATCH 0966/1077] hw/net: Declare link using static DEFINE_PROP_LINK() macro MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Declare link statically using DEFINE_PROP_LINK(). Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Mark Cave-Ayland Message-Id: <20231017140150.44995-7-philmd@linaro.org> --- hw/net/cadence_gem.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/hw/net/cadence_gem.c b/hw/net/cadence_gem.c index f445d8bb5e..37e209cda6 100644 --- a/hw/net/cadence_gem.c +++ b/hw/net/cadence_gem.c @@ -1654,11 +1654,6 @@ static void gem_init(Object *obj) "enet", sizeof(s->regs)); sysbus_init_mmio(SYS_BUS_DEVICE(dev), &s->iomem); - - object_property_add_link(obj, "dma", TYPE_MEMORY_REGION, - (Object **)&s->dma_mr, - qdev_prop_allow_set_link_before_realize, - OBJ_PROP_LINK_STRONG); } static const VMStateDescription vmstate_cadence_gem = { @@ -1691,6 +1686,8 @@ static Property gem_properties[] = { num_type2_screeners, 4), DEFINE_PROP_UINT16("jumbo-max-len", CadenceGEMState, jumbo_max_len, 10240), + DEFINE_PROP_LINK("dma", CadenceGEMState, dma_mr, + TYPE_MEMORY_REGION, MemoryRegion *), DEFINE_PROP_END_OF_LIST(), }; From 9f1b100236223d073915b8eedac3089ec64f8a6e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Tue, 17 Oct 2023 15:05:00 +0200 Subject: [PATCH 0967/1077] ui/input: Constify QemuInputHandler structure MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Access to QemuInputHandlerState::handler are read-only. Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Marc-André Lureau Reviewed-by: Mark Cave-Ayland Message-Id: <20231017131251.43708-1-philmd@linaro.org> --- chardev/msmouse.c | 2 +- chardev/wctablet.c | 2 +- hw/char/escc.c | 2 +- hw/display/xenfb.c | 6 +++--- hw/input/adb-kbd.c | 2 +- hw/input/hid.c | 6 +++--- hw/input/ps2.c | 4 ++-- hw/input/virtio-input-hid.c | 8 ++++---- include/hw/virtio/virtio-input.h | 2 +- include/ui/input.h | 2 +- ui/input-legacy.c | 2 +- ui/input.c | 4 ++-- ui/vdagent.c | 2 +- 13 files changed, 22 insertions(+), 22 deletions(-) diff --git a/chardev/msmouse.c b/chardev/msmouse.c index ab8fe981d6..a774c397b4 100644 --- a/chardev/msmouse.c +++ b/chardev/msmouse.c @@ -171,7 +171,7 @@ static int msmouse_chr_write(struct Chardev *s, const uint8_t *buf, int len) return len; } -static QemuInputHandler msmouse_handler = { +static const QemuInputHandler msmouse_handler = { .name = "QEMU Microsoft Mouse", .mask = INPUT_EVENT_MASK_BTN | INPUT_EVENT_MASK_REL, .event = msmouse_input_event, diff --git a/chardev/wctablet.c b/chardev/wctablet.c index 43bdf6b608..f4008bf35b 100644 --- a/chardev/wctablet.c +++ b/chardev/wctablet.c @@ -178,7 +178,7 @@ static void wctablet_input_sync(DeviceState *dev) } } -static QemuInputHandler wctablet_handler = { +static const QemuInputHandler wctablet_handler = { .name = "QEMU Wacom Pen Tablet", .mask = INPUT_EVENT_MASK_BTN | INPUT_EVENT_MASK_ABS, .event = wctablet_input_event, diff --git a/hw/char/escc.c b/hw/char/escc.c index 4be66053c1..48b30ee760 100644 --- a/hw/char/escc.c +++ b/hw/char/escc.c @@ -845,7 +845,7 @@ static void sunkbd_handle_event(DeviceState *dev, QemuConsole *src, put_queue(s, keycode); } -static QemuInputHandler sunkbd_handler = { +static const QemuInputHandler sunkbd_handler = { .name = "sun keyboard", .mask = INPUT_EVENT_MASK_KEY, .event = sunkbd_handle_event, diff --git a/hw/display/xenfb.c b/hw/display/xenfb.c index 0074a9b6f8..b2130a0d70 100644 --- a/hw/display/xenfb.c +++ b/hw/display/xenfb.c @@ -321,20 +321,20 @@ static void xenfb_mouse_sync(DeviceState *dev) xenfb->wheel = 0; } -static QemuInputHandler xenfb_keyboard = { +static const QemuInputHandler xenfb_keyboard = { .name = "Xen PV Keyboard", .mask = INPUT_EVENT_MASK_KEY, .event = xenfb_key_event, }; -static QemuInputHandler xenfb_abs_mouse = { +static const QemuInputHandler xenfb_abs_mouse = { .name = "Xen PV Mouse", .mask = INPUT_EVENT_MASK_BTN | INPUT_EVENT_MASK_ABS, .event = xenfb_mouse_event, .sync = xenfb_mouse_sync, }; -static QemuInputHandler xenfb_rel_mouse = { +static const QemuInputHandler xenfb_rel_mouse = { .name = "Xen PV Mouse", .mask = INPUT_EVENT_MASK_BTN | INPUT_EVENT_MASK_REL, .event = xenfb_mouse_event, diff --git a/hw/input/adb-kbd.c b/hw/input/adb-kbd.c index a9088c910c..e21edf9acd 100644 --- a/hw/input/adb-kbd.c +++ b/hw/input/adb-kbd.c @@ -355,7 +355,7 @@ static void adb_kbd_reset(DeviceState *dev) s->count = 0; } -static QemuInputHandler adb_keyboard_handler = { +static const QemuInputHandler adb_keyboard_handler = { .name = "QEMU ADB Keyboard", .mask = INPUT_EVENT_MASK_KEY, .event = adb_keyboard_event, diff --git a/hw/input/hid.c b/hw/input/hid.c index a9c7dd1ce1..b8e85374ca 100644 --- a/hw/input/hid.c +++ b/hw/input/hid.c @@ -510,20 +510,20 @@ void hid_free(HIDState *hs) hid_del_idle_timer(hs); } -static QemuInputHandler hid_keyboard_handler = { +static const QemuInputHandler hid_keyboard_handler = { .name = "QEMU HID Keyboard", .mask = INPUT_EVENT_MASK_KEY, .event = hid_keyboard_event, }; -static QemuInputHandler hid_mouse_handler = { +static const QemuInputHandler hid_mouse_handler = { .name = "QEMU HID Mouse", .mask = INPUT_EVENT_MASK_BTN | INPUT_EVENT_MASK_REL, .event = hid_pointer_event, .sync = hid_pointer_sync, }; -static QemuInputHandler hid_tablet_handler = { +static const QemuInputHandler hid_tablet_handler = { .name = "QEMU HID Tablet", .mask = INPUT_EVENT_MASK_BTN | INPUT_EVENT_MASK_ABS, .event = hid_pointer_event, diff --git a/hw/input/ps2.c b/hw/input/ps2.c index 45af76a837..c8fd23cf36 100644 --- a/hw/input/ps2.c +++ b/hw/input/ps2.c @@ -1231,7 +1231,7 @@ static const VMStateDescription vmstate_ps2_mouse = { } }; -static QemuInputHandler ps2_keyboard_handler = { +static const QemuInputHandler ps2_keyboard_handler = { .name = "QEMU PS/2 Keyboard", .mask = INPUT_EVENT_MASK_KEY, .event = ps2_keyboard_event, @@ -1242,7 +1242,7 @@ static void ps2_kbd_realize(DeviceState *dev, Error **errp) qemu_input_handler_register(dev, &ps2_keyboard_handler); } -static QemuInputHandler ps2_mouse_handler = { +static const QemuInputHandler ps2_mouse_handler = { .name = "QEMU PS/2 Mouse", .mask = INPUT_EVENT_MASK_BTN | INPUT_EVENT_MASK_REL, .event = ps2_mouse_event, diff --git a/hw/input/virtio-input-hid.c b/hw/input/virtio-input-hid.c index 7053ad72d4..45e4d4c75d 100644 --- a/hw/input/virtio-input-hid.c +++ b/hw/input/virtio-input-hid.c @@ -265,7 +265,7 @@ static const TypeInfo virtio_input_hid_info = { /* ----------------------------------------------------------------- */ -static QemuInputHandler virtio_keyboard_handler = { +static const QemuInputHandler virtio_keyboard_handler = { .name = VIRTIO_ID_NAME_KEYBOARD, .mask = INPUT_EVENT_MASK_KEY, .event = virtio_input_handle_event, @@ -322,7 +322,7 @@ static const TypeInfo virtio_keyboard_info = { /* ----------------------------------------------------------------- */ -static QemuInputHandler virtio_mouse_handler = { +static const QemuInputHandler virtio_mouse_handler = { .name = VIRTIO_ID_NAME_MOUSE, .mask = INPUT_EVENT_MASK_BTN | INPUT_EVENT_MASK_REL, .event = virtio_input_handle_event, @@ -416,7 +416,7 @@ static const TypeInfo virtio_mouse_info = { /* ----------------------------------------------------------------- */ -static QemuInputHandler virtio_tablet_handler = { +static const QemuInputHandler virtio_tablet_handler = { .name = VIRTIO_ID_NAME_TABLET, .mask = INPUT_EVENT_MASK_BTN | INPUT_EVENT_MASK_ABS, .event = virtio_input_handle_event, @@ -541,7 +541,7 @@ static const TypeInfo virtio_tablet_info = { /* ----------------------------------------------------------------- */ -static QemuInputHandler virtio_multitouch_handler = { +static const QemuInputHandler virtio_multitouch_handler = { .name = VIRTIO_ID_NAME_MULTITOUCH, .mask = INPUT_EVENT_MASK_BTN | INPUT_EVENT_MASK_MTT, .event = virtio_input_handle_event, diff --git a/include/hw/virtio/virtio-input.h b/include/hw/virtio/virtio-input.h index 08f1591424..a6c9703644 100644 --- a/include/hw/virtio/virtio-input.h +++ b/include/hw/virtio/virtio-input.h @@ -84,7 +84,7 @@ struct VirtIOInputHID { VirtIOInput parent_obj; char *display; uint32_t head; - QemuInputHandler *handler; + const QemuInputHandler *handler; QemuInputHandlerState *hs; int ledstate; bool wheel_axis; diff --git a/include/ui/input.h b/include/ui/input.h index 24d8e4579e..8f9aac562e 100644 --- a/include/ui/input.h +++ b/include/ui/input.h @@ -30,7 +30,7 @@ struct QemuInputHandler { }; QemuInputHandlerState *qemu_input_handler_register(DeviceState *dev, - QemuInputHandler *handler); + const QemuInputHandler *handler); void qemu_input_handler_activate(QemuInputHandlerState *s); void qemu_input_handler_deactivate(QemuInputHandlerState *s); void qemu_input_handler_unregister(QemuInputHandlerState *s); diff --git a/ui/input-legacy.c b/ui/input-legacy.c index 46ea74e44d..210ae5eaca 100644 --- a/ui/input-legacy.c +++ b/ui/input-legacy.c @@ -127,7 +127,7 @@ static void legacy_kbd_event(DeviceState *dev, QemuConsole *src, } } -static QemuInputHandler legacy_kbd_handler = { +static const QemuInputHandler legacy_kbd_handler = { .name = "legacy-kbd", .mask = INPUT_EVENT_MASK_KEY, .event = legacy_kbd_event, diff --git a/ui/input.c b/ui/input.c index cbe8573c5c..dc745860f4 100644 --- a/ui/input.c +++ b/ui/input.c @@ -10,7 +10,7 @@ struct QemuInputHandlerState { DeviceState *dev; - QemuInputHandler *handler; + const QemuInputHandler *handler; int id; int events; QemuConsole *con; @@ -46,7 +46,7 @@ static uint32_t queue_count; static uint32_t queue_limit = 1024; QemuInputHandlerState *qemu_input_handler_register(DeviceState *dev, - QemuInputHandler *handler) + const QemuInputHandler *handler) { QemuInputHandlerState *s = g_new0(QemuInputHandlerState, 1); static int id = 1; diff --git a/ui/vdagent.c b/ui/vdagent.c index 00d36a8677..706d6d97bd 100644 --- a/ui/vdagent.c +++ b/ui/vdagent.c @@ -297,7 +297,7 @@ static void vdagent_pointer_sync(DeviceState *dev) } } -static QemuInputHandler vdagent_mouse_handler = { +static const QemuInputHandler vdagent_mouse_handler = { .name = "vdagent mouse", .mask = INPUT_EVENT_MASK_BTN | INPUT_EVENT_MASK_ABS, .event = vdagent_pointer_event, From 4ab9a7429bf7507fba4b96b97d4147628c91ba14 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Thu, 19 Oct 2023 15:47:47 +0100 Subject: [PATCH 0968/1077] hw/rdma/vmw/pvrdma_cmd: Use correct struct in query_port() In query_port() we pass the address of a local pvrdma_port_attr struct to the rdma_query_backend_port() function. Unfortunately, rdma_backend_query_port() wants a pointer to a struct ibv_port_attr, and the two are not the same length. Coverity spotted this (CID 1507146): pvrdma_port_attr is 48 bytes long, and ibv_port_attr is 52 bytes, because it has a few extra fields at the end. Fortunately, all we do with the attrs struct after the call is to read a few specific fields out of it which are all at the same offsets in both structs, so we can simply make the local variable the correct type. This also lets us drop the cast (which should have been a bit of a warning flag that we were doing something wrong here). We do however need to add extra casts for the fields of the struct that are enums: clang will complain about the implicit cast to a different enum type otherwise. Cc: qemu-stable@nongnu.org Signed-off-by: Peter Maydell Signed-off-by: Michael Tokarev --- hw/rdma/vmw/pvrdma_cmd.c | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/hw/rdma/vmw/pvrdma_cmd.c b/hw/rdma/vmw/pvrdma_cmd.c index c6ed025982..d385d18d9c 100644 --- a/hw/rdma/vmw/pvrdma_cmd.c +++ b/hw/rdma/vmw/pvrdma_cmd.c @@ -129,23 +129,27 @@ static int query_port(PVRDMADev *dev, union pvrdma_cmd_req *req, { struct pvrdma_cmd_query_port *cmd = &req->query_port; struct pvrdma_cmd_query_port_resp *resp = &rsp->query_port_resp; - struct pvrdma_port_attr attrs = {}; + struct ibv_port_attr attrs = {}; if (cmd->port_num > MAX_PORTS) { return -EINVAL; } - if (rdma_backend_query_port(&dev->backend_dev, - (struct ibv_port_attr *)&attrs)) { + if (rdma_backend_query_port(&dev->backend_dev, &attrs)) { return -ENOMEM; } memset(resp, 0, sizeof(*resp)); - resp->attrs.state = dev->func0->device_active ? attrs.state : - PVRDMA_PORT_DOWN; - resp->attrs.max_mtu = attrs.max_mtu; - resp->attrs.active_mtu = attrs.active_mtu; + /* + * The state, max_mtu and active_mtu fields are enums; the values + * for pvrdma_port_state and pvrdma_mtu match those for + * ibv_port_state and ibv_mtu, so we can cast them safely. + */ + resp->attrs.state = dev->func0->device_active ? + (enum pvrdma_port_state)attrs.state : PVRDMA_PORT_DOWN; + resp->attrs.max_mtu = (enum pvrdma_mtu)attrs.max_mtu; + resp->attrs.active_mtu = (enum pvrdma_mtu)attrs.active_mtu; resp->attrs.phys_state = attrs.phys_state; resp->attrs.gid_tbl_len = MIN(MAX_PORT_GIDS, attrs.gid_tbl_len); resp->attrs.max_msg_sz = 1024; From 0affd6785a243c8a8460abbfc4caf991e71ff9c6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Wed, 11 Oct 2023 16:07:21 +0200 Subject: [PATCH 0969/1077] hw/ppc/ppc440_uc: Remove dead l2sram_update_mappings() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Apparently l2sram_update_mappings() bit-rotted over time, when defining MAP_L2SRAM we get: hw/ppc/ppc440_uc.c:83:17: error: no member named 'isarc' in 'struct ppc4xx_l2sram_t' if (l2sram->isarc != isarc || ~~~~~~ ^ hw/ppc/ppc440_uc.c:84:18: error: no member named 'isacntl' in 'struct ppc4xx_l2sram_t' (l2sram->isacntl & 0x80000000) != (isacntl & 0x80000000)) { ~~~~~~ ^ hw/ppc/ppc440_uc.c:85:21: error: no member named 'isacntl' in 'struct ppc4xx_l2sram_t' if (l2sram->isacntl & 0x80000000) { ~~~~~~ ^ hw/ppc/ppc440_uc.c:88:50: error: no member named 'isarc_ram' in 'struct ppc4xx_l2sram_t' &l2sram->isarc_ram); ~~~~~~ ^ hw/ppc/ppc440_uc.c:93:50: error: no member named 'isarc_ram' in 'struct ppc4xx_l2sram_t' &l2sram->isarc_ram); ~~~~~~ ^ hw/ppc/ppc440_uc.c:96:17: error: no member named 'dsarc' in 'struct ppc4xx_l2sram_t' if (l2sram->dsarc != dsarc || ~~~~~~ ^ hw/ppc/ppc440_uc.c:97:18: error: no member named 'dsacntl' in 'struct ppc4xx_l2sram_t' (l2sram->dsacntl & 0x80000000) != (dsacntl & 0x80000000)) { ~~~~~~ ^ hw/ppc/ppc440_uc.c:98:21: error: no member named 'dsacntl' in 'struct ppc4xx_l2sram_t' if (l2sram->dsacntl & 0x80000000) { ~~~~~~ ^ hw/ppc/ppc440_uc.c:100:52: error: no member named 'dsarc' in 'struct ppc4xx_l2sram_t' if (!(isacntl & 0x80000000) || l2sram->dsarc != isarc) { ~~~~~~ ^ hw/ppc/ppc440_uc.c:103:54: error: no member named 'dsarc_ram' in 'struct ppc4xx_l2sram_t' &l2sram->dsarc_ram); ~~~~~~ ^ hw/ppc/ppc440_uc.c:111:54: error: no member named 'dsarc_ram' in 'struct ppc4xx_l2sram_t' &l2sram->dsarc_ram); ~~~~~~ ^ Remove that dead code. Reviewed-by: BALATON Zoltan Signed-off-by: Philippe Mathieu-Daudé Signed-off-by: Michael Tokarev --- hw/ppc/ppc440_uc.c | 42 ------------------------------------------ 1 file changed, 42 deletions(-) diff --git a/hw/ppc/ppc440_uc.c b/hw/ppc/ppc440_uc.c index 4181c843a8..7d6ca70387 100644 --- a/hw/ppc/ppc440_uc.c +++ b/hw/ppc/ppc440_uc.c @@ -73,46 +73,6 @@ typedef struct ppc4xx_l2sram_t { uint32_t isram0[11]; } ppc4xx_l2sram_t; -#ifdef MAP_L2SRAM -static void l2sram_update_mappings(ppc4xx_l2sram_t *l2sram, - uint32_t isarc, uint32_t isacntl, - uint32_t dsarc, uint32_t dsacntl) -{ - if (l2sram->isarc != isarc || - (l2sram->isacntl & 0x80000000) != (isacntl & 0x80000000)) { - if (l2sram->isacntl & 0x80000000) { - /* Unmap previously assigned memory region */ - memory_region_del_subregion(get_system_memory(), - &l2sram->isarc_ram); - } - if (isacntl & 0x80000000) { - /* Map new instruction memory region */ - memory_region_add_subregion(get_system_memory(), isarc, - &l2sram->isarc_ram); - } - } - if (l2sram->dsarc != dsarc || - (l2sram->dsacntl & 0x80000000) != (dsacntl & 0x80000000)) { - if (l2sram->dsacntl & 0x80000000) { - /* Beware not to unmap the region we just mapped */ - if (!(isacntl & 0x80000000) || l2sram->dsarc != isarc) { - /* Unmap previously assigned memory region */ - memory_region_del_subregion(get_system_memory(), - &l2sram->dsarc_ram); - } - } - if (dsacntl & 0x80000000) { - /* Beware not to remap the region we just mapped */ - if (!(isacntl & 0x80000000) || dsarc != isarc) { - /* Map new data memory region */ - memory_region_add_subregion(get_system_memory(), dsarc, - &l2sram->dsarc_ram); - } - } - } -} -#endif - static uint32_t dcr_read_l2sram(void *opaque, int dcrn) { ppc4xx_l2sram_t *l2sram = opaque; @@ -193,7 +153,6 @@ static void dcr_write_l2sram(void *opaque, int dcrn, uint32_t val) /*l2sram->isram1[dcrn - DCR_L2CACHE_BASE] = val;*/ break; } - /*l2sram_update_mappings(l2sram, isarc, isacntl, dsarc, dsacntl);*/ } static void l2sram_reset(void *opaque) @@ -203,7 +162,6 @@ static void l2sram_reset(void *opaque) memset(l2sram->l2cache, 0, sizeof(l2sram->l2cache)); l2sram->l2cache[DCR_L2CACHE_STAT - DCR_L2CACHE_BASE] = 0x80000000; memset(l2sram->isram0, 0, sizeof(l2sram->isram0)); - /*l2sram_update_mappings(l2sram, isarc, isacntl, dsarc, dsacntl);*/ } void ppc4xx_l2sram_init(CPUPPCState *env) From b3e1216aa9f721ef096edf62f845ab4205e95b44 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Wed, 11 Oct 2023 16:07:20 +0200 Subject: [PATCH 0970/1077] MAINTAINERS: Cover hw/ppc/ppc440_uc.c with Sam460ex board MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit hw/ppc/ppc440_uc.c implements the TYPE_PPC460EX_PCIE_HOST device, which is used by the aCube Sam460ex board. Signed-off-by: Philippe Mathieu-Daudé Acked-by: BALATON Zoltan Signed-off-by: Michael Tokarev --- MAINTAINERS | 1 + 1 file changed, 1 insertion(+) diff --git a/MAINTAINERS b/MAINTAINERS index 7f9912baa0..c814ed04c4 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1495,6 +1495,7 @@ M: BALATON Zoltan L: qemu-ppc@nongnu.org S: Maintained F: hw/ppc/sam460ex.c +F: hw/ppc/ppc440_uc.c F: hw/ppc/ppc440_pcix.c F: hw/display/sm501* F: hw/ide/sii3112.c From 1805c2b1da391aea46c52abcdef8b9f388e11f3d Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Fri, 13 Oct 2023 08:54:08 +0200 Subject: [PATCH 0971/1077] MAINTAINERS: Add the nios2 interrupt controller to the nios2 section These files obviously belong to the nios2 target, so they should be listed in the nios2 section in the MAINTAINERS file. Signed-off-by: Thomas Huth Signed-off-by: Michael Tokarev --- MAINTAINERS | 2 ++ 1 file changed, 2 insertions(+) diff --git a/MAINTAINERS b/MAINTAINERS index c814ed04c4..5732d2f6ad 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -284,7 +284,9 @@ R: Marek Vasut S: Orphan F: target/nios2/ F: hw/nios2/ +F: hw/intc/nios2_vic.c F: disas/nios2.c +F: include/hw/intc/nios2_vic.h F: configs/devices/nios2-softmmu/default.mak F: tests/docker/dockerfiles/debian-nios2-cross.d/build-toolchain.sh F: tests/tcg/nios2/ From 6345897057834644095975db98593f5034a98e3f Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Tue, 17 Oct 2023 17:26:25 +0200 Subject: [PATCH 0972/1077] MAINTAINERS: Add include/hw/intc/i8259.h to the PC chip section i8259.c is already listed here, so the corresponding header should be mentioned in this section, too. Signed-off-by: Thomas Huth Signed-off-by: Michael Tokarev --- MAINTAINERS | 1 + 1 file changed, 1 insertion(+) diff --git a/MAINTAINERS b/MAINTAINERS index 5732d2f6ad..ab95af5be2 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1781,6 +1781,7 @@ F: include/hw/dma/i8257.h F: include/hw/i2c/pm_smbus.h F: include/hw/input/i8042.h F: include/hw/intc/ioapic* +F: include/hw/intc/i8259.h F: include/hw/isa/i8259_internal.h F: include/hw/isa/superio.h F: include/hw/timer/hpet.h From 2635f961b0aff7fa2e4958cce1059b8d10881b60 Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Tue, 17 Oct 2023 17:17:40 +0200 Subject: [PATCH 0973/1077] MAINTAINERS: Add docs/devel/ebpf_rss.rst to the EBPF section MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This doc file obviously belongs to the EBPF section. Signed-off-by: Thomas Huth Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Michael Tokarev --- MAINTAINERS | 1 + 1 file changed, 1 insertion(+) diff --git a/MAINTAINERS b/MAINTAINERS index ab95af5be2..27e5b882ae 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -3940,6 +3940,7 @@ M: Jason Wang R: Andrew Melnychenko R: Yuri Benditovich S: Maintained +F: docs/devel/ebpf_rss.rst F: ebpf/* F: tools/ebpf/* From 5cf9a81e3400edcee408a25dff9ed30a07650eb8 Mon Sep 17 00:00:00 2001 From: Eric Farman Date: Fri, 20 Oct 2023 16:15:09 +0200 Subject: [PATCH 0974/1077] MAINTAINERS: Fix a couple s390 paths MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit These are simple typos, since the directories don't exist but the files themselves do in hw/s390x/ Fixes: 56e3483402 ("MAINTAINERS: split out s390x sections") Signed-off-by: Eric Farman Reviewed-by: Claudio Imbrenda Reviewed-by: Thomas Huth Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Michael Tokarev --- MAINTAINERS | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/MAINTAINERS b/MAINTAINERS index 27e5b882ae..167f0fe3ac 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -2602,7 +2602,7 @@ M: Halil Pasic M: Christian Borntraeger S: Supported F: hw/s390x/storage-keys.h -F: hw/390x/s390-skeys*.c +F: hw/s390x/s390-skeys*.c L: qemu-s390x@nongnu.org S390 storage attribute device @@ -2610,7 +2610,7 @@ M: Halil Pasic M: Christian Borntraeger S: Supported F: hw/s390x/storage-attributes.h -F: hw/s390/s390-stattrib*.c +F: hw/s390x/s390-stattrib*.c L: qemu-s390x@nongnu.org S390 floating interrupt controller From 64cf81b8128196823cc0ea15d84952d7c5c21dd4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Le=20Goater?= Date: Mon, 2 Oct 2023 17:51:36 +0200 Subject: [PATCH 0975/1077] ppc/{bamboo, virtex_ml507}: Remove useless dependency on ppc405.h header MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Cc: "Edgar E. Iglesias" (odd fixer:virtex_ml507) Reviewed-by: Daniel Henrique Barboza Signed-off-by: Cédric Le Goater Signed-off-by: Michael Tokarev --- hw/ppc/ppc440_bamboo.c | 1 - hw/ppc/virtex_ml507.c | 1 - 2 files changed, 2 deletions(-) diff --git a/hw/ppc/ppc440_bamboo.c b/hw/ppc/ppc440_bamboo.c index 45f409c838..a189942de4 100644 --- a/hw/ppc/ppc440_bamboo.c +++ b/hw/ppc/ppc440_bamboo.c @@ -24,7 +24,6 @@ #include "elf.h" #include "hw/char/serial.h" #include "hw/ppc/ppc.h" -#include "ppc405.h" #include "sysemu/sysemu.h" #include "sysemu/reset.h" #include "hw/sysbus.h" diff --git a/hw/ppc/virtex_ml507.c b/hw/ppc/virtex_ml507.c index f2f81bd425..d02f330650 100644 --- a/hw/ppc/virtex_ml507.c +++ b/hw/ppc/virtex_ml507.c @@ -43,7 +43,6 @@ #include "hw/ppc/ppc.h" #include "hw/ppc/ppc4xx.h" #include "hw/qdev-properties.h" -#include "ppc405.h" #include From 6d7144604fb36149d3ddd69c52e33a01076ea8c2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Le=20Goater?= Date: Mon, 2 Oct 2023 17:51:37 +0200 Subject: [PATCH 0976/1077] MAINTAINERS: Adjust file list for PPC ref405ep machine MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Daniel Henrique Barboza Signed-off-by: Cédric Le Goater Signed-off-by: Michael Tokarev --- MAINTAINERS | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/MAINTAINERS b/MAINTAINERS index 167f0fe3ac..af1fc5d76d 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1367,7 +1367,8 @@ PowerPC Machines 405 (ref405ep) L: qemu-ppc@nongnu.org S: Orphan -F: hw/ppc/ppc405_boards.c +F: hw/ppc/ppc405* +F: tests/avocado/ppc_405.py Bamboo L: qemu-ppc@nongnu.org From e20dbe54f2df52719a698739f10195e31e7f992d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Le=20Goater?= Date: Mon, 2 Oct 2023 17:51:38 +0200 Subject: [PATCH 0977/1077] MAINTAINERS: Adjust file list for PPC 4xx CPUs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Reviewed-by: Daniel Henrique Barboza Signed-off-by: Cédric Le Goater Signed-off-by: Michael Tokarev --- MAINTAINERS | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/MAINTAINERS b/MAINTAINERS index af1fc5d76d..ddac1eea9d 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1998,7 +1998,9 @@ F: docs/specs/acpi_hest_ghes.rst ppc4xx L: qemu-ppc@nongnu.org S: Orphan -F: hw/ppc/ppc4*.c +F: hw/ppc/ppc4xx*.c +F: hw/ppc/ppc440_uc.c +F: hw/ppc/ppc440.h F: hw/i2c/ppc4xx_i2c.c F: include/hw/ppc/ppc4xx.h F: include/hw/i2c/ppc4xx_i2c.h From ab8e1af2475bd26e8a2d6b9dd14782a8cfec1032 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Le=20Goater?= Date: Mon, 2 Oct 2023 17:51:39 +0200 Subject: [PATCH 0978/1077] MAINTAINERS: Adjust file list for PPC e500 machines MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Reviewed-by: Daniel Henrique Barboza Signed-off-by: Cédric Le Goater Signed-off-by: Michael Tokarev --- MAINTAINERS | 2 ++ 1 file changed, 2 insertions(+) diff --git a/MAINTAINERS b/MAINTAINERS index ddac1eea9d..da5bff8ec0 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1380,6 +1380,7 @@ e500 L: qemu-ppc@nongnu.org S: Orphan F: hw/ppc/e500* +F: hw/ppc/ppce500_spin.c F: hw/gpio/mpc8xxx.c F: hw/i2c/mpc_i2c.c F: hw/net/fsl_etsec/ @@ -1389,6 +1390,7 @@ F: include/hw/pci-host/ppce500.h F: pc-bios/u-boot.e500 F: hw/intc/openpic_kvm.h F: include/hw/ppc/openpic_kvm.h +F: docs/system/ppc/ppce500.rst mpc8544ds L: qemu-ppc@nongnu.org From d79d9989764f1a645312fe5bea6dc4ebb3d9e1cf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Le=20Goater?= Date: Mon, 2 Oct 2023 17:51:40 +0200 Subject: [PATCH 0979/1077] MAINTAINERS: Adjust file list for PPC pseries machine MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The fdt.{c.h} files provide a helper routine used by the pseries and pnv machines. Attached it to the list of the larger one: pseries. Protected Execution Facility (PEF) is the confidential guest support for PPC pseries machines. Reviewed-by: Daniel Henrique Barboza Signed-off-by: Cédric Le Goater Signed-off-by: Michael Tokarev --- MAINTAINERS | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/MAINTAINERS b/MAINTAINERS index da5bff8ec0..303f4c7900 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1463,6 +1463,10 @@ F: hw/*/spapr* F: include/hw/*/spapr* F: hw/*/xics* F: include/hw/*/xics* +F: include/hw/ppc/fdt.h +F: hw/ppc/fdt.c +F: include/hw/ppc/pef.h +F: hw/ppc/pef.c F: pc-bios/slof.bin F: docs/system/ppc/pseries.rst F: docs/specs/ppc-spapr-* From 6198558781f5d8abde33f2f05d3c6015140d74d8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Le=20Goater?= Date: Mon, 2 Oct 2023 17:51:41 +0200 Subject: [PATCH 0980/1077] MAINTAINERS: Add fw_cfg.c to PPC mac99 machine MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The hw/ppc/fw_cfg.c file contains the implementation of fw_cfg_arch_key_name(), used by the common nvram model. List it under mac99 machine next to the mac_nvram model. Cc: Mark Cave-Ayland Reviewed-by: Daniel Henrique Barboza Reviewed-by: Mark Cave-Ayland Signed-off-by: Cédric Le Goater Signed-off-by: Michael Tokarev --- MAINTAINERS | 1 + 1 file changed, 1 insertion(+) diff --git a/MAINTAINERS b/MAINTAINERS index 303f4c7900..543a6be00d 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1410,6 +1410,7 @@ F: hw/pci-bridge/dec.[hc] F: hw/misc/macio/ F: hw/misc/mos6522.c F: hw/nvram/mac_nvram.c +F: hw/ppc/fw_cfg.c F: hw/input/adb* F: include/hw/misc/macio/ F: include/hw/misc/mos6522.h From 9c46b512e3a49e2b60a735ba603d44c07b9f4668 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Le=20Goater?= Date: Mon, 2 Oct 2023 17:51:42 +0200 Subject: [PATCH 0981/1077] MAINTAINERS: Add PPC common files to PowerPC TCG CPUs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Reviewed-by: Daniel Henrique Barboza Signed-off-by: Cédric Le Goater Signed-off-by: Michael Tokarev --- MAINTAINERS | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/MAINTAINERS b/MAINTAINERS index 543a6be00d..6b1f9747d4 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -310,6 +310,11 @@ F: target/ppc/ F: hw/ppc/ppc.c F: hw/ppc/ppc_booke.c F: include/hw/ppc/ppc.h +F: hw/ppc/meson.build +F: hw/ppc/trace* +F: configs/devices/ppc* +F: docs/system/ppc/embedded.rst +F: docs/system/target-ppc.rst RISC-V TCG CPUs M: Palmer Dabbelt From 71c1d34455d59cd7772f473354906ee08c877225 Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Wed, 18 Oct 2023 08:24:01 +0200 Subject: [PATCH 0982/1077] MAINTAINERS: Add unvalued folders in tests/tcg/ to the right sections MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Some subfolders in tests/tcg/ are already listed in the MAINTAINERS file, some others aren't listed yet. Add the missing ones now to the MAINTAINERS file, too, to make sure that get_maintainers.pl reports the correct maintainer. Signed-off-by: Thomas Huth Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Cédric Le Goater Signed-off-by: Michael Tokarev --- MAINTAINERS | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/MAINTAINERS b/MAINTAINERS index 6b1f9747d4..00b145280b 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -245,6 +245,7 @@ M: Richard Henderson S: Maintained F: target/hppa/ F: disas/hppa.c +F: tests/tcg/hppa/ LoongArch TCG CPUs M: Song Gao @@ -258,6 +259,7 @@ M: Laurent Vivier S: Maintained F: target/m68k/ F: disas/m68k.c +F: tests/tcg/m68k/ MicroBlaze TCG CPUs M: Edgar E. Iglesias @@ -315,6 +317,7 @@ F: hw/ppc/trace* F: configs/devices/ppc* F: docs/system/ppc/embedded.rst F: docs/system/target-ppc.rst +F: tests/tcg/ppc*/* RISC-V TCG CPUs M: Palmer Dabbelt @@ -333,6 +336,7 @@ F: hw/intc/riscv* F: include/hw/riscv/ F: linux-user/host/riscv32/ F: linux-user/host/riscv64/ +F: tests/tcg/riscv64/ RISC-V XThead* extensions M: Christoph Muellner @@ -374,6 +378,7 @@ F: target/sh4/ F: hw/sh4/ F: disas/sh4.c F: include/hw/sh4/ +F: tests/tcg/sh4/ SPARC TCG CPUs M: Mark Cave-Ayland @@ -384,6 +389,7 @@ F: hw/sparc/ F: hw/sparc64/ F: include/hw/sparc/sparc64.h F: disas/sparc.c +F: tests/tcg/sparc64/ X86 TCG CPUs M: Paolo Bonzini From b96a7487d589fe3beb1d63fdb0be30f6a6311a44 Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Thu, 19 Oct 2023 17:58:22 +0200 Subject: [PATCH 0983/1077] MAINTAINERS: Fix typo in openpic_kvm.c entry MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit It's a .c file, not a header! Fixes: ff8cdbbd7e ("MAINTAINERS: Add information for OpenPIC") Signed-off-by: Thomas Huth Reviewed-by: Cédric Le Goater Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Michael Tokarev --- MAINTAINERS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MAINTAINERS b/MAINTAINERS index 00b145280b..7fd7a0201c 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1399,7 +1399,7 @@ F: hw/pci-host/ppce500.c F: include/hw/ppc/ppc_e500.h F: include/hw/pci-host/ppce500.h F: pc-bios/u-boot.e500 -F: hw/intc/openpic_kvm.h +F: hw/intc/openpic_kvm.c F: include/hw/ppc/openpic_kvm.h F: docs/system/ppc/ppce500.rst From a4a2f7f8161ed1dbaa748350c4bc2d86c4d77d97 Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Fri, 20 Oct 2023 08:24:48 +0200 Subject: [PATCH 0984/1077] MAINTAINERS: Add the ompic.c file to the or1k-sim section The or1k-sim machine is the only one using the ompic, so let's add this file to the corresponding sections in the MAINTAINERS file. Signed-off-by: Thomas Huth Signed-off-by: Michael Tokarev --- MAINTAINERS | 1 + 1 file changed, 1 insertion(+) diff --git a/MAINTAINERS b/MAINTAINERS index 7fd7a0201c..65b7a05070 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1371,6 +1371,7 @@ or1k-sim M: Jia Liu S: Maintained F: docs/system/openrisc/or1k-sim.rst +F: hw/intc/ompic.c F: hw/openrisc/openrisc_sim.c PowerPC Machines From 1428831981edc53fe819f76d07306f6b041fe55c Mon Sep 17 00:00:00 2001 From: Laszlo Ersek Date: Mon, 2 Oct 2023 22:32:15 +0200 Subject: [PATCH 0985/1077] vhost-user: strip superfluous whitespace MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Cc: "Michael S. Tsirkin" (supporter:vhost) Cc: Eugenio Perez Martin Cc: German Maglione Cc: Liu Jiang Cc: Sergio Lopez Pascual Cc: Stefano Garzarella Signed-off-by: Laszlo Ersek Reviewed-by: Stefano Garzarella Reviewed-by: Philippe Mathieu-Daudé Tested-by: Albert Esteve Reviewed-by: Eugenio Pérez Message-Id: <20231002203221.17241-2-lersek@redhat.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/virtio/vhost-user.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/virtio/vhost-user.c b/hw/virtio/vhost-user.c index 68eb1f0c99..3e33a2e9e0 100644 --- a/hw/virtio/vhost-user.c +++ b/hw/virtio/vhost-user.c @@ -388,7 +388,7 @@ static int vhost_user_write(struct vhost_dev *dev, VhostUserMsg *msg, * operations such as configuring device memory mappings or issuing device * resets, which affect the whole device instead of individual VQs, * vhost-user messages should only be sent once. - * + * * Devices with multiple vhost_devs are given an associated dev->vq_index * so per_device requests are only sent if vq_index is 0. */ From ed0b3ebbae4d3afd9f742613ed64444e4d04ae0a Mon Sep 17 00:00:00 2001 From: Laszlo Ersek Date: Mon, 2 Oct 2023 22:32:16 +0200 Subject: [PATCH 0986/1077] vhost-user: tighten "reply_supported" scope in "set_vring_addr" MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In the vhost_user_set_vring_addr() function, we calculate "reply_supported" unconditionally, even though we'll only need it if "wait_for_reply" is also true. Restrict the scope of "reply_supported" to the minimum. This is purely refactoring -- no observable change. Cc: "Michael S. Tsirkin" (supporter:vhost) Cc: Eugenio Perez Martin Cc: German Maglione Cc: Liu Jiang Cc: Sergio Lopez Pascual Cc: Stefano Garzarella Signed-off-by: Laszlo Ersek Reviewed-by: Stefano Garzarella Tested-by: Albert Esteve Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Eugenio Pérez Message-Id: <20231002203221.17241-3-lersek@redhat.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/virtio/vhost-user.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/hw/virtio/vhost-user.c b/hw/virtio/vhost-user.c index 3e33a2e9e0..6c7b4cc75c 100644 --- a/hw/virtio/vhost-user.c +++ b/hw/virtio/vhost-user.c @@ -1321,17 +1321,18 @@ static int vhost_user_set_vring_addr(struct vhost_dev *dev, .hdr.size = sizeof(msg.payload.addr), }; - bool reply_supported = virtio_has_feature(dev->protocol_features, - VHOST_USER_PROTOCOL_F_REPLY_ACK); - /* * wait for a reply if logging is enabled to make sure * backend is actually logging changes */ bool wait_for_reply = addr->flags & (1 << VHOST_VRING_F_LOG); - if (reply_supported && wait_for_reply) { - msg.hdr.flags |= VHOST_USER_NEED_REPLY_MASK; + if (wait_for_reply) { + bool reply_supported = virtio_has_feature(dev->protocol_features, + VHOST_USER_PROTOCOL_F_REPLY_ACK); + if (reply_supported) { + msg.hdr.flags |= VHOST_USER_NEED_REPLY_MASK; + } } ret = vhost_user_write(dev, &msg, NULL, 0); From 54ae36822f6f14603ed117b09fd1b59d6ebfb963 Mon Sep 17 00:00:00 2001 From: Laszlo Ersek Date: Mon, 2 Oct 2023 22:32:17 +0200 Subject: [PATCH 0987/1077] vhost-user: factor out "vhost_user_write_sync" MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The tails of the "vhost_user_set_vring_addr" and "vhost_user_set_u64" functions are now byte-for-byte identical. Factor the common tail out to a new function called "vhost_user_write_sync". This is purely refactoring -- no observable change. Cc: "Michael S. Tsirkin" (supporter:vhost) Cc: Eugenio Perez Martin Cc: German Maglione Cc: Liu Jiang Cc: Sergio Lopez Pascual Cc: Stefano Garzarella Signed-off-by: Laszlo Ersek Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Stefano Garzarella Tested-by: Albert Esteve Reviewed-by: Eugenio Pérez Message-Id: <20231002203221.17241-4-lersek@redhat.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/virtio/vhost-user.c | 66 ++++++++++++++++++------------------------ 1 file changed, 28 insertions(+), 38 deletions(-) diff --git a/hw/virtio/vhost-user.c b/hw/virtio/vhost-user.c index 6c7b4cc75c..95dbf9880c 100644 --- a/hw/virtio/vhost-user.c +++ b/hw/virtio/vhost-user.c @@ -1310,10 +1310,35 @@ static int enforce_reply(struct vhost_dev *dev, return vhost_user_get_features(dev, &dummy); } +/* Note: "msg->hdr.flags" may be modified. */ +static int vhost_user_write_sync(struct vhost_dev *dev, VhostUserMsg *msg, + bool wait_for_reply) +{ + int ret; + + if (wait_for_reply) { + bool reply_supported = virtio_has_feature(dev->protocol_features, + VHOST_USER_PROTOCOL_F_REPLY_ACK); + if (reply_supported) { + msg->hdr.flags |= VHOST_USER_NEED_REPLY_MASK; + } + } + + ret = vhost_user_write(dev, msg, NULL, 0); + if (ret < 0) { + return ret; + } + + if (wait_for_reply) { + return enforce_reply(dev, msg); + } + + return 0; +} + static int vhost_user_set_vring_addr(struct vhost_dev *dev, struct vhost_vring_addr *addr) { - int ret; VhostUserMsg msg = { .hdr.request = VHOST_USER_SET_VRING_ADDR, .hdr.flags = VHOST_USER_VERSION, @@ -1327,24 +1352,7 @@ static int vhost_user_set_vring_addr(struct vhost_dev *dev, */ bool wait_for_reply = addr->flags & (1 << VHOST_VRING_F_LOG); - if (wait_for_reply) { - bool reply_supported = virtio_has_feature(dev->protocol_features, - VHOST_USER_PROTOCOL_F_REPLY_ACK); - if (reply_supported) { - msg.hdr.flags |= VHOST_USER_NEED_REPLY_MASK; - } - } - - ret = vhost_user_write(dev, &msg, NULL, 0); - if (ret < 0) { - return ret; - } - - if (wait_for_reply) { - return enforce_reply(dev, &msg); - } - - return 0; + return vhost_user_write_sync(dev, &msg, wait_for_reply); } static int vhost_user_set_u64(struct vhost_dev *dev, int request, uint64_t u64, @@ -1356,26 +1364,8 @@ static int vhost_user_set_u64(struct vhost_dev *dev, int request, uint64_t u64, .payload.u64 = u64, .hdr.size = sizeof(msg.payload.u64), }; - int ret; - if (wait_for_reply) { - bool reply_supported = virtio_has_feature(dev->protocol_features, - VHOST_USER_PROTOCOL_F_REPLY_ACK); - if (reply_supported) { - msg.hdr.flags |= VHOST_USER_NEED_REPLY_MASK; - } - } - - ret = vhost_user_write(dev, &msg, NULL, 0); - if (ret < 0) { - return ret; - } - - if (wait_for_reply) { - return enforce_reply(dev, &msg); - } - - return 0; + return vhost_user_write_sync(dev, &msg, wait_for_reply); } static int vhost_user_set_status(struct vhost_dev *dev, uint8_t status) From 99ad9ec89d45dbc532471537a4468b9a5ea386e3 Mon Sep 17 00:00:00 2001 From: Laszlo Ersek Date: Mon, 2 Oct 2023 22:32:18 +0200 Subject: [PATCH 0988/1077] vhost-user: flatten "enforce_reply" into "vhost_user_write_sync" MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit At this point, only "vhost_user_write_sync" calls "enforce_reply"; embed the latter into the former. This is purely refactoring -- no observable change. Cc: "Michael S. Tsirkin" (supporter:vhost) Cc: Eugenio Perez Martin Cc: German Maglione Cc: Liu Jiang Cc: Sergio Lopez Pascual Cc: Stefano Garzarella Signed-off-by: Laszlo Ersek Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Stefano Garzarella Tested-by: Albert Esteve Reviewed-by: Eugenio Pérez Message-Id: <20231002203221.17241-5-lersek@redhat.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/virtio/vhost-user.c | 32 +++++++++++++------------------- 1 file changed, 13 insertions(+), 19 deletions(-) diff --git a/hw/virtio/vhost-user.c b/hw/virtio/vhost-user.c index 95dbf9880c..23e9039922 100644 --- a/hw/virtio/vhost-user.c +++ b/hw/virtio/vhost-user.c @@ -1292,24 +1292,6 @@ static int vhost_user_get_features(struct vhost_dev *dev, uint64_t *features) return 0; } -static int enforce_reply(struct vhost_dev *dev, - const VhostUserMsg *msg) -{ - uint64_t dummy; - - if (msg->hdr.flags & VHOST_USER_NEED_REPLY_MASK) { - return process_message_reply(dev, msg); - } - - /* - * We need to wait for a reply but the backend does not - * support replies for the command we just sent. - * Send VHOST_USER_GET_FEATURES which makes all backends - * send a reply. - */ - return vhost_user_get_features(dev, &dummy); -} - /* Note: "msg->hdr.flags" may be modified. */ static int vhost_user_write_sync(struct vhost_dev *dev, VhostUserMsg *msg, bool wait_for_reply) @@ -1330,7 +1312,19 @@ static int vhost_user_write_sync(struct vhost_dev *dev, VhostUserMsg *msg, } if (wait_for_reply) { - return enforce_reply(dev, msg); + uint64_t dummy; + + if (msg->hdr.flags & VHOST_USER_NEED_REPLY_MASK) { + return process_message_reply(dev, msg); + } + + /* + * We need to wait for a reply but the backend does not + * support replies for the command we just sent. + * Send VHOST_USER_GET_FEATURES which makes all backends + * send a reply. + */ + return vhost_user_get_features(dev, &dummy); } return 0; From df3b2abc32c319352e6b350990919d3387520669 Mon Sep 17 00:00:00 2001 From: Laszlo Ersek Date: Mon, 2 Oct 2023 22:32:19 +0200 Subject: [PATCH 0989/1077] vhost-user: hoist "write_sync", "get_features", "get_u64" MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In order to avoid a forward-declaration for "vhost_user_write_sync" in a subsequent patch, hoist "vhost_user_write_sync" -> "vhost_user_get_features" -> "vhost_user_get_u64" just above "vhost_set_vring". This is purely code movement -- no observable change. Cc: "Michael S. Tsirkin" (supporter:vhost) Cc: Eugenio Perez Martin Cc: German Maglione Cc: Liu Jiang Cc: Sergio Lopez Pascual Cc: Stefano Garzarella Signed-off-by: Laszlo Ersek Reviewed-by: Stefano Garzarella Tested-by: Albert Esteve Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Eugenio Pérez Message-Id: <20231002203221.17241-6-lersek@redhat.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/virtio/vhost-user.c | 170 ++++++++++++++++++++--------------------- 1 file changed, 85 insertions(+), 85 deletions(-) diff --git a/hw/virtio/vhost-user.c b/hw/virtio/vhost-user.c index 23e9039922..3c14947589 100644 --- a/hw/virtio/vhost-user.c +++ b/hw/virtio/vhost-user.c @@ -1073,6 +1073,91 @@ static int vhost_user_set_vring_endian(struct vhost_dev *dev, return vhost_user_write(dev, &msg, NULL, 0); } +static int vhost_user_get_u64(struct vhost_dev *dev, int request, uint64_t *u64) +{ + int ret; + VhostUserMsg msg = { + .hdr.request = request, + .hdr.flags = VHOST_USER_VERSION, + }; + + if (vhost_user_per_device_request(request) && dev->vq_index != 0) { + return 0; + } + + ret = vhost_user_write(dev, &msg, NULL, 0); + if (ret < 0) { + return ret; + } + + ret = vhost_user_read(dev, &msg); + if (ret < 0) { + return ret; + } + + if (msg.hdr.request != request) { + error_report("Received unexpected msg type. Expected %d received %d", + request, msg.hdr.request); + return -EPROTO; + } + + if (msg.hdr.size != sizeof(msg.payload.u64)) { + error_report("Received bad msg size."); + return -EPROTO; + } + + *u64 = msg.payload.u64; + + return 0; +} + +static int vhost_user_get_features(struct vhost_dev *dev, uint64_t *features) +{ + if (vhost_user_get_u64(dev, VHOST_USER_GET_FEATURES, features) < 0) { + return -EPROTO; + } + + return 0; +} + +/* Note: "msg->hdr.flags" may be modified. */ +static int vhost_user_write_sync(struct vhost_dev *dev, VhostUserMsg *msg, + bool wait_for_reply) +{ + int ret; + + if (wait_for_reply) { + bool reply_supported = virtio_has_feature(dev->protocol_features, + VHOST_USER_PROTOCOL_F_REPLY_ACK); + if (reply_supported) { + msg->hdr.flags |= VHOST_USER_NEED_REPLY_MASK; + } + } + + ret = vhost_user_write(dev, msg, NULL, 0); + if (ret < 0) { + return ret; + } + + if (wait_for_reply) { + uint64_t dummy; + + if (msg->hdr.flags & VHOST_USER_NEED_REPLY_MASK) { + return process_message_reply(dev, msg); + } + + /* + * We need to wait for a reply but the backend does not + * support replies for the command we just sent. + * Send VHOST_USER_GET_FEATURES which makes all backends + * send a reply. + */ + return vhost_user_get_features(dev, &dummy); + } + + return 0; +} + static int vhost_set_vring(struct vhost_dev *dev, unsigned long int request, struct vhost_vring_state *ring) @@ -1245,91 +1330,6 @@ static int vhost_user_set_vring_err(struct vhost_dev *dev, return vhost_set_vring_file(dev, VHOST_USER_SET_VRING_ERR, file); } -static int vhost_user_get_u64(struct vhost_dev *dev, int request, uint64_t *u64) -{ - int ret; - VhostUserMsg msg = { - .hdr.request = request, - .hdr.flags = VHOST_USER_VERSION, - }; - - if (vhost_user_per_device_request(request) && dev->vq_index != 0) { - return 0; - } - - ret = vhost_user_write(dev, &msg, NULL, 0); - if (ret < 0) { - return ret; - } - - ret = vhost_user_read(dev, &msg); - if (ret < 0) { - return ret; - } - - if (msg.hdr.request != request) { - error_report("Received unexpected msg type. Expected %d received %d", - request, msg.hdr.request); - return -EPROTO; - } - - if (msg.hdr.size != sizeof(msg.payload.u64)) { - error_report("Received bad msg size."); - return -EPROTO; - } - - *u64 = msg.payload.u64; - - return 0; -} - -static int vhost_user_get_features(struct vhost_dev *dev, uint64_t *features) -{ - if (vhost_user_get_u64(dev, VHOST_USER_GET_FEATURES, features) < 0) { - return -EPROTO; - } - - return 0; -} - -/* Note: "msg->hdr.flags" may be modified. */ -static int vhost_user_write_sync(struct vhost_dev *dev, VhostUserMsg *msg, - bool wait_for_reply) -{ - int ret; - - if (wait_for_reply) { - bool reply_supported = virtio_has_feature(dev->protocol_features, - VHOST_USER_PROTOCOL_F_REPLY_ACK); - if (reply_supported) { - msg->hdr.flags |= VHOST_USER_NEED_REPLY_MASK; - } - } - - ret = vhost_user_write(dev, msg, NULL, 0); - if (ret < 0) { - return ret; - } - - if (wait_for_reply) { - uint64_t dummy; - - if (msg->hdr.flags & VHOST_USER_NEED_REPLY_MASK) { - return process_message_reply(dev, msg); - } - - /* - * We need to wait for a reply but the backend does not - * support replies for the command we just sent. - * Send VHOST_USER_GET_FEATURES which makes all backends - * send a reply. - */ - return vhost_user_get_features(dev, &dummy); - } - - return 0; -} - static int vhost_user_set_vring_addr(struct vhost_dev *dev, struct vhost_vring_addr *addr) { From 75b6b6da21a225b7853515d9e14775f8a5d9af3a Mon Sep 17 00:00:00 2001 From: Laszlo Ersek Date: Mon, 2 Oct 2023 22:32:20 +0200 Subject: [PATCH 0990/1077] vhost-user: allow "vhost_set_vring" to wait for a reply MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The "vhost_set_vring" function already centralizes the common parts of "vhost_user_set_vring_num", "vhost_user_set_vring_base" and "vhost_user_set_vring_enable". We'll want to allow some of those callers to wait for a reply. Therefore, rebase "vhost_set_vring" from just "vhost_user_write" to "vhost_user_write_sync", exposing the "wait_for_reply" parameter. This is purely refactoring -- there is no observable change. That's because: - all three callers pass in "false" for "wait_for_reply", which disables all logic in "vhost_user_write_sync" except the call to "vhost_user_write"; - the fds=NULL and fd_num=0 arguments of the original "vhost_user_write" call inside "vhost_set_vring" are hard-coded within "vhost_user_write_sync". Cc: "Michael S. Tsirkin" (supporter:vhost) Cc: Eugenio Perez Martin Cc: German Maglione Cc: Liu Jiang Cc: Sergio Lopez Pascual Cc: Stefano Garzarella Signed-off-by: Laszlo Ersek Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Stefano Garzarella Tested-by: Albert Esteve Reviewed-by: Eugenio Pérez Message-Id: <20231002203221.17241-7-lersek@redhat.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/virtio/vhost-user.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/hw/virtio/vhost-user.c b/hw/virtio/vhost-user.c index 3c14947589..7e452849fa 100644 --- a/hw/virtio/vhost-user.c +++ b/hw/virtio/vhost-user.c @@ -1160,7 +1160,8 @@ static int vhost_user_write_sync(struct vhost_dev *dev, VhostUserMsg *msg, static int vhost_set_vring(struct vhost_dev *dev, unsigned long int request, - struct vhost_vring_state *ring) + struct vhost_vring_state *ring, + bool wait_for_reply) { VhostUserMsg msg = { .hdr.request = request, @@ -1169,13 +1170,13 @@ static int vhost_set_vring(struct vhost_dev *dev, .hdr.size = sizeof(msg.payload.state), }; - return vhost_user_write(dev, &msg, NULL, 0); + return vhost_user_write_sync(dev, &msg, wait_for_reply); } static int vhost_user_set_vring_num(struct vhost_dev *dev, struct vhost_vring_state *ring) { - return vhost_set_vring(dev, VHOST_USER_SET_VRING_NUM, ring); + return vhost_set_vring(dev, VHOST_USER_SET_VRING_NUM, ring, false); } static void vhost_user_host_notifier_free(VhostUserHostNotifier *n) @@ -1206,7 +1207,7 @@ static void vhost_user_host_notifier_remove(VhostUserHostNotifier *n, static int vhost_user_set_vring_base(struct vhost_dev *dev, struct vhost_vring_state *ring) { - return vhost_set_vring(dev, VHOST_USER_SET_VRING_BASE, ring); + return vhost_set_vring(dev, VHOST_USER_SET_VRING_BASE, ring, false); } static int vhost_user_set_vring_enable(struct vhost_dev *dev, int enable) @@ -1224,7 +1225,7 @@ static int vhost_user_set_vring_enable(struct vhost_dev *dev, int enable) .num = enable, }; - ret = vhost_set_vring(dev, VHOST_USER_SET_VRING_ENABLE, &state); + ret = vhost_set_vring(dev, VHOST_USER_SET_VRING_ENABLE, &state, false); if (ret < 0) { /* * Restoring the previous state is likely infeasible, as well as From d7dc0682f5cb549ea9afdc418f95412e83cc5e8c Mon Sep 17 00:00:00 2001 From: Laszlo Ersek Date: Mon, 2 Oct 2023 22:32:21 +0200 Subject: [PATCH 0991/1077] vhost-user: call VHOST_USER_SET_VRING_ENABLE synchronously MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit (1) The virtio-1.2 specification writes: > 3 General Initialization And Device Operation > 3.1 Device Initialization > 3.1.1 Driver Requirements: Device Initialization > > [...] > > 7. Perform device-specific setup, including discovery of virtqueues for > the device, optional per-bus setup, reading and possibly writing the > device’s virtio configuration space, and population of virtqueues. > > 8. Set the DRIVER_OK status bit. At this point the device is “live”. and > 4 Virtio Transport Options > 4.1 Virtio Over PCI Bus > 4.1.4 Virtio Structure PCI Capabilities > 4.1.4.3 Common configuration structure layout > 4.1.4.3.2 Driver Requirements: Common configuration structure layout > > [...] > > The driver MUST configure the other virtqueue fields before enabling the > virtqueue with queue_enable. > > [...] (The same statements are present in virtio-1.0 identically, at .) These together mean that the following sub-sequence of steps is valid for a virtio-1.0 guest driver: (1.1) set "queue_enable" for the needed queues as the final part of device initialization step (7), (1.2) set DRIVER_OK in step (8), (1.3) immediately start sending virtio requests to the device. (2) When vhost-user is enabled, and the VHOST_USER_F_PROTOCOL_FEATURES special virtio feature is negotiated, then virtio rings start in disabled state, according to . In this case, explicit VHOST_USER_SET_VRING_ENABLE messages are needed for enabling vrings. Therefore setting "queue_enable" from the guest (1.1) -- which is technically "buffered" on the QEMU side until the guest sets DRIVER_OK (1.2) -- is a *control plane* operation, which -- after (1.2) -- travels from the guest through QEMU to the vhost-user backend, using a unix domain socket. Whereas sending a virtio request (1.3) is a *data plane* operation, which evades QEMU -- it travels from guest to the vhost-user backend via eventfd. This means that operations ((1.1) + (1.2)) and (1.3) travel through different channels, and their relative order can be reversed, as perceived by the vhost-user backend. That's exactly what happens when OVMF's virtiofs driver (VirtioFsDxe) runs against the Rust-language virtiofsd version 1.7.2. (Which uses version 0.10.1 of the vhost-user-backend crate, and version 0.8.1 of the vhost crate.) Namely, when VirtioFsDxe binds a virtiofs device, it goes through the device initialization steps (i.e., control plane operations), and immediately sends a FUSE_INIT request too (i.e., performs a data plane operation). In the Rust-language virtiofsd, this creates a race between two components that run *concurrently*, i.e., in different threads or processes: - Control plane, handling vhost-user protocol messages: The "VhostUserSlaveReqHandlerMut::set_vring_enable" method [crates/vhost-user-backend/src/handler.rs] handles VHOST_USER_SET_VRING_ENABLE messages, and updates each vring's "enabled" flag according to the message processed. - Data plane, handling virtio / FUSE requests: The "VringEpollHandler::handle_event" method [crates/vhost-user-backend/src/event_loop.rs] handles the incoming virtio / FUSE request, consuming the virtio kick at the same time. If the vring's "enabled" flag is set, the virtio / FUSE request is processed genuinely. If the vring's "enabled" flag is clear, then the virtio / FUSE request is discarded. Note that OVMF enables the queue *first*, and sends FUSE_INIT *second*. However, if the data plane processor in virtiofsd wins the race, then it sees the FUSE_INIT *before* the control plane processor took notice of VHOST_USER_SET_VRING_ENABLE and green-lit the queue for the data plane processor. Therefore the latter drops FUSE_INIT on the floor, and goes back to waiting for further virtio / FUSE requests with epoll_wait. Meanwhile OVMF is stuck waiting for the FUSET_INIT response -- a deadlock. The deadlock is not deterministic. OVMF hangs infrequently during first boot. However, OVMF hangs almost certainly during reboots from the UEFI shell. The race can be "reliably masked" by inserting a very small delay -- a single debug message -- at the top of "VringEpollHandler::handle_event", i.e., just before the data plane processor checks the "enabled" field of the vring. That delay suffices for the control plane processor to act upon VHOST_USER_SET_VRING_ENABLE. We can deterministically prevent the race in QEMU, by blocking OVMF inside step (1.2) -- i.e., in the write to the device status register that "unleashes" queue enablement -- until VHOST_USER_SET_VRING_ENABLE actually *completes*. That way OVMF's VCPU cannot advance to the FUSE_INIT submission before virtiofsd's control plane processor takes notice of the queue being enabled. Wait for VHOST_USER_SET_VRING_ENABLE completion by: - setting the NEED_REPLY flag on VHOST_USER_SET_VRING_ENABLE, and waiting for the reply, if the VHOST_USER_PROTOCOL_F_REPLY_ACK vhost-user feature has been negotiated, or - performing a separate VHOST_USER_GET_FEATURES *exchange*, which requires a backend response regardless of VHOST_USER_PROTOCOL_F_REPLY_ACK. Cc: "Michael S. Tsirkin" (supporter:vhost) Cc: Eugenio Perez Martin Cc: German Maglione Cc: Liu Jiang Cc: Sergio Lopez Pascual Cc: Stefano Garzarella Signed-off-by: Laszlo Ersek Reviewed-by: Stefano Garzarella Tested-by: Albert Esteve [lersek@redhat.com: work Eugenio's explanation into the commit message, about QEMU containing step (1.1) until step (1.2)] Reviewed-by: Eugenio Pérez Message-Id: <20231002203221.17241-8-lersek@redhat.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/virtio/vhost-user.c | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/hw/virtio/vhost-user.c b/hw/virtio/vhost-user.c index 7e452849fa..427ee0ebfb 100644 --- a/hw/virtio/vhost-user.c +++ b/hw/virtio/vhost-user.c @@ -1225,7 +1225,21 @@ static int vhost_user_set_vring_enable(struct vhost_dev *dev, int enable) .num = enable, }; - ret = vhost_set_vring(dev, VHOST_USER_SET_VRING_ENABLE, &state, false); + /* + * SET_VRING_ENABLE travels from guest to QEMU to vhost-user backend / + * control plane thread via unix domain socket. Virtio requests travel + * from guest to vhost-user backend / data plane thread via eventfd. + * Even if the guest enables the ring first, and pushes its first virtio + * request second (conforming to the virtio spec), the data plane thread + * in the backend may see the virtio request before the control plane + * thread sees the queue enablement. This causes (in fact, requires) the + * data plane thread to discard the virtio request (it arrived on a + * seemingly disabled queue). To prevent this out-of-order delivery, + * don't let the guest proceed to pushing the virtio request until the + * backend control plane acknowledges enabling the queue -- IOW, pass + * wait_for_reply=true below. + */ + ret = vhost_set_vring(dev, VHOST_USER_SET_VRING_ENABLE, &state, true); if (ret < 0) { /* * Restoring the previous state is likely infeasible, as well as From b15c18c51910ec5ef8c506f641f487507e42c79b Mon Sep 17 00:00:00 2001 From: Ilya Maximets Date: Mon, 9 Oct 2023 12:43:21 +0200 Subject: [PATCH 0992/1077] memory: initialize 'fv' in MemoryRegionCache to make Coverity happy Coverity scan reports multiple false-positive "defects" for the following series of actions in virtio.c: MemoryRegionCache indirect_desc_cache; address_space_cache_init_empty(&indirect_desc_cache); address_space_cache_destroy(&indirect_desc_cache); For some reason it's unable to recognize the dependency between 'mrs.mr' and 'fv' and insists that '!mrs.mr' check in address_space_cache_destroy may take a 'false' branch, even though it is explicitly initialized to NULL in the address_space_cache_init_empty(): *** CID 1522371: Memory - illegal accesses (UNINIT) /qemu/hw/virtio/virtio.c: 1627 in virtqueue_split_pop() 1621 } 1622 1623 vq->inuse++; 1624 1625 trace_virtqueue_pop(vq, elem, elem->in_num, elem->out_num); 1626 done: >>> CID 1522371: Memory - illegal accesses (UNINIT) >>> Using uninitialized value "indirect_desc_cache.fv" when >>> calling "address_space_cache_destroy". 1627 address_space_cache_destroy(&indirect_desc_cache); 1628 1629 return elem; 1630 1631 err_undo_map: 1632 virtqueue_undo_map_desc(out_num, in_num, iov); ** CID 1522370: Memory - illegal accesses (UNINIT) Instead of trying to silence these false positive reports in 4 different places, initializing 'fv' as well, as this doesn't result in any noticeable performance impact. Signed-off-by: Ilya Maximets Message-Id: <20231009104322.3085887-1-i.maximets@ovn.org> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin Reviewed-by: David Hildenbrand Reviewed-by: Stefan Hajnoczi --- include/exec/memory.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/include/exec/memory.h b/include/exec/memory.h index 653a32ea10..9087d02769 100644 --- a/include/exec/memory.h +++ b/include/exec/memory.h @@ -2793,6 +2793,8 @@ int64_t address_space_cache_init(MemoryRegionCache *cache, static inline void address_space_cache_init_empty(MemoryRegionCache *cache) { cache->mrs.mr = NULL; + /* There is no real need to initialize fv, but it makes Coverity happy. */ + cache->fv = NULL; } /** From 22d2464f7ee6242114733e62541eed14cde15977 Mon Sep 17 00:00:00 2001 From: Stefan Hajnoczi Date: Tue, 3 Oct 2023 21:45:30 -0400 Subject: [PATCH 0993/1077] vhost-user: do not send RESET_OWNER on device reset The VHOST_USER_RESET_OWNER message is deprecated in the spec: This is no longer used. Used to be sent to request disabling all rings, but some back-ends interpreted it to also discard connection state (this interpretation would lead to bugs). It is recommended that back-ends either ignore this message, or use it to disable all rings. The only caller of vhost_user_reset_device() is vhost_user_scsi_reset(). It checks that F_RESET_DEVICE was negotiated before calling it: static void vhost_user_scsi_reset(VirtIODevice *vdev) { VHostSCSICommon *vsc = VHOST_SCSI_COMMON(vdev); struct vhost_dev *dev = &vsc->dev; /* * Historically, reset was not implemented so only reset devices * that are expecting it. */ if (!virtio_has_feature(dev->protocol_features, VHOST_USER_PROTOCOL_F_RESET_DEVICE)) { return; } if (dev->vhost_ops->vhost_reset_device) { dev->vhost_ops->vhost_reset_device(dev); } } Therefore VHOST_USER_RESET_OWNER is actually never sent by vhost_user_reset_device(). Remove the dead code. This effectively moves the vhost-user protocol specific code from vhost-user-scsi.c into vhost-user.c where it belongs. Signed-off-by: Stefan Hajnoczi Message-Id: <20231004014532.1228637-2-stefanha@redhat.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin Reviewed-by: Raphael Norwitz --- hw/scsi/vhost-user-scsi.c | 9 --------- hw/virtio/vhost-user.c | 13 +++++++++---- 2 files changed, 9 insertions(+), 13 deletions(-) diff --git a/hw/scsi/vhost-user-scsi.c b/hw/scsi/vhost-user-scsi.c index df6b66cc1a..78aef4765f 100644 --- a/hw/scsi/vhost-user-scsi.c +++ b/hw/scsi/vhost-user-scsi.c @@ -67,15 +67,6 @@ static void vhost_user_scsi_reset(VirtIODevice *vdev) VHostSCSICommon *vsc = VHOST_SCSI_COMMON(vdev); struct vhost_dev *dev = &vsc->dev; - /* - * Historically, reset was not implemented so only reset devices - * that are expecting it. - */ - if (!virtio_has_feature(dev->protocol_features, - VHOST_USER_PROTOCOL_F_RESET_DEVICE)) { - return; - } - if (dev->vhost_ops->vhost_reset_device) { dev->vhost_ops->vhost_reset_device(dev); } diff --git a/hw/virtio/vhost-user.c b/hw/virtio/vhost-user.c index 427ee0ebfb..f9414f03de 100644 --- a/hw/virtio/vhost-user.c +++ b/hw/virtio/vhost-user.c @@ -1482,12 +1482,17 @@ static int vhost_user_reset_device(struct vhost_dev *dev) { VhostUserMsg msg = { .hdr.flags = VHOST_USER_VERSION, + .hdr.request = VHOST_USER_RESET_DEVICE, }; - msg.hdr.request = virtio_has_feature(dev->protocol_features, - VHOST_USER_PROTOCOL_F_RESET_DEVICE) - ? VHOST_USER_RESET_DEVICE - : VHOST_USER_RESET_OWNER; + /* + * Historically, reset was not implemented so only reset devices + * that are expecting it. + */ + if (!virtio_has_feature(dev->protocol_features, + VHOST_USER_PROTOCOL_F_RESET_DEVICE)) { + return -ENOSYS; + } return vhost_user_write(dev, &msg, NULL, 0); } From e6383293eb01928692047e617665a742cca87e23 Mon Sep 17 00:00:00 2001 From: Stefan Hajnoczi Date: Tue, 3 Oct 2023 21:45:31 -0400 Subject: [PATCH 0994/1077] vhost-backend: remove vhost_kernel_reset_device() vhost_kernel_reset_device() invokes RESET_OWNER, which disassociates the owner process from the device. The device is left non-operational since SET_OWNER is only called once during startup in vhost_dev_init(). vhost_kernel_reset_device() is never called so this latent bug never appears. Get rid of vhost_kernel_reset_device() for now. If someone needs it in the future they'll need to implement it correctly. Signed-off-by: Stefan Hajnoczi Message-Id: <20231004014532.1228637-3-stefanha@redhat.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin Reviewed-by: Raphael Norwitz Reviewed-by: Hanna Czenczek --- hw/virtio/vhost-backend.c | 6 ------ 1 file changed, 6 deletions(-) diff --git a/hw/virtio/vhost-backend.c b/hw/virtio/vhost-backend.c index 8e581575c9..17f3fc6a08 100644 --- a/hw/virtio/vhost-backend.c +++ b/hw/virtio/vhost-backend.c @@ -197,11 +197,6 @@ static int vhost_kernel_set_owner(struct vhost_dev *dev) return vhost_kernel_call(dev, VHOST_SET_OWNER, NULL); } -static int vhost_kernel_reset_device(struct vhost_dev *dev) -{ - return vhost_kernel_call(dev, VHOST_RESET_OWNER, NULL); -} - static int vhost_kernel_get_vq_index(struct vhost_dev *dev, int idx) { assert(idx >= dev->vq_index && idx < dev->vq_index + dev->nvqs); @@ -322,7 +317,6 @@ const VhostOps kernel_ops = { .vhost_get_features = vhost_kernel_get_features, .vhost_set_backend_cap = vhost_kernel_set_backend_cap, .vhost_set_owner = vhost_kernel_set_owner, - .vhost_reset_device = vhost_kernel_reset_device, .vhost_get_vq_index = vhost_kernel_get_vq_index, .vhost_vsock_set_guest_cid = vhost_kernel_vsock_set_guest_cid, .vhost_vsock_set_running = vhost_kernel_vsock_set_running, From c0c4f147291f37765a5275aa24c3e1195468903b Mon Sep 17 00:00:00 2001 From: Stefan Hajnoczi Date: Tue, 3 Oct 2023 21:45:32 -0400 Subject: [PATCH 0995/1077] virtio: call ->vhost_reset_device() during reset vhost-user-scsi has a VirtioDeviceClass->reset() function that calls ->vhost_reset_device(). The other vhost devices don't notify the vhost device upon reset. Stateful vhost devices may need to handle device reset in order to free resources or prevent stale device state from interfering after reset. Call ->vhost_device_reset() from virtio_reset() so that that vhost devices are notified of device reset. This patch affects behavior as follows: - vhost-kernel: No change in behavior since ->vhost_reset_device() is not implemented. - vhost-user: back-ends that negotiate VHOST_USER_PROTOCOL_F_RESET_DEVICE now receive a VHOST_USER_DEVICE_RESET message upon device reset. Otherwise there is no change in behavior. DPDK, SPDK, libvhost-user, and the vhost-user-backend crate do not negotiate VHOST_USER_PROTOCOL_F_RESET_DEVICE automatically. - vhost-vdpa: an extra SET_STATUS 0 call is made during device reset. Signed-off-by: Stefan Hajnoczi Message-Id: <20231004014532.1228637-4-stefanha@redhat.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin Reviewed-by: Raphael Norwitz Reviewed-by: Hanna Czenczek --- hw/scsi/vhost-user-scsi.c | 11 ----------- hw/virtio/vhost.c | 9 +++++++++ hw/virtio/virtio.c | 4 ++++ include/hw/virtio/vhost.h | 10 ++++++++++ meson.build | 1 + 5 files changed, 24 insertions(+), 11 deletions(-) diff --git a/hw/scsi/vhost-user-scsi.c b/hw/scsi/vhost-user-scsi.c index 78aef4765f..b7c6100f3e 100644 --- a/hw/scsi/vhost-user-scsi.c +++ b/hw/scsi/vhost-user-scsi.c @@ -62,16 +62,6 @@ static void vhost_user_scsi_set_status(VirtIODevice *vdev, uint8_t status) } } -static void vhost_user_scsi_reset(VirtIODevice *vdev) -{ - VHostSCSICommon *vsc = VHOST_SCSI_COMMON(vdev); - struct vhost_dev *dev = &vsc->dev; - - if (dev->vhost_ops->vhost_reset_device) { - dev->vhost_ops->vhost_reset_device(dev); - } -} - static void vhost_dummy_handle_output(VirtIODevice *vdev, VirtQueue *vq) { } @@ -191,7 +181,6 @@ static void vhost_user_scsi_class_init(ObjectClass *klass, void *data) vdc->get_features = vhost_scsi_common_get_features; vdc->set_config = vhost_scsi_common_set_config; vdc->set_status = vhost_user_scsi_set_status; - vdc->reset = vhost_user_scsi_reset; fwc->get_dev_path = vhost_scsi_common_get_fw_dev_path; } diff --git a/hw/virtio/vhost.c b/hw/virtio/vhost.c index 9f37206ba0..92a6933f66 100644 --- a/hw/virtio/vhost.c +++ b/hw/virtio/vhost.c @@ -2154,3 +2154,12 @@ int vhost_net_set_backend(struct vhost_dev *hdev, return -ENOSYS; } + +int vhost_reset_device(struct vhost_dev *hdev) +{ + if (hdev->vhost_ops->vhost_reset_device) { + return hdev->vhost_ops->vhost_reset_device(hdev); + } + + return -ENOSYS; +} diff --git a/hw/virtio/virtio.c b/hw/virtio/virtio.c index 6facd64fbc..fb24bc927b 100644 --- a/hw/virtio/virtio.c +++ b/hw/virtio/virtio.c @@ -2136,6 +2136,10 @@ void virtio_reset(void *opaque) vdev->device_endian = virtio_default_endian(); } + if (vdev->vhost_started) { + vhost_reset_device(k->get_vhost(vdev)); + } + if (k->reset) { k->reset(vdev); } diff --git a/include/hw/virtio/vhost.h b/include/hw/virtio/vhost.h index c7e5467693..00e0a669b8 100644 --- a/include/hw/virtio/vhost.h +++ b/include/hw/virtio/vhost.h @@ -339,4 +339,14 @@ int vhost_dev_set_inflight(struct vhost_dev *dev, int vhost_dev_get_inflight(struct vhost_dev *dev, uint16_t queue_size, struct vhost_inflight *inflight); bool vhost_dev_has_iommu(struct vhost_dev *dev); + +#ifdef CONFIG_VHOST +int vhost_reset_device(struct vhost_dev *hdev); +#else +static inline int vhost_reset_device(struct vhost_dev *hdev) +{ + return -ENOSYS; +} +#endif /* CONFIG_VHOST */ + #endif diff --git a/meson.build b/meson.build index e0d1f84b26..cbee764817 100644 --- a/meson.build +++ b/meson.build @@ -2134,6 +2134,7 @@ config_host_data.set('CONFIG_TPM', have_tpm) config_host_data.set('CONFIG_TSAN', get_option('tsan')) config_host_data.set('CONFIG_USB_LIBUSB', libusb.found()) config_host_data.set('CONFIG_VDE', vde.found()) +config_host_data.set('CONFIG_VHOST', have_vhost) config_host_data.set('CONFIG_VHOST_NET', have_vhost_net) config_host_data.set('CONFIG_VHOST_NET_USER', have_vhost_net_user) config_host_data.set('CONFIG_VHOST_NET_VDPA', have_vhost_net_vdpa) From bd7a6d88ec900a9a2c5b3ef09f941558908d3cda Mon Sep 17 00:00:00 2001 From: Bernhard Beschow Date: Wed, 4 Oct 2023 11:23:55 +0200 Subject: [PATCH 0996/1077] hw/i386/acpi-build: Remove build-time assertion on PIIX/ICH9 reset registers being identical MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Commit 6103451aeb74 ("hw/i386: Build-time assertion on pc/q35 reset register being identical.") introduced a build-time check where the addresses of the reset registers are expected to be equal. Back then rev3 of the FADT was used which required the reset register to be populated and there was common code. In commit 3a3fcc75f92a ("pc: acpi: force FADT rev1 for 440fx based machine types") the FADT was downgraded to rev1 for PIIX where the reset register isn't available. Thus, there is no need for the assertion any longer, so remove it. Signed-off-by: Bernhard Beschow Reviewed-by: Ani Sinha Reviewed-by: Philippe Mathieu-Daudé Message-Id: <20231004092355.12929-1-shentey@gmail.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/i386/acpi-build.c | 5 ----- 1 file changed, 5 deletions(-) diff --git a/hw/i386/acpi-build.c b/hw/i386/acpi-build.c index 3f2b27cf75..b0e1f074f1 100644 --- a/hw/i386/acpi-build.c +++ b/hw/i386/acpi-build.c @@ -56,7 +56,6 @@ /* Supported chipsets: */ #include "hw/southbridge/ich9.h" -#include "hw/southbridge/piix.h" #include "hw/acpi/pcihp.h" #include "hw/i386/fw_cfg.h" #include "hw/i386/pc.h" @@ -242,10 +241,6 @@ static void acpi_get_pm_info(MachineState *machine, AcpiPmInfo *pm) pm->pcihp_io_len = object_property_get_uint(obj, ACPI_PCIHP_IO_LEN_PROP, NULL); - /* The above need not be conditional on machine type because the reset port - * happens to be the same on PIIX (pc) and ICH9 (q35). */ - QEMU_BUILD_BUG_ON(ICH9_RST_CNT_IOPORT != PIIX_RCR_IOPORT); - /* Fill in optional s3/s4 related properties */ o = object_property_get_qobject(obj, ACPI_PM_PROP_S3_DISABLED, NULL); if (o) { From 74d7ea50627a60257a92e77402780897075654fd Mon Sep 17 00:00:00 2001 From: Damien Zammit Date: Sun, 26 Feb 2023 01:58:10 +0000 Subject: [PATCH 0997/1077] timer/i8254: Fix one shot PIT mode Currently, the one-shot (mode 1) PIT expires far too quickly, due to the output being set under the wrong logic. This change fixes the one-shot PIT mode to behave similarly to mode 0. TESTED: using the one-shot PIT mode to calibrate a local apic timer. Signed-off-by: Damien Zammit Message-Id: <20230226015755.52624-1-damien@zamaudio.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/timer/i8254_common.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/hw/timer/i8254_common.c b/hw/timer/i8254_common.c index e4093e2904..b25da448c8 100644 --- a/hw/timer/i8254_common.c +++ b/hw/timer/i8254_common.c @@ -52,10 +52,8 @@ int pit_get_out(PITChannelState *s, int64_t current_time) switch (s->mode) { default: case 0: - out = (d >= s->count); - break; case 1: - out = (d < s->count); + out = (d >= s->count); break; case 2: if ((d % s->count) == 0 && d != 0) { From 9b50fd02900c11e6e50c7913e5772031749b3e8d Mon Sep 17 00:00:00 2001 From: Matheus Tavares Bernardino Date: Fri, 6 Oct 2023 17:39:01 -0300 Subject: [PATCH 0998/1077] hw/display: fix memleak from virtio_add_resource When the given uuid is already present in the hash table, virtio_add_resource() does not add the passed VirtioSharedObject. In this case, free it in the callers to avoid leaking memory. This fixed the following `make check` error, when built with --enable-sanitizers: 4/166 qemu:unit / test-virtio-dmabuf ERROR 1.51s exit status 1 ==7716==ERROR: LeakSanitizer: detected memory leaks Direct leak of 320 byte(s) in 20 object(s) allocated from: #0 0x7f6fc16e3808 in __interceptor_malloc ../../../../src/libsanitizer/asan/asan_malloc_linux.cc:144 #1 0x7f6fc1503e98 in g_malloc (/lib/x86_64-linux-gnu/libglib-2.0.so.0+0x57e98) #2 0x564d63cafb6b in test_add_invalid_resource ../tests/unit/test-virtio-dmabuf.c:100 #3 0x7f6fc152659d (/lib/x86_64-linux-gnu/libglib-2.0.so.0+0x7a59d) SUMMARY: AddressSanitizer: 320 byte(s) leaked in 20 allocation(s). The changes at virtio_add_resource() itself are not strictly necessary for the memleak fix, but they make it more obvious that, on an error return, the passed object is not added to the hash. Signed-off-by: Matheus Tavares Bernardino Message-Id: Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin Reviewed-by: Albert Esteve Signed-off-by: Matheus Tavares Bernardino <quic_mathbern@quicinc.com>
--- hw/display/virtio-dmabuf.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/hw/display/virtio-dmabuf.c b/hw/display/virtio-dmabuf.c index 4a8e430f3d..3dba4577ca 100644 --- a/hw/display/virtio-dmabuf.c +++ b/hw/display/virtio-dmabuf.c @@ -29,7 +29,7 @@ static int uuid_equal_func(const void *lhv, const void *rhv) static bool virtio_add_resource(QemuUUID *uuid, VirtioSharedObject *value) { - bool result = false; + bool result = true; g_mutex_lock(&lock); if (resource_uuids == NULL) { @@ -39,7 +39,9 @@ static bool virtio_add_resource(QemuUUID *uuid, VirtioSharedObject *value) g_free); } if (g_hash_table_lookup(resource_uuids, uuid) == NULL) { - result = g_hash_table_insert(resource_uuids, uuid, value); + g_hash_table_insert(resource_uuids, uuid, value); + } else { + result = false; } g_mutex_unlock(&lock); @@ -57,6 +59,9 @@ bool virtio_add_dmabuf(QemuUUID *uuid, int udmabuf_fd) vso->type = TYPE_DMABUF; vso->value = GINT_TO_POINTER(udmabuf_fd); result = virtio_add_resource(uuid, vso); + if (!result) { + g_free(vso); + } return result; } @@ -72,6 +77,9 @@ bool virtio_add_vhost_device(QemuUUID *uuid, struct vhost_dev *dev) vso->type = TYPE_VHOST_DEV; vso->value = dev; result = virtio_add_resource(uuid, vso); + if (!result) { + g_free(vso); + } return result; } From 9c91051119f8c493a5802c4f5347516679e55552 Mon Sep 17 00:00:00 2001 From: Bernhard Beschow Date: Sat, 7 Oct 2023 14:38:09 +0200 Subject: [PATCH 0999/1077] hw/i386/pc: Merge two if statements into one By being the only entity assigning a non-NULL value to "rtc_irq", the first if statement determines whether the second if statement is executed. So merge the two statements into one. Signed-off-by: Bernhard Beschow Message-Id: <20231007123843.127151-2-shentey@gmail.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/i386/pc.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/hw/i386/pc.c b/hw/i386/pc.c index bb3854d1d0..7e6c4dc526 100644 --- a/hw/i386/pc.c +++ b/hw/i386/pc.c @@ -1199,7 +1199,6 @@ void pc_basic_device_init(struct PCMachineState *pcms, DeviceState *hpet = NULL; int pit_isa_irq = 0; qemu_irq pit_alt_irq = NULL; - qemu_irq rtc_irq = NULL; ISADevice *pit = NULL; MemoryRegion *ioport80_io = g_new(MemoryRegion, 1); MemoryRegion *ioportF0_io = g_new(MemoryRegion, 1); @@ -1219,6 +1218,8 @@ void pc_basic_device_init(struct PCMachineState *pcms, */ if (pcms->hpet_enabled && (!kvm_irqchip_in_kernel() || kvm_has_pit_state2())) { + qemu_irq rtc_irq; + hpet = qdev_try_new(TYPE_HPET); if (!hpet) { error_report("couldn't create HPET device"); @@ -1243,9 +1244,6 @@ void pc_basic_device_init(struct PCMachineState *pcms, pit_isa_irq = -1; pit_alt_irq = qdev_get_gpio_in(hpet, HPET_LEGACY_PIT_INT); rtc_irq = qdev_get_gpio_in(hpet, HPET_LEGACY_RTC_INT); - } - - if (rtc_irq) { qdev_connect_gpio_out(DEVICE(rtc_state), 0, rtc_irq); } else { uint32_t irq = object_property_get_uint(OBJECT(rtc_state), @@ -1253,6 +1251,7 @@ void pc_basic_device_init(struct PCMachineState *pcms, &error_fatal); isa_connect_gpio_out(rtc_state, 0, irq); } + object_property_add_alias(OBJECT(pcms), "rtc-time", OBJECT(rtc_state), "date"); From fe9a7350c2900c9609e7a8ce1e042e3458a245e2 Mon Sep 17 00:00:00 2001 From: Bernhard Beschow Date: Sat, 7 Oct 2023 14:38:10 +0200 Subject: [PATCH 1000/1077] hw/i386/pc_piix: Allow for setting properties before realizing PIIX3 south bridge The next patches will need to take advantage of it. Signed-off-by: Bernhard Beschow Reviewed-by: Peter Maydell Reviewed-by: Michael S. Tsirkin Message-Id: <20231007123843.127151-3-shentey@gmail.com> Signed-off-by: Michael S. Tsirkin --- hw/i386/pc_piix.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/hw/i386/pc_piix.c b/hw/i386/pc_piix.c index e36a3262b2..6d2f5509e6 100644 --- a/hw/i386/pc_piix.c +++ b/hw/i386/pc_piix.c @@ -264,7 +264,8 @@ static void pc_init1(MachineState *machine, PIIX3State *piix3; PCIDevice *pci_dev; - pci_dev = pci_create_simple_multifunction(pci_bus, -1, TYPE_PIIX3_DEVICE); + pci_dev = pci_new_multifunction(-1, TYPE_PIIX3_DEVICE); + pci_realize_and_unref(pci_dev, pci_bus, &error_fatal); if (xen_enabled()) { pci_device_set_intx_routing_notifier( From 8b6cf5128ee510729895e00a669fa7ce7457c949 Mon Sep 17 00:00:00 2001 From: Bernhard Beschow Date: Sat, 7 Oct 2023 14:38:11 +0200 Subject: [PATCH 1001/1077] hw/i386/pc_piix: Assign PIIX3's ISA interrupts before its realize() Unlike its PIIX4 counterpart, TYPE_PIIX3_DEVICE doesn't instantiate a PIC itself. Instead, it relies on the board to do so. This means that the board needs to wire the ISA IRQs to the PIIX3 device model. As long as the board assigns the ISA IRQs after PIIX3's realize(), internal devices can't be wired in pci_piix3_realize() since the qemu_irqs are still NULL. Fix that by assigning the ISA interrupts before realize(). This will allow for embedding child devices into the host device as already done for PIIX4. Signed-off-by: Bernhard Beschow Message-Id: <20231007123843.127151-4-shentey@gmail.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/i386/pc_piix.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/hw/i386/pc_piix.c b/hw/i386/pc_piix.c index 6d2f5509e6..a003923788 100644 --- a/hw/i386/pc_piix.c +++ b/hw/i386/pc_piix.c @@ -265,6 +265,8 @@ static void pc_init1(MachineState *machine, PCIDevice *pci_dev; pci_dev = pci_new_multifunction(-1, TYPE_PIIX3_DEVICE); + piix3 = PIIX3_PCI_DEVICE(pci_dev); + piix3->pic = x86ms->gsi; pci_realize_and_unref(pci_dev, pci_bus, &error_fatal); if (xen_enabled()) { @@ -281,8 +283,6 @@ static void pc_init1(MachineState *machine, XEN_IOAPIC_NUM_PIRQS); } - piix3 = PIIX3_PCI_DEVICE(pci_dev); - piix3->pic = x86ms->gsi; piix3_devfn = piix3->dev.devfn; isa_bus = ISA_BUS(qdev_get_child_bus(DEVICE(piix3), "isa.0")); rtc_state = ISA_DEVICE(object_resolve_path_component(OBJECT(pci_dev), From 32f29b26ff150dba6d1c455b826e44447b9ead45 Mon Sep 17 00:00:00 2001 From: Bernhard Beschow Date: Sat, 7 Oct 2023 14:38:12 +0200 Subject: [PATCH 1002/1077] hw/isa/piix3: Resolve redundant PIIX_NUM_PIC_IRQS PIIX_NUM_PIC_IRQS is assumed to be the same as ISA_NUM_IRQS, otherwise inconsistencies can occur. Signed-off-by: Bernhard Beschow Reviewed-by: Michael S. Tsirkin Message-Id: <20231007123843.127151-5-shentey@gmail.com> Signed-off-by: Michael S. Tsirkin --- hw/isa/piix3.c | 8 ++++---- include/hw/southbridge/piix.h | 5 ++--- 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/hw/isa/piix3.c b/hw/isa/piix3.c index 117024e450..7240c91440 100644 --- a/hw/isa/piix3.c +++ b/hw/isa/piix3.c @@ -48,7 +48,7 @@ static void piix3_set_irq_level_internal(PIIX3State *piix3, int pirq, int level) uint64_t mask; pic_irq = piix3->dev.config[PIIX_PIRQCA + pirq]; - if (pic_irq >= PIIX_NUM_PIC_IRQS) { + if (pic_irq >= ISA_NUM_IRQS) { return; } @@ -62,7 +62,7 @@ static void piix3_set_irq_level(PIIX3State *piix3, int pirq, int level) int pic_irq; pic_irq = piix3->dev.config[PIIX_PIRQCA + pirq]; - if (pic_irq >= PIIX_NUM_PIC_IRQS) { + if (pic_irq >= ISA_NUM_IRQS) { return; } @@ -83,7 +83,7 @@ static PCIINTxRoute piix3_route_intx_pin_to_irq(void *opaque, int pin) int irq = piix3->dev.config[PIIX_PIRQCA + pin]; PCIINTxRoute route; - if (irq < PIIX_NUM_PIC_IRQS) { + if (irq < ISA_NUM_IRQS) { route.mode = PCI_INTX_ENABLED; route.irq = irq; } else { @@ -115,7 +115,7 @@ static void piix3_write_config(PCIDevice *dev, pci_bus_fire_intx_routing_notifier(pci_get_bus(&piix3->dev)); piix3_update_irq_levels(piix3); - for (pic_irq = 0; pic_irq < PIIX_NUM_PIC_IRQS; pic_irq++) { + for (pic_irq = 0; pic_irq < ISA_NUM_IRQS; pic_irq++) { piix3_set_irq_pic(piix3, pic_irq); } } diff --git a/include/hw/southbridge/piix.h b/include/hw/southbridge/piix.h index 278171752f..2317bb7974 100644 --- a/include/hw/southbridge/piix.h +++ b/include/hw/southbridge/piix.h @@ -27,7 +27,6 @@ */ #define PIIX_RCR_IOPORT 0xcf9 -#define PIIX_NUM_PIC_IRQS 16 /* i8259 * 2 */ #define PIIX_NUM_PIRQS 4ULL /* PIRQ[A-D] */ struct PIIXState { @@ -39,10 +38,10 @@ struct PIIXState { * So one PIC level is tracked by PIIX_NUM_PIRQS bits. * * PIRQ is mapped to PIC pins, we track it by - * PIIX_NUM_PIRQS * PIIX_NUM_PIC_IRQS = 64 bits with + * PIIX_NUM_PIRQS * ISA_NUM_IRQS = 64 bits with * pic_irq * PIIX_NUM_PIRQS + pirq */ -#if PIIX_NUM_PIC_IRQS * PIIX_NUM_PIRQS > 64 +#if ISA_NUM_IRQS * PIIX_NUM_PIRQS > 64 #error "unable to encode pic state in 64bit in pic_levels." #endif uint64_t pic_levels; From 001cb25f3fb84768db4c1fb0ffd77779e0676745 Mon Sep 17 00:00:00 2001 From: Bernhard Beschow Date: Sat, 7 Oct 2023 14:38:13 +0200 Subject: [PATCH 1003/1077] hw/i386/pc_piix: Wire PIIX3's ISA interrupts by new "isa-irqs" property Avoid assigning the private member of struct PIIX3State from outside which goes against best QOM practices. Instead, implement best QOM practice by adding an "isa-irqs" array property to TYPE_PIIX3_DEVICE and assign it in board code, i.e. from outside. Signed-off-by: Bernhard Beschow Message-Id: <20231007123843.127151-6-shentey@gmail.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/i386/pc_piix.c | 7 ++++++- hw/isa/piix3.c | 2 ++ include/hw/southbridge/piix.h | 2 +- 3 files changed, 9 insertions(+), 2 deletions(-) diff --git a/hw/i386/pc_piix.c b/hw/i386/pc_piix.c index a003923788..4dc7298c15 100644 --- a/hw/i386/pc_piix.c +++ b/hw/i386/pc_piix.c @@ -263,10 +263,15 @@ static void pc_init1(MachineState *machine, if (pcmc->pci_enabled) { PIIX3State *piix3; PCIDevice *pci_dev; + DeviceState *dev; + size_t i; pci_dev = pci_new_multifunction(-1, TYPE_PIIX3_DEVICE); piix3 = PIIX3_PCI_DEVICE(pci_dev); - piix3->pic = x86ms->gsi; + dev = DEVICE(pci_dev); + for (i = 0; i < ISA_NUM_IRQS; i++) { + qdev_connect_gpio_out_named(dev, "isa-irqs", i, x86ms->gsi[i]); + } pci_realize_and_unref(pci_dev, pci_bus, &error_fatal); if (xen_enabled()) { diff --git a/hw/isa/piix3.c b/hw/isa/piix3.c index 7240c91440..c17547a2c0 100644 --- a/hw/isa/piix3.c +++ b/hw/isa/piix3.c @@ -312,6 +312,8 @@ static void pci_piix3_init(Object *obj) { PIIX3State *d = PIIX3_PCI_DEVICE(obj); + qdev_init_gpio_out_named(DEVICE(obj), d->pic, "isa-irqs", ISA_NUM_IRQS); + object_initialize_child(obj, "rtc", &d->rtc, TYPE_MC146818_RTC); } diff --git a/include/hw/southbridge/piix.h b/include/hw/southbridge/piix.h index 2317bb7974..bb898c6c88 100644 --- a/include/hw/southbridge/piix.h +++ b/include/hw/southbridge/piix.h @@ -46,7 +46,7 @@ struct PIIXState { #endif uint64_t pic_levels; - qemu_irq *pic; + qemu_irq pic[ISA_NUM_IRQS]; /* This member isn't used. Just for save/load compatibility */ int32_t pci_irq_levels_vmstate[PIIX_NUM_PIRQS]; From b9a8b8d29f438b6a695b12bd2d3e0567cbae5dc7 Mon Sep 17 00:00:00 2001 From: Bernhard Beschow Date: Sat, 7 Oct 2023 14:38:14 +0200 Subject: [PATCH 1004/1077] hw/i386/pc_piix: Remove redundant "piix3" variable The variable is never used by its declared type. Eliminate it. Signed-off-by: Bernhard Beschow Message-Id: <20231007123843.127151-7-shentey@gmail.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/i386/pc_piix.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/hw/i386/pc_piix.c b/hw/i386/pc_piix.c index 4dc7298c15..cd6c00c0b3 100644 --- a/hw/i386/pc_piix.c +++ b/hw/i386/pc_piix.c @@ -261,13 +261,11 @@ static void pc_init1(MachineState *machine, gsi_state = pc_gsi_create(&x86ms->gsi, pcmc->pci_enabled); if (pcmc->pci_enabled) { - PIIX3State *piix3; PCIDevice *pci_dev; DeviceState *dev; size_t i; pci_dev = pci_new_multifunction(-1, TYPE_PIIX3_DEVICE); - piix3 = PIIX3_PCI_DEVICE(pci_dev); dev = DEVICE(pci_dev); for (i = 0; i < ISA_NUM_IRQS; i++) { qdev_connect_gpio_out_named(dev, "isa-irqs", i, x86ms->gsi[i]); @@ -288,8 +286,8 @@ static void pc_init1(MachineState *machine, XEN_IOAPIC_NUM_PIRQS); } - piix3_devfn = piix3->dev.devfn; - isa_bus = ISA_BUS(qdev_get_child_bus(DEVICE(piix3), "isa.0")); + piix3_devfn = pci_dev->devfn; + isa_bus = ISA_BUS(qdev_get_child_bus(DEVICE(pci_dev), "isa.0")); rtc_state = ISA_DEVICE(object_resolve_path_component(OBJECT(pci_dev), "rtc")); } else { From 40f70623875b4ae46e04f57cfa7c80b6af917e1b Mon Sep 17 00:00:00 2001 From: Bernhard Beschow Date: Sat, 7 Oct 2023 14:38:15 +0200 Subject: [PATCH 1005/1077] hw/isa/piix3: Rename "pic" attribute to "isa_irqs_in" TYPE_PIIX3_DEVICE doesn't instantiate a PIC since it relies on the board to do so. The "pic" attribute, however, suggests that there is one. Rename the attribute to reflect that it represents ISA interrupt lines. Use the same naming convention as in the VIA south bridges as well as in TYPE_I82378. Signed-off-by: Bernhard Beschow Message-Id: <20231007123843.127151-8-shentey@gmail.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/isa/piix3.c | 5 +++-- include/hw/southbridge/piix.h | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/hw/isa/piix3.c b/hw/isa/piix3.c index c17547a2c0..616f5418fa 100644 --- a/hw/isa/piix3.c +++ b/hw/isa/piix3.c @@ -36,7 +36,7 @@ static void piix3_set_irq_pic(PIIX3State *piix3, int pic_irq) { - qemu_set_irq(piix3->pic[pic_irq], + qemu_set_irq(piix3->isa_irqs_in[pic_irq], !!(piix3->pic_levels & (((1ULL << PIIX_NUM_PIRQS) - 1) << (pic_irq * PIIX_NUM_PIRQS)))); @@ -312,7 +312,8 @@ static void pci_piix3_init(Object *obj) { PIIX3State *d = PIIX3_PCI_DEVICE(obj); - qdev_init_gpio_out_named(DEVICE(obj), d->pic, "isa-irqs", ISA_NUM_IRQS); + qdev_init_gpio_out_named(DEVICE(obj), d->isa_irqs_in, "isa-irqs", + ISA_NUM_IRQS); object_initialize_child(obj, "rtc", &d->rtc, TYPE_MC146818_RTC); } diff --git a/include/hw/southbridge/piix.h b/include/hw/southbridge/piix.h index bb898c6c88..b07ff6bb26 100644 --- a/include/hw/southbridge/piix.h +++ b/include/hw/southbridge/piix.h @@ -46,7 +46,7 @@ struct PIIXState { #endif uint64_t pic_levels; - qemu_irq pic[ISA_NUM_IRQS]; + qemu_irq isa_irqs_in[ISA_NUM_IRQS]; /* This member isn't used. Just for save/load compatibility */ int32_t pci_irq_levels_vmstate[PIIX_NUM_PIRQS]; From 295385127e83a923e166f8b4fe1e543ee4540018 Mon Sep 17 00:00:00 2001 From: Bernhard Beschow Date: Sat, 7 Oct 2023 14:38:16 +0200 Subject: [PATCH 1006/1077] hw/i386/pc_q35: Wire ICH9 LPC function's interrupts before its realize() When the board assigns the ISA IRQs after the device's realize(), internal devices such as the RTC can't be wired in ich9_lpc_realize() since the qemu_irqs are still NULL. Fix that by assigning the ISA interrupts before realize(). This change is necessary for PIIX consolidation because PIIX4 wires the RTC interrupts in its realize() method, so PIIX3 needs to do so as well. Since the PC and Q35 boards share RTC code, and since PIIX3 needs the change, ICH9 needs to be adapted as well. Signed-off-by: Bernhard Beschow Message-Id: <20231007123843.127151-9-shentey@gmail.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/i386/pc_q35.c | 14 +++++++------- hw/isa/lpc_ich9.c | 6 +++--- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/hw/i386/pc_q35.c b/hw/i386/pc_q35.c index a7386f2ca2..597943ff1b 100644 --- a/hw/i386/pc_q35.c +++ b/hw/i386/pc_q35.c @@ -242,11 +242,18 @@ static void pc_q35_init(MachineState *machine) host_bus = PCI_BUS(qdev_get_child_bus(DEVICE(phb), "pcie.0")); pcms->bus = host_bus; + /* irq lines */ + gsi_state = pc_gsi_create(&x86ms->gsi, pcmc->pci_enabled); + /* create ISA bus */ lpc = pci_new_multifunction(PCI_DEVFN(ICH9_LPC_DEV, ICH9_LPC_FUNC), TYPE_ICH9_LPC_DEVICE); qdev_prop_set_bit(DEVICE(lpc), "smm-enabled", x86_machine_is_smm_enabled(x86ms)); + lpc_dev = DEVICE(lpc); + for (i = 0; i < IOAPIC_NUM_PINS; i++) { + qdev_connect_gpio_out_named(lpc_dev, ICH9_GPIO_GSI, i, x86ms->gsi[i]); + } pci_realize_and_unref(lpc, host_bus, &error_fatal); rtc_state = ISA_DEVICE(object_resolve_path_component(OBJECT(lpc), "rtc")); @@ -273,13 +280,6 @@ static void pc_q35_init(MachineState *machine) "true", true); } - /* irq lines */ - gsi_state = pc_gsi_create(&x86ms->gsi, pcmc->pci_enabled); - - lpc_dev = DEVICE(lpc); - for (i = 0; i < IOAPIC_NUM_PINS; i++) { - qdev_connect_gpio_out_named(lpc_dev, ICH9_GPIO_GSI, i, x86ms->gsi[i]); - } isa_bus = ISA_BUS(qdev_get_child_bus(lpc_dev, "isa.0")); if (x86ms->pic == ON_OFF_AUTO_ON || x86ms->pic == ON_OFF_AUTO_AUTO) { diff --git a/hw/isa/lpc_ich9.c b/hw/isa/lpc_ich9.c index 3f59980aa0..3fcefc5a8a 100644 --- a/hw/isa/lpc_ich9.c +++ b/hw/isa/lpc_ich9.c @@ -675,6 +675,9 @@ static void ich9_lpc_initfn(Object *obj) object_initialize_child(obj, "rtc", &lpc->rtc, TYPE_MC146818_RTC); + qdev_init_gpio_out_named(DEVICE(lpc), lpc->gsi, ICH9_GPIO_GSI, + IOAPIC_NUM_PINS); + object_property_add_uint8_ptr(obj, ACPI_PM_PROP_SCI_INT, &lpc->sci_gsi, OBJ_PROP_FLAG_READ); object_property_add_uint8_ptr(OBJECT(lpc), ACPI_PM_PROP_ACPI_ENABLE_CMD, @@ -691,7 +694,6 @@ static void ich9_lpc_initfn(Object *obj) static void ich9_lpc_realize(PCIDevice *d, Error **errp) { ICH9LPCState *lpc = ICH9_LPC_DEVICE(d); - DeviceState *dev = DEVICE(d); PCIBus *pci_bus = pci_get_bus(d); ISABus *isa_bus; @@ -734,8 +736,6 @@ static void ich9_lpc_realize(PCIDevice *d, Error **errp) ICH9_RST_CNT_IOPORT, &lpc->rst_cnt_mem, 1); - qdev_init_gpio_out_named(dev, lpc->gsi, ICH9_GPIO_GSI, IOAPIC_NUM_PINS); - isa_bus_register_input_irqs(isa_bus, lpc->gsi); i8257_dma_init(isa_bus, 0); From 64127940aeb674cb5d9d8d0ea4ca20591bf2b010 Mon Sep 17 00:00:00 2001 From: Bernhard Beschow Date: Sat, 7 Oct 2023 14:38:17 +0200 Subject: [PATCH 1007/1077] hw/isa/piix3: Wire PIC IRQs to ISA bus in host device Thie PIIX3 south bridge implements both the PIC and the ISA bus, so wiring the interrupts there makes the device model more self-contained. Furthermore, this allows the ISA interrupts to be wired to internal child devices in pci_piix3_realize() which will be performed in subsequent patches. Signed-off-by: Bernhard Beschow Message-Id: <20231007123843.127151-10-shentey@gmail.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/i386/pc_piix.c | 2 +- hw/isa/piix3.c | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/hw/i386/pc_piix.c b/hw/i386/pc_piix.c index cd6c00c0b3..5988656279 100644 --- a/hw/i386/pc_piix.c +++ b/hw/i386/pc_piix.c @@ -293,6 +293,7 @@ static void pc_init1(MachineState *machine, } else { isa_bus = isa_bus_new(NULL, system_memory, system_io, &error_abort); + isa_bus_register_input_irqs(isa_bus, x86ms->gsi); rtc_state = isa_new(TYPE_MC146818_RTC); qdev_prop_set_int32(DEVICE(rtc_state), "base_year", 2000); @@ -301,7 +302,6 @@ static void pc_init1(MachineState *machine, i8257_dma_init(isa_bus, 0); pcms->hpet_enabled = false; } - isa_bus_register_input_irqs(isa_bus, x86ms->gsi); if (x86ms->pic == ON_OFF_AUTO_ON || x86ms->pic == ON_OFF_AUTO_AUTO) { pc_i8259_create(isa_bus, gsi_state->i8259_irq); diff --git a/hw/isa/piix3.c b/hw/isa/piix3.c index 616f5418fa..3e7c42fa68 100644 --- a/hw/isa/piix3.c +++ b/hw/isa/piix3.c @@ -278,6 +278,8 @@ static void pci_piix3_realize(PCIDevice *dev, Error **errp) memory_region_add_subregion_overlap(pci_address_space_io(dev), PIIX_RCR_IOPORT, &d->rcr_mem, 1); + isa_bus_register_input_irqs(isa_bus, d->isa_irqs_in); + i8257_dma_init(isa_bus, 0); /* RTC */ From 56b1f50e3c101bfe5f52bac73de0e88438de11bd Mon Sep 17 00:00:00 2001 From: Bernhard Beschow Date: Sat, 7 Oct 2023 14:38:18 +0200 Subject: [PATCH 1008/1077] hw/i386/pc: Wire RTC ISA IRQs in south bridges Makes the south bridges a bit more self-contained and aligns PIIX3 more with PIIX4. The latter is needed for consolidating the PIIX south bridges. Signed-off-by: Bernhard Beschow Message-Id: <20231007123843.127151-11-shentey@gmail.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/i386/pc.c | 7 ++----- hw/isa/lpc_ich9.c | 3 +++ hw/isa/piix3.c | 3 +++ 3 files changed, 8 insertions(+), 5 deletions(-) diff --git a/hw/i386/pc.c b/hw/i386/pc.c index 7e6c4dc526..355e1b7cf6 100644 --- a/hw/i386/pc.c +++ b/hw/i386/pc.c @@ -1244,12 +1244,9 @@ void pc_basic_device_init(struct PCMachineState *pcms, pit_isa_irq = -1; pit_alt_irq = qdev_get_gpio_in(hpet, HPET_LEGACY_PIT_INT); rtc_irq = qdev_get_gpio_in(hpet, HPET_LEGACY_RTC_INT); + + /* overwrite connection created by south bridge */ qdev_connect_gpio_out(DEVICE(rtc_state), 0, rtc_irq); - } else { - uint32_t irq = object_property_get_uint(OBJECT(rtc_state), - "irq", - &error_fatal); - isa_connect_gpio_out(rtc_state, 0, irq); } object_property_add_alias(OBJECT(pcms), "rtc-time", OBJECT(rtc_state), diff --git a/hw/isa/lpc_ich9.c b/hw/isa/lpc_ich9.c index 3fcefc5a8a..23eba64f22 100644 --- a/hw/isa/lpc_ich9.c +++ b/hw/isa/lpc_ich9.c @@ -696,6 +696,7 @@ static void ich9_lpc_realize(PCIDevice *d, Error **errp) ICH9LPCState *lpc = ICH9_LPC_DEVICE(d); PCIBus *pci_bus = pci_get_bus(d); ISABus *isa_bus; + uint32_t irq; if ((lpc->smi_host_features & BIT_ULL(ICH9_LPC_SMI_F_CPU_HOT_UNPLUG_BIT)) && !(lpc->smi_host_features & BIT_ULL(ICH9_LPC_SMI_F_CPU_HOTPLUG_BIT))) { @@ -745,6 +746,8 @@ static void ich9_lpc_realize(PCIDevice *d, Error **errp) if (!qdev_realize(DEVICE(&lpc->rtc), BUS(isa_bus), errp)) { return; } + irq = object_property_get_uint(OBJECT(&lpc->rtc), "irq", &error_fatal); + isa_connect_gpio_out(ISA_DEVICE(&lpc->rtc), 0, irq); pci_bus_irqs(pci_bus, ich9_lpc_set_irq, d, ICH9_LPC_NB_PIRQS); pci_bus_map_irqs(pci_bus, ich9_lpc_map_irq); diff --git a/hw/isa/piix3.c b/hw/isa/piix3.c index 3e7c42fa68..11d72ca2bb 100644 --- a/hw/isa/piix3.c +++ b/hw/isa/piix3.c @@ -266,6 +266,7 @@ static void pci_piix3_realize(PCIDevice *dev, Error **errp) { PIIX3State *d = PIIX3_PCI_DEVICE(dev); ISABus *isa_bus; + uint32_t irq; isa_bus = isa_bus_new(DEVICE(d), pci_address_space(dev), pci_address_space_io(dev), errp); @@ -287,6 +288,8 @@ static void pci_piix3_realize(PCIDevice *dev, Error **errp) if (!qdev_realize(DEVICE(&d->rtc), BUS(isa_bus), errp)) { return; } + irq = object_property_get_uint(OBJECT(&d->rtc), "irq", &error_fatal); + isa_connect_gpio_out(ISA_DEVICE(&d->rtc), 0, irq); } static void build_pci_isa_aml(AcpiDevAmlIf *adev, Aml *scope) From e47e5a5b79ffd6b3ca72ea383e3c756b68402735 Mon Sep 17 00:00:00 2001 From: Bernhard Beschow Date: Sat, 7 Oct 2023 14:38:19 +0200 Subject: [PATCH 1009/1077] hw/isa/piix3: Create IDE controller in host device The IDE controller is an integral part of PIIX3 (function 1). So create it as part of the south bridge. Signed-off-by: Bernhard Beschow Reviewed-by: Michael S. Tsirkin Message-Id: <20231007123843.127151-12-shentey@gmail.com> Signed-off-by: Michael S. Tsirkin --- hw/i386/Kconfig | 1 - hw/i386/pc_piix.c | 13 ++++++------- hw/isa/Kconfig | 1 + hw/isa/piix3.c | 9 +++++++++ include/hw/southbridge/piix.h | 2 ++ 5 files changed, 18 insertions(+), 8 deletions(-) diff --git a/hw/i386/Kconfig b/hw/i386/Kconfig index 9051083c1e..ade817f1b6 100644 --- a/hw/i386/Kconfig +++ b/hw/i386/Kconfig @@ -73,7 +73,6 @@ config I440FX select PC_ACPI select PCI_I440FX select PIIX3 - select IDE_PIIX select DIMM select SMBIOS select FW_CFG_DMA diff --git a/hw/i386/pc_piix.c b/hw/i386/pc_piix.c index 5988656279..c98a997482 100644 --- a/hw/i386/pc_piix.c +++ b/hw/i386/pc_piix.c @@ -43,7 +43,6 @@ #include "net/net.h" #include "hw/ide/isa.h" #include "hw/ide/pci.h" -#include "hw/ide/piix.h" #include "hw/irq.h" #include "sysemu/kvm.h" #include "hw/i386/kvm/clock.h" @@ -290,6 +289,10 @@ static void pc_init1(MachineState *machine, isa_bus = ISA_BUS(qdev_get_child_bus(DEVICE(pci_dev), "isa.0")); rtc_state = ISA_DEVICE(object_resolve_path_component(OBJECT(pci_dev), "rtc")); + dev = DEVICE(object_resolve_path_component(OBJECT(pci_dev), "ide")); + pci_ide_create_devs(PCI_DEVICE(dev)); + idebus[0] = qdev_get_child_bus(dev, "ide.0"); + idebus[1] = qdev_get_child_bus(dev, "ide.1"); } else { isa_bus = isa_bus_new(NULL, system_memory, system_io, &error_abort); @@ -301,6 +304,8 @@ static void pc_init1(MachineState *machine, i8257_dma_init(isa_bus, 0); pcms->hpet_enabled = false; + idebus[0] = NULL; + idebus[1] = NULL; } if (x86ms->pic == ON_OFF_AUTO_ON || x86ms->pic == ON_OFF_AUTO_AUTO) { @@ -329,12 +334,6 @@ static void pc_init1(MachineState *machine, pc_nic_init(pcmc, isa_bus, pci_bus); if (pcmc->pci_enabled) { - PCIDevice *dev; - - dev = pci_create_simple(pci_bus, piix3_devfn + 1, TYPE_PIIX3_IDE); - pci_ide_create_devs(dev); - idebus[0] = qdev_get_child_bus(&dev->qdev, "ide.0"); - idebus[1] = qdev_get_child_bus(&dev->qdev, "ide.1"); pc_cmos_init(pcms, idebus[0], idebus[1], rtc_state); } #ifdef CONFIG_IDE_ISA diff --git a/hw/isa/Kconfig b/hw/isa/Kconfig index c10cbc5fc1..28345edbb3 100644 --- a/hw/isa/Kconfig +++ b/hw/isa/Kconfig @@ -34,6 +34,7 @@ config PC87312 config PIIX3 bool select I8257 + select IDE_PIIX select ISA_BUS select MC146818RTC diff --git a/hw/isa/piix3.c b/hw/isa/piix3.c index 11d72ca2bb..3f1dabade0 100644 --- a/hw/isa/piix3.c +++ b/hw/isa/piix3.c @@ -29,6 +29,7 @@ #include "hw/southbridge/piix.h" #include "hw/irq.h" #include "hw/qdev-properties.h" +#include "hw/ide/piix.h" #include "hw/isa/isa.h" #include "sysemu/runstate.h" #include "migration/vmstate.h" @@ -265,6 +266,7 @@ static const MemoryRegionOps rcr_ops = { static void pci_piix3_realize(PCIDevice *dev, Error **errp) { PIIX3State *d = PIIX3_PCI_DEVICE(dev); + PCIBus *pci_bus = pci_get_bus(dev); ISABus *isa_bus; uint32_t irq; @@ -290,6 +292,12 @@ static void pci_piix3_realize(PCIDevice *dev, Error **errp) } irq = object_property_get_uint(OBJECT(&d->rtc), "irq", &error_fatal); isa_connect_gpio_out(ISA_DEVICE(&d->rtc), 0, irq); + + /* IDE */ + qdev_prop_set_int32(DEVICE(&d->ide), "addr", dev->devfn + 1); + if (!qdev_realize(DEVICE(&d->ide), BUS(pci_bus), errp)) { + return; + } } static void build_pci_isa_aml(AcpiDevAmlIf *adev, Aml *scope) @@ -321,6 +329,7 @@ static void pci_piix3_init(Object *obj) ISA_NUM_IRQS); object_initialize_child(obj, "rtc", &d->rtc, TYPE_MC146818_RTC); + object_initialize_child(obj, "ide", &d->ide, TYPE_PIIX3_IDE); } static void pci_piix3_class_init(ObjectClass *klass, void *data) diff --git a/include/hw/southbridge/piix.h b/include/hw/southbridge/piix.h index b07ff6bb26..1daeff397c 100644 --- a/include/hw/southbridge/piix.h +++ b/include/hw/southbridge/piix.h @@ -13,6 +13,7 @@ #define HW_SOUTHBRIDGE_PIIX_H #include "hw/pci/pci_device.h" +#include "hw/ide/pci.h" #include "hw/rtc/mc146818rtc.h" /* PIRQRC[A:D]: PIRQx Route Control Registers */ @@ -52,6 +53,7 @@ struct PIIXState { int32_t pci_irq_levels_vmstate[PIIX_NUM_PIRQS]; MC146818RtcState rtc; + PCIIDEState ide; /* Reset Control Register contents */ uint8_t rcr; From 6fe4464c05f45e726fcfa4a7927f4ed27444a0ca Mon Sep 17 00:00:00 2001 From: Bernhard Beschow Date: Sat, 7 Oct 2023 14:38:20 +0200 Subject: [PATCH 1010/1077] hw/isa/piix3: Create USB controller in host device The USB controller is an integral part of PIIX3 (function 2). So create it as part of the south bridge. Note that the USB function is optional in QEMU. This is why it gets object_initialize_child()'ed in realize rather than in instance_init. Signed-off-by: Bernhard Beschow Reviewed-by: Michael S. Tsirkin Message-Id: <20231007123843.127151-13-shentey@gmail.com> Signed-off-by: Michael S. Tsirkin --- hw/i386/pc_piix.c | 7 ++----- hw/isa/Kconfig | 1 + hw/isa/piix3.c | 16 ++++++++++++++++ include/hw/southbridge/piix.h | 4 ++++ 4 files changed, 23 insertions(+), 5 deletions(-) diff --git a/hw/i386/pc_piix.c b/hw/i386/pc_piix.c index c98a997482..8dcd6851d0 100644 --- a/hw/i386/pc_piix.c +++ b/hw/i386/pc_piix.c @@ -51,7 +51,6 @@ #include "exec/memory.h" #include "hw/acpi/acpi.h" #include "hw/acpi/piix4.h" -#include "hw/usb/hcd-uhci.h" #include "qapi/error.h" #include "qemu/error-report.h" #include "sysemu/xen.h" @@ -265,6 +264,8 @@ static void pc_init1(MachineState *machine, size_t i; pci_dev = pci_new_multifunction(-1, TYPE_PIIX3_DEVICE); + object_property_set_bool(OBJECT(pci_dev), "has-usb", + machine_usb(machine), &error_abort); dev = DEVICE(pci_dev); for (i = 0; i < ISA_NUM_IRQS; i++) { qdev_connect_gpio_out_named(dev, "isa-irqs", i, x86ms->gsi[i]); @@ -359,10 +360,6 @@ static void pc_init1(MachineState *machine, } #endif - if (pcmc->pci_enabled && machine_usb(machine)) { - pci_create_simple(pci_bus, piix3_devfn + 2, TYPE_PIIX3_USB_UHCI); - } - if (pcmc->pci_enabled && x86_machine_is_acpi_enabled(X86_MACHINE(pcms))) { PCIDevice *piix4_pm; diff --git a/hw/isa/Kconfig b/hw/isa/Kconfig index 28345edbb3..1076df69ca 100644 --- a/hw/isa/Kconfig +++ b/hw/isa/Kconfig @@ -37,6 +37,7 @@ config PIIX3 select IDE_PIIX select ISA_BUS select MC146818RTC + select USB_UHCI config PIIX4 bool diff --git a/hw/isa/piix3.c b/hw/isa/piix3.c index 3f1dabade0..aebc0da23b 100644 --- a/hw/isa/piix3.c +++ b/hw/isa/piix3.c @@ -298,6 +298,16 @@ static void pci_piix3_realize(PCIDevice *dev, Error **errp) if (!qdev_realize(DEVICE(&d->ide), BUS(pci_bus), errp)) { return; } + + /* USB */ + if (d->has_usb) { + object_initialize_child(OBJECT(dev), "uhci", &d->uhci, + TYPE_PIIX3_USB_UHCI); + qdev_prop_set_int32(DEVICE(&d->uhci), "addr", dev->devfn + 2); + if (!qdev_realize(DEVICE(&d->uhci), BUS(pci_bus), errp)) { + return; + } + } } static void build_pci_isa_aml(AcpiDevAmlIf *adev, Aml *scope) @@ -332,6 +342,11 @@ static void pci_piix3_init(Object *obj) object_initialize_child(obj, "ide", &d->ide, TYPE_PIIX3_IDE); } +static Property pci_piix3_props[] = { + DEFINE_PROP_BOOL("has-usb", PIIX3State, has_usb, true), + DEFINE_PROP_END_OF_LIST(), +}; + static void pci_piix3_class_init(ObjectClass *klass, void *data) { DeviceClass *dc = DEVICE_CLASS(klass); @@ -352,6 +367,7 @@ static void pci_piix3_class_init(ObjectClass *klass, void *data) * pc_piix.c's pc_init1() */ dc->user_creatable = false; + device_class_set_props(dc, pci_piix3_props); adevc->build_dev_aml = build_pci_isa_aml; } diff --git a/include/hw/southbridge/piix.h b/include/hw/southbridge/piix.h index 1daeff397c..5cd866f1f2 100644 --- a/include/hw/southbridge/piix.h +++ b/include/hw/southbridge/piix.h @@ -15,6 +15,7 @@ #include "hw/pci/pci_device.h" #include "hw/ide/pci.h" #include "hw/rtc/mc146818rtc.h" +#include "hw/usb/hcd-uhci.h" /* PIRQRC[A:D]: PIRQx Route Control Registers */ #define PIIX_PIRQCA 0x60 @@ -54,12 +55,15 @@ struct PIIXState { MC146818RtcState rtc; PCIIDEState ide; + UHCIState uhci; /* Reset Control Register contents */ uint8_t rcr; /* IO memory region for Reset Control Register (PIIX_RCR_IOPORT) */ MemoryRegion rcr_mem; + + bool has_usb; }; typedef struct PIIXState PIIX3State; From 0a15cf0801815a359af211361fba309a2cc5c1e8 Mon Sep 17 00:00:00 2001 From: Bernhard Beschow Date: Sat, 7 Oct 2023 14:38:21 +0200 Subject: [PATCH 1011/1077] hw/isa/piix3: Create power management controller in host device The power management controller is an integral part of PIIX3 (function 3). So create it as part of the south bridge. Note that the ACPI function is optional in QEMU. This is why it gets object_initialize_child()'ed in realize rather than in instance_init. Signed-off-by: Bernhard Beschow Reviewed-by: Michael S. Tsirkin Message-Id: <20231007123843.127151-14-shentey@gmail.com> Signed-off-by: Michael S. Tsirkin --- hw/i386/pc_piix.c | 24 +++++++++++------------- hw/isa/Kconfig | 1 + hw/isa/piix3.c | 15 +++++++++++++++ include/hw/southbridge/piix.h | 6 ++++++ 4 files changed, 33 insertions(+), 13 deletions(-) diff --git a/hw/i386/pc_piix.c b/hw/i386/pc_piix.c index 8dcd6851d0..70cffcfe4f 100644 --- a/hw/i386/pc_piix.c +++ b/hw/i386/pc_piix.c @@ -50,7 +50,6 @@ #include "hw/i2c/smbus_eeprom.h" #include "exec/memory.h" #include "hw/acpi/acpi.h" -#include "hw/acpi/piix4.h" #include "qapi/error.h" #include "qemu/error-report.h" #include "sysemu/xen.h" @@ -115,7 +114,7 @@ static void pc_init1(MachineState *machine, MemoryRegion *system_io = get_system_io(); PCIBus *pci_bus = NULL; ISABus *isa_bus; - int piix3_devfn = -1; + Object *piix4_pm = NULL; qemu_irq smi_irq; GSIState *gsi_state; BusState *idebus[MAX_IDE_BUS]; @@ -266,6 +265,13 @@ static void pc_init1(MachineState *machine, pci_dev = pci_new_multifunction(-1, TYPE_PIIX3_DEVICE); object_property_set_bool(OBJECT(pci_dev), "has-usb", machine_usb(machine), &error_abort); + object_property_set_bool(OBJECT(pci_dev), "has-acpi", + x86_machine_is_acpi_enabled(x86ms), + &error_abort); + qdev_prop_set_uint32(DEVICE(pci_dev), "smb_io_base", 0xb100); + object_property_set_bool(OBJECT(pci_dev), "smm-enabled", + x86_machine_is_smm_enabled(x86ms), + &error_abort); dev = DEVICE(pci_dev); for (i = 0; i < ISA_NUM_IRQS; i++) { qdev_connect_gpio_out_named(dev, "isa-irqs", i, x86ms->gsi[i]); @@ -286,10 +292,10 @@ static void pc_init1(MachineState *machine, XEN_IOAPIC_NUM_PIRQS); } - piix3_devfn = pci_dev->devfn; isa_bus = ISA_BUS(qdev_get_child_bus(DEVICE(pci_dev), "isa.0")); rtc_state = ISA_DEVICE(object_resolve_path_component(OBJECT(pci_dev), "rtc")); + piix4_pm = object_resolve_path_component(OBJECT(pci_dev), "pm"); dev = DEVICE(object_resolve_path_component(OBJECT(pci_dev), "ide")); pci_ide_create_devs(PCI_DEVICE(dev)); idebus[0] = qdev_get_child_bus(dev, "ide.0"); @@ -360,17 +366,9 @@ static void pc_init1(MachineState *machine, } #endif - if (pcmc->pci_enabled && x86_machine_is_acpi_enabled(X86_MACHINE(pcms))) { - PCIDevice *piix4_pm; - + if (piix4_pm) { smi_irq = qemu_allocate_irq(pc_acpi_smi_interrupt, first_cpu, 0); - piix4_pm = pci_new(piix3_devfn + 3, TYPE_PIIX4_PM); - qdev_prop_set_uint32(DEVICE(piix4_pm), "smb_io_base", 0xb100); - qdev_prop_set_bit(DEVICE(piix4_pm), "smm-enabled", - x86_machine_is_smm_enabled(x86ms)); - pci_realize_and_unref(piix4_pm, pci_bus, &error_fatal); - qdev_connect_gpio_out(DEVICE(piix4_pm), 0, x86ms->gsi[9]); qdev_connect_gpio_out_named(DEVICE(piix4_pm), "smi-irq", 0, smi_irq); pcms->smbus = I2C_BUS(qdev_get_child_bus(DEVICE(piix4_pm), "i2c")); /* TODO: Populate SPD eeprom data. */ @@ -382,7 +380,7 @@ static void pc_init1(MachineState *machine, object_property_allow_set_link, OBJ_PROP_LINK_STRONG); object_property_set_link(OBJECT(machine), PC_MACHINE_ACPI_DEVICE_PROP, - OBJECT(piix4_pm), &error_abort); + piix4_pm, &error_abort); } if (machine->nvdimms_state->is_enabled) { diff --git a/hw/isa/Kconfig b/hw/isa/Kconfig index 1076df69ca..17ddb25afc 100644 --- a/hw/isa/Kconfig +++ b/hw/isa/Kconfig @@ -33,6 +33,7 @@ config PC87312 config PIIX3 bool + select ACPI_PIIX4 select I8257 select IDE_PIIX select ISA_BUS diff --git a/hw/isa/piix3.c b/hw/isa/piix3.c index aebc0da23b..5b867df299 100644 --- a/hw/isa/piix3.c +++ b/hw/isa/piix3.c @@ -308,6 +308,18 @@ static void pci_piix3_realize(PCIDevice *dev, Error **errp) return; } } + + /* Power Management */ + if (d->has_acpi) { + object_initialize_child(OBJECT(d), "pm", &d->pm, TYPE_PIIX4_PM); + qdev_prop_set_int32(DEVICE(&d->pm), "addr", dev->devfn + 3); + qdev_prop_set_uint32(DEVICE(&d->pm), "smb_io_base", d->smb_io_base); + qdev_prop_set_bit(DEVICE(&d->pm), "smm-enabled", d->smm_enabled); + if (!qdev_realize(DEVICE(&d->pm), BUS(pci_bus), errp)) { + return; + } + qdev_connect_gpio_out(DEVICE(&d->pm), 0, d->isa_irqs_in[9]); + } } static void build_pci_isa_aml(AcpiDevAmlIf *adev, Aml *scope) @@ -343,7 +355,10 @@ static void pci_piix3_init(Object *obj) } static Property pci_piix3_props[] = { + DEFINE_PROP_UINT32("smb_io_base", PIIX3State, smb_io_base, 0), + DEFINE_PROP_BOOL("has-acpi", PIIX3State, has_acpi, true), DEFINE_PROP_BOOL("has-usb", PIIX3State, has_usb, true), + DEFINE_PROP_BOOL("smm-enabled", PIIX3State, smm_enabled, false), DEFINE_PROP_END_OF_LIST(), }; diff --git a/include/hw/southbridge/piix.h b/include/hw/southbridge/piix.h index 5cd866f1f2..c56ce49fd3 100644 --- a/include/hw/southbridge/piix.h +++ b/include/hw/southbridge/piix.h @@ -13,6 +13,7 @@ #define HW_SOUTHBRIDGE_PIIX_H #include "hw/pci/pci_device.h" +#include "hw/acpi/piix4.h" #include "hw/ide/pci.h" #include "hw/rtc/mc146818rtc.h" #include "hw/usb/hcd-uhci.h" @@ -56,6 +57,9 @@ struct PIIXState { MC146818RtcState rtc; PCIIDEState ide; UHCIState uhci; + PIIX4PMState pm; + + uint32_t smb_io_base; /* Reset Control Register contents */ uint8_t rcr; @@ -63,7 +67,9 @@ struct PIIXState { /* IO memory region for Reset Control Register (PIIX_RCR_IOPORT) */ MemoryRegion rcr_mem; + bool has_acpi; bool has_usb; + bool smm_enabled; }; typedef struct PIIXState PIIX3State; From 9769cfc3e419a704ff1d7feb4621da660903499a Mon Sep 17 00:00:00 2001 From: Bernhard Beschow Date: Sat, 7 Oct 2023 14:38:22 +0200 Subject: [PATCH 1012/1077] hw/isa/piix3: Drop the "3" from PIIX base class name TYPE_PIIX3_PCI_DEVICE was the former base class of the Xen and non-Xen variants of the PIIX3 ISA device models. It will become the base class for the PIIX3 and PIIX4 device models, so drop the "3" from the type names. Signed-off-by: Bernhard Beschow Reviewed-by: Michael S. Tsirkin Message-Id: <20231007123843.127151-15-shentey@gmail.com> Signed-off-by: Michael S. Tsirkin --- hw/isa/piix3.c | 56 +++++++++++++++++------------------ include/hw/southbridge/piix.h | 6 ++-- 2 files changed, 30 insertions(+), 32 deletions(-) diff --git a/hw/isa/piix3.c b/hw/isa/piix3.c index 5b867df299..c7e59249b6 100644 --- a/hw/isa/piix3.c +++ b/hw/isa/piix3.c @@ -35,7 +35,7 @@ #include "migration/vmstate.h" #include "hw/acpi/acpi_aml_interface.h" -static void piix3_set_irq_pic(PIIX3State *piix3, int pic_irq) +static void piix3_set_irq_pic(PIIXState *piix3, int pic_irq) { qemu_set_irq(piix3->isa_irqs_in[pic_irq], !!(piix3->pic_levels & @@ -43,7 +43,7 @@ static void piix3_set_irq_pic(PIIX3State *piix3, int pic_irq) (pic_irq * PIIX_NUM_PIRQS)))); } -static void piix3_set_irq_level_internal(PIIX3State *piix3, int pirq, int level) +static void piix3_set_irq_level_internal(PIIXState *piix3, int pirq, int level) { int pic_irq; uint64_t mask; @@ -58,7 +58,7 @@ static void piix3_set_irq_level_internal(PIIX3State *piix3, int pirq, int level) piix3->pic_levels |= mask * !!level; } -static void piix3_set_irq_level(PIIX3State *piix3, int pirq, int level) +static void piix3_set_irq_level(PIIXState *piix3, int pirq, int level) { int pic_irq; @@ -74,13 +74,13 @@ static void piix3_set_irq_level(PIIX3State *piix3, int pirq, int level) static void piix3_set_irq(void *opaque, int pirq, int level) { - PIIX3State *piix3 = opaque; + PIIXState *piix3 = opaque; piix3_set_irq_level(piix3, pirq, level); } static PCIINTxRoute piix3_route_intx_pin_to_irq(void *opaque, int pin) { - PIIX3State *piix3 = opaque; + PIIXState *piix3 = opaque; int irq = piix3->dev.config[PIIX_PIRQCA + pin]; PCIINTxRoute route; @@ -95,7 +95,7 @@ static PCIINTxRoute piix3_route_intx_pin_to_irq(void *opaque, int pin) } /* irq routing is changed. so rebuild bitmap */ -static void piix3_update_irq_levels(PIIX3State *piix3) +static void piix3_update_irq_levels(PIIXState *piix3) { PCIBus *bus = pci_get_bus(&piix3->dev); int pirq; @@ -111,7 +111,7 @@ static void piix3_write_config(PCIDevice *dev, { pci_default_write_config(dev, address, val, len); if (ranges_overlap(address, len, PIIX_PIRQCA, 4)) { - PIIX3State *piix3 = PIIX3_PCI_DEVICE(dev); + PIIXState *piix3 = PIIX_PCI_DEVICE(dev); int pic_irq; pci_bus_fire_intx_routing_notifier(pci_get_bus(&piix3->dev)); @@ -124,7 +124,7 @@ static void piix3_write_config(PCIDevice *dev, static void piix3_reset(DeviceState *dev) { - PIIX3State *d = PIIX3_PCI_DEVICE(dev); + PIIXState *d = PIIX_PCI_DEVICE(dev); uint8_t *pci_conf = d->dev.config; pci_conf[0x04] = 0x07; /* master, memory and I/O */ @@ -165,7 +165,7 @@ static void piix3_reset(DeviceState *dev) static int piix3_post_load(void *opaque, int version_id) { - PIIX3State *piix3 = opaque; + PIIXState *piix3 = opaque; int pirq; /* @@ -188,7 +188,7 @@ static int piix3_post_load(void *opaque, int version_id) static int piix3_pre_save(void *opaque) { int i; - PIIX3State *piix3 = opaque; + PIIXState *piix3 = opaque; for (i = 0; i < ARRAY_SIZE(piix3->pci_irq_levels_vmstate); i++) { piix3->pci_irq_levels_vmstate[i] = @@ -200,7 +200,7 @@ static int piix3_pre_save(void *opaque) static bool piix3_rcr_needed(void *opaque) { - PIIX3State *piix3 = opaque; + PIIXState *piix3 = opaque; return (piix3->rcr != 0); } @@ -211,7 +211,7 @@ static const VMStateDescription vmstate_piix3_rcr = { .minimum_version_id = 1, .needed = piix3_rcr_needed, .fields = (VMStateField[]) { - VMSTATE_UINT8(rcr, PIIX3State), + VMSTATE_UINT8(rcr, PIIXState), VMSTATE_END_OF_LIST() } }; @@ -223,8 +223,8 @@ static const VMStateDescription vmstate_piix3 = { .post_load = piix3_post_load, .pre_save = piix3_pre_save, .fields = (VMStateField[]) { - VMSTATE_PCI_DEVICE(dev, PIIX3State), - VMSTATE_INT32_ARRAY_V(pci_irq_levels_vmstate, PIIX3State, + VMSTATE_PCI_DEVICE(dev, PIIXState), + VMSTATE_INT32_ARRAY_V(pci_irq_levels_vmstate, PIIXState, PIIX_NUM_PIRQS, 3), VMSTATE_END_OF_LIST() }, @@ -237,7 +237,7 @@ static const VMStateDescription vmstate_piix3 = { static void rcr_write(void *opaque, hwaddr addr, uint64_t val, unsigned len) { - PIIX3State *d = opaque; + PIIXState *d = opaque; if (val & 4) { qemu_system_reset_request(SHUTDOWN_CAUSE_GUEST_RESET); @@ -248,7 +248,7 @@ static void rcr_write(void *opaque, hwaddr addr, uint64_t val, unsigned len) static uint64_t rcr_read(void *opaque, hwaddr addr, unsigned len) { - PIIX3State *d = opaque; + PIIXState *d = opaque; return d->rcr; } @@ -265,7 +265,7 @@ static const MemoryRegionOps rcr_ops = { static void pci_piix3_realize(PCIDevice *dev, Error **errp) { - PIIX3State *d = PIIX3_PCI_DEVICE(dev); + PIIXState *d = PIIX_PCI_DEVICE(dev); PCIBus *pci_bus = pci_get_bus(dev); ISABus *isa_bus; uint32_t irq; @@ -345,7 +345,7 @@ static void build_pci_isa_aml(AcpiDevAmlIf *adev, Aml *scope) static void pci_piix3_init(Object *obj) { - PIIX3State *d = PIIX3_PCI_DEVICE(obj); + PIIXState *d = PIIX_PCI_DEVICE(obj); qdev_init_gpio_out_named(DEVICE(obj), d->isa_irqs_in, "isa-irqs", ISA_NUM_IRQS); @@ -355,10 +355,10 @@ static void pci_piix3_init(Object *obj) } static Property pci_piix3_props[] = { - DEFINE_PROP_UINT32("smb_io_base", PIIX3State, smb_io_base, 0), - DEFINE_PROP_BOOL("has-acpi", PIIX3State, has_acpi, true), - DEFINE_PROP_BOOL("has-usb", PIIX3State, has_usb, true), - DEFINE_PROP_BOOL("smm-enabled", PIIX3State, smm_enabled, false), + DEFINE_PROP_UINT32("smb_io_base", PIIXState, smb_io_base, 0), + DEFINE_PROP_BOOL("has-acpi", PIIXState, has_acpi, true), + DEFINE_PROP_BOOL("has-usb", PIIXState, has_usb, true), + DEFINE_PROP_BOOL("smm-enabled", PIIXState, smm_enabled, false), DEFINE_PROP_END_OF_LIST(), }; @@ -386,10 +386,10 @@ static void pci_piix3_class_init(ObjectClass *klass, void *data) adevc->build_dev_aml = build_pci_isa_aml; } -static const TypeInfo piix3_pci_type_info = { - .name = TYPE_PIIX3_PCI_DEVICE, +static const TypeInfo piix_pci_type_info = { + .name = TYPE_PIIX_PCI_DEVICE, .parent = TYPE_PCI_DEVICE, - .instance_size = sizeof(PIIX3State), + .instance_size = sizeof(PIIXState), .instance_init = pci_piix3_init, .abstract = true, .class_init = pci_piix3_class_init, @@ -403,7 +403,7 @@ static const TypeInfo piix3_pci_type_info = { static void piix3_realize(PCIDevice *dev, Error **errp) { ERRP_GUARD(); - PIIX3State *piix3 = PIIX3_PCI_DEVICE(dev); + PIIXState *piix3 = PIIX_PCI_DEVICE(dev); PCIBus *pci_bus = pci_get_bus(dev); pci_piix3_realize(dev, errp); @@ -424,13 +424,13 @@ static void piix3_class_init(ObjectClass *klass, void *data) static const TypeInfo piix3_info = { .name = TYPE_PIIX3_DEVICE, - .parent = TYPE_PIIX3_PCI_DEVICE, + .parent = TYPE_PIIX_PCI_DEVICE, .class_init = piix3_class_init, }; static void piix3_register_types(void) { - type_register_static(&piix3_pci_type_info); + type_register_static(&piix_pci_type_info); type_register_static(&piix3_info); } diff --git a/include/hw/southbridge/piix.h b/include/hw/southbridge/piix.h index c56ce49fd3..0b257e1582 100644 --- a/include/hw/southbridge/piix.h +++ b/include/hw/southbridge/piix.h @@ -71,11 +71,9 @@ struct PIIXState { bool has_usb; bool smm_enabled; }; -typedef struct PIIXState PIIX3State; -#define TYPE_PIIX3_PCI_DEVICE "pci-piix3" -DECLARE_INSTANCE_CHECKER(PIIX3State, PIIX3_PCI_DEVICE, - TYPE_PIIX3_PCI_DEVICE) +#define TYPE_PIIX_PCI_DEVICE "pci-piix" +OBJECT_DECLARE_SIMPLE_TYPE(PIIXState, PIIX_PCI_DEVICE) #define TYPE_PIIX3_DEVICE "PIIX3" #define TYPE_PIIX4_PCI_DEVICE "piix4-isa" From 06f6efefe06c7958471cbf84c56ccc87624577d8 Mon Sep 17 00:00:00 2001 From: Bernhard Beschow Date: Sat, 7 Oct 2023 14:38:23 +0200 Subject: [PATCH 1013/1077] hw/isa/piix4: Remove unused inbound ISA interrupt lines The Malta board, which is the only user of PIIX4, doesn't connect to the exported interrupt lines. PIIX3 doesn't expose such interrupt lines either, so remove them for PIIX4 for simplicity and consistency. Signed-off-by: Bernhard Beschow Reviewed-by: Michael S. Tsirkin Message-Id: <20231007123843.127151-16-shentey@gmail.com> Signed-off-by: Michael S. Tsirkin --- hw/isa/piix4.c | 8 -------- 1 file changed, 8 deletions(-) diff --git a/hw/isa/piix4.c b/hw/isa/piix4.c index e0b149f8eb..3c3c7a094c 100644 --- a/hw/isa/piix4.c +++ b/hw/isa/piix4.c @@ -148,12 +148,6 @@ static void piix4_request_i8259_irq(void *opaque, int irq, int level) qemu_set_irq(s->cpu_intr, level); } -static void piix4_set_i8259_irq(void *opaque, int irq, int level) -{ - PIIX4State *s = opaque; - qemu_set_irq(s->isa[irq], level); -} - static void piix4_rcr_write(void *opaque, hwaddr addr, uint64_t val, unsigned int len) { @@ -197,8 +191,6 @@ static void piix4_realize(PCIDevice *dev, Error **errp) return; } - qdev_init_gpio_in_named(DEVICE(dev), piix4_set_i8259_irq, - "isa", ISA_NUM_IRQS); qdev_init_gpio_out_named(DEVICE(dev), &s->cpu_intr, "intr", 1); From de710ac40867a409d5e3fbd83940ce9e1f6922d7 Mon Sep 17 00:00:00 2001 From: Bernhard Beschow Date: Sat, 7 Oct 2023 14:38:24 +0200 Subject: [PATCH 1014/1077] hw/isa/piix4: Rename "isa" attribute to "isa_irqs_in" Rename the "isa" attribute to align it with PIIX3 for consolidation. Signed-off-by: Bernhard Beschow Message-Id: <20231007123843.127151-17-shentey@gmail.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/isa/piix4.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/hw/isa/piix4.c b/hw/isa/piix4.c index 3c3c7a094c..9c8b6c98ab 100644 --- a/hw/isa/piix4.c +++ b/hw/isa/piix4.c @@ -45,7 +45,7 @@ struct PIIX4State { PCIDevice dev; qemu_irq cpu_intr; - qemu_irq *isa; + qemu_irq *isa_irqs_in; MC146818RtcState rtc; PCIIDEState ide; @@ -75,7 +75,7 @@ static void piix4_set_irq(void *opaque, int irq_num, int level) pic_level |= pci_bus_get_irq_level(bus, i); } } - qemu_set_irq(s->isa[pic_irq], pic_level); + qemu_set_irq(s->isa_irqs_in[pic_irq], pic_level); } } @@ -201,10 +201,10 @@ static void piix4_realize(PCIDevice *dev, Error **errp) /* initialize i8259 pic */ i8259_out_irq = qemu_allocate_irqs(piix4_request_i8259_irq, s, 1); - s->isa = i8259_init(isa_bus, *i8259_out_irq); + s->isa_irqs_in = i8259_init(isa_bus, *i8259_out_irq); /* initialize ISA irqs */ - isa_bus_register_input_irqs(isa_bus, s->isa); + isa_bus_register_input_irqs(isa_bus, s->isa_irqs_in); /* initialize pit */ i8254_pit_init(isa_bus, 0x40, 0, NULL); @@ -236,7 +236,7 @@ static void piix4_realize(PCIDevice *dev, Error **errp) if (!qdev_realize(DEVICE(&s->pm), BUS(pci_bus), errp)) { return; } - qdev_connect_gpio_out(DEVICE(&s->pm), 0, s->isa[9]); + qdev_connect_gpio_out(DEVICE(&s->pm), 0, s->isa_irqs_in[9]); pci_bus_irqs(pci_bus, piix4_set_irq, s, PIIX_NUM_PIRQS); } From 80ec6f5b574e5368007d8076fd32316765bf4ffb Mon Sep 17 00:00:00 2001 From: Bernhard Beschow Date: Sat, 7 Oct 2023 14:38:25 +0200 Subject: [PATCH 1015/1077] hw/isa/piix4: Rename reset control operations to match PIIX3 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Both implementations are the same and will be shared upon merging. Signed-off-by: Bernhard Beschow Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Michael S. Tsirkin Message-Id: <20231007123843.127151-18-shentey@gmail.com> Signed-off-by: Michael S. Tsirkin --- hw/isa/piix4.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/hw/isa/piix4.c b/hw/isa/piix4.c index 9c8b6c98ab..eb456622c5 100644 --- a/hw/isa/piix4.c +++ b/hw/isa/piix4.c @@ -148,8 +148,8 @@ static void piix4_request_i8259_irq(void *opaque, int irq, int level) qemu_set_irq(s->cpu_intr, level); } -static void piix4_rcr_write(void *opaque, hwaddr addr, uint64_t val, - unsigned int len) +static void rcr_write(void *opaque, hwaddr addr, uint64_t val, + unsigned int len) { PIIX4State *s = opaque; @@ -161,16 +161,16 @@ static void piix4_rcr_write(void *opaque, hwaddr addr, uint64_t val, s->rcr = val & 2; /* keep System Reset type only */ } -static uint64_t piix4_rcr_read(void *opaque, hwaddr addr, unsigned int len) +static uint64_t rcr_read(void *opaque, hwaddr addr, unsigned int len) { PIIX4State *s = opaque; return s->rcr; } -static const MemoryRegionOps piix4_rcr_ops = { - .read = piix4_rcr_read, - .write = piix4_rcr_write, +static const MemoryRegionOps rcr_ops = { + .read = rcr_read, + .write = rcr_write, .endianness = DEVICE_LITTLE_ENDIAN, .impl = { .min_access_size = 1, @@ -194,7 +194,7 @@ static void piix4_realize(PCIDevice *dev, Error **errp) qdev_init_gpio_out_named(DEVICE(dev), &s->cpu_intr, "intr", 1); - memory_region_init_io(&s->rcr_mem, OBJECT(dev), &piix4_rcr_ops, s, + memory_region_init_io(&s->rcr_mem, OBJECT(dev), &rcr_ops, s, "reset-control", 1); memory_region_add_subregion_overlap(pci_address_space_io(dev), PIIX_RCR_IOPORT, &s->rcr_mem, 1); From 74bdcfb4b2ba7958efe8e66e06757579d61ebbb3 Mon Sep 17 00:00:00 2001 From: Bernhard Beschow Date: Sat, 7 Oct 2023 14:38:26 +0200 Subject: [PATCH 1016/1077] hw/isa/piix4: Reuse struct PIIXState from PIIX3 PIIX4 has its own, private PIIX4State structure. PIIX3 has almost the same structure, provided in a public header. So reuse it and add a cpu_intr attribute to it which is only used by PIIX4. Signed-off-by: Bernhard Beschow Message-Id: <20231007123843.127151-19-shentey@gmail.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/isa/piix4.c | 26 +++++++++++--------------- include/hw/southbridge/piix.h | 1 + 2 files changed, 12 insertions(+), 15 deletions(-) diff --git a/hw/isa/piix4.c b/hw/isa/piix4.c index eb456622c5..71899aaa69 100644 --- a/hw/isa/piix4.c +++ b/hw/isa/piix4.c @@ -42,21 +42,9 @@ #include "sysemu/runstate.h" #include "qom/object.h" -struct PIIX4State { - PCIDevice dev; - qemu_irq cpu_intr; - qemu_irq *isa_irqs_in; +typedef struct PIIXState PIIX4State; - MC146818RtcState rtc; - PCIIDEState ide; - UHCIState uhci; - PIIX4PMState pm; - /* Reset Control Register */ - MemoryRegion rcr_mem; - uint8_t rcr; -}; - -OBJECT_DECLARE_SIMPLE_TYPE(PIIX4State, PIIX4_PCI_DEVICE) +DECLARE_INSTANCE_CHECKER(PIIX4State, PIIX4_PCI_DEVICE, TYPE_PIIX4_PCI_DEVICE) static void piix4_set_irq(void *opaque, int irq_num, int level) { @@ -184,6 +172,8 @@ static void piix4_realize(PCIDevice *dev, Error **errp) PCIBus *pci_bus = pci_get_bus(dev); ISABus *isa_bus; qemu_irq *i8259_out_irq; + qemu_irq *i8259; + size_t i; isa_bus = isa_bus_new(DEVICE(dev), pci_address_space(dev), pci_address_space_io(dev), errp); @@ -201,7 +191,13 @@ static void piix4_realize(PCIDevice *dev, Error **errp) /* initialize i8259 pic */ i8259_out_irq = qemu_allocate_irqs(piix4_request_i8259_irq, s, 1); - s->isa_irqs_in = i8259_init(isa_bus, *i8259_out_irq); + i8259 = i8259_init(isa_bus, *i8259_out_irq); + + for (i = 0; i < ISA_NUM_IRQS; i++) { + s->isa_irqs_in[i] = i8259[i]; + } + + g_free(i8259); /* initialize ISA irqs */ isa_bus_register_input_irqs(isa_bus, s->isa_irqs_in); diff --git a/include/hw/southbridge/piix.h b/include/hw/southbridge/piix.h index 0b257e1582..dd5f7b31c0 100644 --- a/include/hw/southbridge/piix.h +++ b/include/hw/southbridge/piix.h @@ -49,6 +49,7 @@ struct PIIXState { #endif uint64_t pic_levels; + qemu_irq cpu_intr; qemu_irq isa_irqs_in[ISA_NUM_IRQS]; /* This member isn't used. Just for save/load compatibility */ From 1697189977032c5bce6e63036277ad4d8ea2f44b Mon Sep 17 00:00:00 2001 From: Bernhard Beschow Date: Sat, 7 Oct 2023 14:38:27 +0200 Subject: [PATCH 1017/1077] hw/isa/piix3: Merge hw/isa/piix4.c Now that the PIIX3 and PIIX4 device models are sufficiently prepared, their implementations can be merged into one file for further consolidation. Signed-off-by: Bernhard Beschow Reviewed-by: Michael S. Tsirkin Message-Id: <20231007123843.127151-20-shentey@gmail.com> Signed-off-by: Michael S. Tsirkin --- MAINTAINERS | 6 +- hw/i386/Kconfig | 2 +- hw/isa/Kconfig | 11 +- hw/isa/meson.build | 3 +- hw/isa/{piix3.c => piix.c} | 190 +++++++++++++++++++++++- hw/isa/piix4.c | 290 ------------------------------------- hw/mips/Kconfig | 2 +- 7 files changed, 195 insertions(+), 309 deletions(-) rename hw/isa/{piix3.c => piix.c} (71%) delete mode 100644 hw/isa/piix4.c diff --git a/MAINTAINERS b/MAINTAINERS index 9bd4fe378d..d9fe5aa367 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1302,7 +1302,7 @@ Malta M: Philippe Mathieu-Daudé R: Aurelien Jarno S: Odd Fixes -F: hw/isa/piix4.c +F: hw/isa/piix.c F: hw/acpi/piix4.c F: hw/mips/malta.c F: hw/pci-host/gt64120.c @@ -1724,7 +1724,7 @@ F: hw/pci-host/pam.c F: include/hw/pci-host/i440fx.h F: include/hw/pci-host/q35.h F: include/hw/pci-host/pam.h -F: hw/isa/piix3.c +F: hw/isa/piix.c F: hw/isa/lpc_ich9.c F: hw/i2c/smbus_ich9.c F: hw/acpi/piix4.c @@ -2478,7 +2478,7 @@ PIIX4 South Bridge (i82371AB) M: Hervé Poussineau M: Philippe Mathieu-Daudé S: Maintained -F: hw/isa/piix4.c +F: hw/isa/piix.c F: include/hw/southbridge/piix.h Firmware configuration (fw_cfg) diff --git a/hw/i386/Kconfig b/hw/i386/Kconfig index ade817f1b6..94772c726b 100644 --- a/hw/i386/Kconfig +++ b/hw/i386/Kconfig @@ -72,7 +72,7 @@ config I440FX select PC_PCI select PC_ACPI select PCI_I440FX - select PIIX3 + select PIIX select DIMM select SMBIOS select FW_CFG_DMA diff --git a/hw/isa/Kconfig b/hw/isa/Kconfig index 17ddb25afc..040a18c070 100644 --- a/hw/isa/Kconfig +++ b/hw/isa/Kconfig @@ -31,16 +31,7 @@ config PC87312 select FDC_ISA select IDE_ISA -config PIIX3 - bool - select ACPI_PIIX4 - select I8257 - select IDE_PIIX - select ISA_BUS - select MC146818RTC - select USB_UHCI - -config PIIX4 +config PIIX bool # For historical reasons, SuperIO devices are created in the board # for PIIX4. diff --git a/hw/isa/meson.build b/hw/isa/meson.build index b855e81276..2ab99ce0c6 100644 --- a/hw/isa/meson.build +++ b/hw/isa/meson.build @@ -3,8 +3,7 @@ system_ss.add(when: 'CONFIG_I82378', if_true: files('i82378.c')) system_ss.add(when: 'CONFIG_ISA_BUS', if_true: files('isa-bus.c')) system_ss.add(when: 'CONFIG_ISA_SUPERIO', if_true: files('isa-superio.c')) system_ss.add(when: 'CONFIG_PC87312', if_true: files('pc87312.c')) -system_ss.add(when: 'CONFIG_PIIX3', if_true: files('piix3.c')) -system_ss.add(when: 'CONFIG_PIIX4', if_true: files('piix4.c')) +system_ss.add(when: 'CONFIG_PIIX', if_true: files('piix.c')) system_ss.add(when: 'CONFIG_SMC37C669', if_true: files('smc37c669-superio.c')) system_ss.add(when: 'CONFIG_VT82C686', if_true: files('vt82c686.c')) diff --git a/hw/isa/piix3.c b/hw/isa/piix.c similarity index 71% rename from hw/isa/piix3.c rename to hw/isa/piix.c index c7e59249b6..f6da334c6f 100644 --- a/hw/isa/piix3.c +++ b/hw/isa/piix.c @@ -2,6 +2,7 @@ * QEMU PIIX PCI ISA Bridge Emulation * * Copyright (c) 2006 Fabrice Bellard + * Copyright (c) 2018 Hervé Poussineau * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -27,14 +28,20 @@ #include "qapi/error.h" #include "hw/dma/i8257.h" #include "hw/southbridge/piix.h" +#include "hw/timer/i8254.h" #include "hw/irq.h" #include "hw/qdev-properties.h" #include "hw/ide/piix.h" +#include "hw/intc/i8259.h" #include "hw/isa/isa.h" #include "sysemu/runstate.h" #include "migration/vmstate.h" #include "hw/acpi/acpi_aml_interface.h" +typedef struct PIIXState PIIX4State; + +DECLARE_INSTANCE_CHECKER(PIIX4State, PIIX4_PCI_DEVICE, TYPE_PIIX4_PCI_DEVICE) + static void piix3_set_irq_pic(PIIXState *piix3, int pic_irq) { qemu_set_irq(piix3->isa_irqs_in[pic_irq], @@ -78,6 +85,33 @@ static void piix3_set_irq(void *opaque, int pirq, int level) piix3_set_irq_level(piix3, pirq, level); } +static void piix4_set_irq(void *opaque, int irq_num, int level) +{ + int i, pic_irq, pic_level; + PIIX4State *s = opaque; + PCIBus *bus = pci_get_bus(&s->dev); + + /* now we change the pic irq level according to the piix irq mappings */ + /* XXX: optimize */ + pic_irq = s->dev.config[PIIX_PIRQCA + irq_num]; + if (pic_irq < ISA_NUM_IRQS) { + /* The pic level is the logical OR of all the PCI irqs mapped to it. */ + pic_level = 0; + for (i = 0; i < PIIX_NUM_PIRQS; i++) { + if (pic_irq == s->dev.config[PIIX_PIRQCA + i]) { + pic_level |= pci_bus_get_irq_level(bus, i); + } + } + qemu_set_irq(s->isa_irqs_in[pic_irq], pic_level); + } +} + +static void piix4_request_i8259_irq(void *opaque, int irq, int level) +{ + PIIX4State *s = opaque; + qemu_set_irq(s->cpu_intr, level); +} + static PCIINTxRoute piix3_route_intx_pin_to_irq(void *opaque, int pin) { PIIXState *piix3 = opaque; @@ -122,9 +156,8 @@ static void piix3_write_config(PCIDevice *dev, } } -static void piix3_reset(DeviceState *dev) +static void piix_reset(PIIXState *d) { - PIIXState *d = PIIX_PCI_DEVICE(dev); uint8_t *pci_conf = d->dev.config; pci_conf[0x04] = 0x07; /* master, memory and I/O */ @@ -163,6 +196,13 @@ static void piix3_reset(DeviceState *dev) d->rcr = 0; } +static void piix3_reset(DeviceState *dev) +{ + PIIXState *d = PIIX_PCI_DEVICE(dev); + + piix_reset(d); +} + static int piix3_post_load(void *opaque, int version_id) { PIIXState *piix3 = opaque; @@ -185,6 +225,17 @@ static int piix3_post_load(void *opaque, int version_id) return 0; } +static int piix4_post_load(void *opaque, int version_id) +{ + PIIX4State *s = opaque; + + if (version_id == 2) { + s->rcr = 0; + } + + return 0; +} + static int piix3_pre_save(void *opaque) { int i; @@ -234,6 +285,17 @@ static const VMStateDescription vmstate_piix3 = { } }; +static const VMStateDescription vmstate_piix4 = { + .name = "PIIX4", + .version_id = 3, + .minimum_version_id = 2, + .post_load = piix4_post_load, + .fields = (VMStateField[]) { + VMSTATE_PCI_DEVICE(dev, PIIX4State), + VMSTATE_UINT8_V(rcr, PIIX4State, 3), + VMSTATE_END_OF_LIST() + } +}; static void rcr_write(void *opaque, hwaddr addr, uint64_t val, unsigned len) { @@ -428,10 +490,134 @@ static const TypeInfo piix3_info = { .class_init = piix3_class_init, }; +static void piix4_realize(PCIDevice *dev, Error **errp) +{ + PIIX4State *s = PIIX4_PCI_DEVICE(dev); + PCIBus *pci_bus = pci_get_bus(dev); + ISABus *isa_bus; + qemu_irq *i8259_out_irq; + qemu_irq *i8259; + size_t i; + + isa_bus = isa_bus_new(DEVICE(dev), pci_address_space(dev), + pci_address_space_io(dev), errp); + if (!isa_bus) { + return; + } + + qdev_init_gpio_out_named(DEVICE(dev), &s->cpu_intr, + "intr", 1); + + memory_region_init_io(&s->rcr_mem, OBJECT(dev), &rcr_ops, s, + "reset-control", 1); + memory_region_add_subregion_overlap(pci_address_space_io(dev), + PIIX_RCR_IOPORT, &s->rcr_mem, 1); + + /* initialize i8259 pic */ + i8259_out_irq = qemu_allocate_irqs(piix4_request_i8259_irq, s, 1); + i8259 = i8259_init(isa_bus, *i8259_out_irq); + + for (i = 0; i < ISA_NUM_IRQS; i++) { + s->isa_irqs_in[i] = i8259[i]; + } + + g_free(i8259); + + /* initialize ISA irqs */ + isa_bus_register_input_irqs(isa_bus, s->isa_irqs_in); + + /* initialize pit */ + i8254_pit_init(isa_bus, 0x40, 0, NULL); + + /* DMA */ + i8257_dma_init(isa_bus, 0); + + /* RTC */ + qdev_prop_set_int32(DEVICE(&s->rtc), "base_year", 2000); + if (!qdev_realize(DEVICE(&s->rtc), BUS(isa_bus), errp)) { + return; + } + s->rtc.irq = isa_get_irq(ISA_DEVICE(&s->rtc), s->rtc.isairq); + + /* IDE */ + qdev_prop_set_int32(DEVICE(&s->ide), "addr", dev->devfn + 1); + if (!qdev_realize(DEVICE(&s->ide), BUS(pci_bus), errp)) { + return; + } + + /* USB */ + qdev_prop_set_int32(DEVICE(&s->uhci), "addr", dev->devfn + 2); + if (!qdev_realize(DEVICE(&s->uhci), BUS(pci_bus), errp)) { + return; + } + + /* ACPI controller */ + qdev_prop_set_int32(DEVICE(&s->pm), "addr", dev->devfn + 3); + if (!qdev_realize(DEVICE(&s->pm), BUS(pci_bus), errp)) { + return; + } + qdev_connect_gpio_out(DEVICE(&s->pm), 0, s->isa_irqs_in[9]); + + pci_bus_irqs(pci_bus, piix4_set_irq, s, PIIX_NUM_PIRQS); +} + +static void piix4_isa_reset(DeviceState *dev) +{ + PIIX4State *s = PIIX4_PCI_DEVICE(dev); + + piix_reset(s); +} + +static void piix4_init(Object *obj) +{ + PIIX4State *s = PIIX4_PCI_DEVICE(obj); + + object_initialize_child(obj, "rtc", &s->rtc, TYPE_MC146818_RTC); + object_initialize_child(obj, "ide", &s->ide, TYPE_PIIX4_IDE); + object_initialize_child(obj, "uhci", &s->uhci, TYPE_PIIX4_USB_UHCI); + + object_initialize_child(obj, "pm", &s->pm, TYPE_PIIX4_PM); + qdev_prop_set_uint32(DEVICE(&s->pm), "smb_io_base", 0x1100); + qdev_prop_set_bit(DEVICE(&s->pm), "smm-enabled", 0); +} + +static void piix4_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); + + k->realize = piix4_realize; + k->vendor_id = PCI_VENDOR_ID_INTEL; + k->device_id = PCI_DEVICE_ID_INTEL_82371AB_0; + k->class_id = PCI_CLASS_BRIDGE_ISA; + dc->reset = piix4_isa_reset; + dc->desc = "ISA bridge"; + dc->vmsd = &vmstate_piix4; + /* + * Reason: part of PIIX4 southbridge, needs to be wired up, + * e.g. by mips_malta_init() + */ + dc->user_creatable = false; + dc->hotpluggable = false; +} + +static const TypeInfo piix4_info = { + .name = TYPE_PIIX4_PCI_DEVICE, + .parent = TYPE_PCI_DEVICE, + .instance_size = sizeof(PIIX4State), + .instance_init = piix4_init, + .class_init = piix4_class_init, + .interfaces = (InterfaceInfo[]) { + { INTERFACE_CONVENTIONAL_PCI_DEVICE }, + { }, + }, +}; + static void piix3_register_types(void) { type_register_static(&piix_pci_type_info); type_register_static(&piix3_info); + type_register_static(&piix4_info); } type_init(piix3_register_types) diff --git a/hw/isa/piix4.c b/hw/isa/piix4.c deleted file mode 100644 index 71899aaa69..0000000000 --- a/hw/isa/piix4.c +++ /dev/null @@ -1,290 +0,0 @@ -/* - * QEMU PIIX4 PCI Bridge Emulation - * - * Copyright (c) 2006 Fabrice Bellard - * Copyright (c) 2018 Hervé Poussineau - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -#include "qemu/osdep.h" -#include "qapi/error.h" -#include "hw/irq.h" -#include "hw/southbridge/piix.h" -#include "hw/pci/pci.h" -#include "hw/ide/piix.h" -#include "hw/isa/isa.h" -#include "hw/intc/i8259.h" -#include "hw/dma/i8257.h" -#include "hw/timer/i8254.h" -#include "hw/rtc/mc146818rtc.h" -#include "hw/ide/pci.h" -#include "hw/acpi/piix4.h" -#include "hw/usb/hcd-uhci.h" -#include "migration/vmstate.h" -#include "sysemu/reset.h" -#include "sysemu/runstate.h" -#include "qom/object.h" - -typedef struct PIIXState PIIX4State; - -DECLARE_INSTANCE_CHECKER(PIIX4State, PIIX4_PCI_DEVICE, TYPE_PIIX4_PCI_DEVICE) - -static void piix4_set_irq(void *opaque, int irq_num, int level) -{ - int i, pic_irq, pic_level; - PIIX4State *s = opaque; - PCIBus *bus = pci_get_bus(&s->dev); - - /* now we change the pic irq level according to the piix irq mappings */ - /* XXX: optimize */ - pic_irq = s->dev.config[PIIX_PIRQCA + irq_num]; - if (pic_irq < ISA_NUM_IRQS) { - /* The pic level is the logical OR of all the PCI irqs mapped to it. */ - pic_level = 0; - for (i = 0; i < PIIX_NUM_PIRQS; i++) { - if (pic_irq == s->dev.config[PIIX_PIRQCA + i]) { - pic_level |= pci_bus_get_irq_level(bus, i); - } - } - qemu_set_irq(s->isa_irqs_in[pic_irq], pic_level); - } -} - -static void piix4_isa_reset(DeviceState *dev) -{ - PIIX4State *d = PIIX4_PCI_DEVICE(dev); - uint8_t *pci_conf = d->dev.config; - - pci_conf[0x04] = 0x07; // master, memory and I/O - pci_conf[0x05] = 0x00; - pci_conf[0x06] = 0x00; - pci_conf[0x07] = 0x02; // PCI_status_devsel_medium - pci_conf[0x4c] = 0x4d; - pci_conf[0x4e] = 0x03; - pci_conf[0x4f] = 0x00; - pci_conf[0x60] = 0x80; - pci_conf[0x61] = 0x80; - pci_conf[0x62] = 0x80; - pci_conf[0x63] = 0x80; - pci_conf[0x69] = 0x02; - pci_conf[0x70] = 0x80; - pci_conf[0x76] = 0x0c; - pci_conf[0x77] = 0x0c; - pci_conf[0x78] = 0x02; - pci_conf[0x79] = 0x00; - pci_conf[0x80] = 0x00; - pci_conf[0x82] = 0x00; - pci_conf[0xa0] = 0x08; - pci_conf[0xa2] = 0x00; - pci_conf[0xa3] = 0x00; - pci_conf[0xa4] = 0x00; - pci_conf[0xa5] = 0x00; - pci_conf[0xa6] = 0x00; - pci_conf[0xa7] = 0x00; - pci_conf[0xa8] = 0x0f; - pci_conf[0xaa] = 0x00; - pci_conf[0xab] = 0x00; - pci_conf[0xac] = 0x00; - pci_conf[0xae] = 0x00; - - d->rcr = 0; -} - -static int piix4_post_load(void *opaque, int version_id) -{ - PIIX4State *s = opaque; - - if (version_id == 2) { - s->rcr = 0; - } - - return 0; -} - -static const VMStateDescription vmstate_piix4 = { - .name = "PIIX4", - .version_id = 3, - .minimum_version_id = 2, - .post_load = piix4_post_load, - .fields = (VMStateField[]) { - VMSTATE_PCI_DEVICE(dev, PIIX4State), - VMSTATE_UINT8_V(rcr, PIIX4State, 3), - VMSTATE_END_OF_LIST() - } -}; - -static void piix4_request_i8259_irq(void *opaque, int irq, int level) -{ - PIIX4State *s = opaque; - qemu_set_irq(s->cpu_intr, level); -} - -static void rcr_write(void *opaque, hwaddr addr, uint64_t val, - unsigned int len) -{ - PIIX4State *s = opaque; - - if (val & 4) { - qemu_system_reset_request(SHUTDOWN_CAUSE_GUEST_RESET); - return; - } - - s->rcr = val & 2; /* keep System Reset type only */ -} - -static uint64_t rcr_read(void *opaque, hwaddr addr, unsigned int len) -{ - PIIX4State *s = opaque; - - return s->rcr; -} - -static const MemoryRegionOps rcr_ops = { - .read = rcr_read, - .write = rcr_write, - .endianness = DEVICE_LITTLE_ENDIAN, - .impl = { - .min_access_size = 1, - .max_access_size = 1, - }, -}; - -static void piix4_realize(PCIDevice *dev, Error **errp) -{ - PIIX4State *s = PIIX4_PCI_DEVICE(dev); - PCIBus *pci_bus = pci_get_bus(dev); - ISABus *isa_bus; - qemu_irq *i8259_out_irq; - qemu_irq *i8259; - size_t i; - - isa_bus = isa_bus_new(DEVICE(dev), pci_address_space(dev), - pci_address_space_io(dev), errp); - if (!isa_bus) { - return; - } - - qdev_init_gpio_out_named(DEVICE(dev), &s->cpu_intr, - "intr", 1); - - memory_region_init_io(&s->rcr_mem, OBJECT(dev), &rcr_ops, s, - "reset-control", 1); - memory_region_add_subregion_overlap(pci_address_space_io(dev), - PIIX_RCR_IOPORT, &s->rcr_mem, 1); - - /* initialize i8259 pic */ - i8259_out_irq = qemu_allocate_irqs(piix4_request_i8259_irq, s, 1); - i8259 = i8259_init(isa_bus, *i8259_out_irq); - - for (i = 0; i < ISA_NUM_IRQS; i++) { - s->isa_irqs_in[i] = i8259[i]; - } - - g_free(i8259); - - /* initialize ISA irqs */ - isa_bus_register_input_irqs(isa_bus, s->isa_irqs_in); - - /* initialize pit */ - i8254_pit_init(isa_bus, 0x40, 0, NULL); - - /* DMA */ - i8257_dma_init(isa_bus, 0); - - /* RTC */ - qdev_prop_set_int32(DEVICE(&s->rtc), "base_year", 2000); - if (!qdev_realize(DEVICE(&s->rtc), BUS(isa_bus), errp)) { - return; - } - s->rtc.irq = isa_get_irq(ISA_DEVICE(&s->rtc), s->rtc.isairq); - - /* IDE */ - qdev_prop_set_int32(DEVICE(&s->ide), "addr", dev->devfn + 1); - if (!qdev_realize(DEVICE(&s->ide), BUS(pci_bus), errp)) { - return; - } - - /* USB */ - qdev_prop_set_int32(DEVICE(&s->uhci), "addr", dev->devfn + 2); - if (!qdev_realize(DEVICE(&s->uhci), BUS(pci_bus), errp)) { - return; - } - - /* ACPI controller */ - qdev_prop_set_int32(DEVICE(&s->pm), "addr", dev->devfn + 3); - if (!qdev_realize(DEVICE(&s->pm), BUS(pci_bus), errp)) { - return; - } - qdev_connect_gpio_out(DEVICE(&s->pm), 0, s->isa_irqs_in[9]); - - pci_bus_irqs(pci_bus, piix4_set_irq, s, PIIX_NUM_PIRQS); -} - -static void piix4_init(Object *obj) -{ - PIIX4State *s = PIIX4_PCI_DEVICE(obj); - - object_initialize_child(obj, "rtc", &s->rtc, TYPE_MC146818_RTC); - object_initialize_child(obj, "ide", &s->ide, TYPE_PIIX4_IDE); - object_initialize_child(obj, "uhci", &s->uhci, TYPE_PIIX4_USB_UHCI); - - object_initialize_child(obj, "pm", &s->pm, TYPE_PIIX4_PM); - qdev_prop_set_uint32(DEVICE(&s->pm), "smb_io_base", 0x1100); - qdev_prop_set_bit(DEVICE(&s->pm), "smm-enabled", 0); -} - -static void piix4_class_init(ObjectClass *klass, void *data) -{ - DeviceClass *dc = DEVICE_CLASS(klass); - PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); - - k->realize = piix4_realize; - k->vendor_id = PCI_VENDOR_ID_INTEL; - k->device_id = PCI_DEVICE_ID_INTEL_82371AB_0; - k->class_id = PCI_CLASS_BRIDGE_ISA; - dc->reset = piix4_isa_reset; - dc->desc = "ISA bridge"; - dc->vmsd = &vmstate_piix4; - /* - * Reason: part of PIIX4 southbridge, needs to be wired up, - * e.g. by mips_malta_init() - */ - dc->user_creatable = false; - dc->hotpluggable = false; -} - -static const TypeInfo piix4_info = { - .name = TYPE_PIIX4_PCI_DEVICE, - .parent = TYPE_PCI_DEVICE, - .instance_size = sizeof(PIIX4State), - .instance_init = piix4_init, - .class_init = piix4_class_init, - .interfaces = (InterfaceInfo[]) { - { INTERFACE_CONVENTIONAL_PCI_DEVICE }, - { }, - }, -}; - -static void piix4_register_types(void) -{ - type_register_static(&piix4_info); -} - -type_init(piix4_register_types) diff --git a/hw/mips/Kconfig b/hw/mips/Kconfig index da3a37e215..ac1eb06a51 100644 --- a/hw/mips/Kconfig +++ b/hw/mips/Kconfig @@ -2,7 +2,7 @@ config MALTA bool select GT64120 select ISA_SUPERIO - select PIIX4 + select PIIX config MIPSSIM bool From 2d7630f5c7dbe5ec1fc42082d135eb6e5f159ebd Mon Sep 17 00:00:00 2001 From: Bernhard Beschow Date: Sat, 7 Oct 2023 14:38:28 +0200 Subject: [PATCH 1018/1077] hw/isa/piix: Allow for optional PIC creation in PIIX3 In the PC machine, the PIC is created in board code to allow it to be virtualized with various virtualization techniques. So explicitly disable its creation in the PC machine via a property which defaults to enabled. Once the PIIX implementations are consolidated this default will keep Malta working without further ado. Signed-off-by: Bernhard Beschow Message-Id: <20231007123843.127151-21-shentey@gmail.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/i386/pc_piix.c | 2 ++ hw/isa/piix.c | 21 +++++++++++++++++++-- include/hw/southbridge/piix.h | 1 + 3 files changed, 22 insertions(+), 2 deletions(-) diff --git a/hw/i386/pc_piix.c b/hw/i386/pc_piix.c index 70cffcfe4f..fa39afd891 100644 --- a/hw/i386/pc_piix.c +++ b/hw/i386/pc_piix.c @@ -268,6 +268,8 @@ static void pc_init1(MachineState *machine, object_property_set_bool(OBJECT(pci_dev), "has-acpi", x86_machine_is_acpi_enabled(x86ms), &error_abort); + object_property_set_bool(OBJECT(pci_dev), "has-pic", false, + &error_abort); qdev_prop_set_uint32(DEVICE(pci_dev), "smb_io_base", 0xb100); object_property_set_bool(OBJECT(pci_dev), "smm-enabled", x86_machine_is_smm_enabled(x86ms), diff --git a/hw/isa/piix.c b/hw/isa/piix.c index f6da334c6f..d6d9ac6473 100644 --- a/hw/isa/piix.c +++ b/hw/isa/piix.c @@ -106,7 +106,7 @@ static void piix4_set_irq(void *opaque, int irq_num, int level) } } -static void piix4_request_i8259_irq(void *opaque, int irq, int level) +static void piix_request_i8259_irq(void *opaque, int irq, int level) { PIIX4State *s = opaque; qemu_set_irq(s->cpu_intr, level); @@ -343,6 +343,22 @@ static void pci_piix3_realize(PCIDevice *dev, Error **errp) memory_region_add_subregion_overlap(pci_address_space_io(dev), PIIX_RCR_IOPORT, &d->rcr_mem, 1); + /* PIC */ + if (d->has_pic) { + qemu_irq *i8259_out_irq = qemu_allocate_irqs(piix_request_i8259_irq, d, + 1); + qemu_irq *i8259 = i8259_init(isa_bus, *i8259_out_irq); + size_t i; + + for (i = 0; i < ISA_NUM_IRQS; i++) { + d->isa_irqs_in[i] = i8259[i]; + } + + g_free(i8259); + + qdev_init_gpio_out_named(DEVICE(dev), &d->cpu_intr, "intr", 1); + } + isa_bus_register_input_irqs(isa_bus, d->isa_irqs_in); i8257_dma_init(isa_bus, 0); @@ -419,6 +435,7 @@ static void pci_piix3_init(Object *obj) static Property pci_piix3_props[] = { DEFINE_PROP_UINT32("smb_io_base", PIIXState, smb_io_base, 0), DEFINE_PROP_BOOL("has-acpi", PIIXState, has_acpi, true), + DEFINE_PROP_BOOL("has-pic", PIIXState, has_pic, true), DEFINE_PROP_BOOL("has-usb", PIIXState, has_usb, true), DEFINE_PROP_BOOL("smm-enabled", PIIXState, smm_enabled, false), DEFINE_PROP_END_OF_LIST(), @@ -514,7 +531,7 @@ static void piix4_realize(PCIDevice *dev, Error **errp) PIIX_RCR_IOPORT, &s->rcr_mem, 1); /* initialize i8259 pic */ - i8259_out_irq = qemu_allocate_irqs(piix4_request_i8259_irq, s, 1); + i8259_out_irq = qemu_allocate_irqs(piix_request_i8259_irq, s, 1); i8259 = i8259_init(isa_bus, *i8259_out_irq); for (i = 0; i < ISA_NUM_IRQS; i++) { diff --git a/include/hw/southbridge/piix.h b/include/hw/southbridge/piix.h index dd5f7b31c0..08491693b4 100644 --- a/include/hw/southbridge/piix.h +++ b/include/hw/southbridge/piix.h @@ -69,6 +69,7 @@ struct PIIXState { MemoryRegion rcr_mem; bool has_acpi; + bool has_pic; bool has_usb; bool smm_enabled; }; From ac4330359bee7a8cf3dab7f8639190dd17f1f4d1 Mon Sep 17 00:00:00 2001 From: Bernhard Beschow Date: Sat, 7 Oct 2023 14:38:29 +0200 Subject: [PATCH 1019/1077] hw/isa/piix: Allow for optional PIT creation in PIIX3 In the PC machine, the PIT is created in board code to allow it to be virtualized with various virtualization techniques. So explicitly disable its creation in the PC machine via a property which defaults to enabled. Once the PIIX implementations are consolidated this default will keep Malta working without further ado. Signed-off-by: Bernhard Beschow Message-Id: <20231007123843.127151-22-shentey@gmail.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/i386/pc_piix.c | 2 ++ hw/isa/piix.c | 6 ++++++ include/hw/southbridge/piix.h | 1 + 3 files changed, 9 insertions(+) diff --git a/hw/i386/pc_piix.c b/hw/i386/pc_piix.c index fa39afd891..e38942a3c3 100644 --- a/hw/i386/pc_piix.c +++ b/hw/i386/pc_piix.c @@ -270,6 +270,8 @@ static void pc_init1(MachineState *machine, &error_abort); object_property_set_bool(OBJECT(pci_dev), "has-pic", false, &error_abort); + object_property_set_bool(OBJECT(pci_dev), "has-pit", false, + &error_abort); qdev_prop_set_uint32(DEVICE(pci_dev), "smb_io_base", 0xb100); object_property_set_bool(OBJECT(pci_dev), "smm-enabled", x86_machine_is_smm_enabled(x86ms), diff --git a/hw/isa/piix.c b/hw/isa/piix.c index d6d9ac6473..270b8eb1f7 100644 --- a/hw/isa/piix.c +++ b/hw/isa/piix.c @@ -361,6 +361,11 @@ static void pci_piix3_realize(PCIDevice *dev, Error **errp) isa_bus_register_input_irqs(isa_bus, d->isa_irqs_in); + /* PIT */ + if (d->has_pit) { + i8254_pit_init(isa_bus, 0x40, 0, NULL); + } + i8257_dma_init(isa_bus, 0); /* RTC */ @@ -436,6 +441,7 @@ static Property pci_piix3_props[] = { DEFINE_PROP_UINT32("smb_io_base", PIIXState, smb_io_base, 0), DEFINE_PROP_BOOL("has-acpi", PIIXState, has_acpi, true), DEFINE_PROP_BOOL("has-pic", PIIXState, has_pic, true), + DEFINE_PROP_BOOL("has-pit", PIIXState, has_pit, true), DEFINE_PROP_BOOL("has-usb", PIIXState, has_usb, true), DEFINE_PROP_BOOL("smm-enabled", PIIXState, smm_enabled, false), DEFINE_PROP_END_OF_LIST(), diff --git a/include/hw/southbridge/piix.h b/include/hw/southbridge/piix.h index 08491693b4..86709ba2e4 100644 --- a/include/hw/southbridge/piix.h +++ b/include/hw/southbridge/piix.h @@ -70,6 +70,7 @@ struct PIIXState { bool has_acpi; bool has_pic; + bool has_pit; bool has_usb; bool smm_enabled; }; From f97479cad8447caa1d77c862a0890e6ff1a3acc6 Mon Sep 17 00:00:00 2001 From: Bernhard Beschow Date: Sat, 7 Oct 2023 14:38:30 +0200 Subject: [PATCH 1020/1077] hw/isa/piix: Harmonize names of reset control memory regions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit There is no need for having different names here. Having the same name further allows code to be shared between PIIX3 and PIIX4. Signed-off-by: Bernhard Beschow Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Michael S. Tsirkin Message-Id: <20231007123843.127151-23-shentey@gmail.com> Signed-off-by: Michael S. Tsirkin --- hw/isa/piix.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/hw/isa/piix.c b/hw/isa/piix.c index 270b8eb1f7..bd66fb7475 100644 --- a/hw/isa/piix.c +++ b/hw/isa/piix.c @@ -339,7 +339,7 @@ static void pci_piix3_realize(PCIDevice *dev, Error **errp) } memory_region_init_io(&d->rcr_mem, OBJECT(dev), &rcr_ops, d, - "piix3-reset-control", 1); + "piix-reset-control", 1); memory_region_add_subregion_overlap(pci_address_space_io(dev), PIIX_RCR_IOPORT, &d->rcr_mem, 1); @@ -532,7 +532,7 @@ static void piix4_realize(PCIDevice *dev, Error **errp) "intr", 1); memory_region_init_io(&s->rcr_mem, OBJECT(dev), &rcr_ops, s, - "reset-control", 1); + "piix-reset-control", 1); memory_region_add_subregion_overlap(pci_address_space_io(dev), PIIX_RCR_IOPORT, &s->rcr_mem, 1); From 7d6f26594bc1ea1f9e7d115051e63c3a71cf0b60 Mon Sep 17 00:00:00 2001 From: Bernhard Beschow Date: Sat, 7 Oct 2023 14:38:31 +0200 Subject: [PATCH 1021/1077] hw/isa/piix: Share PIIX3's base class with PIIX4 Having a common base class will allow for futher code sharing between PIIX3 and PIIX4. Moreover, it makes PIIX4 implement the acpi-dev-aml-interface. Signed-off-by: Bernhard Beschow Reviewed-by: Michael S. Tsirkin Message-Id: <20231007123843.127151-24-shentey@gmail.com> Signed-off-by: Michael S. Tsirkin --- hw/isa/piix.c | 85 ++++++++++++++++++--------------------------------- 1 file changed, 30 insertions(+), 55 deletions(-) diff --git a/hw/isa/piix.c b/hw/isa/piix.c index bd66fb7475..8f7d6c56a8 100644 --- a/hw/isa/piix.c +++ b/hw/isa/piix.c @@ -38,10 +38,6 @@ #include "migration/vmstate.h" #include "hw/acpi/acpi_aml_interface.h" -typedef struct PIIXState PIIX4State; - -DECLARE_INSTANCE_CHECKER(PIIX4State, PIIX4_PCI_DEVICE, TYPE_PIIX4_PCI_DEVICE) - static void piix3_set_irq_pic(PIIXState *piix3, int pic_irq) { qemu_set_irq(piix3->isa_irqs_in[pic_irq], @@ -88,7 +84,7 @@ static void piix3_set_irq(void *opaque, int pirq, int level) static void piix4_set_irq(void *opaque, int irq_num, int level) { int i, pic_irq, pic_level; - PIIX4State *s = opaque; + PIIXState *s = opaque; PCIBus *bus = pci_get_bus(&s->dev); /* now we change the pic irq level according to the piix irq mappings */ @@ -108,7 +104,7 @@ static void piix4_set_irq(void *opaque, int irq_num, int level) static void piix_request_i8259_irq(void *opaque, int irq, int level) { - PIIX4State *s = opaque; + PIIXState *s = opaque; qemu_set_irq(s->cpu_intr, level); } @@ -156,8 +152,9 @@ static void piix3_write_config(PCIDevice *dev, } } -static void piix_reset(PIIXState *d) +static void piix_reset(DeviceState *dev) { + PIIXState *d = PIIX_PCI_DEVICE(dev); uint8_t *pci_conf = d->dev.config; pci_conf[0x04] = 0x07; /* master, memory and I/O */ @@ -196,13 +193,6 @@ static void piix_reset(PIIXState *d) d->rcr = 0; } -static void piix3_reset(DeviceState *dev) -{ - PIIXState *d = PIIX_PCI_DEVICE(dev); - - piix_reset(d); -} - static int piix3_post_load(void *opaque, int version_id) { PIIXState *piix3 = opaque; @@ -227,7 +217,7 @@ static int piix3_post_load(void *opaque, int version_id) static int piix4_post_load(void *opaque, int version_id) { - PIIX4State *s = opaque; + PIIXState *s = opaque; if (version_id == 2) { s->rcr = 0; @@ -291,8 +281,8 @@ static const VMStateDescription vmstate_piix4 = { .minimum_version_id = 2, .post_load = piix4_post_load, .fields = (VMStateField[]) { - VMSTATE_PCI_DEVICE(dev, PIIX4State), - VMSTATE_UINT8_V(rcr, PIIX4State, 3), + VMSTATE_PCI_DEVICE(dev, PIIXState), + VMSTATE_UINT8_V(rcr, PIIXState, 3), VMSTATE_END_OF_LIST() } }; @@ -426,7 +416,7 @@ static void build_pci_isa_aml(AcpiDevAmlIf *adev, Aml *scope) qbus_build_aml(bus, scope); } -static void pci_piix3_init(Object *obj) +static void pci_piix_init(Object *obj) { PIIXState *d = PIIX_PCI_DEVICE(obj); @@ -434,7 +424,6 @@ static void pci_piix3_init(Object *obj) ISA_NUM_IRQS); object_initialize_child(obj, "rtc", &d->rtc, TYPE_MC146818_RTC); - object_initialize_child(obj, "ide", &d->ide, TYPE_PIIX3_IDE); } static Property pci_piix3_props[] = { @@ -447,27 +436,22 @@ static Property pci_piix3_props[] = { DEFINE_PROP_END_OF_LIST(), }; -static void pci_piix3_class_init(ObjectClass *klass, void *data) +static void pci_piix_class_init(ObjectClass *klass, void *data) { DeviceClass *dc = DEVICE_CLASS(klass); PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); AcpiDevAmlIfClass *adevc = ACPI_DEV_AML_IF_CLASS(klass); - k->config_write = piix3_write_config; - dc->reset = piix3_reset; + dc->reset = piix_reset; dc->desc = "ISA bridge"; - dc->vmsd = &vmstate_piix3; dc->hotpluggable = false; k->vendor_id = PCI_VENDOR_ID_INTEL; - /* 82371SB PIIX3 PCI-to-ISA bridge (Step A1) */ - k->device_id = PCI_DEVICE_ID_INTEL_82371SB_0; k->class_id = PCI_CLASS_BRIDGE_ISA; /* - * Reason: part of PIIX3 southbridge, needs to be wired up by + * Reason: part of PIIX southbridge, needs to be wired up by e.g. * pc_piix.c's pc_init1() */ dc->user_creatable = false; - device_class_set_props(dc, pci_piix3_props); adevc->build_dev_aml = build_pci_isa_aml; } @@ -475,9 +459,9 @@ static const TypeInfo piix_pci_type_info = { .name = TYPE_PIIX_PCI_DEVICE, .parent = TYPE_PCI_DEVICE, .instance_size = sizeof(PIIXState), - .instance_init = pci_piix3_init, + .instance_init = pci_piix_init, .abstract = true, - .class_init = pci_piix3_class_init, + .class_init = pci_piix_class_init, .interfaces = (InterfaceInfo[]) { { INTERFACE_CONVENTIONAL_PCI_DEVICE }, { TYPE_ACPI_DEV_AML_IF }, @@ -500,22 +484,36 @@ static void piix3_realize(PCIDevice *dev, Error **errp) pci_bus_set_route_irq_fn(pci_bus, piix3_route_intx_pin_to_irq); } +static void piix3_init(Object *obj) +{ + PIIXState *d = PIIX_PCI_DEVICE(obj); + + object_initialize_child(obj, "ide", &d->ide, TYPE_PIIX3_IDE); +} + static void piix3_class_init(ObjectClass *klass, void *data) { + DeviceClass *dc = DEVICE_CLASS(klass); PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); + k->config_write = piix3_write_config; k->realize = piix3_realize; + /* 82371SB PIIX3 PCI-to-ISA bridge (Step A1) */ + k->device_id = PCI_DEVICE_ID_INTEL_82371SB_0; + dc->vmsd = &vmstate_piix3; + device_class_set_props(dc, pci_piix3_props); } static const TypeInfo piix3_info = { .name = TYPE_PIIX3_DEVICE, .parent = TYPE_PIIX_PCI_DEVICE, + .instance_init = piix3_init, .class_init = piix3_class_init, }; static void piix4_realize(PCIDevice *dev, Error **errp) { - PIIX4State *s = PIIX4_PCI_DEVICE(dev); + PIIXState *s = PIIX_PCI_DEVICE(dev); PCIBus *pci_bus = pci_get_bus(dev); ISABus *isa_bus; qemu_irq *i8259_out_irq; @@ -584,18 +582,10 @@ static void piix4_realize(PCIDevice *dev, Error **errp) pci_bus_irqs(pci_bus, piix4_set_irq, s, PIIX_NUM_PIRQS); } -static void piix4_isa_reset(DeviceState *dev) -{ - PIIX4State *s = PIIX4_PCI_DEVICE(dev); - - piix_reset(s); -} - static void piix4_init(Object *obj) { - PIIX4State *s = PIIX4_PCI_DEVICE(obj); + PIIXState *s = PIIX_PCI_DEVICE(obj); - object_initialize_child(obj, "rtc", &s->rtc, TYPE_MC146818_RTC); object_initialize_child(obj, "ide", &s->ide, TYPE_PIIX4_IDE); object_initialize_child(obj, "uhci", &s->uhci, TYPE_PIIX4_USB_UHCI); @@ -610,30 +600,15 @@ static void piix4_class_init(ObjectClass *klass, void *data) PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); k->realize = piix4_realize; - k->vendor_id = PCI_VENDOR_ID_INTEL; k->device_id = PCI_DEVICE_ID_INTEL_82371AB_0; - k->class_id = PCI_CLASS_BRIDGE_ISA; - dc->reset = piix4_isa_reset; - dc->desc = "ISA bridge"; dc->vmsd = &vmstate_piix4; - /* - * Reason: part of PIIX4 southbridge, needs to be wired up, - * e.g. by mips_malta_init() - */ - dc->user_creatable = false; - dc->hotpluggable = false; } static const TypeInfo piix4_info = { .name = TYPE_PIIX4_PCI_DEVICE, - .parent = TYPE_PCI_DEVICE, - .instance_size = sizeof(PIIX4State), + .parent = TYPE_PIIX_PCI_DEVICE, .instance_init = piix4_init, .class_init = piix4_class_init, - .interfaces = (InterfaceInfo[]) { - { INTERFACE_CONVENTIONAL_PCI_DEVICE }, - { }, - }, }; static void piix3_register_types(void) From 2922dbc28c74a4b3976cb4bc020980030ccfef67 Mon Sep 17 00:00:00 2001 From: Bernhard Beschow Date: Sat, 7 Oct 2023 14:38:32 +0200 Subject: [PATCH 1022/1077] hw/isa/piix: Reuse PIIX3 base class' realize method in PIIX4 Resolves duplicate code. Also makes PIIX4 respect the PIIX3 properties which get added, too. This allows for using PIIX4 in the PC machine. Signed-off-by: Bernhard Beschow Message-Id: <20231007123843.127151-25-shentey@gmail.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/isa/piix.c | 80 ++++++------------------------------------------- hw/mips/malta.c | 5 ++-- 2 files changed, 12 insertions(+), 73 deletions(-) diff --git a/hw/isa/piix.c b/hw/isa/piix.c index 8f7d6c56a8..2ab799b95e 100644 --- a/hw/isa/piix.c +++ b/hw/isa/piix.c @@ -315,7 +315,8 @@ static const MemoryRegionOps rcr_ops = { }, }; -static void pci_piix3_realize(PCIDevice *dev, Error **errp) +static void pci_piix_realize(PCIDevice *dev, const char *uhci_type, + Error **errp) { PIIXState *d = PIIX_PCI_DEVICE(dev); PCIBus *pci_bus = pci_get_bus(dev); @@ -374,8 +375,7 @@ static void pci_piix3_realize(PCIDevice *dev, Error **errp) /* USB */ if (d->has_usb) { - object_initialize_child(OBJECT(dev), "uhci", &d->uhci, - TYPE_PIIX3_USB_UHCI); + object_initialize_child(OBJECT(dev), "uhci", &d->uhci, uhci_type); qdev_prop_set_int32(DEVICE(&d->uhci), "addr", dev->devfn + 2); if (!qdev_realize(DEVICE(&d->uhci), BUS(pci_bus), errp)) { return; @@ -426,7 +426,7 @@ static void pci_piix_init(Object *obj) object_initialize_child(obj, "rtc", &d->rtc, TYPE_MC146818_RTC); } -static Property pci_piix3_props[] = { +static Property pci_piix_props[] = { DEFINE_PROP_UINT32("smb_io_base", PIIXState, smb_io_base, 0), DEFINE_PROP_BOOL("has-acpi", PIIXState, has_acpi, true), DEFINE_PROP_BOOL("has-pic", PIIXState, has_pic, true), @@ -452,6 +452,7 @@ static void pci_piix_class_init(ObjectClass *klass, void *data) * pc_piix.c's pc_init1() */ dc->user_creatable = false; + device_class_set_props(dc, pci_piix_props); adevc->build_dev_aml = build_pci_isa_aml; } @@ -475,7 +476,7 @@ static void piix3_realize(PCIDevice *dev, Error **errp) PIIXState *piix3 = PIIX_PCI_DEVICE(dev); PCIBus *pci_bus = pci_get_bus(dev); - pci_piix3_realize(dev, errp); + pci_piix_realize(dev, TYPE_PIIX3_USB_UHCI, errp); if (*errp) { return; } @@ -501,7 +502,6 @@ static void piix3_class_init(ObjectClass *klass, void *data) /* 82371SB PIIX3 PCI-to-ISA bridge (Step A1) */ k->device_id = PCI_DEVICE_ID_INTEL_82371SB_0; dc->vmsd = &vmstate_piix3; - device_class_set_props(dc, pci_piix3_props); } static const TypeInfo piix3_info = { @@ -513,72 +513,15 @@ static const TypeInfo piix3_info = { static void piix4_realize(PCIDevice *dev, Error **errp) { + ERRP_GUARD(); PIIXState *s = PIIX_PCI_DEVICE(dev); PCIBus *pci_bus = pci_get_bus(dev); - ISABus *isa_bus; - qemu_irq *i8259_out_irq; - qemu_irq *i8259; - size_t i; - isa_bus = isa_bus_new(DEVICE(dev), pci_address_space(dev), - pci_address_space_io(dev), errp); - if (!isa_bus) { + pci_piix_realize(dev, TYPE_PIIX4_USB_UHCI, errp); + if (*errp) { return; } - qdev_init_gpio_out_named(DEVICE(dev), &s->cpu_intr, - "intr", 1); - - memory_region_init_io(&s->rcr_mem, OBJECT(dev), &rcr_ops, s, - "piix-reset-control", 1); - memory_region_add_subregion_overlap(pci_address_space_io(dev), - PIIX_RCR_IOPORT, &s->rcr_mem, 1); - - /* initialize i8259 pic */ - i8259_out_irq = qemu_allocate_irqs(piix_request_i8259_irq, s, 1); - i8259 = i8259_init(isa_bus, *i8259_out_irq); - - for (i = 0; i < ISA_NUM_IRQS; i++) { - s->isa_irqs_in[i] = i8259[i]; - } - - g_free(i8259); - - /* initialize ISA irqs */ - isa_bus_register_input_irqs(isa_bus, s->isa_irqs_in); - - /* initialize pit */ - i8254_pit_init(isa_bus, 0x40, 0, NULL); - - /* DMA */ - i8257_dma_init(isa_bus, 0); - - /* RTC */ - qdev_prop_set_int32(DEVICE(&s->rtc), "base_year", 2000); - if (!qdev_realize(DEVICE(&s->rtc), BUS(isa_bus), errp)) { - return; - } - s->rtc.irq = isa_get_irq(ISA_DEVICE(&s->rtc), s->rtc.isairq); - - /* IDE */ - qdev_prop_set_int32(DEVICE(&s->ide), "addr", dev->devfn + 1); - if (!qdev_realize(DEVICE(&s->ide), BUS(pci_bus), errp)) { - return; - } - - /* USB */ - qdev_prop_set_int32(DEVICE(&s->uhci), "addr", dev->devfn + 2); - if (!qdev_realize(DEVICE(&s->uhci), BUS(pci_bus), errp)) { - return; - } - - /* ACPI controller */ - qdev_prop_set_int32(DEVICE(&s->pm), "addr", dev->devfn + 3); - if (!qdev_realize(DEVICE(&s->pm), BUS(pci_bus), errp)) { - return; - } - qdev_connect_gpio_out(DEVICE(&s->pm), 0, s->isa_irqs_in[9]); - pci_bus_irqs(pci_bus, piix4_set_irq, s, PIIX_NUM_PIRQS); } @@ -587,11 +530,6 @@ static void piix4_init(Object *obj) PIIXState *s = PIIX_PCI_DEVICE(obj); object_initialize_child(obj, "ide", &s->ide, TYPE_PIIX4_IDE); - object_initialize_child(obj, "uhci", &s->uhci, TYPE_PIIX4_USB_UHCI); - - object_initialize_child(obj, "pm", &s->pm, TYPE_PIIX4_PM); - qdev_prop_set_uint32(DEVICE(&s->pm), "smb_io_base", 0x1100); - qdev_prop_set_bit(DEVICE(&s->pm), "smm-enabled", 0); } static void piix4_class_init(ObjectClass *klass, void *data) diff --git a/hw/mips/malta.c b/hw/mips/malta.c index dac27fad9d..155f3c1cc8 100644 --- a/hw/mips/malta.c +++ b/hw/mips/malta.c @@ -1238,8 +1238,9 @@ void mips_malta_init(MachineState *machine) pci_bus_map_irqs(pci_bus, malta_pci_slot_get_pirq); /* Southbridge */ - piix4 = pci_create_simple_multifunction(pci_bus, PIIX4_PCI_DEVFN, - TYPE_PIIX4_PCI_DEVICE); + piix4 = pci_new_multifunction(PIIX4_PCI_DEVFN, TYPE_PIIX4_PCI_DEVICE); + qdev_prop_set_uint32(DEVICE(piix4), "smb_io_base", 0x1100); + pci_realize_and_unref(piix4, pci_bus, &error_fatal); isa_bus = ISA_BUS(qdev_get_child_bus(DEVICE(piix4), "isa.0")); dev = DEVICE(object_resolve_path_component(OBJECT(piix4), "ide")); From 2a62c47926420128bb23edd2ba7d4b339db86660 Mon Sep 17 00:00:00 2001 From: Bernhard Beschow Date: Sat, 7 Oct 2023 14:38:33 +0200 Subject: [PATCH 1023/1077] hw/isa/piix: Rename functions to be shared for PCI interrupt triggering PIIX4 will get the same optimizations which are already implemented for PIIX3. Signed-off-by: Bernhard Beschow Reviewed-by: Michael S. Tsirkin Message-Id: <20231007123843.127151-26-shentey@gmail.com> Signed-off-by: Michael S. Tsirkin --- hw/isa/piix.c | 72 +++++++++++++++++++++++++-------------------------- 1 file changed, 36 insertions(+), 36 deletions(-) diff --git a/hw/isa/piix.c b/hw/isa/piix.c index 2ab799b95e..449c1baaab 100644 --- a/hw/isa/piix.c +++ b/hw/isa/piix.c @@ -38,47 +38,47 @@ #include "migration/vmstate.h" #include "hw/acpi/acpi_aml_interface.h" -static void piix3_set_irq_pic(PIIXState *piix3, int pic_irq) +static void piix_set_irq_pic(PIIXState *s, int pic_irq) { - qemu_set_irq(piix3->isa_irqs_in[pic_irq], - !!(piix3->pic_levels & + qemu_set_irq(s->isa_irqs_in[pic_irq], + !!(s->pic_levels & (((1ULL << PIIX_NUM_PIRQS) - 1) << (pic_irq * PIIX_NUM_PIRQS)))); } -static void piix3_set_irq_level_internal(PIIXState *piix3, int pirq, int level) +static void piix_set_pci_irq_level_internal(PIIXState *s, int pirq, int level) { int pic_irq; uint64_t mask; - pic_irq = piix3->dev.config[PIIX_PIRQCA + pirq]; + pic_irq = s->dev.config[PIIX_PIRQCA + pirq]; if (pic_irq >= ISA_NUM_IRQS) { return; } mask = 1ULL << ((pic_irq * PIIX_NUM_PIRQS) + pirq); - piix3->pic_levels &= ~mask; - piix3->pic_levels |= mask * !!level; + s->pic_levels &= ~mask; + s->pic_levels |= mask * !!level; } -static void piix3_set_irq_level(PIIXState *piix3, int pirq, int level) +static void piix_set_pci_irq_level(PIIXState *s, int pirq, int level) { int pic_irq; - pic_irq = piix3->dev.config[PIIX_PIRQCA + pirq]; + pic_irq = s->dev.config[PIIX_PIRQCA + pirq]; if (pic_irq >= ISA_NUM_IRQS) { return; } - piix3_set_irq_level_internal(piix3, pirq, level); + piix_set_pci_irq_level_internal(s, pirq, level); - piix3_set_irq_pic(piix3, pic_irq); + piix_set_irq_pic(s, pic_irq); } -static void piix3_set_irq(void *opaque, int pirq, int level) +static void piix_set_pci_irq(void *opaque, int pirq, int level) { - PIIXState *piix3 = opaque; - piix3_set_irq_level(piix3, pirq, level); + PIIXState *s = opaque; + piix_set_pci_irq_level(s, pirq, level); } static void piix4_set_irq(void *opaque, int irq_num, int level) @@ -108,10 +108,10 @@ static void piix_request_i8259_irq(void *opaque, int irq, int level) qemu_set_irq(s->cpu_intr, level); } -static PCIINTxRoute piix3_route_intx_pin_to_irq(void *opaque, int pin) +static PCIINTxRoute piix_route_intx_pin_to_irq(void *opaque, int pin) { - PIIXState *piix3 = opaque; - int irq = piix3->dev.config[PIIX_PIRQCA + pin]; + PCIDevice *pci_dev = opaque; + int irq = pci_dev->config[PIIX_PIRQCA + pin]; PCIINTxRoute route; if (irq < ISA_NUM_IRQS) { @@ -125,29 +125,29 @@ static PCIINTxRoute piix3_route_intx_pin_to_irq(void *opaque, int pin) } /* irq routing is changed. so rebuild bitmap */ -static void piix3_update_irq_levels(PIIXState *piix3) +static void piix_update_pci_irq_levels(PIIXState *s) { - PCIBus *bus = pci_get_bus(&piix3->dev); + PCIBus *bus = pci_get_bus(&s->dev); int pirq; - piix3->pic_levels = 0; + s->pic_levels = 0; for (pirq = 0; pirq < PIIX_NUM_PIRQS; pirq++) { - piix3_set_irq_level(piix3, pirq, pci_bus_get_irq_level(bus, pirq)); + piix_set_pci_irq_level(s, pirq, pci_bus_get_irq_level(bus, pirq)); } } -static void piix3_write_config(PCIDevice *dev, - uint32_t address, uint32_t val, int len) +static void piix_write_config(PCIDevice *dev, uint32_t address, uint32_t val, + int len) { pci_default_write_config(dev, address, val, len); if (ranges_overlap(address, len, PIIX_PIRQCA, 4)) { - PIIXState *piix3 = PIIX_PCI_DEVICE(dev); + PIIXState *s = PIIX_PCI_DEVICE(dev); int pic_irq; - pci_bus_fire_intx_routing_notifier(pci_get_bus(&piix3->dev)); - piix3_update_irq_levels(piix3); + pci_bus_fire_intx_routing_notifier(pci_get_bus(&s->dev)); + piix_update_pci_irq_levels(s); for (pic_irq = 0; pic_irq < ISA_NUM_IRQS; pic_irq++) { - piix3_set_irq_pic(piix3, pic_irq); + piix_set_irq_pic(s, pic_irq); } } } @@ -193,9 +193,9 @@ static void piix_reset(DeviceState *dev) d->rcr = 0; } -static int piix3_post_load(void *opaque, int version_id) +static int piix_post_load(void *opaque, int version_id) { - PIIXState *piix3 = opaque; + PIIXState *s = opaque; int pirq; /* @@ -207,10 +207,10 @@ static int piix3_post_load(void *opaque, int version_id) * Here, we update irq levels without raising the interrupt. * Interrupt state will be deserialized separately through the i8259. */ - piix3->pic_levels = 0; + s->pic_levels = 0; for (pirq = 0; pirq < PIIX_NUM_PIRQS; pirq++) { - piix3_set_irq_level_internal(piix3, pirq, - pci_bus_get_irq_level(pci_get_bus(&piix3->dev), pirq)); + piix_set_pci_irq_level_internal(s, pirq, + pci_bus_get_irq_level(pci_get_bus(&s->dev), pirq)); } return 0; } @@ -261,7 +261,7 @@ static const VMStateDescription vmstate_piix3 = { .name = "PIIX3", .version_id = 3, .minimum_version_id = 2, - .post_load = piix3_post_load, + .post_load = piix_post_load, .pre_save = piix3_pre_save, .fields = (VMStateField[]) { VMSTATE_PCI_DEVICE(dev, PIIXState), @@ -481,8 +481,8 @@ static void piix3_realize(PCIDevice *dev, Error **errp) return; } - pci_bus_irqs(pci_bus, piix3_set_irq, piix3, PIIX_NUM_PIRQS); - pci_bus_set_route_irq_fn(pci_bus, piix3_route_intx_pin_to_irq); + pci_bus_irqs(pci_bus, piix_set_pci_irq, piix3, PIIX_NUM_PIRQS); + pci_bus_set_route_irq_fn(pci_bus, piix_route_intx_pin_to_irq); } static void piix3_init(Object *obj) @@ -497,7 +497,7 @@ static void piix3_class_init(ObjectClass *klass, void *data) DeviceClass *dc = DEVICE_CLASS(klass); PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); - k->config_write = piix3_write_config; + k->config_write = piix_write_config; k->realize = piix3_realize; /* 82371SB PIIX3 PCI-to-ISA bridge (Step A1) */ k->device_id = PCI_DEVICE_ID_INTEL_82371SB_0; From 0c9fd5a309c8449c70c727f271baf554491d4ecd Mon Sep 17 00:00:00 2001 From: Bernhard Beschow Date: Sat, 7 Oct 2023 14:38:34 +0200 Subject: [PATCH 1024/1077] hw/isa/piix: Reuse PIIX3's PCI interrupt triggering in PIIX4 Speeds up PIIX4 which resolves an old TODO. Also makes PIIX4 compatible with Xen which relies on pci_bus_fire_intx_routing_notifier() to be fired. Signed-off-by: Bernhard Beschow Reviewed-by: Michael S. Tsirkin Message-Id: <20231007123843.127151-27-shentey@gmail.com> Signed-off-by: Michael S. Tsirkin --- hw/isa/piix.c | 27 +++------------------------ 1 file changed, 3 insertions(+), 24 deletions(-) diff --git a/hw/isa/piix.c b/hw/isa/piix.c index 449c1baaab..17677c2126 100644 --- a/hw/isa/piix.c +++ b/hw/isa/piix.c @@ -81,27 +81,6 @@ static void piix_set_pci_irq(void *opaque, int pirq, int level) piix_set_pci_irq_level(s, pirq, level); } -static void piix4_set_irq(void *opaque, int irq_num, int level) -{ - int i, pic_irq, pic_level; - PIIXState *s = opaque; - PCIBus *bus = pci_get_bus(&s->dev); - - /* now we change the pic irq level according to the piix irq mappings */ - /* XXX: optimize */ - pic_irq = s->dev.config[PIIX_PIRQCA + irq_num]; - if (pic_irq < ISA_NUM_IRQS) { - /* The pic level is the logical OR of all the PCI irqs mapped to it. */ - pic_level = 0; - for (i = 0; i < PIIX_NUM_PIRQS; i++) { - if (pic_irq == s->dev.config[PIIX_PIRQCA + i]) { - pic_level |= pci_bus_get_irq_level(bus, i); - } - } - qemu_set_irq(s->isa_irqs_in[pic_irq], pic_level); - } -} - static void piix_request_i8259_irq(void *opaque, int irq, int level) { PIIXState *s = opaque; @@ -223,7 +202,7 @@ static int piix4_post_load(void *opaque, int version_id) s->rcr = 0; } - return 0; + return piix_post_load(opaque, version_id); } static int piix3_pre_save(void *opaque) @@ -442,6 +421,7 @@ static void pci_piix_class_init(ObjectClass *klass, void *data) PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); AcpiDevAmlIfClass *adevc = ACPI_DEV_AML_IF_CLASS(klass); + k->config_write = piix_write_config; dc->reset = piix_reset; dc->desc = "ISA bridge"; dc->hotpluggable = false; @@ -497,7 +477,6 @@ static void piix3_class_init(ObjectClass *klass, void *data) DeviceClass *dc = DEVICE_CLASS(klass); PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); - k->config_write = piix_write_config; k->realize = piix3_realize; /* 82371SB PIIX3 PCI-to-ISA bridge (Step A1) */ k->device_id = PCI_DEVICE_ID_INTEL_82371SB_0; @@ -522,7 +501,7 @@ static void piix4_realize(PCIDevice *dev, Error **errp) return; } - pci_bus_irqs(pci_bus, piix4_set_irq, s, PIIX_NUM_PIRQS); + pci_bus_irqs(pci_bus, piix_set_pci_irq, s, PIIX_NUM_PIRQS); } static void piix4_init(Object *obj) From a203cc532a18fdb89942fa8c87d332a2a3470379 Mon Sep 17 00:00:00 2001 From: Bernhard Beschow Date: Sat, 7 Oct 2023 14:38:35 +0200 Subject: [PATCH 1025/1077] hw/isa/piix: Resolve duplicate code regarding PCI interrupt wiring Now that both PIIX3 and PIIX4 use piix_set_irq() to trigger PCI IRQs the wiring in the respective realize methods can be shared, too. Signed-off-by: Bernhard Beschow Reviewed-by: Michael S. Tsirkin Message-Id: <20231007123843.127151-28-shentey@gmail.com> Signed-off-by: Michael S. Tsirkin --- hw/isa/piix.c | 13 ++----------- 1 file changed, 2 insertions(+), 11 deletions(-) diff --git a/hw/isa/piix.c b/hw/isa/piix.c index 17677c2126..cba2098ca2 100644 --- a/hw/isa/piix.c +++ b/hw/isa/piix.c @@ -372,6 +372,8 @@ static void pci_piix_realize(PCIDevice *dev, const char *uhci_type, } qdev_connect_gpio_out(DEVICE(&d->pm), 0, d->isa_irqs_in[9]); } + + pci_bus_irqs(pci_bus, piix_set_pci_irq, d, PIIX_NUM_PIRQS); } static void build_pci_isa_aml(AcpiDevAmlIf *adev, Aml *scope) @@ -453,7 +455,6 @@ static const TypeInfo piix_pci_type_info = { static void piix3_realize(PCIDevice *dev, Error **errp) { ERRP_GUARD(); - PIIXState *piix3 = PIIX_PCI_DEVICE(dev); PCIBus *pci_bus = pci_get_bus(dev); pci_piix_realize(dev, TYPE_PIIX3_USB_UHCI, errp); @@ -461,7 +462,6 @@ static void piix3_realize(PCIDevice *dev, Error **errp) return; } - pci_bus_irqs(pci_bus, piix_set_pci_irq, piix3, PIIX_NUM_PIRQS); pci_bus_set_route_irq_fn(pci_bus, piix_route_intx_pin_to_irq); } @@ -492,16 +492,7 @@ static const TypeInfo piix3_info = { static void piix4_realize(PCIDevice *dev, Error **errp) { - ERRP_GUARD(); - PIIXState *s = PIIX_PCI_DEVICE(dev); - PCIBus *pci_bus = pci_get_bus(dev); - pci_piix_realize(dev, TYPE_PIIX4_USB_UHCI, errp); - if (*errp) { - return; - } - - pci_bus_irqs(pci_bus, piix_set_pci_irq, s, PIIX_NUM_PIRQS); } static void piix4_init(Object *obj) From 12cecd45505c239dedc8bad2ded8eab8bc2f0391 Mon Sep 17 00:00:00 2001 From: Bernhard Beschow Date: Sat, 7 Oct 2023 14:38:36 +0200 Subject: [PATCH 1026/1077] hw/isa/piix: Implement multi-process QEMU support also for PIIX4 So far multi-process QEMU was only implemented for PIIX3. Move the support into the base class to achieve feature parity between both device models. Signed-off-by: Bernhard Beschow Message-Id: <20231007123843.127151-29-shentey@gmail.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/isa/piix.c | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/hw/isa/piix.c b/hw/isa/piix.c index cba2098ca2..04ebed5b52 100644 --- a/hw/isa/piix.c +++ b/hw/isa/piix.c @@ -374,6 +374,7 @@ static void pci_piix_realize(PCIDevice *dev, const char *uhci_type, } pci_bus_irqs(pci_bus, piix_set_pci_irq, d, PIIX_NUM_PIRQS); + pci_bus_set_route_irq_fn(pci_bus, piix_route_intx_pin_to_irq); } static void build_pci_isa_aml(AcpiDevAmlIf *adev, Aml *scope) @@ -454,15 +455,7 @@ static const TypeInfo piix_pci_type_info = { static void piix3_realize(PCIDevice *dev, Error **errp) { - ERRP_GUARD(); - PCIBus *pci_bus = pci_get_bus(dev); - pci_piix_realize(dev, TYPE_PIIX3_USB_UHCI, errp); - if (*errp) { - return; - } - - pci_bus_set_route_irq_fn(pci_bus, piix_route_intx_pin_to_irq); } static void piix3_init(Object *obj) From aa0c9aec575f6dba4e6548ad9e5de1b1899d843e Mon Sep 17 00:00:00 2001 From: Bernhard Beschow Date: Sat, 7 Oct 2023 14:38:37 +0200 Subject: [PATCH 1027/1077] hw/i386/pc_piix: Make PIIX4 south bridge usable in PC machine QEMU's PIIX3 implementation actually models the real PIIX4, but with different PCI IDs. Usually, guests deal just fine with it. Still, in order to provide a more consistent illusion to guests, allow QEMU's PIIX4 implementation to be used in the PC machine. Signed-off-by: Bernhard Beschow Message-Id: <20231007123843.127151-30-shentey@gmail.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- docs/system/target-i386-desc.rst.inc | 8 ++++ hw/i386/pc.c | 1 + hw/i386/pc_piix.c | 61 +++++++++++++++++++++++++++- include/hw/i386/pc.h | 2 + 4 files changed, 71 insertions(+), 1 deletion(-) diff --git a/docs/system/target-i386-desc.rst.inc b/docs/system/target-i386-desc.rst.inc index 7d1fffacbe..5ebbcda9db 100644 --- a/docs/system/target-i386-desc.rst.inc +++ b/docs/system/target-i386-desc.rst.inc @@ -71,3 +71,11 @@ machine property, i.e. |qemu_system_x86| some.img \ -audiodev ,id= \ -machine pcspk-audiodev= + +Machine-specific options +~~~~~~~~~~~~~~~~~~~~~~~~ + +It supports the following machine-specific options: + +- ``x-south-bridge=PIIX3|piix4-isa`` (Experimental option to select a particular + south bridge. Default: ``PIIX3``) diff --git a/hw/i386/pc.c b/hw/i386/pc.c index 355e1b7cf6..6293f57a0c 100644 --- a/hw/i386/pc.c +++ b/hw/i386/pc.c @@ -1706,6 +1706,7 @@ static void pc_machine_initfn(Object *obj) #endif /* CONFIG_VMPORT */ pcms->max_ram_below_4g = 0; /* use default */ pcms->smbios_entry_point_type = pcmc->default_smbios_ep_type; + pcms->south_bridge = pcmc->default_south_bridge; /* acpi build is enabled by default if machine supports it */ pcms->acpi_build_enabled = pcmc->has_acpi_build; diff --git a/hw/i386/pc_piix.c b/hw/i386/pc_piix.c index e38942a3c3..334d9a0299 100644 --- a/hw/i386/pc_piix.c +++ b/hw/i386/pc_piix.c @@ -262,7 +262,7 @@ static void pc_init1(MachineState *machine, DeviceState *dev; size_t i; - pci_dev = pci_new_multifunction(-1, TYPE_PIIX3_DEVICE); + pci_dev = pci_new_multifunction(-1, pcms->south_bridge); object_property_set_bool(OBJECT(pci_dev), "has-usb", machine_usb(machine), &error_abort); object_property_set_bool(OBJECT(pci_dev), "has-acpi", @@ -394,6 +394,56 @@ static void pc_init1(MachineState *machine, } } +typedef enum PCSouthBridgeOption { + PC_SOUTH_BRIDGE_OPTION_PIIX3, + PC_SOUTH_BRIDGE_OPTION_PIIX4, + PC_SOUTH_BRIDGE_OPTION_MAX, +} PCSouthBridgeOption; + +static const QEnumLookup PCSouthBridgeOption_lookup = { + .array = (const char *const[]) { + [PC_SOUTH_BRIDGE_OPTION_PIIX3] = TYPE_PIIX3_DEVICE, + [PC_SOUTH_BRIDGE_OPTION_PIIX4] = TYPE_PIIX4_PCI_DEVICE, + }, + .size = PC_SOUTH_BRIDGE_OPTION_MAX +}; + +#define NotifyVmexitOption_str(val) \ + qapi_enum_lookup(&NotifyVmexitOption_lookup, (val)) + +static int pc_get_south_bridge(Object *obj, Error **errp) +{ + PCMachineState *pcms = PC_MACHINE(obj); + int i; + + for (i = 0; i < PCSouthBridgeOption_lookup.size; i++) { + if (g_strcmp0(PCSouthBridgeOption_lookup.array[i], + pcms->south_bridge) == 0) { + return i; + } + } + + error_setg(errp, "Invalid south bridge value set"); + return 0; +} + +static void pc_set_south_bridge(Object *obj, int value, Error **errp) +{ + PCMachineState *pcms = PC_MACHINE(obj); + + if (value < 0) { + error_setg(errp, "Value can't be negative"); + return; + } + + if (value >= PCSouthBridgeOption_lookup.size) { + error_setg(errp, "Value too big"); + return; + } + + pcms->south_bridge = PCSouthBridgeOption_lookup.array[value]; +} + /* Looking for a pc_compat_2_4() function? It doesn't exist. * pc_compat_*() functions that run on machine-init time and * change global QEMU state are deprecated. Please don't create @@ -473,6 +523,8 @@ static void pc_xen_hvm_init(MachineState *machine) static void pc_i440fx_machine_options(MachineClass *m) { PCMachineClass *pcmc = PC_MACHINE_CLASS(m); + ObjectClass *oc = OBJECT_CLASS(m); + pcmc->default_south_bridge = TYPE_PIIX3_DEVICE; pcmc->pci_root_uid = 0; pcmc->default_cpu_version = 1; @@ -484,6 +536,13 @@ static void pc_i440fx_machine_options(MachineClass *m) m->no_parallel = !module_object_class_by_name(TYPE_ISA_PARALLEL); machine_class_allow_dynamic_sysbus_dev(m, TYPE_RAMFB_DEVICE); machine_class_allow_dynamic_sysbus_dev(m, TYPE_VMBUS_BRIDGE); + + object_class_property_add_enum(oc, "x-south-bridge", "PCSouthBridgeOption", + &PCSouthBridgeOption_lookup, + pc_get_south_bridge, + pc_set_south_bridge); + object_class_property_set_description(oc, "x-south-bridge", + "Use a different south bridge than PIIX3"); } static void pc_i440fx_8_2_machine_options(MachineClass *m) diff --git a/include/hw/i386/pc.h b/include/hw/i386/pc.h index bec38cb92c..29a9724524 100644 --- a/include/hw/i386/pc.h +++ b/include/hw/i386/pc.h @@ -42,6 +42,7 @@ typedef struct PCMachineState { uint64_t max_ram_below_4g; OnOffAuto vmport; SmbiosEntryPointType smbios_entry_point_type; + const char *south_bridge; bool acpi_build_enabled; bool smbus_enabled; @@ -92,6 +93,7 @@ struct PCMachineClass { /* Device configuration: */ bool pci_enabled; bool kvmclock_enabled; + const char *default_south_bridge; /* Compat options: */ From f7bd1437ba877e6509fff2b5ffce82500bc79559 Mon Sep 17 00:00:00 2001 From: Li Feng Date: Mon, 9 Oct 2023 12:46:57 +0800 Subject: [PATCH 1028/1077] vhost-user-common: send get_inflight_fd once Currently the get_inflight_fd will be sent every time the device is started, and the backend will allocate shared memory to save the inflight state. If the backend finds that it receives the second get_inflight_fd, it will release the previous shared memory, which breaks inflight working logic. This patch is a preparation for the following patches. Signed-off-by: Li Feng Reviewed-by: Raphael Norwitz Message-Id: <20231009044735.941655-2-fengli@smartx.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/scsi/vhost-scsi-common.c | 37 ++++++++++++++++++------------------- 1 file changed, 18 insertions(+), 19 deletions(-) diff --git a/hw/scsi/vhost-scsi-common.c b/hw/scsi/vhost-scsi-common.c index a06f01af26..a61cd0e907 100644 --- a/hw/scsi/vhost-scsi-common.c +++ b/hw/scsi/vhost-scsi-common.c @@ -52,20 +52,28 @@ int vhost_scsi_common_start(VHostSCSICommon *vsc) vsc->dev.acked_features = vdev->guest_features; - assert(vsc->inflight == NULL); - vsc->inflight = g_new0(struct vhost_inflight, 1); - ret = vhost_dev_get_inflight(&vsc->dev, - vs->conf.virtqueue_size, - vsc->inflight); + ret = vhost_dev_prepare_inflight(&vsc->dev, vdev); if (ret < 0) { - error_report("Error get inflight: %d", -ret); + error_report("Error setting inflight format: %d", -ret); goto err_guest_notifiers; } - ret = vhost_dev_set_inflight(&vsc->dev, vsc->inflight); - if (ret < 0) { - error_report("Error set inflight: %d", -ret); - goto err_guest_notifiers; + if (vsc->inflight) { + if (!vsc->inflight->addr) { + ret = vhost_dev_get_inflight(&vsc->dev, + vs->conf.virtqueue_size, + vsc->inflight); + if (ret < 0) { + error_report("Error getting inflight: %d", -ret); + goto err_guest_notifiers; + } + } + + ret = vhost_dev_set_inflight(&vsc->dev, vsc->inflight); + if (ret < 0) { + error_report("Error setting inflight: %d", -ret); + goto err_guest_notifiers; + } } ret = vhost_dev_start(&vsc->dev, vdev, true); @@ -85,9 +93,6 @@ int vhost_scsi_common_start(VHostSCSICommon *vsc) return ret; err_guest_notifiers: - g_free(vsc->inflight); - vsc->inflight = NULL; - k->set_guest_notifiers(qbus->parent, vsc->dev.nvqs, false); err_host_notifiers: vhost_dev_disable_notifiers(&vsc->dev, vdev); @@ -111,12 +116,6 @@ void vhost_scsi_common_stop(VHostSCSICommon *vsc) } assert(ret >= 0); - if (vsc->inflight) { - vhost_dev_free_inflight(vsc->inflight); - g_free(vsc->inflight); - vsc->inflight = NULL; - } - vhost_dev_disable_notifiers(&vsc->dev, vdev); } From 4dfcc09f48c4f81a9a4e2300065edbe6b589a6ce Mon Sep 17 00:00:00 2001 From: Li Feng Date: Mon, 9 Oct 2023 12:46:58 +0800 Subject: [PATCH 1029/1077] vhost: move and rename the conn retry times Multiple devices need this macro, move it to a common header. Signed-off-by: Li Feng Reviewed-by: Raphael Norwitz Message-Id: <20231009044735.941655-3-fengli@smartx.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/block/vhost-user-blk.c | 4 +--- hw/virtio/vhost-user-gpio.c | 3 +-- include/hw/virtio/vhost.h | 2 ++ 3 files changed, 4 insertions(+), 5 deletions(-) diff --git a/hw/block/vhost-user-blk.c b/hw/block/vhost-user-blk.c index eecf3f7a81..3c69fa47d5 100644 --- a/hw/block/vhost-user-blk.c +++ b/hw/block/vhost-user-blk.c @@ -32,8 +32,6 @@ #include "sysemu/sysemu.h" #include "sysemu/runstate.h" -#define REALIZE_CONNECTION_RETRIES 3 - static const int user_feature_bits[] = { VIRTIO_BLK_F_SIZE_MAX, VIRTIO_BLK_F_SEG_MAX, @@ -482,7 +480,7 @@ static void vhost_user_blk_device_realize(DeviceState *dev, Error **errp) s->inflight = g_new0(struct vhost_inflight, 1); s->vhost_vqs = g_new0(struct vhost_virtqueue, s->num_queues); - retries = REALIZE_CONNECTION_RETRIES; + retries = VU_REALIZE_CONN_RETRIES; assert(!*errp); do { if (*errp) { diff --git a/hw/virtio/vhost-user-gpio.c b/hw/virtio/vhost-user-gpio.c index 3d7fae3984..fc784e4213 100644 --- a/hw/virtio/vhost-user-gpio.c +++ b/hw/virtio/vhost-user-gpio.c @@ -15,7 +15,6 @@ #include "standard-headers/linux/virtio_ids.h" #include "trace.h" -#define REALIZE_CONNECTION_RETRIES 3 #define VHOST_NVQS 2 /* Features required from VirtIO */ @@ -365,7 +364,7 @@ static void vu_gpio_device_realize(DeviceState *dev, Error **errp) qemu_chr_fe_set_handlers(&gpio->chardev, NULL, NULL, vu_gpio_event, NULL, dev, NULL, true); - retries = REALIZE_CONNECTION_RETRIES; + retries = VU_REALIZE_CONN_RETRIES; g_assert(!*errp); do { if (*errp) { diff --git a/include/hw/virtio/vhost.h b/include/hw/virtio/vhost.h index 00e0a669b8..5e8183f64a 100644 --- a/include/hw/virtio/vhost.h +++ b/include/hw/virtio/vhost.h @@ -8,6 +8,8 @@ #define VHOST_F_DEVICE_IOTLB 63 #define VHOST_USER_F_PROTOCOL_FEATURES 30 +#define VU_REALIZE_CONN_RETRIES 3 + /* Generic structures common for any vhost based device. */ struct vhost_inflight { From 7962e432b4e40e4395a93aa121045c58f34195fb Mon Sep 17 00:00:00 2001 From: Li Feng Date: Mon, 9 Oct 2023 12:46:59 +0800 Subject: [PATCH 1030/1077] vhost-user-scsi: support reconnect to backend If the backend crashes and restarts, the device is broken. This patch adds reconnect for vhost-user-scsi. This patch also improves the error messages, and reports some silent errors. Tested with spdk backend. Signed-off-by: Li Feng Message-Id: <20231009044735.941655-4-fengli@smartx.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin Reviewed-by: Manos Pitsidianakis --- hw/scsi/vhost-scsi-common.c | 16 +- hw/scsi/vhost-scsi.c | 6 +- hw/scsi/vhost-user-scsi.c | 201 +++++++++++++++++++++++--- include/hw/virtio/vhost-scsi-common.h | 2 +- include/hw/virtio/vhost-user-scsi.h | 6 + 5 files changed, 201 insertions(+), 30 deletions(-) diff --git a/hw/scsi/vhost-scsi-common.c b/hw/scsi/vhost-scsi-common.c index a61cd0e907..4c8637045d 100644 --- a/hw/scsi/vhost-scsi-common.c +++ b/hw/scsi/vhost-scsi-common.c @@ -16,6 +16,7 @@ */ #include "qemu/osdep.h" +#include "qapi/error.h" #include "qemu/error-report.h" #include "qemu/module.h" #include "hw/virtio/vhost.h" @@ -25,7 +26,7 @@ #include "hw/virtio/virtio-access.h" #include "hw/fw-path-provider.h" -int vhost_scsi_common_start(VHostSCSICommon *vsc) +int vhost_scsi_common_start(VHostSCSICommon *vsc, Error **errp) { int ret, i; VirtIODevice *vdev = VIRTIO_DEVICE(vsc); @@ -35,18 +36,19 @@ int vhost_scsi_common_start(VHostSCSICommon *vsc) VirtIOSCSICommon *vs = (VirtIOSCSICommon *)vsc; if (!k->set_guest_notifiers) { - error_report("binding does not support guest notifiers"); + error_setg(errp, "binding does not support guest notifiers"); return -ENOSYS; } ret = vhost_dev_enable_notifiers(&vsc->dev, vdev); if (ret < 0) { + error_setg_errno(errp, -ret, "Error enabling host notifiers"); return ret; } ret = k->set_guest_notifiers(qbus->parent, vsc->dev.nvqs, true); if (ret < 0) { - error_report("Error binding guest notifier"); + error_setg_errno(errp, -ret, "Error binding guest notifier"); goto err_host_notifiers; } @@ -54,7 +56,7 @@ int vhost_scsi_common_start(VHostSCSICommon *vsc) ret = vhost_dev_prepare_inflight(&vsc->dev, vdev); if (ret < 0) { - error_report("Error setting inflight format: %d", -ret); + error_setg_errno(errp, -ret, "Error setting inflight format"); goto err_guest_notifiers; } @@ -64,21 +66,21 @@ int vhost_scsi_common_start(VHostSCSICommon *vsc) vs->conf.virtqueue_size, vsc->inflight); if (ret < 0) { - error_report("Error getting inflight: %d", -ret); + error_setg_errno(errp, -ret, "Error getting inflight"); goto err_guest_notifiers; } } ret = vhost_dev_set_inflight(&vsc->dev, vsc->inflight); if (ret < 0) { - error_report("Error setting inflight: %d", -ret); + error_setg_errno(errp, -ret, "Error setting inflight"); goto err_guest_notifiers; } } ret = vhost_dev_start(&vsc->dev, vdev, true); if (ret < 0) { - error_report("Error start vhost dev"); + error_setg_errno(errp, -ret, "Error starting vhost dev"); goto err_guest_notifiers; } diff --git a/hw/scsi/vhost-scsi.c b/hw/scsi/vhost-scsi.c index 443f67daa4..95cadb93e7 100644 --- a/hw/scsi/vhost-scsi.c +++ b/hw/scsi/vhost-scsi.c @@ -75,6 +75,7 @@ static int vhost_scsi_start(VHostSCSI *s) int ret, abi_version; VHostSCSICommon *vsc = VHOST_SCSI_COMMON(s); const VhostOps *vhost_ops = vsc->dev.vhost_ops; + Error *local_err = NULL; ret = vhost_ops->vhost_scsi_get_abi_version(&vsc->dev, &abi_version); if (ret < 0) { @@ -88,14 +89,15 @@ static int vhost_scsi_start(VHostSCSI *s) return -ENOSYS; } - ret = vhost_scsi_common_start(vsc); + ret = vhost_scsi_common_start(vsc, &local_err); if (ret < 0) { + error_reportf_err(local_err, "Error starting vhost-scsi"); return ret; } ret = vhost_scsi_set_endpoint(s); if (ret < 0) { - error_report("Error setting vhost-scsi endpoint"); + error_reportf_err(local_err, "Error setting vhost-scsi endpoint"); vhost_scsi_common_stop(vsc); } diff --git a/hw/scsi/vhost-user-scsi.c b/hw/scsi/vhost-user-scsi.c index b7c6100f3e..24c250d3f8 100644 --- a/hw/scsi/vhost-user-scsi.c +++ b/hw/scsi/vhost-user-scsi.c @@ -39,26 +39,56 @@ static const int user_feature_bits[] = { VHOST_INVALID_FEATURE_BIT }; +static int vhost_user_scsi_start(VHostUserSCSI *s, Error **errp) +{ + VHostSCSICommon *vsc = VHOST_SCSI_COMMON(s); + int ret; + + ret = vhost_scsi_common_start(vsc, errp); + s->started_vu = !(ret < 0); + + return ret; +} + +static void vhost_user_scsi_stop(VHostUserSCSI *s) +{ + VHostSCSICommon *vsc = VHOST_SCSI_COMMON(s); + + if (!s->started_vu) { + return; + } + s->started_vu = false; + + vhost_scsi_common_stop(vsc); +} + static void vhost_user_scsi_set_status(VirtIODevice *vdev, uint8_t status) { VHostUserSCSI *s = (VHostUserSCSI *)vdev; + DeviceState *dev = DEVICE(vdev); VHostSCSICommon *vsc = VHOST_SCSI_COMMON(s); - bool start = (status & VIRTIO_CONFIG_S_DRIVER_OK) && vdev->vm_running; + VirtIOSCSICommon *vs = VIRTIO_SCSI_COMMON(dev); + bool should_start = virtio_device_should_start(vdev, status); + Error *local_err = NULL; + int ret; - if (vhost_dev_is_started(&vsc->dev) == start) { + if (!s->connected) { return; } - if (start) { - int ret; + if (vhost_dev_is_started(&vsc->dev) == should_start) { + return; + } - ret = vhost_scsi_common_start(vsc); + if (should_start) { + ret = vhost_user_scsi_start(s, &local_err); if (ret < 0) { - error_report("unable to start vhost-user-scsi: %s", strerror(-ret)); - exit(1); + error_reportf_err(local_err, "unable to start vhost-user-scsi: %s", + strerror(-ret)); + qemu_chr_fe_disconnect(&vs->conf.chardev); } } else { - vhost_scsi_common_stop(vsc); + vhost_user_scsi_stop(s); } } @@ -66,14 +96,124 @@ static void vhost_dummy_handle_output(VirtIODevice *vdev, VirtQueue *vq) { } +static int vhost_user_scsi_connect(DeviceState *dev, Error **errp) +{ + VirtIODevice *vdev = VIRTIO_DEVICE(dev); + VHostUserSCSI *s = VHOST_USER_SCSI(vdev); + VHostSCSICommon *vsc = VHOST_SCSI_COMMON(s); + VirtIOSCSICommon *vs = VIRTIO_SCSI_COMMON(dev); + int ret = 0; + + if (s->connected) { + return 0; + } + s->connected = true; + + vsc->dev.num_queues = vs->conf.num_queues; + vsc->dev.nvqs = VIRTIO_SCSI_VQ_NUM_FIXED + vs->conf.num_queues; + vsc->dev.vqs = s->vhost_vqs; + vsc->dev.vq_index = 0; + vsc->dev.backend_features = 0; + + ret = vhost_dev_init(&vsc->dev, &s->vhost_user, VHOST_BACKEND_TYPE_USER, 0, + errp); + if (ret < 0) { + return ret; + } + + /* restore vhost state */ + if (virtio_device_started(vdev, vdev->status)) { + ret = vhost_user_scsi_start(s, errp); + } + + return ret; +} + +static void vhost_user_scsi_event(void *opaque, QEMUChrEvent event); + +static void vhost_user_scsi_disconnect(DeviceState *dev) +{ + VirtIODevice *vdev = VIRTIO_DEVICE(dev); + VHostUserSCSI *s = VHOST_USER_SCSI(vdev); + VHostSCSICommon *vsc = VHOST_SCSI_COMMON(s); + VirtIOSCSICommon *vs = VIRTIO_SCSI_COMMON(dev); + + if (!s->connected) { + return; + } + s->connected = false; + + vhost_user_scsi_stop(s); + + vhost_dev_cleanup(&vsc->dev); + + /* Re-instate the event handler for new connections */ + qemu_chr_fe_set_handlers(&vs->conf.chardev, NULL, NULL, + vhost_user_scsi_event, NULL, dev, NULL, true); +} + +static void vhost_user_scsi_event(void *opaque, QEMUChrEvent event) +{ + DeviceState *dev = opaque; + VirtIODevice *vdev = VIRTIO_DEVICE(dev); + VHostUserSCSI *s = VHOST_USER_SCSI(vdev); + VHostSCSICommon *vsc = VHOST_SCSI_COMMON(s); + VirtIOSCSICommon *vs = VIRTIO_SCSI_COMMON(dev); + Error *local_err = NULL; + + switch (event) { + case CHR_EVENT_OPENED: + if (vhost_user_scsi_connect(dev, &local_err) < 0) { + error_report_err(local_err); + qemu_chr_fe_disconnect(&vs->conf.chardev); + return; + } + break; + case CHR_EVENT_CLOSED: + /* defer close until later to avoid circular close */ + vhost_user_async_close(dev, &vs->conf.chardev, &vsc->dev, + vhost_user_scsi_disconnect); + break; + case CHR_EVENT_BREAK: + case CHR_EVENT_MUX_IN: + case CHR_EVENT_MUX_OUT: + /* Ignore */ + break; + } +} + +static int vhost_user_scsi_realize_connect(VHostUserSCSI *s, Error **errp) +{ + DeviceState *dev = DEVICE(s); + VirtIOSCSICommon *vs = VIRTIO_SCSI_COMMON(dev); + int ret; + + s->connected = false; + + ret = qemu_chr_fe_wait_connected(&vs->conf.chardev, errp); + if (ret < 0) { + return ret; + } + + ret = vhost_user_scsi_connect(dev, errp); + if (ret < 0) { + qemu_chr_fe_disconnect(&vs->conf.chardev); + return ret; + } + assert(s->connected); + + return 0; +} + static void vhost_user_scsi_realize(DeviceState *dev, Error **errp) { + ERRP_GUARD(); VirtIOSCSICommon *vs = VIRTIO_SCSI_COMMON(dev); VHostUserSCSI *s = VHOST_USER_SCSI(dev); VHostSCSICommon *vsc = VHOST_SCSI_COMMON(s); - struct vhost_virtqueue *vqs = NULL; Error *err = NULL; int ret; + int retries = VU_REALIZE_CONN_RETRIES; if (!vs->conf.chardev.chr) { error_setg(errp, "vhost-user-scsi: missing chardev"); @@ -92,18 +232,28 @@ static void vhost_user_scsi_realize(DeviceState *dev, Error **errp) goto free_virtio; } - vsc->dev.nvqs = VIRTIO_SCSI_VQ_NUM_FIXED + vs->conf.num_queues; - vsc->dev.vqs = g_new0(struct vhost_virtqueue, vsc->dev.nvqs); - vsc->dev.vq_index = 0; - vsc->dev.backend_features = 0; - vqs = vsc->dev.vqs; + vsc->inflight = g_new0(struct vhost_inflight, 1); + s->vhost_vqs = g_new0(struct vhost_virtqueue, + VIRTIO_SCSI_VQ_NUM_FIXED + vs->conf.num_queues); + + assert(!*errp); + do { + if (*errp) { + error_prepend(errp, "Reconnecting after error: "); + error_report_err(*errp); + *errp = NULL; + } + ret = vhost_user_scsi_realize_connect(s, errp); + } while (ret < 0 && retries--); - ret = vhost_dev_init(&vsc->dev, &s->vhost_user, - VHOST_BACKEND_TYPE_USER, 0, errp); if (ret < 0) { goto free_vhost; } + /* we're fully initialized, now we can operate, so add the handler */ + qemu_chr_fe_set_handlers(&vs->conf.chardev, NULL, NULL, + vhost_user_scsi_event, NULL, (void *)dev, + NULL, true); /* Channel and lun both are 0 for bootable vhost-user-scsi disk */ vsc->channel = 0; vsc->lun = 0; @@ -112,8 +262,12 @@ static void vhost_user_scsi_realize(DeviceState *dev, Error **errp) return; free_vhost: + g_free(s->vhost_vqs); + s->vhost_vqs = NULL; + g_free(vsc->inflight); + vsc->inflight = NULL; vhost_user_cleanup(&s->vhost_user); - g_free(vqs); + free_virtio: virtio_scsi_common_unrealize(dev); } @@ -123,16 +277,23 @@ static void vhost_user_scsi_unrealize(DeviceState *dev) VirtIODevice *vdev = VIRTIO_DEVICE(dev); VHostUserSCSI *s = VHOST_USER_SCSI(dev); VHostSCSICommon *vsc = VHOST_SCSI_COMMON(s); - struct vhost_virtqueue *vqs = vsc->dev.vqs; + VirtIOSCSICommon *vs = VIRTIO_SCSI_COMMON(dev); /* This will stop the vhost backend. */ vhost_user_scsi_set_status(vdev, 0); + qemu_chr_fe_set_handlers(&vs->conf.chardev, NULL, NULL, NULL, NULL, NULL, + NULL, false); vhost_dev_cleanup(&vsc->dev); - g_free(vqs); + g_free(s->vhost_vqs); + s->vhost_vqs = NULL; + + vhost_dev_free_inflight(vsc->inflight); + g_free(vsc->inflight); + vsc->inflight = NULL; - virtio_scsi_common_unrealize(dev); vhost_user_cleanup(&s->vhost_user); + virtio_scsi_common_unrealize(dev); } static Property vhost_user_scsi_properties[] = { diff --git a/include/hw/virtio/vhost-scsi-common.h b/include/hw/virtio/vhost-scsi-common.h index 18f115527c..c5d2c09455 100644 --- a/include/hw/virtio/vhost-scsi-common.h +++ b/include/hw/virtio/vhost-scsi-common.h @@ -39,7 +39,7 @@ struct VHostSCSICommon { struct vhost_inflight *inflight; }; -int vhost_scsi_common_start(VHostSCSICommon *vsc); +int vhost_scsi_common_start(VHostSCSICommon *vsc, Error **errp); void vhost_scsi_common_stop(VHostSCSICommon *vsc); char *vhost_scsi_common_get_fw_dev_path(FWPathProvider *p, BusState *bus, DeviceState *dev); diff --git a/include/hw/virtio/vhost-user-scsi.h b/include/hw/virtio/vhost-user-scsi.h index 521b08e559..78fe616ccb 100644 --- a/include/hw/virtio/vhost-user-scsi.h +++ b/include/hw/virtio/vhost-user-scsi.h @@ -28,7 +28,13 @@ OBJECT_DECLARE_SIMPLE_TYPE(VHostUserSCSI, VHOST_USER_SCSI) struct VHostUserSCSI { VHostSCSICommon parent_obj; + + /* Properties */ + bool connected; + bool started_vu; + VhostUserState vhost_user; + struct vhost_virtqueue *vhost_vqs; }; #endif /* VHOST_USER_SCSI_H */ From a6a30a7ec01c743fe71ab7461655d89afe152fcf Mon Sep 17 00:00:00 2001 From: Li Feng Date: Mon, 9 Oct 2023 12:47:00 +0800 Subject: [PATCH 1031/1077] vhost-user-scsi: start vhost when guest kicks Let's keep the same behavior as vhost-user-blk. Some old guests kick virtqueue before setting VIRTIO_CONFIG_S_DRIVER_OK. Signed-off-by: Li Feng Reviewed-by: Raphael Norwitz Message-Id: <20231009044735.941655-5-fengli@smartx.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/scsi/vhost-user-scsi.c | 48 +++++++++++++++++++++++++++++++++++---- 1 file changed, 44 insertions(+), 4 deletions(-) diff --git a/hw/scsi/vhost-user-scsi.c b/hw/scsi/vhost-user-scsi.c index 24c250d3f8..258fba5c69 100644 --- a/hw/scsi/vhost-user-scsi.c +++ b/hw/scsi/vhost-user-scsi.c @@ -92,8 +92,48 @@ static void vhost_user_scsi_set_status(VirtIODevice *vdev, uint8_t status) } } -static void vhost_dummy_handle_output(VirtIODevice *vdev, VirtQueue *vq) +static void vhost_user_scsi_handle_output(VirtIODevice *vdev, VirtQueue *vq) { + VHostUserSCSI *s = (VHostUserSCSI *)vdev; + DeviceState *dev = DEVICE(vdev); + VHostSCSICommon *vsc = VHOST_SCSI_COMMON(s); + VirtIOSCSICommon *vs = VIRTIO_SCSI_COMMON(dev); + + Error *local_err = NULL; + int i, ret; + + if (!vdev->start_on_kick) { + return; + } + + if (!s->connected) { + return; + } + + if (vhost_dev_is_started(&vsc->dev)) { + return; + } + + /* + * Some guests kick before setting VIRTIO_CONFIG_S_DRIVER_OK so start + * vhost here instead of waiting for .set_status(). + */ + ret = vhost_user_scsi_start(s, &local_err); + if (ret < 0) { + error_reportf_err(local_err, "vhost-user-scsi: vhost start failed: "); + qemu_chr_fe_disconnect(&vs->conf.chardev); + return; + } + + /* Kick right away to begin processing requests already in vring */ + for (i = 0; i < vsc->dev.nvqs; i++) { + VirtQueue *kick_vq = virtio_get_queue(vdev, i); + + if (!virtio_queue_get_desc_addr(vdev, i)) { + continue; + } + event_notifier_set(virtio_queue_get_host_notifier(kick_vq)); + } } static int vhost_user_scsi_connect(DeviceState *dev, Error **errp) @@ -220,9 +260,9 @@ static void vhost_user_scsi_realize(DeviceState *dev, Error **errp) return; } - virtio_scsi_common_realize(dev, vhost_dummy_handle_output, - vhost_dummy_handle_output, - vhost_dummy_handle_output, &err); + virtio_scsi_common_realize(dev, vhost_user_scsi_handle_output, + vhost_user_scsi_handle_output, + vhost_user_scsi_handle_output, &err); if (err != NULL) { error_propagate(errp, err); return; From f02a4b8e6431598612466f76aac64ab492849abf Mon Sep 17 00:00:00 2001 From: Li Feng Date: Mon, 9 Oct 2023 12:47:01 +0800 Subject: [PATCH 1032/1077] vhost-user: fix lost reconnect When the vhost-user is reconnecting to the backend, and if the vhost-user fails at the get_features in vhost_dev_init(), then the reconnect will fail and it will not be retriggered forever. The reason is: When the vhost-user fails at get_features, the vhost_dev_cleanup will be called immediately. vhost_dev_cleanup calls 'memset(hdev, 0, sizeof(struct vhost_dev))'. The reconnect path is: vhost_user_blk_event vhost_user_async_close(.. vhost_user_blk_disconnect ..) qemu_chr_fe_set_handlers <----- clear the notifier callback schedule vhost_user_async_close_bh The vhost->vdev is null, so the vhost_user_blk_disconnect will not be called, then the event fd callback will not be reinstalled. All vhost-user devices have this issue, including vhost-user-blk/scsi. With this patch, if the vdev->vdev is null, the fd callback will still be reinstalled. Fixes: 71e076a07d ("hw/virtio: generalise CHR_EVENT_CLOSED handling") Signed-off-by: Li Feng Reviewed-by: Raphael Norwitz Message-Id: <20231009044735.941655-6-fengli@smartx.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/block/vhost-user-blk.c | 2 +- hw/scsi/vhost-user-scsi.c | 3 ++- hw/virtio/vhost-user-gpio.c | 2 +- hw/virtio/vhost-user.c | 10 ++++++++-- include/hw/virtio/vhost-user.h | 3 ++- 5 files changed, 14 insertions(+), 6 deletions(-) diff --git a/hw/block/vhost-user-blk.c b/hw/block/vhost-user-blk.c index 3c69fa47d5..95c758200d 100644 --- a/hw/block/vhost-user-blk.c +++ b/hw/block/vhost-user-blk.c @@ -391,7 +391,7 @@ static void vhost_user_blk_event(void *opaque, QEMUChrEvent event) case CHR_EVENT_CLOSED: /* defer close until later to avoid circular close */ vhost_user_async_close(dev, &s->chardev, &s->dev, - vhost_user_blk_disconnect); + vhost_user_blk_disconnect, vhost_user_blk_event); break; case CHR_EVENT_BREAK: case CHR_EVENT_MUX_IN: diff --git a/hw/scsi/vhost-user-scsi.c b/hw/scsi/vhost-user-scsi.c index 258fba5c69..4486500cac 100644 --- a/hw/scsi/vhost-user-scsi.c +++ b/hw/scsi/vhost-user-scsi.c @@ -212,7 +212,8 @@ static void vhost_user_scsi_event(void *opaque, QEMUChrEvent event) case CHR_EVENT_CLOSED: /* defer close until later to avoid circular close */ vhost_user_async_close(dev, &vs->conf.chardev, &vsc->dev, - vhost_user_scsi_disconnect); + vhost_user_scsi_disconnect, + vhost_user_scsi_event); break; case CHR_EVENT_BREAK: case CHR_EVENT_MUX_IN: diff --git a/hw/virtio/vhost-user-gpio.c b/hw/virtio/vhost-user-gpio.c index fc784e4213..aff2d7eff6 100644 --- a/hw/virtio/vhost-user-gpio.c +++ b/hw/virtio/vhost-user-gpio.c @@ -289,7 +289,7 @@ static void vu_gpio_event(void *opaque, QEMUChrEvent event) case CHR_EVENT_CLOSED: /* defer close until later to avoid circular close */ vhost_user_async_close(dev, &gpio->chardev, &gpio->vhost_dev, - vu_gpio_disconnect); + vu_gpio_disconnect, vu_gpio_event); break; case CHR_EVENT_BREAK: case CHR_EVENT_MUX_IN: diff --git a/hw/virtio/vhost-user.c b/hw/virtio/vhost-user.c index f9414f03de..b8a7b5542d 100644 --- a/hw/virtio/vhost-user.c +++ b/hw/virtio/vhost-user.c @@ -2756,6 +2756,7 @@ typedef struct { DeviceState *dev; CharBackend *cd; struct vhost_dev *vhost; + IOEventHandler *event_cb; } VhostAsyncCallback; static void vhost_user_async_close_bh(void *opaque) @@ -2770,7 +2771,10 @@ static void vhost_user_async_close_bh(void *opaque) */ if (vhost->vdev) { data->cb(data->dev); - } + } else if (data->event_cb) { + qemu_chr_fe_set_handlers(data->cd, NULL, NULL, data->event_cb, + NULL, data->dev, NULL, true); + } g_free(data); } @@ -2782,7 +2786,8 @@ static void vhost_user_async_close_bh(void *opaque) */ void vhost_user_async_close(DeviceState *d, CharBackend *chardev, struct vhost_dev *vhost, - vu_async_close_fn cb) + vu_async_close_fn cb, + IOEventHandler *event_cb) { if (!runstate_check(RUN_STATE_SHUTDOWN)) { /* @@ -2798,6 +2803,7 @@ void vhost_user_async_close(DeviceState *d, data->dev = d; data->cd = chardev; data->vhost = vhost; + data->event_cb = event_cb; /* Disable any further notifications on the chardev */ qemu_chr_fe_set_handlers(chardev, diff --git a/include/hw/virtio/vhost-user.h b/include/hw/virtio/vhost-user.h index 9f9ddf878d..6b06ecb1bd 100644 --- a/include/hw/virtio/vhost-user.h +++ b/include/hw/virtio/vhost-user.h @@ -106,6 +106,7 @@ typedef void (*vu_async_close_fn)(DeviceState *cb); void vhost_user_async_close(DeviceState *d, CharBackend *chardev, struct vhost_dev *vhost, - vu_async_close_fn cb); + vu_async_close_fn cb, + IOEventHandler *event_cb); #endif From 4076bc86a3afd626338f2e3d018f6b884a972143 Mon Sep 17 00:00:00 2001 From: Ani Sinha Date: Wed, 11 Oct 2023 16:23:35 +0530 Subject: [PATCH 1033/1077] hw/i386/cxl: ensure maxram is greater than ram size for calculating cxl range pc_get_device_memory_range() finds the device memory size by calculating the difference between maxram and ram sizes. This calculation makes sense only when maxram is greater than the ram size. Make sure we check for that before calling pc_get_device_memory_range(). Signed-off-by: Ani Sinha Message-Id: <20231011105335.42296-1-anisinha@redhat.com> Acked-by: Jonathan Cameron Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/i386/pc.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/hw/i386/pc.c b/hw/i386/pc.c index 6293f57a0c..dbaefa7617 100644 --- a/hw/i386/pc.c +++ b/hw/i386/pc.c @@ -781,10 +781,12 @@ static void pc_get_device_memory_range(PCMachineState *pcms, static uint64_t pc_get_cxl_range_start(PCMachineState *pcms) { PCMachineClass *pcmc = PC_MACHINE_GET_CLASS(pcms); + MachineState *ms = MACHINE(pcms); hwaddr cxl_base; ram_addr_t size; - if (pcmc->has_reserved_memory) { + if (pcmc->has_reserved_memory && + (ms->ram_size < ms->maxram_size)) { pc_get_device_memory_range(pcms, &cxl_base, &size); cxl_base += size; } else { From 57a6beacd88b67af7ca9dbaf29800442a0e1bfed Mon Sep 17 00:00:00 2001 From: Jonathan Cameron Date: Thu, 12 Oct 2023 13:56:21 +0100 Subject: [PATCH 1034/1077] tests/acpi: Allow update of DSDT.cxl Addition of QTG in following patch requires an update to the test data. Signed-off-by: Jonathan Cameron Reviewed-by: Fan Ni Reviewed-by: Dave Jiang Message-Id: <20231012125623.21101-2-Jonathan.Cameron@huawei.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- tests/qtest/bios-tables-test-allowed-diff.h | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/qtest/bios-tables-test-allowed-diff.h b/tests/qtest/bios-tables-test-allowed-diff.h index dfb8523c8b..9ce0f596cc 100644 --- a/tests/qtest/bios-tables-test-allowed-diff.h +++ b/tests/qtest/bios-tables-test-allowed-diff.h @@ -1 +1,2 @@ /* List of comma-separated changed AML files to ignore */ +"tests/data/acpi/q35/DSDT.cxl", From 6cdd46f66ff91a9c13c5dc4d018ae53d2f28d74a Mon Sep 17 00:00:00 2001 From: Dave Jiang Date: Thu, 12 Oct 2023 13:56:22 +0100 Subject: [PATCH 1035/1077] hw/cxl: Add QTG _DSM support for ACPI0017 device Add a simple _DSM call support for the ACPI0017 device to return fake QTG ID values of 0 and 1 in all cases. This for _DSM plumbing testing from the OS. Following edited for readability Device (CXLM) { Name (_HID, "ACPI0017") // _HID: Hardware ID ... Method (_DSM, 4, Serialized) // _DSM: Device-Specific Method { If ((Arg0 == ToUUID ("f365f9a6-a7de-4071-a66a-b40c0b4f8e52"))) { If ((Arg2 == Zero)) { Return (Buffer (One) { 0x01 }) } If ((Arg2 == One)) { Return (Package (0x02) { One, Package (0x02) { Zero, One } }) } } } Signed-off-by: Dave Jiang Signed-off-by: Jonathan Cameron Message-Id: <20231012125623.21101-3-Jonathan.Cameron@huawei.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/acpi/cxl.c | 69 +++++++++++++++++++++++++++++++++++++++++++ hw/i386/acpi-build.c | 1 + include/hw/acpi/cxl.h | 1 + 3 files changed, 71 insertions(+) diff --git a/hw/acpi/cxl.c b/hw/acpi/cxl.c index 92b46bc932..9cd7905ea2 100644 --- a/hw/acpi/cxl.c +++ b/hw/acpi/cxl.c @@ -30,6 +30,75 @@ #include "qapi/error.h" #include "qemu/uuid.h" +void build_cxl_dsm_method(Aml *dev) +{ + Aml *method, *ifctx, *ifctx2; + + method = aml_method("_DSM", 4, AML_SERIALIZED); + { + Aml *function, *uuid; + + uuid = aml_arg(0); + function = aml_arg(2); + /* CXL spec v3.0 9.17.3.1 _DSM Function for Retrieving QTG ID */ + ifctx = aml_if(aml_equal( + uuid, aml_touuid("F365F9A6-A7DE-4071-A66A-B40C0B4F8E52"))); + + /* Function 0, standard DSM query function */ + ifctx2 = aml_if(aml_equal(function, aml_int(0))); + { + uint8_t byte_list[1] = { 0x01 }; /* function 1 only */ + + aml_append(ifctx2, + aml_return(aml_buffer(sizeof(byte_list), byte_list))); + } + aml_append(ifctx, ifctx2); + + /* + * Function 1 + * Creating a package with static values. The max supported QTG ID will + * be 1 and recommended QTG IDs are 0 and then 1. + * The values here are statically created to simplify emulation. Values + * from a real BIOS would be determined by the performance of all the + * present CXL memory and then assigned. + */ + ifctx2 = aml_if(aml_equal(function, aml_int(1))); + { + Aml *pak, *pak1; + + /* + * Return: A package containing two elements - a WORD that returns + * the maximum throttling group that the platform supports, and a + * package containing the QTG ID(s) that the platform recommends. + * Package { + * Max Supported QTG ID + * Package {QTG Recommendations} + * } + * + * While the SPEC specified WORD that hints at the value being + * 16bit, the ACPI dump of BIOS DSDT table showed that the values + * are integers with no specific size specification. aml_int() will + * be used for the values. + */ + pak1 = aml_package(2); + /* Set QTG ID of 0 */ + aml_append(pak1, aml_int(0)); + /* Set QTG ID of 1 */ + aml_append(pak1, aml_int(1)); + + pak = aml_package(2); + /* Set Max QTG 1 */ + aml_append(pak, aml_int(1)); + aml_append(pak, pak1); + + aml_append(ifctx2, aml_return(pak)); + } + aml_append(ifctx, ifctx2); + } + aml_append(method, ifctx); + aml_append(dev, method); +} + static void cedt_build_chbs(GArray *table_data, PXBCXLDev *cxl) { PXBDev *pxb = PXB_DEV(cxl); diff --git a/hw/i386/acpi-build.c b/hw/i386/acpi-build.c index b0e1f074f1..80db183b78 100644 --- a/hw/i386/acpi-build.c +++ b/hw/i386/acpi-build.c @@ -1417,6 +1417,7 @@ static void build_acpi0017(Aml *table) method = aml_method("_STA", 0, AML_NOTSERIALIZED); aml_append(method, aml_return(aml_int(0x01))); aml_append(dev, method); + build_cxl_dsm_method(dev); aml_append(scope, dev); aml_append(table, scope); diff --git a/include/hw/acpi/cxl.h b/include/hw/acpi/cxl.h index acf4418886..8f22c71530 100644 --- a/include/hw/acpi/cxl.h +++ b/include/hw/acpi/cxl.h @@ -25,5 +25,6 @@ void cxl_build_cedt(GArray *table_offsets, GArray *table_data, BIOSLinker *linker, const char *oem_id, const char *oem_table_id, CXLState *cxl_state); void build_cxl_osc_method(Aml *dev); +void build_cxl_dsm_method(Aml *dev); #endif From e0c72452559ea8dd723c5f13c64318cd1d1fef4c Mon Sep 17 00:00:00 2001 From: Jonathan Cameron Date: Thu, 12 Oct 2023 13:56:23 +0100 Subject: [PATCH 1036/1077] tests/acpi: Update DSDT.cxl with QTG DSM Description of change in previous patch. Signed-off-by: Jonathan Cameron Reviewed-by: Fan Ni Reviewed-by: Dave Jiang Message-Id: <20231012125623.21101-4-Jonathan.Cameron@huawei.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- tests/data/acpi/q35/DSDT.cxl | Bin 9655 -> 9713 bytes tests/qtest/bios-tables-test-allowed-diff.h | 1 - 2 files changed, 1 deletion(-) diff --git a/tests/data/acpi/q35/DSDT.cxl b/tests/data/acpi/q35/DSDT.cxl index ee16a861c2de7b7caaf11d91c50fcdf308815233..145301c52af9a17242bb306c210f8a7e0f01b827 100644 GIT binary patch delta 118 zcmV-+0Ez#%OYutzL{mgm@g)EN0r#;Aks)191z%G_Ut5Ak1w&X&O$c8|Nkk1nLr_UD zFflg(6bN5aR6ziw0Tef1L{m)+pfHnY5fcg!ruk*_-luUurfRed3r~(xpb3*|0HhHE Y0Rf;6lWGB^5(okT5(EMOv%Vqu1A45k9^g@gANoypGNRo(2Yn<_sbn Q@xdXE3`;iuQ2faZ03i7h)c^nh diff --git a/tests/qtest/bios-tables-test-allowed-diff.h b/tests/qtest/bios-tables-test-allowed-diff.h index 9ce0f596cc..dfb8523c8b 100644 --- a/tests/qtest/bios-tables-test-allowed-diff.h +++ b/tests/qtest/bios-tables-test-allowed-diff.h @@ -1,2 +1 @@ /* List of comma-separated changed AML files to ignore */ -"tests/data/acpi/q35/DSDT.cxl", From d4eb50380807f5e881cbb66630f210e3e6eb9750 Mon Sep 17 00:00:00 2001 From: Hanna Czenczek Date: Mon, 16 Oct 2023 10:32:01 +0200 Subject: [PATCH 1037/1077] vhost-user: Fix protocol feature bit conflict The VHOST_USER_PROTOCOL_F_XEN_MMAP feature bit was defined in f21e95ee97d, which has been part of qemu's 8.1.0 release. However, it seems it was never added to qemu's code, but it is well possible that it is already used by different front-ends outside of qemu (i.e., Xen). VHOST_USER_PROTOCOL_F_SHARED_OBJECT in contrast was added to qemu's code in 16094766627, but never defined in the vhost-user specification. As a consequence, both bits were defined to be 17, which cannot work. Regardless of whether actual code or the specification should take precedence, F_XEN_MMAP is already part of a qemu release, while F_SHARED_OBJECT is not. Therefore, bump the latter to take number 18 instead of 17, and add this to the specification. Take the opportunity to add at least a little note on the VhostUserShared structure to the specification. This structure is referenced by the new commands introduced in 16094766627, but was not defined. Fixes: 160947666276c5b7f6bca4d746bcac2966635d79 ("vhost-user: add shared_object msg") Signed-off-by: Hanna Czenczek Message-Id: <20231016083201.23736-1-hreitz@redhat.com> Reviewed-by: Emmanouil Pitsidianakis Reviewed-by: Stefano Garzarella Reviewed-by: Viresh Kumar Reviewed-by: Stefan Hajnoczi Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- docs/interop/vhost-user.rst | 11 +++++++++++ include/hw/virtio/vhost-user.h | 3 ++- subprojects/libvhost-user/libvhost-user.h | 3 ++- 3 files changed, 15 insertions(+), 2 deletions(-) diff --git a/docs/interop/vhost-user.rst b/docs/interop/vhost-user.rst index 415bb47a19..768fb5c28c 100644 --- a/docs/interop/vhost-user.rst +++ b/docs/interop/vhost-user.rst @@ -275,6 +275,16 @@ Inflight description :queue size: a 16-bit size of virtqueues +VhostUserShared +^^^^^^^^^^^^^^^ + ++------+ +| UUID | ++------+ + +:UUID: 16 bytes UUID, whose first three components (a 32-bit value, then + two 16-bit values) are stored in big endian. + C structure ----------- @@ -885,6 +895,7 @@ Protocol features #define VHOST_USER_PROTOCOL_F_CONFIGURE_MEM_SLOTS 15 #define VHOST_USER_PROTOCOL_F_STATUS 16 #define VHOST_USER_PROTOCOL_F_XEN_MMAP 17 + #define VHOST_USER_PROTOCOL_F_SHARED_OBJECT 18 Front-end message types ----------------------- diff --git a/include/hw/virtio/vhost-user.h b/include/hw/virtio/vhost-user.h index 6b06ecb1bd..20b69d8e85 100644 --- a/include/hw/virtio/vhost-user.h +++ b/include/hw/virtio/vhost-user.h @@ -29,7 +29,8 @@ enum VhostUserProtocolFeature { VHOST_USER_PROTOCOL_F_INBAND_NOTIFICATIONS = 14, VHOST_USER_PROTOCOL_F_CONFIGURE_MEM_SLOTS = 15, VHOST_USER_PROTOCOL_F_STATUS = 16, - VHOST_USER_PROTOCOL_F_SHARED_OBJECT = 17, + /* Feature 17 reserved for VHOST_USER_PROTOCOL_F_XEN_MMAP. */ + VHOST_USER_PROTOCOL_F_SHARED_OBJECT = 18, VHOST_USER_PROTOCOL_F_MAX }; diff --git a/subprojects/libvhost-user/libvhost-user.h b/subprojects/libvhost-user/libvhost-user.h index b36a42a7ca..c2352904f0 100644 --- a/subprojects/libvhost-user/libvhost-user.h +++ b/subprojects/libvhost-user/libvhost-user.h @@ -65,7 +65,8 @@ enum VhostUserProtocolFeature { VHOST_USER_PROTOCOL_F_INBAND_NOTIFICATIONS = 14, VHOST_USER_PROTOCOL_F_CONFIGURE_MEM_SLOTS = 15, /* Feature 16 is reserved for VHOST_USER_PROTOCOL_F_STATUS. */ - VHOST_USER_PROTOCOL_F_SHARED_OBJECT = 17, + /* Feature 17 reserved for VHOST_USER_PROTOCOL_F_XEN_MMAP. */ + VHOST_USER_PROTOCOL_F_SHARED_OBJECT = 18, VHOST_USER_PROTOCOL_F_MAX }; From 5e7abc29c56f7823f9a122898685bdfcfac2e522 Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Tue, 17 Oct 2023 17:26:25 +0200 Subject: [PATCH 1038/1077] MAINTAINERS: Add include/hw/intc/i8259.h to the PC chip section i8259.c is already listed here, so the corresponding header should be mentioned in this section, too. Signed-off-by: Thomas Huth Message-Id: <20231017152625.229022-1-thuth@redhat.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- MAINTAINERS | 1 + 1 file changed, 1 insertion(+) diff --git a/MAINTAINERS b/MAINTAINERS index d9fe5aa367..2f435102ec 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1764,6 +1764,7 @@ F: include/hw/dma/i8257.h F: include/hw/i2c/pm_smbus.h F: include/hw/input/i8042.h F: include/hw/intc/ioapic* +F: include/hw/intc/i8259.h F: include/hw/isa/i8259_internal.h F: include/hw/isa/superio.h F: include/hw/timer/hpet.h From c7016bf700cfbee52d2797bc4c592a39b17c4de7 Mon Sep 17 00:00:00 2001 From: David Woodhouse Date: Wed, 23 Aug 2023 13:23:25 +0100 Subject: [PATCH 1039/1077] intel-iommu: Report interrupt remapping faults, fix return value A generic X86IOMMUClass->int_remap function should not return VT-d specific values; fix it to return 0 if the interrupt was successfully translated or -EINVAL if not. The VTD_FR_IR_xxx values are supposed to be used to actually raise faults through the fault reporting mechanism, so do that instead for the case where the IRQ is actually being injected. There is more work to be done here, as pretranslations for the KVM IRQ routing table can't fault; an untranslatable IRQ should be handled in userspace and the fault raised only when the IRQ actually happens (if indeed the IRTE is still not valid at that time). But we can work on that later; we can at least raise faults for the direct case. Signed-off-by: David Woodhouse Message-Id: <31bbfc9041690449d3ac891f4431ec82174ee1b4.camel@infradead.org> Acked-by: Peter Xu Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/i386/intel_iommu.c | 150 ++++++++++++++++++++++----------- hw/i386/intel_iommu_internal.h | 1 + 2 files changed, 103 insertions(+), 48 deletions(-) diff --git a/hw/i386/intel_iommu.c b/hw/i386/intel_iommu.c index 2c832ab68b..30a108a42b 100644 --- a/hw/i386/intel_iommu.c +++ b/hw/i386/intel_iommu.c @@ -469,21 +469,12 @@ static void vtd_set_frcd_and_update_ppf(IntelIOMMUState *s, uint16_t index) /* Must not update F field now, should be done later */ static void vtd_record_frcd(IntelIOMMUState *s, uint16_t index, - uint16_t source_id, hwaddr addr, - VTDFaultReason fault, bool is_write, - bool is_pasid, uint32_t pasid) + uint64_t hi, uint64_t lo) { - uint64_t hi = 0, lo; hwaddr frcd_reg_addr = DMAR_FRCD_REG_OFFSET + (((uint64_t)index) << 4); assert(index < DMAR_FRCD_REG_NR); - lo = VTD_FRCD_FI(addr); - hi = VTD_FRCD_SID(source_id) | VTD_FRCD_FR(fault) | - VTD_FRCD_PV(pasid) | VTD_FRCD_PP(is_pasid); - if (!is_write) { - hi |= VTD_FRCD_T; - } vtd_set_quad_raw(s, frcd_reg_addr, lo); vtd_set_quad_raw(s, frcd_reg_addr + 8, hi); @@ -509,17 +500,11 @@ static bool vtd_try_collapse_fault(IntelIOMMUState *s, uint16_t source_id) } /* Log and report an DMAR (address translation) fault to software */ -static void vtd_report_dmar_fault(IntelIOMMUState *s, uint16_t source_id, - hwaddr addr, VTDFaultReason fault, - bool is_write, bool is_pasid, - uint32_t pasid) +static void vtd_report_frcd_fault(IntelIOMMUState *s, uint64_t source_id, + uint64_t hi, uint64_t lo) { uint32_t fsts_reg = vtd_get_long_raw(s, DMAR_FSTS_REG); - assert(fault < VTD_FR_MAX); - - trace_vtd_dmar_fault(source_id, fault, addr, is_write); - if (fsts_reg & VTD_FSTS_PFO) { error_report_once("New fault is not recorded due to " "Primary Fault Overflow"); @@ -539,8 +524,7 @@ static void vtd_report_dmar_fault(IntelIOMMUState *s, uint16_t source_id, return; } - vtd_record_frcd(s, s->next_frcd_reg, source_id, addr, fault, - is_write, is_pasid, pasid); + vtd_record_frcd(s, s->next_frcd_reg, hi, lo); if (fsts_reg & VTD_FSTS_PPF) { error_report_once("There are pending faults already, " @@ -565,6 +549,40 @@ static void vtd_report_dmar_fault(IntelIOMMUState *s, uint16_t source_id, } } +/* Log and report an DMAR (address translation) fault to software */ +static void vtd_report_dmar_fault(IntelIOMMUState *s, uint16_t source_id, + hwaddr addr, VTDFaultReason fault, + bool is_write, bool is_pasid, + uint32_t pasid) +{ + uint64_t hi, lo; + + assert(fault < VTD_FR_MAX); + + trace_vtd_dmar_fault(source_id, fault, addr, is_write); + + lo = VTD_FRCD_FI(addr); + hi = VTD_FRCD_SID(source_id) | VTD_FRCD_FR(fault) | + VTD_FRCD_PV(pasid) | VTD_FRCD_PP(is_pasid); + if (!is_write) { + hi |= VTD_FRCD_T; + } + + vtd_report_frcd_fault(s, source_id, hi, lo); +} + + +static void vtd_report_ir_fault(IntelIOMMUState *s, uint64_t source_id, + VTDFaultReason fault, uint16_t index) +{ + uint64_t hi, lo; + + lo = VTD_FRCD_IR_IDX(index); + hi = VTD_FRCD_SID(source_id) | VTD_FRCD_FR(fault); + + vtd_report_frcd_fault(s, source_id, hi, lo); +} + /* Handle Invalidation Queue Errors of queued invalidation interface error * conditions. */ @@ -3305,8 +3323,9 @@ static Property vtd_properties[] = { }; /* Read IRTE entry with specific index */ -static int vtd_irte_get(IntelIOMMUState *iommu, uint16_t index, - VTD_IR_TableEntry *entry, uint16_t sid) +static bool vtd_irte_get(IntelIOMMUState *iommu, uint16_t index, + VTD_IR_TableEntry *entry, uint16_t sid, + bool do_fault) { static const uint16_t vtd_svt_mask[VTD_SQ_MAX] = \ {0xffff, 0xfffb, 0xfff9, 0xfff8}; @@ -3317,7 +3336,10 @@ static int vtd_irte_get(IntelIOMMUState *iommu, uint16_t index, if (index >= iommu->intr_size) { error_report_once("%s: index too large: ind=0x%x", __func__, index); - return -VTD_FR_IR_INDEX_OVER; + if (do_fault) { + vtd_report_ir_fault(iommu, sid, VTD_FR_IR_INDEX_OVER, index); + } + return false; } addr = iommu->intr_root + index * sizeof(*entry); @@ -3325,7 +3347,10 @@ static int vtd_irte_get(IntelIOMMUState *iommu, uint16_t index, entry, sizeof(*entry), MEMTXATTRS_UNSPECIFIED)) { error_report_once("%s: read failed: ind=0x%x addr=0x%" PRIx64, __func__, index, addr); - return -VTD_FR_IR_ROOT_INVAL; + if (do_fault) { + vtd_report_ir_fault(iommu, sid, VTD_FR_IR_ROOT_INVAL, index); + } + return false; } entry->data[0] = le64_to_cpu(entry->data[0]); @@ -3333,11 +3358,24 @@ static int vtd_irte_get(IntelIOMMUState *iommu, uint16_t index, trace_vtd_ir_irte_get(index, entry->data[1], entry->data[0]); + /* + * The remaining potential fault conditions are "qualified" by the + * Fault Processing Disable bit in the IRTE. Even "not present". + * So just clear the do_fault flag if PFD is set, which will + * prevent faults being raised. + */ + if (entry->irte.fault_disable) { + do_fault = false; + } + if (!entry->irte.present) { error_report_once("%s: detected non-present IRTE " "(index=%u, high=0x%" PRIx64 ", low=0x%" PRIx64 ")", __func__, index, entry->data[1], entry->data[0]); - return -VTD_FR_IR_ENTRY_P; + if (do_fault) { + vtd_report_ir_fault(iommu, sid, VTD_FR_IR_ENTRY_P, index); + } + return false; } if (entry->irte.__reserved_0 || entry->irte.__reserved_1 || @@ -3345,7 +3383,10 @@ static int vtd_irte_get(IntelIOMMUState *iommu, uint16_t index, error_report_once("%s: detected non-zero reserved IRTE " "(index=%u, high=0x%" PRIx64 ", low=0x%" PRIx64 ")", __func__, index, entry->data[1], entry->data[0]); - return -VTD_FR_IR_IRTE_RSVD; + if (do_fault) { + vtd_report_ir_fault(iommu, sid, VTD_FR_IR_IRTE_RSVD, index); + } + return false; } if (sid != X86_IOMMU_SID_INVALID) { @@ -3361,7 +3402,10 @@ static int vtd_irte_get(IntelIOMMUState *iommu, uint16_t index, error_report_once("%s: invalid IRTE SID " "(index=%u, sid=%u, source_id=%u)", __func__, index, sid, source_id); - return -VTD_FR_IR_SID_ERR; + if (do_fault) { + vtd_report_ir_fault(iommu, sid, VTD_FR_IR_SID_ERR, index); + } + return false; } break; @@ -3373,7 +3417,10 @@ static int vtd_irte_get(IntelIOMMUState *iommu, uint16_t index, error_report_once("%s: invalid SVT_BUS " "(index=%u, bus=%u, min=%u, max=%u)", __func__, index, bus, bus_min, bus_max); - return -VTD_FR_IR_SID_ERR; + if (do_fault) { + vtd_report_ir_fault(iommu, sid, VTD_FR_IR_SID_ERR, index); + } + return false; } break; @@ -3382,23 +3429,24 @@ static int vtd_irte_get(IntelIOMMUState *iommu, uint16_t index, "(index=%u, type=%d)", __func__, index, entry->irte.sid_vtype); /* Take this as verification failure. */ - return -VTD_FR_IR_SID_ERR; + if (do_fault) { + vtd_report_ir_fault(iommu, sid, VTD_FR_IR_SID_ERR, index); + } + return false; } } - return 0; + return true; } /* Fetch IRQ information of specific IR index */ -static int vtd_remap_irq_get(IntelIOMMUState *iommu, uint16_t index, - X86IOMMUIrq *irq, uint16_t sid) +static bool vtd_remap_irq_get(IntelIOMMUState *iommu, uint16_t index, + X86IOMMUIrq *irq, uint16_t sid, bool do_fault) { VTD_IR_TableEntry irte = {}; - int ret = 0; - ret = vtd_irte_get(iommu, index, &irte, sid); - if (ret) { - return ret; + if (!vtd_irte_get(iommu, index, &irte, sid, do_fault)) { + return false; } irq->trigger_mode = irte.irte.trigger_mode; @@ -3417,16 +3465,15 @@ static int vtd_remap_irq_get(IntelIOMMUState *iommu, uint16_t index, trace_vtd_ir_remap(index, irq->trigger_mode, irq->vector, irq->delivery_mode, irq->dest, irq->dest_mode); - return 0; + return true; } /* Interrupt remapping for MSI/MSI-X entry */ static int vtd_interrupt_remap_msi(IntelIOMMUState *iommu, MSIMessage *origin, MSIMessage *translated, - uint16_t sid) + uint16_t sid, bool do_fault) { - int ret = 0; VTD_IR_MSIAddress addr; uint16_t index; X86IOMMUIrq irq = {}; @@ -3443,14 +3490,20 @@ static int vtd_interrupt_remap_msi(IntelIOMMUState *iommu, if (origin->address & VTD_MSI_ADDR_HI_MASK) { error_report_once("%s: MSI address high 32 bits non-zero detected: " "address=0x%" PRIx64, __func__, origin->address); - return -VTD_FR_IR_REQ_RSVD; + if (do_fault) { + vtd_report_ir_fault(iommu, sid, VTD_FR_IR_REQ_RSVD, 0); + } + return -EINVAL; } addr.data = origin->address & VTD_MSI_ADDR_LO_MASK; if (addr.addr.__head != 0xfee) { error_report_once("%s: MSI address low 32 bit invalid: 0x%" PRIx32, __func__, addr.data); - return -VTD_FR_IR_REQ_RSVD; + if (do_fault) { + vtd_report_ir_fault(iommu, sid, VTD_FR_IR_REQ_RSVD, 0); + } + return -EINVAL; } /* This is compatible mode. */ @@ -3469,9 +3522,8 @@ static int vtd_interrupt_remap_msi(IntelIOMMUState *iommu, index += origin->data & VTD_IR_MSI_DATA_SUBHANDLE; } - ret = vtd_remap_irq_get(iommu, index, &irq, sid); - if (ret) { - return ret; + if (!vtd_remap_irq_get(iommu, index, &irq, sid, do_fault)) { + return -EINVAL; } if (addr.addr.sub_valid) { @@ -3481,7 +3533,10 @@ static int vtd_interrupt_remap_msi(IntelIOMMUState *iommu, "(sid=%u, address=0x%" PRIx64 ", data=0x%" PRIx32 ")", __func__, sid, origin->address, origin->data); - return -VTD_FR_IR_REQ_RSVD; + if (do_fault) { + vtd_report_ir_fault(iommu, sid, VTD_FR_IR_REQ_RSVD, 0); + } + return -EINVAL; } } else { uint8_t vector = origin->data & 0xff; @@ -3521,7 +3576,7 @@ static int vtd_int_remap(X86IOMMUState *iommu, MSIMessage *src, MSIMessage *dst, uint16_t sid) { return vtd_interrupt_remap_msi(INTEL_IOMMU_DEVICE(iommu), - src, dst, sid); + src, dst, sid, false); } static MemTxResult vtd_mem_ir_read(void *opaque, hwaddr addr, @@ -3547,9 +3602,8 @@ static MemTxResult vtd_mem_ir_write(void *opaque, hwaddr addr, sid = attrs.requester_id; } - ret = vtd_interrupt_remap_msi(opaque, &from, &to, sid); + ret = vtd_interrupt_remap_msi(opaque, &from, &to, sid, true); if (ret) { - /* TODO: report error */ /* Drop this interrupt */ return MEMTX_ERROR; } diff --git a/hw/i386/intel_iommu_internal.h b/hw/i386/intel_iommu_internal.h index e1450c5cfe..f8cf99bddf 100644 --- a/hw/i386/intel_iommu_internal.h +++ b/hw/i386/intel_iommu_internal.h @@ -268,6 +268,7 @@ #define VTD_FRCD_FI(val) ((val) & ~0xfffULL) #define VTD_FRCD_PV(val) (((val) & 0xffffULL) << 40) #define VTD_FRCD_PP(val) (((val) & 0x1) << 31) +#define VTD_FRCD_IR_IDX(val) (((val) & 0xffffULL) << 48) /* DMA Remapping Fault Conditions */ typedef enum VTDFaultReason { From 096d118592caa03188db6a190988221b65a2bd81 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 4 Aug 2023 20:35:53 +0000 Subject: [PATCH 1040/1077] tcg/ppc: Untabify tcg-target.c.inc Signed-off-by: Richard Henderson --- tcg/ppc/tcg-target.c.inc | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tcg/ppc/tcg-target.c.inc b/tcg/ppc/tcg-target.c.inc index 5c873b2161..5cecc6ed95 100644 --- a/tcg/ppc/tcg-target.c.inc +++ b/tcg/ppc/tcg-target.c.inc @@ -221,7 +221,7 @@ static inline bool in_range_b(tcg_target_long target) } static uint32_t reloc_pc24_val(const tcg_insn_unit *pc, - const tcg_insn_unit *target) + const tcg_insn_unit *target) { ptrdiff_t disp = tcg_ptr_byte_diff(target, pc); tcg_debug_assert(in_range_b(disp)); @@ -241,7 +241,7 @@ static bool reloc_pc24(tcg_insn_unit *src_rw, const tcg_insn_unit *target) } static uint16_t reloc_pc14_val(const tcg_insn_unit *pc, - const tcg_insn_unit *target) + const tcg_insn_unit *target) { ptrdiff_t disp = tcg_ptr_byte_diff(target, pc); tcg_debug_assert(disp == (int16_t) disp); @@ -3645,7 +3645,7 @@ static void expand_vec_mul(TCGType type, unsigned vece, TCGv_vec v0, tcgv_vec_arg(t1), tcgv_vec_arg(t2)); vec_gen_3(INDEX_op_ppc_pkum_vec, type, vece, tcgv_vec_arg(v0), tcgv_vec_arg(v0), tcgv_vec_arg(t1)); - break; + break; case MO_32: tcg_debug_assert(!have_isa_2_07); From 03434d52024934620a001a875b540b06abd0b169 Mon Sep 17 00:00:00 2001 From: Jordan Niethe Date: Tue, 15 Aug 2023 16:47:11 +0000 Subject: [PATCH 1041/1077] tcg/ppc: Enable direct branching tcg_out_goto_tb with TCG_REG_TB Direct branch patching was disabled when using TCG_REG_TB in commit 736a1588c1 ("tcg/ppc: Fix race in goto_tb implementation"). The issue with direct branch patching with TCG_REG_TB is the lack of synchronization between the new TCG_REG_TB being established and the direct branch being patched in. If each translation block is responsible for establishing its own TCG_REG_TB then there can be no synchronization issue. Make each translation block begin by setting up its own TCG_REG_TB. Use the preferred 'bcl 20,31,$+4' sequence. Signed-off-by: Jordan Niethe [rth: Split out tcg_out_tb_start, power9 addpcis] Signed-off-by: Richard Henderson --- tcg/ppc/tcg-target.c.inc | 48 ++++++++++++++-------------------------- 1 file changed, 17 insertions(+), 31 deletions(-) diff --git a/tcg/ppc/tcg-target.c.inc b/tcg/ppc/tcg-target.c.inc index 5cecc6ed95..9197cfd6c6 100644 --- a/tcg/ppc/tcg-target.c.inc +++ b/tcg/ppc/tcg-target.c.inc @@ -2509,9 +2509,6 @@ static void tcg_target_qemu_prologue(TCGContext *s) tcg_out_mov(s, TCG_TYPE_PTR, TCG_AREG0, tcg_target_call_iarg_regs[0]); tcg_out32(s, MTSPR | RS(tcg_target_call_iarg_regs[1]) | CTR); - if (USE_REG_TB) { - tcg_out_mov(s, TCG_TYPE_PTR, TCG_REG_TB, tcg_target_call_iarg_regs[1]); - } tcg_out32(s, BCCTR | BO_ALWAYS); /* Epilogue */ @@ -2529,7 +2526,13 @@ static void tcg_target_qemu_prologue(TCGContext *s) static void tcg_out_tb_start(TCGContext *s) { - /* nothing to do */ + /* Load TCG_REG_TB. */ + if (USE_REG_TB) { + /* bcl 20,31,$+4 (preferred form for getting nia) */ + tcg_out32(s, BC | BO_ALWAYS | BI(7, CR_SO) | 0x4 | LK); + tcg_out32(s, MFSPR | RT(TCG_REG_TB) | LR); + tcg_out32(s, ADDI | TAI(TCG_REG_TB, TCG_REG_TB, -4)); + } } static void tcg_out_exit_tb(TCGContext *s, uintptr_t arg) @@ -2542,32 +2545,22 @@ static void tcg_out_goto_tb(TCGContext *s, int which) { uintptr_t ptr = get_jmp_target_addr(s, which); + /* Direct branch will be patched by tb_target_set_jmp_target. */ + set_jmp_insn_offset(s, which); + tcg_out32(s, NOP); + + /* When branch is out of range, fall through to indirect. */ if (USE_REG_TB) { ptrdiff_t offset = tcg_tbrel_diff(s, (void *)ptr); - tcg_out_mem_long(s, LD, LDX, TCG_REG_TB, TCG_REG_TB, offset); - - /* TODO: Use direct branches when possible. */ - set_jmp_insn_offset(s, which); - tcg_out32(s, MTSPR | RS(TCG_REG_TB) | CTR); - - tcg_out32(s, BCCTR | BO_ALWAYS); - - /* For the unlinked case, need to reset TCG_REG_TB. */ - set_jmp_reset_offset(s, which); - tcg_out_mem_long(s, ADDI, ADD, TCG_REG_TB, TCG_REG_TB, - -tcg_current_code_size(s)); + tcg_out_mem_long(s, LD, LDX, TCG_REG_TMP1, TCG_REG_TB, offset); } else { - /* Direct branch will be patched by tb_target_set_jmp_target. */ - set_jmp_insn_offset(s, which); - tcg_out32(s, NOP); - - /* When branch is out of range, fall through to indirect. */ tcg_out_movi(s, TCG_TYPE_PTR, TCG_REG_TMP1, ptr - (int16_t)ptr); tcg_out_ld(s, TCG_TYPE_PTR, TCG_REG_TMP1, TCG_REG_TMP1, (int16_t)ptr); - tcg_out32(s, MTSPR | RS(TCG_REG_TMP1) | CTR); - tcg_out32(s, BCCTR | BO_ALWAYS); - set_jmp_reset_offset(s, which); } + + tcg_out32(s, MTSPR | RS(TCG_REG_TMP1) | CTR); + tcg_out32(s, BCCTR | BO_ALWAYS); + set_jmp_reset_offset(s, which); } void tb_target_set_jmp_target(const TranslationBlock *tb, int n, @@ -2577,10 +2570,6 @@ void tb_target_set_jmp_target(const TranslationBlock *tb, int n, intptr_t diff = addr - jmp_rx; tcg_insn_unit insn; - if (USE_REG_TB) { - return; - } - if (in_range_b(diff)) { insn = B | (diff & 0x3fffffc); } else { @@ -2600,9 +2589,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, switch (opc) { case INDEX_op_goto_ptr: tcg_out32(s, MTSPR | RS(args[0]) | CTR); - if (USE_REG_TB) { - tcg_out_mov(s, TCG_TYPE_PTR, TCG_REG_TB, args[0]); - } tcg_out32(s, ADDI | TAI(TCG_REG_R3, 0, 0)); tcg_out32(s, BCCTR | BO_ALWAYS); break; From 4430b60c7f201eefac28c711c1bf93983e5966e9 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Tue, 15 Aug 2023 16:58:19 +0000 Subject: [PATCH 1042/1077] tcg/ppc: Reinterpret tb-relative to TB+4 It saves one insn to load the address of TB+4 instead of TB. Adjust all of the indexing to match. Signed-off-by: Richard Henderson --- tcg/ppc/tcg-target.c.inc | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/tcg/ppc/tcg-target.c.inc b/tcg/ppc/tcg-target.c.inc index 9197cfd6c6..aafbf2db4e 100644 --- a/tcg/ppc/tcg-target.c.inc +++ b/tcg/ppc/tcg-target.c.inc @@ -215,6 +215,12 @@ static const int tcg_target_callee_save_regs[] = { TCG_REG_R31 }; +/* For PPC, we use TB+4 instead of TB as the base. */ +static inline ptrdiff_t ppc_tbrel_diff(TCGContext *s, const void *target) +{ + return tcg_tbrel_diff(s, target) - 4; +} + static inline bool in_range_b(tcg_target_long target) { return target == sextract64(target, 0, 26); @@ -991,7 +997,7 @@ static void tcg_out_movi_int(TCGContext *s, TCGType type, TCGReg ret, } /* Load addresses within the TB with one insn. */ - tb_diff = tcg_tbrel_diff(s, (void *)arg); + tb_diff = ppc_tbrel_diff(s, (void *)arg); if (!in_prologue && USE_REG_TB && tb_diff == (int16_t)tb_diff) { tcg_out32(s, ADDI | TAI(ret, TCG_REG_TB, tb_diff)); return; @@ -1044,7 +1050,7 @@ static void tcg_out_movi_int(TCGContext *s, TCGType type, TCGReg ret, /* Use the constant pool, if possible. */ if (!in_prologue && USE_REG_TB) { new_pool_label(s, arg, R_PPC_ADDR16, s->code_ptr, - tcg_tbrel_diff(s, NULL)); + ppc_tbrel_diff(s, NULL)); tcg_out32(s, LD | TAI(ret, TCG_REG_TB, 0)); return; } @@ -1104,7 +1110,7 @@ static void tcg_out_dupi_vec(TCGContext *s, TCGType type, unsigned vece, */ if (USE_REG_TB) { rel = R_PPC_ADDR16; - add = tcg_tbrel_diff(s, NULL); + add = ppc_tbrel_diff(s, NULL); } else { rel = R_PPC_ADDR32; add = 0; @@ -2531,7 +2537,6 @@ static void tcg_out_tb_start(TCGContext *s) /* bcl 20,31,$+4 (preferred form for getting nia) */ tcg_out32(s, BC | BO_ALWAYS | BI(7, CR_SO) | 0x4 | LK); tcg_out32(s, MFSPR | RT(TCG_REG_TB) | LR); - tcg_out32(s, ADDI | TAI(TCG_REG_TB, TCG_REG_TB, -4)); } } @@ -2551,7 +2556,7 @@ static void tcg_out_goto_tb(TCGContext *s, int which) /* When branch is out of range, fall through to indirect. */ if (USE_REG_TB) { - ptrdiff_t offset = tcg_tbrel_diff(s, (void *)ptr); + ptrdiff_t offset = ppc_tbrel_diff(s, (void *)ptr); tcg_out_mem_long(s, LD, LDX, TCG_REG_TMP1, TCG_REG_TB, offset); } else { tcg_out_movi(s, TCG_TYPE_PTR, TCG_REG_TMP1, ptr - (int16_t)ptr); From 3acd75b851759ccfa70a900c04d9ca030140de01 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Tue, 15 Aug 2023 17:04:42 +0000 Subject: [PATCH 1043/1077] tcg/ppc: Use ADDPCIS in tcg_out_tb_start With ISA v3.0, we can use ADDPCIS instead of BCL+MFLR to load NIA. Signed-off-by: Richard Henderson --- tcg/ppc/tcg-target.c.inc | 25 ++++++++++++++++++++++--- 1 file changed, 22 insertions(+), 3 deletions(-) diff --git a/tcg/ppc/tcg-target.c.inc b/tcg/ppc/tcg-target.c.inc index aafbf2db4e..b0b8cd2390 100644 --- a/tcg/ppc/tcg-target.c.inc +++ b/tcg/ppc/tcg-target.c.inc @@ -362,6 +362,7 @@ static bool tcg_target_const_match(int64_t val, TCGType type, int ct, int vece) #define CRNAND XO19(225) #define CROR XO19(449) #define CRNOR XO19( 33) +#define ADDPCIS XO19( 2) #define EXTSB XO31(954) #define EXTSH XO31(922) @@ -859,6 +860,19 @@ static inline void tcg_out_sari64(TCGContext *s, TCGReg dst, TCGReg src, int c) tcg_out32(s, SRADI | RA(dst) | RS(src) | SH(c & 0x1f) | ((c >> 4) & 2)); } +static void tcg_out_addpcis(TCGContext *s, TCGReg dst, intptr_t imm) +{ + uint32_t d0, d1, d2; + + tcg_debug_assert((imm & 0xffff) == 0); + tcg_debug_assert(imm == (int32_t)imm); + + d2 = extract32(imm, 16, 1); + d1 = extract32(imm, 17, 5); + d0 = extract32(imm, 22, 10); + tcg_out32(s, ADDPCIS | RT(dst) | (d1 << 16) | (d0 << 6) | d2); +} + static void tcg_out_bswap16(TCGContext *s, TCGReg dst, TCGReg src, int flags) { TCGReg tmp = dst == src ? TCG_REG_R0 : dst; @@ -2534,9 +2548,14 @@ static void tcg_out_tb_start(TCGContext *s) { /* Load TCG_REG_TB. */ if (USE_REG_TB) { - /* bcl 20,31,$+4 (preferred form for getting nia) */ - tcg_out32(s, BC | BO_ALWAYS | BI(7, CR_SO) | 0x4 | LK); - tcg_out32(s, MFSPR | RT(TCG_REG_TB) | LR); + if (have_isa_3_00) { + /* lnia REG_TB */ + tcg_out_addpcis(s, TCG_REG_TB, 0); + } else { + /* bcl 20,31,$+4 (preferred form for getting nia) */ + tcg_out32(s, BC | BO_ALWAYS | BI(7, CR_SO) | 0x4 | LK); + tcg_out32(s, MFSPR | RT(TCG_REG_TB) | LR); + } } } From 776cd9b64834d735db9c4cac7924497509739755 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Tue, 15 Aug 2023 17:19:37 +0000 Subject: [PATCH 1044/1077] tcg/ppc: Use ADDPCIS in tcg_out_movi_int Signed-off-by: Richard Henderson --- tcg/ppc/tcg-target.c.inc | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/tcg/ppc/tcg-target.c.inc b/tcg/ppc/tcg-target.c.inc index b0b8cd2390..226b5598ac 100644 --- a/tcg/ppc/tcg-target.c.inc +++ b/tcg/ppc/tcg-target.c.inc @@ -1055,6 +1055,19 @@ static void tcg_out_movi_int(TCGContext *s, TCGType type, TCGReg ret, return; } + /* Load addresses within 2GB with 2 insns. */ + if (have_isa_3_00) { + intptr_t hi = tcg_pcrel_diff(s, (void *)arg) - 4; + int16_t lo = hi; + + hi -= lo; + if (hi == (int32_t)hi) { + tcg_out_addpcis(s, TCG_REG_TMP2, hi); + tcg_out32(s, ADDI | TAI(ret, TCG_REG_TMP2, lo)); + return; + } + } + /* Load addresses within 2GB of TB with 2 (or rarely 3) insns. */ if (!in_prologue && USE_REG_TB && tb_diff == (int32_t)tb_diff) { tcg_out_mem_long(s, ADDI, ADD, ret, TCG_REG_TB, tb_diff); From 7a379976d6f12d44d8c97dd4ae68dab5240475b3 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Tue, 15 Aug 2023 17:35:21 +0000 Subject: [PATCH 1045/1077] tcg/ppc: Use ADDPCIS for the constant pool Signed-off-by: Richard Henderson --- tcg/ppc/tcg-target.c.inc | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/tcg/ppc/tcg-target.c.inc b/tcg/ppc/tcg-target.c.inc index 226b5598ac..720f92ff33 100644 --- a/tcg/ppc/tcg-target.c.inc +++ b/tcg/ppc/tcg-target.c.inc @@ -1081,6 +1081,12 @@ static void tcg_out_movi_int(TCGContext *s, TCGType type, TCGReg ret, tcg_out32(s, LD | TAI(ret, TCG_REG_TB, 0)); return; } + if (have_isa_3_00) { + tcg_out_addpcis(s, TCG_REG_TMP2, 0); + new_pool_label(s, arg, R_PPC_REL14, s->code_ptr, 0); + tcg_out32(s, LD | TAI(ret, TCG_REG_TMP2, 0)); + return; + } tmp = arg >> 31 >> 1; tcg_out_movi(s, TCG_TYPE_I32, ret, tmp); @@ -1138,6 +1144,10 @@ static void tcg_out_dupi_vec(TCGContext *s, TCGType type, unsigned vece, if (USE_REG_TB) { rel = R_PPC_ADDR16; add = ppc_tbrel_diff(s, NULL); + } else if (have_isa_3_00) { + tcg_out_addpcis(s, TCG_REG_TMP1, 0); + rel = R_PPC_REL14; + add = 0; } else { rel = R_PPC_ADDR32; add = 0; @@ -1164,6 +1174,8 @@ static void tcg_out_dupi_vec(TCGContext *s, TCGType type, unsigned vece, if (USE_REG_TB) { tcg_out32(s, ADDI | TAI(TCG_REG_TMP1, 0, 0)); load_insn |= RA(TCG_REG_TB); + } else if (have_isa_3_00) { + tcg_out32(s, ADDI | TAI(TCG_REG_TMP1, TCG_REG_TMP1, 0)); } else { tcg_out32(s, ADDIS | TAI(TCG_REG_TMP1, 0, 0)); tcg_out32(s, ADDI | TAI(TCG_REG_TMP1, TCG_REG_TMP1, 0)); From 4a388c7932322476e2395eed350ee6b23a08bf87 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Tue, 15 Aug 2023 17:47:47 +0000 Subject: [PATCH 1046/1077] tcg/ppc: Use ADDPCIS in tcg_out_goto_tb Signed-off-by: Richard Henderson --- tcg/ppc/tcg-target.c.inc | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/tcg/ppc/tcg-target.c.inc b/tcg/ppc/tcg-target.c.inc index 720f92ff33..6337b1e8be 100644 --- a/tcg/ppc/tcg-target.c.inc +++ b/tcg/ppc/tcg-target.c.inc @@ -2593,6 +2593,7 @@ static void tcg_out_exit_tb(TCGContext *s, uintptr_t arg) static void tcg_out_goto_tb(TCGContext *s, int which) { uintptr_t ptr = get_jmp_target_addr(s, which); + int16_t lo; /* Direct branch will be patched by tb_target_set_jmp_target. */ set_jmp_insn_offset(s, which); @@ -2602,9 +2603,15 @@ static void tcg_out_goto_tb(TCGContext *s, int which) if (USE_REG_TB) { ptrdiff_t offset = ppc_tbrel_diff(s, (void *)ptr); tcg_out_mem_long(s, LD, LDX, TCG_REG_TMP1, TCG_REG_TB, offset); + } else if (have_isa_3_00) { + ptrdiff_t offset = tcg_pcrel_diff(s, (void *)ptr) - 4; + lo = offset; + tcg_out_addpcis(s, TCG_REG_TMP1, offset - lo); + tcg_out_ld(s, TCG_TYPE_PTR, TCG_REG_TMP1, TCG_REG_TMP1, lo); } else { - tcg_out_movi(s, TCG_TYPE_PTR, TCG_REG_TMP1, ptr - (int16_t)ptr); - tcg_out_ld(s, TCG_TYPE_PTR, TCG_REG_TMP1, TCG_REG_TMP1, (int16_t)ptr); + lo = ptr; + tcg_out_movi(s, TCG_TYPE_PTR, TCG_REG_TMP1, ptr - lo); + tcg_out_ld(s, TCG_TYPE_PTR, TCG_REG_TMP1, TCG_REG_TMP1, lo); } tcg_out32(s, MTSPR | RS(TCG_REG_TMP1) | CTR); From 103044e4062c55b956617971985c6baa8843ed6b Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Mon, 26 Jun 2023 18:02:18 +0000 Subject: [PATCH 1047/1077] tcg/ppc: Use PADDI in tcg_out_movi PADDI can load 34-bit immediates and 34-bit pc-relative addresses. Reviewed-by: Jordan Niethe Signed-off-by: Richard Henderson --- tcg/ppc/tcg-target.c.inc | 51 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 51 insertions(+) diff --git a/tcg/ppc/tcg-target.c.inc b/tcg/ppc/tcg-target.c.inc index 6337b1e8be..f4235383c6 100644 --- a/tcg/ppc/tcg-target.c.inc +++ b/tcg/ppc/tcg-target.c.inc @@ -719,6 +719,38 @@ static bool patch_reloc(tcg_insn_unit *code_ptr, int type, return true; } +/* Ensure that the prefixed instruction does not cross a 64-byte boundary. */ +static bool tcg_out_need_prefix_align(TCGContext *s) +{ + return ((uintptr_t)s->code_ptr & 0x3f) == 0x3c; +} + +static void tcg_out_prefix_align(TCGContext *s) +{ + if (tcg_out_need_prefix_align(s)) { + tcg_out32(s, NOP); + } +} + +static ptrdiff_t tcg_pcrel_diff_for_prefix(TCGContext *s, const void *target) +{ + return tcg_pcrel_diff(s, target) - (tcg_out_need_prefix_align(s) ? 4 : 0); +} + +/* Output Type 10 Prefix - Modified Load/Store Form (MLS:D) */ +static void tcg_out_mls_d(TCGContext *s, tcg_insn_unit opc, unsigned rt, + unsigned ra, tcg_target_long imm, bool r) +{ + tcg_insn_unit p, i; + + p = OPCD(1) | (2 << 24) | (r << 20) | ((imm >> 16) & 0x3ffff); + i = opc | TAI(rt, ra, imm); + + tcg_out_prefix_align(s); + tcg_out32(s, p); + tcg_out32(s, i); +} + static void tcg_out_mem_long(TCGContext *s, int opi, int opx, TCGReg rt, TCGReg base, tcg_target_long offset); @@ -1017,6 +1049,25 @@ static void tcg_out_movi_int(TCGContext *s, TCGType type, TCGReg ret, return; } + /* + * Load values up to 34 bits, and pc-relative addresses, + * with one prefixed insn. + */ + if (have_isa_3_10) { + if (arg == sextract64(arg, 0, 34)) { + /* pli ret,value = paddi ret,0,value,0 */ + tcg_out_mls_d(s, ADDI, ret, 0, arg, 0); + return; + } + + tmp = tcg_pcrel_diff_for_prefix(s, (void *)arg); + if (tmp == sextract64(tmp, 0, 34)) { + /* pla ret,value = paddi ret,0,value,1 */ + tcg_out_mls_d(s, ADDI, ret, 0, tmp, 1); + return; + } + } + /* Load 32-bit immediates with two insns. Note that we've already eliminated bare ADDIS, so we know both insns are required. */ if (TCG_TARGET_REG_BITS == 32 || arg == (int32_t)arg) { From 1f8e4dc182b7ee8240a4d016162847ff4b581399 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 4 Aug 2023 17:16:32 +0000 Subject: [PATCH 1048/1077] tcg/ppc: Use prefixed instructions in tcg_out_mem_long When the offset is out of range of the non-prefixed insn, but fits the 34-bit immediate of the prefixed insn, use that. Reviewed-by: Jordan Niethe Signed-off-by: Richard Henderson --- tcg/ppc/tcg-target.c.inc | 66 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 66 insertions(+) diff --git a/tcg/ppc/tcg-target.c.inc b/tcg/ppc/tcg-target.c.inc index f4235383c6..34df9144cc 100644 --- a/tcg/ppc/tcg-target.c.inc +++ b/tcg/ppc/tcg-target.c.inc @@ -329,6 +329,15 @@ static bool tcg_target_const_match(int64_t val, TCGType type, int ct, int vece) #define STDX XO31(149) #define STQ XO62( 2) +#define PLWA OPCD( 41) +#define PLD OPCD( 57) +#define PLXSD OPCD( 42) +#define PLXV OPCD(25 * 2 + 1) /* force tx=1 */ + +#define PSTD OPCD( 61) +#define PSTXSD OPCD( 46) +#define PSTXV OPCD(27 * 2 + 1) /* force sx=1 */ + #define ADDIC OPCD( 12) #define ADDI OPCD( 14) #define ADDIS OPCD( 15) @@ -737,6 +746,20 @@ static ptrdiff_t tcg_pcrel_diff_for_prefix(TCGContext *s, const void *target) return tcg_pcrel_diff(s, target) - (tcg_out_need_prefix_align(s) ? 4 : 0); } +/* Output Type 00 Prefix - 8-Byte Load/Store Form (8LS:D) */ +static void tcg_out_8ls_d(TCGContext *s, tcg_insn_unit opc, unsigned rt, + unsigned ra, tcg_target_long imm, bool r) +{ + tcg_insn_unit p, i; + + p = OPCD(1) | (r << 20) | ((imm >> 16) & 0x3ffff); + i = opc | TAI(rt, ra, imm); + + tcg_out_prefix_align(s); + tcg_out32(s, p); + tcg_out32(s, i); +} + /* Output Type 10 Prefix - Modified Load/Store Form (MLS:D) */ static void tcg_out_mls_d(TCGContext *s, tcg_insn_unit opc, unsigned rt, unsigned ra, tcg_target_long imm, bool r) @@ -1418,6 +1441,49 @@ static void tcg_out_mem_long(TCGContext *s, int opi, int opx, TCGReg rt, break; } + /* For unaligned or large offsets, use the prefixed form. */ + if (have_isa_3_10 + && (offset != (int16_t)offset || (offset & align)) + && offset == sextract64(offset, 0, 34)) { + /* + * Note that the MLS:D insns retain their un-prefixed opcode, + * while the 8LS:D insns use a different opcode space. + */ + switch (opi) { + case LBZ: + case LHZ: + case LHA: + case LWZ: + case STB: + case STH: + case STW: + case ADDI: + tcg_out_mls_d(s, opi, rt, base, offset, 0); + return; + case LWA: + tcg_out_8ls_d(s, PLWA, rt, base, offset, 0); + return; + case LD: + tcg_out_8ls_d(s, PLD, rt, base, offset, 0); + return; + case STD: + tcg_out_8ls_d(s, PSTD, rt, base, offset, 0); + return; + case LXSD: + tcg_out_8ls_d(s, PLXSD, rt & 31, base, offset, 0); + return; + case STXSD: + tcg_out_8ls_d(s, PSTXSD, rt & 31, base, offset, 0); + return; + case LXV: + tcg_out_8ls_d(s, PLXV, rt & 31, base, offset, 0); + return; + case STXV: + tcg_out_8ls_d(s, PSTXV, rt & 31, base, offset, 0); + return; + } + } + /* For unaligned, or very large offsets, use the indexed form. */ if (offset & align || offset != (int32_t)offset || opi == 0) { if (rs == base) { From d90b23af6dedb93384c8964882d9fad4af0f3cab Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 4 Aug 2023 18:19:25 +0000 Subject: [PATCH 1049/1077] tcg/ppc: Use PLD in tcg_out_movi for constant pool The prefixed instruction has a pc-relative form to use here. Signed-off-by: Richard Henderson --- tcg/ppc/tcg-target.c.inc | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/tcg/ppc/tcg-target.c.inc b/tcg/ppc/tcg-target.c.inc index 34df9144cc..79e82d2f94 100644 --- a/tcg/ppc/tcg-target.c.inc +++ b/tcg/ppc/tcg-target.c.inc @@ -101,6 +101,10 @@ #define ALL_GENERAL_REGS 0xffffffffu #define ALL_VECTOR_REGS 0xffffffff00000000ull +#ifndef R_PPC64_PCREL34 +#define R_PPC64_PCREL34 132 +#endif + #define have_isel (cpuinfo & CPUINFO_ISEL) #ifndef CONFIG_SOFTMMU @@ -266,6 +270,19 @@ static bool reloc_pc14(tcg_insn_unit *src_rw, const tcg_insn_unit *target) return false; } +static bool reloc_pc34(tcg_insn_unit *src_rw, const tcg_insn_unit *target) +{ + const tcg_insn_unit *src_rx = tcg_splitwx_to_rx(src_rw); + ptrdiff_t disp = tcg_ptr_byte_diff(target, src_rx); + + if (disp == sextract64(disp, 0, 34)) { + src_rw[0] = (src_rw[0] & ~0x3ffff) | ((disp >> 16) & 0x3ffff); + src_rw[1] = (src_rw[1] & ~0xffff) | (disp & 0xffff); + return true; + } + return false; +} + /* test if a constant matches the constraint */ static bool tcg_target_const_match(int64_t val, TCGType type, int ct, int vece) { @@ -696,6 +713,8 @@ static bool patch_reloc(tcg_insn_unit *code_ptr, int type, return reloc_pc14(code_ptr, target); case R_PPC_REL24: return reloc_pc24(code_ptr, target); + case R_PPC64_PCREL34: + return reloc_pc34(code_ptr, target); case R_PPC_ADDR16: /* * We are (slightly) abusing this relocation type. In particular, @@ -1155,6 +1174,11 @@ static void tcg_out_movi_int(TCGContext *s, TCGType type, TCGReg ret, tcg_out32(s, LD | TAI(ret, TCG_REG_TB, 0)); return; } + if (have_isa_3_10) { + tcg_out_8ls_d(s, PLD, ret, 0, 0, 1); + new_pool_label(s, arg, R_PPC64_PCREL34, s->code_ptr - 2, 0); + return; + } if (have_isa_3_00) { tcg_out_addpcis(s, TCG_REG_TMP2, 0); new_pool_label(s, arg, R_PPC_REL14, s->code_ptr, 0); From c90f897a541951821af1abdadca3b68c3f74c3ae Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 4 Aug 2023 18:32:57 +0000 Subject: [PATCH 1050/1077] tcg/ppc: Use prefixed instructions in tcg_out_dupi_vec The prefixed instructions have a pc-relative form to use here. Signed-off-by: Richard Henderson --- tcg/ppc/tcg-target.c.inc | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/tcg/ppc/tcg-target.c.inc b/tcg/ppc/tcg-target.c.inc index 79e82d2f94..db3212083b 100644 --- a/tcg/ppc/tcg-target.c.inc +++ b/tcg/ppc/tcg-target.c.inc @@ -1242,6 +1242,15 @@ static void tcg_out_dupi_vec(TCGContext *s, TCGType type, unsigned vece, if (USE_REG_TB) { rel = R_PPC_ADDR16; add = ppc_tbrel_diff(s, NULL); + } else if (have_isa_3_10) { + if (type == TCG_TYPE_V64) { + tcg_out_8ls_d(s, PLXSD, ret & 31, 0, 0, 1); + new_pool_label(s, val, R_PPC64_PCREL34, s->code_ptr - 2, 0); + } else { + tcg_out_8ls_d(s, PLXV, ret & 31, 0, 0, 1); + new_pool_l2(s, R_PPC64_PCREL34, s->code_ptr - 2, 0, val, val); + } + return; } else if (have_isa_3_00) { tcg_out_addpcis(s, TCG_REG_TMP1, 0); rel = R_PPC_REL14; From 1958dbbd2a79b9fe7cae80da66e04e11b86f5455 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Tue, 15 Aug 2023 18:17:10 +0000 Subject: [PATCH 1051/1077] tcg/ppc: Use PLD in tcg_out_goto_tb Signed-off-by: Richard Henderson --- tcg/ppc/tcg-target.c.inc | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tcg/ppc/tcg-target.c.inc b/tcg/ppc/tcg-target.c.inc index db3212083b..6496f76e41 100644 --- a/tcg/ppc/tcg-target.c.inc +++ b/tcg/ppc/tcg-target.c.inc @@ -2753,6 +2753,9 @@ static void tcg_out_goto_tb(TCGContext *s, int which) if (USE_REG_TB) { ptrdiff_t offset = ppc_tbrel_diff(s, (void *)ptr); tcg_out_mem_long(s, LD, LDX, TCG_REG_TMP1, TCG_REG_TB, offset); + } else if (have_isa_3_10) { + ptrdiff_t offset = tcg_pcrel_diff_for_prefix(s, (void *)ptr); + tcg_out_8ls_d(s, PLD, TCG_REG_TMP1, 0, offset, 1); } else if (have_isa_3_00) { ptrdiff_t offset = tcg_pcrel_diff(s, (void *)ptr) - 4; lo = offset; From cc3f99aac41903362521fac551b835abe369659a Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Tue, 15 Aug 2023 17:48:19 +0000 Subject: [PATCH 1052/1077] tcg/ppc: Disable TCG_REG_TB for Power9/Power10 This appears to slightly improve performance on power9/10. Signed-off-by: Richard Henderson --- tcg/ppc/tcg-target.c.inc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tcg/ppc/tcg-target.c.inc b/tcg/ppc/tcg-target.c.inc index 6496f76e41..c31da4da9d 100644 --- a/tcg/ppc/tcg-target.c.inc +++ b/tcg/ppc/tcg-target.c.inc @@ -83,7 +83,7 @@ #define TCG_VEC_TMP2 TCG_REG_V1 #define TCG_REG_TB TCG_REG_R31 -#define USE_REG_TB (TCG_TARGET_REG_BITS == 64) +#define USE_REG_TB (TCG_TARGET_REG_BITS == 64 && !have_isa_3_00) /* Shorthand for size of a pointer. Avoid promotion to unsigned. */ #define SZP ((int)sizeof(void *)) From 397cabaae035102afb547155757fd506620b2bb2 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Sun, 1 Oct 2023 07:53:03 -0700 Subject: [PATCH 1053/1077] tcg: Introduce tcg_use_softmmu MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Begin disconnecting CONFIG_SOFTMMU from !CONFIG_USER_ONLY. Introduce a variable which can be set at startup to select one method or another for user-only. Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Richard Henderson --- include/tcg/tcg.h | 8 ++++++-- tcg/tcg-op-ldst.c | 14 +++++++------- tcg/tcg.c | 9 ++++++--- 3 files changed, 19 insertions(+), 12 deletions(-) diff --git a/include/tcg/tcg.h b/include/tcg/tcg.h index 680ff00722..a9282cdcc6 100644 --- a/include/tcg/tcg.h +++ b/include/tcg/tcg.h @@ -488,11 +488,9 @@ struct TCGContext { int nb_ops; TCGType addr_type; /* TCG_TYPE_I32 or TCG_TYPE_I64 */ -#ifdef CONFIG_SOFTMMU int page_mask; uint8_t page_bits; uint8_t tlb_dyn_max_bits; -#endif uint8_t insn_start_words; TCGBar guest_mo; @@ -573,6 +571,12 @@ static inline bool temp_readonly(TCGTemp *ts) return ts->kind >= TEMP_FIXED; } +#ifdef CONFIG_USER_ONLY +extern bool tcg_use_softmmu; +#else +#define tcg_use_softmmu true +#endif + extern __thread TCGContext *tcg_ctx; extern const void *tcg_code_gen_epilogue; extern uintptr_t tcg_splitwx_diff; diff --git a/tcg/tcg-op-ldst.c b/tcg/tcg-op-ldst.c index df4f22c427..2b96687699 100644 --- a/tcg/tcg-op-ldst.c +++ b/tcg/tcg-op-ldst.c @@ -34,13 +34,13 @@ static void check_max_alignment(unsigned a_bits) { -#if defined(CONFIG_SOFTMMU) /* * The requested alignment cannot overlap the TLB flags. * FIXME: Must keep the count up-to-date with "exec/cpu-all.h". */ - tcg_debug_assert(a_bits + 5 <= tcg_ctx->page_bits); -#endif + if (tcg_use_softmmu) { + tcg_debug_assert(a_bits + 5 <= tcg_ctx->page_bits); + } } static MemOp tcg_canonicalize_memop(MemOp op, bool is64, bool st) @@ -411,10 +411,11 @@ void tcg_gen_qemu_st_i64_chk(TCGv_i64 val, TCGTemp *addr, TCGArg idx, */ static bool use_two_i64_for_i128(MemOp mop) { -#ifdef CONFIG_SOFTMMU /* Two softmmu tlb lookups is larger than one function call. */ - return false; -#else + if (tcg_use_softmmu) { + return false; + } + /* * For user-only, two 64-bit operations may well be smaller than a call. * Determine if that would be legal for the requested atomicity. @@ -432,7 +433,6 @@ static bool use_two_i64_for_i128(MemOp mop) default: g_assert_not_reached(); } -#endif } static void canonicalize_memop_i128_as_i64(MemOp ret[2], MemOp orig) diff --git a/tcg/tcg.c b/tcg/tcg.c index 637b9e6870..d3a4a17ef2 100644 --- a/tcg/tcg.c +++ b/tcg/tcg.c @@ -226,6 +226,10 @@ static TCGAtomAlign atom_and_align_for_opc(TCGContext *s, MemOp opc, MemOp host_atom, bool allow_two_ops) __attribute__((unused)); +#ifdef CONFIG_USER_ONLY +bool tcg_use_softmmu; +#endif + TCGContext tcg_init_ctx; __thread TCGContext *tcg_ctx; @@ -404,13 +408,12 @@ static uintptr_t G_GNUC_UNUSED get_jmp_target_addr(TCGContext *s, int which) return (uintptr_t)tcg_splitwx_to_rx(&s->gen_tb->jmp_target_addr[which]); } -#if defined(CONFIG_SOFTMMU) && !defined(CONFIG_TCG_INTERPRETER) -static int tlb_mask_table_ofs(TCGContext *s, int which) +static int __attribute__((unused)) +tlb_mask_table_ofs(TCGContext *s, int which) { return (offsetof(CPUNegativeOffsetState, tlb.f[which]) - sizeof(CPUNegativeOffsetState)); } -#endif /* Signal overflow, starting over with fewer guest insns. */ static G_NORETURN From 23088ca0bcf491eaa3e99a2760cf85f4cd7a3bce Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Sun, 1 Oct 2023 17:12:32 +0000 Subject: [PATCH 1054/1077] tcg: Provide guest_base fallback for system mode MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Provide a define to allow !tcg_use_softmmu code paths to compile in system mode, but require elimination. Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Richard Henderson --- tcg/tcg.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tcg/tcg.c b/tcg/tcg.c index d3a4a17ef2..35158a0846 100644 --- a/tcg/tcg.c +++ b/tcg/tcg.c @@ -178,6 +178,10 @@ static bool tcg_target_const_match(int64_t val, TCGType type, int ct, int vece); static int tcg_out_ldst_finalize(TCGContext *s); #endif +#ifndef CONFIG_USER_ONLY +#define guest_base ({ qemu_build_not_reached(); (uintptr_t)0; }) +#endif + typedef struct TCGLdstHelperParam { TCGReg (*ra_gen)(TCGContext *s, const TCGLabelQemuLdst *l, int arg_reg); unsigned ntmp; From 2c53bdf110ef09422ceed89357a7dd8fc7d0b7a8 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Sun, 1 Oct 2023 17:13:00 +0000 Subject: [PATCH 1055/1077] tcg/arm: Use tcg_use_softmmu MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Richard Henderson --- tcg/arm/tcg-target.c.inc | 203 +++++++++++++++++++-------------------- 1 file changed, 97 insertions(+), 106 deletions(-) diff --git a/tcg/arm/tcg-target.c.inc b/tcg/arm/tcg-target.c.inc index 0d9c2d157b..fc78566494 100644 --- a/tcg/arm/tcg-target.c.inc +++ b/tcg/arm/tcg-target.c.inc @@ -89,9 +89,7 @@ static TCGReg tcg_target_call_oarg_reg(TCGCallReturnKind kind, int slot) #define TCG_REG_TMP TCG_REG_R12 #define TCG_VEC_TMP TCG_REG_Q15 -#ifndef CONFIG_SOFTMMU #define TCG_REG_GUEST_BASE TCG_REG_R11 -#endif typedef enum { COND_EQ = 0x0, @@ -356,14 +354,8 @@ static bool patch_reloc(tcg_insn_unit *code_ptr, int type, * r0-r3 will be overwritten when reading the tlb entry (system-mode only); * r14 will be overwritten by the BLNE branching to the slow path. */ -#ifdef CONFIG_SOFTMMU #define ALL_QLDST_REGS \ - (ALL_GENERAL_REGS & ~((1 << TCG_REG_R0) | (1 << TCG_REG_R1) | \ - (1 << TCG_REG_R2) | (1 << TCG_REG_R3) | \ - (1 << TCG_REG_R14))) -#else -#define ALL_QLDST_REGS (ALL_GENERAL_REGS & ~(1 << TCG_REG_R14)) -#endif + (ALL_GENERAL_REGS & ~((tcg_use_softmmu ? 0xf : 0) | (1 << TCG_REG_R14))) /* * ARM immediates for ALU instructions are made of an unsigned 8-bit @@ -1387,113 +1379,115 @@ static TCGLabelQemuLdst *prepare_host_addr(TCGContext *s, HostAddress *h, MemOp opc = get_memop(oi); unsigned a_mask; -#ifdef CONFIG_SOFTMMU - *h = (HostAddress){ - .cond = COND_AL, - .base = addrlo, - .index = TCG_REG_R1, - .index_scratch = true, - }; -#else - *h = (HostAddress){ - .cond = COND_AL, - .base = addrlo, - .index = guest_base ? TCG_REG_GUEST_BASE : -1, - .index_scratch = false, - }; -#endif + if (tcg_use_softmmu) { + *h = (HostAddress){ + .cond = COND_AL, + .base = addrlo, + .index = TCG_REG_R1, + .index_scratch = true, + }; + } else { + *h = (HostAddress){ + .cond = COND_AL, + .base = addrlo, + .index = guest_base ? TCG_REG_GUEST_BASE : -1, + .index_scratch = false, + }; + } h->aa = atom_and_align_for_opc(s, opc, MO_ATOM_IFALIGN, false); a_mask = (1 << h->aa.align) - 1; -#ifdef CONFIG_SOFTMMU - int mem_index = get_mmuidx(oi); - int cmp_off = is_ld ? offsetof(CPUTLBEntry, addr_read) - : offsetof(CPUTLBEntry, addr_write); - int fast_off = tlb_mask_table_ofs(s, mem_index); - unsigned s_mask = (1 << (opc & MO_SIZE)) - 1; - TCGReg t_addr; + if (tcg_use_softmmu) { + int mem_index = get_mmuidx(oi); + int cmp_off = is_ld ? offsetof(CPUTLBEntry, addr_read) + : offsetof(CPUTLBEntry, addr_write); + int fast_off = tlb_mask_table_ofs(s, mem_index); + unsigned s_mask = (1 << (opc & MO_SIZE)) - 1; + TCGReg t_addr; - ldst = new_ldst_label(s); - ldst->is_ld = is_ld; - ldst->oi = oi; - ldst->addrlo_reg = addrlo; - ldst->addrhi_reg = addrhi; + ldst = new_ldst_label(s); + ldst->is_ld = is_ld; + ldst->oi = oi; + ldst->addrlo_reg = addrlo; + ldst->addrhi_reg = addrhi; - /* Load cpu->neg.tlb.f[mmu_idx].{mask,table} into {r0,r1}. */ - QEMU_BUILD_BUG_ON(offsetof(CPUTLBDescFast, mask) != 0); - QEMU_BUILD_BUG_ON(offsetof(CPUTLBDescFast, table) != 4); - tcg_out_ldrd_8(s, COND_AL, TCG_REG_R0, TCG_AREG0, fast_off); + /* Load cpu->neg.tlb.f[mmu_idx].{mask,table} into {r0,r1}. */ + QEMU_BUILD_BUG_ON(offsetof(CPUTLBDescFast, mask) != 0); + QEMU_BUILD_BUG_ON(offsetof(CPUTLBDescFast, table) != 4); + tcg_out_ldrd_8(s, COND_AL, TCG_REG_R0, TCG_AREG0, fast_off); - /* Extract the tlb index from the address into R0. */ - tcg_out_dat_reg(s, COND_AL, ARITH_AND, TCG_REG_R0, TCG_REG_R0, addrlo, - SHIFT_IMM_LSR(s->page_bits - CPU_TLB_ENTRY_BITS)); + /* Extract the tlb index from the address into R0. */ + tcg_out_dat_reg(s, COND_AL, ARITH_AND, TCG_REG_R0, TCG_REG_R0, addrlo, + SHIFT_IMM_LSR(s->page_bits - CPU_TLB_ENTRY_BITS)); - /* - * Add the tlb_table pointer, creating the CPUTLBEntry address in R1. - * Load the tlb comparator into R2/R3 and the fast path addend into R1. - */ - QEMU_BUILD_BUG_ON(HOST_BIG_ENDIAN); - if (cmp_off == 0) { - if (s->addr_type == TCG_TYPE_I32) { - tcg_out_ld32_rwb(s, COND_AL, TCG_REG_R2, TCG_REG_R1, TCG_REG_R0); + /* + * Add the tlb_table pointer, creating the CPUTLBEntry address in R1. + * Load the tlb comparator into R2/R3 and the fast path addend into R1. + */ + QEMU_BUILD_BUG_ON(HOST_BIG_ENDIAN); + if (cmp_off == 0) { + if (s->addr_type == TCG_TYPE_I32) { + tcg_out_ld32_rwb(s, COND_AL, TCG_REG_R2, + TCG_REG_R1, TCG_REG_R0); + } else { + tcg_out_ldrd_rwb(s, COND_AL, TCG_REG_R2, + TCG_REG_R1, TCG_REG_R0); + } } else { - tcg_out_ldrd_rwb(s, COND_AL, TCG_REG_R2, TCG_REG_R1, TCG_REG_R0); + tcg_out_dat_reg(s, COND_AL, ARITH_ADD, + TCG_REG_R1, TCG_REG_R1, TCG_REG_R0, 0); + if (s->addr_type == TCG_TYPE_I32) { + tcg_out_ld32_12(s, COND_AL, TCG_REG_R2, TCG_REG_R1, cmp_off); + } else { + tcg_out_ldrd_8(s, COND_AL, TCG_REG_R2, TCG_REG_R1, cmp_off); + } } - } else { - tcg_out_dat_reg(s, COND_AL, ARITH_ADD, - TCG_REG_R1, TCG_REG_R1, TCG_REG_R0, 0); - if (s->addr_type == TCG_TYPE_I32) { - tcg_out_ld32_12(s, COND_AL, TCG_REG_R2, TCG_REG_R1, cmp_off); + + /* Load the tlb addend. */ + tcg_out_ld32_12(s, COND_AL, TCG_REG_R1, TCG_REG_R1, + offsetof(CPUTLBEntry, addend)); + + /* + * Check alignment, check comparators. + * Do this in 2-4 insns. Use MOVW for v7, if possible, + * to reduce the number of sequential conditional instructions. + * Almost all guests have at least 4k pages, which means that we need + * to clear at least 9 bits even for an 8-byte memory, which means it + * isn't worth checking for an immediate operand for BIC. + * + * For unaligned accesses, test the page of the last unit of alignment. + * This leaves the least significant alignment bits unchanged, and of + * course must be zero. + */ + t_addr = addrlo; + if (a_mask < s_mask) { + t_addr = TCG_REG_R0; + tcg_out_dat_imm(s, COND_AL, ARITH_ADD, t_addr, + addrlo, s_mask - a_mask); + } + if (use_armv7_instructions && s->page_bits <= 16) { + tcg_out_movi32(s, COND_AL, TCG_REG_TMP, ~(s->page_mask | a_mask)); + tcg_out_dat_reg(s, COND_AL, ARITH_BIC, TCG_REG_TMP, + t_addr, TCG_REG_TMP, 0); + tcg_out_dat_reg(s, COND_AL, ARITH_CMP, 0, + TCG_REG_R2, TCG_REG_TMP, 0); } else { - tcg_out_ldrd_8(s, COND_AL, TCG_REG_R2, TCG_REG_R1, cmp_off); + if (a_mask) { + tcg_debug_assert(a_mask <= 0xff); + tcg_out_dat_imm(s, COND_AL, ARITH_TST, 0, addrlo, a_mask); + } + tcg_out_dat_reg(s, COND_AL, ARITH_MOV, TCG_REG_TMP, 0, t_addr, + SHIFT_IMM_LSR(s->page_bits)); + tcg_out_dat_reg(s, (a_mask ? COND_EQ : COND_AL), ARITH_CMP, + 0, TCG_REG_R2, TCG_REG_TMP, + SHIFT_IMM_LSL(s->page_bits)); } - } - /* Load the tlb addend. */ - tcg_out_ld32_12(s, COND_AL, TCG_REG_R1, TCG_REG_R1, - offsetof(CPUTLBEntry, addend)); - - /* - * Check alignment, check comparators. - * Do this in 2-4 insns. Use MOVW for v7, if possible, - * to reduce the number of sequential conditional instructions. - * Almost all guests have at least 4k pages, which means that we need - * to clear at least 9 bits even for an 8-byte memory, which means it - * isn't worth checking for an immediate operand for BIC. - * - * For unaligned accesses, test the page of the last unit of alignment. - * This leaves the least significant alignment bits unchanged, and of - * course must be zero. - */ - t_addr = addrlo; - if (a_mask < s_mask) { - t_addr = TCG_REG_R0; - tcg_out_dat_imm(s, COND_AL, ARITH_ADD, t_addr, - addrlo, s_mask - a_mask); - } - if (use_armv7_instructions && s->page_bits <= 16) { - tcg_out_movi32(s, COND_AL, TCG_REG_TMP, ~(s->page_mask | a_mask)); - tcg_out_dat_reg(s, COND_AL, ARITH_BIC, TCG_REG_TMP, - t_addr, TCG_REG_TMP, 0); - tcg_out_dat_reg(s, COND_AL, ARITH_CMP, 0, TCG_REG_R2, TCG_REG_TMP, 0); - } else { - if (a_mask) { - tcg_debug_assert(a_mask <= 0xff); - tcg_out_dat_imm(s, COND_AL, ARITH_TST, 0, addrlo, a_mask); + if (s->addr_type != TCG_TYPE_I32) { + tcg_out_dat_reg(s, COND_EQ, ARITH_CMP, 0, TCG_REG_R3, addrhi, 0); } - tcg_out_dat_reg(s, COND_AL, ARITH_MOV, TCG_REG_TMP, 0, t_addr, - SHIFT_IMM_LSR(s->page_bits)); - tcg_out_dat_reg(s, (a_mask ? COND_EQ : COND_AL), ARITH_CMP, - 0, TCG_REG_R2, TCG_REG_TMP, - SHIFT_IMM_LSL(s->page_bits)); - } - - if (s->addr_type != TCG_TYPE_I32) { - tcg_out_dat_reg(s, COND_EQ, ARITH_CMP, 0, TCG_REG_R3, addrhi, 0); - } -#else - if (a_mask) { + } else if (a_mask) { ldst = new_ldst_label(s); ldst->is_ld = is_ld; ldst->oi = oi; @@ -1505,7 +1499,6 @@ static TCGLabelQemuLdst *prepare_host_addr(TCGContext *s, HostAddress *h, /* tst addr, #mask */ tcg_out_dat_imm(s, COND_AL, ARITH_TST, 0, addrlo, a_mask); } -#endif return ldst; } @@ -2931,12 +2924,10 @@ static void tcg_target_qemu_prologue(TCGContext *s) tcg_out_mov(s, TCG_TYPE_PTR, TCG_AREG0, tcg_target_call_iarg_regs[0]); -#ifndef CONFIG_SOFTMMU - if (guest_base) { + if (!tcg_use_softmmu && guest_base) { tcg_out_movi(s, TCG_TYPE_PTR, TCG_REG_GUEST_BASE, guest_base); tcg_regset_set_reg(s->reserved_regs, TCG_REG_GUEST_BASE); } -#endif tcg_out_b_reg(s, COND_AL, tcg_target_call_iarg_regs[1]); From e2b7a40d05c682e8a254d9f664b368af9fdb1e8f Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Sun, 1 Oct 2023 16:26:53 +0000 Subject: [PATCH 1056/1077] tcg/aarch64: Use tcg_use_softmmu MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Richard Henderson --- tcg/aarch64/tcg-target.c.inc | 177 +++++++++++++++++------------------ 1 file changed, 88 insertions(+), 89 deletions(-) diff --git a/tcg/aarch64/tcg-target.c.inc b/tcg/aarch64/tcg-target.c.inc index 3afb896a3a..a3efa1e67a 100644 --- a/tcg/aarch64/tcg-target.c.inc +++ b/tcg/aarch64/tcg-target.c.inc @@ -77,9 +77,7 @@ static TCGReg tcg_target_call_oarg_reg(TCGCallReturnKind kind, int slot) #define TCG_REG_TMP2 TCG_REG_X30 #define TCG_VEC_TMP0 TCG_REG_V31 -#ifndef CONFIG_SOFTMMU #define TCG_REG_GUEST_BASE TCG_REG_X28 -#endif static bool reloc_pc26(tcg_insn_unit *src_rw, const tcg_insn_unit *target) { @@ -1664,97 +1662,98 @@ static TCGLabelQemuLdst *prepare_host_addr(TCGContext *s, HostAddress *h, s_bits == MO_128); a_mask = (1 << h->aa.align) - 1; -#ifdef CONFIG_SOFTMMU - unsigned s_mask = (1u << s_bits) - 1; - unsigned mem_index = get_mmuidx(oi); - TCGReg addr_adj; - TCGType mask_type; - uint64_t compare_mask; + if (tcg_use_softmmu) { + unsigned s_mask = (1u << s_bits) - 1; + unsigned mem_index = get_mmuidx(oi); + TCGReg addr_adj; + TCGType mask_type; + uint64_t compare_mask; - ldst = new_ldst_label(s); - ldst->is_ld = is_ld; - ldst->oi = oi; - ldst->addrlo_reg = addr_reg; - - mask_type = (s->page_bits + s->tlb_dyn_max_bits > 32 - ? TCG_TYPE_I64 : TCG_TYPE_I32); - - /* Load cpu->neg.tlb.f[mmu_idx].{mask,table} into {tmp0,tmp1}. */ - QEMU_BUILD_BUG_ON(offsetof(CPUTLBDescFast, mask) != 0); - QEMU_BUILD_BUG_ON(offsetof(CPUTLBDescFast, table) != 8); - tcg_out_insn(s, 3314, LDP, TCG_REG_TMP0, TCG_REG_TMP1, TCG_AREG0, - tlb_mask_table_ofs(s, mem_index), 1, 0); - - /* Extract the TLB index from the address into X0. */ - tcg_out_insn(s, 3502S, AND_LSR, mask_type == TCG_TYPE_I64, - TCG_REG_TMP0, TCG_REG_TMP0, addr_reg, - s->page_bits - CPU_TLB_ENTRY_BITS); - - /* Add the tlb_table pointer, forming the CPUTLBEntry address in TMP1. */ - tcg_out_insn(s, 3502, ADD, 1, TCG_REG_TMP1, TCG_REG_TMP1, TCG_REG_TMP0); - - /* Load the tlb comparator into TMP0, and the fast path addend into TMP1. */ - QEMU_BUILD_BUG_ON(HOST_BIG_ENDIAN); - tcg_out_ld(s, addr_type, TCG_REG_TMP0, TCG_REG_TMP1, - is_ld ? offsetof(CPUTLBEntry, addr_read) - : offsetof(CPUTLBEntry, addr_write)); - tcg_out_ld(s, TCG_TYPE_PTR, TCG_REG_TMP1, TCG_REG_TMP1, - offsetof(CPUTLBEntry, addend)); - - /* - * For aligned accesses, we check the first byte and include the alignment - * bits within the address. For unaligned access, we check that we don't - * cross pages using the address of the last byte of the access. - */ - if (a_mask >= s_mask) { - addr_adj = addr_reg; - } else { - addr_adj = TCG_REG_TMP2; - tcg_out_insn(s, 3401, ADDI, addr_type, - addr_adj, addr_reg, s_mask - a_mask); - } - compare_mask = (uint64_t)s->page_mask | a_mask; - - /* Store the page mask part of the address into TMP2. */ - tcg_out_logicali(s, I3404_ANDI, addr_type, TCG_REG_TMP2, - addr_adj, compare_mask); - - /* Perform the address comparison. */ - tcg_out_cmp(s, addr_type, TCG_REG_TMP0, TCG_REG_TMP2, 0); - - /* If not equal, we jump to the slow path. */ - ldst->label_ptr[0] = s->code_ptr; - tcg_out_insn(s, 3202, B_C, TCG_COND_NE, 0); - - h->base = TCG_REG_TMP1; - h->index = addr_reg; - h->index_ext = addr_type; -#else - if (a_mask) { ldst = new_ldst_label(s); - ldst->is_ld = is_ld; ldst->oi = oi; ldst->addrlo_reg = addr_reg; - /* tst addr, #mask */ - tcg_out_logicali(s, I3404_ANDSI, 0, TCG_REG_XZR, addr_reg, a_mask); + mask_type = (s->page_bits + s->tlb_dyn_max_bits > 32 + ? TCG_TYPE_I64 : TCG_TYPE_I32); - /* b.ne slow_path */ + /* Load cpu->neg.tlb.f[mmu_idx].{mask,table} into {tmp0,tmp1}. */ + QEMU_BUILD_BUG_ON(offsetof(CPUTLBDescFast, mask) != 0); + QEMU_BUILD_BUG_ON(offsetof(CPUTLBDescFast, table) != 8); + tcg_out_insn(s, 3314, LDP, TCG_REG_TMP0, TCG_REG_TMP1, TCG_AREG0, + tlb_mask_table_ofs(s, mem_index), 1, 0); + + /* Extract the TLB index from the address into X0. */ + tcg_out_insn(s, 3502S, AND_LSR, mask_type == TCG_TYPE_I64, + TCG_REG_TMP0, TCG_REG_TMP0, addr_reg, + s->page_bits - CPU_TLB_ENTRY_BITS); + + /* Add the tlb_table pointer, forming the CPUTLBEntry address. */ + tcg_out_insn(s, 3502, ADD, 1, TCG_REG_TMP1, TCG_REG_TMP1, TCG_REG_TMP0); + + /* Load the tlb comparator into TMP0, and the fast path addend. */ + QEMU_BUILD_BUG_ON(HOST_BIG_ENDIAN); + tcg_out_ld(s, addr_type, TCG_REG_TMP0, TCG_REG_TMP1, + is_ld ? offsetof(CPUTLBEntry, addr_read) + : offsetof(CPUTLBEntry, addr_write)); + tcg_out_ld(s, TCG_TYPE_PTR, TCG_REG_TMP1, TCG_REG_TMP1, + offsetof(CPUTLBEntry, addend)); + + /* + * For aligned accesses, we check the first byte and include + * the alignment bits within the address. For unaligned access, + * we check that we don't cross pages using the address of the + * last byte of the access. + */ + if (a_mask >= s_mask) { + addr_adj = addr_reg; + } else { + addr_adj = TCG_REG_TMP2; + tcg_out_insn(s, 3401, ADDI, addr_type, + addr_adj, addr_reg, s_mask - a_mask); + } + compare_mask = (uint64_t)s->page_mask | a_mask; + + /* Store the page mask part of the address into TMP2. */ + tcg_out_logicali(s, I3404_ANDI, addr_type, TCG_REG_TMP2, + addr_adj, compare_mask); + + /* Perform the address comparison. */ + tcg_out_cmp(s, addr_type, TCG_REG_TMP0, TCG_REG_TMP2, 0); + + /* If not equal, we jump to the slow path. */ ldst->label_ptr[0] = s->code_ptr; tcg_out_insn(s, 3202, B_C, TCG_COND_NE, 0); - } - if (guest_base || addr_type == TCG_TYPE_I32) { - h->base = TCG_REG_GUEST_BASE; + h->base = TCG_REG_TMP1; h->index = addr_reg; h->index_ext = addr_type; } else { - h->base = addr_reg; - h->index = TCG_REG_XZR; - h->index_ext = TCG_TYPE_I64; + if (a_mask) { + ldst = new_ldst_label(s); + + ldst->is_ld = is_ld; + ldst->oi = oi; + ldst->addrlo_reg = addr_reg; + + /* tst addr, #mask */ + tcg_out_logicali(s, I3404_ANDSI, 0, TCG_REG_XZR, addr_reg, a_mask); + + /* b.ne slow_path */ + ldst->label_ptr[0] = s->code_ptr; + tcg_out_insn(s, 3202, B_C, TCG_COND_NE, 0); + } + + if (guest_base || addr_type == TCG_TYPE_I32) { + h->base = TCG_REG_GUEST_BASE; + h->index = addr_reg; + h->index_ext = addr_type; + } else { + h->base = addr_reg; + h->index = TCG_REG_XZR; + h->index_ext = TCG_TYPE_I64; + } } -#endif return ldst; } @@ -3117,16 +3116,16 @@ static void tcg_target_qemu_prologue(TCGContext *s) tcg_set_frame(s, TCG_REG_SP, TCG_STATIC_CALL_ARGS_SIZE, CPU_TEMP_BUF_NLONGS * sizeof(long)); -#if !defined(CONFIG_SOFTMMU) - /* - * Note that XZR cannot be encoded in the address base register slot, - * as that actually encodes SP. Depending on the guest, we may need - * to zero-extend the guest address via the address index register slot, - * therefore we need to load even a zero guest base into a register. - */ - tcg_out_movi(s, TCG_TYPE_PTR, TCG_REG_GUEST_BASE, guest_base); - tcg_regset_set_reg(s->reserved_regs, TCG_REG_GUEST_BASE); -#endif + if (!tcg_use_softmmu) { + /* + * Note that XZR cannot be encoded in the address base register slot, + * as that actually encodes SP. Depending on the guest, we may need + * to zero-extend the guest address via the address index register slot, + * therefore we need to load even a zero guest base into a register. + */ + tcg_out_movi(s, TCG_TYPE_PTR, TCG_REG_GUEST_BASE, guest_base); + tcg_regset_set_reg(s->reserved_regs, TCG_REG_GUEST_BASE); + } tcg_out_mov(s, TCG_TYPE_PTR, TCG_AREG0, tcg_target_call_iarg_regs[0]); tcg_out_insn(s, 3207, BR, tcg_target_call_iarg_regs[1]); From 915e1d52e205cdfa85cfc848e022b470f35a090e Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Sun, 1 Oct 2023 08:13:44 -0700 Subject: [PATCH 1057/1077] tcg/i386: Use tcg_use_softmmu MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Richard Henderson --- tcg/i386/tcg-target.c.inc | 198 +++++++++++++++++++------------------- 1 file changed, 98 insertions(+), 100 deletions(-) diff --git a/tcg/i386/tcg-target.c.inc b/tcg/i386/tcg-target.c.inc index 788d608150..a83f8aab30 100644 --- a/tcg/i386/tcg-target.c.inc +++ b/tcg/i386/tcg-target.c.inc @@ -153,11 +153,8 @@ static TCGReg tcg_target_call_oarg_reg(TCGCallReturnKind kind, int slot) # define ALL_VECTOR_REGS 0x00ff0000u # define ALL_BYTEL_REGS 0x0000000fu #endif -#ifdef CONFIG_SOFTMMU -# define SOFTMMU_RESERVE_REGS ((1 << TCG_REG_L0) | (1 << TCG_REG_L1)) -#else -# define SOFTMMU_RESERVE_REGS 0 -#endif +#define SOFTMMU_RESERVE_REGS \ + (tcg_use_softmmu ? (1 << TCG_REG_L0) | (1 << TCG_REG_L1) : 0) /* For 64-bit, we always know that CMOV is available. */ #if TCG_TARGET_REG_BITS == 64 @@ -1933,7 +1930,7 @@ static bool tcg_out_qemu_st_slow_path(TCGContext *s, TCGLabelQemuLdst *l) return true; } -#ifndef CONFIG_SOFTMMU +#ifdef CONFIG_USER_ONLY static HostAddress x86_guest_base = { .index = -1 }; @@ -1949,6 +1946,7 @@ static inline int setup_guest_base_seg(void) } return 0; } +#define setup_guest_base_seg setup_guest_base_seg #elif defined(__x86_64__) && \ (defined (__FreeBSD__) || defined (__FreeBSD_kernel__)) # include @@ -1959,13 +1957,14 @@ static inline int setup_guest_base_seg(void) } return 0; } +#define setup_guest_base_seg setup_guest_base_seg +#endif #else -static inline int setup_guest_base_seg(void) -{ - return 0; -} -#endif /* setup_guest_base_seg */ -#endif /* !SOFTMMU */ +# define x86_guest_base (*(HostAddress *)({ qemu_build_not_reached(); NULL; })) +#endif /* CONFIG_USER_ONLY */ +#ifndef setup_guest_base_seg +# define setup_guest_base_seg() 0 +#endif #define MIN_TLB_MASK_TABLE_OFS INT_MIN @@ -1984,94 +1983,94 @@ static TCGLabelQemuLdst *prepare_host_addr(TCGContext *s, HostAddress *h, MemOp s_bits = opc & MO_SIZE; unsigned a_mask; -#ifdef CONFIG_SOFTMMU - h->index = TCG_REG_L0; - h->ofs = 0; - h->seg = 0; -#else - *h = x86_guest_base; -#endif + if (tcg_use_softmmu) { + h->index = TCG_REG_L0; + h->ofs = 0; + h->seg = 0; + } else { + *h = x86_guest_base; + } h->base = addrlo; h->aa = atom_and_align_for_opc(s, opc, MO_ATOM_IFALIGN, s_bits == MO_128); a_mask = (1 << h->aa.align) - 1; -#ifdef CONFIG_SOFTMMU - int cmp_ofs = is_ld ? offsetof(CPUTLBEntry, addr_read) - : offsetof(CPUTLBEntry, addr_write); - TCGType ttype = TCG_TYPE_I32; - TCGType tlbtype = TCG_TYPE_I32; - int trexw = 0, hrexw = 0, tlbrexw = 0; - unsigned mem_index = get_mmuidx(oi); - unsigned s_mask = (1 << s_bits) - 1; - int fast_ofs = tlb_mask_table_ofs(s, mem_index); - int tlb_mask; + if (tcg_use_softmmu) { + int cmp_ofs = is_ld ? offsetof(CPUTLBEntry, addr_read) + : offsetof(CPUTLBEntry, addr_write); + TCGType ttype = TCG_TYPE_I32; + TCGType tlbtype = TCG_TYPE_I32; + int trexw = 0, hrexw = 0, tlbrexw = 0; + unsigned mem_index = get_mmuidx(oi); + unsigned s_mask = (1 << s_bits) - 1; + int fast_ofs = tlb_mask_table_ofs(s, mem_index); + int tlb_mask; - ldst = new_ldst_label(s); - ldst->is_ld = is_ld; - ldst->oi = oi; - ldst->addrlo_reg = addrlo; - ldst->addrhi_reg = addrhi; + ldst = new_ldst_label(s); + ldst->is_ld = is_ld; + ldst->oi = oi; + ldst->addrlo_reg = addrlo; + ldst->addrhi_reg = addrhi; - if (TCG_TARGET_REG_BITS == 64) { - ttype = s->addr_type; - trexw = (ttype == TCG_TYPE_I32 ? 0 : P_REXW); - if (TCG_TYPE_PTR == TCG_TYPE_I64) { - hrexw = P_REXW; - if (s->page_bits + s->tlb_dyn_max_bits > 32) { - tlbtype = TCG_TYPE_I64; - tlbrexw = P_REXW; + if (TCG_TARGET_REG_BITS == 64) { + ttype = s->addr_type; + trexw = (ttype == TCG_TYPE_I32 ? 0 : P_REXW); + if (TCG_TYPE_PTR == TCG_TYPE_I64) { + hrexw = P_REXW; + if (s->page_bits + s->tlb_dyn_max_bits > 32) { + tlbtype = TCG_TYPE_I64; + tlbrexw = P_REXW; + } } } - } - tcg_out_mov(s, tlbtype, TCG_REG_L0, addrlo); - tcg_out_shifti(s, SHIFT_SHR + tlbrexw, TCG_REG_L0, - s->page_bits - CPU_TLB_ENTRY_BITS); + tcg_out_mov(s, tlbtype, TCG_REG_L0, addrlo); + tcg_out_shifti(s, SHIFT_SHR + tlbrexw, TCG_REG_L0, + s->page_bits - CPU_TLB_ENTRY_BITS); - tcg_out_modrm_offset(s, OPC_AND_GvEv + trexw, TCG_REG_L0, TCG_AREG0, - fast_ofs + offsetof(CPUTLBDescFast, mask)); + tcg_out_modrm_offset(s, OPC_AND_GvEv + trexw, TCG_REG_L0, TCG_AREG0, + fast_ofs + offsetof(CPUTLBDescFast, mask)); - tcg_out_modrm_offset(s, OPC_ADD_GvEv + hrexw, TCG_REG_L0, TCG_AREG0, - fast_ofs + offsetof(CPUTLBDescFast, table)); + tcg_out_modrm_offset(s, OPC_ADD_GvEv + hrexw, TCG_REG_L0, TCG_AREG0, + fast_ofs + offsetof(CPUTLBDescFast, table)); - /* - * If the required alignment is at least as large as the access, simply - * copy the address and mask. For lesser alignments, check that we don't - * cross pages for the complete access. - */ - if (a_mask >= s_mask) { - tcg_out_mov(s, ttype, TCG_REG_L1, addrlo); - } else { - tcg_out_modrm_offset(s, OPC_LEA + trexw, TCG_REG_L1, - addrlo, s_mask - a_mask); - } - tlb_mask = s->page_mask | a_mask; - tgen_arithi(s, ARITH_AND + trexw, TCG_REG_L1, tlb_mask, 0); + /* + * If the required alignment is at least as large as the access, + * simply copy the address and mask. For lesser alignments, + * check that we don't cross pages for the complete access. + */ + if (a_mask >= s_mask) { + tcg_out_mov(s, ttype, TCG_REG_L1, addrlo); + } else { + tcg_out_modrm_offset(s, OPC_LEA + trexw, TCG_REG_L1, + addrlo, s_mask - a_mask); + } + tlb_mask = s->page_mask | a_mask; + tgen_arithi(s, ARITH_AND + trexw, TCG_REG_L1, tlb_mask, 0); - /* cmp 0(TCG_REG_L0), TCG_REG_L1 */ - tcg_out_modrm_offset(s, OPC_CMP_GvEv + trexw, - TCG_REG_L1, TCG_REG_L0, cmp_ofs); - - /* jne slow_path */ - tcg_out_opc(s, OPC_JCC_long + JCC_JNE, 0, 0, 0); - ldst->label_ptr[0] = s->code_ptr; - s->code_ptr += 4; - - if (TCG_TARGET_REG_BITS == 32 && s->addr_type == TCG_TYPE_I64) { - /* cmp 4(TCG_REG_L0), addrhi */ - tcg_out_modrm_offset(s, OPC_CMP_GvEv, addrhi, TCG_REG_L0, cmp_ofs + 4); + /* cmp 0(TCG_REG_L0), TCG_REG_L1 */ + tcg_out_modrm_offset(s, OPC_CMP_GvEv + trexw, + TCG_REG_L1, TCG_REG_L0, cmp_ofs); /* jne slow_path */ tcg_out_opc(s, OPC_JCC_long + JCC_JNE, 0, 0, 0); - ldst->label_ptr[1] = s->code_ptr; + ldst->label_ptr[0] = s->code_ptr; s->code_ptr += 4; - } - /* TLB Hit. */ - tcg_out_ld(s, TCG_TYPE_PTR, TCG_REG_L0, TCG_REG_L0, - offsetof(CPUTLBEntry, addend)); -#else - if (a_mask) { + if (TCG_TARGET_REG_BITS == 32 && s->addr_type == TCG_TYPE_I64) { + /* cmp 4(TCG_REG_L0), addrhi */ + tcg_out_modrm_offset(s, OPC_CMP_GvEv, addrhi, + TCG_REG_L0, cmp_ofs + 4); + + /* jne slow_path */ + tcg_out_opc(s, OPC_JCC_long + JCC_JNE, 0, 0, 0); + ldst->label_ptr[1] = s->code_ptr; + s->code_ptr += 4; + } + + /* TLB Hit. */ + tcg_out_ld(s, TCG_TYPE_PTR, TCG_REG_L0, TCG_REG_L0, + offsetof(CPUTLBEntry, addend)); + } else if (a_mask) { ldst = new_ldst_label(s); ldst->is_ld = is_ld; @@ -2085,7 +2084,6 @@ static TCGLabelQemuLdst *prepare_host_addr(TCGContext *s, HostAddress *h, ldst->label_ptr[0] = s->code_ptr; s->code_ptr += 4; } -#endif return ldst; } @@ -4140,35 +4138,35 @@ static void tcg_target_qemu_prologue(TCGContext *s) tcg_out_push(s, tcg_target_callee_save_regs[i]); } -#if TCG_TARGET_REG_BITS == 32 - tcg_out_ld(s, TCG_TYPE_PTR, TCG_AREG0, TCG_REG_ESP, - (ARRAY_SIZE(tcg_target_callee_save_regs) + 1) * 4); - tcg_out_addi(s, TCG_REG_ESP, -stack_addend); - /* jmp *tb. */ - tcg_out_modrm_offset(s, OPC_GRP5, EXT5_JMPN_Ev, TCG_REG_ESP, - (ARRAY_SIZE(tcg_target_callee_save_regs) + 2) * 4 - + stack_addend); -#else -# if !defined(CONFIG_SOFTMMU) - if (guest_base) { + if (!tcg_use_softmmu && guest_base) { int seg = setup_guest_base_seg(); if (seg != 0) { x86_guest_base.seg = seg; } else if (guest_base == (int32_t)guest_base) { x86_guest_base.ofs = guest_base; } else { + assert(TCG_TARGET_REG_BITS == 64); /* Choose R12 because, as a base, it requires a SIB byte. */ x86_guest_base.index = TCG_REG_R12; tcg_out_movi(s, TCG_TYPE_PTR, x86_guest_base.index, guest_base); tcg_regset_set_reg(s->reserved_regs, x86_guest_base.index); } } -# endif - tcg_out_mov(s, TCG_TYPE_PTR, TCG_AREG0, tcg_target_call_iarg_regs[0]); - tcg_out_addi(s, TCG_REG_ESP, -stack_addend); - /* jmp *tb. */ - tcg_out_modrm(s, OPC_GRP5, EXT5_JMPN_Ev, tcg_target_call_iarg_regs[1]); -#endif + + if (TCG_TARGET_REG_BITS == 32) { + tcg_out_ld(s, TCG_TYPE_PTR, TCG_AREG0, TCG_REG_ESP, + (ARRAY_SIZE(tcg_target_callee_save_regs) + 1) * 4); + tcg_out_addi(s, TCG_REG_ESP, -stack_addend); + /* jmp *tb. */ + tcg_out_modrm_offset(s, OPC_GRP5, EXT5_JMPN_Ev, TCG_REG_ESP, + (ARRAY_SIZE(tcg_target_callee_save_regs) + 2) * 4 + + stack_addend); + } else { + tcg_out_mov(s, TCG_TYPE_PTR, TCG_AREG0, tcg_target_call_iarg_regs[0]); + tcg_out_addi(s, TCG_REG_ESP, -stack_addend); + /* jmp *tb. */ + tcg_out_modrm(s, OPC_GRP5, EXT5_JMPN_Ev, tcg_target_call_iarg_regs[1]); + } /* * Return path for goto_ptr. Set return value to 0, a-la exit_tb, From 10e1fd2784e59e1781ce09f65b0499784938e83b Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Sun, 1 Oct 2023 18:05:27 +0000 Subject: [PATCH 1058/1077] tcg/loongarch64: Use tcg_use_softmmu MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Richard Henderson --- tcg/loongarch64/tcg-target.c.inc | 126 +++++++++++++++---------------- 1 file changed, 61 insertions(+), 65 deletions(-) diff --git a/tcg/loongarch64/tcg-target.c.inc b/tcg/loongarch64/tcg-target.c.inc index 801302d85d..ccf133db4b 100644 --- a/tcg/loongarch64/tcg-target.c.inc +++ b/tcg/loongarch64/tcg-target.c.inc @@ -165,10 +165,7 @@ static TCGReg tcg_target_call_oarg_reg(TCGCallReturnKind kind, int slot) return TCG_REG_A0 + slot; } -#ifndef CONFIG_SOFTMMU -#define USE_GUEST_BASE (guest_base != 0) #define TCG_GUEST_BASE_REG TCG_REG_S1 -#endif #define TCG_CT_CONST_ZERO 0x100 #define TCG_CT_CONST_S12 0x200 @@ -908,76 +905,77 @@ static TCGLabelQemuLdst *prepare_host_addr(TCGContext *s, HostAddress *h, h->aa = atom_and_align_for_opc(s, opc, MO_ATOM_IFALIGN, false); a_bits = h->aa.align; -#ifdef CONFIG_SOFTMMU - unsigned s_bits = opc & MO_SIZE; - int mem_index = get_mmuidx(oi); - int fast_ofs = tlb_mask_table_ofs(s, mem_index); - int mask_ofs = fast_ofs + offsetof(CPUTLBDescFast, mask); - int table_ofs = fast_ofs + offsetof(CPUTLBDescFast, table); + if (tcg_use_softmmu) { + unsigned s_bits = opc & MO_SIZE; + int mem_index = get_mmuidx(oi); + int fast_ofs = tlb_mask_table_ofs(s, mem_index); + int mask_ofs = fast_ofs + offsetof(CPUTLBDescFast, mask); + int table_ofs = fast_ofs + offsetof(CPUTLBDescFast, table); - ldst = new_ldst_label(s); - ldst->is_ld = is_ld; - ldst->oi = oi; - ldst->addrlo_reg = addr_reg; - - tcg_out_ld(s, TCG_TYPE_PTR, TCG_REG_TMP0, TCG_AREG0, mask_ofs); - tcg_out_ld(s, TCG_TYPE_PTR, TCG_REG_TMP1, TCG_AREG0, table_ofs); - - tcg_out_opc_srli_d(s, TCG_REG_TMP2, addr_reg, - s->page_bits - CPU_TLB_ENTRY_BITS); - tcg_out_opc_and(s, TCG_REG_TMP2, TCG_REG_TMP2, TCG_REG_TMP0); - tcg_out_opc_add_d(s, TCG_REG_TMP2, TCG_REG_TMP2, TCG_REG_TMP1); - - /* Load the tlb comparator and the addend. */ - QEMU_BUILD_BUG_ON(HOST_BIG_ENDIAN); - tcg_out_ld(s, addr_type, TCG_REG_TMP0, TCG_REG_TMP2, - is_ld ? offsetof(CPUTLBEntry, addr_read) - : offsetof(CPUTLBEntry, addr_write)); - tcg_out_ld(s, TCG_TYPE_PTR, TCG_REG_TMP2, TCG_REG_TMP2, - offsetof(CPUTLBEntry, addend)); - - /* - * For aligned accesses, we check the first byte and include the alignment - * bits within the address. For unaligned access, we check that we don't - * cross pages using the address of the last byte of the access. - */ - if (a_bits < s_bits) { - unsigned a_mask = (1u << a_bits) - 1; - unsigned s_mask = (1u << s_bits) - 1; - tcg_out_addi(s, addr_type, TCG_REG_TMP1, addr_reg, s_mask - a_mask); - } else { - tcg_out_mov(s, addr_type, TCG_REG_TMP1, addr_reg); - } - tcg_out_opc_bstrins_d(s, TCG_REG_TMP1, TCG_REG_ZERO, - a_bits, s->page_bits - 1); - - /* Compare masked address with the TLB entry. */ - ldst->label_ptr[0] = s->code_ptr; - tcg_out_opc_bne(s, TCG_REG_TMP0, TCG_REG_TMP1, 0); - - h->index = TCG_REG_TMP2; -#else - if (a_bits) { ldst = new_ldst_label(s); - ldst->is_ld = is_ld; ldst->oi = oi; ldst->addrlo_reg = addr_reg; + tcg_out_ld(s, TCG_TYPE_PTR, TCG_REG_TMP0, TCG_AREG0, mask_ofs); + tcg_out_ld(s, TCG_TYPE_PTR, TCG_REG_TMP1, TCG_AREG0, table_ofs); + + tcg_out_opc_srli_d(s, TCG_REG_TMP2, addr_reg, + s->page_bits - CPU_TLB_ENTRY_BITS); + tcg_out_opc_and(s, TCG_REG_TMP2, TCG_REG_TMP2, TCG_REG_TMP0); + tcg_out_opc_add_d(s, TCG_REG_TMP2, TCG_REG_TMP2, TCG_REG_TMP1); + + /* Load the tlb comparator and the addend. */ + QEMU_BUILD_BUG_ON(HOST_BIG_ENDIAN); + tcg_out_ld(s, addr_type, TCG_REG_TMP0, TCG_REG_TMP2, + is_ld ? offsetof(CPUTLBEntry, addr_read) + : offsetof(CPUTLBEntry, addr_write)); + tcg_out_ld(s, TCG_TYPE_PTR, TCG_REG_TMP2, TCG_REG_TMP2, + offsetof(CPUTLBEntry, addend)); + /* - * Without micro-architecture details, we don't know which of - * bstrpick or andi is faster, so use bstrpick as it's not - * constrained by imm field width. Not to say alignments >= 2^12 - * are going to happen any time soon. + * For aligned accesses, we check the first byte and include the + * alignment bits within the address. For unaligned access, we + * check that we don't cross pages using the address of the last + * byte of the access. */ - tcg_out_opc_bstrpick_d(s, TCG_REG_TMP1, addr_reg, 0, a_bits - 1); + if (a_bits < s_bits) { + unsigned a_mask = (1u << a_bits) - 1; + unsigned s_mask = (1u << s_bits) - 1; + tcg_out_addi(s, addr_type, TCG_REG_TMP1, addr_reg, s_mask - a_mask); + } else { + tcg_out_mov(s, addr_type, TCG_REG_TMP1, addr_reg); + } + tcg_out_opc_bstrins_d(s, TCG_REG_TMP1, TCG_REG_ZERO, + a_bits, s->page_bits - 1); + /* Compare masked address with the TLB entry. */ ldst->label_ptr[0] = s->code_ptr; - tcg_out_opc_bne(s, TCG_REG_TMP1, TCG_REG_ZERO, 0); - } + tcg_out_opc_bne(s, TCG_REG_TMP0, TCG_REG_TMP1, 0); - h->index = USE_GUEST_BASE ? TCG_GUEST_BASE_REG : TCG_REG_ZERO; -#endif + h->index = TCG_REG_TMP2; + } else { + if (a_bits) { + ldst = new_ldst_label(s); + + ldst->is_ld = is_ld; + ldst->oi = oi; + ldst->addrlo_reg = addr_reg; + + /* + * Without micro-architecture details, we don't know which of + * bstrpick or andi is faster, so use bstrpick as it's not + * constrained by imm field width. Not to say alignments >= 2^12 + * are going to happen any time soon. + */ + tcg_out_opc_bstrpick_d(s, TCG_REG_TMP1, addr_reg, 0, a_bits - 1); + + ldst->label_ptr[0] = s->code_ptr; + tcg_out_opc_bne(s, TCG_REG_TMP1, TCG_REG_ZERO, 0); + } + + h->index = guest_base ? TCG_GUEST_BASE_REG : TCG_REG_ZERO; + } if (addr_type == TCG_TYPE_I32) { h->base = TCG_REG_TMP0; @@ -2272,12 +2270,10 @@ static void tcg_target_qemu_prologue(TCGContext *s) TCG_REG_SP, SAVE_OFS + i * REG_SIZE); } -#if !defined(CONFIG_SOFTMMU) - if (USE_GUEST_BASE) { + if (!tcg_use_softmmu && guest_base) { tcg_out_movi(s, TCG_TYPE_PTR, TCG_GUEST_BASE_REG, guest_base); tcg_regset_set_reg(s->reserved_regs, TCG_GUEST_BASE_REG); } -#endif /* Call generated code */ tcg_out_mov(s, TCG_TYPE_PTR, TCG_AREG0, tcg_target_call_iarg_regs[0]); From e3a650cd9dca1d10df8ac426fc59736e009ebd7f Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Sun, 1 Oct 2023 11:49:03 -0700 Subject: [PATCH 1059/1077] tcg/mips: Use tcg_use_softmmu MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Richard Henderson --- tcg/mips/tcg-target.c.inc | 231 +++++++++++++++++++------------------- 1 file changed, 113 insertions(+), 118 deletions(-) diff --git a/tcg/mips/tcg-target.c.inc b/tcg/mips/tcg-target.c.inc index e2892edc6a..328984ccff 100644 --- a/tcg/mips/tcg-target.c.inc +++ b/tcg/mips/tcg-target.c.inc @@ -78,13 +78,11 @@ static const char * const tcg_target_reg_names[TCG_TARGET_NB_REGS] = { #define TCG_TMP2 TCG_REG_T8 #define TCG_TMP3 TCG_REG_T7 -#ifndef CONFIG_SOFTMMU #define TCG_GUEST_BASE_REG TCG_REG_S7 -#endif #if TCG_TARGET_REG_BITS == 64 #define TCG_REG_TB TCG_REG_S6 #else -#define TCG_REG_TB (qemu_build_not_reached(), TCG_REG_ZERO) +#define TCG_REG_TB ({ qemu_build_not_reached(); TCG_REG_ZERO; }) #endif /* check if we really need so many registers :P */ @@ -1279,130 +1277,129 @@ static TCGLabelQemuLdst *prepare_host_addr(TCGContext *s, HostAddress *h, a_bits = h->aa.align; a_mask = (1 << a_bits) - 1; -#ifdef CONFIG_SOFTMMU - unsigned s_mask = (1 << s_bits) - 1; - int mem_index = get_mmuidx(oi); - int fast_off = tlb_mask_table_ofs(s, mem_index); - int mask_off = fast_off + offsetof(CPUTLBDescFast, mask); - int table_off = fast_off + offsetof(CPUTLBDescFast, table); - int add_off = offsetof(CPUTLBEntry, addend); - int cmp_off = is_ld ? offsetof(CPUTLBEntry, addr_read) - : offsetof(CPUTLBEntry, addr_write); + if (tcg_use_softmmu) { + unsigned s_mask = (1 << s_bits) - 1; + int mem_index = get_mmuidx(oi); + int fast_off = tlb_mask_table_ofs(s, mem_index); + int mask_off = fast_off + offsetof(CPUTLBDescFast, mask); + int table_off = fast_off + offsetof(CPUTLBDescFast, table); + int add_off = offsetof(CPUTLBEntry, addend); + int cmp_off = is_ld ? offsetof(CPUTLBEntry, addr_read) + : offsetof(CPUTLBEntry, addr_write); - ldst = new_ldst_label(s); - ldst->is_ld = is_ld; - ldst->oi = oi; - ldst->addrlo_reg = addrlo; - ldst->addrhi_reg = addrhi; - - /* Load tlb_mask[mmu_idx] and tlb_table[mmu_idx]. */ - tcg_out_ld(s, TCG_TYPE_PTR, TCG_TMP0, TCG_AREG0, mask_off); - tcg_out_ld(s, TCG_TYPE_PTR, TCG_TMP1, TCG_AREG0, table_off); - - /* Extract the TLB index from the address into TMP3. */ - if (TCG_TARGET_REG_BITS == 32 || addr_type == TCG_TYPE_I32) { - tcg_out_opc_sa(s, OPC_SRL, TCG_TMP3, addrlo, - s->page_bits - CPU_TLB_ENTRY_BITS); - } else { - tcg_out_dsrl(s, TCG_TMP3, addrlo, - s->page_bits - CPU_TLB_ENTRY_BITS); - } - tcg_out_opc_reg(s, OPC_AND, TCG_TMP3, TCG_TMP3, TCG_TMP0); - - /* Add the tlb_table pointer, creating the CPUTLBEntry address in TMP3. */ - tcg_out_opc_reg(s, ALIAS_PADD, TCG_TMP3, TCG_TMP3, TCG_TMP1); - - if (TCG_TARGET_REG_BITS == 32 || addr_type == TCG_TYPE_I32) { - /* Load the (low half) tlb comparator. */ - tcg_out_ld(s, TCG_TYPE_I32, TCG_TMP0, TCG_TMP3, - cmp_off + HOST_BIG_ENDIAN * 4); - } else { - tcg_out_ld(s, TCG_TYPE_I64, TCG_TMP0, TCG_TMP3, cmp_off); - } - - if (TCG_TARGET_REG_BITS == 64 || addr_type == TCG_TYPE_I32) { - /* Load the tlb addend for the fast path. */ - tcg_out_ld(s, TCG_TYPE_PTR, TCG_TMP3, TCG_TMP3, add_off); - } - - /* - * Mask the page bits, keeping the alignment bits to compare against. - * For unaligned accesses, compare against the end of the access to - * verify that it does not cross a page boundary. - */ - tcg_out_movi(s, addr_type, TCG_TMP1, s->page_mask | a_mask); - if (a_mask < s_mask) { - if (TCG_TARGET_REG_BITS == 32 || addr_type == TCG_TYPE_I32) { - tcg_out_opc_imm(s, OPC_ADDIU, TCG_TMP2, addrlo, s_mask - a_mask); - } else { - tcg_out_opc_imm(s, OPC_DADDIU, TCG_TMP2, addrlo, s_mask - a_mask); - } - tcg_out_opc_reg(s, OPC_AND, TCG_TMP1, TCG_TMP1, TCG_TMP2); - } else { - tcg_out_opc_reg(s, OPC_AND, TCG_TMP1, TCG_TMP1, addrlo); - } - - /* Zero extend a 32-bit guest address for a 64-bit host. */ - if (TCG_TARGET_REG_BITS == 64 && addr_type == TCG_TYPE_I32) { - tcg_out_ext32u(s, TCG_TMP2, addrlo); - addrlo = TCG_TMP2; - } - - ldst->label_ptr[0] = s->code_ptr; - tcg_out_opc_br(s, OPC_BNE, TCG_TMP1, TCG_TMP0); - - /* Load and test the high half tlb comparator. */ - if (TCG_TARGET_REG_BITS == 32 && addr_type != TCG_TYPE_I32) { - /* delay slot */ - tcg_out_ldst(s, OPC_LW, TCG_TMP0, TCG_TMP3, cmp_off + HI_OFF); - - /* Load the tlb addend for the fast path. */ - tcg_out_ld(s, TCG_TYPE_PTR, TCG_TMP3, TCG_TMP3, add_off); - - ldst->label_ptr[1] = s->code_ptr; - tcg_out_opc_br(s, OPC_BNE, addrhi, TCG_TMP0); - } - - /* delay slot */ - base = TCG_TMP3; - tcg_out_opc_reg(s, ALIAS_PADD, base, TCG_TMP3, addrlo); -#else - if (a_mask && (use_mips32r6_instructions || a_bits != s_bits)) { ldst = new_ldst_label(s); - ldst->is_ld = is_ld; ldst->oi = oi; ldst->addrlo_reg = addrlo; ldst->addrhi_reg = addrhi; - /* We are expecting a_bits to max out at 7, much lower than ANDI. */ - tcg_debug_assert(a_bits < 16); - tcg_out_opc_imm(s, OPC_ANDI, TCG_TMP0, addrlo, a_mask); + /* Load tlb_mask[mmu_idx] and tlb_table[mmu_idx]. */ + tcg_out_ld(s, TCG_TYPE_PTR, TCG_TMP0, TCG_AREG0, mask_off); + tcg_out_ld(s, TCG_TYPE_PTR, TCG_TMP1, TCG_AREG0, table_off); + + /* Extract the TLB index from the address into TMP3. */ + if (TCG_TARGET_REG_BITS == 32 || addr_type == TCG_TYPE_I32) { + tcg_out_opc_sa(s, OPC_SRL, TCG_TMP3, addrlo, + s->page_bits - CPU_TLB_ENTRY_BITS); + } else { + tcg_out_dsrl(s, TCG_TMP3, addrlo, + s->page_bits - CPU_TLB_ENTRY_BITS); + } + tcg_out_opc_reg(s, OPC_AND, TCG_TMP3, TCG_TMP3, TCG_TMP0); + + /* Add the tlb_table pointer, creating the CPUTLBEntry address. */ + tcg_out_opc_reg(s, ALIAS_PADD, TCG_TMP3, TCG_TMP3, TCG_TMP1); + + if (TCG_TARGET_REG_BITS == 32 || addr_type == TCG_TYPE_I32) { + /* Load the (low half) tlb comparator. */ + tcg_out_ld(s, TCG_TYPE_I32, TCG_TMP0, TCG_TMP3, + cmp_off + HOST_BIG_ENDIAN * 4); + } else { + tcg_out_ld(s, TCG_TYPE_I64, TCG_TMP0, TCG_TMP3, cmp_off); + } + + if (TCG_TARGET_REG_BITS == 64 || addr_type == TCG_TYPE_I32) { + /* Load the tlb addend for the fast path. */ + tcg_out_ld(s, TCG_TYPE_PTR, TCG_TMP3, TCG_TMP3, add_off); + } + + /* + * Mask the page bits, keeping the alignment bits to compare against. + * For unaligned accesses, compare against the end of the access to + * verify that it does not cross a page boundary. + */ + tcg_out_movi(s, addr_type, TCG_TMP1, s->page_mask | a_mask); + if (a_mask < s_mask) { + tcg_out_opc_imm(s, (TCG_TARGET_REG_BITS == 32 + || addr_type == TCG_TYPE_I32 + ? OPC_ADDIU : OPC_DADDIU), + TCG_TMP2, addrlo, s_mask - a_mask); + tcg_out_opc_reg(s, OPC_AND, TCG_TMP1, TCG_TMP1, TCG_TMP2); + } else { + tcg_out_opc_reg(s, OPC_AND, TCG_TMP1, TCG_TMP1, addrlo); + } + + /* Zero extend a 32-bit guest address for a 64-bit host. */ + if (TCG_TARGET_REG_BITS == 64 && addr_type == TCG_TYPE_I32) { + tcg_out_ext32u(s, TCG_TMP2, addrlo); + addrlo = TCG_TMP2; + } ldst->label_ptr[0] = s->code_ptr; - if (use_mips32r6_instructions) { - tcg_out_opc_br(s, OPC_BNEZALC_R6, TCG_REG_ZERO, TCG_TMP0); - } else { - tcg_out_opc_br(s, OPC_BNEL, TCG_TMP0, TCG_REG_ZERO); - tcg_out_nop(s); - } - } + tcg_out_opc_br(s, OPC_BNE, TCG_TMP1, TCG_TMP0); - base = addrlo; - if (TCG_TARGET_REG_BITS == 64 && addr_type == TCG_TYPE_I32) { - tcg_out_ext32u(s, TCG_REG_A0, base); - base = TCG_REG_A0; - } - if (guest_base) { - if (guest_base == (int16_t)guest_base) { - tcg_out_opc_imm(s, ALIAS_PADDI, TCG_REG_A0, base, guest_base); - } else { - tcg_out_opc_reg(s, ALIAS_PADD, TCG_REG_A0, base, - TCG_GUEST_BASE_REG); + /* Load and test the high half tlb comparator. */ + if (TCG_TARGET_REG_BITS == 32 && addr_type != TCG_TYPE_I32) { + /* delay slot */ + tcg_out_ldst(s, OPC_LW, TCG_TMP0, TCG_TMP3, cmp_off + HI_OFF); + + /* Load the tlb addend for the fast path. */ + tcg_out_ld(s, TCG_TYPE_PTR, TCG_TMP3, TCG_TMP3, add_off); + + ldst->label_ptr[1] = s->code_ptr; + tcg_out_opc_br(s, OPC_BNE, addrhi, TCG_TMP0); + } + + /* delay slot */ + base = TCG_TMP3; + tcg_out_opc_reg(s, ALIAS_PADD, base, TCG_TMP3, addrlo); + } else { + if (a_mask && (use_mips32r6_instructions || a_bits != s_bits)) { + ldst = new_ldst_label(s); + + ldst->is_ld = is_ld; + ldst->oi = oi; + ldst->addrlo_reg = addrlo; + ldst->addrhi_reg = addrhi; + + /* We are expecting a_bits to max out at 7, much lower than ANDI. */ + tcg_debug_assert(a_bits < 16); + tcg_out_opc_imm(s, OPC_ANDI, TCG_TMP0, addrlo, a_mask); + + ldst->label_ptr[0] = s->code_ptr; + if (use_mips32r6_instructions) { + tcg_out_opc_br(s, OPC_BNEZALC_R6, TCG_REG_ZERO, TCG_TMP0); + } else { + tcg_out_opc_br(s, OPC_BNEL, TCG_TMP0, TCG_REG_ZERO); + tcg_out_nop(s); + } + } + + base = addrlo; + if (TCG_TARGET_REG_BITS == 64 && addr_type == TCG_TYPE_I32) { + tcg_out_ext32u(s, TCG_REG_A0, base); + base = TCG_REG_A0; + } + if (guest_base) { + if (guest_base == (int16_t)guest_base) { + tcg_out_opc_imm(s, ALIAS_PADDI, TCG_REG_A0, base, guest_base); + } else { + tcg_out_opc_reg(s, ALIAS_PADD, TCG_REG_A0, base, + TCG_GUEST_BASE_REG); + } + base = TCG_REG_A0; } - base = TCG_REG_A0; } -#endif h->base = base; return ldst; @@ -2465,8 +2462,7 @@ static void tcg_target_qemu_prologue(TCGContext *s) TCG_REG_SP, SAVE_OFS + i * REG_SIZE); } -#ifndef CONFIG_SOFTMMU - if (guest_base != (int16_t)guest_base) { + if (!tcg_use_softmmu && guest_base != (int16_t)guest_base) { /* * The function call abi for n32 and n64 will have loaded $25 (t9) * with the address of the prologue, so we can use that instead @@ -2479,7 +2475,6 @@ static void tcg_target_qemu_prologue(TCGContext *s) TCG_TARGET_REG_BITS == 64 ? TCG_REG_T9 : 0); tcg_regset_set_reg(s->reserved_regs, TCG_GUEST_BASE_REG); } -#endif if (TCG_TARGET_REG_BITS == 64) { tcg_out_mov(s, TCG_TYPE_PTR, TCG_REG_TB, tcg_target_call_iarg_regs[1]); From 5b5bd4a9b1ddd724b5f12725fa186e75047dbfe1 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Sun, 1 Oct 2023 19:09:52 +0000 Subject: [PATCH 1060/1077] tcg/ppc: Use tcg_use_softmmu MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fix TCG_GUEST_BASE_REG to use 'TCG_REG_R30' instead of '30'. Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Richard Henderson --- tcg/ppc/tcg-target.c.inc | 284 ++++++++++++++++++++------------------- 1 file changed, 143 insertions(+), 141 deletions(-) diff --git a/tcg/ppc/tcg-target.c.inc b/tcg/ppc/tcg-target.c.inc index c31da4da9d..856c3b18f5 100644 --- a/tcg/ppc/tcg-target.c.inc +++ b/tcg/ppc/tcg-target.c.inc @@ -107,9 +107,7 @@ #define have_isel (cpuinfo & CPUINFO_ISEL) -#ifndef CONFIG_SOFTMMU -#define TCG_GUEST_BASE_REG 30 -#endif +#define TCG_GUEST_BASE_REG TCG_REG_R30 #ifdef CONFIG_DEBUG_TCG static const char tcg_target_reg_names[TCG_TARGET_NB_REGS][4] = { @@ -2317,151 +2315,157 @@ static TCGLabelQemuLdst *prepare_host_addr(TCGContext *s, HostAddress *h, s_bits == MO_128); a_bits = h->aa.align; -#ifdef CONFIG_SOFTMMU - int mem_index = get_mmuidx(oi); - int cmp_off = is_ld ? offsetof(CPUTLBEntry, addr_read) - : offsetof(CPUTLBEntry, addr_write); - int fast_off = tlb_mask_table_ofs(s, mem_index); - int mask_off = fast_off + offsetof(CPUTLBDescFast, mask); - int table_off = fast_off + offsetof(CPUTLBDescFast, table); + if (tcg_use_softmmu) { + int mem_index = get_mmuidx(oi); + int cmp_off = is_ld ? offsetof(CPUTLBEntry, addr_read) + : offsetof(CPUTLBEntry, addr_write); + int fast_off = tlb_mask_table_ofs(s, mem_index); + int mask_off = fast_off + offsetof(CPUTLBDescFast, mask); + int table_off = fast_off + offsetof(CPUTLBDescFast, table); - ldst = new_ldst_label(s); - ldst->is_ld = is_ld; - ldst->oi = oi; - ldst->addrlo_reg = addrlo; - ldst->addrhi_reg = addrhi; - - /* Load tlb_mask[mmu_idx] and tlb_table[mmu_idx]. */ - tcg_out_ld(s, TCG_TYPE_PTR, TCG_REG_TMP1, TCG_AREG0, mask_off); - tcg_out_ld(s, TCG_TYPE_PTR, TCG_REG_TMP2, TCG_AREG0, table_off); - - /* Extract the page index, shifted into place for tlb index. */ - if (TCG_TARGET_REG_BITS == 32) { - tcg_out_shri32(s, TCG_REG_R0, addrlo, - s->page_bits - CPU_TLB_ENTRY_BITS); - } else { - tcg_out_shri64(s, TCG_REG_R0, addrlo, - s->page_bits - CPU_TLB_ENTRY_BITS); - } - tcg_out32(s, AND | SAB(TCG_REG_TMP1, TCG_REG_TMP1, TCG_REG_R0)); - - /* - * Load the (low part) TLB comparator into TMP2. - * For 64-bit host, always load the entire 64-bit slot for simplicity. - * We will ignore the high bits with tcg_out_cmp(..., addr_type). - */ - if (TCG_TARGET_REG_BITS == 64) { - if (cmp_off == 0) { - tcg_out32(s, LDUX | TAB(TCG_REG_TMP2, TCG_REG_TMP1, TCG_REG_TMP2)); - } else { - tcg_out32(s, ADD | TAB(TCG_REG_TMP1, TCG_REG_TMP1, TCG_REG_TMP2)); - tcg_out_ld(s, TCG_TYPE_I64, TCG_REG_TMP2, TCG_REG_TMP1, cmp_off); - } - } else if (cmp_off == 0 && !HOST_BIG_ENDIAN) { - tcg_out32(s, LWZUX | TAB(TCG_REG_TMP2, TCG_REG_TMP1, TCG_REG_TMP2)); - } else { - tcg_out32(s, ADD | TAB(TCG_REG_TMP1, TCG_REG_TMP1, TCG_REG_TMP2)); - tcg_out_ld(s, TCG_TYPE_I32, TCG_REG_TMP2, TCG_REG_TMP1, - cmp_off + 4 * HOST_BIG_ENDIAN); - } - - /* - * Load the TLB addend for use on the fast path. - * Do this asap to minimize any load use delay. - */ - if (TCG_TARGET_REG_BITS == 64 || addr_type == TCG_TYPE_I32) { - tcg_out_ld(s, TCG_TYPE_PTR, TCG_REG_TMP1, TCG_REG_TMP1, - offsetof(CPUTLBEntry, addend)); - } - - /* Clear the non-page, non-alignment bits from the address in R0. */ - if (TCG_TARGET_REG_BITS == 32) { - /* - * We don't support unaligned accesses on 32-bits. - * Preserve the bottom bits and thus trigger a comparison - * failure on unaligned accesses. - */ - if (a_bits < s_bits) { - a_bits = s_bits; - } - tcg_out_rlw(s, RLWINM, TCG_REG_R0, addrlo, 0, - (32 - a_bits) & 31, 31 - s->page_bits); - } else { - TCGReg t = addrlo; - - /* - * If the access is unaligned, we need to make sure we fail if we - * cross a page boundary. The trick is to add the access size-1 - * to the address before masking the low bits. That will make the - * address overflow to the next page if we cross a page boundary, - * which will then force a mismatch of the TLB compare. - */ - if (a_bits < s_bits) { - unsigned a_mask = (1 << a_bits) - 1; - unsigned s_mask = (1 << s_bits) - 1; - tcg_out32(s, ADDI | TAI(TCG_REG_R0, t, s_mask - a_mask)); - t = TCG_REG_R0; - } - - /* Mask the address for the requested alignment. */ - if (addr_type == TCG_TYPE_I32) { - tcg_out_rlw(s, RLWINM, TCG_REG_R0, t, 0, - (32 - a_bits) & 31, 31 - s->page_bits); - } else if (a_bits == 0) { - tcg_out_rld(s, RLDICR, TCG_REG_R0, t, 0, 63 - s->page_bits); - } else { - tcg_out_rld(s, RLDICL, TCG_REG_R0, t, - 64 - s->page_bits, s->page_bits - a_bits); - tcg_out_rld(s, RLDICL, TCG_REG_R0, TCG_REG_R0, s->page_bits, 0); - } - } - - if (TCG_TARGET_REG_BITS == 32 && addr_type != TCG_TYPE_I32) { - /* Low part comparison into cr7. */ - tcg_out_cmp(s, TCG_COND_EQ, TCG_REG_R0, TCG_REG_TMP2, - 0, 7, TCG_TYPE_I32); - - /* Load the high part TLB comparator into TMP2. */ - tcg_out_ld(s, TCG_TYPE_I32, TCG_REG_TMP2, TCG_REG_TMP1, - cmp_off + 4 * !HOST_BIG_ENDIAN); - - /* Load addend, deferred for this case. */ - tcg_out_ld(s, TCG_TYPE_PTR, TCG_REG_TMP1, TCG_REG_TMP1, - offsetof(CPUTLBEntry, addend)); - - /* High part comparison into cr6. */ - tcg_out_cmp(s, TCG_COND_EQ, addrhi, TCG_REG_TMP2, 0, 6, TCG_TYPE_I32); - - /* Combine comparisons into cr7. */ - tcg_out32(s, CRAND | BT(7, CR_EQ) | BA(6, CR_EQ) | BB(7, CR_EQ)); - } else { - /* Full comparison into cr7. */ - tcg_out_cmp(s, TCG_COND_EQ, TCG_REG_R0, TCG_REG_TMP2, 0, 7, addr_type); - } - - /* Load a pointer into the current opcode w/conditional branch-link. */ - ldst->label_ptr[0] = s->code_ptr; - tcg_out32(s, BC | BI(7, CR_EQ) | BO_COND_FALSE | LK); - - h->base = TCG_REG_TMP1; -#else - if (a_bits) { ldst = new_ldst_label(s); ldst->is_ld = is_ld; ldst->oi = oi; ldst->addrlo_reg = addrlo; ldst->addrhi_reg = addrhi; - /* We are expecting a_bits to max out at 7, much lower than ANDI. */ - tcg_debug_assert(a_bits < 16); - tcg_out32(s, ANDI | SAI(addrlo, TCG_REG_R0, (1 << a_bits) - 1)); + /* Load tlb_mask[mmu_idx] and tlb_table[mmu_idx]. */ + tcg_out_ld(s, TCG_TYPE_PTR, TCG_REG_TMP1, TCG_AREG0, mask_off); + tcg_out_ld(s, TCG_TYPE_PTR, TCG_REG_TMP2, TCG_AREG0, table_off); + /* Extract the page index, shifted into place for tlb index. */ + if (TCG_TARGET_REG_BITS == 32) { + tcg_out_shri32(s, TCG_REG_R0, addrlo, + s->page_bits - CPU_TLB_ENTRY_BITS); + } else { + tcg_out_shri64(s, TCG_REG_R0, addrlo, + s->page_bits - CPU_TLB_ENTRY_BITS); + } + tcg_out32(s, AND | SAB(TCG_REG_TMP1, TCG_REG_TMP1, TCG_REG_R0)); + + /* + * Load the (low part) TLB comparator into TMP2. + * For 64-bit host, always load the entire 64-bit slot for simplicity. + * We will ignore the high bits with tcg_out_cmp(..., addr_type). + */ + if (TCG_TARGET_REG_BITS == 64) { + if (cmp_off == 0) { + tcg_out32(s, LDUX | TAB(TCG_REG_TMP2, + TCG_REG_TMP1, TCG_REG_TMP2)); + } else { + tcg_out32(s, ADD | TAB(TCG_REG_TMP1, + TCG_REG_TMP1, TCG_REG_TMP2)); + tcg_out_ld(s, TCG_TYPE_I64, TCG_REG_TMP2, + TCG_REG_TMP1, cmp_off); + } + } else if (cmp_off == 0 && !HOST_BIG_ENDIAN) { + tcg_out32(s, LWZUX | TAB(TCG_REG_TMP2, + TCG_REG_TMP1, TCG_REG_TMP2)); + } else { + tcg_out32(s, ADD | TAB(TCG_REG_TMP1, TCG_REG_TMP1, TCG_REG_TMP2)); + tcg_out_ld(s, TCG_TYPE_I32, TCG_REG_TMP2, TCG_REG_TMP1, + cmp_off + 4 * HOST_BIG_ENDIAN); + } + + /* + * Load the TLB addend for use on the fast path. + * Do this asap to minimize any load use delay. + */ + if (TCG_TARGET_REG_BITS == 64 || addr_type == TCG_TYPE_I32) { + tcg_out_ld(s, TCG_TYPE_PTR, TCG_REG_TMP1, TCG_REG_TMP1, + offsetof(CPUTLBEntry, addend)); + } + + /* Clear the non-page, non-alignment bits from the address in R0. */ + if (TCG_TARGET_REG_BITS == 32) { + /* + * We don't support unaligned accesses on 32-bits. + * Preserve the bottom bits and thus trigger a comparison + * failure on unaligned accesses. + */ + if (a_bits < s_bits) { + a_bits = s_bits; + } + tcg_out_rlw(s, RLWINM, TCG_REG_R0, addrlo, 0, + (32 - a_bits) & 31, 31 - s->page_bits); + } else { + TCGReg t = addrlo; + + /* + * If the access is unaligned, we need to make sure we fail if we + * cross a page boundary. The trick is to add the access size-1 + * to the address before masking the low bits. That will make the + * address overflow to the next page if we cross a page boundary, + * which will then force a mismatch of the TLB compare. + */ + if (a_bits < s_bits) { + unsigned a_mask = (1 << a_bits) - 1; + unsigned s_mask = (1 << s_bits) - 1; + tcg_out32(s, ADDI | TAI(TCG_REG_R0, t, s_mask - a_mask)); + t = TCG_REG_R0; + } + + /* Mask the address for the requested alignment. */ + if (addr_type == TCG_TYPE_I32) { + tcg_out_rlw(s, RLWINM, TCG_REG_R0, t, 0, + (32 - a_bits) & 31, 31 - s->page_bits); + } else if (a_bits == 0) { + tcg_out_rld(s, RLDICR, TCG_REG_R0, t, 0, 63 - s->page_bits); + } else { + tcg_out_rld(s, RLDICL, TCG_REG_R0, t, + 64 - s->page_bits, s->page_bits - a_bits); + tcg_out_rld(s, RLDICL, TCG_REG_R0, TCG_REG_R0, s->page_bits, 0); + } + } + + if (TCG_TARGET_REG_BITS == 32 && addr_type != TCG_TYPE_I32) { + /* Low part comparison into cr7. */ + tcg_out_cmp(s, TCG_COND_EQ, TCG_REG_R0, TCG_REG_TMP2, + 0, 7, TCG_TYPE_I32); + + /* Load the high part TLB comparator into TMP2. */ + tcg_out_ld(s, TCG_TYPE_I32, TCG_REG_TMP2, TCG_REG_TMP1, + cmp_off + 4 * !HOST_BIG_ENDIAN); + + /* Load addend, deferred for this case. */ + tcg_out_ld(s, TCG_TYPE_PTR, TCG_REG_TMP1, TCG_REG_TMP1, + offsetof(CPUTLBEntry, addend)); + + /* High part comparison into cr6. */ + tcg_out_cmp(s, TCG_COND_EQ, addrhi, TCG_REG_TMP2, + 0, 6, TCG_TYPE_I32); + + /* Combine comparisons into cr7. */ + tcg_out32(s, CRAND | BT(7, CR_EQ) | BA(6, CR_EQ) | BB(7, CR_EQ)); + } else { + /* Full comparison into cr7. */ + tcg_out_cmp(s, TCG_COND_EQ, TCG_REG_R0, TCG_REG_TMP2, + 0, 7, addr_type); + } + + /* Load a pointer into the current opcode w/conditional branch-link. */ ldst->label_ptr[0] = s->code_ptr; - tcg_out32(s, BC | BI(0, CR_EQ) | BO_COND_FALSE | LK); - } + tcg_out32(s, BC | BI(7, CR_EQ) | BO_COND_FALSE | LK); - h->base = guest_base ? TCG_GUEST_BASE_REG : 0; -#endif + h->base = TCG_REG_TMP1; + } else { + if (a_bits) { + ldst = new_ldst_label(s); + ldst->is_ld = is_ld; + ldst->oi = oi; + ldst->addrlo_reg = addrlo; + ldst->addrhi_reg = addrhi; + + /* We are expecting a_bits to max out at 7, much lower than ANDI. */ + tcg_debug_assert(a_bits < 16); + tcg_out32(s, ANDI | SAI(addrlo, TCG_REG_R0, (1 << a_bits) - 1)); + + ldst->label_ptr[0] = s->code_ptr; + tcg_out32(s, BC | BI(0, CR_EQ) | BO_COND_FALSE | LK); + } + + h->base = guest_base ? TCG_GUEST_BASE_REG : 0; + } if (TCG_TARGET_REG_BITS == 64 && addr_type == TCG_TYPE_I32) { /* Zero-extend the guest address for use in the host address. */ @@ -2695,12 +2699,10 @@ static void tcg_target_qemu_prologue(TCGContext *s) } tcg_out_st(s, TCG_TYPE_PTR, TCG_REG_R0, TCG_REG_R1, FRAME_SIZE+LR_OFFSET); -#ifndef CONFIG_SOFTMMU - if (guest_base) { + if (!tcg_use_softmmu && guest_base) { tcg_out_movi_int(s, TCG_TYPE_PTR, TCG_GUEST_BASE_REG, guest_base, true); tcg_regset_set_reg(s->reserved_regs, TCG_GUEST_BASE_REG); } -#endif tcg_out_mov(s, TCG_TYPE_PTR, TCG_AREG0, tcg_target_call_iarg_regs[0]); tcg_out32(s, MTSPR | RS(tcg_target_call_iarg_regs[1]) | CTR); From cf0ed30eb10c7341fd1f253446e3bbb6e0114c30 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Thu, 12 Oct 2023 20:45:36 -0700 Subject: [PATCH 1061/1077] tcg/riscv: Do not reserve TCG_GUEST_BASE_REG for guest_base zero Fixes: 92c041c59b ("tcg/riscv: Add the prologue generation and register the JIT") Signed-off-by: Richard Henderson --- tcg/riscv/tcg-target.c.inc | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/tcg/riscv/tcg-target.c.inc b/tcg/riscv/tcg-target.c.inc index d6dbcaf3cb..dc71f829d1 100644 --- a/tcg/riscv/tcg-target.c.inc +++ b/tcg/riscv/tcg-target.c.inc @@ -2076,8 +2076,10 @@ static void tcg_target_qemu_prologue(TCGContext *s) } #if !defined(CONFIG_SOFTMMU) - tcg_out_movi(s, TCG_TYPE_PTR, TCG_GUEST_BASE_REG, guest_base); - tcg_regset_set_reg(s->reserved_regs, TCG_GUEST_BASE_REG); + if (guest_base) { + tcg_out_movi(s, TCG_TYPE_PTR, TCG_GUEST_BASE_REG, guest_base); + tcg_regset_set_reg(s->reserved_regs, TCG_GUEST_BASE_REG); + } #endif /* Call generated code */ From 4944d359107fa3e88200697daef28e3b5878daa6 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Sun, 1 Oct 2023 12:35:44 -0700 Subject: [PATCH 1062/1077] tcg/riscv: Use tcg_use_softmmu Signed-off-by: Richard Henderson --- tcg/riscv/tcg-target.c.inc | 185 +++++++++++++++++++------------------ 1 file changed, 94 insertions(+), 91 deletions(-) diff --git a/tcg/riscv/tcg-target.c.inc b/tcg/riscv/tcg-target.c.inc index dc71f829d1..34e10e77d9 100644 --- a/tcg/riscv/tcg-target.c.inc +++ b/tcg/riscv/tcg-target.c.inc @@ -1245,105 +1245,110 @@ static TCGLabelQemuLdst *prepare_host_addr(TCGContext *s, TCGReg *pbase, aa = atom_and_align_for_opc(s, opc, MO_ATOM_IFALIGN, false); a_mask = (1u << aa.align) - 1; -#ifdef CONFIG_SOFTMMU - unsigned s_bits = opc & MO_SIZE; - unsigned s_mask = (1u << s_bits) - 1; - int mem_index = get_mmuidx(oi); - int fast_ofs = tlb_mask_table_ofs(s, mem_index); - int mask_ofs = fast_ofs + offsetof(CPUTLBDescFast, mask); - int table_ofs = fast_ofs + offsetof(CPUTLBDescFast, table); - int compare_mask; - TCGReg addr_adj; + if (tcg_use_softmmu) { + unsigned s_bits = opc & MO_SIZE; + unsigned s_mask = (1u << s_bits) - 1; + int mem_index = get_mmuidx(oi); + int fast_ofs = tlb_mask_table_ofs(s, mem_index); + int mask_ofs = fast_ofs + offsetof(CPUTLBDescFast, mask); + int table_ofs = fast_ofs + offsetof(CPUTLBDescFast, table); + int compare_mask; + TCGReg addr_adj; - ldst = new_ldst_label(s); - ldst->is_ld = is_ld; - ldst->oi = oi; - ldst->addrlo_reg = addr_reg; - - tcg_out_ld(s, TCG_TYPE_PTR, TCG_REG_TMP0, TCG_AREG0, mask_ofs); - tcg_out_ld(s, TCG_TYPE_PTR, TCG_REG_TMP1, TCG_AREG0, table_ofs); - - tcg_out_opc_imm(s, OPC_SRLI, TCG_REG_TMP2, addr_reg, - s->page_bits - CPU_TLB_ENTRY_BITS); - tcg_out_opc_reg(s, OPC_AND, TCG_REG_TMP2, TCG_REG_TMP2, TCG_REG_TMP0); - tcg_out_opc_reg(s, OPC_ADD, TCG_REG_TMP2, TCG_REG_TMP2, TCG_REG_TMP1); - - /* - * For aligned accesses, we check the first byte and include the alignment - * bits within the address. For unaligned access, we check that we don't - * cross pages using the address of the last byte of the access. - */ - addr_adj = addr_reg; - if (a_mask < s_mask) { - addr_adj = TCG_REG_TMP0; - tcg_out_opc_imm(s, addr_type == TCG_TYPE_I32 ? OPC_ADDIW : OPC_ADDI, - addr_adj, addr_reg, s_mask - a_mask); - } - compare_mask = s->page_mask | a_mask; - if (compare_mask == sextreg(compare_mask, 0, 12)) { - tcg_out_opc_imm(s, OPC_ANDI, TCG_REG_TMP1, addr_adj, compare_mask); - } else { - tcg_out_movi(s, addr_type, TCG_REG_TMP1, compare_mask); - tcg_out_opc_reg(s, OPC_AND, TCG_REG_TMP1, TCG_REG_TMP1, addr_adj); - } - - /* Load the tlb comparator and the addend. */ - QEMU_BUILD_BUG_ON(HOST_BIG_ENDIAN); - tcg_out_ld(s, addr_type, TCG_REG_TMP0, TCG_REG_TMP2, - is_ld ? offsetof(CPUTLBEntry, addr_read) - : offsetof(CPUTLBEntry, addr_write)); - tcg_out_ld(s, TCG_TYPE_PTR, TCG_REG_TMP2, TCG_REG_TMP2, - offsetof(CPUTLBEntry, addend)); - - /* Compare masked address with the TLB entry. */ - ldst->label_ptr[0] = s->code_ptr; - tcg_out_opc_branch(s, OPC_BNE, TCG_REG_TMP0, TCG_REG_TMP1, 0); - - /* TLB Hit - translate address using addend. */ - if (addr_type != TCG_TYPE_I32) { - tcg_out_opc_reg(s, OPC_ADD, TCG_REG_TMP0, addr_reg, TCG_REG_TMP2); - } else if (have_zba) { - tcg_out_opc_reg(s, OPC_ADD_UW, TCG_REG_TMP0, addr_reg, TCG_REG_TMP2); - } else { - tcg_out_ext32u(s, TCG_REG_TMP0, addr_reg); - tcg_out_opc_reg(s, OPC_ADD, TCG_REG_TMP0, TCG_REG_TMP0, TCG_REG_TMP2); - } - *pbase = TCG_REG_TMP0; -#else - TCGReg base; - - if (a_mask) { ldst = new_ldst_label(s); ldst->is_ld = is_ld; ldst->oi = oi; ldst->addrlo_reg = addr_reg; - /* We are expecting alignment max 7, so we can always use andi. */ - tcg_debug_assert(a_mask == sextreg(a_mask, 0, 12)); - tcg_out_opc_imm(s, OPC_ANDI, TCG_REG_TMP1, addr_reg, a_mask); + tcg_out_ld(s, TCG_TYPE_PTR, TCG_REG_TMP0, TCG_AREG0, mask_ofs); + tcg_out_ld(s, TCG_TYPE_PTR, TCG_REG_TMP1, TCG_AREG0, table_ofs); - ldst->label_ptr[0] = s->code_ptr; - tcg_out_opc_branch(s, OPC_BNE, TCG_REG_TMP1, TCG_REG_ZERO, 0); - } + tcg_out_opc_imm(s, OPC_SRLI, TCG_REG_TMP2, addr_reg, + s->page_bits - CPU_TLB_ENTRY_BITS); + tcg_out_opc_reg(s, OPC_AND, TCG_REG_TMP2, TCG_REG_TMP2, TCG_REG_TMP0); + tcg_out_opc_reg(s, OPC_ADD, TCG_REG_TMP2, TCG_REG_TMP2, TCG_REG_TMP1); - if (guest_base != 0) { - base = TCG_REG_TMP0; - if (addr_type != TCG_TYPE_I32) { - tcg_out_opc_reg(s, OPC_ADD, base, addr_reg, TCG_GUEST_BASE_REG); - } else if (have_zba) { - tcg_out_opc_reg(s, OPC_ADD_UW, base, addr_reg, TCG_GUEST_BASE_REG); - } else { - tcg_out_ext32u(s, base, addr_reg); - tcg_out_opc_reg(s, OPC_ADD, base, base, TCG_GUEST_BASE_REG); + /* + * For aligned accesses, we check the first byte and include the + * alignment bits within the address. For unaligned access, we + * check that we don't cross pages using the address of the last + * byte of the access. + */ + addr_adj = addr_reg; + if (a_mask < s_mask) { + addr_adj = TCG_REG_TMP0; + tcg_out_opc_imm(s, addr_type == TCG_TYPE_I32 ? OPC_ADDIW : OPC_ADDI, + addr_adj, addr_reg, s_mask - a_mask); } - } else if (addr_type != TCG_TYPE_I32) { - base = addr_reg; + compare_mask = s->page_mask | a_mask; + if (compare_mask == sextreg(compare_mask, 0, 12)) { + tcg_out_opc_imm(s, OPC_ANDI, TCG_REG_TMP1, addr_adj, compare_mask); + } else { + tcg_out_movi(s, addr_type, TCG_REG_TMP1, compare_mask); + tcg_out_opc_reg(s, OPC_AND, TCG_REG_TMP1, TCG_REG_TMP1, addr_adj); + } + + /* Load the tlb comparator and the addend. */ + QEMU_BUILD_BUG_ON(HOST_BIG_ENDIAN); + tcg_out_ld(s, addr_type, TCG_REG_TMP0, TCG_REG_TMP2, + is_ld ? offsetof(CPUTLBEntry, addr_read) + : offsetof(CPUTLBEntry, addr_write)); + tcg_out_ld(s, TCG_TYPE_PTR, TCG_REG_TMP2, TCG_REG_TMP2, + offsetof(CPUTLBEntry, addend)); + + /* Compare masked address with the TLB entry. */ + ldst->label_ptr[0] = s->code_ptr; + tcg_out_opc_branch(s, OPC_BNE, TCG_REG_TMP0, TCG_REG_TMP1, 0); + + /* TLB Hit - translate address using addend. */ + if (addr_type != TCG_TYPE_I32) { + tcg_out_opc_reg(s, OPC_ADD, TCG_REG_TMP0, addr_reg, TCG_REG_TMP2); + } else if (have_zba) { + tcg_out_opc_reg(s, OPC_ADD_UW, TCG_REG_TMP0, + addr_reg, TCG_REG_TMP2); + } else { + tcg_out_ext32u(s, TCG_REG_TMP0, addr_reg); + tcg_out_opc_reg(s, OPC_ADD, TCG_REG_TMP0, + TCG_REG_TMP0, TCG_REG_TMP2); + } + *pbase = TCG_REG_TMP0; } else { - base = TCG_REG_TMP0; - tcg_out_ext32u(s, base, addr_reg); + TCGReg base; + + if (a_mask) { + ldst = new_ldst_label(s); + ldst->is_ld = is_ld; + ldst->oi = oi; + ldst->addrlo_reg = addr_reg; + + /* We are expecting alignment max 7, so we can always use andi. */ + tcg_debug_assert(a_mask == sextreg(a_mask, 0, 12)); + tcg_out_opc_imm(s, OPC_ANDI, TCG_REG_TMP1, addr_reg, a_mask); + + ldst->label_ptr[0] = s->code_ptr; + tcg_out_opc_branch(s, OPC_BNE, TCG_REG_TMP1, TCG_REG_ZERO, 0); + } + + if (guest_base != 0) { + base = TCG_REG_TMP0; + if (addr_type != TCG_TYPE_I32) { + tcg_out_opc_reg(s, OPC_ADD, base, addr_reg, + TCG_GUEST_BASE_REG); + } else if (have_zba) { + tcg_out_opc_reg(s, OPC_ADD_UW, base, addr_reg, + TCG_GUEST_BASE_REG); + } else { + tcg_out_ext32u(s, base, addr_reg); + tcg_out_opc_reg(s, OPC_ADD, base, base, TCG_GUEST_BASE_REG); + } + } else if (addr_type != TCG_TYPE_I32) { + base = addr_reg; + } else { + base = TCG_REG_TMP0; + tcg_out_ext32u(s, base, addr_reg); + } + *pbase = base; } - *pbase = base; -#endif return ldst; } @@ -2075,12 +2080,10 @@ static void tcg_target_qemu_prologue(TCGContext *s) TCG_REG_SP, SAVE_OFS + i * REG_SIZE); } -#if !defined(CONFIG_SOFTMMU) - if (guest_base) { + if (!tcg_use_softmmu && guest_base) { tcg_out_movi(s, TCG_TYPE_PTR, TCG_GUEST_BASE_REG, guest_base); tcg_regset_set_reg(s->reserved_regs, TCG_GUEST_BASE_REG); } -#endif /* Call generated code */ tcg_out_mov(s, TCG_TYPE_PTR, TCG_AREG0, tcg_target_call_iarg_regs[0]); From 2e486b5901986134863487352df961331a2b56c2 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Sun, 1 Oct 2023 21:16:32 +0000 Subject: [PATCH 1063/1077] tcg/s390x: Use tcg_use_softmmu MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Richard Henderson --- tcg/s390x/tcg-target.c.inc | 161 ++++++++++++++++++------------------- 1 file changed, 79 insertions(+), 82 deletions(-) diff --git a/tcg/s390x/tcg-target.c.inc b/tcg/s390x/tcg-target.c.inc index 4ef9ac3d5b..fbee43d3b0 100644 --- a/tcg/s390x/tcg-target.c.inc +++ b/tcg/s390x/tcg-target.c.inc @@ -46,9 +46,7 @@ /* A scratch register that may be be used throughout the backend. */ #define TCG_TMP0 TCG_REG_R1 -#ifndef CONFIG_SOFTMMU #define TCG_GUEST_BASE_REG TCG_REG_R13 -#endif /* All of the following instructions are prefixed with their instruction format, and are defined as 8- or 16-bit quantities, even when the two @@ -1768,94 +1766,95 @@ static TCGLabelQemuLdst *prepare_host_addr(TCGContext *s, HostAddress *h, h->aa = atom_and_align_for_opc(s, opc, MO_ATOM_IFALIGN, s_bits == MO_128); a_mask = (1 << h->aa.align) - 1; -#ifdef CONFIG_SOFTMMU - unsigned s_mask = (1 << s_bits) - 1; - int mem_index = get_mmuidx(oi); - int fast_off = tlb_mask_table_ofs(s, mem_index); - int mask_off = fast_off + offsetof(CPUTLBDescFast, mask); - int table_off = fast_off + offsetof(CPUTLBDescFast, table); - int ofs, a_off; - uint64_t tlb_mask; + if (tcg_use_softmmu) { + unsigned s_mask = (1 << s_bits) - 1; + int mem_index = get_mmuidx(oi); + int fast_off = tlb_mask_table_ofs(s, mem_index); + int mask_off = fast_off + offsetof(CPUTLBDescFast, mask); + int table_off = fast_off + offsetof(CPUTLBDescFast, table); + int ofs, a_off; + uint64_t tlb_mask; - ldst = new_ldst_label(s); - ldst->is_ld = is_ld; - ldst->oi = oi; - ldst->addrlo_reg = addr_reg; - - tcg_out_sh64(s, RSY_SRLG, TCG_TMP0, addr_reg, TCG_REG_NONE, - s->page_bits - CPU_TLB_ENTRY_BITS); - - tcg_out_insn(s, RXY, NG, TCG_TMP0, TCG_AREG0, TCG_REG_NONE, mask_off); - tcg_out_insn(s, RXY, AG, TCG_TMP0, TCG_AREG0, TCG_REG_NONE, table_off); - - /* - * For aligned accesses, we check the first byte and include the alignment - * bits within the address. For unaligned access, we check that we don't - * cross pages using the address of the last byte of the access. - */ - a_off = (a_mask >= s_mask ? 0 : s_mask - a_mask); - tlb_mask = (uint64_t)s->page_mask | a_mask; - if (a_off == 0) { - tgen_andi_risbg(s, TCG_REG_R0, addr_reg, tlb_mask); - } else { - tcg_out_insn(s, RX, LA, TCG_REG_R0, addr_reg, TCG_REG_NONE, a_off); - tgen_andi(s, addr_type, TCG_REG_R0, tlb_mask); - } - - if (is_ld) { - ofs = offsetof(CPUTLBEntry, addr_read); - } else { - ofs = offsetof(CPUTLBEntry, addr_write); - } - if (addr_type == TCG_TYPE_I32) { - ofs += HOST_BIG_ENDIAN * 4; - tcg_out_insn(s, RX, C, TCG_REG_R0, TCG_TMP0, TCG_REG_NONE, ofs); - } else { - tcg_out_insn(s, RXY, CG, TCG_REG_R0, TCG_TMP0, TCG_REG_NONE, ofs); - } - - tcg_out16(s, RI_BRC | (S390_CC_NE << 4)); - ldst->label_ptr[0] = s->code_ptr++; - - h->index = TCG_TMP0; - tcg_out_insn(s, RXY, LG, h->index, TCG_TMP0, TCG_REG_NONE, - offsetof(CPUTLBEntry, addend)); - - if (addr_type == TCG_TYPE_I32) { - tcg_out_insn(s, RRE, ALGFR, h->index, addr_reg); - h->base = TCG_REG_NONE; - } else { - h->base = addr_reg; - } - h->disp = 0; -#else - if (a_mask) { ldst = new_ldst_label(s); ldst->is_ld = is_ld; ldst->oi = oi; ldst->addrlo_reg = addr_reg; - /* We are expecting a_bits to max out at 7, much lower than TMLL. */ - tcg_debug_assert(a_mask <= 0xffff); - tcg_out_insn(s, RI, TMLL, addr_reg, a_mask); + tcg_out_sh64(s, RSY_SRLG, TCG_TMP0, addr_reg, TCG_REG_NONE, + s->page_bits - CPU_TLB_ENTRY_BITS); - tcg_out16(s, RI_BRC | (7 << 4)); /* CC in {1,2,3} */ + tcg_out_insn(s, RXY, NG, TCG_TMP0, TCG_AREG0, TCG_REG_NONE, mask_off); + tcg_out_insn(s, RXY, AG, TCG_TMP0, TCG_AREG0, TCG_REG_NONE, table_off); + + /* + * For aligned accesses, we check the first byte and include the + * alignment bits within the address. For unaligned access, we + * check that we don't cross pages using the address of the last + * byte of the access. + */ + a_off = (a_mask >= s_mask ? 0 : s_mask - a_mask); + tlb_mask = (uint64_t)s->page_mask | a_mask; + if (a_off == 0) { + tgen_andi_risbg(s, TCG_REG_R0, addr_reg, tlb_mask); + } else { + tcg_out_insn(s, RX, LA, TCG_REG_R0, addr_reg, TCG_REG_NONE, a_off); + tgen_andi(s, addr_type, TCG_REG_R0, tlb_mask); + } + + if (is_ld) { + ofs = offsetof(CPUTLBEntry, addr_read); + } else { + ofs = offsetof(CPUTLBEntry, addr_write); + } + if (addr_type == TCG_TYPE_I32) { + ofs += HOST_BIG_ENDIAN * 4; + tcg_out_insn(s, RX, C, TCG_REG_R0, TCG_TMP0, TCG_REG_NONE, ofs); + } else { + tcg_out_insn(s, RXY, CG, TCG_REG_R0, TCG_TMP0, TCG_REG_NONE, ofs); + } + + tcg_out16(s, RI_BRC | (S390_CC_NE << 4)); ldst->label_ptr[0] = s->code_ptr++; - } - h->base = addr_reg; - if (addr_type == TCG_TYPE_I32) { - tcg_out_ext32u(s, TCG_TMP0, addr_reg); - h->base = TCG_TMP0; - } - if (guest_base < 0x80000) { - h->index = TCG_REG_NONE; - h->disp = guest_base; - } else { - h->index = TCG_GUEST_BASE_REG; + h->index = TCG_TMP0; + tcg_out_insn(s, RXY, LG, h->index, TCG_TMP0, TCG_REG_NONE, + offsetof(CPUTLBEntry, addend)); + + if (addr_type == TCG_TYPE_I32) { + tcg_out_insn(s, RRE, ALGFR, h->index, addr_reg); + h->base = TCG_REG_NONE; + } else { + h->base = addr_reg; + } h->disp = 0; + } else { + if (a_mask) { + ldst = new_ldst_label(s); + ldst->is_ld = is_ld; + ldst->oi = oi; + ldst->addrlo_reg = addr_reg; + + /* We are expecting a_bits to max out at 7, much lower than TMLL. */ + tcg_debug_assert(a_mask <= 0xffff); + tcg_out_insn(s, RI, TMLL, addr_reg, a_mask); + + tcg_out16(s, RI_BRC | (7 << 4)); /* CC in {1,2,3} */ + ldst->label_ptr[0] = s->code_ptr++; + } + + h->base = addr_reg; + if (addr_type == TCG_TYPE_I32) { + tcg_out_ext32u(s, TCG_TMP0, addr_reg); + h->base = TCG_TMP0; + } + if (guest_base < 0x80000) { + h->index = TCG_REG_NONE; + h->disp = guest_base; + } else { + h->index = TCG_GUEST_BASE_REG; + h->disp = 0; + } } -#endif return ldst; } @@ -3453,12 +3452,10 @@ static void tcg_target_qemu_prologue(TCGContext *s) TCG_STATIC_CALL_ARGS_SIZE + TCG_TARGET_CALL_STACK_OFFSET, CPU_TEMP_BUF_NLONGS * sizeof(long)); -#ifndef CONFIG_SOFTMMU - if (guest_base >= 0x80000) { + if (!tcg_use_softmmu && guest_base >= 0x80000) { tcg_out_movi(s, TCG_TYPE_PTR, TCG_GUEST_BASE_REG, guest_base); tcg_regset_set_reg(s->reserved_regs, TCG_GUEST_BASE_REG); } -#endif tcg_out_mov(s, TCG_TYPE_PTR, TCG_AREG0, tcg_target_call_iarg_regs[0]); From 40f40fc8f09edd8db620786a16a927e711257ff2 Mon Sep 17 00:00:00 2001 From: Mike Frysinger Date: Sun, 15 Oct 2023 06:45:46 +0545 Subject: [PATCH 1064/1077] tcg: drop unused tcg_temp_free define MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use of the API was removed a while back, but the define wasn't. Signed-off-by: Mike Frysinger Reviewed-by: Philippe Mathieu-Daudé Message-Id: <20231015010046.16020-1-vapier@gentoo.org> Signed-off-by: Richard Henderson --- include/tcg/tcg-op.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/include/tcg/tcg-op.h b/include/tcg/tcg-op.h index 80cfcf8104..3ead59e459 100644 --- a/include/tcg/tcg-op.h +++ b/include/tcg/tcg-op.h @@ -52,7 +52,6 @@ static inline void tcg_gen_insn_start(target_ulong pc, target_ulong a1, typedef TCGv_i32 TCGv; #define tcg_temp_new() tcg_temp_new_i32() #define tcg_global_mem_new tcg_global_mem_new_i32 -#define tcg_temp_free tcg_temp_free_i32 #define tcgv_tl_temp tcgv_i32_temp #define tcg_gen_qemu_ld_tl tcg_gen_qemu_ld_i32 #define tcg_gen_qemu_st_tl tcg_gen_qemu_st_i32 @@ -60,7 +59,6 @@ typedef TCGv_i32 TCGv; typedef TCGv_i64 TCGv; #define tcg_temp_new() tcg_temp_new_i64() #define tcg_global_mem_new tcg_global_mem_new_i64 -#define tcg_temp_free tcg_temp_free_i64 #define tcgv_tl_temp tcgv_i64_temp #define tcg_gen_qemu_ld_tl tcg_gen_qemu_ld_i64 #define tcg_gen_qemu_st_tl tcg_gen_qemu_st_i64 From bfefdbea9ee491842d4e61e54f97508c040913a8 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Mon, 16 Oct 2023 14:45:12 -0700 Subject: [PATCH 1065/1077] tcg: Use constant zero when expanding with divu2 Signed-off-by: Richard Henderson --- tcg/tcg-op.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/tcg/tcg-op.c b/tcg/tcg-op.c index 393dbcd01c..c29355b67b 100644 --- a/tcg/tcg-op.c +++ b/tcg/tcg-op.c @@ -342,8 +342,8 @@ void tcg_gen_divu_i32(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2) tcg_gen_op3_i32(INDEX_op_divu_i32, ret, arg1, arg2); } else if (TCG_TARGET_HAS_div2_i32) { TCGv_i32 t0 = tcg_temp_ebb_new_i32(); - tcg_gen_movi_i32(t0, 0); - tcg_gen_op5_i32(INDEX_op_divu2_i32, ret, t0, arg1, t0, arg2); + TCGv_i32 zero = tcg_constant_i32(0); + tcg_gen_op5_i32(INDEX_op_divu2_i32, ret, t0, arg1, zero, arg2); tcg_temp_free_i32(t0); } else { gen_helper_divu_i32(ret, arg1, arg2); @@ -362,8 +362,8 @@ void tcg_gen_remu_i32(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2) tcg_temp_free_i32(t0); } else if (TCG_TARGET_HAS_div2_i32) { TCGv_i32 t0 = tcg_temp_ebb_new_i32(); - tcg_gen_movi_i32(t0, 0); - tcg_gen_op5_i32(INDEX_op_divu2_i32, t0, ret, arg1, t0, arg2); + TCGv_i32 zero = tcg_constant_i32(0); + tcg_gen_op5_i32(INDEX_op_divu2_i32, t0, ret, arg1, zero, arg2); tcg_temp_free_i32(t0); } else { gen_helper_remu_i32(ret, arg1, arg2); @@ -1674,8 +1674,8 @@ void tcg_gen_divu_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2) tcg_gen_op3_i64(INDEX_op_divu_i64, ret, arg1, arg2); } else if (TCG_TARGET_HAS_div2_i64) { TCGv_i64 t0 = tcg_temp_ebb_new_i64(); - tcg_gen_movi_i64(t0, 0); - tcg_gen_op5_i64(INDEX_op_divu2_i64, ret, t0, arg1, t0, arg2); + TCGv_i64 zero = tcg_constant_i64(0); + tcg_gen_op5_i64(INDEX_op_divu2_i64, ret, t0, arg1, zero, arg2); tcg_temp_free_i64(t0); } else { gen_helper_divu_i64(ret, arg1, arg2); @@ -1694,8 +1694,8 @@ void tcg_gen_remu_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2) tcg_temp_free_i64(t0); } else if (TCG_TARGET_HAS_div2_i64) { TCGv_i64 t0 = tcg_temp_ebb_new_i64(); - tcg_gen_movi_i64(t0, 0); - tcg_gen_op5_i64(INDEX_op_divu2_i64, t0, ret, arg1, t0, arg2); + TCGv_i64 zero = tcg_constant_i64(0); + tcg_gen_op5_i64(INDEX_op_divu2_i64, t0, ret, arg1, zero, arg2); tcg_temp_free_i64(t0); } else { gen_helper_remu_i64(ret, arg1, arg2); From d97f8f394184403beb655f5f077bef8ef83ffa3a Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Mon, 16 Oct 2023 19:10:42 -0700 Subject: [PATCH 1066/1077] tcg: Optimize past conditional branches We already register allocate through extended basic blocks, optimize through extended basic blocks as well. Signed-off-by: Richard Henderson --- tcg/optimize.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/tcg/optimize.c b/tcg/optimize.c index 3013eb04e6..2db5177c32 100644 --- a/tcg/optimize.c +++ b/tcg/optimize.c @@ -688,12 +688,14 @@ static void finish_folding(OptContext *ctx, TCGOp *op) int i, nb_oargs; /* - * For an opcode that ends a BB, reset all temp data. - * We do no cross-BB optimization. + * We only optimize extended basic blocks. If the opcode ends a BB + * and is not a conditional branch, reset all temp data. */ if (def->flags & TCG_OPF_BB_END) { - memset(&ctx->temps_used, 0, sizeof(ctx->temps_used)); ctx->prev_mb = NULL; + if (!(def->flags & TCG_OPF_COND_BRANCH)) { + memset(&ctx->temps_used, 0, sizeof(ctx->temps_used)); + } return; } From a01d9792a737f371a5050c483097e38eab9fa81c Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Thu, 24 Aug 2023 10:25:21 -0700 Subject: [PATCH 1067/1077] tcg: Add tcg_gen_{ld,st}_i128 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Do not require the translators to jump through concat and extract of i64 in order to move values to and from env. Tested-by: Song Gao Reviewed-by: Song Gao Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Richard Henderson --- include/tcg/tcg-op-common.h | 3 +++ tcg/tcg-op.c | 22 ++++++++++++++++++++++ 2 files changed, 25 insertions(+) diff --git a/include/tcg/tcg-op-common.h b/include/tcg/tcg-op-common.h index 2048f92b5e..56d4e9cb9f 100644 --- a/include/tcg/tcg-op-common.h +++ b/include/tcg/tcg-op-common.h @@ -747,6 +747,9 @@ void tcg_gen_mov_i128(TCGv_i128 dst, TCGv_i128 src); void tcg_gen_extr_i128_i64(TCGv_i64 lo, TCGv_i64 hi, TCGv_i128 arg); void tcg_gen_concat_i64_i128(TCGv_i128 ret, TCGv_i64 lo, TCGv_i64 hi); +void tcg_gen_ld_i128(TCGv_i128 ret, TCGv_ptr base, tcg_target_long offset); +void tcg_gen_st_i128(TCGv_i128 val, TCGv_ptr base, tcg_target_long offset); + static inline void tcg_gen_concat32_i64(TCGv_i64 ret, TCGv_i64 lo, TCGv_i64 hi) { tcg_gen_deposit_i64(ret, lo, hi, 32, 32); diff --git a/tcg/tcg-op.c b/tcg/tcg-op.c index c29355b67b..b4dbb2f2ba 100644 --- a/tcg/tcg-op.c +++ b/tcg/tcg-op.c @@ -2880,6 +2880,28 @@ void tcg_gen_mov_i128(TCGv_i128 dst, TCGv_i128 src) } } +void tcg_gen_ld_i128(TCGv_i128 ret, TCGv_ptr base, tcg_target_long offset) +{ + if (HOST_BIG_ENDIAN) { + tcg_gen_ld_i64(TCGV128_HIGH(ret), base, offset); + tcg_gen_ld_i64(TCGV128_LOW(ret), base, offset + 8); + } else { + tcg_gen_ld_i64(TCGV128_LOW(ret), base, offset); + tcg_gen_ld_i64(TCGV128_HIGH(ret), base, offset + 8); + } +} + +void tcg_gen_st_i128(TCGv_i128 val, TCGv_ptr base, tcg_target_long offset) +{ + if (HOST_BIG_ENDIAN) { + tcg_gen_st_i64(TCGV128_HIGH(val), base, offset); + tcg_gen_st_i64(TCGV128_LOW(val), base, offset + 8); + } else { + tcg_gen_st_i64(TCGV128_LOW(val), base, offset); + tcg_gen_st_i64(TCGV128_HIGH(val), base, offset + 8); + } +} + /* QEMU specific operations. */ void tcg_gen_exit_tb(const TranslationBlock *tb, unsigned idx) From 46c684c86260489eef485311aa76bb7aa94cedfc Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Thu, 24 Aug 2023 11:08:44 -0700 Subject: [PATCH 1068/1077] target/i386: Use i128 for 128 and 256-bit loads and stores Signed-off-by: Richard Henderson --- target/i386/tcg/translate.c | 63 +++++++++++++++++-------------------- 1 file changed, 29 insertions(+), 34 deletions(-) diff --git a/target/i386/tcg/translate.c b/target/i386/tcg/translate.c index 4f6f9fa7e5..18d06ab247 100644 --- a/target/i386/tcg/translate.c +++ b/target/i386/tcg/translate.c @@ -2918,59 +2918,54 @@ static inline void gen_stq_env_A0(DisasContext *s, int offset) static inline void gen_ldo_env_A0(DisasContext *s, int offset, bool align) { + MemOp atom = (s->cpuid_ext_features & CPUID_EXT_AVX + ? MO_ATOM_IFALIGN : MO_ATOM_IFALIGN_PAIR); + MemOp mop = MO_128 | MO_LE | atom | (align ? MO_ALIGN_16 : 0); int mem_index = s->mem_index; - tcg_gen_qemu_ld_i64(s->tmp1_i64, s->A0, mem_index, - MO_LEUQ | (align ? MO_ALIGN_16 : 0)); - tcg_gen_st_i64(s->tmp1_i64, tcg_env, offset + offsetof(XMMReg, XMM_Q(0))); - tcg_gen_addi_tl(s->tmp0, s->A0, 8); - tcg_gen_qemu_ld_i64(s->tmp1_i64, s->tmp0, mem_index, MO_LEUQ); - tcg_gen_st_i64(s->tmp1_i64, tcg_env, offset + offsetof(XMMReg, XMM_Q(1))); + TCGv_i128 t = tcg_temp_new_i128(); + + tcg_gen_qemu_ld_i128(t, s->A0, mem_index, mop); + tcg_gen_st_i128(t, tcg_env, offset); } static inline void gen_sto_env_A0(DisasContext *s, int offset, bool align) { + MemOp atom = (s->cpuid_ext_features & CPUID_EXT_AVX + ? MO_ATOM_IFALIGN : MO_ATOM_IFALIGN_PAIR); + MemOp mop = MO_128 | MO_LE | atom | (align ? MO_ALIGN_16 : 0); int mem_index = s->mem_index; - tcg_gen_ld_i64(s->tmp1_i64, tcg_env, offset + offsetof(XMMReg, XMM_Q(0))); - tcg_gen_qemu_st_i64(s->tmp1_i64, s->A0, mem_index, - MO_LEUQ | (align ? MO_ALIGN_16 : 0)); - tcg_gen_addi_tl(s->tmp0, s->A0, 8); - tcg_gen_ld_i64(s->tmp1_i64, tcg_env, offset + offsetof(XMMReg, XMM_Q(1))); - tcg_gen_qemu_st_i64(s->tmp1_i64, s->tmp0, mem_index, MO_LEUQ); + TCGv_i128 t = tcg_temp_new_i128(); + + tcg_gen_ld_i128(t, tcg_env, offset); + tcg_gen_qemu_st_i128(t, s->A0, mem_index, mop); } static void gen_ldy_env_A0(DisasContext *s, int offset, bool align) { + MemOp mop = MO_128 | MO_LE | MO_ATOM_IFALIGN_PAIR; int mem_index = s->mem_index; - tcg_gen_qemu_ld_i64(s->tmp1_i64, s->A0, mem_index, - MO_LEUQ | (align ? MO_ALIGN_32 : 0)); - tcg_gen_st_i64(s->tmp1_i64, tcg_env, offset + offsetof(YMMReg, YMM_Q(0))); - tcg_gen_addi_tl(s->tmp0, s->A0, 8); - tcg_gen_qemu_ld_i64(s->tmp1_i64, s->tmp0, mem_index, MO_LEUQ); - tcg_gen_st_i64(s->tmp1_i64, tcg_env, offset + offsetof(YMMReg, YMM_Q(1))); + TCGv_i128 t0 = tcg_temp_new_i128(); + TCGv_i128 t1 = tcg_temp_new_i128(); + tcg_gen_qemu_ld_i128(t0, s->A0, mem_index, mop | (align ? MO_ALIGN_32 : 0)); tcg_gen_addi_tl(s->tmp0, s->A0, 16); - tcg_gen_qemu_ld_i64(s->tmp1_i64, s->tmp0, mem_index, MO_LEUQ); - tcg_gen_st_i64(s->tmp1_i64, tcg_env, offset + offsetof(YMMReg, YMM_Q(2))); - tcg_gen_addi_tl(s->tmp0, s->A0, 24); - tcg_gen_qemu_ld_i64(s->tmp1_i64, s->tmp0, mem_index, MO_LEUQ); - tcg_gen_st_i64(s->tmp1_i64, tcg_env, offset + offsetof(YMMReg, YMM_Q(3))); + tcg_gen_qemu_ld_i128(t1, s->tmp0, mem_index, mop); + + tcg_gen_st_i128(t0, tcg_env, offset + offsetof(YMMReg, YMM_X(0))); + tcg_gen_st_i128(t1, tcg_env, offset + offsetof(YMMReg, YMM_X(1))); } static void gen_sty_env_A0(DisasContext *s, int offset, bool align) { + MemOp mop = MO_128 | MO_LE | MO_ATOM_IFALIGN_PAIR; int mem_index = s->mem_index; - tcg_gen_ld_i64(s->tmp1_i64, tcg_env, offset + offsetof(YMMReg, YMM_Q(0))); - tcg_gen_qemu_st_i64(s->tmp1_i64, s->A0, mem_index, - MO_LEUQ | (align ? MO_ALIGN_32 : 0)); - tcg_gen_addi_tl(s->tmp0, s->A0, 8); - tcg_gen_ld_i64(s->tmp1_i64, tcg_env, offset + offsetof(YMMReg, YMM_Q(1))); - tcg_gen_qemu_st_i64(s->tmp1_i64, s->tmp0, mem_index, MO_LEUQ); + TCGv_i128 t = tcg_temp_new_i128(); + + tcg_gen_ld_i128(t, tcg_env, offset + offsetof(YMMReg, YMM_X(0))); + tcg_gen_qemu_st_i128(t, s->A0, mem_index, mop | (align ? MO_ALIGN_32 : 0)); tcg_gen_addi_tl(s->tmp0, s->A0, 16); - tcg_gen_ld_i64(s->tmp1_i64, tcg_env, offset + offsetof(YMMReg, YMM_Q(2))); - tcg_gen_qemu_st_i64(s->tmp1_i64, s->tmp0, mem_index, MO_LEUQ); - tcg_gen_addi_tl(s->tmp0, s->A0, 24); - tcg_gen_ld_i64(s->tmp1_i64, tcg_env, offset + offsetof(YMMReg, YMM_Q(3))); - tcg_gen_qemu_st_i64(s->tmp1_i64, s->tmp0, mem_index, MO_LEUQ); + tcg_gen_ld_i128(t, tcg_env, offset + offsetof(YMMReg, YMM_X(1))); + tcg_gen_qemu_st_i128(t, s->tmp0, mem_index, mop); } #include "decode-new.h" From 93c86ecd77a308e023fe158936abc78ea01072d5 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Thu, 19 Oct 2023 12:46:43 +0200 Subject: [PATCH 1069/1077] tcg: add negsetcondi This can be useful to write a shift bit extraction that does not depend on TARGET_LONG_BITS. Signed-off-by: Paolo Bonzini Message-Id: <20231019104648.389942-15-pbonzini@redhat.com> Signed-off-by: Richard Henderson --- include/tcg/tcg-op-common.h | 4 ++++ include/tcg/tcg-op.h | 2 ++ tcg/tcg-op.c | 12 ++++++++++++ 3 files changed, 18 insertions(+) diff --git a/include/tcg/tcg-op-common.h b/include/tcg/tcg-op-common.h index 56d4e9cb9f..a0bae5df01 100644 --- a/include/tcg/tcg-op-common.h +++ b/include/tcg/tcg-op-common.h @@ -346,6 +346,8 @@ void tcg_gen_setcondi_i32(TCGCond cond, TCGv_i32 ret, TCGv_i32 arg1, int32_t arg2); void tcg_gen_negsetcond_i32(TCGCond cond, TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2); +void tcg_gen_negsetcondi_i32(TCGCond cond, TCGv_i32 ret, + TCGv_i32 arg1, int32_t arg2); void tcg_gen_movcond_i32(TCGCond cond, TCGv_i32 ret, TCGv_i32 c1, TCGv_i32 c2, TCGv_i32 v1, TCGv_i32 v2); void tcg_gen_add2_i32(TCGv_i32 rl, TCGv_i32 rh, TCGv_i32 al, @@ -544,6 +546,8 @@ void tcg_gen_setcondi_i64(TCGCond cond, TCGv_i64 ret, TCGv_i64 arg1, int64_t arg2); void tcg_gen_negsetcond_i64(TCGCond cond, TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2); +void tcg_gen_negsetcondi_i64(TCGCond cond, TCGv_i64 ret, + TCGv_i64 arg1, int64_t arg2); void tcg_gen_movcond_i64(TCGCond cond, TCGv_i64 ret, TCGv_i64 c1, TCGv_i64 c2, TCGv_i64 v1, TCGv_i64 v2); void tcg_gen_add2_i64(TCGv_i64 rl, TCGv_i64 rh, TCGv_i64 al, diff --git a/include/tcg/tcg-op.h b/include/tcg/tcg-op.h index 3ead59e459..e81dd7dd9e 100644 --- a/include/tcg/tcg-op.h +++ b/include/tcg/tcg-op.h @@ -199,6 +199,7 @@ DEF_ATOMIC2(tcg_gen_atomic_umax_fetch, i64) #define tcg_gen_setcond_tl tcg_gen_setcond_i64 #define tcg_gen_setcondi_tl tcg_gen_setcondi_i64 #define tcg_gen_negsetcond_tl tcg_gen_negsetcond_i64 +#define tcg_gen_negsetcondi_tl tcg_gen_negsetcondi_i64 #define tcg_gen_mul_tl tcg_gen_mul_i64 #define tcg_gen_muli_tl tcg_gen_muli_i64 #define tcg_gen_div_tl tcg_gen_div_i64 @@ -317,6 +318,7 @@ DEF_ATOMIC2(tcg_gen_atomic_umax_fetch, i64) #define tcg_gen_setcond_tl tcg_gen_setcond_i32 #define tcg_gen_setcondi_tl tcg_gen_setcondi_i32 #define tcg_gen_negsetcond_tl tcg_gen_negsetcond_i32 +#define tcg_gen_negsetcondi_tl tcg_gen_negsetcondi_i32 #define tcg_gen_mul_tl tcg_gen_mul_i32 #define tcg_gen_muli_tl tcg_gen_muli_i32 #define tcg_gen_div_tl tcg_gen_div_i32 diff --git a/tcg/tcg-op.c b/tcg/tcg-op.c index b4dbb2f2ba..828eb9ee46 100644 --- a/tcg/tcg-op.c +++ b/tcg/tcg-op.c @@ -291,6 +291,12 @@ void tcg_gen_negsetcond_i32(TCGCond cond, TCGv_i32 ret, } } +void tcg_gen_negsetcondi_i32(TCGCond cond, TCGv_i32 ret, + TCGv_i32 arg1, int32_t arg2) +{ + tcg_gen_negsetcond_i32(cond, ret, arg1, tcg_constant_i32(arg2)); +} + void tcg_gen_muli_i32(TCGv_i32 ret, TCGv_i32 arg1, int32_t arg2) { if (arg2 == 0) { @@ -1602,6 +1608,12 @@ void tcg_gen_setcondi_i64(TCGCond cond, TCGv_i64 ret, } } +void tcg_gen_negsetcondi_i64(TCGCond cond, TCGv_i64 ret, + TCGv_i64 arg1, int64_t arg2) +{ + tcg_gen_negsetcond_i64(cond, ret, arg1, tcg_constant_i64(arg2)); +} + void tcg_gen_negsetcond_i64(TCGCond cond, TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2) { From f1c29532e7f85932d541fc733fda82e8cf887311 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Thu, 19 Oct 2023 09:15:22 -0700 Subject: [PATCH 1070/1077] tcg: Export tcg_gen_ext_{i32,i64,tl} MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The two concrete type functions already existed, merely needing a bit of hardening to invalid inputs. Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Richard Henderson --- include/tcg/tcg-op-common.h | 2 ++ include/tcg/tcg-op.h | 2 ++ tcg/tcg-op-ldst.c | 14 ++++++++++---- 3 files changed, 14 insertions(+), 4 deletions(-) diff --git a/include/tcg/tcg-op-common.h b/include/tcg/tcg-op-common.h index a0bae5df01..677aea6dd1 100644 --- a/include/tcg/tcg-op-common.h +++ b/include/tcg/tcg-op-common.h @@ -361,6 +361,7 @@ void tcg_gen_ext8s_i32(TCGv_i32 ret, TCGv_i32 arg); void tcg_gen_ext16s_i32(TCGv_i32 ret, TCGv_i32 arg); void tcg_gen_ext8u_i32(TCGv_i32 ret, TCGv_i32 arg); void tcg_gen_ext16u_i32(TCGv_i32 ret, TCGv_i32 arg); +void tcg_gen_ext_i32(TCGv_i32 ret, TCGv_i32 val, MemOp opc); void tcg_gen_bswap16_i32(TCGv_i32 ret, TCGv_i32 arg, int flags); void tcg_gen_bswap32_i32(TCGv_i32 ret, TCGv_i32 arg); void tcg_gen_hswap_i32(TCGv_i32 ret, TCGv_i32 arg); @@ -564,6 +565,7 @@ void tcg_gen_ext32s_i64(TCGv_i64 ret, TCGv_i64 arg); void tcg_gen_ext8u_i64(TCGv_i64 ret, TCGv_i64 arg); void tcg_gen_ext16u_i64(TCGv_i64 ret, TCGv_i64 arg); void tcg_gen_ext32u_i64(TCGv_i64 ret, TCGv_i64 arg); +void tcg_gen_ext_i64(TCGv_i64 ret, TCGv_i64 val, MemOp opc); void tcg_gen_bswap16_i64(TCGv_i64 ret, TCGv_i64 arg, int flags); void tcg_gen_bswap32_i64(TCGv_i64 ret, TCGv_i64 arg, int flags); void tcg_gen_bswap64_i64(TCGv_i64 ret, TCGv_i64 arg); diff --git a/include/tcg/tcg-op.h b/include/tcg/tcg-op.h index e81dd7dd9e..a02850583b 100644 --- a/include/tcg/tcg-op.h +++ b/include/tcg/tcg-op.h @@ -219,6 +219,7 @@ DEF_ATOMIC2(tcg_gen_atomic_umax_fetch, i64) #define tcg_gen_ext16s_tl tcg_gen_ext16s_i64 #define tcg_gen_ext32u_tl tcg_gen_ext32u_i64 #define tcg_gen_ext32s_tl tcg_gen_ext32s_i64 +#define tcg_gen_ext_tl tcg_gen_ext_i64 #define tcg_gen_bswap16_tl tcg_gen_bswap16_i64 #define tcg_gen_bswap32_tl tcg_gen_bswap32_i64 #define tcg_gen_bswap64_tl tcg_gen_bswap64_i64 @@ -338,6 +339,7 @@ DEF_ATOMIC2(tcg_gen_atomic_umax_fetch, i64) #define tcg_gen_ext16s_tl tcg_gen_ext16s_i32 #define tcg_gen_ext32u_tl tcg_gen_mov_i32 #define tcg_gen_ext32s_tl tcg_gen_mov_i32 +#define tcg_gen_ext_tl tcg_gen_ext_i32 #define tcg_gen_bswap16_tl tcg_gen_bswap16_i32 #define tcg_gen_bswap32_tl(D, S, F) tcg_gen_bswap32_i32(D, S) #define tcg_gen_bswap_tl tcg_gen_bswap32_i32 diff --git a/tcg/tcg-op-ldst.c b/tcg/tcg-op-ldst.c index 2b96687699..e2c55df217 100644 --- a/tcg/tcg-op-ldst.c +++ b/tcg/tcg-op-ldst.c @@ -714,7 +714,7 @@ void tcg_gen_qemu_st_i128_chk(TCGv_i128 val, TCGTemp *addr, TCGArg idx, tcg_gen_qemu_st_i128_int(val, addr, idx, memop); } -static void tcg_gen_ext_i32(TCGv_i32 ret, TCGv_i32 val, MemOp opc) +void tcg_gen_ext_i32(TCGv_i32 ret, TCGv_i32 val, MemOp opc) { switch (opc & MO_SSIZE) { case MO_SB: @@ -729,13 +729,16 @@ static void tcg_gen_ext_i32(TCGv_i32 ret, TCGv_i32 val, MemOp opc) case MO_UW: tcg_gen_ext16u_i32(ret, val); break; - default: + case MO_UL: + case MO_SL: tcg_gen_mov_i32(ret, val); break; + default: + g_assert_not_reached(); } } -static void tcg_gen_ext_i64(TCGv_i64 ret, TCGv_i64 val, MemOp opc) +void tcg_gen_ext_i64(TCGv_i64 ret, TCGv_i64 val, MemOp opc) { switch (opc & MO_SSIZE) { case MO_SB: @@ -756,9 +759,12 @@ static void tcg_gen_ext_i64(TCGv_i64 ret, TCGv_i64 val, MemOp opc) case MO_UL: tcg_gen_ext32u_i64(ret, val); break; - default: + case MO_UQ: + case MO_SQ: tcg_gen_mov_i64(ret, val); break; + default: + g_assert_not_reached(); } } From c048b68385c2146931ea032d775479a8ab1cddf3 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Sun, 22 Oct 2023 16:34:21 -0700 Subject: [PATCH 1071/1077] tcg: Define MO_TL This will also come in handy later for "less than" comparisons. Signed-off-by: Paolo Bonzini Message-Id: <03ba02fd-fade-4409-be16-2f81a5690b4c@redhat.com> Reviewed-by: Richard Henderson Signed-off-by: Richard Henderson --- include/exec/target_long.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/include/exec/target_long.h b/include/exec/target_long.h index 93c9472971..3cd8e26a23 100644 --- a/include/exec/target_long.h +++ b/include/exec/target_long.h @@ -29,12 +29,14 @@ typedef uint32_t target_ulong; #define TARGET_FMT_lx "%08x" #define TARGET_FMT_ld "%d" #define TARGET_FMT_lu "%u" +#define MO_TL MO_32 #elif TARGET_LONG_SIZE == 8 typedef int64_t target_long; typedef uint64_t target_ulong; #define TARGET_FMT_lx "%016" PRIx64 #define TARGET_FMT_ld "%" PRId64 #define TARGET_FMT_lu "%" PRIu64 +#define MO_TL MO_64 #else #error TARGET_LONG_SIZE undefined #endif From 2f02c14b21cfe0954e203353af21cd41bce76822 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Thu, 19 Oct 2023 11:18:08 -0700 Subject: [PATCH 1072/1077] target/arm: Use tcg_gen_ext_i64 The ext_and_shift_reg helper does this plus a shift. The non-zero check for shift count is duplicate to the one done within tcg_gen_shli_i64. Signed-off-by: Richard Henderson --- target/arm/tcg/translate-a64.c | 37 ++-------------------------------- 1 file changed, 2 insertions(+), 35 deletions(-) diff --git a/target/arm/tcg/translate-a64.c b/target/arm/tcg/translate-a64.c index 10e8dcf743..ad78b8b120 100644 --- a/target/arm/tcg/translate-a64.c +++ b/target/arm/tcg/translate-a64.c @@ -1324,41 +1324,8 @@ static void ext_and_shift_reg(TCGv_i64 tcg_out, TCGv_i64 tcg_in, int extsize = extract32(option, 0, 2); bool is_signed = extract32(option, 2, 1); - if (is_signed) { - switch (extsize) { - case 0: - tcg_gen_ext8s_i64(tcg_out, tcg_in); - break; - case 1: - tcg_gen_ext16s_i64(tcg_out, tcg_in); - break; - case 2: - tcg_gen_ext32s_i64(tcg_out, tcg_in); - break; - case 3: - tcg_gen_mov_i64(tcg_out, tcg_in); - break; - } - } else { - switch (extsize) { - case 0: - tcg_gen_ext8u_i64(tcg_out, tcg_in); - break; - case 1: - tcg_gen_ext16u_i64(tcg_out, tcg_in); - break; - case 2: - tcg_gen_ext32u_i64(tcg_out, tcg_in); - break; - case 3: - tcg_gen_mov_i64(tcg_out, tcg_in); - break; - } - } - - if (shift) { - tcg_gen_shli_i64(tcg_out, tcg_out, shift); - } + tcg_gen_ext_i64(tcg_out, tcg_in, extsize | (is_signed ? MO_SIGN : 0)); + tcg_gen_shli_i64(tcg_out, tcg_out, shift); } static inline void gen_check_sp_alignment(DisasContext *s) From 23f3d586e4da86b86df8ab38e8dacad8a804ed3f Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Thu, 19 Oct 2023 11:18:51 -0700 Subject: [PATCH 1073/1077] target/i386: Use tcg_gen_ext_tl MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Richard Henderson --- target/i386/tcg/translate.c | 28 +++------------------------- 1 file changed, 3 insertions(+), 25 deletions(-) diff --git a/target/i386/tcg/translate.c b/target/i386/tcg/translate.c index 18d06ab247..587d88692a 100644 --- a/target/i386/tcg/translate.c +++ b/target/i386/tcg/translate.c @@ -701,33 +701,11 @@ static inline void gen_op_movl_T0_Dshift(DisasContext *s, MemOp ot) static TCGv gen_ext_tl(TCGv dst, TCGv src, MemOp size, bool sign) { - switch (size) { - case MO_8: - if (sign) { - tcg_gen_ext8s_tl(dst, src); - } else { - tcg_gen_ext8u_tl(dst, src); - } - return dst; - case MO_16: - if (sign) { - tcg_gen_ext16s_tl(dst, src); - } else { - tcg_gen_ext16u_tl(dst, src); - } - return dst; -#ifdef TARGET_X86_64 - case MO_32: - if (sign) { - tcg_gen_ext32s_tl(dst, src); - } else { - tcg_gen_ext32u_tl(dst, src); - } - return dst; -#endif - default: + if (size == MO_TL) { return src; } + tcg_gen_ext_tl(dst, src, size | (sign ? MO_SIGN : 0)); + return dst; } static void gen_extu(MemOp ot, TCGv reg) From 443025e4d0f71bb82fe80369032bf1a04f433352 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Thu, 19 Oct 2023 11:20:12 -0700 Subject: [PATCH 1074/1077] target/m68k: Use tcg_gen_ext_i32 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We still need to check OS_{BYTE,WORD,LONG}, because m68k includes floating point in OS_*. Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Richard Henderson --- target/m68k/translate.c | 23 +++-------------------- 1 file changed, 3 insertions(+), 20 deletions(-) diff --git a/target/m68k/translate.c b/target/m68k/translate.c index 4d0110de95..4a0b0b2703 100644 --- a/target/m68k/translate.c +++ b/target/m68k/translate.c @@ -520,21 +520,9 @@ static inline void gen_ext(TCGv res, TCGv val, int opsize, int sign) { switch (opsize) { case OS_BYTE: - if (sign) { - tcg_gen_ext8s_i32(res, val); - } else { - tcg_gen_ext8u_i32(res, val); - } - break; case OS_WORD: - if (sign) { - tcg_gen_ext16s_i32(res, val); - } else { - tcg_gen_ext16u_i32(res, val); - } - break; case OS_LONG: - tcg_gen_mov_i32(res, val); + tcg_gen_ext_i32(res, val, opsize | (sign ? MO_SIGN : 0)); break; default: g_assert_not_reached(); @@ -1072,15 +1060,10 @@ static int gen_ea_mode_fp(CPUM68KState *env, DisasContext *s, int mode, tmp = tcg_temp_new(); switch (opsize) { case OS_BYTE: - tcg_gen_ext8s_i32(tmp, reg); - gen_helper_exts32(tcg_env, fp, tmp); - break; case OS_WORD: - tcg_gen_ext16s_i32(tmp, reg); - gen_helper_exts32(tcg_env, fp, tmp); - break; case OS_LONG: - gen_helper_exts32(tcg_env, fp, reg); + tcg_gen_ext_i32(tmp, reg, opsize | MO_SIGN); + gen_helper_exts32(tcg_env, fp, tmp); break; case OS_SINGLE: gen_helper_extf32(tcg_env, fp, reg); From 0d67249c6d30a626434815c4fc39ab6bc60708f6 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Thu, 19 Oct 2023 11:21:40 -0700 Subject: [PATCH 1075/1077] target/rx: Use tcg_gen_ext_i32 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Reviewed-by: Yoshinori Sato Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Richard Henderson --- target/rx/translate.c | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/target/rx/translate.c b/target/rx/translate.c index f8860830ae..c6ce717a95 100644 --- a/target/rx/translate.c +++ b/target/rx/translate.c @@ -492,13 +492,11 @@ static bool trans_MOV_ra(DisasContext *ctx, arg_MOV_ra *a) /* mov. rs,rd */ static bool trans_MOV_mm(DisasContext *ctx, arg_MOV_mm *a) { - static void (* const mov[])(TCGv ret, TCGv arg) = { - tcg_gen_ext8s_i32, tcg_gen_ext16s_i32, tcg_gen_mov_i32, - }; TCGv tmp, mem, addr; + if (a->lds == 3 && a->ldd == 3) { /* mov. rs,rd */ - mov[a->sz](cpu_regs[a->rd], cpu_regs[a->rs]); + tcg_gen_ext_i32(cpu_regs[a->rd], cpu_regs[a->rs], a->sz | MO_SIGN); return true; } @@ -570,10 +568,7 @@ static bool trans_MOVU_mr(DisasContext *ctx, arg_MOVU_mr *a) /* movu. rs,rd */ static bool trans_MOVU_rr(DisasContext *ctx, arg_MOVU_rr *a) { - static void (* const ext[])(TCGv ret, TCGv arg) = { - tcg_gen_ext8u_i32, tcg_gen_ext16u_i32, - }; - ext[a->sz](cpu_regs[a->rd], cpu_regs[a->rs]); + tcg_gen_ext_i32(cpu_regs[a->rd], cpu_regs[a->rs], a->sz); return true; } From 8b8bb295489fe8853a650aabf7349cd7aa6d1e9c Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Thu, 19 Oct 2023 11:23:19 -0700 Subject: [PATCH 1076/1077] target/tricore: Use tcg_gen_*extract_tl The EXTR instructions can use the extract opcodes. Reviewed-by: Bastian Koppelmann Signed-off-by: Richard Henderson --- target/tricore/translate.c | 20 ++++---------------- 1 file changed, 4 insertions(+), 16 deletions(-) diff --git a/target/tricore/translate.c b/target/tricore/translate.c index dd812ec0f0..66553d1be0 100644 --- a/target/tricore/translate.c +++ b/target/tricore/translate.c @@ -6542,28 +6542,16 @@ static void decode_rrpw_extract_insert(DisasContext *ctx) switch (op2) { case OPC2_32_RRPW_EXTR: if (width == 0) { - tcg_gen_movi_tl(cpu_gpr_d[r3], 0); - break; - } - - if (pos + width <= 32) { - /* optimize special cases */ - if ((pos == 0) && (width == 8)) { - tcg_gen_ext8s_tl(cpu_gpr_d[r3], cpu_gpr_d[r1]); - } else if ((pos == 0) && (width == 16)) { - tcg_gen_ext16s_tl(cpu_gpr_d[r3], cpu_gpr_d[r1]); - } else { - tcg_gen_shli_tl(cpu_gpr_d[r3], cpu_gpr_d[r1], 32 - pos - width); - tcg_gen_sari_tl(cpu_gpr_d[r3], cpu_gpr_d[r3], 32 - width); - } + tcg_gen_movi_tl(cpu_gpr_d[r3], 0); + } else if (pos + width <= 32) { + tcg_gen_sextract_tl(cpu_gpr_d[r3], cpu_gpr_d[r1], pos, width); } break; case OPC2_32_RRPW_EXTR_U: if (width == 0) { tcg_gen_movi_tl(cpu_gpr_d[r3], 0); } else { - tcg_gen_shri_tl(cpu_gpr_d[r3], cpu_gpr_d[r1], pos); - tcg_gen_andi_tl(cpu_gpr_d[r3], cpu_gpr_d[r3], ~0u >> (32-width)); + tcg_gen_extract_tl(cpu_gpr_d[r3], cpu_gpr_d[r1], pos, width); } break; case OPC2_32_RRPW_IMASK: From e40df3522b384d3b7dd38187d735bd6228b20e47 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Thu, 19 Oct 2023 11:25:32 -0700 Subject: [PATCH 1077/1077] target/xtensa: Use tcg_gen_sextract_i32 Reviewed-by: Max Filippov Signed-off-by: Richard Henderson --- target/xtensa/translate.c | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/target/xtensa/translate.c b/target/xtensa/translate.c index 54bee7ddba..de89940599 100644 --- a/target/xtensa/translate.c +++ b/target/xtensa/translate.c @@ -2262,17 +2262,7 @@ static void translate_salt(DisasContext *dc, const OpcodeArg arg[], static void translate_sext(DisasContext *dc, const OpcodeArg arg[], const uint32_t par[]) { - int shift = 31 - arg[2].imm; - - if (shift == 24) { - tcg_gen_ext8s_i32(arg[0].out, arg[1].in); - } else if (shift == 16) { - tcg_gen_ext16s_i32(arg[0].out, arg[1].in); - } else { - TCGv_i32 tmp = tcg_temp_new_i32(); - tcg_gen_shli_i32(tmp, arg[1].in, shift); - tcg_gen_sari_i32(arg[0].out, tmp, shift); - } + tcg_gen_sextract_i32(arg[0].out, arg[1].in, 0, arg[2].imm + 1); } static uint32_t test_exceptions_simcall(DisasContext *dc,