xref: /qemu/docs/interop/firmware.json (revision efe25c260cd69dcfc948e1622bedbdec953569a8)
1# -*- Mode: Python -*-
2# vim: filetype=python
3#
4# Copyright (C) 2018 Red Hat, Inc.
5#
6# Authors:
7#  Daniel P. Berrange <berrange@redhat.com>
8#  Laszlo Ersek <lersek@redhat.com>
9#
10# This work is licensed under the terms of the GNU GPL, version 2 or
11# later. See the COPYING file in the top-level directory.
12
13##
14# = Firmware
15##
16
17{ 'pragma': {
18    'member-name-exceptions': [
19        'FirmwareArchitecture' # x86_64
20    ] } }
21
22##
23# @FirmwareOSInterface:
24#
25# Lists the firmware-OS interface types provided by various firmware
26# that is commonly used with QEMU virtual machines.
27#
28# @bios: Traditional x86 BIOS interface. For example, firmware built
29#        from the SeaBIOS project usually provides this interface.
30#
31# @openfirmware: The interface is defined by the (historical) IEEE
32#                1275-1994 standard. Examples for firmware projects that
33#                provide this interface are: OpenBIOS and SLOF.
34#
35# @uboot: Firmware interface defined by the U-Boot project.
36#
37# @uefi: Firmware interface defined by the UEFI specification. For
38#        example, firmware built from the edk2 (EFI Development Kit II)
39#        project usually provides this interface.
40#
41# Since: 3.0
42##
43{ 'enum' : 'FirmwareOSInterface',
44  'data' : [ 'bios', 'openfirmware', 'uboot', 'uefi' ] }
45
46##
47# @FirmwareDevice:
48#
49# Defines the device types that firmware can be mapped into.
50#
51# @flash: The firmware executable and its accompanying NVRAM file are to
52#         be mapped into a pflash chip each.
53#
54# @kernel: The firmware is to be loaded like a Linux kernel. This is
55#          similar to @memory but may imply additional processing that
56#          is specific to the target architecture and machine type.
57#
58# @memory: The firmware is to be mapped into memory.
59#
60# Since: 3.0
61##
62{ 'enum' : 'FirmwareDevice',
63  'data' : [ 'flash', 'kernel', 'memory' ] }
64
65##
66# @FirmwareArchitecture:
67#
68# Enumeration of architectures for which Qemu uses additional
69# firmware files.
70#
71# @aarch64: 64-bit Arm.
72#
73# @arm: 32-bit Arm.
74#
75# @i386: 32-bit x86.
76#
77# @loongarch64: 64-bit LoongArch. (since: 7.1)
78#
79# @x86_64: 64-bit x86.
80#
81# Since: 3.0
82##
83{ 'enum' : 'FirmwareArchitecture',
84  'data' : [ 'aarch64', 'arm', 'i386', 'loongarch64', 'x86_64' ] }
85
86##
87# @FirmwareTarget:
88#
89# Defines the machine types that firmware may execute on.
90#
91# @architecture: Determines the emulation target (the QEMU system
92#                emulator) that can execute the firmware.
93#
94# @machines: Lists the machine types (known by the emulator that is
95#            specified through @architecture) that can execute the
96#            firmware. Elements of @machines are supposed to be concrete
97#            machine types, not aliases. Glob patterns are understood,
98#            which is especially useful for versioned machine types.
99#            (For example, the glob pattern "pc-i440fx-*" matches
100#            "pc-i440fx-2.12".) On the QEMU command line, "-machine
101#            type=..." specifies the requested machine type (but that
102#            option does not accept glob patterns).
103#
104# Since: 3.0
105##
106{ 'struct' : 'FirmwareTarget',
107  'data'   : { 'architecture' : 'FirmwareArchitecture',
108               'machines'     : [ 'str' ] } }
109
110##
111# @FirmwareFeature:
112#
113# Defines the features that firmware may support, and the platform
114# requirements that firmware may present.
115#
116# @acpi-s3: The firmware supports S3 sleep (suspend to RAM), as defined
117#           in the ACPI specification. On the "pc-i440fx-*" machine
118#           types of the @i386 and @x86_64 emulation targets, S3 can be
119#           enabled with "-global PIIX4_PM.disable_s3=0" and disabled
120#           with "-global PIIX4_PM.disable_s3=1". On the "pc-q35-*"
121#           machine types of the @i386 and @x86_64 emulation targets, S3
122#           can be enabled with "-global ICH9-LPC.disable_s3=0" and
123#           disabled with "-global ICH9-LPC.disable_s3=1".
124#
125# @acpi-s4: The firmware supports S4 hibernation (suspend to disk), as
126#           defined in the ACPI specification. On the "pc-i440fx-*"
127#           machine types of the @i386 and @x86_64 emulation targets, S4
128#           can be enabled with "-global PIIX4_PM.disable_s4=0" and
129#           disabled with "-global PIIX4_PM.disable_s4=1". On the
130#           "pc-q35-*" machine types of the @i386 and @x86_64 emulation
131#           targets, S4 can be enabled with "-global
132#           ICH9-LPC.disable_s4=0" and disabled with "-global
133#           ICH9-LPC.disable_s4=1".
134#
135# @amd-sev: The firmware supports running under AMD Secure Encrypted
136#           Virtualization, as specified in the AMD64 Architecture
137#           Programmer's Manual. QEMU command line options related to
138#           this feature are documented in
139#           "docs/system/i386/amd-memory-encryption.rst".
140#
141# @amd-sev-es: The firmware supports running under AMD Secure Encrypted
142#              Virtualization - Encrypted State, as specified in the AMD64
143#              Architecture Programmer's Manual. QEMU command line options
144#              related to this feature are documented in
145#              "docs/system/i386/amd-memory-encryption.rst".
146#
147# @amd-sev-snp: The firmware supports running under AMD Secure Encrypted
148#               Virtualization - Secure Nested Paging, as specified in the
149#               AMD64 Architecture Programmer's Manual. QEMU command line
150#               options related to this feature are documented in
151#               "docs/system/i386/amd-memory-encryption.rst".
152#
153# @intel-tdx: The firmware supports running under Intel Trust Domain
154#             Extensions (TDX).
155#
156# @enrolled-keys: The variable store (NVRAM) template associated with
157#                 the firmware binary has the UEFI Secure Boot
158#                 operational mode turned on, with certificates
159#                 enrolled.
160#
161# @requires-smm: The firmware requires the platform to emulate SMM
162#                (System Management Mode), as defined in the AMD64
163#                Architecture Programmer's Manual, and in the Intel(R)64
164#                and IA-32 Architectures Software Developer's Manual. On
165#                the "pc-q35-*" machine types of the @i386 and @x86_64
166#                emulation targets, SMM emulation can be enabled with
167#                "-machine smm=on". (On the "pc-q35-*" machine types of
168#                the @i386 emulation target, @requires-smm presents
169#                further CPU requirements; one combination known to work
170#                is "-cpu coreduo,nx=off".) If the firmware is marked as
171#                both @secure-boot and @requires-smm, then write
172#                accesses to the pflash chip (NVRAM) that holds the UEFI
173#                variable store must be restricted to code that executes
174#                in SMM, using the additional option "-global
175#                driver=cfi.pflash01,property=secure,value=on".
176#                Furthermore, a large guest-physical address space
177#                (comprising guest RAM, memory hotplug range, and 64-bit
178#                PCI MMIO aperture), and/or a high VCPU count, may
179#                present high SMRAM requirements from the firmware. On
180#                the "pc-q35-*" machine types of the @i386 and @x86_64
181#                emulation targets, the SMRAM size may be increased
182#                above the default 16MB with the "-global
183#                mch.extended-tseg-mbytes=uint16" option. As a rule of
184#                thumb, the default 16MB size suffices for 1TB of
185#                guest-phys address space and a few tens of VCPUs; for
186#                every further TB of guest-phys address space, add 8MB
187#                of SMRAM. 48MB should suffice for 4TB of guest-phys
188#                address space and 2-3 hundred VCPUs.
189#
190# @secure-boot: The firmware implements the software interfaces for UEFI
191#               Secure Boot, as defined in the UEFI specification. Note
192#               that without @requires-smm, guest code running with
193#               kernel privileges can undermine the security of Secure
194#               Boot.
195#
196# @verbose-dynamic: When firmware log capture is enabled, the firmware
197#                   logs a large amount of debug messages, which may
198#                   impact boot performance. With log capture disabled,
199#                   there is no boot performance impact. On the
200#                   "pc-i440fx-*" and "pc-q35-*" machine types of the
201#                   @i386 and @x86_64 emulation targets, firmware log
202#                   capture can be enabled with the QEMU command line
203#                   options "-chardev file,id=fwdebug,path=LOGFILEPATH
204#                   -device isa-debugcon,iobase=0x402,chardev=fwdebug".
205#                   @verbose-dynamic is mutually exclusive with
206#                   @verbose-static.
207#
208# @verbose-static: The firmware unconditionally produces a large amount
209#                  of debug messages, which may impact boot performance.
210#                  This feature may typically be carried by certain UEFI
211#                  firmware for the "virt-*" machine types of the @arm
212#                  and @aarch64 emulation targets, where the debug
213#                  messages are written to the first (always present)
214#                  PL011 UART. @verbose-static is mutually exclusive
215#                  with @verbose-dynamic.
216#
217# @host-uefi-vars: The firmware expects the host to provide an uefi
218#                  variable store.  qemu supports that via
219#                  "uefi-vars-sysbus" (aarch64, riscv64, loongarch64)
220#                  or "uefi-vars-x64" (x86_64) devices.  The firmware
221#                  will not use flash for nvram.  When loading the
222#                  firmware into flash the 'stateless' setup should be
223#                  used.  It is recommened to load the firmware into
224#                  memory though.
225#
226# Since: 3.0
227##
228{ 'enum' : 'FirmwareFeature',
229  'data' : [ 'acpi-s3', 'acpi-s4',
230             'amd-sev', 'amd-sev-es', 'amd-sev-snp',
231             'intel-tdx',
232             'enrolled-keys', 'requires-smm',
233             'secure-boot', 'host-uefi-vars',
234             'verbose-dynamic', 'verbose-static' ] }
235
236##
237# @FirmwareFormat:
238#
239# Formats that are supported for firmware images.
240#
241# @raw: Raw disk image format.
242#
243# @qcow2: The QCOW2 image format.
244#
245# Since: 3.0
246##
247{ 'enum': 'FirmwareFormat',
248  'data': [ 'raw', 'qcow2' ] }
249
250##
251# @FirmwareFlashFile:
252#
253# Defines common properties that are necessary for loading a firmware
254# file into a pflash chip. The corresponding QEMU command line option is
255# "-drive file=@filename,format=@format". Note however that the
256# option-argument shown here is incomplete; it is completed under
257# @FirmwareMappingFlash.
258#
259# @filename: Specifies the filename on the host filesystem where the
260#            firmware file can be found.
261#
262# @format: Specifies the block format of the file pointed-to by
263#          @filename, such as @raw or @qcow2.
264#
265# Since: 3.0
266##
267{ 'struct' : 'FirmwareFlashFile',
268  'data'   : { 'filename' : 'str',
269               'format'   : 'FirmwareFormat' } }
270
271
272##
273# @FirmwareFlashMode:
274#
275# Describes how the firmware build handles code versus variable
276# persistence.
277#
278# @split: the executable file contains code while the NVRAM
279#         template provides variable storage. The executable
280#         must be configured read-only and can be shared between
281#         multiple guests. The NVRAM template must be cloned
282#         for each new guest and configured read-write.
283#
284# @combined: the executable file contains both code and
285#            variable storage. The executable must be cloned
286#            for each new guest and configured read-write.
287#            No NVRAM template will be specified.
288#
289# @stateless: the executable file contains code and variable
290#             storage is not persisted. The executable must
291#             be configured read-only and can be shared
292#             between multiple guests. No NVRAM template
293#             will be specified.
294#
295# Since: 7.0.0
296##
297{ 'enum': 'FirmwareFlashMode',
298  'data': [ 'split', 'combined', 'stateless' ] }
299
300##
301# @FirmwareMappingFlash:
302#
303# Describes loading and mapping properties for the firmware executable
304# and its accompanying NVRAM file, when @FirmwareDevice is @flash.
305#
306# @mode: Describes how the firmware build handles code versus variable
307#        storage. If not present, it must be treated as if it was
308#        configured with value @split. Since: 7.0.0
309#
310# @executable: Identifies the firmware executable. The @mode
311#              indicates whether there will be an associated
312#              NVRAM template present. The preferred
313#              corresponding QEMU command line options are
314#                  -drive if=none,id=pflash0,readonly=on,file=@executable.@filename,format=@executable.@format
315#                  -machine pflash0=pflash0
316#              or equivalent -blockdev instead of -drive. When
317#              @mode is @combined the executable must be
318#              cloned before use and configured with readonly=off.
319#              With QEMU versions older than 4.0, you have to use
320#                  -drive if=pflash,unit=0,readonly=on,file=@executable.@filename,format=@executable.@format
321#
322# @nvram-template: Identifies the NVRAM template compatible with
323#                  @executable, when @mode is set to @split,
324#                  otherwise it should not be present.
325#                  Management software instantiates an
326#                  individual copy -- a specific NVRAM file -- from
327#                  @nvram-template.@filename for each new virtual
328#                  machine definition created. @nvram-template.@filename
329#                  itself is never mapped into virtual machines, only
330#                  individual copies of it are. An NVRAM file is
331#                  typically used for persistently storing the
332#                  non-volatile UEFI variables of a virtual machine
333#                  definition. The preferred corresponding QEMU
334#                  command line options are
335#                      -drive if=none,id=pflash1,readonly=off,file=FILENAME_OF_PRIVATE_NVRAM_FILE,format=@nvram-template.@format
336#                      -machine pflash1=pflash1
337#                  or equivalent -blockdev instead of -drive.
338#                  With QEMU versions older than 4.0, you have to use
339#                      -drive if=pflash,unit=1,readonly=off,file=FILENAME_OF_PRIVATE_NVRAM_FILE,format=@nvram-template.@format
340#
341# Since: 3.0
342##
343{ 'struct' : 'FirmwareMappingFlash',
344  'data'   : { '*mode': 'FirmwareFlashMode',
345               'executable'     : 'FirmwareFlashFile',
346               '*nvram-template' : 'FirmwareFlashFile' } }
347
348##
349# @FirmwareMappingKernel:
350#
351# Describes loading and mapping properties for the firmware executable,
352# when @FirmwareDevice is @kernel.
353#
354# @filename: Identifies the firmware executable. The firmware executable
355#            may be shared by multiple virtual machine definitions. The
356#            corresponding QEMU command line option is "-kernel
357#            @filename".
358#
359# Since: 3.0
360##
361{ 'struct' : 'FirmwareMappingKernel',
362  'data'   : { 'filename' : 'str' } }
363
364##
365# @FirmwareMappingMemory:
366#
367# Describes loading and mapping properties for the firmware executable,
368# when @FirmwareDevice is @memory.
369#
370# @filename: Identifies the firmware executable. The firmware executable
371#            may be shared by multiple virtual machine definitions. The
372#            corresponding QEMU command line option is "-bios
373#            @filename".
374#
375# Since: 3.0
376##
377{ 'struct' : 'FirmwareMappingMemory',
378  'data'   : { 'filename' : 'str' } }
379
380##
381# @FirmwareMapping:
382#
383# Provides a discriminated structure for firmware to describe its
384# loading / mapping properties.
385#
386# @device: Selects the device type that the firmware must be mapped
387#          into.
388#
389# Since: 3.0
390##
391{ 'union'         : 'FirmwareMapping',
392  'base'          : { 'device' : 'FirmwareDevice' },
393  'discriminator' : 'device',
394  'data'          : { 'flash'  : 'FirmwareMappingFlash',
395                      'kernel' : 'FirmwareMappingKernel',
396                      'memory' : 'FirmwareMappingMemory' } }
397
398##
399# @Firmware:
400#
401# Describes a firmware (or a firmware use case) to management software.
402#
403# It is possible for multiple @Firmware elements to match the search
404# criteria of management software. Applications thus need rules to pick
405# one of the many matches, and users need the ability to override distro
406# defaults.
407#
408# It is recommended to create firmware JSON files (each containing a
409# single @Firmware root element) with a double-digit prefix, for example
410# "50-ovmf.json", "50-seabios-256k.json", etc, so they can be sorted in
411# predictable order. The firmware JSON files should be searched for in
412# three directories:
413#
414#   - /usr/share/qemu/firmware -- populated by distro-provided firmware
415#                                 packages (XDG_DATA_DIRS covers
416#                                 /usr/share by default),
417#
418#   - /etc/qemu/firmware -- exclusively for sysadmins' local additions,
419#
420#   - $XDG_CONFIG_HOME/qemu/firmware -- exclusively for per-user local
421#                                       additions (XDG_CONFIG_HOME
422#                                       defaults to $HOME/.config).
423#
424# Top-down, the list of directories goes from general to specific.
425#
426# Management software should build a list of files from all three
427# locations, then sort the list by filename (i.e., last pathname
428# component). Management software should choose the first JSON file on
429# the sorted list that matches the search criteria. If a more specific
430# directory has a file with same name as a less specific directory, then
431# the file in the more specific directory takes effect. If the more
432# specific file is zero length, it hides the less specific one.
433#
434# For example, if a distro ships
435#
436#   - /usr/share/qemu/firmware/50-ovmf.json
437#
438#   - /usr/share/qemu/firmware/50-seabios-256k.json
439#
440# then the sysadmin can prevent the default OVMF being used at all with
441#
442#   $ touch /etc/qemu/firmware/50-ovmf.json
443#
444# The sysadmin can replace/alter the distro default OVMF with
445#
446#   $ vim /etc/qemu/firmware/50-ovmf.json
447#
448# or they can provide a parallel OVMF with higher priority
449#
450#   $ vim /etc/qemu/firmware/10-ovmf.json
451#
452# or they can provide a parallel OVMF with lower priority
453#
454#   $ vim /etc/qemu/firmware/99-ovmf.json
455#
456# @description: Provides a human-readable description of the firmware.
457#               Management software may or may not display @description.
458#
459# @interface-types: Lists the types of interfaces that the firmware can
460#                   expose to the guest OS. This is a non-empty, ordered
461#                   list; entries near the beginning of @interface-types
462#                   are considered more native to the firmware, and/or
463#                   to have a higher quality implementation in the
464#                   firmware, than entries near the end of
465#                   @interface-types.
466#
467# @mapping: Describes the loading / mapping properties of the firmware.
468#
469# @targets: Collects the target architectures (QEMU system emulators)
470#           and their machine types that may execute the firmware.
471#
472# @features: Lists the features that the firmware supports, and the
473#            platform requirements it presents.
474#
475# @tags: A list of auxiliary strings associated with the firmware for
476#        which @description is not appropriate, due to the latter's
477#        possible exposure to the end-user. @tags serves development and
478#        debugging purposes only, and management software shall
479#        explicitly ignore it.
480#
481# Since: 3.0
482#
483# .. qmp-example::
484#
485#     {
486#         "description": "SeaBIOS",
487#         "interface-types": [
488#             "bios"
489#         ],
490#         "mapping": {
491#             "device": "memory",
492#             "filename": "/usr/share/seabios/bios-256k.bin"
493#         },
494#         "targets": [
495#             {
496#                 "architecture": "i386",
497#                 "machines": [
498#                     "pc-i440fx-*",
499#                     "pc-q35-*"
500#                 ]
501#             },
502#             {
503#                 "architecture": "x86_64",
504#                 "machines": [
505#                     "pc-i440fx-*",
506#                     "pc-q35-*"
507#                 ]
508#             }
509#         ],
510#         "features": [
511#             "acpi-s3",
512#             "acpi-s4"
513#         ],
514#         "tags": [
515#             "CONFIG_BOOTSPLASH=n",
516#             "CONFIG_ROM_SIZE=256",
517#             "CONFIG_USE_SMM=n"
518#         ]
519#     }
520#
521#     {
522#         "description": "OVMF with SB+SMM, empty varstore",
523#         "interface-types": [
524#             "uefi"
525#         ],
526#         "mapping": {
527#             "device": "flash",
528#             "executable": {
529#                 "filename": "/usr/share/OVMF/OVMF_CODE.secboot.fd",
530#                 "format": "raw"
531#             },
532#             "nvram-template": {
533#                 "filename": "/usr/share/OVMF/OVMF_VARS.fd",
534#                 "format": "raw"
535#             }
536#         },
537#         "targets": [
538#             {
539#                 "architecture": "x86_64",
540#                 "machines": [
541#                     "pc-q35-*"
542#                 ]
543#             }
544#         ],
545#         "features": [
546#             "acpi-s3",
547#             "amd-sev",
548#             "requires-smm",
549#             "secure-boot",
550#             "verbose-dynamic"
551#         ],
552#         "tags": [
553#             "-a IA32",
554#             "-a X64",
555#             "-p OvmfPkg/OvmfPkgIa32X64.dsc",
556#             "-t GCC48",
557#             "-b DEBUG",
558#             "-D SMM_REQUIRE",
559#             "-D SECURE_BOOT_ENABLE",
560#             "-D FD_SIZE_4MB"
561#         ]
562#     }
563#
564#     {
565#         "description": "OVMF with SB+SMM, SB enabled, MS certs enrolled",
566#         "interface-types": [
567#             "uefi"
568#         ],
569#         "mapping": {
570#             "device": "flash",
571#             "executable": {
572#                 "filename": "/usr/share/OVMF/OVMF_CODE.secboot.fd",
573#                 "format": "raw"
574#             },
575#             "nvram-template": {
576#                 "filename": "/usr/share/OVMF/OVMF_VARS.secboot.fd",
577#                 "format": "raw"
578#             }
579#         },
580#         "targets": [
581#             {
582#                 "architecture": "x86_64",
583#                 "machines": [
584#                     "pc-q35-*"
585#                 ]
586#             }
587#         ],
588#         "features": [
589#             "acpi-s3",
590#             "amd-sev",
591#             "enrolled-keys",
592#             "requires-smm",
593#             "secure-boot",
594#             "verbose-dynamic"
595#         ],
596#         "tags": [
597#             "-a IA32",
598#             "-a X64",
599#             "-p OvmfPkg/OvmfPkgIa32X64.dsc",
600#             "-t GCC48",
601#             "-b DEBUG",
602#             "-D SMM_REQUIRE",
603#             "-D SECURE_BOOT_ENABLE",
604#             "-D FD_SIZE_4MB"
605#         ]
606#     }
607#
608#     {
609#         "description": "OVMF with SEV-ES support",
610#         "interface-types": [
611#             "uefi"
612#         ],
613#         "mapping": {
614#             "device": "flash",
615#             "executable": {
616#                 "filename": "/usr/share/OVMF/OVMF_CODE.fd",
617#                 "format": "raw"
618#             },
619#             "nvram-template": {
620#                 "filename": "/usr/share/OVMF/OVMF_VARS.fd",
621#                 "format": "raw"
622#             }
623#         },
624#         "targets": [
625#             {
626#                 "architecture": "x86_64",
627#                 "machines": [
628#                     "pc-q35-*"
629#                 ]
630#             }
631#         ],
632#         "features": [
633#             "acpi-s3",
634#             "amd-sev",
635#             "amd-sev-es",
636#             "verbose-dynamic"
637#         ],
638#         "tags": [
639#             "-a X64",
640#             "-p OvmfPkg/OvmfPkgX64.dsc",
641#             "-t GCC48",
642#             "-b DEBUG",
643#             "-D FD_SIZE_4MB"
644#         ]
645#     }
646#
647#     {
648#         "description": "UEFI firmware for ARM64 virtual machines",
649#         "interface-types": [
650#             "uefi"
651#         ],
652#         "mapping": {
653#             "device": "flash",
654#             "executable": {
655#                 "filename": "/usr/share/AAVMF/AAVMF_CODE.fd",
656#                 "format": "raw"
657#             },
658#             "nvram-template": {
659#                 "filename": "/usr/share/AAVMF/AAVMF_VARS.fd",
660#                 "format": "raw"
661#             }
662#         },
663#         "targets": [
664#             {
665#                 "architecture": "aarch64",
666#                 "machines": [
667#                     "virt-*"
668#                 ]
669#             }
670#         ],
671#         "features": [
672#
673#         ],
674#         "tags": [
675#             "-a AARCH64",
676#             "-p ArmVirtPkg/ArmVirtQemu.dsc",
677#             "-t GCC48",
678#             "-b DEBUG",
679#             "-D DEBUG_PRINT_ERROR_LEVEL=0x80000000"
680#         ]
681#     }
682##
683{ 'struct' : 'Firmware',
684  'data'   : { 'description'     : 'str',
685               'interface-types' : [ 'FirmwareOSInterface' ],
686               'mapping'         : 'FirmwareMapping',
687               'targets'         : [ 'FirmwareTarget' ],
688               'features'        : [ 'FirmwareFeature' ],
689               'tags'            : [ 'str' ] } }
690