#include <config.h>
#include <kernel/boot.h>
#include <machine/io.h>
#include <model/statedata.h>
#include <object/interrupt.h>
#include <arch/object/interrupt.h>
#include <arch/machine.h>
#include <arch/kernel/apic.h>
#include <arch/kernel/boot.h>
#include <arch/kernel/boot_sys.h>
#include <arch/kernel/vspace.h>
#include <machine/fpu.h>
#include <arch/machine/timer.h>
#include <arch/object/ioport.h>
#include <arch/linker.h>
#include <util.h>
#include <plat/machine/intel-vtd.h>
BOOT_CODE static void
init_irqs(cap_t root_cnode_cap)
{
irq_t i;
for (i = 0; i <= maxIRQ; i++) {
if (i == irq_timer) {
setIRQState(IRQTimer, i);
#if CONFIG_MAX_NUM_NODES > 1
} else if (i == irq_remote_call_ipi || i == irq_reschedule_ipi) {
setIRQState(IRQIPI, i);
#endif
} else if (i == irq_iommu) {
setIRQState(IRQReserved, i);
} else if (i == 2 && config_set(CONFIG_IRQ_PIC)) {
setIRQState(IRQReserved, i);
} else if (i >= irq_isa_min && i <= irq_isa_max) {
if (config_set(CONFIG_IRQ_PIC)) {
setIRQState(IRQInactive, i);
} else {
setIRQState(IRQReserved, i);
}
} else if (i >= irq_user_min && i <= irq_user_max) {
if (config_set(CONFIG_IRQ_IOAPIC)) {
setIRQState(IRQInactive, i);
} else {
setIRQState(IRQReserved, i);
}
} else {
setIRQState(IRQReserved, i);
}
}
Arch_irqStateInit();
write_slot(SLOT_PTR(pptr_of_cap(root_cnode_cap), seL4_CapIRQControl), cap_irq_control_cap_new());
}
#define NUM_RESERVED_REGIONS (MAX_NUM_FREEMEM_REG + CONFIG_MAX_NUM_IOAPIC + MAX_NUM_DRHU + 2)
typedef struct allocated_p_region {
p_region_t regs[NUM_RESERVED_REGIONS];
word_t cur_pos;
} allocated_p_region_t;
BOOT_BSS static allocated_p_region_t allocated_p_regions;
BOOT_CODE static void
merge_regions(void)
{
unsigned int i, j;
for (i = 1; i < allocated_p_regions.cur_pos;) {
if (allocated_p_regions.regs[i - 1].end == allocated_p_regions.regs[i].start) {
allocated_p_regions.regs[i - 1].end = allocated_p_regions.regs[i].end;
for (j = i; j < allocated_p_regions.cur_pos - 1; j++) {
allocated_p_regions.regs[j] = allocated_p_regions.regs[j + 1];
}
allocated_p_regions.cur_pos--;
} else {
i++;
}
}
}
static UNUSED BOOT_CODE bool_t p_region_overlaps(p_region_t reg)
{
unsigned int i;
for (i = 0; i < allocated_p_regions.cur_pos; i++) {
if (allocated_p_regions.regs[i].start < reg.end &&
allocated_p_regions.regs[i].end > reg.start) {
return true;
}
}
return false;
}
BOOT_CODE bool_t
add_allocated_p_region(p_region_t reg)
{
unsigned int i, j;
assert(reg.start <= reg.end);
assert(!p_region_overlaps(reg));
for (i = 0; i < allocated_p_regions.cur_pos; i++) {
if (allocated_p_regions.regs[i].end == reg.start) {
allocated_p_regions.regs[i].end = reg.end;
merge_regions();
return true;
}
if (allocated_p_regions.regs[i].start == reg.end) {
allocated_p_regions.regs[i].start = reg.start;
merge_regions();
return true;
}
if (reg.end < allocated_p_regions.regs[i].start) {
if (allocated_p_regions.cur_pos + 1 == NUM_RESERVED_REGIONS) {
printf("Ran out of reserved physical regions\n");
return false;
}
for (j = allocated_p_regions.cur_pos; j != i; j--) {
allocated_p_regions.regs[j] = allocated_p_regions.regs[j - 1];
}
allocated_p_regions.regs[i] = reg;
allocated_p_regions.cur_pos++;
return true;
}
}
if (i + 1 == NUM_RESERVED_REGIONS) {
printf("Ran out of reserved physical regions\n");
return false;
}
allocated_p_regions.regs[i] = reg;
allocated_p_regions.cur_pos = i + 1;
return true;
}
BOOT_CODE void
init_allocated_p_regions()
{
allocated_p_regions.cur_pos = 0;
}
BOOT_CODE static bool_t
create_untypeds(
cap_t root_cnode_cap,
region_t boot_mem_reuse_reg)
{
seL4_SlotPos slot_pos_before;
seL4_SlotPos slot_pos_after;
word_t i;
paddr_t start = 0;
slot_pos_before = ndks_boot.slot_pos_cur;
create_kernel_untypeds(root_cnode_cap, boot_mem_reuse_reg, slot_pos_before);
for (i = 0; i < allocated_p_regions.cur_pos; i++) {
if (start != allocated_p_regions.regs[i].start) {
if (!create_untypeds_for_region(root_cnode_cap, true,
paddr_to_pptr_reg((p_region_t) {
start, allocated_p_regions.regs[i].start
}),
slot_pos_before)) {
return false;
}
}
start = allocated_p_regions.regs[i].end;
}
if (start != PADDR_USER_DEVICE_TOP) {
if (!create_untypeds_for_region(root_cnode_cap, true,
paddr_to_pptr_reg((p_region_t) {
start, PADDR_USER_DEVICE_TOP
}),
slot_pos_before)) {
return false;
}
}
slot_pos_after = ndks_boot.slot_pos_cur;
ndks_boot.bi_frame->untyped = (seL4_SlotRegion) {
slot_pos_before, slot_pos_after
};
return true;
}
BOOT_CODE static void
init_freemem(p_region_t ui_p_reg, mem_p_regs_t mem_p_regs)
{
word_t i;
pptr_t floor = ui_p_reg.end;
for (i = 0; i < MAX_NUM_FREEMEM_REG; i++) {
ndks_boot.freemem[i] = REG_EMPTY;
}
for (i = 0; i < mem_p_regs.count; i++) {
pptr_t start = mem_p_regs.list[i].start;
pptr_t end = mem_p_regs.list[i].end;
if (start < floor) {
start = floor;
}
if (end < floor) {
end = floor;
}
insert_region(paddr_to_pptr_reg((p_region_t) {
start, end
}));
}
}
BOOT_CODE bool_t
init_sys_state(
cpu_id_t cpu_id,
mem_p_regs_t mem_p_regs,
ui_info_t ui_info,
p_region_t boot_mem_reuse_p_reg,
uint32_t num_drhu,
paddr_t* drhu_list,
acpi_rmrr_list_t *rmrr_list,
seL4_X86_BootInfo_VBE *vbe
)
{
cap_t root_cnode_cap;
vptr_t extra_bi_frame_vptr;
vptr_t bi_frame_vptr;
vptr_t ipcbuf_vptr;
cap_t it_vspace_cap;
cap_t it_ap_cap;
cap_t ipcbuf_cap;
pptr_t bi_frame_pptr;
word_t extra_bi_size = sizeof(seL4_BootInfoHeader);
region_t extra_bi_region;
pptr_t extra_bi_offset = 0;
create_frames_of_region_ret_t create_frames_ret;
create_frames_of_region_ret_t extra_bi_ret;
region_t ui_reg = paddr_to_pptr_reg(ui_info.p_reg);
region_t boot_mem_reuse_reg = paddr_to_pptr_reg(boot_mem_reuse_p_reg);
v_region_t ui_v_reg;
v_region_t it_v_reg;
ui_v_reg.start = ui_info.p_reg.start - ui_info.pv_offset;
ui_v_reg.end = ui_info.p_reg.end - ui_info.pv_offset;
ipcbuf_vptr = ui_v_reg.end;
bi_frame_vptr = ipcbuf_vptr + BIT(PAGE_BITS);
extra_bi_frame_vptr = bi_frame_vptr + BIT(PAGE_BITS);
if (vbe->vbeMode != -1) {
extra_bi_size += sizeof(seL4_X86_BootInfo_VBE);
}
it_v_reg.start = ui_v_reg.start;
it_v_reg.end = ROUND_UP(extra_bi_frame_vptr + extra_bi_size, PAGE_BITS);
init_freemem(ui_info.p_reg, mem_p_regs);
root_cnode_cap = create_root_cnode();
write_slot(
SLOT_PTR(pptr_of_cap(root_cnode_cap), seL4_CapIOPort),
cap_io_port_cap_new(
0,
NUM_IO_PORTS - 1,
VPID_INVALID
)
);
create_domain_cap(root_cnode_cap);
if (!create_irq_cnode()) {
return false;
}
init_irqs(root_cnode_cap);
bi_frame_pptr = allocate_bi_frame(0, ksNumCPUs, ipcbuf_vptr);
if (!bi_frame_pptr) {
return false;
}
extra_bi_region = allocate_extra_bi_region(extra_bi_size);
if (extra_bi_region.start == 0) {
return false;
}
if (vbe->vbeMode != -1) {
vbe->header.id = SEL4_BOOTINFO_HEADER_X86_VBE;
vbe->header.len = sizeof(seL4_X86_BootInfo_VBE);
memcpy((void*)(extra_bi_region.start + extra_bi_offset), vbe, sizeof(seL4_X86_BootInfo_VBE));
extra_bi_offset += sizeof(seL4_X86_BootInfo_VBE);
}
seL4_BootInfoHeader padding_header;
padding_header.id = SEL4_BOOTINFO_HEADER_PADDING;
padding_header.len = (extra_bi_region.end - extra_bi_region.start) - extra_bi_offset;
memcpy((void*)(extra_bi_region.start + extra_bi_offset), &padding_header, sizeof(seL4_BootInfoHeader));
it_vspace_cap = create_it_address_space(root_cnode_cap, it_v_reg);
if (cap_get_capType(it_vspace_cap) == cap_null_cap) {
return false;
}
create_bi_frame_cap(
root_cnode_cap,
it_vspace_cap,
bi_frame_pptr,
bi_frame_vptr
);
extra_bi_ret =
create_frames_of_region(
root_cnode_cap,
it_vspace_cap,
extra_bi_region,
true,
pptr_to_paddr((void*)(extra_bi_region.start - extra_bi_frame_vptr))
);
if (!extra_bi_ret.success) {
return false;
}
ndks_boot.bi_frame->extraBIPages = extra_bi_ret.region;
ipcbuf_cap = create_ipcbuf_frame(root_cnode_cap, it_vspace_cap, ipcbuf_vptr);
if (cap_get_capType(ipcbuf_cap) == cap_null_cap) {
return false;
}
create_frames_ret =
create_frames_of_region(
root_cnode_cap,
it_vspace_cap,
ui_reg,
true,
ui_info.pv_offset
);
if (!create_frames_ret.success) {
return false;
}
ndks_boot.bi_frame->userImageFrames = create_frames_ret.region;
it_ap_cap = create_it_asid_pool(root_cnode_cap);
if (cap_get_capType(it_ap_cap) == cap_null_cap) {
return false;
}
write_it_asid_pool(it_ap_cap, it_vspace_cap);
ndks_boot.bi_frame->archInfo = tsc_init();
if (!create_idle_thread()) {
return false;
}
tcb_t *initial = create_initial_thread(root_cnode_cap,
it_vspace_cap,
ui_info.v_entry,
bi_frame_vptr,
ipcbuf_vptr,
ipcbuf_cap);
if (initial == NULL) {
return false;
}
init_core_state(initial);
if (config_set(CONFIG_IOMMU)) {
if (!vtd_init(cpu_id, num_drhu, rmrr_list)) {
return false;
}
ndks_boot.bi_frame->numIOPTLevels = x86KSnumIOPTLevels;
write_slot(SLOT_PTR(pptr_of_cap(root_cnode_cap), seL4_CapIOSpace), master_iospace_cap());
} else {
ndks_boot.bi_frame->numIOPTLevels = -1;
}
if (!create_untypeds(root_cnode_cap, boot_mem_reuse_reg)) {
return false;
}
bi_finalise();
return true;
}
BOOT_CODE bool_t
init_cpu(
bool_t mask_legacy_irqs
)
{
if (!init_vm_state()) {
return false;
}
init_dtrs();
if (config_set(CONFIG_SYSENTER)) {
init_sysenter_msrs();
} else if (config_set(CONFIG_SYSCALL)) {
init_syscall_msrs();
} else {
return false;
}
if (!init_pat_msr()) {
return false;
}
#ifdef CONFIG_HARDWARE_DEBUG_API
Arch_initHardwareBreakpoints();
#endif
if (!Arch_initFpu()) {
return false;
}
if (!apic_init(mask_legacy_irqs)) {
return false;
}
#ifdef CONFIG_DEBUG_DISABLE_PREFETCHERS
if (!disablePrefetchers()) {
return false;
}
#endif
#ifdef CONFIG_VTX
if (!vtx_init()) {
return false;
}
#endif
return true;
}