Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion libsel4vm/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,6 @@ file(
sources
src/*.c
src/arch/${KernelArch}/*.c
src/arch/${KernelArch}/i8259/*.c
src/arch/${KernelArch}/processor/*.c
src/sel4_arch/${KernelSel4Arch}/*.c
)
Expand All @@ -67,6 +66,7 @@ target_include_directories(
)
target_link_libraries(
sel4vm
sel4vmmplatsupport
muslc
sel4
sel4simple
Expand Down
16 changes: 16 additions & 0 deletions libsel4vm/arch_include/x86/sel4vm/arch/boot_arch.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
/*
* Copyright 2022, UNSW (ABN 57 195 873 179)
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#pragma once

#include <sel4vmmplatsupport/arch/drivers/timer_emul.h>

/***
* @function vm_assign_vcpu_timer(vcpu, timer_functions)
* Assign a vcpu with timer functions to emulate a timer.
* @param {vm_vcpu_t *} vcpu A handle to the VCPU
* @param {int} target Logical target CPU ID
*/
void vm_assign_vcpu_timer(vm_vcpu_t *vcpu, struct timer_functions *timer_emul);
68 changes: 68 additions & 0 deletions libsel4vm/arch_include/x86/sel4vm/arch/guest_x86_irq_controller.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
/*
* Copyright 2022, UNSW (ABN 57 195 873 179)
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#pragma once

#include <sel4/sel4.h>
#include <sel4vm/guest_vm.h>
#include <sel4vm/guest_irq_controller.h>
#include <sel4vmmplatsupport/drivers/pci_msi.h>

#define I8259_NR_IRQS 16
#define LAPIC_NR_IRQS 14
#define NR_IRQS (I8259_NR_IRQS + LAPIC_NR_IRQS)

/**
* seL4 vectors
*
* For x86 there are 256 idt entries. Vectors are used to index
* into the idt and invoke interrupt handlers. This is how vectors
* are reserved in seL4:
*
* 0 - 31 : system traps and exceptions (hardcoded)
* 32 - ... : start of seL4 vectors
* 32 - 47 : PIC interrupts/kernel only
* 48 : start of user interrupts, when an irq is passed into an seL4
* system call, the _vector_ it is assigned to is (irq + 48).
*/
#define USER_IRQ_TO_CPU_VECTOR(x) ((x) + 48)


typedef struct x86_irq_msi_cookie {
/* The original MSI data the guest programmed. We copy
* this back on every irq injection. */
pci_msi_data_t data;
} x86_irq_msi_cookie_t;

typedef struct x86_irq_cookie {
bool is_msi;
x86_irq_msi_cookie_t msi_cookie; /* Cookie for MSI interrupts */
seL4_CPtr irq_cap; /* Cap to ack on after EOI signal from guest */
} x86_irq_cookie_t;

/* Struct to store information needed when injecting or ack'ing interrupts */
typedef struct irq_info {
irq_ack_fn_t callback;
x86_irq_cookie_t *cookie;
} irq_info_t;

/***
* @function vm_timer_inject_irq(vcpu)
* Inject an a timer IRQ. This is for when the IRQ controller handles the nitty-gritty
* IRQ assignments, and we have no way of telling where the timer IRQ is supposed to go.
* @param {vm_vcpu_t *} vcpu Handle to the VCPU
* @return 0 on success, otherwise -1 for error
*/
int vm_inject_timer_irq(vm_vcpu_t *vcpu);

/***
* @function vm_irq_set_msi_data(irq, msi_data)
* Save the msi data for an irq so we can patch values in later when the
* device invokes an msi.
*
* @param {int} irq the msi's irq
* @param {pci_msi_data_t *} msi_data the msi data we want to patch in later
*/
void vm_irq_set_msi_data(int irq, pci_msi_data_t *msi_data);
7 changes: 6 additions & 1 deletion libsel4vm/src/arch/x86/boot.c
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,11 @@ static int make_guest_page_dir(vm_t *vm)
seL4_PageBits, seL4_AllRights, 1, make_guest_page_dir_continued, NULL);
}

void vm_assign_vcpu_timer(vm_vcpu_t *vcpu, struct timer_functions *timer_emul)
{
vm_apic_set_timer_and_update(vcpu->vcpu_arch.lapic, timer_emul);
}

int vm_init_arch(vm_t *vm)
{
int err;
Expand Down Expand Up @@ -143,7 +148,7 @@ int vm_create_vcpu_arch(vm_t *vm, vm_vcpu_t *vcpu)
int err;
err = seL4_X86_VCPU_SetTCB(vcpu->vcpu.cptr, simple_get_tcb(vm->simple));
assert(err == seL4_NoError);
/* All LAPICs are created enabled, in virtual wire mode */
/* All LAPICs are created enabled */
vm_create_lapic(vcpu, 1);
vcpu->vcpu_arch.guest_state = calloc(1, sizeof(guest_state_t));
if (!vcpu->vcpu_arch.guest_state) {
Expand Down
2 changes: 1 addition & 1 deletion libsel4vm/src/arch/x86/guest_irq_controller.c
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
#include <sel4vm/guest_vm.h>
#include <sel4vm/guest_memory.h>

#include "i8259/i8259.h"
#include "processor/i8259.h"
#include "processor/apicdef.h"
#include "processor/lapic.h"

Expand Down
16 changes: 0 additions & 16 deletions libsel4vm/src/arch/x86/i8259/i8259.h

This file was deleted.

2 changes: 1 addition & 1 deletion libsel4vm/src/arch/x86/interrupt.c
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
#include <sel4vm/boot.h>

#include "vm.h"
#include "i8259/i8259.h"
#include "processor/i8259.h"
#include "guest_state.h"
#include "processor/decode.h"
#include "processor/lapic.h"
Expand Down
7 changes: 7 additions & 0 deletions libsel4vm/src/arch/x86/processor/apicdef.h
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,7 @@
#define APIC_ICR_RR_INVALID 0x00000
#define APIC_ICR_RR_INPROG 0x10000
#define APIC_ICR_RR_VALID 0x20000
#define APIC_INT_EDGETRIG 0x00000
#define APIC_INT_LEVELTRIG 0x08000
#define APIC_INT_ASSERT 0x04000
#define APIC_ICR_BUSY 0x01000
Expand All @@ -108,15 +109,21 @@
#define APIC_LVTTHMR 0x330
#define APIC_LVTPC 0x340
#define APIC_LVT0 0x350

/* This mask is shifted by 18 due to the i82489DX not using the TSC bit in the LVTT, ignore */
#define APIC_LVT_TIMER_BASE_MASK (0x3 << 18)
#define GET_APIC_TIMER_BASE(x) (((x) >> 18) & 0x3)
#define SET_APIC_TIMER_BASE(x) (((x) << 18))

#define APIC_TIMER_BASE_CLKIN 0x0
#define APIC_TIMER_BASE_TMBASE 0x1
#define APIC_TIMER_BASE_DIV 0x2

#define APIC_LVT_TIMER_MASK (0x3 << 17)
#define APIC_LVT_TIMER_ONESHOT (0 << 17)
#define APIC_LVT_TIMER_PERIODIC (BIT(17))
#define APIC_LVT_TIMER_TSCDEADLINE (2 << 17)

#define APIC_LVT_MASKED (BIT(16))
#define APIC_LVT_LEVEL_TRIGGER (BIT(15))
#define APIC_LVT_REMOTE_IRR (BIT(14))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,14 +22,13 @@
#include <sel4vm/guest_vm.h>
#include <sel4vm/boot.h>
#include <sel4vm/guest_irq_controller.h>
#include <sel4vm/arch/guest_x86_irq_controller.h>
#include <sel4vm/arch/ioports.h>
#include "i8259.h"

#define I8259_MASTER 0
#define I8259_SLAVE 1

#define PIC_NUM_PINS 16

/*first programmable interrupt controller, master*/
#define X86_IO_PIC_1_START 0x20
#define X86_IO_PIC_1_END 0x21
Expand All @@ -42,13 +41,6 @@
#define X86_IO_ELCR_START 0x4d0
#define X86_IO_ELCR_END 0x4d1

typedef struct i8259_irq_ack {
irq_ack_fn_t callback;
void *cookie;
} i8259_irq_ack_t;

static i8259_irq_ack_t irq_ack_fns[PIC_NUM_PINS];

/* PIC Machine state. */
struct i8259_state {
unsigned char last_irr; /* Edge detection */
Expand Down Expand Up @@ -175,8 +167,10 @@ static void pic_clear_isr(vm_t *vm, struct i8259_state *s, int irq)
}

if (irq != 2) {
if (irq_ack_fns[irq].callback) {
irq_ack_fns[irq].callback(vm->vcpus[BOOT_VCPU], irq, irq_ack_fns[irq].cookie);
if (irq >= I8259_NR_IRQS)
assert(0);
if (irq_info[irq].callback) {
irq_info[irq].callback(vm->vcpus[BOOT_VCPU], irq, (void *) irq_info[irq].cookie);
}
}
}
Expand Down Expand Up @@ -277,7 +271,7 @@ static void pic_reset(vm_t *vm, struct i8259_state *s)
}
#endif

for (irq = 0; irq < PIC_NUM_PINS / 2; irq++) {
for (irq = 0; irq < I8259_NR_IRQS / 2; irq++) {
if (edge_irr & (1 << irq)) {
pic_clear_isr(vm, s, irq);
}
Expand Down Expand Up @@ -368,7 +362,7 @@ static void pic_ioport_write(vm_vcpu_t *vcpu, struct i8259_state *s, unsigned in
//off = (s == &s->pics_state->pics[0]) ? 0 : 8;
s->imr = val;
#if 0
for (irq = 0; irq < PIC_NUM_PINS / 2; irq++)
for (irq = 0; irq < I8259_NR_IRQS / 2; irq++)
if (imr_diff & (1 << irq))
/*FIXME: notify the status changes for IMR*/
kvm_fire_mask_notifiers(
Expand Down Expand Up @@ -714,21 +708,21 @@ int vm_set_irq_level(vm_vcpu_t *vcpu, int irq, int irq_level)
return 0;
}

int vm_inject_irq(vm_vcpu_t *vcpu, int irq)
int i8259_inject_irq(vm_vcpu_t *vcpu, int irq)
{
vm_set_irq_level(vcpu, irq, 1);
vm_set_irq_level(vcpu, irq, 0);
return 0;
}

int vm_register_irq(vm_vcpu_t *vcpu, int irq, irq_ack_fn_t fn, void *cookie)
int i8259_register_irq(vm_vcpu_t *vcpu, int irq, irq_ack_fn_t fn, void *cookie)
{
if (irq < 0 || irq >= PIC_NUM_PINS) {
if (irq < 0 || irq >= I8259_NR_IRQS) {
ZF_LOGE("irq %d is invalid", irq);
return -1;
}
i8259_irq_ack_t *ack = &irq_ack_fns[irq];
ack->callback = fn;
ack->cookie = cookie;
irq_info_t *info = &irq_info[irq];
info->callback = fn;
info->cookie = (x86_irq_cookie_t *) cookie;
return 0;
}
26 changes: 26 additions & 0 deletions libsel4vm/src/arch/x86/processor/i8259.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
/*
* Copyright 2019, Data61, CSIRO (ABN 41 687 119 230)
*
* SPDX-License-Identifier: GPL-2.0-only
*/

#pragma once

#include <sel4vm/guest_vm.h>
#include <sel4vm/guest_irq_controller.h>
#include <sel4vm/arch/guest_x86_irq_controller.h>

extern irq_info_t irq_info[NR_IRQS];

/* Init function */
int i8259_pre_init(vm_t *vm);

/* Functions to retrieve interrupt state */
int i8259_get_interrupt(vm_t *vm);
int i8259_has_interrupt(vm_t *vm);

/* Inject IRQ into guest PIC */
int i8259_inject_irq(vm_vcpu_t *vcpu, int irq);

/* Register IRQ with an ack function for EOIs */
int i8259_register_irq(vm_vcpu_t *vcpu, int irq, irq_ack_fn_t fn, void *cookie);
Loading