[PATCH 1/6] x86: program the flags before writing to ICR

17 views
Skip to first unread message

hcha...@xvisor-x86.org

unread,
Jun 18, 2021, 10:23:40 AM6/18/21
to xvisor...@googlegroups.com, Himanshu Chauhan
From: Himanshu Chauhan <hcha...@xvisor-x86.org>

o Program periodic/non-periodic flag before program ICR
o Add write memory barrier before programming ICR

Signed-off-by: Himanshu Chauhan <hcha...@xvisor-x86.org>
---
arch/x86/cpu/common/cpu_apic.c | 9 ++++++---
1 file changed, 6 insertions(+), 3 deletions(-)

diff --git a/arch/x86/cpu/common/cpu_apic.c b/arch/x86/cpu/common/cpu_apic.c
index 4c741000..e915b465 100644
--- a/arch/x86/cpu/common/cpu_apic.c
+++ b/arch/x86/cpu/common/cpu_apic.c
@@ -31,6 +31,7 @@
#include <libs/stringlib.h>
#include <arch_cpu.h>
#include <arch_io.h>
+#include <arch_barrier.h>
#include <cpu_mmu.h>
#include <cpu_features.h>
#include <cpu_interrupts.h>
@@ -743,9 +744,6 @@ lapic_set_timer_count(u32 count, int periodic)
/* Setup Divide Count Register to use the bus frequency directl. */
lapic_write(LAPIC_TIMER_DCR(this_cpu(lapic).vbase), LAPIC_TDR_DIV_1);

- /* Program the initial count register */
- lapic_write(LAPIC_TIMER_ICR(this_cpu(lapic).vbase), count);
-
/* Enable the local APIC timer */
lvt = lapic_read(LAPIC_LVTTR(this_cpu(lapic).vbase));
lvt &= ~APIC_LVT_MASKED;
@@ -755,6 +753,11 @@ lapic_set_timer_count(u32 count, int periodic)
lvt &= ~APIC_LVT_TIMER_PERIODIC;

lapic_write(LAPIC_LVTTR(this_cpu(lapic).vbase), lvt);
+
+ arch_wmb();
+
+ /* Program the initial count register */
+ lapic_write(LAPIC_TIMER_ICR(this_cpu(lapic).vbase), count);
}

static void
--
2.25.1

hcha...@xvisor-x86.org

unread,
Jun 18, 2021, 10:23:53 AM6/18/21
to xvisor...@googlegroups.com, Himanshu Chauhan
From: Himanshu Chauhan <hcha...@xvisor-x86.org>

Signed-off-by: Himanshu Chauhan <hcha...@xvisor-x86.org>
---
arch/x86/cpu/common/cpu_apic.c | 81 ++++++++++++++++++++++++++++++++++
1 file changed, 81 insertions(+)

diff --git a/arch/x86/cpu/common/cpu_apic.c b/arch/x86/cpu/common/cpu_apic.c
index e915b465..5c268c0f 100644
--- a/arch/x86/cpu/common/cpu_apic.c
+++ b/arch/x86/cpu/common/cpu_apic.c
@@ -46,6 +46,8 @@
#include <tsc.h>
#include <timers/timer.h>

+#define ENABLE_TIMER_TRACE 1
+
#undef DEBUG_IOAPIC

#ifdef DEBUG_IOAPIC
@@ -54,6 +56,78 @@
#define debug_print(fmnt, args...) { }
#endif

+#if ENABLE_TIMER_TRACE
+#define MAX_TRACE_ELEMENTS 2048
+
+typedef struct timer_irq_trace_element {
+ u64 tsc_val;
+ u64 init_val;
+ u64 cc_val;
+ u64 res;
+} timer_irq_te_t;
+
+typedef struct timer_trace_element {
+ u64 timer_val;
+ u64 tsc_val;
+ u64 cc_val;
+ u64 esr_val;
+ u64 lvt_val;
+} timer_te_t;
+
+typedef struct timer_trace {
+ u32 trace_index;
+ u32 trace_irq_index;
+ u32 wraps;
+ u32 irq_wraps;
+ u32 irqs;
+ timer_te_t trace_buf[MAX_TRACE_ELEMENTS];
+ timer_irq_te_t trace_irq_buf[MAX_TRACE_ELEMENTS];
+} timer_trace_t;
+
+static timer_trace_t timer_trace;
+
+void init_trace_timer(void)
+{
+ memset(&timer_trace, 0, sizeof(timer_trace));
+}
+
+void trace_timer(u64 next, u64 tsc, u64 cc, u64 esr, u64 lvt)
+{
+ timer_te_t *te = &timer_trace.trace_buf[timer_trace.trace_index];
+
+ te->timer_val = next;
+ te->tsc_val = tsc;
+ te->cc_val = cc;
+ te->esr_val = esr;
+ te->lvt_val = lvt;
+
+ timer_trace.trace_index++;
+ timer_trace.trace_index %= MAX_TRACE_ELEMENTS;
+ if (timer_trace.trace_index == 0)
+ timer_trace.wraps++;
+}
+
+void trace_timer_irq(u64 tsc, u64 cc, u64 init)
+{
+ timer_irq_te_t *tie = &timer_trace.trace_irq_buf[timer_trace.trace_irq_index];
+
+ tie->tsc_val = tsc;
+ tie->cc_val = cc;
+ tie->init_val = init;
+
+ timer_trace.irqs++;
+ timer_trace.trace_irq_index++;
+ timer_trace.trace_irq_index %= MAX_TRACE_ELEMENTS;
+ if (timer_trace.trace_irq_index == 0)
+ timer_trace.irq_wraps++;
+}
+
+#else
+void init_trace_timer(void) {}
+void trace_timer(u64 next, u64 tsc, u64 cc, u64 esr, u64 lvt) {}
+void trace_timer_irq(u64 tsc, u64 cc, u64 init) {}
+#endif /* ENABLE_TIMER_TRACE */
+
/* FIXME we should spread the irqs across as many priority levels as possible
* due to buggy hw */
#define LAPIC_VECTOR(irq) (IRQ0_VECTOR +(irq))
@@ -396,6 +470,8 @@ static int setup_lapic(int cpu)

this_cpu(lapic).msr = cpu_read_msr(MSR_IA32_APICBASE);

+ init_trace_timer();
+
if (!APIC_ENABLED(this_cpu(lapic).msr)) {
this_cpu(lapic).msr |= (0x1UL << 11);
cpu_write_msr(MSR_IA32_APICBASE, this_cpu(lapic).msr);
@@ -462,6 +538,11 @@ static vmm_irq_return_t
lapic_clockchip_irq_handler(int irq_no, void *dev)
{
struct lapic_timer *timer = (struct lapic_timer *)dev;
+ u64 cc, init;
+
+ cc = lapic_read(LAPIC_TIMER_CCR(this_cpu(lapic).vbase));
+ init = lapic_read(LAPIC_TIMER_ICR(this_cpu(lapic).vbase));
+ trace_timer_irq(get_tsc_serialized(), cc, init);

#ifndef CONFIG_USE_DEADLINE_TSC
/* when using incremental count mode, just set the count
--
2.25.1

hcha...@xvisor-x86.org

unread,
Jun 18, 2021, 10:23:58 AM6/18/21
to xvisor...@googlegroups.com, Himanshu Chauhan
From: Himanshu Chauhan <hcha...@xvisor-x86.org>

Signed-off-by: Himanshu Chauhan <hcha...@xvisor-x86.org>
---
arch/x86/cpu/common/cpu_apic.c | 37 +++++++++++++++++++++++---
arch/x86/cpu/common/include/cpu_apic.h | 2 ++
2 files changed, 36 insertions(+), 3 deletions(-)

diff --git a/arch/x86/cpu/common/cpu_apic.c b/arch/x86/cpu/common/cpu_apic.c
index 5c268c0f..176741af 100644
--- a/arch/x86/cpu/common/cpu_apic.c
+++ b/arch/x86/cpu/common/cpu_apic.c
@@ -477,6 +477,8 @@ static int setup_lapic(int cpu)
cpu_write_msr(MSR_IA32_APICBASE, this_cpu(lapic).msr);
}

+ INIT_SPIN_LOCK(&this_cpu(lapic).lock);
+
this_cpu(lapic).pbase = (APIC_BASE(this_cpu(lapic).msr) << 12);

/* remap base */
@@ -587,11 +589,15 @@ static int
lapic_arm_timer(struct lapic_timer *timer)
{
u32 lvt;
+ u32 flags;
+
+ vmm_spin_lock_irqsave(&this_cpu(lapic).lock, flags);

lvt = lapic_read(LAPIC_LVTTR(this_cpu(lapic).vbase));
lvt &= ~APIC_LVT_MASKED;
lapic_write(LAPIC_LVTTR(this_cpu(lapic).vbase), lvt);
timer->armed = 1;
+ vmm_spin_unlock_irqrestore(&this_cpu(lapic).lock, flags);

return VMM_OK;
}
@@ -600,11 +606,15 @@ static __unused int
lapic_disarm_timer(struct lapic_timer *timer)
{
u32 lvt;
+ u32 flags;
+
+ vmm_spin_lock_irqsave(&this_cpu(lapic).lock, flags);

lvt = lapic_read(LAPIC_LVTTR(this_cpu(lapic).vbase));
lvt |= APIC_LVT_MASKED;
lapic_write(LAPIC_LVTTR(this_cpu(lapic).vbase), lvt);
timer->armed = 0;
+ vmm_spin_unlock_irqrestore(&this_cpu(lapic).lock, flags);

return VMM_OK;
}
@@ -648,43 +658,63 @@ lapic_clockchip_set_next_event(unsigned long next,
{
struct lapic_timer *timer = container_of(cc, struct lapic_timer,
clkchip);
+ u32 flags;
+ int rc;
+
BUG_ON(timer == NULL);

+ vmm_spin_lock_irqsave(&this_cpu(lapic).lock, flags);
+
if (unlikely(!timer->armed)) {
lapic_arm_timer(timer);
timer->armed = 1;
}

+ trace_timer(next, get_tsc_serialized(),
+ lapic_read(LAPIC_TIMER_CCR(this_cpu(lapic).vbase)),
+ lapic_read(LAPIC_ESR(this_cpu(lapic).vbase)),
+ lapic_read(LAPIC_LVTTR(this_cpu(lapic).vbase)));
+
#ifdef CONFIG_USE_DEADLINE_TSC
if (this_cpu(lapic).deadline_supported)
return lapic_set_deadline(next);
#endif

- return lapic_set_icr(next);
+ rc = lapic_set_icr(next);
+ vmm_spin_unlock_irqrestore(&this_cpu(lapic).lock, flags);
+
+ return rc;
}

static void
lapic_timer_irq_mask(struct vmm_host_irq *irq)
{
struct lapic_timer *timer = (struct lapic_timer *)irq->chip_data;
- u32 lvt;
+ u32 lvt, flags;
+
+ vmm_spin_lock_irqsave(&this_cpu(lapic).lock, flags);

/* Disable the local APIC timer */
lvt = lapic_read(LAPIC_LVTTR(timer->lapic->vbase));
lvt |= APIC_LVT_MASKED;
lapic_write(LAPIC_LVTTR(timer->lapic->vbase), lvt);
+ vmm_spin_unlock_irqrestore(&this_cpu(lapic).lock, flags);
}

static void
lapic_timer_irq_unmask(struct vmm_host_irq *irq)
{
struct lapic_timer *timer = (struct lapic_timer *)irq->chip_data;
- u32 lvt;
+ u32 lvt, flags;
+
+ vmm_spin_lock_irqsave(&this_cpu(lapic).lock, flags);

/* Disable the local APIC timer */
lvt = lapic_read(LAPIC_LVTTR(timer->lapic->vbase));
lvt &= ~APIC_LVT_MASKED;
lapic_write(LAPIC_LVTTR(timer->lapic->vbase), lvt);
+
+ vmm_spin_unlock_irqrestore(&this_cpu(lapic).lock, flags);
}

int __cpuinit lapic_clockchip_init(void)
@@ -817,6 +847,7 @@ pit_calibrate_tsc(void)
return (end - start)/50;
}

+/* NOTE: lapic lock should be held before calling this */
static void
lapic_set_timer_count(u32 count, int periodic)
{
diff --git a/arch/x86/cpu/common/include/cpu_apic.h b/arch/x86/cpu/common/include/cpu_apic.h
index 9f6043b7..b3693156 100644
--- a/arch/x86/cpu/common/include/cpu_apic.h
+++ b/arch/x86/cpu/common/include/cpu_apic.h
@@ -26,6 +26,7 @@

#include <vmm_types.h>
#include <vmm_host_irq.h>
+#include <vmm_spinlocks.h>
#include <libs/list.h>

extern virtual_addr_t lapic_eoi_addr;
@@ -228,6 +229,7 @@ struct cpu_ioapic {
};

struct cpu_lapic {
+ vmm_spinlock_t lock;
u32 id;
physical_addr_t pbase;
virtual_addr_t vbase;
--
2.25.1

hcha...@xvisor-x86.org

unread,
Jun 18, 2021, 10:23:59 AM6/18/21
to xvisor...@googlegroups.com, Himanshu Chauhan
From: Himanshu Chauhan <hcha...@xvisor-x86.org>

This patch adds tracepoints for all the EPT programming that
is being done.

Signed-off-by: Himanshu Chauhan <hcha...@xvisor-x86.org>
---
arch/x86/cpu/common/vm/vtx/ept.c | 60 ++++++++++++++++++++++++++++++++
1 file changed, 60 insertions(+)

diff --git a/arch/x86/cpu/common/vm/vtx/ept.c b/arch/x86/cpu/common/vm/vtx/ept.c
index 8dbe7bf5..ef7e42c1 100644
--- a/arch/x86/cpu/common/vm/vtx/ept.c
+++ b/arch/x86/cpu/common/vm/vtx/ept.c
@@ -36,6 +36,61 @@
#include <vmm_main.h>
#include <vm/ept.h>

+#define TRACE_EPT 1
+
+#if TRACE_EPT
+#define MAX_EPT_TRACE_ENTRIES 2048
+
+typedef struct ept_trace_entry {
+ u64 g_phys;
+ u64 h_phys;
+ u64 pml4_index:10;
+ u64 pdpt_index:10;
+ u64 pde_index:10;
+ u64 pt_index:10;
+ u64 pg_sz:24;
+ u32 pg_prot;
+} ept_trace_entry_t;
+
+typedef struct ept_trace {
+ u64 trace_index;
+ u64 wraps;
+ ept_trace_entry_t ept_trace_buf[MAX_EPT_TRACE_ENTRIES];
+} ept_trace_t;
+
+static ept_trace_t ept_trace;
+
+static void init_ept_trace(void)
+{
+ memset(&ept_trace, 0, sizeof(ept_trace));
+}
+
+static void add_ept_trace_point(u64 gphys, u64 hphys, u32 pml4, u32 pdpt,
+ u32 pde, u32 pt, u32 sz, u32 pg_prot)
+{
+ ept_trace_entry_t *te = &ept_trace.ept_trace_buf[ept_trace.trace_index];
+
+ te->g_phys = gphys;
+ te->h_phys = hphys;
+ te->pml4_index = pml4;
+ te->pdpt_index = pdpt;
+ te->pde_index = pde;
+ te->pt_index = pt;
+ te->pg_sz = sz;
+ te->pg_prot = pg_prot;
+
+ ept_trace.trace_index++;
+ ept_trace.trace_index %= MAX_EPT_TRACE_ENTRIES;
+
+ if (ept_trace.trace_index == 0)
+ ept_trace.wraps++;
+}
+#else
+static void init_ept_trace(void) {}
+static void add_ept_trace_point(u64 gphys, u64 hphys, u32 pml4, u32 pdpt,
+ u32 pde, u32 pg_prot) {}
+#endif /* EPT Trace */
+
static inline u32 ept_pml4_index(physical_addr_t gphys)
{
gphys &= PHYS_ADDR_BIT_MASK;
@@ -151,6 +206,8 @@ int ept_create_pte_map(struct vcpu_hw_context *context,
VM_LOG(LVL_DEBUG, "pml4: 0x%"PRIx32" pdpt: 0x%"PRIx32" pd: 0x%"PRIx32" pt: 0x%"PRIx32"\n",
pml4_index, pdpt_index, pd_index, pt_index);

+ add_ept_trace_point(gphys, hphys, pml4_index, pdpt_index, pd_index, pt_index, pg_size, pg_prot);
+
pml4e = (ept_pml4e_t *)(&pml4[pml4_index]);
decode_ept_entry(EPT_LEVEL_PML4E, (void *)pml4e, &e_phys, &e_pg_prot);
if (!e_pg_prot) {
@@ -404,6 +461,9 @@ int setup_ept(struct vcpu_hw_context *context)

}

+ /* initialize tracing of EPT programming */
+ init_ept_trace();
+
/* most of the reserved bits want zeros */
memset((void *)pml4, 0, PAGE_SIZE);

--
2.25.1

hcha...@xvisor-x86.org

unread,
Jun 18, 2021, 10:24:01 AM6/18/21
to xvisor...@googlegroups.com, Himanshu Chauhan
From: Himanshu Chauhan <hcha...@xvisor-x86.org>

Signed-off-by: Himanshu Chauhan <hcha...@xvisor-x86.org>
---
docs/x86/x86_64_generic.txt | 3 +++
1 file changed, 3 insertions(+)

diff --git a/docs/x86/x86_64_generic.txt b/docs/x86/x86_64_generic.txt
index 0a6856ed..7b8119fa 100644
--- a/docs/x86/x86_64_generic.txt
+++ b/docs/x86/x86_64_generic.txt
@@ -77,6 +77,9 @@ C. Preparing to Boot Guest:
OR ON INTEL
#qemu-system-x86_64 -cpu SandyBridge,hv_relaxed,hv_spinlocks=0x1fff,hv_vapic,hv_time,+vmx -enable-kvm -cdrom bootable.iso -hda xvisor-hd.disk -m 1024m -boot d -serial stdio -vnc :2

+ To enable Qemu monitor on telnet following can be appended to above command:
+ -monitor telnet:127.0.0.1:55555,server,nowait
+
d. Load guest binary:
When Xvisor boots, we will need to load guest binary in memory:
i. First check if the correct block device and its partition are seen by Xvisor. You should see something like this:
--
2.25.1

hcha...@xvisor-x86.org

unread,
Jun 18, 2021, 10:24:02 AM6/18/21
to xvisor...@googlegroups.com, Himanshu Chauhan
From: Himanshu Chauhan <hcha...@xvisor-x86.org>

GRUB boots Xvisor with framebuffer initialized in UEFI mode.
So the early prints are not printed until late when the
framebuffer is initialized.

This patch adds support for early framebuffer. It has following
changes:
1. Change early pagetable setup with 2MB page support
2. Since the framebuffer address can be in the upper 4G region
Current 3-levels of paging structure only maps the code. So
added 16K of extra pages to keep PGDP and PGDI for framebuffers.

Signed-off-by: Himanshu Chauhan <hcha...@xvisor-x86.org>
---
.../common/devices/video/fb_early_console.c | 228 ++++++++++++++++++
.../x86/board/common/devices/video/objects.mk | 1 +
.../x86/board/common/include/video/ter-i16b.h | 3 +-
.../x86/board/common/include/video/ter-i16n.h | 4 +-
arch/x86/board/x86_64_generic/brd_defterm.c | 5 +
arch/x86/cpu/x86_64/cpu_main.c | 9 +-
arch/x86/cpu/x86_64/cpu_mmu.c | 93 +++++--
arch/x86/cpu/x86_64/include/cpu_mmu.h | 4 +
arch/x86/cpu/x86_64/start.S | 5 +
9 files changed, 323 insertions(+), 29 deletions(-)
create mode 100644 arch/x86/board/common/devices/video/fb_early_console.c

diff --git a/arch/x86/board/common/devices/video/fb_early_console.c b/arch/x86/board/common/devices/video/fb_early_console.c
new file mode 100644
index 00000000..63ccf957
--- /dev/null
+++ b/arch/x86/board/common/devices/video/fb_early_console.c
@@ -0,0 +1,228 @@
+/*
+ * Copyright (c) 2021 Himanshu Chauhan.
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+/*!
+ * @file fb_early_console.c
+ * @author Himanshu Chauhan (hcha...@xvisor-x86.org)
+ * @brief Early framebuffer console with only writing capabilities
+ */
+
+#include <vmm_types.h>
+#include <vmm_error.h>
+#include <vmm_compiler.h>
+#include <vmm_host_io.h>
+#include <vmm_params.h>
+#include <libs/stringlib.h>
+#include <video/fb_console.h>
+#include <video/svga.h>
+#include <video/ter-i16b.h>
+#include <video/ter-i16n.h>
+#include <brd_defterm.h>
+#include <multiboot.h>
+#include <cpu_mmu.h>
+
+/* Pointers to fonts */
+static u8 *font_reg, *font_bold;
+/* Video mode info */
+static u16 width, height, depth, bytesPerLine;
+static void *video_base;//, video_size;
+/* Cursor location (in text cells) */
+static u16 col, row;
+/* Set by escape sequences */
+static u8 fg_colour, bg_colour;
+/* Used to parse escape codes */
+static bool next_char_is_escape_seq, is_bold;
+
+extern struct multiboot_info boot_info;
+extern int __create_bootstrap_pgtbl_entry(u64 va, u64 pa, u32 page_size, u8 wt, u8 cd);
+
+#define VMM_ROUNDUP2_SIZE(_address, _size) \
+ ((_address & ~(_size-1)) + _size)
+
+/* Colour code -> 16bpp */
+static u32 early_fb_console_col_map[16] = {
+ 0x000000, 0x0000AA, 0x00AA00, 0x00AAAA,
+ 0xAA0000, 0xAA00AA, 0xAA5500, 0xAAAAAA,
+
+ 0x555555, 0x5555FF, 0x55FF55, 0x55FFFF,
+ 0xFF5555, 0xFF55FF, 0xFFFF55, 0xFFFFFF
+};
+
+static void early_memclr(void *area, u32 size)
+{
+ memset(area, 0, size);
+}
+
+static void early_fb_console_set_font(void* reg, void* bold)
+{
+ if(reg) font_reg = reg;
+ if(bold) font_bold = bold;
+}
+static void early_fb_console_scroll_up(unsigned int num_rows)
+{
+ /* Copy rows upwards */
+ u8 *read_ptr = (u8 *) video_base + ((num_rows * CHAR_HEIGHT) * bytesPerLine);
+ u8 *write_ptr = (u8 *) video_base;
+ unsigned int num_bytes = (bytesPerLine * height) - (bytesPerLine * (num_rows * CHAR_HEIGHT));
+ memcpy(write_ptr, read_ptr, num_bytes);
+
+ /* Clear the rows at the end */
+ read_ptr = (u8 *)(video_base + (bytesPerLine * height) - (bytesPerLine * (num_rows * CHAR_HEIGHT)));
+ early_memclr(read_ptr, bytesPerLine * (num_rows * CHAR_HEIGHT));
+}
+
+static void early_fb_console_control(unsigned char c)
+{
+ switch(c) {
+ case '\n':
+ col = 0;
+ /* We're on the last row, a newline should only scroll the viewport up */
+ if(row == (height / CHAR_HEIGHT)-1) {
+ early_fb_console_scroll_up(1);
+ } else {
+ row++;
+ }
+
+ break;
+
+ default:
+ break;
+ }
+}
+
+int early_fb_defterm_putc(unsigned char c)
+{
+ if (c == '\n') {
+ early_fb_console_control('\n');
+ return VMM_OK;
+ }
+
+ if(c == 0x01) {
+ next_char_is_escape_seq = true;
+ return VMM_OK;
+ }
+
+ /* Check if the following character is part of an escape sequence */
+ if(next_char_is_escape_seq) {
+ /* Codes 0x00 to 0x0F are colours */
+ if(c >= 0x00 && c <= 0x0F) {
+ fg_colour = c;
+ next_char_is_escape_seq = false;
+ } else if(c == 0x10 || c == 0x11) {
+ is_bold = (c == 0x11) ? true : false;
+
+ next_char_is_escape_seq = false;
+ } else {
+ next_char_is_escape_seq = false;
+ }
+ } else { /* Handle printing of a regular character */
+ /* Characters are 16 px tall, i.e. 0x10 bytes in stored rep */
+ u8 *read_ptr = (u8 *) ((is_bold) ? font_bold : font_reg) + (c * CHAR_HEIGHT);
+ u32 *write_base;
+
+ const u8 x_to_bitmap[CHAR_WIDTH] = {0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01};
+ u8 fontChar = 0;
+ u32 out = 0;
+
+ for(u8 y = 0; y < CHAR_HEIGHT; y++) {
+ fontChar = read_ptr[y];
+
+ /* Process one column at a time */
+ if(depth == 4) {
+ write_base = (u32 *) (video_base) + (((bytesPerLine / 4) * CHAR_HEIGHT * row)) + (CHAR_WIDTH * col);
+
+ for(u8 x = 0; x < CHAR_WIDTH; x++) {
+ if(x_to_bitmap[x] & fontChar) {
+ write_base[x+(y * (bytesPerLine / 4))] = early_fb_console_col_map[fg_colour];
+ }
+ }
+ } else if(depth == 2) {
+ write_base = (u32 *) (video_base) + (((bytesPerLine / 4) * CHAR_HEIGHT * row)) + ((CHAR_WIDTH * (col)) >> 1);
+
+ /* In 16bpp, process two pixels at once */
+ for(u8 x = 0; x < CHAR_WIDTH; x+=2) {
+ out = 0;
+
+ if(x_to_bitmap[x] & fontChar) {
+ out = ((SVGA_24TO16BPP(early_fb_console_col_map[fg_colour])) & 0xFFFF) << 16;
+ }
+
+ if(x_to_bitmap[x+1] & fontChar) {
+ out |= ((SVGA_24TO16BPP(early_fb_console_col_map[fg_colour])) & 0xFFFF);
+ }
+
+ write_base[(x >> 1) + (y * (bytesPerLine / 4))] = out;
+ }
+ }
+ }
+
+ /* Increment column and check row */
+ col++;
+
+ if(col > (width / CHAR_WIDTH)) {
+ early_fb_console_control('\n');
+ }
+ }
+
+ return VMM_OK;
+}
+
+int init_early_fb_console(void)
+{
+ virtual_size_t fb_length;
+ u32 nr_pages = 0;
+
+ bytesPerLine = boot_info.framebuffer_pitch;
+ width = boot_info.framebuffer_width;
+ height = boot_info.framebuffer_height;
+ depth = boot_info.framebuffer_bpp/8;
+
+ fb_length = (bytesPerLine * height);
+ fb_length = VMM_ROUNDUP2_SIZE(fb_length, PAGE_SIZE_2M);
+ video_base = (void *)boot_info.framebuffer_addr;
+ nr_pages = fb_length/PAGE_SIZE_2M;
+ fb_length = (bytesPerLine * height);
+
+ while (nr_pages) {
+ if (__create_bootstrap_pgtbl_entry((u64)video_base,
+ (u64)video_base, PAGE_SIZE_2M,
+ 0, 1) != VMM_OK) {
+ return VMM_EFAIL;
+ }
+ video_base += PAGE_SIZE_2M;
+ nr_pages--;
+ }
+
+ video_base = (void *)boot_info.framebuffer_addr;
+
+ early_fb_console_set_font(&ter_i16n_raw, &ter_i16b_raw);
+
+ /* Clear screen */
+ early_memclr((void *)video_base, bytesPerLine * height);
+
+ is_bold = false;
+ next_char_is_escape_seq = false;
+ fg_colour = 0x0F;
+ bg_colour = 0x00;
+
+ col = row = 0;
+
+ early_putc = early_fb_defterm_putc;
+
+ return VMM_OK;
+}
diff --git a/arch/x86/board/common/devices/video/objects.mk b/arch/x86/board/common/devices/video/objects.mk
index 17217df2..8c9d4c07 100644
--- a/arch/x86/board/common/devices/video/objects.mk
+++ b/arch/x86/board/common/devices/video/objects.mk
@@ -24,3 +24,4 @@
board-common-objs-y+= devices/video/vga.o
board-common-objs-y+= devices/video/svga.o
board-common-objs-y+= devices/video/fb_console.o
+board-common-objs-y+= devices/video/fb_early_console.o
diff --git a/arch/x86/board/common/include/video/ter-i16b.h b/arch/x86/board/common/include/video/ter-i16b.h
index 7f8fc5de..52669788 100644
--- a/arch/x86/board/common/include/video/ter-i16b.h
+++ b/arch/x86/board/common/include/video/ter-i16b.h
@@ -5,7 +5,7 @@
*/
#include <vmm_types.h>

-u8 ter_i16b_raw[] = {
+static u8 ter_i16b_raw[] = {
0x00, 0x00, 0xfe, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xfe, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x7c, 0x82, 0xaa, 0x82, 0x82, 0xba, 0x92, 0x82, 0x82, 0x7c, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x7c, 0xfe, 0xd6, 0xfe, 0xfe, 0xc6, 0xee, 0xfe, 0xfe, 0x7c, 0x00, 0x00, 0x00, 0x00,
@@ -263,4 +263,3 @@ u8 ter_i16b_raw[] = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0x7c, 0x7c, 0x7c, 0x7c, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};
-unsigned int ter_i16b_raw_len = 4096;
diff --git a/arch/x86/board/common/include/video/ter-i16n.h b/arch/x86/board/common/include/video/ter-i16n.h
index 3eb3d786..1106a26a 100644
--- a/arch/x86/board/common/include/video/ter-i16n.h
+++ b/arch/x86/board/common/include/video/ter-i16n.h
@@ -5,7 +5,7 @@
*/
#include <vmm_types.h>

-u8 ter_i16n_raw[] = {
+static u8 ter_i16n_raw[] = {
0x00, 0x00, 0x7e, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x7e, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x7c, 0x82, 0xaa, 0x82, 0x82, 0xba, 0x92, 0x82, 0x82, 0x7c, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x7c, 0xfe, 0xd6, 0xfe, 0xfe, 0xc6, 0xee, 0xfe, 0xfe, 0x7c, 0x00, 0x00, 0x00, 0x00,
@@ -263,5 +263,3 @@ u8 ter_i16n_raw[] = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};
-
-unsigned int ter_i16n_raw_len = 4096;
diff --git a/arch/x86/board/x86_64_generic/brd_defterm.c b/arch/x86/board/x86_64_generic/brd_defterm.c
index 76e511fb..02f1149c 100644
--- a/arch/x86/board/x86_64_generic/brd_defterm.c
+++ b/arch/x86/board/x86_64_generic/brd_defterm.c
@@ -39,6 +39,7 @@
static char cmdline_console_string[CONSOLE_SETUP_STR_LEN];
static struct defterm_ops *ops = NULL;
EARLY_PUTC early_putc = NULL;
+int init_early_fb_console(void);

void arch_defterm_early_putc(u8 ch)
{
@@ -58,6 +59,9 @@ static int __init setup_early_print(char *buf)
if (!strncmp(buf, VGA_CONSOLE_NAME, strlen(VGA_CONSOLE_NAME)))
return init_early_vga_console();

+ if (!strncmp(buf, FB_CONSOLE_NAME, strlen(FB_CONSOLE_NAME)))
+ return init_early_fb_console();
+
return VMM_EFAIL;
}

@@ -79,6 +83,7 @@ static int __init set_default_console(char *buf)

vmm_snprintf(cmdline_console_string, strlen(DEFAULT_CONSOLE_STR),
DEFAULT_CONSOLE_STR);
+
return VMM_OK;
}

diff --git a/arch/x86/cpu/x86_64/cpu_main.c b/arch/x86/cpu/x86_64/cpu_main.c
index 4186de44..d15651b0 100644
--- a/arch/x86/cpu/x86_64/cpu_main.c
+++ b/arch/x86/cpu/x86_64/cpu_main.c
@@ -230,7 +230,7 @@ void arch_cpu_print_summary(struct vmm_chardev *cdev)
(cpu_info.hw_virt_available ? "Supported" : "Unsupported"));
}

-extern void __create_bootstrap_pgtbl_entry(u64 va, u64 pa);
+extern void __create_bootstrap_pgtbl_entry(u64 va, u64 pa, u32 page_size, u8 wt, u8 cd);
extern void __delete_bootstrap_pgtbl_entry(u64 va);

/*
@@ -246,7 +246,8 @@ static void __init boot_modules_move(struct multiboot_info *binfo)
u64 daddr, saddr;
int i;

- __create_bootstrap_pgtbl_entry(binfo->mods_addr, binfo->mods_addr);
+ __create_bootstrap_pgtbl_entry(binfo->mods_addr, binfo->mods_addr,
+ 4096, 0, 0);

modlist = (struct multiboot_mod_list *)((u64)binfo->mods_addr);

@@ -299,8 +300,8 @@ static void __init boot_modules_move(struct multiboot_info *binfo)
mod_size = VMM_ROUNDUP2_PAGE_SIZE(mod_size);

while (mod_size) {
- __create_bootstrap_pgtbl_entry(saddr, saddr);
- __create_bootstrap_pgtbl_entry(daddr, daddr);
+ __create_bootstrap_pgtbl_entry(saddr, saddr, 4096, 0, 0);
+ __create_bootstrap_pgtbl_entry(daddr, daddr, 4096, 0, 0);
memcpy((void *)daddr, (void *)saddr, VMM_PAGE_SIZE);
__delete_bootstrap_pgtbl_entry(daddr);
__delete_bootstrap_pgtbl_entry(saddr);
diff --git a/arch/x86/cpu/x86_64/cpu_mmu.c b/arch/x86/cpu/x86_64/cpu_mmu.c
index 7f61483b..ee09400e 100644
--- a/arch/x86/cpu/x86_64/cpu_mmu.c
+++ b/arch/x86/cpu/x86_64/cpu_mmu.c
@@ -46,9 +46,26 @@ extern u64 __pml4[];
extern u64 __pgdp[];
extern u64 __pgdi[];
extern u64 __pgti[];
+extern u64 __early_iodev_pages[];

+static char *early_iodev_pages = (char *)__early_iodev_pages;
+static early_iodev_pages_used = 0;
struct page_table host_pgtbl_array[HOST_PGTBL_MAX_TABLE_COUNT];

+static
+char *alloc_iodev_page(void)
+{
+ char *iodev_page = NULL;
+
+ if (early_iodev_pages_used >= NR_IODEV_PAGES)
+ return NULL;
+
+ iodev_page = (early_iodev_pages + (early_iodev_pages_used * PAGE_SIZE));
+ early_iodev_pages_used++;
+
+ return iodev_page;
+}
+
static void arch_preinit_pgtable_entries(void)
{
int i;
@@ -68,13 +85,18 @@ static void arch_preinit_pgtable_entries(void)
__pgdi[i] = ((u64)(pgti_base + (PAGE_SIZE * i)) & PAGE_MASK) + 3;
}

-int __create_bootstrap_pgtbl_entry(u64 va, u64 pa)
+int __create_bootstrap_pgtbl_entry(u64 va, u64 pa, u32 page_size,
+ u8 wt, u8 cd)
{
static int preinit_pgtables = 0;
union page ent;

ent._val = 0;

+ if ((page_size != PAGE_SIZE_2M) && (page_size != PAGE_SIZE_4K)) {
+ return VMM_EFAIL;
+ }
+
if (!preinit_pgtables) {
arch_preinit_pgtable_entries();
preinit_pgtables = 1;
@@ -90,23 +112,55 @@ int __create_bootstrap_pgtbl_entry(u64 va, u64 pa)

u64 *pgdp_base = (u64 *)(((u64)__pml4[pml4_index]) & ~0xff);

- if (!(pgdp_base[pgdp_index] & 0x3))
- return VMM_EFAIL;
+ if (pgdp_base[pgdp_index] == 0) {
+ pgdp_base[pgdp_index] = alloc_iodev_page();
+ if (pgdp_base[pgdp_index] == NULL)
+ return VMM_EFAIL;
+ pgdp_base[pgdp_index] |= 0x3;
+ } else {
+ if (!(pgdp_base[pgdp_index] & 0x3))
+ return VMM_EFAIL;
+ }

u64 *pgdi_base = (u64 *)(((u64)pgdp_base[pgdp_index]) & ~0xff);

- if (!(pgdi_base[pgdp_index] & 0x3))
- return VMM_EFAIL;
+ if (pgdi_base[pgdi_index] == 0) {
+ if (page_size == PAGE_SIZE_2M) {
+ pgdi_base[pgdi_index] |= ((pa >> 21) << 21);
+ pgdi_base[pgdi_index] |= (0x1UL << 7);
+ pgdi_base[pgdi_index] |= (wt ? (0x1UL << 3) : 0);
+ pgdi_base[pgdi_index] |= (cd ? (0x1UL << 4) : 0);
+ pgdi_base[pgdi_index] |= 0x3;
+ return VMM_OK;
+ } else {
+ pgdi_base[pgdi_index] = alloc_iodev_page();
+ if (pgdi_base[pgdi_index] == NULL)
+ return VMM_EFAIL;
+ pgdi_base[pgdi_index] |= 0x3;
+ }
+ } else {
+ if (!(pgdi_base[pgdi_index] & 0x3))
+ return VMM_EFAIL;
+ }

u64 *pgti_base = (u64 *)(((u64)pgdi_base[pgdi_index]) & ~0xff);

- if (pgti_base[pgti_index] & 0x3)
- return VMM_EFAIL;
+ if (pgti_base[pgti_index] == 0) {
+ pgti_base[pgti_index] = alloc_iodev_page();
+ if (pgti_base[pgti_index] == NULL)
+ return VMM_EFAIL;
+ pgti_base[pgti_index] |= 0x3;
+ } else {
+ if (pgti_base[pgti_index] & 0x3)
+ return VMM_EFAIL;
+ }

ent.bits.paddr = pa >> PAGE_SHIFT;
ent.bits.present = 1;
ent.bits.rw = 1;
pgti_base[pgti_index] = ent._val;
+ pgti_base[pgti_index] |= (wt ? (0x1UL << 3) : 0);
+ pgti_base[pgti_index] |= (cd ? (0x1UL << 4) : 0);

invalidate_vaddr_tlb(va);

@@ -249,7 +303,7 @@ int __init arch_cpu_aspace_primary_init(physical_addr_t *core_resv_pa,
*/
arch_preinit_pgtable_entries();

- /* Check & setup core reserved space and update the
+ /* Check & setup core reserved space and update the
* core_resv_pa, core_resv_va, and core_resv_sz parameters
* to inform host aspace about correct placement of the
* core reserved space.
@@ -272,8 +326,8 @@ int __init arch_cpu_aspace_primary_init(physical_addr_t *core_resv_pa,
*core_resv_va = resv_va;
*core_resv_sz = resv_sz;

- /* Initialize MMU control and allocate arch reserved space and
- * update the *arch_resv_pa, *arch_resv_va, and *arch_resv_sz
+ /* Initialize MMU control and allocate arch reserved space and
+ * update the *arch_resv_pa, *arch_resv_va, and *arch_resv_sz
* parameters to inform host aspace about the arch reserved space.
*/
memset(&host_pgtbl_ctl, 0, sizeof(host_pgtbl_ctl));
@@ -309,8 +363,8 @@ int __init arch_cpu_aspace_primary_init(physical_addr_t *core_resv_pa,
pgtbl->stage = 0;
pgtbl->parent = NULL;
pgtbl->map_ia = 0;
- pgtbl->tbl_pa = (virtual_addr_t)__pml4 -
- arch_code_vaddr_start() +
+ pgtbl->tbl_pa = (virtual_addr_t)__pml4 -
+ arch_code_vaddr_start() +
arch_code_paddr_start();
INIT_SPIN_LOCK(&pgtbl->tbl_lock);
pgtbl->tbl_va = (virtual_addr_t)__pml4;
@@ -331,8 +385,8 @@ int __init arch_cpu_aspace_primary_init(physical_addr_t *core_resv_pa,
pgtbl->stage = 0;
pgtbl->parent = &host_pgtbl_ctl.pgtbl_pml4;
pgtbl->map_ia = arch_code_vaddr_start() & mmu_level_map_mask(0);
- pgtbl->tbl_pa = (virtual_addr_t)__pgdp -
- arch_code_vaddr_start() +
+ pgtbl->tbl_pa = (virtual_addr_t)__pgdp -
+ arch_code_vaddr_start() +
arch_code_paddr_start();
INIT_SPIN_LOCK(&pgtbl->tbl_lock);
pgtbl->tbl_va = (virtual_addr_t)__pgdp;
@@ -355,8 +409,8 @@ int __init arch_cpu_aspace_primary_init(physical_addr_t *core_resv_pa,
pgtbl->stage = 0;
pgtbl->parent = &host_pgtbl_ctl.pgtbl_pgdp;
pgtbl->map_ia = arch_code_vaddr_start() & mmu_level_map_mask(1);
- pgtbl->tbl_pa = (virtual_addr_t)__pgdi -
- arch_code_vaddr_start() +
+ pgtbl->tbl_pa = (virtual_addr_t)__pgdi -
+ arch_code_vaddr_start() +
arch_code_paddr_start();
INIT_SPIN_LOCK(&pgtbl->tbl_lock);
pgtbl->tbl_va = (virtual_addr_t)__pgdi;
@@ -379,8 +433,8 @@ int __init arch_cpu_aspace_primary_init(physical_addr_t *core_resv_pa,
pgtbl->stage = 0;
pgtbl->parent = &host_pgtbl_ctl.pgtbl_pgdi;
pgtbl->map_ia = arch_code_vaddr_start() & mmu_level_map_mask(2);
- pgtbl->tbl_pa = (virtual_addr_t)__pgti -
- arch_code_vaddr_start() +
+ pgtbl->tbl_pa = (virtual_addr_t)__pgti -
+ arch_code_vaddr_start() +
arch_code_paddr_start();
INIT_SPIN_LOCK(&pgtbl->tbl_lock);
pgtbl->tbl_va = (virtual_addr_t)__pgti;
@@ -412,7 +466,7 @@ int __init arch_cpu_aspace_primary_init(physical_addr_t *core_resv_pa,
hyppg._val = 0x0;
hyppg.bits.paddr = (pa >> PAGE_SHIFT);
hyppg.bits.present = 1;
- hyppg.bits.rw = 1;
+ hyppg.bits.rw = 1;
if ((rc = mmu_map_page(&host_pgtbl_ctl, host_pgtbl_ctl.base_pgtbl, va, &hyppg))) {
goto mmu_init_error;
}
@@ -439,4 +493,3 @@ int __cpuinit arch_cpu_aspace_secondary_init(void)
/* FIXME: For now nothing to do here. */
return VMM_OK;
}
-
diff --git a/arch/x86/cpu/x86_64/include/cpu_mmu.h b/arch/x86/cpu/x86_64/include/cpu_mmu.h
index db49e7e1..4dec7947 100644
--- a/arch/x86/cpu/x86_64/include/cpu_mmu.h
+++ b/arch/x86/cpu/x86_64/include/cpu_mmu.h
@@ -27,6 +27,7 @@
#define NR_PGDP_PAGES 4
#define NR_PGDI_PAGES 8
#define NR_PGTI_PAGES 32
+#define NR_IODEV_PAGES 4

#define VMM_CODE_SEG_SEL 0x08
#define VMM_DATA_SEG_SEL 0x10
@@ -80,6 +81,9 @@

extern struct pgtbl_ctrl host_pgtbl_ctl;

+#define PAGE_SIZE_1G (0x40000000UL)
+#define PAGE_SIZE_2M (0x200000UL)
+#define PAGE_SIZE_4K (0x1000UL)

static inline void invalidate_vaddr_tlb(virtual_addr_t vaddr)
{
diff --git a/arch/x86/cpu/x86_64/start.S b/arch/x86/cpu/x86_64/start.S
index 9a120467..7b2f5f57 100644
--- a/arch/x86/cpu/x86_64/start.S
+++ b/arch/x86/cpu/x86_64/start.S
@@ -323,6 +323,11 @@ __pgdi:
__pgti:
.zero (PAGE_SIZE * NR_PGTI_PAGES)

+__early_iodev_pages:
+ .globl __early_iodev_pages
+ .align 32
+ .type __early_iodev_pages, @object
+ .zero (PAGE_SIZE * NR_IODEV_PAGES)

.align 4
.type _mboot_info, @object
--
2.25.1

Reply all
Reply to author
Forward
0 new messages