diff --git a/misc/config_tools/data/cfl-k700-i7/hybrid.xml b/misc/config_tools/data/cfl-k700-i7/hybrid.xml
index 5634c505a..975d03c51 100644
--- a/misc/config_tools/data/cfl-k700-i7/hybrid.xml
+++ b/misc/config_tools/data/cfl-k700-i7/hybrid.xml
@@ -32,8 +32,7 @@
y
n
n
-
-
+
0x2000
@@ -67,13 +66,12 @@
- STANDARD_VM
PRE_LAUNCHED_VM
+ STANDARD_VM
SAFETY_VM0
3
-
0
@@ -106,10 +104,11 @@
n
n
+
- STANDARD_VM
SERVICE_VM
+ STANDARD_VM
ACRN_Service_VM
0
@@ -146,8 +145,8 @@
- STANDARD_VM
POST_LAUNCHED_VM
+ STANDARD_VM
POST_STD_VM1
2
@@ -170,8 +169,8 @@
n
- STANDARD_VM
POST_LAUNCHED_VM
+ STANDARD_VM
POST_STD_VM2
2
diff --git a/misc/config_tools/data/cfl-k700-i7/hybrid_rt.xml b/misc/config_tools/data/cfl-k700-i7/hybrid_rt.xml
index b8d6bd03b..0d329d179 100644
--- a/misc/config_tools/data/cfl-k700-i7/hybrid_rt.xml
+++ b/misc/config_tools/data/cfl-k700-i7/hybrid_rt.xml
@@ -73,8 +73,8 @@
- RTVM
PRE_LAUNCHED_VM
+ RTVM
PRE_RT_VM0
y
@@ -113,18 +113,26 @@
INVALID_PCI_BASE
+
+ n
+
00:1f.6 Ethernet controller: Intel Corporation Ethernet Connection (7) I219-LM (rev 10)
01:00.0 Non-Volatile memory controller: Silicon Motion, Inc. SM2263EN/SM2263XT SSD Controller (rev 03)
-
- n
-
- STANDARD_VM
SERVICE_VM
+ STANDARD_VM
ACRN_Service_VM
+
+ 0
+ 1
+ 2
+ 3
+ 4
+ 5
+
0
0
@@ -143,14 +151,6 @@
root=/dev/nvme0n1p3 rw rootwait console=ttyS0,115200n8 ignore_loglevel no_timer_check
-
- 0
- 1
- 2
- 3
- 4
- 5
-
VUART_LEGACY_PIO
SERVICE_VM_COM1_BASE
@@ -164,8 +164,8 @@
- STANDARD_VM
POST_LAUNCHED_VM
+ STANDARD_VM
POST_STD_VM1
1
@@ -192,8 +192,8 @@
n
- STANDARD_VM
POST_LAUNCHED_VM
+ STANDARD_VM
POST_STD_VM2
4
diff --git a/misc/config_tools/data/cfl-k700-i7/partitioned.xml b/misc/config_tools/data/cfl-k700-i7/partitioned.xml
index 32071cf89..f2297e51b 100644
--- a/misc/config_tools/data/cfl-k700-i7/partitioned.xml
+++ b/misc/config_tools/data/cfl-k700-i7/partitioned.xml
@@ -32,8 +32,7 @@
y
n
n
-
-
+
0x2000
@@ -67,8 +66,8 @@
- STANDARD_VM
PRE_LAUNCHED_VM
+ STANDARD_VM
PRE_STD_VM0
0
@@ -104,18 +103,18 @@
INVALID_PCI_BASE
+
+ n
+
00:17.0 SATA controller: Intel Corporation Cannon Lake PCH SATA AHCI Controller (rev 10)
00:1f.6 Ethernet controller: Intel Corporation Ethernet Connection (7) I219-LM (rev 10)
-
- n
-
- STANDARD_VM
PRE_LAUNCHED_VM
+ STANDARD_VM
PRE_STD_VM1
1
@@ -152,12 +151,12 @@
INVALID_PCI_BASE
+
+ n
+
00:14.0 USB controller: Intel Corporation Cannon Lake PCH USB 3.1 xHCI Host Controller (rev 10)
-
- n
-
diff --git a/misc/config_tools/data/cfl-k700-i7/shared.xml b/misc/config_tools/data/cfl-k700-i7/shared.xml
index 5c088c4cb..726b4f05f 100644
--- a/misc/config_tools/data/cfl-k700-i7/shared.xml
+++ b/misc/config_tools/data/cfl-k700-i7/shared.xml
@@ -24,8 +24,7 @@
y
n
n
-
-
+
0x2000
@@ -60,8 +59,8 @@
- STANDARD_VM
SERVICE_VM
+ STANDARD_VM
ACRN_Service_VM
0
@@ -91,8 +90,8 @@
- STANDARD_VM
POST_LAUNCHED_VM
+ STANDARD_VM
POST_STD_VM1
0
@@ -116,8 +115,8 @@
- RTVM
POST_LAUNCHED_VM
+ RTVM
POST_RT_VM1
2
@@ -142,8 +141,8 @@
n
- STANDARD_VM
POST_LAUNCHED_VM
+ STANDARD_VM
POST_STD_VM2
0
@@ -168,8 +167,8 @@
n
- STANDARD_VM
POST_LAUNCHED_VM
+ STANDARD_VM
POST_STD_VM3
0
@@ -194,8 +193,8 @@
n
- STANDARD_VM
POST_LAUNCHED_VM
+ STANDARD_VM
POST_STD_VM4
0
@@ -220,8 +219,8 @@
n
- STANDARD_VM
POST_LAUNCHED_VM
+ STANDARD_VM
POST_STD_VM5
0
diff --git a/misc/config_tools/data/generic_board/hybrid.xml b/misc/config_tools/data/generic_board/hybrid.xml
index bdff6a8e1..d6b3fd8a6 100644
--- a/misc/config_tools/data/generic_board/hybrid.xml
+++ b/misc/config_tools/data/generic_board/hybrid.xml
@@ -32,8 +32,7 @@
y
n
n
-
-
+
0x2000
@@ -67,13 +66,12 @@
- STANDARD_VM
PRE_LAUNCHED_VM
+ STANDARD_VM
SAFETY_VM0
3
-
0
@@ -102,17 +100,18 @@
INVALID_PCI_BASE
-
-
-
n
n
+
+
+
+
- STANDARD_VM
SERVICE_VM
+ STANDARD_VM
ACRN_Service_VM
0
@@ -148,8 +147,8 @@
- STANDARD_VM
POST_LAUNCHED_VM
+ STANDARD_VM
POST_STD_VM1
2
@@ -172,8 +171,8 @@
n
- STANDARD_VM
POST_LAUNCHED_VM
+ STANDARD_VM
POST_STD_VM2
2
diff --git a/misc/config_tools/data/generic_board/hybrid_rt.xml b/misc/config_tools/data/generic_board/hybrid_rt.xml
index 675199db9..5ce6c4f8e 100644
--- a/misc/config_tools/data/generic_board/hybrid_rt.xml
+++ b/misc/config_tools/data/generic_board/hybrid_rt.xml
@@ -86,8 +86,8 @@
- RTVM
PRE_LAUNCHED_VM
+ RTVM
PRE_RT_VM0
y
@@ -123,17 +123,17 @@
INVALID_PCI_BASE
+
+ n
+
00:17.0 SATA controller: Intel Corporation Device a0d3 (rev 20)
58:00.0 Ethernet controller: Intel Corporation Device 15f2 (rev 03)
-
- n
-
- STANDARD_VM
SERVICE_VM
+ STANDARD_VM
ACRN_Service_VM
0
@@ -167,8 +167,8 @@
- STANDARD_VM
POST_LAUNCHED_VM
+ STANDARD_VM
POST_STD_VM1
0
@@ -193,8 +193,8 @@
n
- STANDARD_VM
POST_LAUNCHED_VM
+ STANDARD_VM
POST_STD_VM2
1
diff --git a/misc/config_tools/data/generic_board/partitioned.xml b/misc/config_tools/data/generic_board/partitioned.xml
index 604b5facd..960154afa 100644
--- a/misc/config_tools/data/generic_board/partitioned.xml
+++ b/misc/config_tools/data/generic_board/partitioned.xml
@@ -32,8 +32,7 @@
y
n
n
-
-
+
0x2000
@@ -67,8 +66,8 @@
- STANDARD_VM
PRE_LAUNCHED_VM
+ STANDARD_VM
PRE_STD_VM0
0
@@ -104,18 +103,18 @@
INVALID_PCI_BASE
+
+ n
+
00:17.0 SATA controller: Intel Corporation Device a0d3 (rev 20)
58:00.0 Ethernet controller: Intel Corporation Device 15f2 (rev 03)
-
- n
-
- STANDARD_VM
PRE_LAUNCHED_VM
+ STANDARD_VM
PRE_STD_VM1
1
@@ -152,12 +151,12 @@
INVALID_PCI_BASE
+
+ n
+
00:14.0 USB controller: Intel Corporation Device a0ed (rev 20)
-
- n
-
diff --git a/misc/config_tools/data/generic_board/shared.xml b/misc/config_tools/data/generic_board/shared.xml
index 468ee62b4..879b106ee 100644
--- a/misc/config_tools/data/generic_board/shared.xml
+++ b/misc/config_tools/data/generic_board/shared.xml
@@ -32,8 +32,7 @@
y
n
n
-
-
+
0x2000
@@ -67,8 +66,8 @@
- STANDARD_VM
SERVICE_VM
+ STANDARD_VM
ACRN_Service_VM
0
@@ -98,8 +97,8 @@
- STANDARD_VM
POST_LAUNCHED_VM
+ STANDARD_VM
POST_STD_VM1
0
@@ -124,8 +123,8 @@
n
- RTVM
POST_LAUNCHED_VM
+ RTVM
POST_RT_VM1
y
@@ -151,8 +150,8 @@
n
- STANDARD_VM
POST_LAUNCHED_VM
+ STANDARD_VM
POST_STD_VM2
0
@@ -177,8 +176,8 @@
n
- STANDARD_VM
POST_LAUNCHED_VM
+ STANDARD_VM
POST_STD_VM3
0
@@ -203,8 +202,8 @@
n
- STANDARD_VM
POST_LAUNCHED_VM
+ STANDARD_VM
POST_STD_VM4
0
@@ -229,8 +228,8 @@
n
- STANDARD_VM
POST_LAUNCHED_VM
+ STANDARD_VM
POST_STD_VM5
0
diff --git a/misc/config_tools/data/nuc11tnbi5/hybrid.xml b/misc/config_tools/data/nuc11tnbi5/hybrid.xml
index f30a9303d..786afc414 100644
--- a/misc/config_tools/data/nuc11tnbi5/hybrid.xml
+++ b/misc/config_tools/data/nuc11tnbi5/hybrid.xml
@@ -32,8 +32,7 @@
y
n
n
-
-
+
0x2000
@@ -67,13 +66,12 @@
- STANDARD_VM
PRE_LAUNCHED_VM
+ STANDARD_VM
SAFETY_VM0
3
-
0
@@ -102,17 +100,18 @@
INVALID_PCI_BASE
-
-
-
n
n
+
+
+
+
- STANDARD_VM
SERVICE_VM
+ STANDARD_VM
ACRN_Service_VM
0
@@ -148,8 +147,8 @@
- STANDARD_VM
POST_LAUNCHED_VM
+ STANDARD_VM
POST_STD_VM1
2
@@ -172,8 +171,8 @@
n
- STANDARD_VM
POST_LAUNCHED_VM
+ STANDARD_VM
POST_STD_VM2
2
diff --git a/misc/config_tools/data/nuc11tnbi5/partitioned.xml b/misc/config_tools/data/nuc11tnbi5/partitioned.xml
index c0e1e3023..d01612cb6 100644
--- a/misc/config_tools/data/nuc11tnbi5/partitioned.xml
+++ b/misc/config_tools/data/nuc11tnbi5/partitioned.xml
@@ -32,8 +32,7 @@
y
n
n
-
-
+
0x2000
@@ -67,8 +66,8 @@
- STANDARD_VM
PRE_LAUNCHED_VM
+ STANDARD_VM
PRE_STD_VM0
0
@@ -104,18 +103,18 @@
INVALID_PCI_BASE
+
+ n
+
00:17.0 SATA controller: Intel Corporation Device a0d3 (rev 20)
58:00.0 Ethernet controller: Intel Corporation Device 15f2 (rev 03)
-
- n
-
- STANDARD_VM
PRE_LAUNCHED_VM
+ STANDARD_VM
PRE_STD_VM1
1
@@ -152,12 +151,12 @@
INVALID_PCI_BASE
+
+ n
+
00:14.0 USB controller: Intel Corporation Device a0ed (rev 20)
-
- n
-
diff --git a/misc/config_tools/data/nuc11tnbi5/shared.xml b/misc/config_tools/data/nuc11tnbi5/shared.xml
index 1e47addd3..aabaec630 100644
--- a/misc/config_tools/data/nuc11tnbi5/shared.xml
+++ b/misc/config_tools/data/nuc11tnbi5/shared.xml
@@ -32,8 +32,7 @@
y
n
n
-
-
+
0x2000
@@ -79,8 +78,8 @@
- STANDARD_VM
SERVICE_VM
+ STANDARD_VM
ACRN_Service_VM
0
@@ -110,8 +109,8 @@
- STANDARD_VM
POST_LAUNCHED_VM
+ STANDARD_VM
POST_STD_VM1
0
@@ -136,8 +135,8 @@
n
- RTVM
POST_LAUNCHED_VM
+ RTVM
POST_RT_VM1
y
@@ -163,8 +162,8 @@
n
- STANDARD_VM
POST_LAUNCHED_VM
+ STANDARD_VM
POST_STD_VM2
0
@@ -189,8 +188,8 @@
n
- STANDARD_VM
POST_LAUNCHED_VM
+ STANDARD_VM
POST_STD_VM3
0
@@ -215,8 +214,8 @@
n
- STANDARD_VM
POST_LAUNCHED_VM
+ STANDARD_VM
POST_STD_VM4
0
@@ -241,8 +240,8 @@
n
- STANDARD_VM
POST_LAUNCHED_VM
+ STANDARD_VM
POST_STD_VM5
0
diff --git a/misc/config_tools/data/qemu/shared.xml b/misc/config_tools/data/qemu/shared.xml
index 67dc43e15..f3e423b88 100644
--- a/misc/config_tools/data/qemu/shared.xml
+++ b/misc/config_tools/data/qemu/shared.xml
@@ -24,8 +24,7 @@
y
n
n
-
-
+
0x2000
@@ -60,8 +59,8 @@
- STANDARD_VM
SERVICE_VM
+ STANDARD_VM
ACRN_Service_VM
0
@@ -90,8 +89,8 @@
- STANDARD_VM
POST_LAUNCHED_VM
+ STANDARD_VM
POST_STD_VM1
1
diff --git a/misc/config_tools/data/tgl-vecow-spc-7100-Corei7/hybrid.xml b/misc/config_tools/data/tgl-vecow-spc-7100-Corei7/hybrid.xml
index 0f5f13d95..70d4afc9f 100644
--- a/misc/config_tools/data/tgl-vecow-spc-7100-Corei7/hybrid.xml
+++ b/misc/config_tools/data/tgl-vecow-spc-7100-Corei7/hybrid.xml
@@ -32,8 +32,7 @@
y
n
n
-
-
+
0x2000
@@ -67,13 +66,12 @@
- STANDARD_VM
PRE_LAUNCHED_VM
+ STANDARD_VM
SAFETY_VM0
3
-
0
@@ -102,17 +100,18 @@
INVALID_PCI_BASE
-
-
-
n
n
+
+
+
+
- STANDARD_VM
SERVICE_VM
+ STANDARD_VM
ACRN_Service_VM
0
@@ -149,8 +148,8 @@
- STANDARD_VM
POST_LAUNCHED_VM
+ STANDARD_VM
POST_STD_VM1
2
@@ -173,8 +172,8 @@
n
- STANDARD_VM
POST_LAUNCHED_VM
+ STANDARD_VM
POST_STD_VM2
2
diff --git a/misc/config_tools/data/tgl-vecow-spc-7100-Corei7/partitioned.xml b/misc/config_tools/data/tgl-vecow-spc-7100-Corei7/partitioned.xml
index fe82a8ea4..c4cd2c073 100644
--- a/misc/config_tools/data/tgl-vecow-spc-7100-Corei7/partitioned.xml
+++ b/misc/config_tools/data/tgl-vecow-spc-7100-Corei7/partitioned.xml
@@ -32,8 +32,7 @@
y
n
n
-
-
+
0x2000
@@ -67,8 +66,8 @@
- STANDARD_VM
PRE_LAUNCHED_VM
+ STANDARD_VM
PRE_STD_VM0
0
@@ -104,18 +103,18 @@
INVALID_PCI_BASE
+
+ n
+
00:17.0 SATA controller: Intel Corporation Device a0d3 (rev 20)
00:1f.6 Ethernet controller: Intel Corporation Ethernet Connection (13) I219-LM (rev 20)
-
- n
-
- STANDARD_VM
PRE_LAUNCHED_VM
+ STANDARD_VM
PRE_STD_VM1
1
@@ -139,7 +138,7 @@
YOCTO
KERNEL_BZIMAGE
Linux_bzImage
-
+
rw rootwait root=/dev/sda3 console=ttyS0 noxsave nohpet no_timer_check ignore_loglevel log_buf_len=16M
consoleblank=0 tsc=reliable reboot=acpi
@@ -152,12 +151,12 @@
INVALID_PCI_BASE
+
+ n
+
00:14.0 USB controller: Intel Corporation Tiger Lake-LP USB 3.2 Gen 2x1 xHCI Host Controller (rev 20)
-
- n
-
diff --git a/misc/config_tools/data/tgl-vecow-spc-7100-Corei7/shared.xml b/misc/config_tools/data/tgl-vecow-spc-7100-Corei7/shared.xml
index 7a9e6523b..ea22f11a0 100644
--- a/misc/config_tools/data/tgl-vecow-spc-7100-Corei7/shared.xml
+++ b/misc/config_tools/data/tgl-vecow-spc-7100-Corei7/shared.xml
@@ -32,8 +32,7 @@
y
n
n
-
-
+
0x2000
@@ -79,8 +78,8 @@
- STANDARD_VM
SERVICE_VM
+ STANDARD_VM
ACRN_Service_VM
0
@@ -111,8 +110,8 @@
- STANDARD_VM
POST_LAUNCHED_VM
+ STANDARD_VM
POST_STD_VM1
0
@@ -126,6 +125,7 @@
0
0
+ PRIO_LOW
VUART_LEGACY_PIO
COM1_BASE
@@ -135,11 +135,10 @@
INVALID_PCI_BASE
n
- PRIO_LOW
- RTVM
POST_LAUNCHED_VM
+ RTVM
POST_RT_VM1
y
@@ -154,6 +153,7 @@
0
0
+ PRIO_LOW
VUART_LEGACY_PIO
COM1_BASE
@@ -163,6 +163,5 @@
INVALID_PCI_BASE
n
- PRIO_LOW
diff --git a/misc/config_tools/data/whl-ipc-i5/hybrid.xml b/misc/config_tools/data/whl-ipc-i5/hybrid.xml
index f8151365b..8308199ae 100644
--- a/misc/config_tools/data/whl-ipc-i5/hybrid.xml
+++ b/misc/config_tools/data/whl-ipc-i5/hybrid.xml
@@ -24,8 +24,7 @@
y
n
n
-
-
+
0x2000
@@ -59,8 +58,8 @@
- STANDARD_VM
PRE_LAUNCHED_VM
+ STANDARD_VM
SAFETY_VM0
3
@@ -93,16 +92,16 @@
INVALID_PCI_BASE
-
-
-
n
+
+
+
- STANDARD_VM
SERVICE_VM
+ STANDARD_VM
ACRN_Service_VM
0
@@ -138,8 +137,8 @@
- STANDARD_VM
POST_LAUNCHED_VM
+ STANDARD_VM
POST_STD_VM1
2
diff --git a/misc/config_tools/data/whl-ipc-i5/hybrid_rt.xml b/misc/config_tools/data/whl-ipc-i5/hybrid_rt.xml
index 989aa4d3f..718e1e457 100644
--- a/misc/config_tools/data/whl-ipc-i5/hybrid_rt.xml
+++ b/misc/config_tools/data/whl-ipc-i5/hybrid_rt.xml
@@ -72,8 +72,8 @@
- RTVM
PRE_LAUNCHED_VM
+ RTVM
PRE_RT_VM0
y
@@ -112,17 +112,17 @@
INVALID_PCI_BASE
+
+ n
+
00:17.0 SATA controller: Intel Corporation Device 9dd3 (rev 30)
03:00.0 Ethernet controller: Intel Corporation I210 Gigabit Network Connection (rev 03)
-
- n
-
- STANDARD_VM
SERVICE_VM
+ STANDARD_VM
ACRN_Service_VM
0
@@ -156,8 +156,8 @@
- STANDARD_VM
POST_LAUNCHED_VM
+ STANDARD_VM
POST_STD_VM1
0
@@ -182,8 +182,8 @@
n
- STANDARD_VM
POST_LAUNCHED_VM
+ STANDARD_VM
POST_STD_VM2
1
diff --git a/misc/config_tools/data/whl-ipc-i5/partitioned.xml b/misc/config_tools/data/whl-ipc-i5/partitioned.xml
index 937dbdfa0..fe6456439 100644
--- a/misc/config_tools/data/whl-ipc-i5/partitioned.xml
+++ b/misc/config_tools/data/whl-ipc-i5/partitioned.xml
@@ -24,8 +24,7 @@
y
n
n
-
-
+
0x2000
@@ -59,8 +58,8 @@
- STANDARD_VM
PRE_LAUNCHED_VM
+ STANDARD_VM
PRE_STD_VM0
0
@@ -98,17 +97,17 @@
INVALID_PCI_BASE
+
+ n
+
00:17.0 SATA controller: Intel Corporation Cannon Point-LP SATA Controller [AHCI Mode] (rev 30)
04:00.0 Ethernet controller: Intel Corporation I210 Gigabit Network Connection (rev 03)
-
- n
-
- STANDARD_VM
PRE_LAUNCHED_VM
+ STANDARD_VM
PRE_STD_VM1
1
@@ -146,12 +145,12 @@
INVALID_PCI_BASE
+
+ n
+
00:14.0 USB controller: Intel Corporation Cannon Point-LP USB 3.1 xHCI Controller (rev 30)
03:00.0 Ethernet controller: Intel Corporation I210 Gigabit Network Connection (rev 03)
-
- n
-
diff --git a/misc/config_tools/data/whl-ipc-i5/sdc.xml b/misc/config_tools/data/whl-ipc-i5/sdc.xml
index 3f174c7f4..b2981ea69 100644
--- a/misc/config_tools/data/whl-ipc-i5/sdc.xml
+++ b/misc/config_tools/data/whl-ipc-i5/sdc.xml
@@ -24,8 +24,7 @@
y
n
n
-
-
+
0x2000
@@ -43,10 +42,11 @@
0x00000010
+
- STANDARD_VM
SERVICE_VM
+ STANDARD_VM
ACRN_Service_VM
0
@@ -75,8 +75,8 @@
- STANDARD_VM
POST_LAUNCHED_VM
+ STANDARD_VM
POST_STD_VM1
1
diff --git a/misc/config_tools/data/whl-ipc-i5/shared.xml b/misc/config_tools/data/whl-ipc-i5/shared.xml
index 9ec8457bf..6a9e4362b 100644
--- a/misc/config_tools/data/whl-ipc-i5/shared.xml
+++ b/misc/config_tools/data/whl-ipc-i5/shared.xml
@@ -24,8 +24,7 @@
y
n
n
-
-
+
0x2000
@@ -59,8 +58,8 @@
- STANDARD_VM
SERVICE_VM
+ STANDARD_VM
ACRN_Service_VM
0
@@ -90,8 +89,8 @@
- STANDARD_VM
POST_LAUNCHED_VM
+ STANDARD_VM
POST_STD_VM1
0
@@ -115,8 +114,8 @@
- RTVM
POST_LAUNCHED_VM
+ RTVM
POST_RT_VM1
2
@@ -141,8 +140,8 @@
n
- STANDARD_VM
POST_LAUNCHED_VM
+ STANDARD_VM
POST_STD_VM2
0
@@ -167,8 +166,8 @@
n
- STANDARD_VM
POST_LAUNCHED_VM
+ STANDARD_VM
POST_STD_VM3
0
@@ -193,8 +192,8 @@
n
- STANDARD_VM
POST_LAUNCHED_VM
+ STANDARD_VM
POST_STD_VM4
0
@@ -219,8 +218,8 @@
n
- STANDARD_VM
POST_LAUNCHED_VM
+ STANDARD_VM
POST_STD_VM5
0
diff --git a/misc/config_tools/scenario_config/upgrader.py b/misc/config_tools/scenario_config/upgrader.py
new file mode 100755
index 000000000..cdb1c0a4e
--- /dev/null
+++ b/misc/config_tools/scenario_config/upgrader.py
@@ -0,0 +1,508 @@
+#!/usr/bin/env python3
+#
+# Copyright (C) 2022 Intel Corporation.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+import os
+import argparse, logging
+import re
+from functools import lru_cache, partialmethod
+from collections import defaultdict, namedtuple
+import lxml.etree as etree
+
+from scenario_transformer import ScenarioTransformer
+
+from pipeline import PipelineObject, PipelineStage, PipelineEngine
+from lxml_loader import LXMLLoadStage
+from schema_slicer import SlicingSchemaByVMTypeStage
+
+class VirtualUartConnections:
+ class VirtualUartEndpoint:
+ # The BDF of PCI virtual UARTs starts from 00:10.0
+ next_dev = defaultdict(lambda: 16)
+
+ @classmethod
+ def from_endpoint_definition(cls, element):
+ # For v2.x style scenario XML, the name of the VM is a child of a `vm` node.
+ vm_name = element.xpath("ancestor::vm/name/text()").pop()
+ if "legacy" in element.tag:
+ base = element.find("base").text
+ io_port = \
+ "0x3F8" if base.endswith("COM1_BASE") else \
+ "0x2F8" if base.endswith("COM2_BASE") else \
+ "0x3E8" if base.endswith("COM3_BASE") else \
+ "0x2E8" if base.endswith("COM4_BASE") else \
+ base
+ return cls(vm_name, io_port = io_port)
+ else:
+ dev = cls.next_dev[vm_name]
+ cls.next_dev[vm_name] += 1
+ return cls(vm_name, pci_bdf = f"00:{dev:02x}.0")
+
+ def __init__(self, vm_name, io_port = None, pci_bdf = None):
+ self.vm_name = vm_name
+ self.io_port = io_port
+ self.pci_bdf = pci_bdf
+
+ class VirtualUartConnection:
+ next_id = 1
+
+ @classmethod
+ def from_connection_definition(cls, element):
+ name = element.find("name").text
+ ty = element.find("type").text
+ conn = cls(name = name, ty = ty)
+ for endpoint in element.findall("endpoint"):
+ vm_name_node = endpoint.find("vm_name")
+ vm_name = vm_name_node.text if vm_name_node is not None else ""
+ io_port_node = endpoint.find("io_port")
+ io_port = io_port_node.text if io_port_node is not None else None
+ vbdf_node = endpoint.find("vbdf")
+ vbdf = vbdf_node.text if vbdf_node is not None else None
+ conn.add_endpoint(VirtualUartConnections.VirtualUartEndpoint(vm_name, io_port, vbdf))
+ return conn
+
+ def __init__(self, name = None, ty = "legacy"):
+ if name:
+ self.name = name
+ else:
+ self.name = f"vUART connection {self.next_id}"
+ self.__class__.next_id += 1
+ self.ty = ty
+ self.endpoints = []
+
+ def add_endpoint(self, endpoint):
+ self.endpoints.append(endpoint)
+
+ def __init__(self):
+ self.conns = [] # List of connections
+ self.dangling_conns = {} # (vm_id, vuart_id) -> conn whose target is the key
+
+ def add_endpoint(self, element):
+ """Parse the vUART endpoint definition in ACRN v2.x. Returns True if and only if the element is parsed properly."""
+
+ try:
+ key = (element.xpath("ancestor::vm/@id").pop(), element.xpath("@id").pop())
+ if key in self.dangling_conns.keys():
+ conn = self.dangling_conns.pop(key)
+ conn.add_endpoint(self.VirtualUartEndpoint.from_endpoint_definition(element))
+ self.conns.append(conn)
+ else:
+ ty = "legacy" if "legacy" in element.tag else "pci"
+ conn = self.VirtualUartConnection(ty = ty)
+ conn.add_endpoint(self.VirtualUartEndpoint.from_endpoint_definition(element))
+ self.dangling_conns[(element.xpath("target_vm_id/text()").pop(), element.xpath("target_uart_id/text()").pop())] = conn
+
+ return True
+ except Exception as e:
+ # Skip vUART endpoint definition not satisfying the schema. The discarded-data warnings will report those
+ # unmigrated data.
+ logging.debug(e)
+ return False
+
+ def add_connection(self, element):
+ """Parse the vUART connection definition in ACRN v3.x"""
+ self.conns.append(self.VirtualUartConnection.from_connection_definition(element))
+ return True
+
+ def format_xml_elements(self, xsd_element_node):
+ new_parent_node = etree.Element(xsd_element_node.get("name"))
+ for conn in self.conns:
+ new_node = etree.Element("vuart_connection")
+ etree.SubElement(new_node, "name").text = conn.name
+ etree.SubElement(new_node, "type").text = conn.ty
+ for endpoint in conn.endpoints:
+ new_endpoint_node = etree.SubElement(new_node, "endpoint")
+ etree.SubElement(new_endpoint_node, "vm_name").text = endpoint.vm_name
+ if endpoint.io_port:
+ etree.SubElement(new_endpoint_node, "io_port").text = endpoint.io_port
+ if endpoint.pci_bdf:
+ etree.SubElement(new_endpoint_node, "vbdf").text = endpoint.pci_bdf
+ new_parent_node.append(new_node)
+ return [new_parent_node]
+
+class SharedMemoryRegions:
+ class SharedMemoryRegion(namedtuple("SharedMemoryRegion", ["name", "size", "shared_vms"])):
+ # The BDF of IVSHMEM PCI functions starts from 00:08.0
+ next_dev = defaultdict(lambda: 8)
+
+ @classmethod
+ def from_hypervisor_encoding(cls, text, old_xml_etree):
+ parts = [p.strip() for p in text[text.find("/") + 1 :].split(",")]
+ name = parts[0]
+ size = parts[1]
+ shared_vm_ids = parts[2].split(":")
+
+ shared_vms = []
+ for vm_id in shared_vm_ids:
+ vm_name_node = old_xml_etree.xpath(f"//vm[@id='{vm_id}']/name")
+ if not vm_name_node:
+ logging.warning(f"VM {vm_id}, which is referred by shared memory region {name}, is not defined in the scenario.")
+ continue
+
+ vm_name = vm_name_node[0].text
+ dev = cls.next_dev[vm_name]
+ cls.next_dev[vm_name] += 1
+ shared_vms.append((vm_name, f"00:{dev:02x}.0"))
+
+ return cls(name, size, shared_vms)
+
+ @classmethod
+ def from_xml_node(cls, node):
+ name = node.get("name")
+ size = node.find("IVSHMEM_SIZE").text
+ shared_vms = []
+ for shared_vm_node in node.find("IVSHMEM_VMS"):
+ vm_name = shared_vm_node.find("VM_NAME").text
+ vbdf = shared_vm_node.find("VBDF").text
+ shared_vms.append((vm_name, vbdf))
+ return cls(name, size, shared_vms)
+
+ def format_xml_element(self):
+ node = etree.Element("IVSHMEM_REGION")
+ node.set("name", self.name)
+ etree.SubElement(node, "IVSHMEM_SIZE").text = self.size
+
+ vms_node = etree.SubElement(node, "IVSHMEM_VMS")
+ for vm_name, vbdf in self.shared_vms:
+ vm_node = etree.SubElement(vms_node, "IVSHMEM_VM")
+ etree.SubElement(vm_node, "VM_NAME").text = vm_name
+ etree.SubElement(vm_node, "VBDF").text = vbdf
+
+ return node
+
+ def __init__(self, old_xml_etree):
+ self.old_xml_etree = old_xml_etree
+ self.regions = {}
+
+ def add_ivshmem_region(self, ivshmem_region_node):
+ """Parse IVSHMEM_REGION nodes in either v2.x and v3.x format."""
+
+ if len(ivshmem_region_node) == 0:
+ # ACRN v2.x format
+ region = self.SharedMemoryRegion.from_hypervisor_encoding(ivshmem_region_node.text, self.old_xml_etree)
+ self.regions[region.name] = region
+ else:
+ # ACRN v3.x format
+ region = self.SharedMemoryRegion.from_xml_node(ivshmem_region_node)
+ self.regions[region.name] = region
+
+ def format_xml_element(self):
+ node = etree.Element("IVSHMEM")
+ for region in self.regions.values():
+ node.append(region.format_xml_element())
+ return node
+
+class ScenarioUpgrader(ScenarioTransformer):
+ @classmethod
+ def get_node(cls, element, xpath):
+ return next(iter(element.xpath(xpath, namespaces=cls.xpath_ns)), None)
+
+ def __init__(self, xsd_etree, old_xml_etree):
+ super().__init__(xsd_etree, visit_optional_node=True)
+ self.old_xml_etree = old_xml_etree
+
+ # Collect all nodes in old_xml_etree which will be used to track data not moved
+ self.old_data_nodes = set()
+ for node in old_xml_etree.iter():
+ if node.text:
+ self.old_data_nodes.add(node)
+
+ self.hv_vm_node_map = {}
+
+ def get_from_old_data(self, new_parent_node, xpath):
+ hv_vm_node = new_parent_node
+ if hv_vm_node.tag not in ["vm", "hv"]:
+ hv_vm_node = next(new_parent_node.iterancestors(["vm", "hv"]), None)
+ old_hv_vm_node = self.hv_vm_node_map[hv_vm_node]
+ old_data_node = old_hv_vm_node.xpath(xpath)
+ return old_data_node
+
+ def move_legacy_vuart(self, xsd_element_node, xml_parent_node, new_nodes):
+ # Preserve the legacy vuart for console only.
+ legacy_vuart = self.get_from_old_data(xml_parent_node, ".//legacy_vuart[@id = '0']")
+ if legacy_vuart:
+ new_nodes.append(legacy_vuart[0])
+ for child in legacy_vuart[0].iter():
+ self.old_data_nodes.discard(child)
+ return False
+
+ def move_vuart_connections(self, xsd_element_node, xml_parent_node, new_nodes):
+ conns = VirtualUartConnections()
+
+ # Fetch vUART endpoints in the old data
+ vuart_endpoints = self.old_xml_etree.xpath("//legacy_vuart[@id != '0' and base != 'INVALID_COM_BASE'] | //communication_vuart[base != 'INVALID_PCI_BASE']")
+ vuart_connections = self.old_xml_etree.xpath("//vuart_connection")
+
+ for endpoint in vuart_endpoints:
+ if conns.add_endpoint(endpoint):
+ for child in endpoint.iter():
+ self.old_data_nodes.discard(child)
+
+ for connection in vuart_connections:
+ if conns.add_connection(connection):
+ for child in connection.iter():
+ self.old_data_nodes.discard(child)
+
+ new_nodes.extend(conns.format_xml_elements(xsd_element_node))
+
+ # Disconnected endpoints do not migrate, but remove such nodes from old_data_nodes to avoid raising
+ # data-is-discarded warnings.
+ for n in self.old_xml_etree.xpath("//legacy_vuart[@id != '0' and base = 'INVALID_COM_BASE'] | //communication_vuart[base = 'INVALID_PCI_BASE']"):
+ for child in n.iter():
+ self.old_data_nodes.discard(child)
+
+ return False
+
+ def move_ivshmem(self, xsd_element_node, xml_parent_node, new_nodes):
+ regions = SharedMemoryRegions(self.old_xml_etree)
+ for old_region in self.old_xml_etree.xpath("//IVSHMEM_REGION"):
+ regions.add_ivshmem_region(old_region)
+ for child in old_region.iter():
+ self.old_data_nodes.discard(child)
+ new_nodes.append(regions.format_xml_element())
+
+ return False
+
+ def move_vm_type(self, xsd_element_node, xml_parent_node, new_nodes):
+ old_vm_type_node = self.get_from_old_data(xml_parent_node, ".//vm_type").pop()
+ old_guest_flag_nodes = self.get_from_old_data(xml_parent_node, ".//guest_flag[text() = 'GUEST_FLAG_RT']")
+
+ new_node = etree.Element(xsd_element_node.get("name"))
+ if old_vm_type_node.text in ["PRE_RT_VM", "POST_RT_VM"] or old_guest_flag_nodes:
+ new_node.text = "RTVM"
+ elif old_vm_type_node.text in ["SAFETY_VM", "PRE_STD_VM", "POST_STD_VM"]:
+ new_node.text = "STANDARD_VM"
+ else:
+ new_node.text = old_vm_type_node.text
+ new_nodes.append(new_node)
+ self.old_data_nodes.discard(old_vm_type_node)
+ for n in old_guest_flag_nodes:
+ self.old_data_nodes.discard(n)
+
+ return False
+
+ def move_guest_flag(self, guest_flag, xsd_element_node, xml_parent_node, new_nodes):
+ old_data_nodes = self.get_from_old_data(xml_parent_node, f".//guest_flag[text() = '{guest_flag}']")
+ if old_data_nodes:
+ new_node = etree.Element(xsd_element_node.get("name"))
+ new_node.text = "y"
+ new_nodes.append(new_node)
+ for n in old_data_nodes:
+ self.old_data_nodes.discard(n)
+ else:
+ self.move_data_by_same_tag(xsd_element_node, xml_parent_node, new_nodes)
+
+ return False
+
+ def move_data_by_xpath(self, xpath, xsd_element_node, xml_parent_node, new_nodes):
+ element_tag = xsd_element_node.get("name")
+
+ old_data_nodes = self.get_from_old_data(xml_parent_node, xpath)
+ if self.complex_type_of_element(xsd_element_node) is None:
+ max_occurs_raw = xsd_element_node.get("maxOccurs")
+
+ # Use `len(old_data_nodes)` to ensure that all old data nodes are moved if an unbound number of
+ # occurrences is allowed.
+ max_occurs = \
+ len(old_data_nodes) if max_occurs_raw == "unbounded" else \
+ 1 if max_occurs_raw is None else \
+ int(max_occurs_raw)
+
+ if len(old_data_nodes) <= max_occurs:
+ for n in old_data_nodes:
+ new_node = etree.Element(element_tag)
+ new_node.text = n.text
+ for k, v in n.items():
+ new_node.set(k, v)
+ new_nodes.append(new_node)
+ self.old_data_nodes.discard(n)
+
+ return False
+ else:
+ # For each complex type containing multiple configuration items, this method can only create at most one
+ # single node, as there is no way for the default data movers to migrate multiple pieces of data of the same
+ # type to the new XML.
+ if old_data_nodes:
+ new_node = etree.Element(element_tag)
+ for k, v in old_data_nodes[0].items():
+ new_node.set(k, v)
+ new_nodes.append(new_node)
+ return True
+
+ def move_data_by_same_tag(self, xsd_element_node, xml_parent_node, new_nodes):
+ element_tag = xsd_element_node.get("name")
+ return self.move_data_by_xpath(f".//{element_tag}", xsd_element_node, xml_parent_node, new_nodes)
+
+ def move_data_null(self, xsd_element_node, xml_parent_node, new_nodes):
+ return False
+
+ data_movers = {
+ # Configuration items with the same name but under different parents
+ "vm/name": partialmethod(move_data_by_xpath, "./name"),
+ "os_config/name": partialmethod(move_data_by_xpath, ".//os_config/name"),
+ "epc_section/base": partialmethod(move_data_by_xpath, ".//epc_section/base"),
+ "console_vuart/base": partialmethod(move_data_by_xpath, ".//console_vuart/base"),
+ "epc_section/size": partialmethod(move_data_by_xpath, ".//epc_section/size"),
+ "memory/size": partialmethod(move_data_by_xpath, ".//memory/size"),
+
+ # Guest flags
+ "lapic_passthrough": partialmethod(move_guest_flag, "GUEST_FLAG_LAPIC_PASSTHROUGH"),
+ "io_completion_polling": partialmethod(move_guest_flag, "GUEST_FLAG_IO_COMPLETION_POLLING"),
+ "nested_virtualization_support": partialmethod(move_guest_flag, "GUEST_FLAG_NVMX_ENABLED"),
+ "virtual_cat_support": partialmethod(move_guest_flag, "GUEST_FLAG_VCAT_ENABLED"),
+ "secure_world_support": partialmethod(move_guest_flag, "GUEST_FLAG_SECURITY_VM"),
+ "hide_mtrr_support": partialmethod(move_guest_flag, "GUEST_FLAG_HIDE_MTRR"),
+ "security_vm": partialmethod(move_guest_flag, "GUEST_FLAG_SECURITY_VM"),
+
+ "legacy_vuart": move_legacy_vuart,
+ "vuart_connections": move_vuart_connections,
+ "IVSHMEM": move_ivshmem,
+ "vm_type": move_vm_type,
+
+ "default": move_data_by_same_tag,
+ }
+
+ def add_missing_nodes(self, xsd_element_node, xml_parent_node, xml_anchor_node):
+ new_nodes = []
+ def call_mover(mover):
+ if isinstance(mover, partialmethod):
+ return mover.__get__(self, type(self))(xsd_element_node, xml_parent_node, new_nodes)
+ else:
+ return mover(self, xsd_element_node, xml_parent_node, new_nodes)
+
+ # Common names (such as 'name' or 'base') may be used as tags in multiple places each of which has different
+ # meanings. In such cases it is ambiguious to query old data by that common tag alone.
+ element_tag = xsd_element_node.get("name")
+ element_tag_with_parent = f"{xml_parent_node.tag}/{element_tag}"
+
+ mover_key = \
+ element_tag_with_parent if element_tag_with_parent in self.data_movers.keys() else \
+ element_tag if element_tag in self.data_movers.keys() else \
+ "default"
+ visit_children = call_mover(self.data_movers[mover_key])
+
+ if xml_anchor_node is not None:
+ for n in new_nodes:
+ xml_anchor_node.addprevious(n)
+ else:
+ xml_parent_node.extend(new_nodes)
+
+ if visit_children:
+ return new_nodes
+ else:
+ return []
+
+ @property
+ @lru_cache
+ def upgraded_etree(self):
+ new_xml_etree = etree.ElementTree(etree.Element(self.old_xml_etree.getroot().tag))
+ root_node = new_xml_etree.getroot()
+ for k, v in self.old_xml_etree.getroot().items():
+ new_xml_etree.getroot().set(k, v)
+
+ # Migrate the HV and VM nodes, which are needed to kick off a thorough traversal of the existing scenario.
+ for old_node in self.old_xml_etree.getroot():
+ new_node = etree.Element(old_node.tag)
+
+ if old_node.tag == "vm":
+ # FIXME: Here we still hard code how the load order of a VM is specified in different versions of
+ # schemas. While it is not subject to frequent changes, it would be better if we use a more generic
+ # approach instead.
+ load_order_node = etree.SubElement(new_node, "load_order")
+
+ # In the history we have two ways of specifying the load order of a VM: either by vm_type or by
+ # loader_order.
+ vm_type = old_node.xpath(".//vm_type/text()")
+ old_load_order_node = old_node.xpath(".//load_order")
+ if old_load_order_node:
+ load_order_node.text = old_load_order_node[0].text
+ self.old_data_nodes.discard(old_load_order_node[0])
+ elif vm_type:
+ if vm_type[0].startswith("PRE_") or vm_type[0] in ["SAFETY_VM"]:
+ load_order_node.text = "PRE_LAUNCHED_VM"
+ elif vm_type[0].startswith("POST_"):
+ load_order_node.text = "POST_LAUNCHED_VM"
+ else:
+ load_order_node.text = "SERVICE_VM"
+ else:
+ logging.error(f"Cannot infer the loader order of VM {self.old_xml_etree.getelementpath(old_node)}")
+ continue
+
+ root_node.append(new_node)
+ for k, v in old_node.items():
+ new_node.set(k, v)
+ self.hv_vm_node_map[new_node] = old_node
+
+ # Now fill the rest of configuration items using the old data
+ self.transform(new_xml_etree)
+
+ return new_xml_etree
+
+class UpgradingScenarioStage(PipelineStage):
+ uses = {"schema_etree", "scenario_etree"}
+ provides = {"scenario_etree"}
+
+ class DiscardedDataFilter(namedtuple("DiscardedDataFilter", ["path", "data", "info"])):
+ def filter(self, path, data):
+ simp_path = re.sub(r"\[[^\]]*\]", "", path)
+ if not simp_path.endswith(self.path):
+ return False
+ if self.data and data != self.data:
+ return False
+
+ if self.info:
+ logging.info(f"{path} = '{data}': {self.info}")
+ return True
+
+ filters = [
+ DiscardedDataFilter("hv/FEATURES/IVSHMEM", None, "IVSHMEM is now automatically enabled if any IVSHMEM region is specified."),
+ DiscardedDataFilter("hv/FEATURES/NVMX_ENABLED", None, "Nest virtualization support is now automatically included if enabled for any VM."),
+ DiscardedDataFilter("hv/MISC_CFG/UEFI_OS_LOADER_NAME", None, None),
+ DiscardedDataFilter("vm/guest_flags/guest_flag", "0", None),
+ DiscardedDataFilter("vm/epc_section/base", "0", "Post-launched VMs cannot have EPC sections."),
+ DiscardedDataFilter("vm/epc_section/size", "0", "Post-launched VMs cannot have EPC sections."),
+ DiscardedDataFilter("vm/cpu_affinity/pcpu_id", None, "CPU affinity of the service VM is no longer needed."),
+ DiscardedDataFilter("vm/os_config/name", None, "Guest OS names are no longer needed in scenario definitions."),
+ ]
+
+ def run(self, obj):
+ upgrader = ScenarioUpgrader(obj.get("schema_etree"), obj.get("scenario_etree"))
+ new_scenario_etree = upgrader.upgraded_etree
+
+ discarded_data = [(obj.get("scenario_etree").getelementpath(n), n.text) for n in upgrader.old_data_nodes]
+ for path, data in sorted(discarded_data):
+ if not any(map(lambda x: x.filter(path, data), self.filters)):
+ escaped_data = data.replace("\n", "\\n")
+ logging.warning(f"{path} = '{escaped_data}' is discarded")
+
+ obj.set("scenario_etree", new_scenario_etree)
+
+def main(args):
+ pipeline = PipelineEngine(["schema_path", "scenario_path"])
+ pipeline.add_stages([
+ LXMLLoadStage("schema"),
+ LXMLLoadStage("scenario"),
+ SlicingSchemaByVMTypeStage(),
+ UpgradingScenarioStage(),
+ ])
+
+ obj = PipelineObject(schema_path = args.schema, scenario_path = args.scenario)
+ pipeline.run(obj)
+ # We know we are using lxml to parse the scenario XML, so it is ok to use lxml specific write options here.
+ obj.get("scenario_etree").write(args.out, pretty_print=True)
+
+if __name__ == "__main__":
+ config_tools_dir = os.path.join(os.path.dirname(__file__), "..")
+ schema_dir = os.path.join(config_tools_dir, "schema")
+
+ parser = argparse.ArgumentParser(description="Try adapting data in a scenario XML to the latest schema.")
+ parser.add_argument("scenario", help="Path to the scenario XML file from users")
+ parser.add_argument("out", nargs="?", default="out.xml", help="Path where the output is placed")
+ parser.add_argument("--schema", default=os.path.join(schema_dir, "config.xsd"), help="the XML schema that defines the syntax of scenario XMLs")
+ args = parser.parse_args()
+
+ logging.basicConfig(level="INFO")
+ main(args)