summaryrefslogtreecommitdiffstats
path: root/src/main/java/org/openslx/firmware
diff options
context:
space:
mode:
Diffstat (limited to 'src/main/java/org/openslx/firmware')
-rw-r--r--src/main/java/org/openslx/firmware/FirmwareException.java25
-rw-r--r--src/main/java/org/openslx/firmware/QemuFirmware.java169
-rw-r--r--src/main/java/org/openslx/firmware/QemuFirmwareUtil.java121
3 files changed, 315 insertions, 0 deletions
diff --git a/src/main/java/org/openslx/firmware/FirmwareException.java b/src/main/java/org/openslx/firmware/FirmwareException.java
new file mode 100644
index 0000000..494d653
--- /dev/null
+++ b/src/main/java/org/openslx/firmware/FirmwareException.java
@@ -0,0 +1,25 @@
+package org.openslx.firmware;
+
+/**
+ * An exception of a firmware-related error.
+ *
+ * @author Manuel Bentele
+ * @version 1.0
+ */
+public class FirmwareException extends Exception
+{
+ /**
+ * Version for serialization.
+ */
+ private static final long serialVersionUID = -5932122856822258867L;
+
+ /**
+ * Creates a firmware exception including an error message.
+ *
+ * @param errorMsg message to describe the exception.
+ */
+ public FirmwareException( String errorMsg )
+ {
+ super( errorMsg );
+ }
+}
diff --git a/src/main/java/org/openslx/firmware/QemuFirmware.java b/src/main/java/org/openslx/firmware/QemuFirmware.java
new file mode 100644
index 0000000..7a81217
--- /dev/null
+++ b/src/main/java/org/openslx/firmware/QemuFirmware.java
@@ -0,0 +1,169 @@
+package org.openslx.firmware;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileReader;
+import java.io.Reader;
+import java.util.ArrayList;
+
+import com.google.gson.Gson;
+import com.google.gson.JsonIOException;
+import com.google.gson.JsonSyntaxException;
+import com.google.gson.annotations.SerializedName;
+
+/**
+ * Data representation of QEMU firmware specification files (*.json).
+ *
+ * @author Manuel Bentele
+ * @version 1.0
+ */
+public class QemuFirmware
+{
+ /**
+ * Default QEMU firmware specification directory under Linux-based systems.
+ */
+ public final static String DEFAULT_SPEC_DIR = "/usr/share/qemu/firmware";
+
+ @SerializedName( "description" )
+ private String description;
+ @SerializedName( "interface-types" )
+ private ArrayList<String> interfaceTypes;
+ @SerializedName( "mapping" )
+ private FirmwareMapping mapping;
+ @SerializedName( "targets" )
+ private ArrayList<FirmwareTarget> targets;
+ @SerializedName( "features" )
+ private ArrayList<String> features;
+ @SerializedName( "tags" )
+ private ArrayList<String> tags;
+
+ public String getDescription()
+ {
+ return description;
+ }
+
+ public ArrayList<String> getInterfaceTypes()
+ {
+ return interfaceTypes;
+ }
+
+ public FirmwareMapping getMapping()
+ {
+ return mapping;
+ }
+
+ public ArrayList<FirmwareTarget> getTargets()
+ {
+ return targets;
+ }
+
+ public ArrayList<String> getFeatures()
+ {
+ return features;
+ }
+
+ public ArrayList<String> getTags()
+ {
+ return tags;
+ }
+
+ /**
+ * Parse QEMU firmware specification from firmware specification Json file.
+ *
+ * @param fwSpecFile firmware specification Json file.
+ * @return QEMU firmware specification.
+ */
+ public static QemuFirmware fromFwSpec( File fwSpecFile )
+ {
+ final Gson gson = new Gson();
+ QemuFirmware firmware = null;
+
+ try {
+ final Reader jsonContent = new FileReader( fwSpecFile );
+ firmware = gson.fromJson( jsonContent, QemuFirmware.class );
+ } catch ( FileNotFoundException | NullPointerException | JsonSyntaxException | JsonIOException e ) {
+ firmware = null;
+ }
+
+ return firmware;
+ }
+}
+
+class FirmwareMapping
+{
+ @SerializedName( "device" )
+ private String device;
+ @SerializedName( "executable" )
+ private FirmwareMappingExecutable executable;
+ @SerializedName( "nvram-template" )
+ private FirmwareMappingNvramTemplate nvramTemplate;
+
+ public String getDevice()
+ {
+ return device;
+ }
+
+ public FirmwareMappingExecutable getExecutable()
+ {
+ return executable;
+ }
+
+ public FirmwareMappingNvramTemplate getNvramTemplate()
+ {
+ return nvramTemplate;
+ }
+}
+
+class FirmwareMappingExecutable
+{
+ @SerializedName( "filename" )
+ private String fileName;
+ @SerializedName( "format" )
+ private String format;
+
+ public String getFileName()
+ {
+ return fileName;
+ }
+
+ public String getFormat()
+ {
+ return format;
+ }
+}
+
+class FirmwareMappingNvramTemplate
+{
+ @SerializedName( "filename" )
+ private String fileName;
+ @SerializedName( "format" )
+ private String format;
+
+ public String getFileName()
+ {
+ return fileName;
+ }
+
+ public String getFormat()
+ {
+ return format;
+ }
+}
+
+class FirmwareTarget
+{
+ @SerializedName( "architecture" )
+ private String architecture;
+ @SerializedName( "machines" )
+ private ArrayList<String> machines;
+
+ public String getArchitecture()
+ {
+ return architecture;
+ }
+
+ public ArrayList<String> getMachines()
+ {
+ return machines;
+ }
+}
diff --git a/src/main/java/org/openslx/firmware/QemuFirmwareUtil.java b/src/main/java/org/openslx/firmware/QemuFirmwareUtil.java
new file mode 100644
index 0000000..987a0c0
--- /dev/null
+++ b/src/main/java/org/openslx/firmware/QemuFirmwareUtil.java
@@ -0,0 +1,121 @@
+package org.openslx.firmware;
+
+import java.io.File;
+import java.io.FileFilter;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.ArrayList;
+import java.util.function.Predicate;
+
+import org.openslx.util.LevenshteinDistance;
+import org.openslx.virtualization.configuration.transformation.TransformationException;
+
+/**
+ * Utilities to process QEMU firmware specification files.
+ *
+ * @author Manuel Bentele
+ * @version 1.0
+ */
+public class QemuFirmwareUtil
+{
+ /**
+ * Lookup a virtual machine's target OS loader based on QEMU firmware specification files.
+ *
+ * @param fwSpecDir QEMU firmware specification directory of the target host.
+ * @param sourceOsLoader OS loader of the virtual machine.
+ * @param sourceOsArch OS architecture of the virtual machine.
+ * @param sourceOsMachine OS machine type of the virtual machine.
+ * @return Path to the new target OS loader file for the virtual machine.
+ *
+ * @throws TransformationException Failed to lookup target OS loader for virtual machine.
+ */
+ public static String lookupTargetOsLoader( String fwSpecDir, String sourceOsLoader, String sourceOsArch,
+ String sourceOsMachine )
+ throws FirmwareException
+ {
+ String lookupOsLoader = null;
+
+ // parse and check firmware specification directory
+ final File fwSpecDirFile = new File( fwSpecDir );
+ if ( !fwSpecDirFile.exists() || !fwSpecDirFile.isDirectory() ) {
+ throw new FirmwareException( "Path to QEMU firmware specifications directory is invalid!" );
+ }
+
+ // get all firmware specification files
+ final FileFilter fwSpecFilesFilter = file -> !file.isDirectory() && file.getName().endsWith( ".json" );
+ final File[] fwSpecFiles = fwSpecDirFile.listFiles( fwSpecFilesFilter );
+
+ // get paths to firmware files from firmware specification files
+ if ( fwSpecFiles != null ) {
+ final ArrayList<QemuFirmware> uefiFirmwares = new ArrayList<QemuFirmware>();
+
+ for ( final File fwSpecFile : fwSpecFiles ) {
+ // parse the firmware file
+ final QemuFirmware firmware = QemuFirmware.fromFwSpec( fwSpecFile );
+ if ( firmware == null ) {
+ throw new FirmwareException( "Firmware '" + fwSpecFile.toString() + "' can not be parsed correctly!" );
+ } else {
+ final Predicate<String> byInterfaceType = s -> s.toLowerCase().equals( "uefi" );
+ if ( firmware.getInterfaceTypes().stream().filter( byInterfaceType ).findAny().isPresent() ) {
+ // found valid UEFI firmware
+ // check if architecture and machine type of the VM is supported by the firmware
+ final Predicate<FirmwareTarget> byArchitecture = t -> sourceOsArch.equals( t.getArchitecture() );
+ final Predicate<String> byMachineType = s -> sourceOsMachine.startsWith( s.replace( "*", "" ) );
+ final Predicate<FirmwareTarget> byMachines = t -> t.getMachines().stream().filter( byMachineType )
+ .findAny().isPresent();
+
+ if ( firmware.getTargets().stream().filter( byArchitecture ).filter( byMachines ).findAny()
+ .isPresent() ) {
+ // found UEFI firmware supporting suitable architecture and machine type from VM
+ uefiFirmwares.add( firmware );
+ }
+ }
+ }
+ }
+
+ if ( uefiFirmwares.isEmpty() ) {
+ throw new FirmwareException( "There aren't any suitable UEFI firmwares locally available!" );
+ } else {
+ final LevenshteinDistance distance = new LevenshteinDistance( 1, 1, 1 );
+ int minFileNameDistance = Integer.MAX_VALUE;
+ Path suitablestUefiFirmwarePath = null;
+
+ for ( final QemuFirmware uefiFirmware : uefiFirmwares ) {
+ final Path uefiFirmwarePath = Paths.get( uefiFirmware.getMapping().getExecutable().getFileName() );
+ final Path sourceOsLoaderPath = Paths.get( sourceOsLoader );
+ final String uefiFirmwareFileName = uefiFirmwarePath.getFileName().toString().toLowerCase();
+ final String sourceOsLoaderFileName = sourceOsLoaderPath.getFileName().toString().toLowerCase();
+
+ final int fileNameDistance = distance.calculateDistance( uefiFirmwareFileName, sourceOsLoaderFileName );
+ if ( fileNameDistance < minFileNameDistance ) {
+ minFileNameDistance = fileNameDistance;
+ suitablestUefiFirmwarePath = uefiFirmwarePath;
+ }
+ }
+
+ lookupOsLoader = suitablestUefiFirmwarePath.toString();
+ }
+ }
+
+ return lookupOsLoader;
+ }
+
+ /**
+ * Lookup a virtual machine's target OS loader based on QEMU firmware specification files under
+ * the default path.
+ *
+ * @param sourceOsLoader OS loader of the virtual machine.
+ * @param sourceOsArch OS architecture of the virtual machine.
+ * @param sourceOsMachine OS machine type of the virtual machine.
+ * @return Path to the new target OS loader file for the virtual machine.
+ *
+ * @throws TransformationException Failed to lookup target OS loader for virtual machine.
+ */
+ public static String lookupTargetOsLoaderDefaultFwSpecDir( String sourceOsLoader, String sourceOsArch,
+ String sourceOsMachine )
+ throws FirmwareException
+ {
+ return QemuFirmwareUtil.lookupTargetOsLoader( QemuFirmware.DEFAULT_SPEC_DIR, sourceOsLoader, sourceOsArch,
+ sourceOsMachine );
+ }
+}