For answering a message, the cell first has to clear the "Message to Cell"
field. It then has to write a non-zero reply code into the "Message from Cell"
-field.
+field. If a cell receives an unknown message code, it has to send the reply
+"Message unknown" (code 1).
Write ordering of all updates has to be ensured by both the hypervisor
and the cell according to the requirements of the hardware architecture.
The following messages and corresponding replies are defined:
- - Shutdown Requested (code 1):
+ - Shutdown Request (code 1):
The cell is supposed to be shut down, either to destroy only the cell
itself or to disable the hypervisor completely.
Possible replies:
- 1 - Shutdown denied
- 2 - Shutdown OK
+ 2 - Request denied
+ 3 - Request approved
-Note: The hypervisor does not request shutdown permission from a cell if that
- cell has the "Passive Communication Region" flag set in its configuration
- (see also [2]) or if the cell state is set to "Shut Down" or "Failed"
- (see below).
+ Note: The hypervisor does not request shutdown permission from a cell if
+ that cell has the "Passive Communication Region" flag set in its
+ configuration (see also [2]) or if the cell state is set to "Shut
+ Down" or "Failed" (see below).
Logical Channel "Cell State"
#include <asm/bitops.h>
#include <asm/spinlock.h>
+enum msg_type {MSG_REQUEST, MSG_INFORMATION};
+
struct jailhouse_system *system_config;
static DEFINE_SPINLOCK(shutdown_lock);
arch_resume_cpu(cpu);
}
+/**
+ * cell_send_message - Deliver a message to cell and wait for the reply
+ * @cell: target cell
+ * @message: message code to be sent (JAILHOUSE_MSG_*)
+ * @type: message type, defines the valid replies
+ *
+ * Returns true if a request message was approved or reception of an
+ * information message was acknowledged by the target cell. It also return true
+ * of the target cell does not support a communication region, is shut down or
+ * in failed state. Return false on request denial or invalid replies.
+ */
+static bool cell_send_message(struct cell *cell, u32 message,
+ enum msg_type type)
+{
+ if (cell->config->flags & JAILHOUSE_CELL_PASSIVE_COMMREG)
+ return true;
+
+ jailhouse_send_msg_to_cell(&cell->comm_page.comm_region, message);
+
+ while (1) {
+ u32 reply = cell->comm_page.comm_region.reply_from_cell;
+ u32 cell_state = cell->comm_page.comm_region.cell_state;
+
+ if (cell_state == JAILHOUSE_CELL_SHUT_DOWN ||
+ cell_state == JAILHOUSE_CELL_FAILED)
+ return true;
+
+ if ((type == MSG_REQUEST &&
+ reply == JAILHOUSE_MSG_REQUEST_APPROVED) ||
+ (type == MSG_INFORMATION &&
+ reply == JAILHOUSE_MSG_RECEIVED))
+ return true;
+
+ if (reply != JAILHOUSE_MSG_NONE)
+ return false;
+
+ cpu_relax();
+ }
+}
+
static unsigned int get_free_cell_id(void)
{
unsigned int id = 0;
static bool cell_shutdown_ok(struct cell *cell)
{
- volatile u32 *reply = &cell->comm_page.comm_region.reply_from_cell;
- volatile u32 *cell_state = &cell->comm_page.comm_region.cell_state;
-
- if (cell->config->flags & JAILHOUSE_CELL_PASSIVE_COMMREG)
- return true;
-
- jailhouse_send_msg_to_cell(&cell->comm_page.comm_region,
- JAILHOUSE_MSG_SHUTDOWN_REQUESTED);
-
- while (*reply != JAILHOUSE_MSG_SHUTDOWN_DENIED) {
- if (*reply == JAILHOUSE_MSG_SHUTDOWN_OK ||
- *cell_state == JAILHOUSE_CELL_SHUT_DOWN ||
- *cell_state == JAILHOUSE_CELL_FAILED)
- return true;
- cpu_relax();
- }
- return false;
+ return cell_send_message(cell, JAILHOUSE_MSG_SHUTDOWN_REQUEST,
+ MSG_REQUEST);
}
static int cell_management_prologue(struct per_cpu *cpu_data, unsigned long id,
#define JAILHOUSE_MSG_NONE 0
/* messages to cell */
-#define JAILHOUSE_MSG_SHUTDOWN_REQUESTED 1
+#define JAILHOUSE_MSG_SHUTDOWN_REQUEST 1
/* replies from cell */
-#define JAILHOUSE_MSG_SHUTDOWN_DENIED 1
-#define JAILHOUSE_MSG_SHUTDOWN_OK 2
+#define JAILHOUSE_MSG_UNKNOWN 1
+#define JAILHOUSE_MSG_REQUEST_DENIED 2
+#define JAILHOUSE_MSG_REQUEST_APPROVED 3
+#define JAILHOUSE_MSG_RECEIVED 4
/* cell state, initialized by hypervisor, updated by cell */
#define JAILHOUSE_CELL_RUNNING 0
void inmate_main(void)
{
+ bool terminate = false;
unsigned int n;
printk_uart_base = UART_BASE;
if (init_pm_timer())
init_apic();
- while (comm_region->msg_to_cell != JAILHOUSE_MSG_SHUTDOWN_REQUESTED)
+ while (!terminate) {
asm volatile("hlt");
- printk("Rejecting first shutdown - try again!\n");
- jailhouse_send_reply_from_cell(comm_region,
- JAILHOUSE_MSG_SHUTDOWN_DENIED);
+ switch (comm_region->msg_to_cell) {
+ case JAILHOUSE_MSG_SHUTDOWN_REQUEST:
+ printk("Rejecting first shutdown request - "
+ "try again!\n");
+ jailhouse_send_reply_from_cell(comm_region,
+ JAILHOUSE_MSG_REQUEST_DENIED);
+ terminate = true;
+ break;
+ default:
+ jailhouse_send_reply_from_cell(comm_region,
+ JAILHOUSE_MSG_UNKNOWN);
+ break;
+ }
+ }
for (n = 0; n < 10; n++)
asm volatile("hlt");