lx_emul: finalize support for x86_32 and x86_64

Original commit by Josef Soentgen.

Fix genodelabs/genode#4411
This commit is contained in:
Stefan Kalkowski 2022-02-09 15:06:08 +01:00 committed by Norman Feske
parent 5a48f8ab0f
commit da55425114
17 changed files with 661 additions and 0 deletions

View File

@ -0,0 +1,12 @@
/**
* \brief Shadow copy of asm/cpufeature.h
* \author Josef Soentgen
* \date 2022-01-14
*/
#ifndef _ASM__CPUFEATURE_H_
#define _ASM__CPUFEATURE_H_
#define boot_cpu_has(bit) 0
#endif

View File

@ -0,0 +1,9 @@
/**
* \brief Shadow copy of asm/debugreg.h
* \author Josef Soentgen
* \date 2022-01-14
*/
#ifndef _ASM__DEBUGREG_H_
#define _ASM__DEBUGREG_H_
#endif

View File

@ -0,0 +1,27 @@
/*
* \brief Shadows Linux kernel asm-generic/memory_model.h
* \author Norman Feske
* \date 2021-06-25
*/
/*
* Copyright (C) 2021 Genode Labs GmbH
*
* This file is distributed under the terms of the GNU General Public License
* version 2.
*/
#ifndef __ASM_MEMORY_MODEL_H
#define __ASM_MEMORY_MODEL_H
#include <linux/pfn.h>
#ifndef __ASSEMBLY__
#define page_to_pfn(page) virt_to_pfn(page_to_virt(page))
#define pfn_to_page(pfn) virt_to_page(pfn_to_virt(pfn))
#endif /* __ASSEMBLY__ */
#endif /* __ASM_MEMORY_MODEL_H */

View File

@ -0,0 +1,74 @@
/*
* \brief Shadows Linux kernel asm-generic/page.h
* \author Norman Feske
* \date 2021-06-25
*/
/*
* Copyright (C) 2021 Genode Labs GmbH
*
* This file is distributed under the terms of the GNU General Public License
* version 2.
*/
#ifndef __ASM_GENERIC_PAGE_H
#define __ASM_GENERIC_PAGE_H
#include <asm/page_types.h>
#ifdef CONFIG_X86_64
#include <asm/page_64.h>
#else
#include <asm/page_32.h>
#endif /* CONFIG_X86_64 */
/*
* The 'virtual' member of 'struct page' is needed by 'lx_emul_virt_to_phys'
* and 'page_to_virt'.
*/
#define WANT_PAGE_VIRTUAL
#ifndef __ASSEMBLY__
#include <lx_emul/debug.h>
#include <lx_emul/page_virt.h>
#include <lx_emul/alloc.h>
struct page;
#include <linux/range.h>
extern struct range pfn_mapped[];
extern int nr_pfn_mapped;
static inline void clear_user_page(void *page, unsigned long vaddr,
struct page *pg)
{
clear_page(page);
}
static inline void copy_user_page(void *to, void *from, unsigned long vaddr,
struct page *topage)
{
copy_page(to, from);
}
typedef struct page *pgtable_t;
#define __va(x) ((void*)lx_emul_mem_virt_addr((void*)(x)))
#define __pa(x) lx_emul_mem_dma_addr((void *)(x))
#define virt_to_pfn(kaddr) (__pa(kaddr) >> PAGE_SHIFT)
#define pfn_to_virt(pfn) __va((pfn) << PAGE_SHIFT)
#define pfn_to_kaddr(pfn) __va((pfn) << PAGE_SHIFT)
static inline struct page *virt_to_page(void const *v) { return lx_emul_virt_to_pages(v, 1U); }
#define page_to_virt(p) ((p)->virtual)
#define virt_addr_valid(kaddr) ((unsigned long)kaddr != 0UL)
#endif /* __ASSEMBLY__ */
#include <asm/memory_model.h>
#include <asm-generic/getorder.h>
#endif /* __ASM_GENERIC_PAGE_H */

View File

@ -0,0 +1,49 @@
/*
* \brief Shadows Linux kernel arch/x86/include/asm/pgtable.h
* \author Stefan Kalkowski
* \date 2022-01-25
*/
/*
* Copyright (C) 2022 Genode Labs GmbH
*
* This file is distributed under the terms of the GNU General Public License
* version 2.
*/
#ifndef _ASM__X86__PGTABLE_H
#define _ASM__X86__PGTABLE_H
#include <linux/mem_encrypt.h>
#include <asm/page.h>
#include <asm/pgtable_types.h>
#include <lx_emul/debug.h>
static inline pte_t pte_mkwrite(pte_t pte) { return pte; }
static inline bool __pkru_allows_pkey(u16 pkey, bool write)
{
lx_emul_trace_and_stop(__func__);
}
extern unsigned long empty_zero_page[PAGE_SIZE / sizeof(unsigned long)];
#define ZERO_PAGE(vaddr) ((void)(vaddr),virt_to_page(empty_zero_page))
#ifdef CONFIG_X86_64
static inline int p4d_none(p4d_t p4d)
{
lx_emul_trace_and_stop(__func__);
}
static inline int pud_none(pud_t pud)
{
lx_emul_trace_and_stop(__func__);
}
#endif
#endif /*_ASM__X86__PGTABLE_H */

View File

@ -0,0 +1,13 @@
/**
* \brief Shadow copy of asm/sections.h
* \author Josef Soentgen
* \date 2022-01-13
*/
#ifndef _ASM__SECTIONS_H_
#define _ASM__SECTIONS_H_
#include <asm-generic/sections.h>
#include <asm/extable.h>
#endif

View File

@ -0,0 +1,9 @@
/**
* \brief Shadow copy of asm/switch_to.h
* \author Josef Soentgen
* \date 2022-01-14
*/
#ifndef _ASM__SWITCH_TO_H_
#define _ASM__SWITCH_TO_H_
#endif

View File

@ -0,0 +1,9 @@
/**
* \brief Shadow copy of asm/sync_core.h
* \author Josef Soentgen
* \date 2022-01-14
*/
#ifndef _ASM__SYNC_CORE_H_
#define _ASM__SYNC_CORE_H_
#endif

View File

@ -0,0 +1,18 @@
/**
* \brief Shadow copy of asm/uaccess.h
* \author Josef Soentgen
* \date 2022-01-14
*/
#ifndef _ASM__UACCESS_H_
#define _ASM__UACCESS_H_
#include_next <asm/uaccess.h>
#undef put_user
#undef get_user
#define get_user(x, ptr) ({ (x) = *(ptr); 0; })
#define put_user(x, ptr) ({ *(ptr) = (x); 0; })
#endif

View File

@ -0,0 +1,28 @@
/*
* \brief Shadow copy of linux/compiler-gcc.h
* \author Stefan Kalkowski
* \date 2021-03-17
*/
/*
* Copyright (C) 2021 Genode Labs GmbH
*
* This file is distributed under the terms of the GNU General Public License
* version 2.
*/
#ifndef _LX_EMUL__SHADOW__LINUX__COMPILER_GCC_H_
#define _LX_EMUL__SHADOW__LINUX__COMPILER_GCC_H_
#include_next <linux/compiler-gcc.h>
/**
* We have to re-define `asm_volatile_goto`, because the original function
* uses `asm goto(...)`, which is a problem when building PIC code.
*/
#ifdef asm_volatile_goto
#undef asm_volatile_goto
#define asm_volatile_goto(x...) asm volatile("invalid use of asm_volatile_goto")
#endif
#endif /* _LX_EMUL__SHADOW__LINUX__COMPILER_GCC_H_ */

View File

@ -0,0 +1,22 @@
/**
* \brief Shadow copy of linux/pci.h
* \author Josef Soentgen
* \date 2022-01-14
*/
#ifndef _LINUX__PCI_H_
#define _LINUX__PCI_H_
#include <lx_emul/init.h>
#include_next <linux/pci.h>
#undef DECLARE_PCI_FIXUP_CLASS_FINAL
#define DECLARE_PCI_FIXUP_CLASS_FINAL(vendor, device, class, \
class_shift, hook) \
static void __pci_fixup_final_##hook(struct pci_dev *dev) __attribute__((constructor)); \
static void __pci_fixup_final_##hook(struct pci_dev *dev) { \
lx_emul_register_pci_fixup(hook, __func__); };
#endif /* _LINUX__PCI_H_ */

View File

@ -0,0 +1,9 @@
/**
* \brief Shadow copy of linux/swapops.h
* \author Josef Soentgen
* \date 2022-01-14
*/
#ifndef _LINUX__SWAPOPS_H_
#define _LINUX__SWAPOPS_H_
#endif

View File

@ -0,0 +1,59 @@
/**
* \brief Shadow copy of asm/atomic64_32.h
* \author Josef Soentgen
* \date 2022-01-31
*
* This header contains all declarations but only a handful are
* actually implemented.
*/
#ifndef _ASM__ATOMIC64_32_H_
#define _ASM__ATOMIC64_32_H_
#include <linux/types.h>
typedef struct {
s64 __aligned(8) counter;
} atomic64_t;
s64 arch_atomic64_add(s64 i, atomic64_t *v);
s64 arch_atomic64_add_return(s64 i, atomic64_t *v);
int arch_atomic64_add_unless(atomic64_t *v, s64 a, s64 u);
void arch_atomic64_and(s64 i, atomic64_t *v);
s64 arch_atomic64_cmpxchg(atomic64_t *v, s64 o, s64 n);
void arch_atomic64_dec(atomic64_t *v);
s64 arch_atomic64_dec_if_positive(atomic64_t *v);
s64 arch_atomic64_dec_return(atomic64_t *v);
s64 arch_atomic64_fetch_add(s64 i, atomic64_t *v);
s64 arch_atomic64_fetch_and(s64 i, atomic64_t *v);
s64 arch_atomic64_fetch_or(s64 i, atomic64_t *v);
s64 arch_atomic64_fetch_xor(s64 i, atomic64_t *v);
void arch_atomic64_inc(atomic64_t *v);
int arch_atomic64_inc_not_zero(atomic64_t *v);
s64 arch_atomic64_inc_return(atomic64_t *v);
void arch_atomic64_or(s64 i, atomic64_t *v);
s64 arch_atomic64_read(const atomic64_t *v);
void arch_atomic64_set(atomic64_t *v, s64 i);
s64 arch_atomic64_sub(s64 i, atomic64_t *v);
s64 arch_atomic64_sub_return(s64 i, atomic64_t *v);
s64 arch_atomic64_xchg(atomic64_t *v, s64 n);
void arch_atomic64_xor(s64 i, atomic64_t *v);
#define arch_atomic64_cmpxchg arch_atomic64_cmpxchg
#define arch_atomic64_xchg arch_atomic64_xchg
#define arch_atomic64_add_return arch_atomic64_add_return
#define arch_atomic64_sub_return arch_atomic64_sub_return
#define arch_atomic64_inc_return arch_atomic64_inc_return
#define arch_atomic64_dec_return arch_atomic64_dec_return
#define arch_atomic64_inc arch_atomic64_inc
#define arch_atomic64_dec arch_atomic64_dec
#define arch_atomic64_add_unless arch_atomic64_add_unless
#define arch_atomic64_inc_not_zero arch_atomic64_inc_not_zero
#define arch_atomic64_dec_if_positive arch_atomic64_dec_if_positive
#define arch_atomic64_fetch_and arch_atomic64_fetch_and
#define arch_atomic64_fetch_or arch_atomic64_fetch_or
#define arch_atomic64_fetch_xor arch_atomic64_fetch_xor
#define arch_atomic64_fetch_add arch_atomic64_fetch_add
#define arch_atomic64_fetch_sub(i, v) arch_atomic64_fetch_add(-(i), (v))
#endif /* _ASM__ATOMIC64_32_H_ */

View File

@ -0,0 +1,9 @@
/**
* \brief Shadow copy of asm/string_32.h
* \author Josef Soentgen
* \date 2022-01-31
*/
#ifndef _ASM__STRING_32_H_
#define _ASM__STRING_32_H_
#endif /* _ASM__STRING_32_H_ */

View File

@ -0,0 +1,95 @@
/*
* \brief Linux DDE x86 interrupt controller
* \author Josef Soentgen
* \date 2022-01-20
*/
/*
* Copyright (C) 2022 Genode Labs GmbH
*
* This file is distributed under the terms of the GNU General Public License
* version 2.
*/
#include <lx_emul/debug.h>
#include <lx_emul/irq.h>
#include <linux/irq.h>
#include <linux/irqchip.h>
#include <../kernel/irq/internals.h>
static void dde_irq_unmask(struct irq_data *d)
{
lx_emul_irq_unmask(d->hwirq);
}
static void dde_irq_mask(struct irq_data *d)
{
lx_emul_irq_mask(d->hwirq);
}
struct irq_chip dde_irqchip_data_chip = {
.name = "dde-irqs",
.irq_mask = dde_irq_mask,
.irq_disable = dde_irq_mask,
.irq_unmask = dde_irq_unmask,
.irq_mask_ack = dde_irq_mask,
};
int lx_emul_irq_task_function(void * data)
{
int irq;
for (;;) {
lx_emul_task_schedule(true);
irq_enter();
irq = lx_emul_irq_last();
if (!irq) {
ack_bad_irq(irq);
WARN_ONCE(true, "Unexpected interrupt %d received!\n",
lx_emul_irq_last());
} else {
generic_handle_irq(irq);
}
irq_exit();
}
return 0;
}
struct task_struct irq_task = {
.__state = 0,
.usage = REFCOUNT_INIT(2),
.flags = PF_KTHREAD,
.prio = MAX_PRIO - 20,
.static_prio = MAX_PRIO - 20,
.normal_prio = MAX_PRIO - 20,
.policy = SCHED_NORMAL,
.cpus_ptr = &irq_task.cpus_mask,
.cpus_mask = CPU_MASK_ALL,
.nr_cpus_allowed = 1,
.mm = NULL,
.active_mm = NULL,
.tasks = LIST_HEAD_INIT(irq_task.tasks),
.real_parent = &irq_task,
.parent = &irq_task,
.children = LIST_HEAD_INIT(irq_task.children),
.sibling = LIST_HEAD_INIT(irq_task.sibling),
.group_leader = &irq_task,
.comm = "kirqd",
.thread = INIT_THREAD,
.pending = {
.list = LIST_HEAD_INIT(irq_task.pending.list),
.signal = {{0}}
},
.blocked = {{0}},
};
void * lx_emul_irq_task_struct = &irq_task;

View File

@ -0,0 +1,194 @@
/*
* \brief Linux kernel PCI
* \author Josef Soentgen
* \date 2022-01-14
*/
/*
* Copyright (C) 2022 Genode Labs GmbH
*
* This file is distributed under the terms of the GNU General Public License
* version 2.
*/
#include <lx_emul.h>
#include <linux/slab.h>
#include <linux/interrupt.h>
int arch_probe_nr_irqs(void)
{
return 16;
}
#include <asm/x86_init.h>
static int x86_init_pci_init(void)
{
return 1;
}
static void x86_init_pci_init_irq(void) { }
struct x86_init_ops x86_init = {
.pci = {
.init = x86_init_pci_init,
.init_irq = x86_init_pci_init_irq,
},
};
#include <lx_emul/pci_config_space.h>
#include <linux/pci.h>
#include <asm/pci.h>
#include <asm/pci_x86.h>
static int pci_raw_ops_read(unsigned int domain, unsigned int bus, unsigned int devfn,
int reg, int len, u32 *val)
{
return lx_emul_pci_read_config(bus, devfn, (unsigned)reg, (unsigned)len, val);
}
static int pci_raw_ops_write(unsigned int domain, unsigned int bus, unsigned int devfn,
int reg, int len, u32 val)
{
return lx_emul_pci_write_config(bus, devfn, (unsigned)reg, (unsigned)len, val);
}
const struct pci_raw_ops genode_raw_pci_ops = {
.read = pci_raw_ops_read,
.write = pci_raw_ops_write,
};
const struct pci_raw_ops *raw_pci_ops = &genode_raw_pci_ops;
static int pci_read(struct pci_bus *bus, unsigned int devfn, int where, int size, u32 *value)
{
return pci_raw_ops_read(0, bus->number, devfn, where, size, value);
}
static int pci_write(struct pci_bus *bus, unsigned int devfn, int where, int size, u32 value)
{
return pci_raw_ops_write(0, bus->number, devfn, where, size, value);
}
struct pci_ops pci_root_ops = {
.read = pci_read,
.write = pci_write,
};
#include <lx_emul/init.h>
static struct resource _dummy_parent;
void pcibios_scan_root(int busnum)
{
struct pci_bus *bus;
struct pci_sysdata *sd;
struct pci_dev *dev;
LIST_HEAD(resources);
sd = kzalloc(sizeof(*sd), GFP_KERNEL);
if (!sd) {
return;
}
sd->node = NUMA_NO_NODE;
pci_add_resource(&resources, &ioport_resource);
pci_add_resource(&resources, &iomem_resource);
bus = pci_scan_root_bus(NULL, busnum, &pci_root_ops, sd, &resources);
if (!bus) {
pci_free_resource_list(&resources);
kfree(sd);
return;
}
pci_bus_add_devices(bus);
/* handle early quirks */
list_for_each_entry(dev, &bus->devices, bus_list) {
/*
* As pci_enable_resources() is only going to check if
* the parent of the resource is set register the dummy.
*/
struct resource *r;
int i;
for (i = 0; i < PCI_NUM_RESOURCES; i++) {
r = &dev->resource[i];
r->parent = &_dummy_parent;
}
lx_emul_execute_pci_fixup(dev);
}
}
#include <linux/irq.h>
#include <linux/pci.h>
extern struct irq_chip dde_irqchip_data_chip;
void pci_assign_irq(struct pci_dev * dev)
{
struct irq_data *irq_data;
/*
* Be lazy and treat irq as hwirq as this is used by the
* dde_irqchip_data_chip for (un-)masking.
*/
irq_data = irq_get_irq_data(dev->irq);
irq_data->hwirq = dev->irq;
irq_set_chip_and_handler(dev->irq, &dde_irqchip_data_chip,
handle_level_irq);
}
#include <linux/pci.h>
unsigned long pci_mem_start = 0xaeedbabe;
const struct attribute_group aspm_ctrl_attr_group[] = { 0 };
const struct attribute_group pci_dev_vpd_attr_group = { };
struct pci_fixup __start_pci_fixups_early[] = { 0 };
struct pci_fixup __end_pci_fixups_early[] = { 0 };
struct pci_fixup __start_pci_fixups_header[] = { 0 };
struct pci_fixup __end_pci_fixups_header[] = { 0 };
struct pci_fixup __start_pci_fixups_final[] = { 0 };
struct pci_fixup __end_pci_fixups_final[] = { 0 };
struct pci_fixup __start_pci_fixups_enable[] = { 0 };
struct pci_fixup __end_pci_fixups_enable[] = { 0 };
struct pci_fixup __start_pci_fixups_resume[] = { 0 };
struct pci_fixup __end_pci_fixups_resume[] = { 0 };
struct pci_fixup __start_pci_fixups_resume_early[] = { 0 };
struct pci_fixup __end_pci_fixups_resume_early[] = { 0 };
struct pci_fixup __start_pci_fixups_suspend[] = { 0 };
struct pci_fixup __end_pci_fixups_suspend[] = { 0 };
struct pci_fixup __start_pci_fixups_suspend_late[] = { 0 };
struct pci_fixup __end_pci_fixups_suspend_late[] = { 0 };
int pcibios_last_bus = -1;
extern int __init pcibios_init(void);
int __init pcibios_init(void)
{
lx_emul_trace(__func__);
return 0;
}

View File

@ -0,0 +1,25 @@
#include <asm/atomic64_32.h>
/**
* This is not atomic on 32bit systems but this is not a problem
* because we will not be preempted.
*/
s64 arch_atomic64_add(s64 i, atomic64_t *v)
{
v->counter += i;
return v->counter;
}
s64 arch_atomic64_read(const atomic64_t *v)
{
return v->counter;
}
s64 arch_atomic64_sub(s64 i, atomic64_t *v)
{
v->counter -= i;
return v->counter;
}