From: Petr Tesarik <petr.tesarik1@xxxxxxxxxxxxxxxxxxx> Map CPU system data structures (GDT, TSS, IDT) read-only into every sandbox instance. Map interrupt stacks read-write. The TSS mappings may look confusing. The trick is that TSS pages are mapped twice in the kernel address space: once read-only and once read-write. The GDT entry for the TR register uses the read-only address, but since __pa() does not work for virtual addresses in this range (cpu_entry_area), use the read-write mapping to get TSS physical address. Signed-off-by: Petr Tesarik <petr.tesarik1@xxxxxxxxxxxxxxxxxxx> --- arch/x86/include/asm/page_64_types.h | 1 + arch/x86/kernel/sbm/core.c | 74 ++++++++++++++++++++++++++++ 2 files changed, 75 insertions(+) diff --git a/arch/x86/include/asm/page_64_types.h b/arch/x86/include/asm/page_64_types.h index 06ef25411d62..62f6e40b3361 100644 --- a/arch/x86/include/asm/page_64_types.h +++ b/arch/x86/include/asm/page_64_types.h @@ -29,6 +29,7 @@ #define IST_INDEX_DB 2 #define IST_INDEX_MCE 3 #define IST_INDEX_VC 4 +#define IST_INDEX_NUM 7 /* * Set __PAGE_OFFSET to the most negative possible address + diff --git a/arch/x86/kernel/sbm/core.c b/arch/x86/kernel/sbm/core.c index de6986801148..f3a123d64afc 100644 --- a/arch/x86/kernel/sbm/core.c +++ b/arch/x86/kernel/sbm/core.c @@ -7,9 +7,13 @@ * SandBox Mode (SBM) implementation for the x86 architecture. */ +#include <asm/cpu_entry_area.h> +#include <asm/desc.h> #include <asm/pgtable.h> +#include <asm/page.h> #include <asm/sbm.h> #include <asm/sections.h> +#include <linux/cpumask.h> #include <linux/mm.h> #include <linux/sbm.h> #include <linux/sched/task_stack.h> @@ -155,6 +159,72 @@ static int map_kernel(struct x86_sbm_state *state) return 0; } +/** map_cpu_data() - map CPU system data structures into a sandbox instance + * @sbm: Target sandbox instance. + * + * Create sandbox page tables for: + * * Global Descriptor Table (GDT) + * * Task State Segment (TSS) + * * Interrupt Descriptor Table (IDT). + * + * Return: Zero on success, negative error code on failure. + */ +static int map_cpu_data(struct x86_sbm_state *state) +{ + unsigned long off; + phys_addr_t paddr; + unsigned int ist; + void *vaddr; + int cpu; + int err; + + for_each_possible_cpu(cpu) { + struct cpu_entry_area *cea; + struct tss_struct *tss; + + err = map_page(state, (unsigned long)get_cpu_gdt_ro(cpu), + PHYS_PFN(get_cpu_gdt_paddr(cpu)), + PAGE_KERNEL_RO); + if (err) + return err; + + cea = get_cpu_entry_area(cpu); + + tss = &cea->tss; + paddr = __pa(&per_cpu(cpu_tss_rw, cpu)); + for (off = 0; off < sizeof(cpu_tss_rw); off += PAGE_SIZE) { + err = map_page(state, (unsigned long)tss + off, + PHYS_PFN(paddr + off), PAGE_KERNEL_RO); + if (err) + return err; + } + + paddr = slow_virt_to_phys(&cea->entry_stack_page); + err = map_page(state, (unsigned long)&cea->entry_stack_page, + PHYS_PFN(paddr), PAGE_KERNEL); + if (err) + return err; + + for (ist = 0; ist < IST_INDEX_NUM; ++ist) { + vaddr = (void *)tss->x86_tss.ist[ist]; + if (!vaddr) + continue; + + for (off = EXCEPTION_STKSZ; off; off -= PAGE_SIZE) { + paddr = slow_virt_to_phys(vaddr - off); + err = map_page(state, (unsigned long)vaddr - off, + PHYS_PFN(paddr), PAGE_KERNEL); + if (err) + return err; + } + } + } + + paddr = slow_virt_to_phys((void *)CPU_ENTRY_AREA_RO_IDT); + return map_page(state, CPU_ENTRY_AREA_RO_IDT, PHYS_PFN(paddr), + PAGE_KERNEL_RO); +} + int arch_sbm_init(struct sbm *sbm) { struct x86_sbm_state *state; @@ -194,6 +264,10 @@ int arch_sbm_init(struct sbm *sbm) if (err) return err; + err = map_cpu_data(state); + if (err) + return err; + return 0; } -- 2.34.1