Viele Embedded-Systeme werden unter der Voraussetzung entwickelt, dass die anstehenden Rechenaufgaben und die Hardware genau bekannt sind. Die Entwickler können während der Designphase die Hardware-Komponenten mit den Tasks in der Applikation verknüpfen. Bei Verwendung eines Embedded-Betriebssystems ist es typischerweise Aufgabe des Entwicklers, Tasks und Speicherbelegung fest zuzuordnen. Es entsteht ein statisches Speicherlayout. Obwohl das Scheduling von mehreren Tasks, die auf dem gleichen Core laufen, nach wie vor wichtig ist, spielt die Aufteilung, welche Tasks auf welchem Core laufen, eine untergeordnete Rolle. Ebenso ist die Variationsbreite durch dynamisches Scheduling und dynamisches Speichermanagement eingeschränkt. In einer virtualisierten Umgebung ist der VMM verantwortlich für die Zuteilung der Prozessorzeit und die Speicherverwaltung des Gast-Betriebssystems – ganz ähnlich wie das Betriebssystem verantwortlich ist für die Vergabe der Rechenzeit und das Speichermanagement für die Applikationen. Deshalb gelten viele Anforderungen an ein Betriebssystem im Embedded-Umfeld gleichermaßen für VMMs in Embedded-Systemen. Mit diesem Hintergrund sollten Systementwickler statische Konfigurationen in der Designphase vornehmen und die Hardware-Ressourcen mit den VMs verknüpfen.
Dies verändert das Design von VMMs für Embedded-Systeme in zweierlei Hinsicht. Erstens vereinfacht sich der Scheduler, wenn der Entwickler die Tasks statisch und manuell den Rechenkernen zuweist. Der Scheduler muss zwar nach wie vor die VMs, die auf einem Rechenkern laufen, entsprechend den Scheduling-Regeln einteilen, doch die Verteilung auf die Prozessoren wird vereinfacht. Zweitens wird die Speicherverwaltung mehr auf Konfigurierbarkeit ausgelegt als auf dynamische Zuteilung. Die Speicherbereiche für die einzelnen VMs definiert der Entwickler, nicht das Speichermanagement. Dies vereinfacht das Design des Speichermanagers innerhalb der VMM, erhöht aber gleichzeitig den Konfigurationsaufwand des VMM.
Echtzeit-Unterstützung in der virtuellen Maschine
Oft werden mehrere Embedded-Systeme benötigt, um Echtzeit-Aufgaben zu erledigen. Einer der Gründe, warum General-Purpose-Betriebssysteme wie Windows keine Echtzeit-Fähigkeiten besitzen, liegt in der Limitierung des Schedulers. Der Scheduler ist die Einheit, die definiert, wieviel Rechenzeit ein Prozess von der CPU bekommt. Der Windows-Scheduler teilt die Zeitschlitze für Prozesse und Threads in gleichen Maßeinheiten und mit im voraus definierten Prioritäten ein. Dies bedeutet in der Praxis, dass Threads mit gleicher Priorität nach dem Zufallsprinzip eingeteilt und Threads mit höherer Priorität bevorzugt werden und damit mehr CPU-Zeit bekommen. Linux verwendet ein ähnliches Verfahren für die Aufteilung der CPU-Zeit. Ein Echtzeit-Betriebssystem hingegen plant die Tasks strikt über Prioritäten und überlässt nichts dem Zufall.
Ein Priority-Scheduler [3] lässt höher priorisierte Tasks so lange laufen, bis sie abgearbeitet sind. Ein General-Purpose-Scheduler hingegen versucht zu garantieren, dass kein Task einen anderen blockieren kann, und schaltet nach einer maximalen Zeit auf den nächsten Task um. Echtzeit-Applikationen in einer virtualisierten Umgebung laufen zu lassen, ist eine Herausforderung. Ein VMM hat typischerweise keinen Einblick in die individuellen Tasks, die innerhalb eines Echtzeit-Betriebssystems ablaufen, noch weiß der VMM über deren Prioritäten Bescheid. Embedded-VMM-Anbieter haben die Aufgabe so gelöst, dass die Echtzeit-Betriebssysteme alleine auf einem Prozessorkern laufen oder maximal ein Echtzeit-Betriebssystem und ein General-Purpose-Betriebsystem sich einen CPU-Kern teilen, wobei das Echtzeit-Betriebssystem immer Priorität hat.
Ein weiterer Unterschied zwischen Echtzeit- und General-Purpose-Umgebungen ist die Art, wie Interrupts bedient werden. In vielen Embedded-Applikationen müssen Interrupts, die von externer Hardware erzeugt werden, innerhalb einer bestimmten Zeitspanne abgearbeitet werden. General-Purpose-Betriebssysteme bieten diese Garantie nicht – sie können die Verarbeitung der Interrupts für eine unbegrenzte Zeit abschalten. Dieses Verhalten ist für Echtzeit-Anwendungen nicht brauchbar.