├── COPYING ├── Makefile ├── README.md ├── asor.img ├── configure ├── core └── virt.c ├── driver └── monitor.c ├── include ├── monitor.h └── virt.h ├── lib ├── abort.c ├── alloc.c ├── alloc.h ├── alloc_page.c ├── alloc_page.h ├── alloc_phys.c ├── alloc_phys.h ├── argv.c ├── argv.h ├── arm │ ├── .gitignore │ ├── asm-offsets.c │ ├── asm │ │ ├── arch_gicv3.h │ │ ├── barrier.h │ │ ├── bitops.h │ │ ├── cpumask.h │ │ ├── delay.h │ │ ├── gic-v2.h │ │ ├── gic-v3.h │ │ ├── gic.h │ │ ├── io.h │ │ ├── mmu-api.h │ │ ├── mmu.h │ │ ├── page.h │ │ ├── pci.h │ │ ├── pgtable-hwdef.h │ │ ├── pgtable.h │ │ ├── processor.h │ │ ├── psci.h │ │ ├── ptrace.h │ │ ├── setup.h │ │ ├── smp.h │ │ ├── spinlock.h │ │ ├── stack.h │ │ ├── sysreg.h │ │ └── thread_info.h │ ├── bitops.c │ ├── delay.c │ ├── eabi_compat.c │ ├── gic-v2.c │ ├── gic-v3.c │ ├── gic.c │ ├── io.c │ ├── io.h │ ├── mmu.c │ ├── processor.c │ ├── psci.c │ ├── setup.c │ ├── smp.c │ ├── spinlock.c │ └── stack.c ├── arm64 │ ├── .gitignore │ ├── asm-offsets.c │ ├── asm │ │ ├── arch_gicv3.h │ │ ├── barrier.h │ │ ├── bitops.h │ │ ├── cpumask.h │ │ ├── delay.h │ │ ├── esr.h │ │ ├── gic-v2.h │ │ ├── gic-v3.h │ │ ├── gic.h │ │ ├── io.h │ │ ├── mmu-api.h │ │ ├── mmu.h │ │ ├── page.h │ │ ├── pci.h │ │ ├── pgtable-hwdef.h │ │ ├── pgtable.h │ │ ├── processor.h │ │ ├── psci.h │ │ ├── ptrace.h │ │ ├── setup.h │ │ ├── smp.h │ │ ├── spinlock.h │ │ ├── stack.h │ │ ├── sysreg.h │ │ └── thread_info.h │ ├── processor.c │ └── spinlock.c ├── asm-generic │ ├── atomic.h │ ├── barrier.h │ ├── io.h │ ├── page.h │ ├── pci-host-bridge.h │ ├── pci.h │ └── spinlock.h ├── auxinfo.c ├── auxinfo.h ├── bitops.h ├── chr-testdev.c ├── chr-testdev.h ├── devicetree.c ├── devicetree.h ├── elf.c ├── elf.h ├── errata.h ├── getchar.c ├── kbuild.h ├── libcflat.h ├── libfdt │ ├── Makefile.libfdt │ ├── README │ ├── fdt.c │ ├── fdt.h │ ├── fdt_empty_tree.c │ ├── fdt_ro.c │ ├── fdt_rw.c │ ├── fdt_strerror.c │ ├── fdt_sw.c │ ├── fdt_wip.c │ ├── libfdt.h │ ├── libfdt_env.h │ ├── libfdt_internal.h │ └── version.lds ├── linux │ ├── const.h │ ├── pci_regs.h │ └── psci.h ├── pci-edu.c ├── pci-edu.h ├── pci-host-generic.c ├── pci-host-generic.h ├── pci-testdev.c ├── pci.c ├── pci.h ├── powerpc │ ├── .gitignore │ ├── asm │ │ ├── handlers.h │ │ ├── hcall.h │ │ ├── ppc_asm.h │ │ ├── processor.h │ │ ├── rtas.h │ │ ├── setup.h │ │ ├── smp.h │ │ └── stack.h │ ├── handlers.c │ ├── hcall.c │ ├── io.c │ ├── io.h │ ├── processor.c │ ├── rtas.c │ ├── setup.c │ └── smp.c ├── ppc64 │ ├── .gitignore │ ├── asm-offsets.c │ └── asm │ │ ├── barrier.h │ │ ├── bitops.h │ │ ├── handlers.h │ │ ├── hcall.h │ │ ├── io.h │ │ ├── page.h │ │ ├── ppc_asm.h │ │ ├── processor.h │ │ ├── ptrace.h │ │ ├── rtas.h │ │ ├── setup.h │ │ ├── smp.h │ │ ├── spinlock.h │ │ └── stack.h ├── printf.c ├── report.c ├── s390x │ ├── .gitignore │ ├── asm-offsets.c │ ├── asm │ │ ├── arch_def.h │ │ ├── barrier.h │ │ ├── bitops.h │ │ ├── cpacf.h │ │ ├── facility.h │ │ ├── float.h │ │ ├── interrupt.h │ │ ├── io.h │ │ ├── mem.h │ │ ├── page.h │ │ ├── pgtable.h │ │ ├── sigp.h │ │ ├── spinlock.h │ │ └── stack.h │ ├── interrupt.c │ ├── io.c │ ├── mmu.c │ ├── mmu.h │ ├── sclp-console.c │ ├── sclp.c │ ├── sclp.h │ └── stack.c ├── setjmp.h ├── stack.c ├── stack.h ├── string.c ├── string.h ├── util.c ├── util.h ├── virtio-mmio.c ├── virtio-mmio.h ├── virtio.c ├── virtio.h ├── vmalloc.c ├── vmalloc.h └── x86 │ ├── acpi.c │ ├── acpi.h │ ├── apic-defs.h │ ├── apic.c │ ├── apic.h │ ├── asm │ ├── barrier.h │ ├── bitops.h │ ├── io.h │ ├── page.h │ ├── pci.h │ ├── spinlock.h │ └── stack.h │ ├── atomic.c │ ├── atomic.h │ ├── delay.c │ ├── delay.h │ ├── desc.c │ ├── desc.h │ ├── fake-apic.h │ ├── fault_test.c │ ├── fault_test.h │ ├── fwcfg.c │ ├── fwcfg.h │ ├── intel-iommu.c │ ├── intel-iommu.h │ ├── io.c │ ├── isr.c │ ├── isr.h │ ├── msr.h │ ├── processor.h │ ├── setjmp32.S │ ├── setjmp64.S │ ├── setup.c │ ├── smp.c │ ├── smp.h │ ├── stack.c │ ├── usermode.c │ ├── usermode.h │ ├── vm.c │ └── vm.h ├── scripts ├── arch-run.bash ├── asm-offsets.mak ├── common.bash ├── git.difforder ├── mkstandalone.sh ├── pretty_print_stacks.py └── runtime.bash └── x86 ├── Makefile ├── Makefile.common ├── Makefile.i386 ├── Makefile.x86_64 ├── asor.c ├── cstart.S ├── cstart64.S ├── ept.c ├── ept.h ├── flat.lds ├── run ├── vm.c ├── vmx.c └── vmx.h /COPYING: -------------------------------------------------------------------------------- 1 | The asor project is provided under: 2 | 3 | SPDX-License-Identifier: GPL-2.0-or-later 4 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | **ASOR**, 是一个简单的虚拟化管理软件(VMM),用来帮助人们了解硬件辅助虚拟化的基本概念以及虚拟化管理软件的实现。 2 | 3 | 参考 [**ASOR - 基于x86架构的虚拟机实现**](https://calinyara.github.io/technology/2019/08/05/asor-hypervisor.html) 4 | 5 | **编译及运行** 6 | 7 | ``` 8 | make // 编译asor二进制 9 | make img // 制作asor QEMU启动硬盘 10 | make qemu // 加载asor二进制启动盘到QEMU运行 11 | x86-run x86/asor.flat // 直接在QEMU中运行asor 12 | ``` 13 | -------------------------------------------------------------------------------- /asor.img: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/calinyara/asor/b04562624a1fa5942f6633aafe5c94cd34390e7a/asor.img -------------------------------------------------------------------------------- /core/virt.c: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0 2 | /* 3 | * ASOR Hypervisor. 4 | * 5 | * Author: Jie Deng 6 | */ 7 | 8 | #include "libcflat.h" 9 | #include "virt.h" 10 | 11 | static const struct virt_arch_ops *virt_arch_ops = NULL; 12 | 13 | int register_virt_ops(const struct virt_arch_ops *ops) 14 | { 15 | if (virt_arch_ops != NULL || ops == NULL) 16 | return -1; 17 | 18 | virt_arch_ops = ops; 19 | return 0; 20 | } 21 | 22 | void free_virt_ops(const struct virt_arch_ops *ops) 23 | { 24 | virt_arch_ops = NULL; 25 | } 26 | 27 | const struct virt_arch_ops *get_virt_arch_ops(void) 28 | { 29 | return virt_arch_ops; 30 | } 31 | 32 | int enable_hw_virt(void) 33 | { 34 | const struct virt_arch_ops *ops = get_virt_arch_ops(); 35 | 36 | if (ops == NULL) { 37 | error("Error: virt_arch_ops is NULL.\n"); 38 | return -1; 39 | } 40 | 41 | return ops->enable(); 42 | } 43 | 44 | -------------------------------------------------------------------------------- /include/monitor.h: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0 2 | /* 3 | * ASOR Hypervisor. 4 | * 5 | * Author: Jie Deng 6 | */ 7 | 8 | #ifndef __MONITOR_H__ 9 | #define __MONITOR_H__ 10 | 11 | #include 12 | 13 | typedef enum mcolor { 14 | MC_BLACK = 0, 15 | MC_DARK_BLUE = 1, 16 | MC_DARK_GREEN = 2, 17 | MC_DARK_CYAN = 3, 18 | MC_DARK_RED = 4, 19 | MC_DARK_MAGENTA = 5, 20 | MC_DARK_YELLOW = 6, 21 | MC_LIGHT_GREY = 7, 22 | MC_DARK_GREY = 8, 23 | MC_LIGHT_BLUE = 9, 24 | MC_LIGHT_GREEN = 10, 25 | MC_LIGHT_CYAN = 11, 26 | MC_LIGHT_RED = 12, 27 | MC_LIGHT_MAGENTA = 13, 28 | MC_LIGHT_YELLOW = 14, 29 | MC_WHITE = 15 30 | } mcolor_t; 31 | 32 | /* Write a single character out to the screen with color. */ 33 | void monitor_put(char c, mcolor_t bc, mcolor_t fc); 34 | 35 | /* Clear the screen to all black. */ 36 | void monitor_clear(void); 37 | 38 | /* Output a null-terminated ASCII string to the monitor with color. */ 39 | void monitor_write_color(const char *str, mcolor_t bc, mcolor_t fc); 40 | 41 | /* Output a null-terminated ASCII string to the monitor with 42 | * black backround and white foreground. 43 | */ 44 | void monitor_write(const char *str); 45 | 46 | /* Output a hexadecimal to the monitor. */ 47 | void monitor_write_hex(uint32_t n, mcolor_t bc, mcolor_t fc); 48 | 49 | /* Output a decimal to the monitor. */ 50 | void monitor_write_dec(uint32_t n, mcolor_t bc, mcolor_t fc); 51 | 52 | #endif /* __MONITOR_H__ */ 53 | -------------------------------------------------------------------------------- /include/virt.h: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0 2 | /* 3 | * ASOR Hypervisor. 4 | * 5 | * Author: Jie Deng 6 | */ 7 | 8 | #ifndef __VIRT_H__ 9 | #define __VIRT_H__ 10 | 11 | struct virt_arch_ops { 12 | int (*enable)(void); 13 | }; 14 | 15 | int enable_hw_virt(void); 16 | int register_virt_ops(const struct virt_arch_ops *ops); 17 | void free_virt_ops(const struct virt_arch_ops *ops); 18 | const struct virt_arch_ops *get_virt_arch_ops(void); 19 | 20 | #endif /* __VIRT_H__ */ 21 | -------------------------------------------------------------------------------- /lib/abort.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2014, Red Hat Inc, Andrew Jones 3 | * 4 | * This work is licensed under the terms of the GNU LGPL, version 2. 5 | */ 6 | #include "libcflat.h" 7 | 8 | /* 9 | * When exit(code) is invoked, qemu will exit with ((code << 1) | 1), 10 | * leaving us 128 exit status codes. To avoid confusion with signal 11 | * status, we further limit exit codes to those resulting in qemu 12 | * exiting with a status < 128. We give abort() the highest (127), 13 | * leaving the lower status codes for unit tests. 14 | */ 15 | #define ABORT_EXIT_STATUS 63 /* 127 exit status from qemu */ 16 | 17 | void abort(void) 18 | { 19 | exit(ABORT_EXIT_STATUS); 20 | } 21 | -------------------------------------------------------------------------------- /lib/alloc.c: -------------------------------------------------------------------------------- 1 | #include "alloc.h" 2 | #include "asm/page.h" 3 | 4 | void *malloc(size_t size) 5 | { 6 | return memalign(sizeof(long), size); 7 | } 8 | 9 | void *calloc(size_t nmemb, size_t size) 10 | { 11 | void *ptr = malloc(nmemb * size); 12 | if (ptr) 13 | memset(ptr, 0, nmemb * size); 14 | return ptr; 15 | } 16 | 17 | #define METADATA_EXTRA (2 * sizeof(uintptr_t)) 18 | #define OFS_SLACK (-2 * sizeof(uintptr_t)) 19 | #define OFS_SIZE (-sizeof(uintptr_t)) 20 | 21 | static inline void *block_begin(void *mem) 22 | { 23 | uintptr_t slack = *(uintptr_t *)(mem + OFS_SLACK); 24 | return mem - slack; 25 | } 26 | 27 | static inline uintptr_t block_size(void *mem) 28 | { 29 | return *(uintptr_t *)(mem + OFS_SIZE); 30 | } 31 | 32 | void free(void *ptr) 33 | { 34 | if (!alloc_ops->free) 35 | return; 36 | 37 | void *base = block_begin(ptr); 38 | uintptr_t sz = block_size(ptr); 39 | 40 | alloc_ops->free(base, sz); 41 | } 42 | 43 | void *memalign(size_t alignment, size_t size) 44 | { 45 | void *p; 46 | uintptr_t blkalign; 47 | uintptr_t mem; 48 | 49 | assert(alloc_ops && alloc_ops->memalign); 50 | if (alignment <= sizeof(uintptr_t)) 51 | alignment = sizeof(uintptr_t); 52 | else 53 | size += alignment - 1; 54 | 55 | blkalign = MAX(alignment, alloc_ops->align_min); 56 | size = ALIGN(size + METADATA_EXTRA, alloc_ops->align_min); 57 | p = alloc_ops->memalign(blkalign, size); 58 | 59 | /* Leave room for metadata before aligning the result. */ 60 | mem = (uintptr_t)p + METADATA_EXTRA; 61 | mem = ALIGN(mem, alignment); 62 | 63 | /* Write the metadata */ 64 | *(uintptr_t *)(mem + OFS_SLACK) = mem - (uintptr_t)p; 65 | *(uintptr_t *)(mem + OFS_SIZE) = size; 66 | return (void *)mem; 67 | } 68 | -------------------------------------------------------------------------------- /lib/alloc.h: -------------------------------------------------------------------------------- 1 | #ifndef _ALLOC_H_ 2 | #define _ALLOC_H_ 3 | /* 4 | * alloc supplies three ingredients to the test framework that are all 5 | * related to the support of dynamic memory allocation. 6 | * 7 | * The first is a set of alloc function wrappers for malloc and its 8 | * friends. Using wrappers allows test code and common code to use the 9 | * same interface for memory allocation at all stages, even though the 10 | * implementations may change with the stage, e.g. pre/post paging. 11 | * 12 | * The second is a set of implementations for the alloc function 13 | * interfaces. These implementations are named early_*, as they can be 14 | * used almost immediately by the test framework. 15 | * 16 | * The third is a very simple physical memory allocator, which the 17 | * early_* alloc functions build on. 18 | * 19 | * Copyright (C) 2014, Red Hat Inc, Andrew Jones 20 | * 21 | * This work is licensed under the terms of the GNU LGPL, version 2. 22 | */ 23 | #include "libcflat.h" 24 | 25 | struct alloc_ops { 26 | void *(*memalign)(size_t alignment, size_t size); 27 | void (*free)(void *ptr, size_t size); 28 | size_t align_min; 29 | }; 30 | 31 | extern struct alloc_ops *alloc_ops; 32 | 33 | void *malloc(size_t size); 34 | void *calloc(size_t nmemb, size_t size); 35 | void free(void *ptr); 36 | void *memalign(size_t alignment, size_t size); 37 | 38 | #endif /* _ALLOC_H_ */ 39 | -------------------------------------------------------------------------------- /lib/alloc_page.h: -------------------------------------------------------------------------------- 1 | /* 2 | * This work is licensed under the terms of the GNU LGPL, version 2. 3 | * 4 | * This is a simple allocator that provides contiguous physical addresses 5 | * with byte granularity. 6 | */ 7 | 8 | #ifndef ALLOC_PAGE_H 9 | #define ALLOC_PAGE_H 1 10 | 11 | bool page_alloc_initialized(void); 12 | void page_alloc_ops_enable(void); 13 | void *alloc_page(void); 14 | void *alloc_pages(unsigned long order); 15 | void free_page(void *page); 16 | void free_pages(void *mem, unsigned long size); 17 | 18 | #endif 19 | -------------------------------------------------------------------------------- /lib/alloc_phys.h: -------------------------------------------------------------------------------- 1 | #ifndef _ALLOC_PHYS_H_ 2 | #define _ALLOC_PHYS_H_ 3 | /* 4 | * phys_alloc is a very simple allocator which allows physical memory 5 | * to be partitioned into regions until all memory is allocated. 6 | * 7 | * Note: This is such a simple allocator that there is no way to free 8 | * a region. For more complicated memory management a single region 9 | * can be allocated, but then have its memory managed by a more 10 | * sophisticated allocator, e.g. a page allocator. 11 | * 12 | * Copyright (C) 2014, Red Hat Inc, Andrew Jones 13 | * 14 | * This work is licensed under the terms of the GNU LGPL, version 2. 15 | */ 16 | #include "libcflat.h" 17 | 18 | #define DEFAULT_MINIMUM_ALIGNMENT 32 19 | 20 | /* 21 | * phys_alloc_init creates the initial free memory region of size @size 22 | * at @base. The minimum alignment is set to DEFAULT_MINIMUM_ALIGNMENT. 23 | */ 24 | extern void phys_alloc_init(phys_addr_t base, phys_addr_t size); 25 | 26 | /* 27 | * phys_alloc_set_minimum_alignment sets the minimum alignment to 28 | * @align. 29 | */ 30 | extern void phys_alloc_set_minimum_alignment(phys_addr_t align); 31 | 32 | /* 33 | * phys_alloc_show outputs all currently allocated regions with the 34 | * following format 35 | * - [] 36 | */ 37 | extern void phys_alloc_show(void); 38 | 39 | /* 40 | * phys_alloc_get_unused allocates all remaining memory from the region 41 | * passed to phys_alloc_init, returning the newly allocated memory's base 42 | * and top addresses. phys_allo_get_unused will still return base and top 43 | * when no free memory is remaining, but base will equal top. 44 | */ 45 | extern void phys_alloc_get_unused(phys_addr_t *p_base, phys_addr_t *p_top); 46 | 47 | #endif /* _ALLOC_PHYS_H_ */ 48 | -------------------------------------------------------------------------------- /lib/argv.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Set up arguments for main() and prepare environment variables 3 | * 4 | * This code is free software; you can redistribute it and/or modify it 5 | * under the terms of the GNU Library General Public License version 2. 6 | */ 7 | 8 | #include "libcflat.h" 9 | #include "argv.h" 10 | #include "auxinfo.h" 11 | 12 | int __argc; 13 | const char *__args; 14 | char *__argv[100]; 15 | char *__environ[200]; 16 | 17 | char **environ = __environ; 18 | 19 | static char args_copy[1000]; 20 | static char *copy_ptr = args_copy; 21 | 22 | #define isblank(c) ((c) == ' ' || (c) == '\t') 23 | #define isalpha(c) (((c) >= 'A' && (c) <= 'Z') || ((c) >= 'a' && (c) <= 'z') || (c) == '_') 24 | #define isalnum(c) (isalpha(c) || ((c) >= '0' && (c) <= '9')) 25 | 26 | static const char *skip_blanks(const char *p) 27 | { 28 | while (isblank(*p)) 29 | ++p; 30 | return p; 31 | } 32 | 33 | void __setup_args(void) 34 | { 35 | const char *args = __args; 36 | char **argv = __argv + __argc; 37 | 38 | while (*(args = skip_blanks(args)) != '\0') { 39 | *argv++ = copy_ptr; 40 | while (*args != '\0' && !isblank(*args)) 41 | *copy_ptr++ = *args++; 42 | *copy_ptr++ = '\0'; 43 | } 44 | __argc = argv - __argv; 45 | } 46 | 47 | static void setup_args(const char *args) 48 | { 49 | if (!args) 50 | return; 51 | 52 | __args = args; 53 | __setup_args(); 54 | } 55 | 56 | void setup_args_progname(const char *args) 57 | { 58 | __argv[0] = copy_ptr; 59 | strcpy(__argv[0], auxinfo.progname); 60 | copy_ptr += strlen(auxinfo.progname) + 1; 61 | ++__argc; 62 | setup_args(args); 63 | } 64 | 65 | static char *env_eol(char *env) 66 | { 67 | while (*env && *env != '\n') 68 | ++env; 69 | return env; 70 | } 71 | 72 | static char *env_invalid_eol(char *env) 73 | { 74 | char *eol = env_eol(env); 75 | char eol_old = *eol; 76 | 77 | *eol = '\0'; 78 | printf("Invalid environment variable: %s\n", env); 79 | *eol = eol_old; 80 | return eol; 81 | } 82 | 83 | static char *env_next(char *env) 84 | { 85 | char *p; 86 | 87 | if (!*env) 88 | return env; 89 | 90 | if (isalpha(*env)) { 91 | bool invalid = false; 92 | 93 | p = env + 1; 94 | while (*p && *p != '=' && *p != '\n') { 95 | if (!isalnum(*p)) 96 | invalid = true; 97 | ++p; 98 | } 99 | 100 | if (*p != '=') 101 | invalid = true; 102 | 103 | if (invalid) { 104 | env = env_invalid_eol(env); 105 | return *env ? env_next(env + 1) : env; 106 | } 107 | return env; 108 | } 109 | 110 | p = env; 111 | while (isblank(*p)) 112 | ++p; 113 | 114 | if (*p == '\n') 115 | return env_next(p + 1); 116 | 117 | if (*p == '#') 118 | env = env_eol(env); 119 | else 120 | env = env_invalid_eol(env); 121 | 122 | return *env ? env_next(env + 1) : env; 123 | } 124 | 125 | void setup_env(char *env, int size) 126 | { 127 | char *eof = env + size, *p = env; 128 | bool newline = false; 129 | int i = 0; 130 | 131 | while (*p) 132 | ++p; 133 | if (p == eof) 134 | newline = true; 135 | 136 | while (env < eof) { 137 | if (newline) 138 | env = env_next(env); 139 | if (!*env || env >= eof) 140 | break; 141 | __environ[i++] = env; 142 | while (env < eof && *env && !(newline && *env == '\n')) 143 | ++env; 144 | *env++ = '\0'; 145 | } 146 | } 147 | -------------------------------------------------------------------------------- /lib/argv.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Set up arguments for main() and prepare environment variables 3 | * 4 | * This code is free software; you can redistribute it and/or modify it 5 | * under the terms of the GNU Library General Public License version 2. 6 | */ 7 | 8 | extern void __setup_args(void); 9 | extern void setup_args_progname(const char *args); 10 | extern void setup_env(char *env, int size); 11 | -------------------------------------------------------------------------------- /lib/arm/.gitignore: -------------------------------------------------------------------------------- 1 | asm-offsets.[hs] 2 | -------------------------------------------------------------------------------- /lib/arm/asm-offsets.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Adapted from arch/arm/kernel/asm-offsets.c 3 | * 4 | * Copyright (C) 2017, Red Hat Inc, Andrew Jones 5 | * 6 | * This work is licensed under the terms of the GNU GPL, version 2. 7 | */ 8 | #include 9 | #include 10 | #include 11 | 12 | int main(void) 13 | { 14 | OFFSET(S_R0, pt_regs, ARM_r0); 15 | OFFSET(S_R1, pt_regs, ARM_r1); 16 | OFFSET(S_R2, pt_regs, ARM_r2); 17 | OFFSET(S_R3, pt_regs, ARM_r3); 18 | OFFSET(S_R4, pt_regs, ARM_r4); 19 | OFFSET(S_R5, pt_regs, ARM_r5); 20 | OFFSET(S_R6, pt_regs, ARM_r6); 21 | OFFSET(S_R7, pt_regs, ARM_r7); 22 | OFFSET(S_R8, pt_regs, ARM_r8); 23 | OFFSET(S_R9, pt_regs, ARM_r9); 24 | OFFSET(S_R10, pt_regs, ARM_r10); 25 | OFFSET(S_FP, pt_regs, ARM_fp); 26 | OFFSET(S_IP, pt_regs, ARM_ip); 27 | OFFSET(S_SP, pt_regs, ARM_sp); 28 | OFFSET(S_LR, pt_regs, ARM_lr); 29 | OFFSET(S_PC, pt_regs, ARM_pc); 30 | OFFSET(S_PSR, pt_regs, ARM_cpsr); 31 | OFFSET(S_OLD_R0, pt_regs, ARM_ORIG_r0); 32 | DEFINE(S_FRAME_SIZE, sizeof(struct pt_regs)); 33 | return 0; 34 | } 35 | -------------------------------------------------------------------------------- /lib/arm/asm/arch_gicv3.h: -------------------------------------------------------------------------------- 1 | /* 2 | * All ripped off from arch/arm/include/asm/arch_gicv3.h 3 | * 4 | * Copyright (C) 2016, Red Hat Inc, Andrew Jones 5 | * 6 | * This work is licensed under the terms of the GNU LGPL, version 2. 7 | */ 8 | #ifndef _ASMARM_ARCH_GICV3_H_ 9 | #define _ASMARM_ARCH_GICV3_H_ 10 | 11 | #ifndef __ASSEMBLY__ 12 | #include 13 | #include 14 | #include 15 | #include 16 | 17 | #define ICC_PMR __ACCESS_CP15(c4, 0, c6, 0) 18 | #define ICC_SGI1R __ACCESS_CP15_64(0, c12) 19 | #define ICC_IAR1 __ACCESS_CP15(c12, 0, c12, 0) 20 | #define ICC_EOIR1 __ACCESS_CP15(c12, 0, c12, 1) 21 | #define ICC_IGRPEN1 __ACCESS_CP15(c12, 0, c12, 7) 22 | 23 | static inline void gicv3_write_pmr(u32 val) 24 | { 25 | write_sysreg(val, ICC_PMR); 26 | } 27 | 28 | static inline void gicv3_write_sgi1r(u64 val) 29 | { 30 | write_sysreg(val, ICC_SGI1R); 31 | } 32 | 33 | static inline u32 gicv3_read_iar(void) 34 | { 35 | u32 irqstat = read_sysreg(ICC_IAR1); 36 | dsb(sy); 37 | return irqstat; 38 | } 39 | 40 | static inline void gicv3_write_eoir(u32 irq) 41 | { 42 | write_sysreg(irq, ICC_EOIR1); 43 | isb(); 44 | } 45 | 46 | static inline void gicv3_write_grpen1(u32 val) 47 | { 48 | write_sysreg(val, ICC_IGRPEN1); 49 | isb(); 50 | } 51 | 52 | /* 53 | * We may access GICR_TYPER and GITS_TYPER by reading both the TYPER 54 | * offset and the following offset (+ 4) and then combining them to 55 | * form a 64-bit address. 56 | */ 57 | static inline u64 gicv3_read_typer(const volatile void __iomem *addr) 58 | { 59 | u64 val = readl(addr); 60 | val |= (u64)readl(addr + 4) << 32; 61 | return val; 62 | } 63 | 64 | #endif /* !__ASSEMBLY__ */ 65 | #endif /* _ASMARM_ARCH_GICV3_H_ */ 66 | -------------------------------------------------------------------------------- /lib/arm/asm/barrier.h: -------------------------------------------------------------------------------- 1 | #ifndef _ASMARM_BARRIER_H_ 2 | #define _ASMARM_BARRIER_H_ 3 | /* 4 | * Adapted from arch/arm/include/asm/barrier.h 5 | * 6 | * Copyright (C) 2017, Red Hat Inc, Andrew Jones 7 | * 8 | * This work is licensed under the terms of the GNU GPL, version 2. 9 | */ 10 | 11 | #define sev() asm volatile("sev" : : : "memory") 12 | #define wfe() asm volatile("wfe" : : : "memory") 13 | #define wfi() asm volatile("wfi" : : : "memory") 14 | #define yield() asm volatile("yield" : : : "memory") 15 | #define cpu_relax() yield() 16 | 17 | #define isb(option) __asm__ __volatile__ ("isb " #option : : : "memory") 18 | #define dsb(option) __asm__ __volatile__ ("dsb " #option : : : "memory") 19 | #define dmb(option) __asm__ __volatile__ ("dmb " #option : : : "memory") 20 | 21 | #define mb() dsb() 22 | #define rmb() dsb() 23 | #define wmb() dsb(st) 24 | #define smp_mb() dmb(ish) 25 | #define smp_rmb() smp_mb() 26 | #define smp_wmb() dmb(ishst) 27 | 28 | #endif /* _ASMARM_BARRIER_H_ */ 29 | -------------------------------------------------------------------------------- /lib/arm/asm/bitops.h: -------------------------------------------------------------------------------- 1 | #ifndef _ASMARM_BITOPS_H_ 2 | #define _ASMARM_BITOPS_H_ 3 | /* 4 | * Adapted from 5 | * arch/arm/lib/bitops.h 6 | * 7 | * Copyright (C) 2017, Red Hat Inc, Andrew Jones 8 | * 9 | * This work is licensed under the terms of the GNU GPL, version 2. 10 | */ 11 | 12 | #ifndef _BITOPS_H_ 13 | #error only can be included directly 14 | #endif 15 | 16 | #define BITS_PER_LONG 32 17 | 18 | #define HAVE_BUILTIN_FLS 1 19 | 20 | #define ATOMIC_BITOP(insn, mask, word) \ 21 | ({ \ 22 | unsigned long tmp1, tmp2; \ 23 | asm volatile( \ 24 | "1: ldrex %0, [%2]\n" \ 25 | insn" %0, %0, %3\n" \ 26 | " strex %1, %0, [%2]\n" \ 27 | " cmp %1, #0\n" \ 28 | " bne 1b\n" \ 29 | : "=&r" (tmp1), "=&r" (tmp2) \ 30 | : "r" (word), "r" (mask) \ 31 | : "cc"); \ 32 | }) 33 | 34 | #define ATOMIC_TESTOP(insn, mask, word, old) \ 35 | ({ \ 36 | unsigned long tmp1, tmp2; \ 37 | asm volatile( \ 38 | "1: ldrex %0, [%3]\n" \ 39 | " and %1, %0, %4\n" \ 40 | insn" %0, %0, %4\n" \ 41 | " strex %2, %0, [%3]\n" \ 42 | " cmp %2, #0\n" \ 43 | " bne 1b\n" \ 44 | : "=&r" (tmp1), "=&r" (old), "=&r" (tmp2) \ 45 | : "r" (word), "r" (mask) \ 46 | : "cc"); \ 47 | }) 48 | 49 | extern void set_bit(int nr, volatile unsigned long *addr); 50 | extern void clear_bit(int nr, volatile unsigned long *addr); 51 | extern int test_bit(int nr, const volatile unsigned long *addr); 52 | extern int test_and_set_bit(int nr, volatile unsigned long *addr); 53 | extern int test_and_clear_bit(int nr, volatile unsigned long *addr); 54 | 55 | #endif /* _ASMARM_BITOPS_H_ */ 56 | -------------------------------------------------------------------------------- /lib/arm/asm/cpumask.h: -------------------------------------------------------------------------------- 1 | #ifndef _ASMARM_CPUMASK_H_ 2 | #define _ASMARM_CPUMASK_H_ 3 | /* 4 | * Simple cpumask implementation 5 | * 6 | * Copyright (C) 2015, Red Hat Inc, Andrew Jones 7 | * 8 | * This work is licensed under the terms of the GNU LGPL, version 2. 9 | */ 10 | #include 11 | #include 12 | 13 | #define CPUMASK_NR_LONGS ((NR_CPUS + BITS_PER_LONG - 1) / BITS_PER_LONG) 14 | 15 | typedef struct cpumask { 16 | unsigned long bits[CPUMASK_NR_LONGS]; 17 | } cpumask_t; 18 | 19 | #define cpumask_bits(maskp) ((maskp)->bits) 20 | 21 | static inline void cpumask_set_cpu(int cpu, cpumask_t *mask) 22 | { 23 | set_bit(cpu, cpumask_bits(mask)); 24 | } 25 | 26 | static inline void cpumask_clear_cpu(int cpu, cpumask_t *mask) 27 | { 28 | clear_bit(cpu, cpumask_bits(mask)); 29 | } 30 | 31 | static inline int cpumask_test_cpu(int cpu, const cpumask_t *mask) 32 | { 33 | return test_bit(cpu, cpumask_bits(mask)); 34 | } 35 | 36 | static inline int cpumask_test_and_set_cpu(int cpu, cpumask_t *mask) 37 | { 38 | return test_and_set_bit(cpu, cpumask_bits(mask)); 39 | } 40 | 41 | static inline int cpumask_test_and_clear_cpu(int cpu, cpumask_t *mask) 42 | { 43 | return test_and_clear_bit(cpu, cpumask_bits(mask)); 44 | } 45 | 46 | static inline void cpumask_setall(cpumask_t *mask) 47 | { 48 | int i; 49 | for (i = 0; i < nr_cpus; i += BITS_PER_LONG) 50 | cpumask_bits(mask)[BIT_WORD(i)] = ~0UL; 51 | i -= BITS_PER_LONG; 52 | if ((nr_cpus - i) < BITS_PER_LONG) 53 | cpumask_bits(mask)[BIT_WORD(i)] = BIT_MASK(nr_cpus - i) - 1; 54 | } 55 | 56 | static inline void cpumask_clear(cpumask_t *mask) 57 | { 58 | int i; 59 | for (i = 0; i < nr_cpus; i += BITS_PER_LONG) 60 | cpumask_bits(mask)[BIT_WORD(i)] = 0UL; 61 | } 62 | 63 | static inline bool cpumask_empty(const cpumask_t *mask) 64 | { 65 | int i; 66 | for (i = 0; i < nr_cpus; i += BITS_PER_LONG) { 67 | if (i < NR_CPUS) { /* silence crazy compiler warning */ 68 | if (cpumask_bits(mask)[BIT_WORD(i)] != 0UL) 69 | return false; 70 | } 71 | } 72 | return true; 73 | } 74 | 75 | static inline bool cpumask_full(const cpumask_t *mask) 76 | { 77 | int i; 78 | for (i = 0; i < nr_cpus; i += BITS_PER_LONG) { 79 | if (cpumask_bits(mask)[BIT_WORD(i)] != ~0UL) { 80 | if ((nr_cpus - i) >= BITS_PER_LONG) 81 | return false; 82 | if (cpumask_bits(mask)[BIT_WORD(i)] 83 | != BIT_MASK(nr_cpus - i) - 1) 84 | return false; 85 | } 86 | } 87 | return true; 88 | } 89 | 90 | static inline int cpumask_weight(const cpumask_t *mask) 91 | { 92 | int w = 0, i; 93 | 94 | for (i = 0; i < nr_cpus; ++i) 95 | if (cpumask_test_cpu(i, mask)) 96 | ++w; 97 | return w; 98 | } 99 | 100 | static inline void cpumask_copy(cpumask_t *dst, const cpumask_t *src) 101 | { 102 | memcpy(cpumask_bits(dst), cpumask_bits(src), 103 | CPUMASK_NR_LONGS * sizeof(long)); 104 | } 105 | 106 | static inline int cpumask_next(int cpu, const cpumask_t *mask) 107 | { 108 | while (cpu < nr_cpus && !cpumask_test_cpu(++cpu, mask)) 109 | ; 110 | return cpu; 111 | } 112 | 113 | #define for_each_cpu(cpu, mask) \ 114 | for ((cpu) = cpumask_next(-1, mask); \ 115 | (cpu) < nr_cpus; \ 116 | (cpu) = cpumask_next(cpu, mask)) 117 | 118 | #endif /* _ASMARM_CPUMASK_H_ */ 119 | -------------------------------------------------------------------------------- /lib/arm/asm/delay.h: -------------------------------------------------------------------------------- 1 | #ifndef _ASMARM_DELAY_H_ 2 | #define _ASMARM_DELAY_H_ 3 | /* 4 | * Copyright (C) 2016, Red Hat Inc, Andrew Jones 5 | * 6 | * This work is licensed under the terms of the GNU LGPL, version 2. 7 | */ 8 | #include 9 | 10 | extern void delay(u64 cycles); 11 | extern void udelay(unsigned long usecs); 12 | extern void mdelay(unsigned long msecs); 13 | 14 | #endif /* _ASMARM_DELAY_H_ */ 15 | -------------------------------------------------------------------------------- /lib/arm/asm/gic-v2.h: -------------------------------------------------------------------------------- 1 | /* 2 | * All GIC* defines are lifted from include/linux/irqchip/arm-gic.h 3 | * 4 | * Copyright (C) 2016, Red Hat Inc, Andrew Jones 5 | * 6 | * This work is licensed under the terms of the GNU LGPL, version 2. 7 | */ 8 | #ifndef _ASMARM_GIC_V2_H_ 9 | #define _ASMARM_GIC_V2_H_ 10 | 11 | #ifndef _ASMARM_GIC_H_ 12 | #error Do not directly include . Include 13 | #endif 14 | 15 | #define GICD_ENABLE 0x1 16 | 17 | #define GICC_ENABLE 0x1 18 | #define GICC_IAR_INT_ID_MASK 0x3ff 19 | 20 | #ifndef __ASSEMBLY__ 21 | #include 22 | 23 | struct gicv2_data { 24 | void *dist_base; 25 | void *cpu_base; 26 | unsigned int irq_nr; 27 | }; 28 | extern struct gicv2_data gicv2_data; 29 | 30 | #define gicv2_dist_base() (gicv2_data.dist_base) 31 | #define gicv2_cpu_base() (gicv2_data.cpu_base) 32 | 33 | extern int gicv2_init(void); 34 | extern void gicv2_enable_defaults(void); 35 | extern u32 gicv2_read_iar(void); 36 | extern u32 gicv2_iar_irqnr(u32 iar); 37 | extern void gicv2_write_eoir(u32 irqstat); 38 | extern void gicv2_ipi_send_single(int irq, int cpu); 39 | extern void gicv2_ipi_send_mask(int irq, const cpumask_t *dest); 40 | 41 | #endif /* !__ASSEMBLY__ */ 42 | #endif /* _ASMARM_GIC_V2_H_ */ 43 | -------------------------------------------------------------------------------- /lib/arm/asm/gic.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2016, Red Hat Inc, Andrew Jones 3 | * 4 | * This work is licensed under the terms of the GNU LGPL, version 2. 5 | */ 6 | #ifndef _ASMARM_GIC_H_ 7 | #define _ASMARM_GIC_H_ 8 | 9 | #define GIC_NR_PRIVATE_IRQS 32 10 | #define GIC_FIRST_SPI GIC_NR_PRIVATE_IRQS 11 | 12 | /* Distributor registers */ 13 | #define GICD_CTLR 0x0000 14 | #define GICD_TYPER 0x0004 15 | #define GICD_IIDR 0x0008 16 | #define GICD_IGROUPR 0x0080 17 | #define GICD_ISENABLER 0x0100 18 | #define GICD_ISPENDR 0x0200 19 | #define GICD_ICPENDR 0x0280 20 | #define GICD_ISACTIVER 0x0300 21 | #define GICD_ICACTIVER 0x0380 22 | #define GICD_IPRIORITYR 0x0400 23 | #define GICD_ITARGETSR 0x0800 24 | #define GICD_SGIR 0x0f00 25 | #define GICD_ICPIDR2 0x0fe8 26 | 27 | #define GICD_TYPER_IRQS(typer) ((((typer) & 0x1f) + 1) * 32) 28 | #define GICD_INT_EN_SET_SGI 0x0000ffff 29 | #define GICD_INT_DEF_PRI_X4 0xa0a0a0a0 30 | 31 | /* CPU interface registers */ 32 | #define GICC_CTLR 0x0000 33 | #define GICC_PMR 0x0004 34 | #define GICC_IAR 0x000c 35 | #define GICC_EOIR 0x0010 36 | 37 | #define GICC_INT_PRI_THRESHOLD 0xf0 38 | #define GICC_INT_SPURIOUS 0x3ff 39 | 40 | #include 41 | #include 42 | 43 | #define PPI(irq) ((irq) + 16) 44 | 45 | #ifndef __ASSEMBLY__ 46 | #include 47 | 48 | /* 49 | * gic_init will try to find all known gics, and then 50 | * initialize the gic data for the one found. 51 | * returns 52 | * 0 : no gic was found 53 | * > 0 : the gic version of the gic found 54 | */ 55 | extern int gic_init(void); 56 | 57 | /* 58 | * gic_enable_defaults enables the gic with basic but useful 59 | * settings. gic_enable_defaults will call gic_init if it has 60 | * not yet been invoked. 61 | */ 62 | extern void gic_enable_defaults(void); 63 | 64 | /* 65 | * After enabling the gic with gic_enable_defaults the functions 66 | * below will work with any supported gic version. 67 | */ 68 | extern int gic_version(void); 69 | extern u32 gic_read_iar(void); 70 | extern u32 gic_iar_irqnr(u32 iar); 71 | extern void gic_write_eoir(u32 irqstat); 72 | extern void gic_ipi_send_single(int irq, int cpu); 73 | extern void gic_ipi_send_mask(int irq, const cpumask_t *dest); 74 | 75 | #endif /* !__ASSEMBLY__ */ 76 | #endif /* _ASMARM_GIC_H_ */ 77 | -------------------------------------------------------------------------------- /lib/arm/asm/io.h: -------------------------------------------------------------------------------- 1 | #ifndef _ASMARM_IO_H_ 2 | #define _ASMARM_IO_H_ 3 | #include 4 | #include 5 | #include 6 | 7 | #define __iomem 8 | #define __force 9 | 10 | #define __bswap16 bswap16 11 | static inline u16 bswap16(u16 val) 12 | { 13 | u16 ret; 14 | asm volatile("rev16 %0, %1" : "=r" (ret) : "r" (val)); 15 | return ret; 16 | } 17 | 18 | #define __bswap32 bswap32 19 | static inline u32 bswap32(u32 val) 20 | { 21 | u32 ret; 22 | asm volatile("rev %0, %1" : "=r" (ret) : "r" (val)); 23 | return ret; 24 | } 25 | 26 | #define __raw_readb __raw_readb 27 | static inline u8 __raw_readb(const volatile void __iomem *addr) 28 | { 29 | u8 val; 30 | asm volatile("ldrb %1, %0" 31 | : "+Qo" (*(volatile u8 __force *)addr), 32 | "=r" (val)); 33 | return val; 34 | } 35 | 36 | #define __raw_readw __raw_readw 37 | static inline u16 __raw_readw(const volatile void __iomem *addr) 38 | { 39 | u16 val; 40 | asm volatile("ldrh %1, %0" 41 | : "+Q" (*(volatile u16 __force *)addr), 42 | "=r" (val)); 43 | return val; 44 | } 45 | 46 | #define __raw_readl __raw_readl 47 | static inline u32 __raw_readl(const volatile void __iomem *addr) 48 | { 49 | u32 val; 50 | asm volatile("ldr %1, %0" 51 | : "+Qo" (*(volatile u32 __force *)addr), 52 | "=r" (val)); 53 | return val; 54 | } 55 | 56 | #define __raw_writeb __raw_writeb 57 | static inline void __raw_writeb(u8 val, volatile void __iomem *addr) 58 | { 59 | asm volatile("strb %1, %0" 60 | : "+Qo" (*(volatile u8 __force *)addr) 61 | : "r" (val)); 62 | } 63 | 64 | #define __raw_writew __raw_writew 65 | static inline void __raw_writew(u16 val, volatile void __iomem *addr) 66 | { 67 | asm volatile("strh %1, %0" 68 | : "+Q" (*(volatile u16 __force *)addr) 69 | : "r" (val)); 70 | } 71 | 72 | #define __raw_writel __raw_writel 73 | static inline void __raw_writel(u32 val, volatile void __iomem *addr) 74 | { 75 | asm volatile("str %1, %0" 76 | : "+Qo" (*(volatile u32 __force *)addr) 77 | : "r" (val)); 78 | } 79 | 80 | #define virt_to_phys virt_to_phys 81 | static inline phys_addr_t virt_to_phys(const volatile void *x) 82 | { 83 | return __virt_to_phys((unsigned long)(x)); 84 | } 85 | 86 | #define phys_to_virt phys_to_virt 87 | static inline void *phys_to_virt(phys_addr_t x) 88 | { 89 | return (void *)__phys_to_virt(x); 90 | } 91 | 92 | #include 93 | 94 | #endif /* _ASMARM_IO_H_ */ 95 | -------------------------------------------------------------------------------- /lib/arm/asm/mmu-api.h: -------------------------------------------------------------------------------- 1 | #ifndef __ASMARM_MMU_API_H_ 2 | #define __ASMARM_MMU_API_H_ 3 | 4 | #include 5 | #include 6 | 7 | extern pgd_t *mmu_idmap; 8 | extern unsigned int mmu_disabled_cpu_count; 9 | extern bool __mmu_enabled(void); 10 | static inline bool mmu_enabled(void) 11 | { 12 | return mmu_disabled_cpu_count == 0 || __mmu_enabled(); 13 | } 14 | extern void mmu_mark_enabled(int cpu); 15 | extern void mmu_mark_disabled(int cpu); 16 | extern void mmu_enable(pgd_t *pgtable); 17 | extern void mmu_disable(void); 18 | 19 | extern void mmu_set_range_sect(pgd_t *pgtable, uintptr_t virt_offset, 20 | phys_addr_t phys_start, phys_addr_t phys_end, 21 | pgprot_t prot); 22 | extern void mmu_set_range_ptes(pgd_t *pgtable, uintptr_t virt_offset, 23 | phys_addr_t phys_start, phys_addr_t phys_end, 24 | pgprot_t prot); 25 | #endif 26 | -------------------------------------------------------------------------------- /lib/arm/asm/mmu.h: -------------------------------------------------------------------------------- 1 | #ifndef __ASMARM_MMU_H_ 2 | #define __ASMARM_MMU_H_ 3 | /* 4 | * Copyright (C) 2014, Red Hat Inc, Andrew Jones 5 | * 6 | * This work is licensed under the terms of the GNU LGPL, version 2. 7 | */ 8 | #include 9 | 10 | #define PTE_USER L_PTE_USER 11 | #define PTE_RDONLY PTE_AP2 12 | #define PTE_SHARED L_PTE_SHARED 13 | #define PTE_AF PTE_EXT_AF 14 | #define PTE_WBWA L_PTE_MT_WRITEALLOC 15 | 16 | /* See B3.18.7 TLB maintenance operations */ 17 | 18 | static inline void local_flush_tlb_all(void) 19 | { 20 | /* TLBIALL */ 21 | asm volatile("mcr p15, 0, %0, c8, c7, 0" :: "r" (0)); 22 | dsb(); 23 | isb(); 24 | } 25 | 26 | static inline void flush_tlb_all(void) 27 | { 28 | //TODO 29 | local_flush_tlb_all(); 30 | } 31 | 32 | static inline void flush_tlb_page(unsigned long vaddr) 33 | { 34 | /* TLBIMVAA */ 35 | asm volatile("mcr p15, 0, %0, c8, c7, 3" :: "r" (vaddr)); 36 | dsb(); 37 | isb(); 38 | } 39 | 40 | static inline void flush_dcache_addr(unsigned long vaddr) 41 | { 42 | asm volatile("mcr p15, 0, %0, c7, c14, 1" :: "r" (vaddr)); 43 | } 44 | 45 | #include 46 | 47 | #endif /* __ASMARM_MMU_H_ */ 48 | -------------------------------------------------------------------------------- /lib/arm/asm/page.h: -------------------------------------------------------------------------------- 1 | #ifndef _ASMARM_PAGE_H_ 2 | #define _ASMARM_PAGE_H_ 3 | /* 4 | * Copyright (C) 2014, Red Hat Inc, Andrew Jones 5 | * 6 | * This work is licensed under the terms of the GNU LGPL, version 2. 7 | */ 8 | 9 | #include 10 | 11 | #define PAGE_SHIFT 12 12 | #define PAGE_SIZE (_AC(1,UL) << PAGE_SHIFT) 13 | #define PAGE_MASK (~(PAGE_SIZE-1)) 14 | 15 | #ifndef __ASSEMBLY__ 16 | 17 | #define PAGE_ALIGN(addr) ALIGN(addr, PAGE_SIZE) 18 | 19 | typedef u64 pteval_t; 20 | typedef u64 pmdval_t; 21 | typedef u64 pgdval_t; 22 | typedef struct { pteval_t pte; } pte_t; 23 | typedef struct { pmdval_t pmd; } pmd_t; 24 | typedef struct { pgdval_t pgd; } pgd_t; 25 | typedef struct { pteval_t pgprot; } pgprot_t; 26 | 27 | #define pte_val(x) ((x).pte) 28 | #define pmd_val(x) ((x).pmd) 29 | #define pgd_val(x) ((x).pgd) 30 | #define pgprot_val(x) ((x).pgprot) 31 | 32 | #define __pte(x) ((pte_t) { (x) } ) 33 | #define __pmd(x) ((pmd_t) { (x) } ) 34 | #define __pgd(x) ((pgd_t) { (x) } ) 35 | #define __pgprot(x) ((pgprot_t) { (x) } ) 36 | 37 | #define __va(x) ((void *)__phys_to_virt((phys_addr_t)(x))) 38 | #define __pa(x) __virt_to_phys((unsigned long)(x)) 39 | 40 | #define virt_to_pfn(kaddr) (__pa(kaddr) >> PAGE_SHIFT) 41 | #define pfn_to_virt(pfn) __va((pfn) << PAGE_SHIFT) 42 | 43 | extern phys_addr_t __virt_to_phys(unsigned long addr); 44 | extern unsigned long __phys_to_virt(phys_addr_t addr); 45 | 46 | #endif /* !__ASSEMBLY__ */ 47 | #endif /* _ASMARM_PAGE_H_ */ 48 | -------------------------------------------------------------------------------- /lib/arm/asm/pci.h: -------------------------------------------------------------------------------- 1 | #include 2 | -------------------------------------------------------------------------------- /lib/arm/asm/pgtable.h: -------------------------------------------------------------------------------- 1 | #ifndef _ASMARM_PGTABLE_H_ 2 | #define _ASMARM_PGTABLE_H_ 3 | /* 4 | * Adapted from arch/arm/include/asm/pgtable.h 5 | * arch/arm/include/asm/pgtable-3level.h 6 | * arch/arm/include/asm/pgalloc.h 7 | * 8 | * Note: some Linux function APIs have been modified. Nothing crazy, 9 | * but if a function took, for example, an mm_struct, then 10 | * that was either removed or replaced. 11 | * 12 | * Copyright (C) 2017, Red Hat Inc, Andrew Jones 13 | * 14 | * This work is licensed under the terms of the GNU GPL, version 2. 15 | */ 16 | 17 | /* 18 | * We can convert va <=> pa page table addresses with simple casts 19 | * because we always allocate their pages with alloc_page(), and 20 | * alloc_page() always returns identity mapped pages. 21 | */ 22 | #define pgtable_va(x) ((void *)(unsigned long)(x)) 23 | #define pgtable_pa(x) ((unsigned long)(x)) 24 | 25 | #define pgd_none(pgd) (!pgd_val(pgd)) 26 | #define pmd_none(pmd) (!pmd_val(pmd)) 27 | #define pte_none(pte) (!pte_val(pte)) 28 | 29 | #define pgd_index(addr) \ 30 | (((addr) >> PGDIR_SHIFT) & (PTRS_PER_PGD - 1)) 31 | #define pgd_offset(pgtable, addr) ((pgtable) + pgd_index(addr)) 32 | 33 | #define pgd_free(pgd) free(pgd) 34 | static inline pgd_t *pgd_alloc(void) 35 | { 36 | pgd_t *pgd = memalign(L1_CACHE_BYTES, PTRS_PER_PGD * sizeof(pgd_t)); 37 | memset(pgd, 0, PTRS_PER_PGD * sizeof(pgd_t)); 38 | return pgd; 39 | } 40 | 41 | static inline pmd_t *pgd_page_vaddr(pgd_t pgd) 42 | { 43 | return pgtable_va(pgd_val(pgd) & PHYS_MASK & (s32)PAGE_MASK); 44 | } 45 | 46 | #define pmd_index(addr) \ 47 | (((addr) >> PMD_SHIFT) & (PTRS_PER_PMD - 1)) 48 | #define pmd_offset(pgd, addr) \ 49 | (pgd_page_vaddr(*(pgd)) + pmd_index(addr)) 50 | 51 | #define pmd_free(pmd) free_page(pmd) 52 | static inline pmd_t *pmd_alloc_one(void) 53 | { 54 | assert(PTRS_PER_PMD * sizeof(pmd_t) == PAGE_SIZE); 55 | pmd_t *pmd = alloc_page(); 56 | memset(pmd, 0, PTRS_PER_PMD * sizeof(pmd_t)); 57 | return pmd; 58 | } 59 | static inline pmd_t *pmd_alloc(pgd_t *pgd, unsigned long addr) 60 | { 61 | if (pgd_none(*pgd)) { 62 | pmd_t *pmd = pmd_alloc_one(); 63 | pgd_val(*pgd) = pgtable_pa(pmd) | PMD_TYPE_TABLE; 64 | } 65 | return pmd_offset(pgd, addr); 66 | } 67 | 68 | static inline pte_t *pmd_page_vaddr(pmd_t pmd) 69 | { 70 | return pgtable_va(pmd_val(pmd) & PHYS_MASK & (s32)PAGE_MASK); 71 | } 72 | 73 | #define pte_index(addr) \ 74 | (((addr) >> PAGE_SHIFT) & (PTRS_PER_PTE - 1)) 75 | #define pte_offset(pmd, addr) \ 76 | (pmd_page_vaddr(*(pmd)) + pte_index(addr)) 77 | 78 | #define pte_free(pte) free_page(pte) 79 | static inline pte_t *pte_alloc_one(void) 80 | { 81 | assert(PTRS_PER_PTE * sizeof(pte_t) == PAGE_SIZE); 82 | pte_t *pte = alloc_page(); 83 | memset(pte, 0, PTRS_PER_PTE * sizeof(pte_t)); 84 | return pte; 85 | } 86 | static inline pte_t *pte_alloc(pmd_t *pmd, unsigned long addr) 87 | { 88 | if (pmd_none(*pmd)) { 89 | pte_t *pte = pte_alloc_one(); 90 | pmd_val(*pmd) = pgtable_pa(pte) | PMD_TYPE_TABLE; 91 | } 92 | return pte_offset(pmd, addr); 93 | } 94 | 95 | #endif /* _ASMARM_PGTABLE_H_ */ 96 | -------------------------------------------------------------------------------- /lib/arm/asm/processor.h: -------------------------------------------------------------------------------- 1 | #ifndef _ASMARM_PROCESSOR_H_ 2 | #define _ASMARM_PROCESSOR_H_ 3 | /* 4 | * Copyright (C) 2014, Red Hat Inc, Andrew Jones 5 | * 6 | * This work is licensed under the terms of the GNU LGPL, version 2. 7 | */ 8 | #include 9 | #include 10 | #include 11 | 12 | enum vector { 13 | EXCPTN_RST, 14 | EXCPTN_UND, 15 | EXCPTN_SVC, 16 | EXCPTN_PABT, 17 | EXCPTN_DABT, 18 | EXCPTN_ADDREXCPTN, 19 | EXCPTN_IRQ, 20 | EXCPTN_FIQ, 21 | EXCPTN_MAX, 22 | }; 23 | 24 | typedef void (*exception_fn)(struct pt_regs *); 25 | extern void install_exception_handler(enum vector v, exception_fn fn); 26 | 27 | extern void show_regs(struct pt_regs *regs); 28 | 29 | static inline unsigned long current_cpsr(void) 30 | { 31 | unsigned long cpsr; 32 | asm volatile("mrs %0, cpsr" : "=r" (cpsr)); 33 | return cpsr; 34 | } 35 | 36 | #define current_mode() (current_cpsr() & MODE_MASK) 37 | 38 | static inline void local_irq_enable(void) 39 | { 40 | asm volatile("cpsie i" : : : "memory", "cc"); 41 | } 42 | 43 | static inline void local_irq_disable(void) 44 | { 45 | asm volatile("cpsid i" : : : "memory", "cc"); 46 | } 47 | 48 | #define MPIDR __ACCESS_CP15(c0, 0, c0, 5) 49 | static inline uint64_t get_mpidr(void) 50 | { 51 | return read_sysreg(MPIDR); 52 | } 53 | 54 | #define MPIDR_HWID_BITMASK 0xffffff 55 | extern int mpidr_to_cpu(uint64_t mpidr); 56 | 57 | #define MPIDR_LEVEL_SHIFT(level) \ 58 | (((1 << level) >> 1) << 3) 59 | #define MPIDR_AFFINITY_LEVEL(mpidr, level) \ 60 | ((mpidr >> MPIDR_LEVEL_SHIFT(level)) & 0xff) 61 | 62 | extern void start_usr(void (*func)(void *arg), void *arg, unsigned long sp_usr); 63 | extern bool is_user(void); 64 | 65 | #define CNTVCT __ACCESS_CP15_64(1, c14) 66 | #define CNTFRQ __ACCESS_CP15(c14, 0, c0, 0) 67 | 68 | static inline u64 get_cntvct(void) 69 | { 70 | isb(); 71 | return read_sysreg(CNTVCT); 72 | } 73 | 74 | static inline u32 get_cntfrq(void) 75 | { 76 | return read_sysreg(CNTFRQ); 77 | } 78 | 79 | #endif /* _ASMARM_PROCESSOR_H_ */ 80 | -------------------------------------------------------------------------------- /lib/arm/asm/psci.h: -------------------------------------------------------------------------------- 1 | #ifndef _ASMARM_PSCI_H_ 2 | #define _ASMARM_PSCI_H_ 3 | #include 4 | #include 5 | 6 | extern int psci_invoke(unsigned long function_id, unsigned long arg0, 7 | unsigned long arg1, unsigned long arg2); 8 | extern int psci_cpu_on(unsigned long cpuid, unsigned long entry_point); 9 | extern void psci_system_reset(void); 10 | extern int cpu_psci_cpu_boot(unsigned int cpu); 11 | extern void cpu_psci_cpu_die(void); 12 | extern void psci_system_off(void); 13 | 14 | #endif /* _ASMARM_PSCI_H_ */ 15 | -------------------------------------------------------------------------------- /lib/arm/asm/ptrace.h: -------------------------------------------------------------------------------- 1 | #ifndef _ASMARM_PTRACE_H_ 2 | #define _ASMARM_PTRACE_H_ 3 | /* 4 | * Adapted from Linux kernel headers 5 | * arch/arm/include/asm/ptrace.h 6 | * arch/arm/include/uapi/asm/ptrace.h 7 | * 8 | * Copyright (C) 2017, Red Hat Inc, Andrew Jones 9 | * 10 | * This work is licensed under the terms of the GNU GPL, version 2. 11 | */ 12 | 13 | /* 14 | * PSR bits 15 | */ 16 | #define USR_MODE 0x00000010 17 | #define SVC_MODE 0x00000013 18 | #define FIQ_MODE 0x00000011 19 | #define IRQ_MODE 0x00000012 20 | #define ABT_MODE 0x00000017 21 | #define HYP_MODE 0x0000001a 22 | #define UND_MODE 0x0000001b 23 | #define SYSTEM_MODE 0x0000001f 24 | #define MODE32_BIT 0x00000010 25 | #define MODE_MASK 0x0000001f 26 | 27 | #define PSR_T_BIT 0x00000020 /* >= V4T, but not V7M */ 28 | #define PSR_F_BIT 0x00000040 /* >= V4, but not V7M */ 29 | #define PSR_I_BIT 0x00000080 /* >= V4, but not V7M */ 30 | #define PSR_A_BIT 0x00000100 /* >= V6, but not V7M */ 31 | #define PSR_E_BIT 0x00000200 /* >= V6, but not V7M */ 32 | #define PSR_J_BIT 0x01000000 /* >= V5J, but not V7M */ 33 | #define PSR_Q_BIT 0x08000000 /* >= V5E, including V7M */ 34 | #define PSR_V_BIT 0x10000000 35 | #define PSR_C_BIT 0x20000000 36 | #define PSR_Z_BIT 0x40000000 37 | #define PSR_N_BIT 0x80000000 38 | 39 | /* 40 | * Groups of PSR bits 41 | */ 42 | #define PSR_f 0xff000000 /* Flags */ 43 | #define PSR_s 0x00ff0000 /* Status */ 44 | #define PSR_x 0x0000ff00 /* Extension */ 45 | #define PSR_c 0x000000ff /* Control */ 46 | 47 | /* 48 | * ARMv7 groups of PSR bits 49 | */ 50 | #define APSR_MASK 0xf80f0000 /* N, Z, C, V, Q and GE flags */ 51 | #define PSR_ISET_MASK 0x01000010 /* ISA state (J, T) mask */ 52 | #define PSR_IT_MASK 0x0600fc00 /* If-Then execution state mask */ 53 | #define PSR_ENDIAN_MASK 0x00000200 /* Endianness state mask */ 54 | 55 | #ifndef __ASSEMBLY__ 56 | #include 57 | 58 | struct pt_regs { 59 | unsigned long uregs[18]; 60 | }; 61 | 62 | #define ARM_cpsr uregs[16] 63 | #define ARM_pc uregs[15] 64 | #define ARM_lr uregs[14] 65 | #define ARM_sp uregs[13] 66 | #define ARM_ip uregs[12] 67 | #define ARM_fp uregs[11] 68 | #define ARM_r10 uregs[10] 69 | #define ARM_r9 uregs[9] 70 | #define ARM_r8 uregs[8] 71 | #define ARM_r7 uregs[7] 72 | #define ARM_r6 uregs[6] 73 | #define ARM_r5 uregs[5] 74 | #define ARM_r4 uregs[4] 75 | #define ARM_r3 uregs[3] 76 | #define ARM_r2 uregs[2] 77 | #define ARM_r1 uregs[1] 78 | #define ARM_r0 uregs[0] 79 | #define ARM_ORIG_r0 uregs[17] 80 | 81 | #define user_mode(regs) \ 82 | (((regs)->ARM_cpsr & 0xf) == 0) 83 | 84 | #define processor_mode(regs) \ 85 | ((regs)->ARM_cpsr & MODE_MASK) 86 | 87 | #define interrupts_enabled(regs) \ 88 | (!((regs)->ARM_cpsr & PSR_I_BIT)) 89 | 90 | #define fast_interrupts_enabled(regs) \ 91 | (!((regs)->ARM_cpsr & PSR_F_BIT)) 92 | 93 | #define MAX_REG_OFFSET (offsetof(struct pt_regs, ARM_ORIG_r0)) 94 | 95 | static inline unsigned long regs_get_register(struct pt_regs *regs, 96 | unsigned int offset) 97 | { 98 | if (offset > MAX_REG_OFFSET) 99 | return 0; 100 | return *(unsigned long *)((unsigned long)regs + offset); 101 | } 102 | 103 | #endif /* !__ASSEMBLY__ */ 104 | #endif /* _ASMARM_PTRACE_H_ */ 105 | -------------------------------------------------------------------------------- /lib/arm/asm/setup.h: -------------------------------------------------------------------------------- 1 | #ifndef _ASMARM_SETUP_H_ 2 | #define _ASMARM_SETUP_H_ 3 | /* 4 | * Copyright (C) 2014, Red Hat Inc, Andrew Jones 5 | * 6 | * This work is licensed under the terms of the GNU LGPL, version 2. 7 | */ 8 | #include 9 | #include 10 | #include 11 | 12 | #define NR_CPUS 511 13 | extern u64 cpus[NR_CPUS]; /* per-cpu IDs (MPIDRs) */ 14 | extern int nr_cpus; 15 | 16 | #define NR_MEM_REGIONS 8 17 | #define MR_F_PRIMARY (1U << 0) 18 | struct mem_region { 19 | phys_addr_t start; 20 | phys_addr_t end; 21 | unsigned int flags; 22 | }; 23 | extern struct mem_region mem_regions[NR_MEM_REGIONS]; 24 | extern phys_addr_t __phys_offset, __phys_end; 25 | 26 | #define PHYS_OFFSET (__phys_offset) 27 | #define PHYS_END (__phys_end) 28 | 29 | #define L1_CACHE_SHIFT 6 30 | #define L1_CACHE_BYTES (1 << L1_CACHE_SHIFT) 31 | #define SMP_CACHE_BYTES L1_CACHE_BYTES 32 | 33 | void setup(const void *fdt); 34 | 35 | #endif /* _ASMARM_SETUP_H_ */ 36 | -------------------------------------------------------------------------------- /lib/arm/asm/smp.h: -------------------------------------------------------------------------------- 1 | #ifndef _ASMARM_SMP_H_ 2 | #define _ASMARM_SMP_H_ 3 | /* 4 | * Copyright (C) 2015, Red Hat Inc, Andrew Jones 5 | * 6 | * This work is licensed under the terms of the GNU LGPL, version 2. 7 | */ 8 | #include 9 | #include 10 | 11 | #define smp_processor_id() (current_thread_info()->cpu) 12 | 13 | extern bool cpu0_calls_idle; 14 | 15 | extern void halt(void); 16 | extern void do_idle(void); 17 | 18 | extern cpumask_t cpu_present_mask; 19 | extern cpumask_t cpu_online_mask; 20 | extern cpumask_t cpu_idle_mask; 21 | #define cpu_present(cpu) cpumask_test_cpu(cpu, &cpu_present_mask) 22 | #define cpu_online(cpu) cpumask_test_cpu(cpu, &cpu_online_mask) 23 | #define cpu_idle(cpu) cpumask_test_cpu(cpu, &cpu_idle_mask) 24 | #define for_each_present_cpu(cpu) for_each_cpu(cpu, &cpu_present_mask) 25 | #define for_each_online_cpu(cpu) for_each_cpu(cpu, &cpu_online_mask) 26 | 27 | static inline void set_cpu_present(int cpu, bool present) 28 | { 29 | if (present) 30 | cpumask_set_cpu(cpu, &cpu_present_mask); 31 | else 32 | cpumask_clear_cpu(cpu, &cpu_present_mask); 33 | } 34 | 35 | static inline void set_cpu_online(int cpu, bool online) 36 | { 37 | if (online) 38 | cpumask_set_cpu(cpu, &cpu_online_mask); 39 | else 40 | cpumask_clear_cpu(cpu, &cpu_online_mask); 41 | } 42 | 43 | static inline void set_cpu_idle(int cpu, bool idle) 44 | { 45 | if (idle) 46 | cpumask_set_cpu(cpu, &cpu_idle_mask); 47 | else 48 | cpumask_clear_cpu(cpu, &cpu_idle_mask); 49 | } 50 | 51 | typedef void (*secondary_entry_fn)(void); 52 | extern void smp_boot_secondary(int cpu, secondary_entry_fn entry); 53 | extern void on_cpu_async(int cpu, void (*func)(void *data), void *data); 54 | extern void on_cpu(int cpu, void (*func)(void *data), void *data); 55 | extern void on_cpus(void (*func)(void *data), void *data); 56 | 57 | #endif /* _ASMARM_SMP_H_ */ 58 | -------------------------------------------------------------------------------- /lib/arm/asm/spinlock.h: -------------------------------------------------------------------------------- 1 | #ifndef _ASMARM_SPINLOCK_H_ 2 | #define _ASMARM_SPINLOCK_H_ 3 | 4 | struct spinlock { 5 | int v; 6 | }; 7 | 8 | extern void spin_lock(struct spinlock *lock); 9 | extern void spin_unlock(struct spinlock *lock); 10 | 11 | #endif /* _ASMARM_SPINLOCK_H_ */ 12 | -------------------------------------------------------------------------------- /lib/arm/asm/stack.h: -------------------------------------------------------------------------------- 1 | #ifndef _ASMARM_STACK_H_ 2 | #define _ASMARM_STACK_H_ 3 | 4 | #ifndef _STACK_H_ 5 | #error Do not directly include . Just use . 6 | #endif 7 | 8 | #define HAVE_ARCH_BACKTRACE_FRAME 9 | #define HAVE_ARCH_BACKTRACE 10 | 11 | #endif 12 | -------------------------------------------------------------------------------- /lib/arm/asm/sysreg.h: -------------------------------------------------------------------------------- 1 | #ifndef _ASMARM_SYSREG_H_ 2 | #define _ASMARM_SYSREG_H_ 3 | /* 4 | * From the Linux kernel arch/arm/include/asm/cp15.h 5 | * 6 | * This work is licensed under the terms of the GNU GPL, version 2. 7 | */ 8 | 9 | /* 10 | * CR1 bits (CP#15 CR1) 11 | */ 12 | #define CR_M (1 << 0) /* MMU enable */ 13 | #define CR_A (1 << 1) /* Alignment abort enable */ 14 | #define CR_C (1 << 2) /* Dcache enable */ 15 | #define CR_W (1 << 3) /* Write buffer enable */ 16 | #define CR_P (1 << 4) /* 32-bit exception handler */ 17 | #define CR_D (1 << 5) /* 32-bit data address range */ 18 | #define CR_L (1 << 6) /* Implementation defined */ 19 | #define CR_B (1 << 7) /* Big endian */ 20 | #define CR_S (1 << 8) /* System MMU protection */ 21 | #define CR_R (1 << 9) /* ROM MMU protection */ 22 | #define CR_F (1 << 10) /* Implementation defined */ 23 | #define CR_Z (1 << 11) /* Implementation defined */ 24 | #define CR_I (1 << 12) /* Icache enable */ 25 | #define CR_V (1 << 13) /* Vectors relocated to 0xffff0000 */ 26 | #define CR_RR (1 << 14) /* Round Robin cache replacement */ 27 | #define CR_L4 (1 << 15) /* LDR pc can set T bit */ 28 | #define CR_DT (1 << 16) 29 | #define CR_HA (1 << 17) /* Hardware management of Access Flag */ 30 | #define CR_IT (1 << 18) 31 | #define CR_ST (1 << 19) 32 | #define CR_FI (1 << 21) /* Fast interrupt (lower latency mode) */ 33 | #define CR_U (1 << 22) /* Unaligned access operation */ 34 | #define CR_XP (1 << 23) /* Extended page tables */ 35 | #define CR_VE (1 << 24) /* Vectored interrupts */ 36 | #define CR_EE (1 << 25) /* Exception (Big) Endian */ 37 | #define CR_TRE (1 << 28) /* TEX remap enable */ 38 | #define CR_AFE (1 << 29) /* Access flag enable */ 39 | #define CR_TE (1 << 30) /* Thumb exception enable */ 40 | 41 | #ifndef __ASSEMBLY__ 42 | #include 43 | 44 | #define __ACCESS_CP15(CRn, Op1, CRm, Op2) \ 45 | "mrc", "mcr", xstr(p15, Op1, %0, CRn, CRm, Op2), u32 46 | #define __ACCESS_CP15_64(Op1, CRm) \ 47 | "mrrc", "mcrr", xstr(p15, Op1, %Q0, %R0, CRm), u64 48 | 49 | #define __ACCESS_CP14(CRn, Op1, CRm, Op2) \ 50 | "mrc", "mcr", xstr(p14, Op1, %0, CRn, CRm, Op2), u32 51 | #define __ACCESS_CP14_64(Op1, CRm) \ 52 | "mrrc", "mcrr", xstr(p14, Op1, %Q0, %R0, CRm), u64 53 | 54 | #define __read_sysreg(r, w, c, t) ({ \ 55 | t __val; \ 56 | asm volatile(r " " c : "=r" (__val)); \ 57 | __val; \ 58 | }) 59 | #define read_sysreg(...) __read_sysreg(__VA_ARGS__) 60 | 61 | #define __write_sysreg(v, r, w, c, t) asm volatile(w " " c : : "r" ((t)(v))) 62 | #define write_sysreg(v, ...) __write_sysreg(v, __VA_ARGS__) 63 | #endif /* !__ASSEMBLY__ */ 64 | 65 | #endif /* _ASMARM_SYSREG_H_ */ 66 | -------------------------------------------------------------------------------- /lib/arm/asm/thread_info.h: -------------------------------------------------------------------------------- 1 | #ifndef _ASMARM_THREAD_INFO_H_ 2 | #define _ASMARM_THREAD_INFO_H_ 3 | /* 4 | * Adapted from arch/arm64/include/asm/thread_info.h 5 | * 6 | * Copyright (C) 2017, Red Hat Inc, Andrew Jones 7 | * 8 | * This work is licensed under the terms of the GNU GPL, version 2. 9 | */ 10 | #include 11 | 12 | #define MIN_THREAD_SHIFT 14 /* THREAD_SIZE == 16K */ 13 | #if PAGE_SHIFT > MIN_THREAD_SHIFT 14 | #define THREAD_SHIFT PAGE_SHIFT 15 | #define THREAD_SIZE PAGE_SIZE 16 | #define THREAD_MASK PAGE_MASK 17 | #else 18 | #define THREAD_SHIFT MIN_THREAD_SHIFT 19 | #define THREAD_SIZE (_AC(1,UL) << THREAD_SHIFT) 20 | #define THREAD_MASK (~(THREAD_SIZE-1)) 21 | #endif 22 | 23 | #ifndef __ASSEMBLY__ 24 | #include 25 | #include 26 | 27 | #ifdef __arm__ 28 | #include 29 | /* 30 | * arm needs room left at the top for the exception stacks, 31 | * and the stack needs to be 8-byte aligned 32 | */ 33 | #define THREAD_START_SP \ 34 | ((THREAD_SIZE - (sizeof(struct pt_regs) * 8)) & ~7) 35 | #else 36 | #define THREAD_START_SP (THREAD_SIZE - 16) 37 | #endif 38 | 39 | static inline void *thread_stack_alloc(void) 40 | { 41 | void *sp = memalign(PAGE_SIZE, THREAD_SIZE); 42 | return sp + THREAD_START_SP; 43 | } 44 | 45 | #define TIF_USER_MODE (1U << 0) 46 | 47 | struct thread_info { 48 | int cpu; 49 | unsigned int flags; 50 | void *pgtable; 51 | #ifdef __arm__ 52 | exception_fn exception_handlers[EXCPTN_MAX]; 53 | #else 54 | vector_fn vector_handlers[VECTOR_MAX]; 55 | exception_fn exception_handlers[VECTOR_MAX][EC_MAX]; 56 | #endif 57 | char ext[0]; /* allow unit tests to add extended info */ 58 | }; 59 | 60 | static inline struct thread_info *thread_info_sp(unsigned long sp) 61 | { 62 | return (struct thread_info *)(sp & ~(THREAD_SIZE - 1)); 63 | } 64 | 65 | register unsigned long current_stack_pointer asm("sp"); 66 | 67 | static inline struct thread_info *current_thread_info(void) 68 | { 69 | return thread_info_sp(current_stack_pointer); 70 | } 71 | 72 | extern void thread_info_init(struct thread_info *ti, unsigned int flags); 73 | 74 | #endif /* !__ASSEMBLY__ */ 75 | #endif /* _ASMARM_THREAD_INFO_H_ */ 76 | -------------------------------------------------------------------------------- /lib/arm/bitops.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Adapted from 3 | * include/asm-generic/bitops/atomic.h 4 | * 5 | * Copyright (C) 2017, Red Hat Inc, Andrew Jones 6 | * 7 | * This work is licensed under the terms of the GNU GPL, version 2. 8 | */ 9 | #include "libcflat.h" 10 | #include 11 | #include 12 | #include 13 | 14 | void set_bit(int nr, volatile unsigned long *addr) 15 | { 16 | volatile unsigned long *word = addr + BIT_WORD(nr); 17 | unsigned long mask = BIT_MASK(nr); 18 | 19 | if (mmu_enabled()) 20 | ATOMIC_BITOP("orr", mask, word); 21 | else 22 | *word |= mask; 23 | smp_mb(); 24 | } 25 | 26 | void clear_bit(int nr, volatile unsigned long *addr) 27 | { 28 | volatile unsigned long *word = addr + BIT_WORD(nr); 29 | unsigned long mask = BIT_MASK(nr); 30 | 31 | if (mmu_enabled()) 32 | ATOMIC_BITOP("bic", mask, word); 33 | else 34 | *word &= ~mask; 35 | smp_mb(); 36 | } 37 | 38 | int test_bit(int nr, const volatile unsigned long *addr) 39 | { 40 | const volatile unsigned long *word = addr + BIT_WORD(nr); 41 | unsigned long mask = BIT_MASK(nr); 42 | 43 | return (*word & mask) != 0; 44 | } 45 | 46 | int test_and_set_bit(int nr, volatile unsigned long *addr) 47 | { 48 | volatile unsigned long *word = addr + BIT_WORD(nr); 49 | unsigned long mask = BIT_MASK(nr); 50 | unsigned long old; 51 | 52 | smp_mb(); 53 | 54 | if (mmu_enabled()) { 55 | ATOMIC_TESTOP("orr", mask, word, old); 56 | } else { 57 | old = *word; 58 | *word = old | mask; 59 | } 60 | smp_mb(); 61 | 62 | return (old & mask) != 0; 63 | } 64 | 65 | int test_and_clear_bit(int nr, volatile unsigned long *addr) 66 | { 67 | volatile unsigned long *word = addr + BIT_WORD(nr); 68 | unsigned long mask = BIT_MASK(nr); 69 | unsigned long old; 70 | 71 | smp_mb(); 72 | 73 | if (mmu_enabled()) { 74 | ATOMIC_TESTOP("bic", mask, word, old); 75 | } else { 76 | old = *word; 77 | *word = old & ~mask; 78 | } 79 | smp_mb(); 80 | 81 | return (old & mask) != 0; 82 | } 83 | -------------------------------------------------------------------------------- /lib/arm/delay.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Delay loops 3 | * 4 | * Copyright (C) 2016, Red Hat Inc, Andrew Jones 5 | * 6 | * This work is licensed under the terms of the GNU LGPL, version 2. 7 | */ 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | void delay(u64 cycles) 14 | { 15 | u64 start = get_cntvct(); 16 | 17 | while ((get_cntvct() - start) < cycles) 18 | cpu_relax(); 19 | } 20 | 21 | void udelay(unsigned long usec) 22 | { 23 | delay((u64)usec * get_cntfrq() / 1000000); 24 | } 25 | 26 | void mdelay(unsigned long msecs) 27 | { 28 | while (msecs--) 29 | udelay(1000); 30 | } 31 | -------------------------------------------------------------------------------- /lib/arm/eabi_compat.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Adapted from u-boot's arch/arm/lib/eabi_compat.c 3 | * 4 | * Copyright (C) 2017, Red Hat Inc, Andrew Jones 5 | * 6 | * This work is licensed under the terms of the GNU GPL, version 2. 7 | */ 8 | #include 9 | 10 | /* Needed to compile with -Wmissing-prototypes */ 11 | int raise(int signum); 12 | void __aeabi_unwind_cpp_pr0(void); 13 | void __aeabi_unwind_cpp_pr1(void); 14 | 15 | int raise(int signum __unused) 16 | { 17 | printf("Divide by zero!\n"); 18 | abort(); 19 | return 0; 20 | } 21 | 22 | /* Dummy functions to avoid linker complaints */ 23 | void __aeabi_unwind_cpp_pr0(void) 24 | { 25 | } 26 | 27 | void __aeabi_unwind_cpp_pr1(void) 28 | { 29 | } 30 | -------------------------------------------------------------------------------- /lib/arm/gic-v2.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2016, Red Hat Inc, Andrew Jones 3 | * 4 | * This work is licensed under the terms of the GNU LGPL, version 2. 5 | */ 6 | #include 7 | #include 8 | 9 | void gicv2_enable_defaults(void) 10 | { 11 | void *dist = gicv2_dist_base(); 12 | void *cpu_base = gicv2_cpu_base(); 13 | unsigned int i; 14 | 15 | gicv2_data.irq_nr = GICD_TYPER_IRQS(readl(dist + GICD_TYPER)); 16 | if (gicv2_data.irq_nr > 1020) 17 | gicv2_data.irq_nr = 1020; 18 | 19 | for (i = 0; i < gicv2_data.irq_nr; i += 4) 20 | writel(GICD_INT_DEF_PRI_X4, dist + GICD_IPRIORITYR + i); 21 | 22 | writel(GICD_INT_EN_SET_SGI, dist + GICD_ISENABLER + 0); 23 | writel(GICD_ENABLE, dist + GICD_CTLR); 24 | 25 | writel(GICC_INT_PRI_THRESHOLD, cpu_base + GICC_PMR); 26 | writel(GICC_ENABLE, cpu_base + GICC_CTLR); 27 | } 28 | 29 | u32 gicv2_read_iar(void) 30 | { 31 | return readl(gicv2_cpu_base() + GICC_IAR); 32 | } 33 | 34 | u32 gicv2_iar_irqnr(u32 iar) 35 | { 36 | return iar & GICC_IAR_INT_ID_MASK; 37 | } 38 | 39 | void gicv2_write_eoir(u32 irqstat) 40 | { 41 | writel(irqstat, gicv2_cpu_base() + GICC_EOIR); 42 | } 43 | 44 | void gicv2_ipi_send_single(int irq, int cpu) 45 | { 46 | assert(cpu < 8); 47 | assert(irq < 16); 48 | writel(1 << (cpu + 16) | irq, gicv2_dist_base() + GICD_SGIR); 49 | } 50 | 51 | void gicv2_ipi_send_mask(int irq, const cpumask_t *dest) 52 | { 53 | u8 tlist = (u8)cpumask_bits(dest)[0]; 54 | 55 | assert(irq < 16); 56 | writel(tlist << 16 | irq, gicv2_dist_base() + GICD_SGIR); 57 | } 58 | -------------------------------------------------------------------------------- /lib/arm/io.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Each architecture must implement puts() and exit() with the I/O 3 | * devices exposed from QEMU, e.g. pl011 and chr-testdev. That's 4 | * what's done here, along with initialization functions for those 5 | * devices. 6 | * 7 | * Copyright (C) 2014, Red Hat Inc, Andrew Jones 8 | * 9 | * This work is licensed under the terms of the GNU LGPL, version 2. 10 | */ 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | 19 | #include "io.h" 20 | 21 | static struct spinlock uart_lock; 22 | /* 23 | * Use this guess for the uart base in order to make an attempt at 24 | * having earlier printf support. We'll overwrite it with the real 25 | * base address that we read from the device tree later. This is 26 | * the address we expect the virtual machine manager to put in 27 | * its generated device tree. 28 | */ 29 | #define UART_EARLY_BASE (u8 *)(unsigned long)CONFIG_UART_EARLY_BASE 30 | static volatile u8 *uart0_base = UART_EARLY_BASE; 31 | 32 | static void uart0_init(void) 33 | { 34 | /* 35 | * kvm-unit-tests uses the uart only for output. Both uart models have 36 | * the TX register at offset 0 from the base address, so there is no 37 | * need to treat them separately. 38 | */ 39 | const char *compatible[] = {"arm,pl011", "ns16550a"}; 40 | struct dt_pbus_reg base; 41 | int i, ret; 42 | 43 | ret = dt_get_default_console_node(); 44 | assert(ret >= 0 || ret == -FDT_ERR_NOTFOUND); 45 | 46 | if (ret == -FDT_ERR_NOTFOUND) { 47 | 48 | for (i = 0; i < ARRAY_SIZE(compatible); i++) { 49 | ret = dt_pbus_get_base_compatible(compatible[i], &base); 50 | assert(ret == 0 || ret == -FDT_ERR_NOTFOUND); 51 | 52 | if (ret == 0) 53 | break; 54 | } 55 | 56 | if (ret) { 57 | printf("%s: Compatible uart not found in the device tree, " 58 | "aborting...\n", __func__); 59 | abort(); 60 | } 61 | 62 | } else { 63 | ret = dt_pbus_translate_node(ret, 0, &base); 64 | assert(ret == 0); 65 | } 66 | 67 | uart0_base = ioremap(base.addr, base.size); 68 | 69 | if (uart0_base != UART_EARLY_BASE) { 70 | printf("WARNING: early print support may not work. " 71 | "Found uart at %p, but early base is %p.\n", 72 | uart0_base, UART_EARLY_BASE); 73 | } 74 | } 75 | 76 | void io_init(void) 77 | { 78 | uart0_init(); 79 | chr_testdev_init(); 80 | } 81 | 82 | void puts(const char *s) 83 | { 84 | spin_lock(&uart_lock); 85 | while (*s) 86 | writeb(*s++, uart0_base); 87 | spin_unlock(&uart_lock); 88 | } 89 | 90 | 91 | /* 92 | * Defining halt to take 'code' as an argument guarantees that it will 93 | * be in x0/r0 when we halt. That gives us a final chance to see the exit 94 | * status while inspecting the halted unit test state. 95 | */ 96 | extern void halt(int code); 97 | 98 | void exit(int code) 99 | { 100 | chr_testdev_exit(code); 101 | psci_system_off(); 102 | halt(code); 103 | __builtin_unreachable(); 104 | } 105 | -------------------------------------------------------------------------------- /lib/arm/io.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Prototypes for io.c 3 | * 4 | * This work is licensed under the terms of the GNU GPL, version 2. 5 | */ 6 | 7 | extern void io_init(void); 8 | -------------------------------------------------------------------------------- /lib/arm/psci.c: -------------------------------------------------------------------------------- 1 | /* 2 | * PSCI API 3 | * From arch/arm[64]/kernel/psci.c 4 | * 5 | * Copyright (C) 2015, Red Hat Inc, Andrew Jones 6 | * 7 | * This work is licensed under the terms of the GNU LGPL, version 2. 8 | */ 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | __attribute__((noinline)) 15 | int psci_invoke(unsigned long function_id, unsigned long arg0, 16 | unsigned long arg1, unsigned long arg2) 17 | { 18 | asm volatile( 19 | "hvc #0" 20 | : "+r" (function_id) 21 | : "r" (arg0), "r" (arg1), "r" (arg2)); 22 | return function_id; 23 | } 24 | 25 | int psci_cpu_on(unsigned long cpuid, unsigned long entry_point) 26 | { 27 | #ifdef __arm__ 28 | return psci_invoke(PSCI_0_2_FN_CPU_ON, cpuid, entry_point, 0); 29 | #else 30 | return psci_invoke(PSCI_0_2_FN64_CPU_ON, cpuid, entry_point, 0); 31 | #endif 32 | } 33 | 34 | extern void secondary_entry(void); 35 | int cpu_psci_cpu_boot(unsigned int cpu) 36 | { 37 | int err = psci_cpu_on(cpus[cpu], __pa(secondary_entry)); 38 | if (err) 39 | printf("failed to boot CPU%d (%d)\n", cpu, err); 40 | return err; 41 | } 42 | 43 | #define PSCI_POWER_STATE_TYPE_POWER_DOWN (1U << 16) 44 | void cpu_psci_cpu_die(void) 45 | { 46 | int err = psci_invoke(PSCI_0_2_FN_CPU_OFF, 47 | PSCI_POWER_STATE_TYPE_POWER_DOWN, 0, 0); 48 | printf("CPU%d unable to power off (error = %d)\n", smp_processor_id(), err); 49 | } 50 | 51 | void psci_system_reset(void) 52 | { 53 | psci_invoke(PSCI_0_2_FN_SYSTEM_RESET, 0, 0, 0); 54 | } 55 | 56 | void psci_system_off(void) 57 | { 58 | int err = psci_invoke(PSCI_0_2_FN_SYSTEM_OFF, 0, 0, 0); 59 | printf("CPU%d unable to do system off (error = %d)\n", smp_processor_id(), err); 60 | } 61 | -------------------------------------------------------------------------------- /lib/arm/spinlock.c: -------------------------------------------------------------------------------- 1 | /* 2 | * ARM spinlock implementation 3 | * 4 | * This code is free software; you can redistribute it and/or modify it 5 | * under the terms of the GNU Library General Public License version 2. 6 | */ 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | void spin_lock(struct spinlock *lock) 13 | { 14 | u32 val, fail; 15 | 16 | if (!mmu_enabled()) { 17 | lock->v = 1; 18 | smp_mb(); 19 | return; 20 | } 21 | 22 | do { 23 | asm volatile( 24 | "1: ldrex %0, [%2]\n" 25 | " teq %0, #0\n" 26 | " bne 1b\n" 27 | " mov %0, #1\n" 28 | " strex %1, %0, [%2]\n" 29 | : "=&r" (val), "=&r" (fail) 30 | : "r" (&lock->v) 31 | : "cc" ); 32 | } while (fail); 33 | 34 | smp_mb(); 35 | } 36 | 37 | void spin_unlock(struct spinlock *lock) 38 | { 39 | smp_mb(); 40 | lock->v = 0; 41 | } 42 | -------------------------------------------------------------------------------- /lib/arm/stack.c: -------------------------------------------------------------------------------- 1 | /* 2 | * backtrace support (this is a modified lib/x86/stack.c) 3 | * 4 | * Copyright (C) 2016, Red Hat Inc, Andrew Jones 5 | * 6 | * This work is licensed under the terms of the GNU LGPL, version 2. 7 | */ 8 | #include 9 | #include 10 | 11 | int backtrace_frame(const void *frame, const void **return_addrs, 12 | int max_depth) 13 | { 14 | static int walking; 15 | int depth; 16 | const unsigned long *fp = (unsigned long *)frame; 17 | 18 | if (walking) { 19 | printf("RECURSIVE STACK WALK!!!\n"); 20 | return 0; 21 | } 22 | walking = 1; 23 | 24 | for (depth = 0; depth < max_depth; depth++) { 25 | if (!fp) 26 | break; 27 | return_addrs[depth] = (void *)fp[0]; 28 | if (return_addrs[depth] == 0) 29 | break; 30 | fp = (unsigned long *)fp[-1]; 31 | } 32 | 33 | walking = 0; 34 | return depth; 35 | } 36 | 37 | int backtrace(const void **return_addrs, int max_depth) 38 | { 39 | return backtrace_frame(__builtin_frame_address(0), 40 | return_addrs, max_depth); 41 | } 42 | -------------------------------------------------------------------------------- /lib/arm64/.gitignore: -------------------------------------------------------------------------------- 1 | asm-offsets.[hs] 2 | -------------------------------------------------------------------------------- /lib/arm64/asm-offsets.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Adapted from arch/arm64/kernel/asm-offsets.c 3 | * 4 | * Copyright (C) 2017, Red Hat Inc, Andrew Jones 5 | * 6 | * This work is licensed under the terms of the GNU GPL, version 2. 7 | */ 8 | #include 9 | #include 10 | #include 11 | 12 | int main(void) 13 | { 14 | OFFSET(S_X0, pt_regs, regs[0]); 15 | OFFSET(S_X1, pt_regs, regs[1]); 16 | OFFSET(S_X2, pt_regs, regs[2]); 17 | OFFSET(S_X3, pt_regs, regs[3]); 18 | OFFSET(S_X4, pt_regs, regs[4]); 19 | OFFSET(S_X5, pt_regs, regs[5]); 20 | OFFSET(S_X6, pt_regs, regs[6]); 21 | OFFSET(S_X7, pt_regs, regs[7]); 22 | OFFSET(S_LR, pt_regs, regs[30]); 23 | OFFSET(S_SP, pt_regs, sp); 24 | OFFSET(S_PC, pt_regs, pc); 25 | OFFSET(S_PSTATE, pt_regs, pstate); 26 | OFFSET(S_ORIG_X0, pt_regs, orig_x0); 27 | OFFSET(S_SYSCALLNO, pt_regs, syscallno); 28 | DEFINE(S_FRAME_SIZE, sizeof(struct pt_regs)); 29 | return 0; 30 | } 31 | -------------------------------------------------------------------------------- /lib/arm64/asm/arch_gicv3.h: -------------------------------------------------------------------------------- 1 | /* 2 | * All ripped off from arch/arm64/include/asm/arch_gicv3.h 3 | * 4 | * Copyright (C) 2016, Red Hat Inc, Andrew Jones 5 | * 6 | * This work is licensed under the terms of the GNU LGPL, version 2. 7 | */ 8 | #ifndef _ASMARM64_ARCH_GICV3_H_ 9 | #define _ASMARM64_ARCH_GICV3_H_ 10 | 11 | #include 12 | 13 | #define ICC_PMR_EL1 sys_reg(3, 0, 4, 6, 0) 14 | #define ICC_SGI1R_EL1 sys_reg(3, 0, 12, 11, 5) 15 | #define ICC_IAR1_EL1 sys_reg(3, 0, 12, 12, 0) 16 | #define ICC_EOIR1_EL1 sys_reg(3, 0, 12, 12, 1) 17 | #define ICC_GRPEN1_EL1 sys_reg(3, 0, 12, 12, 7) 18 | 19 | #ifndef __ASSEMBLY__ 20 | 21 | #include 22 | #include 23 | 24 | /* 25 | * Low-level accessors 26 | * 27 | * These system registers are 32 bits, but we make sure that the compiler 28 | * sets the GP register's most significant bits to 0 with an explicit cast. 29 | */ 30 | 31 | static inline void gicv3_write_pmr(u32 val) 32 | { 33 | asm volatile("msr_s " xstr(ICC_PMR_EL1) ", %0" : : "r" ((u64)val)); 34 | } 35 | 36 | static inline void gicv3_write_sgi1r(u64 val) 37 | { 38 | asm volatile("msr_s " xstr(ICC_SGI1R_EL1) ", %0" : : "r" (val)); 39 | } 40 | 41 | static inline u32 gicv3_read_iar(void) 42 | { 43 | u64 irqstat; 44 | asm volatile("mrs_s %0, " xstr(ICC_IAR1_EL1) : "=r" (irqstat)); 45 | dsb(sy); 46 | return (u64)irqstat; 47 | } 48 | 49 | static inline void gicv3_write_eoir(u32 irq) 50 | { 51 | asm volatile("msr_s " xstr(ICC_EOIR1_EL1) ", %0" : : "r" ((u64)irq)); 52 | isb(); 53 | } 54 | 55 | static inline void gicv3_write_grpen1(u32 val) 56 | { 57 | asm volatile("msr_s " xstr(ICC_GRPEN1_EL1) ", %0" : : "r" ((u64)val)); 58 | isb(); 59 | } 60 | 61 | #define gicv3_read_typer(c) readq(c) 62 | 63 | #endif /* !__ASSEMBLY__ */ 64 | #endif /* _ASMARM64_ARCH_GICV3_H_ */ 65 | -------------------------------------------------------------------------------- /lib/arm64/asm/barrier.h: -------------------------------------------------------------------------------- 1 | #ifndef _ASMARM64_BARRIER_H_ 2 | #define _ASMARM64_BARRIER_H_ 3 | /* 4 | * From Linux arch/arm64/include/asm/barrier.h 5 | * 6 | * Copyright (C) 2017, Red Hat Inc, Andrew Jones 7 | * 8 | * This work is licensed under the terms of the GNU GPL, version 2. 9 | */ 10 | 11 | #define sev() asm volatile("sev" : : : "memory") 12 | #define wfe() asm volatile("wfe" : : : "memory") 13 | #define wfi() asm volatile("wfi" : : : "memory") 14 | #define yield() asm volatile("yield" : : : "memory") 15 | #define cpu_relax() yield() 16 | 17 | #define isb() asm volatile("isb" : : : "memory") 18 | #define dmb(opt) asm volatile("dmb " #opt : : : "memory") 19 | #define dsb(opt) asm volatile("dsb " #opt : : : "memory") 20 | #define mb() dsb(sy) 21 | #define rmb() dsb(ld) 22 | #define wmb() dsb(st) 23 | #define smp_mb() dmb(ish) 24 | #define smp_rmb() dmb(ishld) 25 | #define smp_wmb() dmb(ishst) 26 | 27 | #endif /* _ASMARM64_BARRIER_H_ */ 28 | -------------------------------------------------------------------------------- /lib/arm64/asm/bitops.h: -------------------------------------------------------------------------------- 1 | #ifndef _ASMARM64_BITOPS_H_ 2 | #define _ASMARM64_BITOPS_H_ 3 | /* 4 | * Adapted from 5 | * arch/arm64/lib/bitops.S 6 | * 7 | * Copyright (C) 2017, Red Hat Inc, Andrew Jones 8 | * 9 | * This work is licensed under the terms of the GNU GPL, version 2. 10 | */ 11 | 12 | #ifndef _BITOPS_H_ 13 | #error only can be included directly 14 | #endif 15 | 16 | #define BITS_PER_LONG 64 17 | 18 | #define HAVE_BUILTIN_FLS 1 19 | 20 | #define ATOMIC_BITOP(insn, mask, word) \ 21 | ({ \ 22 | unsigned long tmp1, tmp2; \ 23 | asm volatile( \ 24 | "1: ldxr %0, [%2]\n" \ 25 | insn" %0, %0, %3\n" \ 26 | " stxr %w1, %0, [%2]\n" \ 27 | " cbnz %w1, 1b\n" \ 28 | : "=&r" (tmp1), "=&r" (tmp2) \ 29 | : "r" (word), "r" (mask) \ 30 | : "cc"); \ 31 | }) 32 | 33 | #define ATOMIC_TESTOP(insn, mask, word, old) \ 34 | ({ \ 35 | unsigned long tmp1, tmp2; \ 36 | asm volatile( \ 37 | "1: ldxr %0, [%3]\n" \ 38 | " and %1, %0, %4\n" \ 39 | insn" %0, %0, %4\n" \ 40 | " stlxr %w2, %0, [%3]\n" \ 41 | " cbnz %w2, 1b\n" \ 42 | : "=&r" (tmp1), "=&r" (old), "=&r" (tmp2) \ 43 | : "r" (word), "r" (mask) \ 44 | : "cc"); \ 45 | }) 46 | 47 | extern void set_bit(int nr, volatile unsigned long *addr); 48 | extern void clear_bit(int nr, volatile unsigned long *addr); 49 | extern int test_bit(int nr, const volatile unsigned long *addr); 50 | extern int test_and_set_bit(int nr, volatile unsigned long *addr); 51 | extern int test_and_clear_bit(int nr, volatile unsigned long *addr); 52 | 53 | #endif /* _ASMARM64_BITOPS_H_ */ 54 | -------------------------------------------------------------------------------- /lib/arm64/asm/cpumask.h: -------------------------------------------------------------------------------- 1 | #include "../../arm/asm/cpumask.h" 2 | -------------------------------------------------------------------------------- /lib/arm64/asm/delay.h: -------------------------------------------------------------------------------- 1 | #include "../../arm/asm/delay.h" 2 | -------------------------------------------------------------------------------- /lib/arm64/asm/esr.h: -------------------------------------------------------------------------------- 1 | /* 2 | * From Linux kernel arch/arm64/include/asm/esr.h 3 | * 4 | * Copyright (C) 2017, Red Hat Inc, Andrew Jones 5 | * 6 | * This work is licensed under the terms of the GNU GPL, version 2. 7 | */ 8 | #ifndef _ASMARM64_ESR_H_ 9 | #define _ASMARM64_ESR_H_ 10 | 11 | #define ESR_EL1_WRITE (1 << 6) 12 | #define ESR_EL1_CM (1 << 8) 13 | #define ESR_EL1_IL (1 << 25) 14 | 15 | #define ESR_EL1_EC_SHIFT (26) 16 | #define ESR_EL1_EC_UNKNOWN (0x00) 17 | #define ESR_EL1_EC_WFI (0x01) 18 | #define ESR_EL1_EC_CP15_32 (0x03) 19 | #define ESR_EL1_EC_CP15_64 (0x04) 20 | #define ESR_EL1_EC_CP14_MR (0x05) 21 | #define ESR_EL1_EC_CP14_LS (0x06) 22 | #define ESR_EL1_EC_FP_ASIMD (0x07) 23 | #define ESR_EL1_EC_CP10_ID (0x08) 24 | #define ESR_EL1_EC_CP14_64 (0x0C) 25 | #define ESR_EL1_EC_ILL_ISS (0x0E) 26 | #define ESR_EL1_EC_SVC32 (0x11) 27 | #define ESR_EL1_EC_SVC64 (0x15) 28 | #define ESR_EL1_EC_SYS64 (0x18) 29 | #define ESR_EL1_EC_IABT_EL0 (0x20) 30 | #define ESR_EL1_EC_IABT_EL1 (0x21) 31 | #define ESR_EL1_EC_PC_ALIGN (0x22) 32 | #define ESR_EL1_EC_DABT_EL0 (0x24) 33 | #define ESR_EL1_EC_DABT_EL1 (0x25) 34 | #define ESR_EL1_EC_SP_ALIGN (0x26) 35 | #define ESR_EL1_EC_FP_EXC32 (0x28) 36 | #define ESR_EL1_EC_FP_EXC64 (0x2C) 37 | #define ESR_EL1_EC_SERROR (0x2F) 38 | #define ESR_EL1_EC_BREAKPT_EL0 (0x30) 39 | #define ESR_EL1_EC_BREAKPT_EL1 (0x31) 40 | #define ESR_EL1_EC_SOFTSTP_EL0 (0x32) 41 | #define ESR_EL1_EC_SOFTSTP_EL1 (0x33) 42 | #define ESR_EL1_EC_WATCHPT_EL0 (0x34) 43 | #define ESR_EL1_EC_WATCHPT_EL1 (0x35) 44 | #define ESR_EL1_EC_BKPT32 (0x38) 45 | #define ESR_EL1_EC_BRK64 (0x3C) 46 | 47 | #endif /* _ASMARM64_ESR_H_ */ 48 | -------------------------------------------------------------------------------- /lib/arm64/asm/gic-v2.h: -------------------------------------------------------------------------------- 1 | #include "../../arm/asm/gic-v2.h" 2 | -------------------------------------------------------------------------------- /lib/arm64/asm/gic-v3.h: -------------------------------------------------------------------------------- 1 | #include "../../arm/asm/gic-v3.h" 2 | -------------------------------------------------------------------------------- /lib/arm64/asm/gic.h: -------------------------------------------------------------------------------- 1 | #include "../../arm/asm/gic.h" 2 | -------------------------------------------------------------------------------- /lib/arm64/asm/io.h: -------------------------------------------------------------------------------- 1 | #ifndef _ASMARM64_IO_H_ 2 | #define _ASMARM64_IO_H_ 3 | /* 4 | * From Linux arch/arm64/include/asm/io.h 5 | * Generic IO read/write. These perform native-endian accesses. 6 | * 7 | * Copyright (C) 2017, Red Hat Inc, Andrew Jones 8 | * 9 | * This work is licensed under the terms of the GNU GPL, version 2. 10 | */ 11 | #include 12 | #include 13 | #include 14 | 15 | #define __iomem 16 | #define __force 17 | 18 | #define __raw_writeb __raw_writeb 19 | static inline void __raw_writeb(u8 val, volatile void __iomem *addr) 20 | { 21 | asm volatile("strb %w0, [%1]" : : "r" (val), "r" (addr)); 22 | } 23 | 24 | #define __raw_writew __raw_writew 25 | static inline void __raw_writew(u16 val, volatile void __iomem *addr) 26 | { 27 | asm volatile("strh %w0, [%1]" : : "r" (val), "r" (addr)); 28 | } 29 | 30 | #define __raw_writel __raw_writel 31 | static inline void __raw_writel(u32 val, volatile void __iomem *addr) 32 | { 33 | asm volatile("str %w0, [%1]" : : "r" (val), "r" (addr)); 34 | } 35 | 36 | #define __raw_writeq __raw_writeq 37 | static inline void __raw_writeq(u64 val, volatile void __iomem *addr) 38 | { 39 | asm volatile("str %0, [%1]" : : "r" (val), "r" (addr)); 40 | } 41 | 42 | #define __raw_readb __raw_readb 43 | static inline u8 __raw_readb(const volatile void __iomem *addr) 44 | { 45 | u8 val; 46 | asm volatile("ldrb %w0, [%1]" : "=r" (val) : "r" (addr)); 47 | return val; 48 | } 49 | 50 | #define __raw_readw __raw_readw 51 | static inline u16 __raw_readw(const volatile void __iomem *addr) 52 | { 53 | u16 val; 54 | asm volatile("ldrh %w0, [%1]" : "=r" (val) : "r" (addr)); 55 | return val; 56 | } 57 | 58 | #define __raw_readl __raw_readl 59 | static inline u32 __raw_readl(const volatile void __iomem *addr) 60 | { 61 | u32 val; 62 | asm volatile("ldr %w0, [%1]" : "=r" (val) : "r" (addr)); 63 | return val; 64 | } 65 | 66 | #define __raw_readq __raw_readq 67 | static inline u64 __raw_readq(const volatile void __iomem *addr) 68 | { 69 | u64 val; 70 | asm volatile("ldr %0, [%1]" : "=r" (val) : "r" (addr)); 71 | return val; 72 | } 73 | 74 | #define virt_to_phys virt_to_phys 75 | static inline phys_addr_t virt_to_phys(const volatile void *x) 76 | { 77 | return __virt_to_phys((unsigned long)(x)); 78 | } 79 | 80 | #define phys_to_virt phys_to_virt 81 | static inline void *phys_to_virt(phys_addr_t x) 82 | { 83 | return (void *)__phys_to_virt(x); 84 | } 85 | 86 | #include 87 | 88 | #endif /* _ASMARM64_IO_H_ */ 89 | -------------------------------------------------------------------------------- /lib/arm64/asm/mmu-api.h: -------------------------------------------------------------------------------- 1 | #include "../../arm/asm/mmu-api.h" 2 | -------------------------------------------------------------------------------- /lib/arm64/asm/mmu.h: -------------------------------------------------------------------------------- 1 | #ifndef __ASMARM64_MMU_H_ 2 | #define __ASMARM64_MMU_H_ 3 | /* 4 | * Copyright (C) 2014, Red Hat Inc, Andrew Jones 5 | * 6 | * This work is licensed under the terms of the GNU LGPL, version 2. 7 | */ 8 | #include 9 | 10 | #define PMD_SECT_UNCACHED PMD_ATTRINDX(MT_DEVICE_nGnRE) 11 | #define PTE_WBWA PTE_ATTRINDX(MT_NORMAL) 12 | 13 | static inline void flush_tlb_all(void) 14 | { 15 | dsb(ishst); 16 | asm("tlbi vmalle1is"); 17 | dsb(ish); 18 | isb(); 19 | } 20 | 21 | static inline void flush_tlb_page(unsigned long vaddr) 22 | { 23 | unsigned long page = vaddr >> 12; 24 | dsb(ishst); 25 | asm("tlbi vaae1is, %0" :: "r" (page)); 26 | dsb(ish); 27 | } 28 | 29 | static inline void flush_dcache_addr(unsigned long vaddr) 30 | { 31 | asm volatile("dc civac, %0" :: "r" (vaddr)); 32 | } 33 | 34 | #include 35 | 36 | #endif /* __ASMARM64_MMU_H_ */ 37 | -------------------------------------------------------------------------------- /lib/arm64/asm/page.h: -------------------------------------------------------------------------------- 1 | #ifndef _ASMARM64_PAGE_H_ 2 | #define _ASMARM64_PAGE_H_ 3 | /* 4 | * Adapted from 5 | * arch/arm64/include/asm/pgtable-types.h 6 | * include/asm-generic/pgtable-nopmd.h 7 | * 8 | * Copyright (C) 2017, Red Hat Inc, Andrew Jones 9 | * 10 | * This work is licensed under the terms of the GNU GPL, version 2. 11 | */ 12 | 13 | #include 14 | 15 | #define PGTABLE_LEVELS 2 16 | #define VA_BITS 42 17 | 18 | #define PAGE_SHIFT 16 19 | #define PAGE_SIZE (_AC(1,UL) << PAGE_SHIFT) 20 | #define PAGE_MASK (~(PAGE_SIZE-1)) 21 | 22 | #ifndef __ASSEMBLY__ 23 | 24 | #define PAGE_ALIGN(addr) ALIGN(addr, PAGE_SIZE) 25 | 26 | typedef u64 pteval_t; 27 | typedef u64 pmdval_t; 28 | typedef u64 pgdval_t; 29 | typedef struct { pteval_t pte; } pte_t; 30 | typedef struct { pgdval_t pgd; } pgd_t; 31 | typedef struct { pteval_t pgprot; } pgprot_t; 32 | 33 | #define pte_val(x) ((x).pte) 34 | #define pgd_val(x) ((x).pgd) 35 | #define pgprot_val(x) ((x).pgprot) 36 | 37 | #define __pte(x) ((pte_t) { (x) } ) 38 | #define __pgd(x) ((pgd_t) { (x) } ) 39 | #define __pgprot(x) ((pgprot_t) { (x) } ) 40 | 41 | typedef struct { pgd_t pgd; } pmd_t; 42 | #define pmd_val(x) (pgd_val((x).pgd)) 43 | #define __pmd(x) ((pmd_t) { __pgd(x) } ) 44 | 45 | #define __va(x) ((void *)__phys_to_virt((phys_addr_t)(x))) 46 | #define __pa(x) __virt_to_phys((unsigned long)(x)) 47 | 48 | #define virt_to_pfn(kaddr) (__pa(kaddr) >> PAGE_SHIFT) 49 | #define pfn_to_virt(pfn) __va((pfn) << PAGE_SHIFT) 50 | 51 | extern phys_addr_t __virt_to_phys(unsigned long addr); 52 | extern unsigned long __phys_to_virt(phys_addr_t addr); 53 | 54 | #endif /* !__ASSEMBLY__ */ 55 | #endif /* _ASMARM64_PAGE_H_ */ 56 | -------------------------------------------------------------------------------- /lib/arm64/asm/pci.h: -------------------------------------------------------------------------------- 1 | #include "../../arm/asm/pci.h" 2 | -------------------------------------------------------------------------------- /lib/arm64/asm/pgtable.h: -------------------------------------------------------------------------------- 1 | #ifndef _ASMARM64_PGTABLE_H_ 2 | #define _ASMARM64_PGTABLE_H_ 3 | /* 4 | * Adapted from arch/arm64/include/asm/pgtable.h 5 | * include/asm-generic/pgtable-nopmd.h 6 | * include/linux/mm.h 7 | * 8 | * Note: some Linux function APIs have been modified. Nothing crazy, 9 | * but if a function took, for example, an mm_struct, then 10 | * that was either removed or replaced. 11 | * 12 | * Copyright (C) 2017, Red Hat Inc, Andrew Jones 13 | * 14 | * This work is licensed under the terms of the GNU GPL, version 2. 15 | */ 16 | #include 17 | #include 18 | #include 19 | #include 20 | 21 | /* 22 | * We can convert va <=> pa page table addresses with simple casts 23 | * because we always allocate their pages with alloc_page(), and 24 | * alloc_page() always returns identity mapped pages. 25 | */ 26 | #define pgtable_va(x) ((void *)(unsigned long)(x)) 27 | #define pgtable_pa(x) ((unsigned long)(x)) 28 | 29 | #define pgd_none(pgd) (!pgd_val(pgd)) 30 | #define pmd_none(pmd) (!pmd_val(pmd)) 31 | #define pte_none(pte) (!pte_val(pte)) 32 | 33 | #define pgd_index(addr) \ 34 | (((addr) >> PGDIR_SHIFT) & (PTRS_PER_PGD - 1)) 35 | #define pgd_offset(pgtable, addr) ((pgtable) + pgd_index(addr)) 36 | 37 | #define pgd_free(pgd) free(pgd) 38 | static inline pgd_t *pgd_alloc(void) 39 | { 40 | pgd_t *pgd = memalign(PAGE_SIZE, PTRS_PER_PGD * sizeof(pgd_t)); 41 | memset(pgd, 0, PTRS_PER_PGD * sizeof(pgd_t)); 42 | return pgd; 43 | } 44 | 45 | #define pmd_offset(pgd, addr) ((pmd_t *)pgd) 46 | #define pmd_free(pmd) 47 | #define pmd_alloc(pgd, addr) pmd_offset(pgd, addr) 48 | 49 | static inline pte_t *pmd_page_vaddr(pmd_t pmd) 50 | { 51 | return pgtable_va(pmd_val(pmd) & PHYS_MASK & (s32)PAGE_MASK); 52 | } 53 | 54 | #define pte_index(addr) \ 55 | (((addr) >> PAGE_SHIFT) & (PTRS_PER_PTE - 1)) 56 | #define pte_offset(pmd, addr) \ 57 | (pmd_page_vaddr(*(pmd)) + pte_index(addr)) 58 | 59 | #define pte_free(pte) free_page(pte) 60 | static inline pte_t *pte_alloc_one(void) 61 | { 62 | assert(PTRS_PER_PTE * sizeof(pte_t) == PAGE_SIZE); 63 | pte_t *pte = alloc_page(); 64 | memset(pte, 0, PTRS_PER_PTE * sizeof(pte_t)); 65 | return pte; 66 | } 67 | static inline pte_t *pte_alloc(pmd_t *pmd, unsigned long addr) 68 | { 69 | if (pmd_none(*pmd)) { 70 | pte_t *pte = pte_alloc_one(); 71 | pmd_val(*pmd) = pgtable_pa(pte) | PMD_TYPE_TABLE; 72 | } 73 | return pte_offset(pmd, addr); 74 | } 75 | 76 | #endif /* _ASMARM64_PGTABLE_H_ */ 77 | -------------------------------------------------------------------------------- /lib/arm64/asm/processor.h: -------------------------------------------------------------------------------- 1 | #ifndef _ASMARM64_PROCESSOR_H_ 2 | #define _ASMARM64_PROCESSOR_H_ 3 | /* 4 | * Copyright (C) 2014, Red Hat Inc, Andrew Jones 5 | * 6 | * This work is licensed under the terms of the GNU LGPL, version 2. 7 | */ 8 | 9 | /* System Control Register (SCTLR_EL1) bits */ 10 | #define SCTLR_EL1_EE (1 << 25) 11 | #define SCTLR_EL1_WXN (1 << 19) 12 | #define SCTLR_EL1_I (1 << 12) 13 | #define SCTLR_EL1_SA0 (1 << 4) 14 | #define SCTLR_EL1_SA (1 << 3) 15 | #define SCTLR_EL1_C (1 << 2) 16 | #define SCTLR_EL1_A (1 << 1) 17 | #define SCTLR_EL1_M (1 << 0) 18 | 19 | #ifndef __ASSEMBLY__ 20 | #include 21 | #include 22 | #include 23 | #include 24 | 25 | enum vector { 26 | EL1T_SYNC, 27 | EL1T_IRQ, 28 | EL1T_FIQ, 29 | EL1T_ERROR, 30 | EL1H_SYNC, 31 | EL1H_IRQ, 32 | EL1H_FIQ, 33 | EL1H_ERROR, 34 | EL0_SYNC_64, 35 | EL0_IRQ_64, 36 | EL0_FIQ_64, 37 | EL0_ERROR_64, 38 | EL0_SYNC_32, 39 | EL0_IRQ_32, 40 | EL0_FIQ_32, 41 | EL0_ERROR_32, 42 | VECTOR_MAX, 43 | }; 44 | 45 | #define EC_MAX 64 46 | 47 | typedef void (*vector_fn)(enum vector v, struct pt_regs *regs, 48 | unsigned int esr); 49 | typedef void (*exception_fn)(struct pt_regs *regs, unsigned int esr); 50 | typedef void (*irq_handler_fn)(struct pt_regs *regs); 51 | extern void install_vector_handler(enum vector v, vector_fn fn); 52 | extern void install_exception_handler(enum vector v, unsigned int ec, 53 | exception_fn fn); 54 | extern void install_irq_handler(enum vector v, irq_handler_fn fn); 55 | extern void default_vector_sync_handler(enum vector v, struct pt_regs *regs, 56 | unsigned int esr); 57 | extern void default_vector_irq_handler(enum vector v, struct pt_regs *regs, 58 | unsigned int esr); 59 | extern void vector_handlers_default_init(vector_fn *handlers); 60 | 61 | extern void show_regs(struct pt_regs *regs); 62 | extern bool get_far(unsigned int esr, unsigned long *far); 63 | 64 | static inline unsigned long current_level(void) 65 | { 66 | unsigned long el; 67 | asm volatile("mrs %0, CurrentEL" : "=r" (el)); 68 | return el & 0xc; 69 | } 70 | 71 | static inline void local_irq_enable(void) 72 | { 73 | asm volatile("msr daifclr, #2" : : : "memory"); 74 | } 75 | 76 | static inline void local_irq_disable(void) 77 | { 78 | asm volatile("msr daifset, #2" : : : "memory"); 79 | } 80 | 81 | static inline uint64_t get_mpidr(void) 82 | { 83 | return read_sysreg(mpidr_el1); 84 | } 85 | 86 | #define MPIDR_HWID_BITMASK 0xff00ffffff 87 | extern int mpidr_to_cpu(uint64_t mpidr); 88 | 89 | #define MPIDR_LEVEL_SHIFT(level) \ 90 | (((1 << level) >> 1) << 3) 91 | #define MPIDR_AFFINITY_LEVEL(mpidr, level) \ 92 | ((mpidr >> MPIDR_LEVEL_SHIFT(level)) & 0xff) 93 | 94 | extern void start_usr(void (*func)(void *arg), void *arg, unsigned long sp_usr); 95 | extern bool is_user(void); 96 | 97 | static inline u64 get_cntvct(void) 98 | { 99 | isb(); 100 | return read_sysreg(cntvct_el0); 101 | } 102 | 103 | static inline u32 get_cntfrq(void) 104 | { 105 | return read_sysreg(cntfrq_el0); 106 | } 107 | 108 | #endif /* !__ASSEMBLY__ */ 109 | #endif /* _ASMARM64_PROCESSOR_H_ */ 110 | -------------------------------------------------------------------------------- /lib/arm64/asm/psci.h: -------------------------------------------------------------------------------- 1 | #include "../../arm/asm/psci.h" 2 | -------------------------------------------------------------------------------- /lib/arm64/asm/ptrace.h: -------------------------------------------------------------------------------- 1 | #ifndef _ASMARM64_PTRACE_H_ 2 | #define _ASMARM64_PTRACE_H_ 3 | /* 4 | * Adapted from Linux kernel headers 5 | * arch/arm64/include/asm/ptrace.h 6 | * arch/arm64/include/uapi/asm/ptrace.h 7 | * 8 | * Copyright (C) 2017, Red Hat Inc, Andrew Jones 9 | * 10 | * This work is licensed under the terms of the GNU GPL, version 2. 11 | */ 12 | 13 | /* Current Exception Level values, as contained in CurrentEL */ 14 | #define CurrentEL_EL1 (1 << 2) 15 | #define CurrentEL_EL2 (2 << 2) 16 | 17 | /* 18 | * PSR bits 19 | */ 20 | #define PSR_MODE_EL0t 0x00000000 21 | #define PSR_MODE_EL1t 0x00000004 22 | #define PSR_MODE_EL1h 0x00000005 23 | #define PSR_MODE_EL2t 0x00000008 24 | #define PSR_MODE_EL2h 0x00000009 25 | #define PSR_MODE_EL3t 0x0000000c 26 | #define PSR_MODE_EL3h 0x0000000d 27 | #define PSR_MODE_MASK 0x0000000f 28 | 29 | /* AArch32 CPSR bits */ 30 | #define PSR_MODE32_BIT 0x00000010 31 | 32 | /* AArch64 SPSR bits */ 33 | #define PSR_F_BIT 0x00000040 34 | #define PSR_I_BIT 0x00000080 35 | #define PSR_A_BIT 0x00000100 36 | #define PSR_D_BIT 0x00000200 37 | #define PSR_Q_BIT 0x08000000 38 | #define PSR_V_BIT 0x10000000 39 | #define PSR_C_BIT 0x20000000 40 | #define PSR_Z_BIT 0x40000000 41 | #define PSR_N_BIT 0x80000000 42 | 43 | /* 44 | * Groups of PSR bits 45 | */ 46 | #define PSR_f 0xff000000 /* Flags */ 47 | #define PSR_s 0x00ff0000 /* Status */ 48 | #define PSR_x 0x0000ff00 /* Extension */ 49 | #define PSR_c 0x000000ff /* Control */ 50 | 51 | #ifndef __ASSEMBLY__ 52 | #include 53 | 54 | struct user_pt_regs { 55 | u64 regs[31]; 56 | u64 sp; 57 | u64 pc; 58 | u64 pstate; 59 | }; 60 | 61 | struct user_fpsimd_state { 62 | __uint128_t vregs[32]; 63 | u32 fpsr; 64 | u32 fpcr; 65 | }; 66 | 67 | /* 68 | * This struct defines the way the registers are stored on the stack during an 69 | * exception. Note that sizeof(struct pt_regs) has to be a multiple of 16 (for 70 | * stack alignment). struct user_pt_regs must form a prefix of struct pt_regs. 71 | */ 72 | struct pt_regs { 73 | union { 74 | struct user_pt_regs user_regs; 75 | struct { 76 | u64 regs[31]; 77 | u64 sp; 78 | u64 pc; 79 | u64 pstate; 80 | }; 81 | }; 82 | u64 orig_x0; 83 | u64 syscallno; 84 | }; 85 | 86 | #define user_mode(regs) \ 87 | (((regs)->pstate & PSR_MODE_MASK) == PSR_MODE_EL0t) 88 | 89 | #define processor_mode(regs) \ 90 | ((regs)->pstate & PSR_MODE_MASK) 91 | 92 | #define interrupts_enabled(regs) \ 93 | (!((regs)->pstate & PSR_I_BIT)) 94 | 95 | #define fast_interrupts_enabled(regs) \ 96 | (!((regs)->pstate & PSR_F_BIT)) 97 | 98 | #endif /* !__ASSEMBLY__ */ 99 | #endif /* _ASMARM64_PTRACE_H_ */ 100 | -------------------------------------------------------------------------------- /lib/arm64/asm/setup.h: -------------------------------------------------------------------------------- 1 | #include "../../arm/asm/setup.h" 2 | -------------------------------------------------------------------------------- /lib/arm64/asm/smp.h: -------------------------------------------------------------------------------- 1 | #include "../../arm/asm/smp.h" 2 | -------------------------------------------------------------------------------- /lib/arm64/asm/spinlock.h: -------------------------------------------------------------------------------- 1 | #ifndef _ASMARM64_SPINLOCK_H_ 2 | #define _ASMARM64_SPINLOCK_H_ 3 | 4 | struct spinlock { 5 | int v; 6 | }; 7 | 8 | extern void spin_lock(struct spinlock *lock); 9 | extern void spin_unlock(struct spinlock *lock); 10 | 11 | #endif /* _ASMARM64_SPINLOCK_H_ */ 12 | -------------------------------------------------------------------------------- /lib/arm64/asm/stack.h: -------------------------------------------------------------------------------- 1 | #ifndef _ASMARM64_STACK_H_ 2 | #define _ASMARM64_STACK_H_ 3 | 4 | #ifndef _STACK_H_ 5 | #error Do not directly include . Just use . 6 | #endif 7 | 8 | #endif 9 | -------------------------------------------------------------------------------- /lib/arm64/asm/sysreg.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Ripped off from arch/arm64/include/asm/sysreg.h 3 | * 4 | * Copyright (C) 2016, Red Hat Inc, Andrew Jones 5 | * 6 | * This work is licensed under the terms of the GNU LGPL, version 2. 7 | */ 8 | #ifndef _ASMARM64_SYSREG_H_ 9 | #define _ASMARM64_SYSREG_H_ 10 | 11 | #define sys_reg(op0, op1, crn, crm, op2) \ 12 | ((((op0)&3)<<19)|((op1)<<16)|((crn)<<12)|((crm)<<8)|((op2)<<5)) 13 | 14 | #ifdef __ASSEMBLY__ 15 | .irp num,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30 16 | .equ .L__reg_num_x\num, \num 17 | .endr 18 | .equ .L__reg_num_xzr, 31 19 | 20 | .macro mrs_s, rt, sreg 21 | .inst 0xd5200000|(\sreg)|(.L__reg_num_\rt) 22 | .endm 23 | 24 | .macro msr_s, sreg, rt 25 | .inst 0xd5000000|(\sreg)|(.L__reg_num_\rt) 26 | .endm 27 | #else 28 | #include 29 | 30 | #define read_sysreg(r) ({ \ 31 | u64 __val; \ 32 | asm volatile("mrs %0, " xstr(r) : "=r" (__val)); \ 33 | __val; \ 34 | }) 35 | 36 | #define write_sysreg(v, r) do { \ 37 | u64 __val = (u64)v; \ 38 | asm volatile("msr " xstr(r) ", %x0" : : "rZ" (__val)); \ 39 | } while (0) 40 | 41 | asm( 42 | " .irp num,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30\n" 43 | " .equ .L__reg_num_x\\num, \\num\n" 44 | " .endr\n" 45 | " .equ .L__reg_num_xzr, 31\n" 46 | "\n" 47 | " .macro mrs_s, rt, sreg\n" 48 | " .inst 0xd5200000|(\\sreg)|(.L__reg_num_\\rt)\n" 49 | " .endm\n" 50 | "\n" 51 | " .macro msr_s, sreg, rt\n" 52 | " .inst 0xd5000000|(\\sreg)|(.L__reg_num_\\rt)\n" 53 | " .endm\n" 54 | ); 55 | #endif /* __ASSEMBLY__ */ 56 | #endif /* _ASMARM64_SYSREG_H_ */ 57 | -------------------------------------------------------------------------------- /lib/arm64/asm/thread_info.h: -------------------------------------------------------------------------------- 1 | #include "../../arm/asm/thread_info.h" 2 | -------------------------------------------------------------------------------- /lib/arm64/spinlock.c: -------------------------------------------------------------------------------- 1 | /* 2 | * spinlocks 3 | * 4 | * Copyright (C) 2015, Red Hat Inc, Andrew Jones 5 | * 6 | * This work is licensed under the terms of the GNU LGPL, version 2. 7 | */ 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | void spin_lock(struct spinlock *lock) 14 | { 15 | u32 val, fail; 16 | 17 | if (!mmu_enabled()) { 18 | lock->v = 1; 19 | smp_mb(); 20 | return; 21 | } 22 | 23 | do { 24 | asm volatile( 25 | "1: ldaxr %w0, [%2]\n" 26 | " cbnz %w0, 1b\n" 27 | " mov %0, #1\n" 28 | " stxr %w1, %w0, [%2]\n" 29 | : "=&r" (val), "=&r" (fail) 30 | : "r" (&lock->v) 31 | : "cc" ); 32 | } while (fail); 33 | smp_mb(); 34 | } 35 | 36 | void spin_unlock(struct spinlock *lock) 37 | { 38 | smp_mb(); 39 | if (mmu_enabled()) 40 | asm volatile("stlrh wzr, [%0]" :: "r" (&lock->v)); 41 | else 42 | lock->v = 0; 43 | } 44 | -------------------------------------------------------------------------------- /lib/asm-generic/atomic.h: -------------------------------------------------------------------------------- 1 | #ifndef __ASM_GENERIC_ATOMIC_H__ 2 | #define __ASM_GENERIC_ATOMIC_H__ 3 | 4 | /* From QEMU include/qemu/atomic.h */ 5 | #define atomic_fetch_inc(ptr) __sync_fetch_and_add(ptr, 1) 6 | #define atomic_fetch_dec(ptr) __sync_fetch_and_add(ptr, -1) 7 | #define atomic_fetch_add(ptr, n) __sync_fetch_and_add(ptr, n) 8 | #define atomic_fetch_sub(ptr, n) __sync_fetch_and_sub(ptr, n) 9 | #define atomic_fetch_and(ptr, n) __sync_fetch_and_and(ptr, n) 10 | #define atomic_fetch_or(ptr, n) __sync_fetch_and_or(ptr, n) 11 | #define atomic_fetch_xor(ptr, n) __sync_fetch_and_xor(ptr, n) 12 | 13 | #define atomic_inc_fetch(ptr) __sync_add_and_fetch(ptr, 1) 14 | #define atomic_dec_fetch(ptr) __sync_add_and_fetch(ptr, -1) 15 | #define atomic_add_fetch(ptr, n) __sync_add_and_fetch(ptr, n) 16 | #define atomic_sub_fetch(ptr, n) __sync_sub_and_fetch(ptr, n) 17 | #define atomic_and_fetch(ptr, n) __sync_and_and_fetch(ptr, n) 18 | #define atomic_or_fetch(ptr, n) __sync_or_and_fetch(ptr, n) 19 | #define atomic_xor_fetch(ptr, n) __sync_xor_and_fetch(ptr, n) 20 | 21 | #endif 22 | -------------------------------------------------------------------------------- /lib/asm-generic/barrier.h: -------------------------------------------------------------------------------- 1 | #ifndef _ASM_BARRIER_H_ 2 | #define _ASM_BARRIER_H_ 3 | /* 4 | * asm-generic/barrier.h 5 | * 6 | * Copyright (C) 2016, Red Hat Inc, Alexander Gordeev 7 | * 8 | * This work is licensed under the terms of the GNU LGPL, version 2. 9 | */ 10 | 11 | #ifndef mb 12 | #define mb() asm volatile("":::"memory") 13 | #endif 14 | #ifndef rmb 15 | #define rmb() asm volatile("":::"memory") 16 | #endif 17 | #ifndef wmb 18 | #define wmb() asm volatile("":::"memory") 19 | #endif 20 | 21 | #ifndef smp_mb 22 | #define smp_mb() mb() 23 | #endif 24 | #ifndef smp_rmb 25 | #define smp_rmb() rmb() 26 | #endif 27 | #ifndef smp_wmb 28 | #define smp_wmb() wmb() 29 | #endif 30 | 31 | #ifndef cpu_relax 32 | #define cpu_relax() asm volatile ("":::"memory") 33 | #endif 34 | 35 | #endif /* _ASM_BARRIER_H_ */ 36 | -------------------------------------------------------------------------------- /lib/asm-generic/page.h: -------------------------------------------------------------------------------- 1 | #ifndef _ASM_GENERIC_PAGE_H_ 2 | #define _ASM_GENERIC_PAGE_H_ 3 | /* 4 | * asm-generic/page.h 5 | * adapted from the Linux kernel's include/asm-generic/page.h 6 | * 7 | * Copyright (C) 2017, Red Hat Inc, Andrew Jones 8 | * 9 | * This work is licensed under the terms of the GNU GPL, version 2. 10 | */ 11 | 12 | #include 13 | 14 | #define PAGE_SHIFT 12 15 | #define PAGE_SIZE (_AC(1,UL) << PAGE_SHIFT) 16 | #define PAGE_MASK (~(PAGE_SIZE-1)) 17 | 18 | #ifndef __ASSEMBLY__ 19 | 20 | #define PAGE_ALIGN(addr) ALIGN(addr, PAGE_SIZE) 21 | 22 | #define __va(x) ((void *)((unsigned long) (x))) 23 | #define __pa(x) ((unsigned long) (x)) 24 | #define virt_to_pfn(kaddr) (__pa(kaddr) >> PAGE_SHIFT) 25 | #define pfn_to_virt(pfn) __va((pfn) << PAGE_SHIFT) 26 | 27 | #endif /* !__ASSEMBLY__ */ 28 | 29 | #endif /* _ASM_GENERIC_PAGE_H_ */ 30 | -------------------------------------------------------------------------------- /lib/asm-generic/pci-host-bridge.h: -------------------------------------------------------------------------------- 1 | #ifndef _ASM_PCI_HOST_BRIDGE_H_ 2 | #define _ASM_PCI_HOST_BRIDGE_H_ 3 | /* 4 | * Copyright (C) 2016, Red Hat Inc, Alexander Gordeev 5 | * 6 | * This work is licensed under the terms of the GNU LGPL, version 2. 7 | */ 8 | #include "libcflat.h" 9 | 10 | phys_addr_t pci_host_bridge_get_paddr(uint64_t addr); 11 | 12 | static inline 13 | phys_addr_t pci_translate_addr(pcidevaddr_t dev __unused, uint64_t addr) 14 | { 15 | /* 16 | * Assume we only have single PCI host bridge in a system. 17 | */ 18 | return pci_host_bridge_get_paddr(addr); 19 | } 20 | 21 | uint8_t pci_config_readb(pcidevaddr_t dev, uint8_t reg); 22 | uint16_t pci_config_readw(pcidevaddr_t dev, uint8_t reg); 23 | uint32_t pci_config_readl(pcidevaddr_t dev, uint8_t reg); 24 | void pci_config_writeb(pcidevaddr_t dev, uint8_t reg, uint8_t val); 25 | void pci_config_writew(pcidevaddr_t dev, uint8_t reg, uint16_t val); 26 | void pci_config_writel(pcidevaddr_t dev, uint8_t reg, uint32_t val); 27 | 28 | #endif 29 | -------------------------------------------------------------------------------- /lib/asm-generic/pci.h: -------------------------------------------------------------------------------- 1 | #ifndef _ASM_GENERIC_PCI_H_ 2 | #define _ASM_GENERIC_PCI_H_ 3 | #error need architecture specific asm/pci.h 4 | #endif 5 | -------------------------------------------------------------------------------- /lib/asm-generic/spinlock.h: -------------------------------------------------------------------------------- 1 | #ifndef _ASM_GENERIC_SPINLOCK_H_ 2 | #define _ASM_GENERIC_SPINLOCK_H_ 3 | 4 | struct spinlock { 5 | unsigned int v; 6 | }; 7 | 8 | static inline void spin_lock(struct spinlock *lock) 9 | { 10 | while (__sync_lock_test_and_set(&lock->v, 1)); 11 | } 12 | 13 | static inline void spin_unlock(struct spinlock *lock) 14 | { 15 | __sync_lock_release(&lock->v); 16 | } 17 | 18 | #endif 19 | -------------------------------------------------------------------------------- /lib/auxinfo.c: -------------------------------------------------------------------------------- 1 | #include "auxinfo.h" 2 | 3 | #ifndef PROGNAME 4 | #define PROGNAME ((void *)0) 5 | #endif 6 | #ifndef AUXFLAGS 7 | #define AUXFLAGS 0 8 | #endif 9 | 10 | struct auxinfo auxinfo = { 11 | .progname = PROGNAME, 12 | .flags = AUXFLAGS, 13 | }; 14 | -------------------------------------------------------------------------------- /lib/auxinfo.h: -------------------------------------------------------------------------------- 1 | /* 2 | * This code is free software; you can redistribute it and/or modify it 3 | * under the terms of the GNU Library General Public License version 2. 4 | */ 5 | #ifndef _AUXINFO_H_ 6 | #define _AUXINFO_H_ 7 | 8 | #define AUXINFO_MMU_OFF (1 << 0) 9 | 10 | #ifndef __ASSEMBLY__ 11 | struct auxinfo { 12 | const char *progname; 13 | unsigned long flags; 14 | }; 15 | 16 | /* No extern! Define a common symbol. */ 17 | struct auxinfo auxinfo; 18 | #endif 19 | #endif 20 | -------------------------------------------------------------------------------- /lib/bitops.h: -------------------------------------------------------------------------------- 1 | #ifndef _BITOPS_H_ 2 | #define _BITOPS_H_ 3 | 4 | /* 5 | * Adapted from 6 | * include/linux/bitops.h 7 | * 8 | * Copyright (C) 2017, Red Hat Inc, Andrew Jones 9 | * 10 | * This work is licensed under the terms of the GNU GPL, version 2. 11 | */ 12 | 13 | #define BITS_PER_LONG_LONG 64 14 | #define BIT(nr) (1UL << (nr)) 15 | #define BIT_ULL(nr) (1ULL << (nr)) 16 | #define BIT_MASK(nr) (1UL << ((nr) % BITS_PER_LONG)) 17 | #define BIT_WORD(nr) ((nr) / BITS_PER_LONG) 18 | #define BIT_ULL_MASK(nr) (1ULL << ((nr) % BITS_PER_LONG_LONG)) 19 | #define BIT_ULL_WORD(nr) ((nr) / BITS_PER_LONG_LONG) 20 | #define BITS_PER_BYTE 8 21 | #define BITS_TO_LONGS(nr) DIV_ROUND_UP(nr, BITS_PER_BYTE * sizeof(long)) 22 | 23 | #include 24 | 25 | /* 26 | * Create a contiguous bitmask starting at bit position @l and ending at 27 | * position @h. For example 28 | * GENMASK_ULL(39, 21) gives us the 64bit vector 0x000000ffffe00000. 29 | */ 30 | #define GENMASK(h, l) \ 31 | (((~0UL) << (l)) & (~0UL >> (BITS_PER_LONG - 1 - (h)))) 32 | 33 | #define GENMASK_ULL(h, l) \ 34 | (((~0ULL) << (l)) & (~0ULL >> (BITS_PER_LONG_LONG - 1 - (h)))) 35 | 36 | #ifndef HAVE_BUILTIN_FLS 37 | static inline unsigned long fls(unsigned long word) 38 | { 39 | int num = BITS_PER_LONG - 1; 40 | 41 | #if BITS_PER_LONG == 64 42 | if (!(word & (~0ul << 32))) { 43 | num -= 32; 44 | word <<= 32; 45 | } 46 | #endif 47 | if (!(word & (~0ul << (BITS_PER_LONG-16)))) { 48 | num -= 16; 49 | word <<= 16; 50 | } 51 | if (!(word & (~0ul << (BITS_PER_LONG-8)))) { 52 | num -= 8; 53 | word <<= 8; 54 | } 55 | if (!(word & (~0ul << (BITS_PER_LONG-4)))) { 56 | num -= 4; 57 | word <<= 4; 58 | } 59 | if (!(word & (~0ul << (BITS_PER_LONG-2)))) { 60 | num -= 2; 61 | word <<= 2; 62 | } 63 | if (!(word & (~0ul << (BITS_PER_LONG-1)))) 64 | num -= 1; 65 | return num; 66 | } 67 | #else 68 | static inline unsigned long fls(unsigned long word) 69 | { 70 | return BITS_PER_LONG - __builtin_clzl(word) - 1; 71 | } 72 | #endif 73 | 74 | #endif 75 | -------------------------------------------------------------------------------- /lib/chr-testdev.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2014, Red Hat Inc, Andrew Jones 3 | * 4 | * This work is licensed under the terms of the GNU LGPL, version 2. 5 | */ 6 | #include "libcflat.h" 7 | #include "virtio.h" 8 | #include "asm/spinlock.h" 9 | 10 | #include "chr-testdev.h" 11 | 12 | #define TESTDEV_NAME "chr-testdev" 13 | 14 | static struct virtio_device *vcon; 15 | static struct virtqueue *in_vq, *out_vq; 16 | static struct spinlock lock; 17 | 18 | static void __testdev_send(char *buf, unsigned int len) 19 | { 20 | int ret; 21 | 22 | ret = virtqueue_add_outbuf(out_vq, buf, len); 23 | virtqueue_kick(out_vq); 24 | 25 | if (ret < 0) 26 | return; 27 | 28 | while (!virtqueue_get_buf(out_vq, &len)) 29 | ; 30 | } 31 | 32 | void chr_testdev_exit(int code) 33 | { 34 | unsigned int len; 35 | static char buf[8]; 36 | 37 | spin_lock(&lock); 38 | if (!vcon) 39 | goto out; 40 | 41 | snprintf(buf, sizeof(buf), "%dq", code); 42 | len = strlen(buf); 43 | 44 | __testdev_send(buf, len); 45 | 46 | out: 47 | spin_unlock(&lock); 48 | } 49 | 50 | void chr_testdev_init(void) 51 | { 52 | const char *io_names[] = { "input", "output" }; 53 | struct virtqueue *vqs[2]; 54 | int ret; 55 | 56 | vcon = virtio_bind(VIRTIO_ID_CONSOLE); 57 | if (vcon == NULL) { 58 | printf("%s: %s: can't find a virtio-console\n", 59 | __func__, TESTDEV_NAME); 60 | return; 61 | } 62 | 63 | ret = vcon->config->find_vqs(vcon, 2, vqs, NULL, io_names); 64 | if (ret < 0) { 65 | printf("%s: %s: can't init virtqueues\n", 66 | __func__, TESTDEV_NAME); 67 | vcon = NULL; 68 | return; 69 | } 70 | 71 | in_vq = vqs[0]; 72 | out_vq = vqs[1]; 73 | } 74 | -------------------------------------------------------------------------------- /lib/chr-testdev.h: -------------------------------------------------------------------------------- 1 | #ifndef _CHR_TESTDEV_H_ 2 | #define _CHR_TESTDEV_H_ 3 | /* 4 | * chr-testdev is a driver for the chr-testdev qemu backend. 5 | * The chr-testdev backend exposes a simple control interface to 6 | * qemu for kvm-unit-tests accessible through virtio-console. 7 | * 8 | * Copyright (C) 2014, Red Hat Inc, Andrew Jones 9 | * 10 | * This work is licensed under the terms of the GNU LGPL, version 2. 11 | */ 12 | extern void chr_testdev_init(void); 13 | extern void chr_testdev_exit(int code); 14 | #endif 15 | -------------------------------------------------------------------------------- /lib/elf.h: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0 2 | /* 3 | * ASOR Hypervisor. 4 | * 5 | * Author: Jie Deng 6 | */ 7 | 8 | #ifndef __ELF_H__ 9 | #define __ELF_H__ 10 | 11 | #include 12 | #include 13 | 14 | #define cacheflush(a1, a2, a3) __builtin___clear_cache(a1, a1 + a2) 15 | 16 | #if defined(X64) 17 | typedef Elf64_Ehdr Elf_Ehdr; 18 | typedef Elf64_Phdr Elf_Phdr; 19 | typedef Elf64_Sym Elf_Sym; 20 | typedef Elf64_Shdr Elf_Shdr; 21 | typedef Elf64_Rel Elf_Rel; 22 | typedef Elf64_Word Elf_Word; 23 | #define ELF_R_SYM(x) ELF64_R_SYM(x) 24 | #define ELF_R_TYPE(x) ELF64_R_TYPE(x) 25 | #else 26 | typedef Elf32_Ehdr Elf_Ehdr; 27 | typedef Elf32_Phdr Elf_Phdr; 28 | typedef Elf32_Sym Elf_Sym; 29 | typedef Elf32_Shdr Elf_Shdr; 30 | typedef Elf32_Rel Elf_Rel; 31 | typedef Elf32_Word Elf_Word; 32 | #define ELF_R_SYM(x) ELF32_R_SYM(x) 33 | #define ELF_R_TYPE(x) ELF32_R_TYPE(x) 34 | #endif 35 | 36 | #define STACK_SIZE (8*1024*1024) 37 | #define STACK_STORAGE_SIZE 0x5000 38 | #define STACK_STRING_SIZE 0x5000 39 | 40 | #define ROUND_UP(v, s) ((v + s - 1) & -s) 41 | #define ROUND_DOWN(v, s) (v & -s) 42 | 43 | /* Not all archs have this one defined */ 44 | #ifndef AT_RANDOM 45 | #define AT_RANDOM 25 46 | #endif 47 | 48 | struct ATENTRY { 49 | size_t id; 50 | size_t value; 51 | } __attribute__((packed)); 52 | 53 | void *elf_sym(void *elf_start, char *sym_name); 54 | 55 | /* 56 | * brief Map the ELF into memory. 57 | */ 58 | void elf_load(char *elf_start, void *stack, int stack_size, size_t *base_addr, size_t *entry); 59 | 60 | /* 61 | * brief Map the ELF into memory and run it with the provided arguments. 62 | */ 63 | void elf_run(void *buf, char **argv, char **env); 64 | 65 | #endif /* __ELF_H__ */ 66 | 67 | -------------------------------------------------------------------------------- /lib/errata.h: -------------------------------------------------------------------------------- 1 | /* 2 | * errata functions 3 | * 4 | * This code is free software; you can redistribute it and/or modify it 5 | * under the terms of the GNU Library General Public License version 2. 6 | */ 7 | #ifndef _ERRATA_H_ 8 | #define _ERRATA_H_ 9 | #include "config.h" 10 | 11 | #ifndef CONFIG_ERRATA_FORCE 12 | #define CONFIG_ERRATA_FORCE 0 13 | #endif 14 | 15 | #define _ERRATA(erratum) errata("ERRATA_" # erratum) 16 | #define ERRATA(erratum) _ERRATA(erratum) 17 | 18 | #define _ERRATA_RELAXED(erratum) errata_relaxed("ERRATA_" # erratum) 19 | #define ERRATA_RELAXED(erratum) _ERRATA_RELAXED(erratum) 20 | 21 | static inline bool errata_force(void) 22 | { 23 | char *s; 24 | 25 | if (CONFIG_ERRATA_FORCE == 1) 26 | return true; 27 | 28 | s = getenv("ERRATA_FORCE"); 29 | return s && (*s == '1' || *s == 'y' || *s == 'Y'); 30 | } 31 | 32 | static inline bool errata(const char *erratum) 33 | { 34 | char *s; 35 | 36 | if (errata_force()) 37 | return true; 38 | 39 | s = getenv(erratum); 40 | 41 | return s && (*s == '1' || *s == 'y' || *s == 'Y'); 42 | } 43 | 44 | static inline bool errata_relaxed(const char *erratum) 45 | { 46 | char *s; 47 | 48 | if (errata_force()) 49 | return true; 50 | 51 | s = getenv(erratum); 52 | 53 | return !(s && (*s == '0' || *s == 'n' || *s == 'N')); 54 | } 55 | 56 | #endif 57 | -------------------------------------------------------------------------------- /lib/getchar.c: -------------------------------------------------------------------------------- 1 | #include "libcflat.h" 2 | #include "asm/barrier.h" 3 | 4 | int getchar(void) 5 | { 6 | int c; 7 | 8 | while ((c = __getchar()) == -1) 9 | cpu_relax(); 10 | return c; 11 | } 12 | -------------------------------------------------------------------------------- /lib/kbuild.h: -------------------------------------------------------------------------------- 1 | #ifndef _KBUILD_H_ 2 | #define _KBUILD_H_ 3 | #define DEFINE(sym, val) \ 4 | asm volatile("\n->" #sym " %0 " #val : : "i" (val)) 5 | #define OFFSET(sym, str, mem) DEFINE(sym, offsetof(struct str, mem)) 6 | #define COMMENT(x) asm volatile("\n->#" x) 7 | #define BLANK() asm volatile("\n->" : : ) 8 | #endif 9 | -------------------------------------------------------------------------------- /lib/libfdt/Makefile.libfdt: -------------------------------------------------------------------------------- 1 | # Makefile.libfdt 2 | # 3 | # This is not a complete Makefile of itself. Instead, it is designed to 4 | # be easily embeddable into other systems of Makefiles. 5 | # 6 | LIBFDT_soname = libfdt.$(SHAREDLIB_EXT).1 7 | LIBFDT_INCLUDES = fdt.h libfdt.h libfdt_env.h 8 | LIBFDT_VERSION = version.lds 9 | LIBFDT_SRCS = fdt.c fdt_ro.c fdt_wip.c fdt_sw.c fdt_rw.c fdt_strerror.c fdt_empty_tree.c 10 | LIBFDT_OBJS = $(LIBFDT_SRCS:%.c=%.o) 11 | -------------------------------------------------------------------------------- /lib/libfdt/README: -------------------------------------------------------------------------------- 1 | 2 | The code in this directory is originally imported from the libfdt 3 | directory of git://git.jdl.com/software/dtc.git - version 1.4.0. 4 | 5 | -------------------------------------------------------------------------------- /lib/libfdt/fdt_empty_tree.c: -------------------------------------------------------------------------------- 1 | /* 2 | * libfdt - Flat Device Tree manipulation 3 | * Copyright (C) 2012 David Gibson, IBM Corporation. 4 | * 5 | * libfdt is dual licensed: you can use it either under the terms of 6 | * the GPL, or the BSD license, at your option. 7 | * 8 | * a) This library is free software; you can redistribute it and/or 9 | * modify it under the terms of the GNU General Public License as 10 | * published by the Free Software Foundation; either version 2 of the 11 | * License, or (at your option) any later version. 12 | * 13 | * This library is distributed in the hope that it will be useful, 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | * GNU General Public License for more details. 17 | * 18 | * You should have received a copy of the GNU General Public 19 | * License along with this library; if not, write to the Free 20 | * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, 21 | * MA 02110-1301 USA 22 | * 23 | * Alternatively, 24 | * 25 | * b) Redistribution and use in source and binary forms, with or 26 | * without modification, are permitted provided that the following 27 | * conditions are met: 28 | * 29 | * 1. Redistributions of source code must retain the above 30 | * copyright notice, this list of conditions and the following 31 | * disclaimer. 32 | * 2. Redistributions in binary form must reproduce the above 33 | * copyright notice, this list of conditions and the following 34 | * disclaimer in the documentation and/or other materials 35 | * provided with the distribution. 36 | * 37 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 38 | * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, 39 | * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 40 | * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 41 | * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR 42 | * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 43 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 44 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 45 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 46 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 47 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 48 | * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, 49 | * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 50 | */ 51 | #include "libfdt_env.h" 52 | 53 | #include 54 | #include 55 | 56 | #include "libfdt_internal.h" 57 | 58 | int fdt_create_empty_tree(void *buf, int bufsize) 59 | { 60 | int err; 61 | 62 | err = fdt_create(buf, bufsize); 63 | if (err) 64 | return err; 65 | 66 | err = fdt_finish_reservemap(buf); 67 | if (err) 68 | return err; 69 | 70 | err = fdt_begin_node(buf, ""); 71 | if (err) 72 | return err; 73 | 74 | err = fdt_end_node(buf); 75 | if (err) 76 | return err; 77 | 78 | err = fdt_finish(buf); 79 | if (err) 80 | return err; 81 | 82 | return fdt_open_into(buf, buf, bufsize); 83 | } 84 | 85 | -------------------------------------------------------------------------------- /lib/libfdt/version.lds: -------------------------------------------------------------------------------- 1 | LIBFDT_1.2 { 2 | global: 3 | fdt_next_node; 4 | fdt_check_header; 5 | fdt_move; 6 | fdt_string; 7 | fdt_num_mem_rsv; 8 | fdt_get_mem_rsv; 9 | fdt_subnode_offset_namelen; 10 | fdt_subnode_offset; 11 | fdt_path_offset; 12 | fdt_get_name; 13 | fdt_get_property_namelen; 14 | fdt_get_property; 15 | fdt_getprop_namelen; 16 | fdt_getprop; 17 | fdt_get_phandle; 18 | fdt_get_alias_namelen; 19 | fdt_get_alias; 20 | fdt_get_path; 21 | fdt_supernode_atdepth_offset; 22 | fdt_node_depth; 23 | fdt_parent_offset; 24 | fdt_node_offset_by_prop_value; 25 | fdt_node_offset_by_phandle; 26 | fdt_node_check_compatible; 27 | fdt_node_offset_by_compatible; 28 | fdt_setprop_inplace; 29 | fdt_nop_property; 30 | fdt_nop_node; 31 | fdt_create; 32 | fdt_add_reservemap_entry; 33 | fdt_finish_reservemap; 34 | fdt_begin_node; 35 | fdt_property; 36 | fdt_end_node; 37 | fdt_finish; 38 | fdt_open_into; 39 | fdt_pack; 40 | fdt_add_mem_rsv; 41 | fdt_del_mem_rsv; 42 | fdt_set_name; 43 | fdt_setprop; 44 | fdt_delprop; 45 | fdt_add_subnode_namelen; 46 | fdt_add_subnode; 47 | fdt_del_node; 48 | fdt_strerror; 49 | fdt_offset_ptr; 50 | fdt_next_tag; 51 | fdt_appendprop; 52 | fdt_create_empty_tree; 53 | fdt_first_property_offset; 54 | fdt_get_property_by_offset; 55 | fdt_getprop_by_offset; 56 | fdt_next_property_offset; 57 | 58 | local: 59 | *; 60 | }; 61 | -------------------------------------------------------------------------------- /lib/linux/const.h: -------------------------------------------------------------------------------- 1 | /* const.h: Macros for dealing with constants. */ 2 | 3 | #ifndef _LINUX_CONST_H 4 | #define _LINUX_CONST_H 5 | 6 | /* Some constant macros are used in both assembler and 7 | * C code. Therefore we cannot annotate them always with 8 | * 'UL' and other type specifiers unilaterally. We 9 | * use the following macros to deal with this. 10 | * 11 | * Similarly, _AT() will cast an expression with a type in C, but 12 | * leave it unchanged in asm. 13 | */ 14 | 15 | #ifdef __ASSEMBLY__ 16 | #define _AC(X,Y) X 17 | #define _AT(T,X) X 18 | #else 19 | #define __AC(X,Y) (X##Y) 20 | #define _AC(X,Y) __AC(X,Y) 21 | #define _AT(T,X) ((T)(X)) 22 | #endif 23 | 24 | #define _BITUL(x) (_AC(1,UL) << (x)) 25 | #define _BITULL(x) (_AC(1,ULL) << (x)) 26 | 27 | #endif /* !(_LINUX_CONST_H) */ 28 | -------------------------------------------------------------------------------- /lib/pci-edu.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Edu PCI device. 3 | * 4 | * Copyright (C) 2016 Red Hat, Inc. 5 | * 6 | * Authors: 7 | * Peter Xu , 8 | * 9 | * This work is licensed under the terms of the GNU LGPL, version 2 or 10 | * later. 11 | */ 12 | 13 | #include "pci-edu.h" 14 | #include "asm/barrier.h" 15 | 16 | /* Return true if alive */ 17 | static inline bool edu_check_alive(struct pci_edu_dev *dev) 18 | { 19 | static uint32_t live_count = 1; 20 | uint32_t value; 21 | 22 | edu_reg_writel(dev, EDU_REG_ALIVE, live_count++); 23 | value = edu_reg_readl(dev, EDU_REG_ALIVE); 24 | return (live_count - 1 == ~value); 25 | } 26 | 27 | bool edu_init(struct pci_edu_dev *dev) 28 | { 29 | pcidevaddr_t dev_addr; 30 | 31 | dev_addr = pci_find_dev(PCI_VENDOR_ID_QEMU, PCI_DEVICE_ID_EDU); 32 | if (dev_addr == PCIDEVADDR_INVALID) 33 | return false; 34 | 35 | pci_dev_init(&dev->pci_dev, dev_addr); 36 | pci_enable_defaults(&dev->pci_dev); 37 | dev->reg_base = ioremap(dev->pci_dev.resource[EDU_BAR], PAGE_SIZE); 38 | assert(edu_check_alive(dev)); 39 | return true; 40 | } 41 | 42 | void edu_dma(struct pci_edu_dev *dev, iova_t iova, 43 | size_t size, unsigned int dev_offset, bool from_device) 44 | { 45 | uint64_t from, to; 46 | uint32_t cmd = EDU_CMD_DMA_START; 47 | 48 | assert(size <= EDU_DMA_SIZE_MAX); 49 | assert(dev_offset < EDU_DMA_SIZE_MAX); 50 | 51 | printf("edu device DMA start %s addr %#" PRIx64 " size %lu off %#x\n", 52 | from_device ? "FROM" : "TO", 53 | iova, (ulong)size, dev_offset); 54 | 55 | if (from_device) { 56 | from = dev_offset + EDU_DMA_START; 57 | to = iova; 58 | cmd |= EDU_CMD_DMA_FROM; 59 | } else { 60 | from = iova; 61 | to = EDU_DMA_START + dev_offset; 62 | cmd |= EDU_CMD_DMA_TO; 63 | } 64 | 65 | edu_reg_writeq(dev, EDU_REG_DMA_SRC, from); 66 | edu_reg_writeq(dev, EDU_REG_DMA_DST, to); 67 | edu_reg_writeq(dev, EDU_REG_DMA_COUNT, size); 68 | edu_reg_writel(dev, EDU_REG_DMA_CMD, cmd); 69 | 70 | /* Wait until DMA finished */ 71 | while (edu_reg_readl(dev, EDU_REG_DMA_CMD) & EDU_CMD_DMA_START) 72 | cpu_relax(); 73 | } 74 | -------------------------------------------------------------------------------- /lib/pci-edu.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Edu PCI device header. 3 | * 4 | * Copyright (C) 2016 Red Hat, Inc. 5 | * 6 | * Authors: 7 | * Peter Xu , 8 | * 9 | * This work is licensed under the terms of the GNU LGPL, version 2 or 10 | * later. 11 | * 12 | * Edu device is a virtualized device in QEMU. Please refer to 13 | * docs/specs/edu.txt in QEMU repository for EDU device manual. 14 | */ 15 | #ifndef __PCI_EDU_H__ 16 | #define __PCI_EDU_H__ 17 | 18 | #include "pci.h" 19 | #include "asm/io.h" 20 | 21 | #define PCI_VENDOR_ID_QEMU 0x1234 22 | #define PCI_DEVICE_ID_EDU 0x11e8 23 | 24 | /* The only bar used by EDU device */ 25 | #define EDU_BAR 0 26 | #define EDU_MAGIC 0xed 27 | #define EDU_VERSION 0x100 28 | #define EDU_DMA_BUF_SIZE (1 << 20) 29 | #define EDU_INPUT_BUF_SIZE 256 30 | 31 | #define EDU_REG_ID 0x0 32 | #define EDU_REG_ALIVE 0x4 33 | #define EDU_REG_FACTORIAL 0x8 34 | #define EDU_REG_STATUS 0x20 35 | #define EDU_REG_INTR_STATUS 0x24 36 | #define EDU_REG_INTR_RAISE 0x60 37 | #define EDU_REG_INTR_ACK 0x64 38 | #define EDU_REG_DMA_SRC 0x80 39 | #define EDU_REG_DMA_DST 0x88 40 | #define EDU_REG_DMA_COUNT 0x90 41 | #define EDU_REG_DMA_CMD 0x98 42 | 43 | #define EDU_CMD_DMA_START 0x01 44 | #define EDU_CMD_DMA_FROM 0x02 45 | #define EDU_CMD_DMA_TO 0x00 46 | 47 | #define EDU_STATUS_FACTORIAL 0x1 48 | #define EDU_STATUS_INT_ENABLE 0x80 49 | 50 | #define EDU_DMA_START 0x40000 51 | #define EDU_DMA_SIZE_MAX 4096 52 | 53 | struct pci_edu_dev { 54 | struct pci_dev pci_dev; 55 | volatile void *reg_base; 56 | }; 57 | 58 | #define edu_reg(d, r) (volatile void *)((d)->reg_base + (r)) 59 | 60 | static inline uint64_t edu_reg_readq(struct pci_edu_dev *dev, int reg) 61 | { 62 | return __raw_readq(edu_reg(dev, reg)); 63 | } 64 | 65 | static inline uint32_t edu_reg_readl(struct pci_edu_dev *dev, int reg) 66 | { 67 | return __raw_readl(edu_reg(dev, reg)); 68 | } 69 | 70 | static inline void edu_reg_writeq(struct pci_edu_dev *dev, int reg, 71 | uint64_t val) 72 | { 73 | __raw_writeq(val, edu_reg(dev, reg)); 74 | } 75 | 76 | static inline void edu_reg_writel(struct pci_edu_dev *dev, int reg, 77 | uint32_t val) 78 | { 79 | __raw_writel(val, edu_reg(dev, reg)); 80 | } 81 | 82 | bool edu_init(struct pci_edu_dev *dev); 83 | void edu_dma(struct pci_edu_dev *dev, iova_t iova, 84 | size_t size, unsigned int dev_offset, bool from_device); 85 | 86 | #endif 87 | -------------------------------------------------------------------------------- /lib/pci-host-generic.h: -------------------------------------------------------------------------------- 1 | #ifndef PCI_HOST_GENERIC_H 2 | #define PCI_HOST_GENERIC_H 3 | /* 4 | * PCI host bridge supporting structures and constants 5 | * 6 | * Copyright (C) 2016, Red Hat Inc, Alexander Gordeev 7 | * 8 | * This work is licensed under the terms of the GNU LGPL, version 2. 9 | */ 10 | #include "libcflat.h" 11 | 12 | struct pci_addr_space { 13 | phys_addr_t pci_start; 14 | phys_addr_t start; 15 | phys_addr_t size; 16 | phys_addr_t allocated; 17 | int type; 18 | }; 19 | 20 | struct pci_host_bridge { 21 | phys_addr_t start; 22 | phys_addr_t size; 23 | int bus; 24 | int bus_max; 25 | int nr_addr_spaces; 26 | struct pci_addr_space addr_space[]; 27 | }; 28 | 29 | /* 30 | * The following constants are derived from Linux, see this source: 31 | * 32 | * drivers/pci/host/pci-host-generic.c 33 | * struct gen_pci_cfg_bus_ops::bus_shift 34 | * int gen_pci_parse_map_cfg_windows(struct gen_pci *pci) 35 | * 36 | * Documentation/devicetree/bindings/pci/host-generic-pci.txt describes 37 | * ECAM Configuration Space is be memory-mapped by concatenating the various 38 | * components to form an offset: 39 | * 40 | * cfg_offset(bus, device, function, register) = 41 | * bus << 20 | device << 15 | function << 12 | register 42 | */ 43 | #define PCI_ECAM_BUS_SHIFT 20 44 | #define PCI_ECAM_DEVFN_SHIFT 12 45 | 46 | #endif 47 | -------------------------------------------------------------------------------- /lib/powerpc/.gitignore: -------------------------------------------------------------------------------- 1 | asm-offsets.[hs] 2 | -------------------------------------------------------------------------------- /lib/powerpc/asm/handlers.h: -------------------------------------------------------------------------------- 1 | #ifndef _ASMPOWERPC_HANDLERS_H_ 2 | #define _ASMPOWERPC_HANDLERS_H_ 3 | 4 | #include 5 | 6 | void dec_except_handler(struct pt_regs *regs, void *data); 7 | 8 | #endif /* _ASMPOWERPC_HANDLERS_H_ */ 9 | -------------------------------------------------------------------------------- /lib/powerpc/asm/hcall.h: -------------------------------------------------------------------------------- 1 | #ifndef _ASMPOWERPC_HCALL_H_ 2 | #define _ASMPOWERPC_HCALL_H_ 3 | /* 4 | * Copyright (C) 2016, Red Hat Inc, Andrew Jones 5 | * 6 | * This work is licensed under the terms of the GNU LGPL, version 2. 7 | */ 8 | 9 | #define SC1 0x44000022 10 | #define SC1_REPLACEMENT 0x7c000268 11 | 12 | #define H_SUCCESS 0 13 | #define H_HARDWARE -1 14 | #define H_FUNCTION -2 15 | #define H_PRIVILEGE -3 16 | #define H_PARAMETER -4 17 | 18 | #define H_SET_SPRG0 0x24 19 | #define H_SET_DABR 0x28 20 | #define H_PAGE_INIT 0x2c 21 | #define H_CEDE 0xE0 22 | #define H_GET_TERM_CHAR 0x54 23 | #define H_PUT_TERM_CHAR 0x58 24 | #define H_RANDOM 0x300 25 | #define H_SET_MODE 0x31C 26 | 27 | #ifndef __ASSEMBLY__ 28 | /* 29 | * hcall_have_broken_sc1 checks if we're on a host with a broken sc1. 30 | * Returns 0 if we're not. 31 | */ 32 | extern int hcall_have_broken_sc1(void); 33 | 34 | /* 35 | * hcall is the hypercall wrapper function. unittests may do what 36 | * they like, but the framework should make all hypercalls through 37 | * here to ensure they use a working sc1 instruction. @nr is the 38 | * hypercall number. 39 | */ 40 | extern unsigned long hcall(unsigned long nr, ...); 41 | 42 | #endif /* !__ASSEMBLY__ */ 43 | #endif /* _ASMPOWERPC_HCALL_H_ */ 44 | -------------------------------------------------------------------------------- /lib/powerpc/asm/ppc_asm.h: -------------------------------------------------------------------------------- 1 | #ifndef _ASMPOWERPC_PPC_ASM_H 2 | #define _ASMPOWERPC_PPC_ASM_H 3 | 4 | #include 5 | 6 | #define SAVE_GPR(n, base) std n,GPR0+8*(n)(base) 7 | #define REST_GPR(n, base) ld n,GPR0+8*(n)(base) 8 | 9 | #define LOAD_REG_IMMEDIATE(reg,expr) \ 10 | lis reg,(expr)@highest; \ 11 | ori reg,reg,(expr)@higher; \ 12 | rldicr reg,reg,32,31; \ 13 | oris reg,reg,(expr)@h; \ 14 | ori reg,reg,(expr)@l; 15 | 16 | #define LOAD_REG_ADDR(reg,name) \ 17 | ld reg,name@got(r2) 18 | 19 | #if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ 20 | 21 | #define FIXUP_ENDIAN 22 | 23 | #elif __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ 24 | 25 | #define FIXUP_ENDIAN \ 26 | .long 0x05000048; /* bl . + 4 */ \ 27 | .long 0xa602487d; /* mflr r10 */ \ 28 | .long 0x20004a39; /* addi r10,r10,32 */ \ 29 | .long 0xa600607d; /* mfmsr r11 */ \ 30 | .long 0x01006b69; /* xori r11,r11,1 */ \ 31 | .long 0xa6035a7d; /* mtsrr0 r10 */ \ 32 | .long 0xa6037b7d; /* mtsrr1 r11 */ \ 33 | .long 0x2400004c; /* rfid */ \ 34 | .long 0x00000048; /* b . */ \ 35 | 36 | #endif /* __BYTE_ORDER__ */ 37 | 38 | #endif /* _ASMPOWERPC_PPC_ASM_H */ 39 | -------------------------------------------------------------------------------- /lib/powerpc/asm/processor.h: -------------------------------------------------------------------------------- 1 | #ifndef _ASMPOWERPC_PROCESSOR_H_ 2 | #define _ASMPOWERPC_PROCESSOR_H_ 3 | 4 | #include 5 | #include 6 | 7 | #ifndef __ASSEMBLY__ 8 | void handle_exception(int trap, void (*func)(struct pt_regs *, void *), void *); 9 | void do_handle_exception(struct pt_regs *regs); 10 | #endif /* __ASSEMBLY__ */ 11 | 12 | static inline uint64_t get_tb(void) 13 | { 14 | uint64_t tb; 15 | 16 | asm volatile ("mfspr %[tb],268" : [tb] "=r" (tb)); 17 | 18 | return tb; 19 | } 20 | 21 | extern void delay(uint64_t cycles); 22 | extern void udelay(uint64_t us); 23 | 24 | static inline void mdelay(uint64_t ms) 25 | { 26 | while (ms--) 27 | udelay(1000); 28 | } 29 | 30 | #endif /* _ASMPOWERPC_PROCESSOR_H_ */ 31 | -------------------------------------------------------------------------------- /lib/powerpc/asm/rtas.h: -------------------------------------------------------------------------------- 1 | #ifndef _ASMPOWERPC_RTAS_H_ 2 | #define _ASMPOWERPC_RTAS_H_ 3 | /* 4 | * Copyright (C) 2016, Red Hat Inc, Andrew Jones 5 | * 6 | * This work is licensed under the terms of the GNU LGPL, version 2. 7 | */ 8 | 9 | #ifndef __ASSEMBLY__ 10 | 11 | #include 12 | 13 | #define RTAS_UNKNOWN_SERVICE (-1) 14 | 15 | struct rtas_args { 16 | u32 token; 17 | u32 nargs; 18 | u32 nret; 19 | u32 args[16]; 20 | u32 *rets; 21 | }; 22 | 23 | extern void rtas_init(void); 24 | extern int rtas_token(const char *service, uint32_t *token); 25 | extern int rtas_call(int token, int nargs, int nret, int *outputs, ...); 26 | 27 | extern void rtas_power_off(void); 28 | #endif /* __ASSEMBLY__ */ 29 | 30 | #define RTAS_MSR_MASK 0xfffffffffffffffe 31 | 32 | #endif /* _ASMPOWERPC_RTAS_H_ */ 33 | -------------------------------------------------------------------------------- /lib/powerpc/asm/setup.h: -------------------------------------------------------------------------------- 1 | #ifndef _ASMPOWERPC_SETUP_H_ 2 | #define _ASMPOWERPC_SETUP_H_ 3 | /* 4 | * Copyright (C) 2016, Red Hat Inc, Andrew Jones 5 | * 6 | * This work is licensed under the terms of the GNU LGPL, version 2. 7 | */ 8 | #include 9 | 10 | #define NR_CPUS 8 /* arbitrarily set for now */ 11 | extern u32 cpus[NR_CPUS]; 12 | extern int nr_cpus; 13 | 14 | extern uint64_t tb_hz; 15 | 16 | #define NR_MEM_REGIONS 8 17 | #define MR_F_PRIMARY (1U << 0) 18 | struct mem_region { 19 | phys_addr_t start; 20 | phys_addr_t end; 21 | unsigned int flags; 22 | }; 23 | extern struct mem_region mem_regions[NR_MEM_REGIONS]; 24 | extern phys_addr_t __physical_start, __physical_end; 25 | extern unsigned __icache_bytes, __dcache_bytes; 26 | 27 | #define PHYSICAL_START (__physical_start) 28 | #define PHYSICAL_END (__physical_end) 29 | 30 | void setup(const void *fdt); 31 | 32 | #endif /* _ASMPOWERPC_SETUP_H_ */ 33 | -------------------------------------------------------------------------------- /lib/powerpc/asm/smp.h: -------------------------------------------------------------------------------- 1 | #ifndef _ASMPOWERPC_SMP_H_ 2 | #define _ASMPOWERPC_SMP_H_ 3 | 4 | #include 5 | 6 | extern int nr_threads; 7 | 8 | struct start_threads { 9 | int nr_threads; 10 | int nr_started; 11 | }; 12 | 13 | typedef void (*secondary_entry_fn)(void); 14 | 15 | extern void halt(void); 16 | 17 | extern int start_thread(int cpu_id, secondary_entry_fn entry, uint32_t r3); 18 | extern struct start_threads start_cpu(int cpu_node, secondary_entry_fn entry, 19 | uint32_t r3); 20 | extern bool start_all_cpus(secondary_entry_fn entry, uint32_t r3); 21 | 22 | #endif /* _ASMPOWERPC_SMP_H_ */ 23 | -------------------------------------------------------------------------------- /lib/powerpc/asm/stack.h: -------------------------------------------------------------------------------- 1 | #ifndef _ASMPOWERPC_STACK_H_ 2 | #define _ASMPOWERPC_STACK_H_ 3 | 4 | #ifndef _STACK_H_ 5 | #error Do not directly include . Just use . 6 | #endif 7 | 8 | #endif 9 | -------------------------------------------------------------------------------- /lib/powerpc/handlers.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Generic exception handlers for registration and use in tests 3 | * 4 | * Copyright 2016 Suraj Jitindar Singh, IBM. 5 | * 6 | * This work is licensed under the terms of the GNU LGPL, version 2. 7 | */ 8 | 9 | #include 10 | #include 11 | #include 12 | 13 | /* 14 | * Generic handler for decrementer exceptions (0x900) 15 | * Just reset the decrementer back to its maximum value (0x7FFFFFFF) 16 | */ 17 | void dec_except_handler(struct pt_regs *regs __unused, void *data __unused) 18 | { 19 | uint32_t dec = 0x7FFFFFFF; 20 | 21 | asm volatile ("mtdec %0" : : "r" (dec)); 22 | } 23 | -------------------------------------------------------------------------------- /lib/powerpc/hcall.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Hypercall helpers 3 | * 4 | * broken_sc1 probing/patching inspired by SLOF, see 5 | * SLOF:lib/libhvcall/brokensc1.c 6 | * 7 | * Copyright (C) 2016, Red Hat Inc, Andrew Jones 8 | * 9 | * This work is licensed under the terms of the GNU LGPL, version 2. 10 | */ 11 | #include 12 | #include 13 | #include "io.h" 14 | 15 | int hcall_have_broken_sc1(void) 16 | { 17 | register unsigned long r3 asm("r3") = H_SET_DABR; 18 | register unsigned long r4 asm("r4") = 0; 19 | 20 | asm volatile("sc 1" 21 | : "=r" (r3) 22 | : "r" (r3), "r" (r4) 23 | : "r5", "r6", "r7", "r8", "r9", "r10", "r11", "r12"); 24 | 25 | return r3 == (unsigned long)H_PRIVILEGE; 26 | } 27 | 28 | void putchar(int c) 29 | { 30 | unsigned long vty = 0; /* 0 == default */ 31 | unsigned long nr_chars = 1; 32 | unsigned long chars = (unsigned long)c << 56; 33 | 34 | hcall(H_PUT_TERM_CHAR, vty, nr_chars, chars); 35 | } 36 | 37 | int __getchar(void) 38 | { 39 | register unsigned long r3 asm("r3") = H_GET_TERM_CHAR; 40 | register unsigned long r4 asm("r4") = 0; /* 0 == default vty */ 41 | register unsigned long r5 asm("r5"); 42 | 43 | asm volatile (" sc 1 " : "+r"(r3), "+r"(r4), "=r"(r5) 44 | : "r"(r3), "r"(r4)); 45 | 46 | return r3 == H_SUCCESS && r4 > 0 ? r5 >> 48 : -1; 47 | } 48 | -------------------------------------------------------------------------------- /lib/powerpc/io.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Each architecture must implement puts() and exit(). 3 | * 4 | * Copyright (C) 2016, Red Hat Inc, Andrew Jones 5 | * 6 | * This work is licensed under the terms of the GNU LGPL, version 2. 7 | */ 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include "io.h" 13 | 14 | static struct spinlock print_lock; 15 | 16 | void io_init(void) 17 | { 18 | rtas_init(); 19 | } 20 | 21 | void puts(const char *s) 22 | { 23 | spin_lock(&print_lock); 24 | while (*s) 25 | putchar(*s++); 26 | spin_unlock(&print_lock); 27 | } 28 | 29 | /* 30 | * Defining halt to take 'code' as an argument guarantees that it will 31 | * be in r3 when we halt. That gives us a final chance to see the exit 32 | * status while inspecting the halted unit test state. 33 | */ 34 | extern void halt(int code); 35 | 36 | void exit(int code) 37 | { 38 | // FIXME: change this print-exit/rtas-poweroff to chr_testdev_exit(), 39 | // maybe by plugging chr-testdev into a spapr-vty. 40 | printf("\nEXIT: STATUS=%d\n", ((code) << 1) | 1); 41 | rtas_power_off(); 42 | halt(code); 43 | __builtin_unreachable(); 44 | } 45 | -------------------------------------------------------------------------------- /lib/powerpc/io.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Prototypes for io.c 3 | * 4 | * This work is licensed under the terms of the GNU GPL, version 2. 5 | */ 6 | 7 | extern void io_init(void); 8 | extern void putchar(int c); 9 | -------------------------------------------------------------------------------- /lib/powerpc/processor.c: -------------------------------------------------------------------------------- 1 | /* 2 | * processor control and status function 3 | * 4 | * This code is free software; you can redistribute it and/or modify it 5 | * under the terms of the GNU Library General Public License version 2. 6 | */ 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | static struct { 15 | void (*func)(struct pt_regs *, void *data); 16 | void *data; 17 | } handlers[16]; 18 | 19 | void handle_exception(int trap, void (*func)(struct pt_regs *, void *), 20 | void * data) 21 | { 22 | trap >>= 8; 23 | 24 | if (trap < 16) { 25 | handlers[trap].func = func; 26 | handlers[trap].data = data; 27 | } 28 | } 29 | 30 | void do_handle_exception(struct pt_regs *regs) 31 | { 32 | unsigned char v; 33 | 34 | v = regs->trap >> 8; 35 | 36 | if (v < 16 && handlers[v].func) { 37 | handlers[v].func(regs, handlers[v].data); 38 | return; 39 | } 40 | 41 | printf("unhandled cpu exception %#lx\n", regs->trap); 42 | abort(); 43 | } 44 | 45 | void delay(uint64_t cycles) 46 | { 47 | uint64_t start = get_tb(); 48 | 49 | while ((get_tb() - start) < cycles) 50 | cpu_relax(); 51 | } 52 | 53 | void udelay(uint64_t us) 54 | { 55 | delay((us * tb_hz) / 1000000); 56 | } 57 | -------------------------------------------------------------------------------- /lib/powerpc/smp.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Secondary cpu support 3 | * 4 | * Copyright 2016 Suraj Jitindar Singh, IBM. 5 | * 6 | * This work is licensed under the terms of the GNU LGPL, version 2. 7 | */ 8 | 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | int nr_threads; 15 | 16 | struct secondary_entry_data { 17 | secondary_entry_fn entry; 18 | uint64_t r3; 19 | int nr_started; 20 | }; 21 | 22 | /* 23 | * Start stopped thread cpu_id at entry 24 | * Returns: <0 on failure to start stopped cpu 25 | * 0 on success 26 | * >0 on cpu not in stopped state 27 | */ 28 | int start_thread(int cpu_id, secondary_entry_fn entry, uint32_t r3) 29 | { 30 | uint32_t query_token, start_token; 31 | int outputs[1], ret; 32 | 33 | ret = rtas_token("query-cpu-stopped-state", &query_token); 34 | assert(ret == 0); 35 | ret = rtas_token("start-cpu", &start_token); 36 | assert(ret == 0); 37 | 38 | ret = rtas_call(query_token, 1, 2, outputs, cpu_id); 39 | if (ret) { 40 | printf("query-cpu-stopped-state failed for cpu %d\n", cpu_id); 41 | } else if (!outputs[0]) { /* cpu in stopped state */ 42 | ret = rtas_call(start_token, 3, 1, NULL, cpu_id, entry, r3); 43 | if (ret) 44 | printf("failed to start cpu %d\n", cpu_id); 45 | } else { /* cpu not in stopped state */ 46 | ret = outputs[0]; 47 | } 48 | 49 | return ret; 50 | } 51 | 52 | /* 53 | * Start all stopped threads (vcpus) on cpu_node 54 | * Returns: Number of stopped cpus which were successfully started 55 | */ 56 | struct start_threads start_cpu(int cpu_node, secondary_entry_fn entry, 57 | uint32_t r3) 58 | { 59 | int len, i, nr_threads, nr_started = 0; 60 | const struct fdt_property *prop; 61 | u32 *threads; 62 | 63 | /* Get the id array of threads on this cpu_node */ 64 | prop = fdt_get_property(dt_fdt(), cpu_node, 65 | "ibm,ppc-interrupt-server#s", &len); 66 | assert(prop); 67 | 68 | nr_threads = len >> 2; /* Divide by 4 since 4 bytes per thread */ 69 | threads = (u32 *)prop->data; /* Array of valid ids */ 70 | 71 | for (i = 0; i < nr_threads; i++) { 72 | if (!start_thread(fdt32_to_cpu(threads[i]), entry, r3)) 73 | nr_started++; 74 | } 75 | 76 | return (struct start_threads) { nr_threads, nr_started }; 77 | } 78 | 79 | static void start_each_secondary(int fdtnode, u64 regval __unused, void *info) 80 | { 81 | struct secondary_entry_data *datap = info; 82 | struct start_threads ret = start_cpu(fdtnode, datap->entry, datap->r3); 83 | 84 | nr_threads += ret.nr_threads; 85 | datap->nr_started += ret.nr_started; 86 | } 87 | 88 | /* 89 | * Start all stopped cpus on the guest at entry with register 3 set to r3 90 | * We expect that we come in with only one thread currently started 91 | * Returns: TRUE on success 92 | * FALSE on failure 93 | */ 94 | bool start_all_cpus(secondary_entry_fn entry, uint32_t r3) 95 | { 96 | struct secondary_entry_data data = { entry, r3, 0 }; 97 | int ret; 98 | 99 | ret = dt_for_each_cpu_node(start_each_secondary, &data); 100 | assert(ret == 0); 101 | 102 | /* We expect that we come in with one thread already started */ 103 | return data.nr_started == nr_threads - 1; 104 | } 105 | -------------------------------------------------------------------------------- /lib/ppc64/.gitignore: -------------------------------------------------------------------------------- 1 | asm-offsets.[hs] 2 | -------------------------------------------------------------------------------- /lib/ppc64/asm-offsets.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2016, Red Hat Inc, Andrew Jones 3 | * 4 | * This work is licensed under the terms of the GNU LGPL, version 2. 5 | */ 6 | #include 7 | #include 8 | #include 9 | 10 | int main(void) 11 | { 12 | DEFINE(INT_FRAME_SIZE, STACK_INT_FRAME_SIZE); 13 | 14 | DEFINE(GPR0, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[0])); 15 | DEFINE(GPR1, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[1])); 16 | DEFINE(GPR2, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[2])); 17 | DEFINE(GPR3, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[3])); 18 | DEFINE(GPR4, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[4])); 19 | DEFINE(GPR5, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[5])); 20 | DEFINE(GPR6, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[6])); 21 | DEFINE(GPR7, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[7])); 22 | DEFINE(GPR8, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[8])); 23 | DEFINE(GPR9, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[9])); 24 | DEFINE(GPR10, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[10])); 25 | DEFINE(GPR11, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[11])); 26 | DEFINE(GPR12, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[12])); 27 | DEFINE(GPR13, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[13])); 28 | DEFINE(GPR14, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[14])); 29 | DEFINE(GPR15, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[15])); 30 | DEFINE(GPR16, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[16])); 31 | DEFINE(GPR17, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[17])); 32 | DEFINE(GPR18, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[18])); 33 | DEFINE(GPR19, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[19])); 34 | DEFINE(GPR20, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[20])); 35 | DEFINE(GPR21, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[21])); 36 | DEFINE(GPR22, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[22])); 37 | DEFINE(GPR23, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[23])); 38 | DEFINE(GPR24, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[24])); 39 | DEFINE(GPR25, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[25])); 40 | DEFINE(GPR26, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[26])); 41 | DEFINE(GPR27, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[27])); 42 | DEFINE(GPR28, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[28])); 43 | DEFINE(GPR29, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[29])); 44 | DEFINE(GPR30, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[30])); 45 | DEFINE(GPR31, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[31])); 46 | DEFINE(_NIP, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, nip)); 47 | DEFINE(_MSR, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, msr)); 48 | DEFINE(_CTR, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, ctr)); 49 | DEFINE(_LINK, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, link)); 50 | DEFINE(_XER, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, xer)); 51 | DEFINE(_CCR, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, ccr)); 52 | DEFINE(_TRAP, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, trap)); 53 | return 0; 54 | } 55 | -------------------------------------------------------------------------------- /lib/ppc64/asm/barrier.h: -------------------------------------------------------------------------------- 1 | #ifndef _ASMPPC64_BARRIER_H_ 2 | #define _ASMPPC64_BARRIER_H_ 3 | 4 | #define mb() asm volatile("sync":::"memory") 5 | #define rmb() asm volatile("sync":::"memory") 6 | #define wmb() asm volatile("sync":::"memory") 7 | 8 | #include 9 | #endif 10 | -------------------------------------------------------------------------------- /lib/ppc64/asm/bitops.h: -------------------------------------------------------------------------------- 1 | #ifndef _ASMPPC64_BITOPS_H_ 2 | #define _ASMPPC64_BITOPS_H_ 3 | 4 | #ifndef _BITOPS_H_ 5 | #error only can be included directly 6 | #endif 7 | 8 | #define BITS_PER_LONG 64 9 | 10 | #define HAVE_BUILTIN_FLS 1 11 | 12 | #endif 13 | -------------------------------------------------------------------------------- /lib/ppc64/asm/handlers.h: -------------------------------------------------------------------------------- 1 | #include "../../powerpc/asm/handlers.h" 2 | -------------------------------------------------------------------------------- /lib/ppc64/asm/hcall.h: -------------------------------------------------------------------------------- 1 | #include "../../powerpc/asm/hcall.h" 2 | -------------------------------------------------------------------------------- /lib/ppc64/asm/io.h: -------------------------------------------------------------------------------- 1 | #ifndef _ASMPPC64_IO_H_ 2 | #define _ASMPPC64_IO_H_ 3 | 4 | #if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ 5 | #define __cpu_is_be() (0) 6 | #elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ 7 | #define __cpu_is_be() (1) 8 | #else 9 | #error Undefined byte order 10 | #endif 11 | 12 | #define __iomem 13 | 14 | #include 15 | #endif 16 | -------------------------------------------------------------------------------- /lib/ppc64/asm/page.h: -------------------------------------------------------------------------------- 1 | #include 2 | -------------------------------------------------------------------------------- /lib/ppc64/asm/ppc_asm.h: -------------------------------------------------------------------------------- 1 | #include "../../powerpc/asm/ppc_asm.h" 2 | -------------------------------------------------------------------------------- /lib/ppc64/asm/processor.h: -------------------------------------------------------------------------------- 1 | #include "../../powerpc/asm/processor.h" 2 | -------------------------------------------------------------------------------- /lib/ppc64/asm/ptrace.h: -------------------------------------------------------------------------------- 1 | #ifndef _ASMPPC64_PTRACE_H_ 2 | #define _ASMPPC64_PTRACE_H_ 3 | 4 | #define KERNEL_REDZONE_SIZE 288 5 | #define STACK_FRAME_OVERHEAD 112 /* size of minimum stack frame */ 6 | 7 | #ifndef __ASSEMBLY__ 8 | struct pt_regs { 9 | unsigned long gpr[32]; 10 | unsigned long nip; 11 | unsigned long msr; 12 | unsigned long ctr; 13 | unsigned long link; 14 | unsigned long xer; 15 | unsigned long ccr; 16 | unsigned long trap; 17 | }; 18 | 19 | #define STACK_INT_FRAME_SIZE (sizeof(struct pt_regs) + \ 20 | STACK_FRAME_OVERHEAD + KERNEL_REDZONE_SIZE) 21 | 22 | #endif /* __ASSEMBLY__ */ 23 | 24 | #endif /* _ASMPPC64_PTRACE_H_ */ 25 | -------------------------------------------------------------------------------- /lib/ppc64/asm/rtas.h: -------------------------------------------------------------------------------- 1 | #include "../../powerpc/asm/rtas.h" 2 | -------------------------------------------------------------------------------- /lib/ppc64/asm/setup.h: -------------------------------------------------------------------------------- 1 | #include "../../powerpc/asm/setup.h" 2 | -------------------------------------------------------------------------------- /lib/ppc64/asm/smp.h: -------------------------------------------------------------------------------- 1 | #include "../../powerpc/asm/smp.h" 2 | -------------------------------------------------------------------------------- /lib/ppc64/asm/spinlock.h: -------------------------------------------------------------------------------- 1 | #ifndef _ASMPPC64_SPINLOCK_H_ 2 | #define _ASMPPC64_SPINLOCK_H_ 3 | 4 | #include 5 | 6 | #endif /* _ASMPPC64_SPINLOCK_H_ */ 7 | -------------------------------------------------------------------------------- /lib/ppc64/asm/stack.h: -------------------------------------------------------------------------------- 1 | #ifndef _ASMPPC64_STACK_H_ 2 | #define _ASMPPC64_STACK_H_ 3 | 4 | #ifndef _STACK_H_ 5 | #error Do not directly include . Just use . 6 | #endif 7 | 8 | #endif 9 | -------------------------------------------------------------------------------- /lib/s390x/.gitignore: -------------------------------------------------------------------------------- 1 | asm-offsets.[hs] 2 | -------------------------------------------------------------------------------- /lib/s390x/asm/barrier.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2017 Red Hat Inc 3 | * 4 | * Authors: 5 | * Thomas Huth 6 | * David Hildenbrand 7 | * 8 | * This code is free software; you can redistribute it and/or modify it 9 | * under the terms of the GNU Library General Public License version 2. 10 | */ 11 | #ifndef _ASM_S390X_BARRIER_H_ 12 | #define _ASM_S390X_BARRIER_H_ 13 | 14 | #include 15 | 16 | #endif 17 | -------------------------------------------------------------------------------- /lib/s390x/asm/bitops.h: -------------------------------------------------------------------------------- 1 | #ifndef _ASMS390X_BITOPS_H_ 2 | #define _ASMS390X_BITOPS_H_ 3 | 4 | #ifndef _BITOPS_H_ 5 | #error only can be included directly 6 | #endif 7 | 8 | #define BITS_PER_LONG 64 9 | 10 | #endif 11 | -------------------------------------------------------------------------------- /lib/s390x/asm/facility.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2017 Red Hat Inc 3 | * 4 | * Authors: 5 | * David Hildenbrand 6 | * 7 | * This code is free software; you can redistribute it and/or modify it 8 | * under the terms of the GNU Library General Public License version 2. 9 | */ 10 | #ifndef _ASM_S390X_FACILITY_H_ 11 | #define _ASM_S390X_FACILITY_H_ 12 | 13 | #include 14 | #include 15 | #include 16 | 17 | #define NR_STFL_BYTES 256 18 | extern uint8_t stfl_bytes[]; 19 | 20 | static inline bool test_facility(int nr) 21 | { 22 | return stfl_bytes[nr / 8] & (0x80U >> (nr % 8)); 23 | } 24 | 25 | static inline void stfl(void) 26 | { 27 | asm volatile(" stfl 0(0)\n"); 28 | } 29 | 30 | static inline void stfle(uint8_t *fac, unsigned int len) 31 | { 32 | register unsigned long r0 asm("0") = len - 1; 33 | 34 | asm volatile(" .insn s,0xb2b00000,0(%1)\n" 35 | : "+d" (r0) : "a" (fac) : "memory", "cc"); 36 | } 37 | 38 | static inline void setup_facilities(void) 39 | { 40 | struct lowcore *lc = NULL; 41 | 42 | stfl(); 43 | memcpy(stfl_bytes, &lc->stfl, sizeof(lc->stfl)); 44 | if (test_facility(7)) 45 | stfle(stfl_bytes, NR_STFL_BYTES); 46 | } 47 | 48 | #endif 49 | -------------------------------------------------------------------------------- /lib/s390x/asm/float.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2018 Red Hat Inc 3 | * 4 | * Authors: 5 | * David Hildenbrand 6 | * 7 | * This code is free software; you can redistribute it and/or modify it 8 | * under the terms of the GNU Library General Public License version 2. 9 | */ 10 | #ifndef _ASM_S390X_FLOAT_H_ 11 | #define _ASM_S390X_FLOAT_H_ 12 | 13 | static inline void set_fpc(uint32_t fpc) 14 | { 15 | asm volatile(" lfpc %0\n" : : "m"(fpc) ); 16 | } 17 | 18 | static inline uint32_t get_fpc(void) 19 | { 20 | uint32_t fpc; 21 | 22 | asm volatile(" stfpc %0\n" : "=m"(fpc)); 23 | 24 | return fpc; 25 | } 26 | 27 | static inline uint8_t get_fpc_dxc(void) 28 | { 29 | return get_fpc() >> 8; 30 | } 31 | 32 | static inline void set_fpc_dxc(uint8_t dxc) 33 | { 34 | uint32_t fpc = get_fpc(); 35 | 36 | fpc = (fpc & ~0xff00) | ((uint32_t)dxc) << 8; 37 | 38 | set_fpc(fpc); 39 | } 40 | 41 | static inline void afp_enable(void) 42 | { 43 | ctl_set_bit(0, 63 - 45); 44 | } 45 | 46 | static inline void afp_disable(void) 47 | { 48 | ctl_clear_bit(0, 63 - 45); 49 | } 50 | 51 | #endif 52 | -------------------------------------------------------------------------------- /lib/s390x/asm/interrupt.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2017 Red Hat Inc 3 | * 4 | * Authors: 5 | * David Hildenbrand 6 | * 7 | * This code is free software; you can redistribute it and/or modify it 8 | * under the terms of the GNU Library General Public License version 2. 9 | */ 10 | #ifndef _ASMS390X_IRQ_H_ 11 | #define _ASMS390X_IRQ_H_ 12 | #include 13 | 14 | void handle_pgm_int(void); 15 | void handle_ext_int(void); 16 | void handle_mcck_int(void); 17 | void handle_io_int(void); 18 | void handle_svc_int(void); 19 | void expect_pgm_int(void); 20 | uint16_t clear_pgm_int(void); 21 | void check_pgm_int_code(uint16_t code); 22 | 23 | /* Activate low-address protection */ 24 | static inline void low_prot_enable(void) 25 | { 26 | ctl_set_bit(0, 63 - 35); 27 | } 28 | 29 | /* Disable low-address protection */ 30 | static inline void low_prot_disable(void) 31 | { 32 | ctl_clear_bit(0, 63 - 35); 33 | } 34 | 35 | #endif 36 | -------------------------------------------------------------------------------- /lib/s390x/asm/io.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2017 Red Hat Inc 3 | * 4 | * Authors: 5 | * Thomas Huth 6 | * David Hildenbrand 7 | * 8 | * This code is free software; you can redistribute it and/or modify it 9 | * under the terms of the GNU Library General Public License version 2. 10 | */ 11 | #ifndef _ASMS390X_IO_H_ 12 | #define _ASMS390X_IO_H_ 13 | 14 | #define __iomem 15 | 16 | #include 17 | 18 | #endif 19 | -------------------------------------------------------------------------------- /lib/s390x/asm/mem.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Physical memory management related functions and definitions. 3 | * 4 | * Copyright IBM Corp. 2018 5 | * Author(s): Janosch Frank 6 | * 7 | * This code is free software; you can redistribute it and/or modify it 8 | * under the terms of the GNU Library General Public License version 2. 9 | */ 10 | #ifndef _ASM_S390_MEM_H 11 | #define _ASM_S390_MEM_H 12 | 13 | #define SKEY_ACC 0xf0 14 | #define SKEY_FP 0x08 15 | #define SKEY_RF 0x04 16 | #define SKEY_CH 0x02 17 | 18 | union skey { 19 | struct { 20 | uint8_t acc : 4; 21 | uint8_t fp : 1; 22 | uint8_t rf : 1; 23 | uint8_t ch : 1; 24 | uint8_t pad : 1; 25 | } str; 26 | uint8_t val; 27 | }; 28 | 29 | static inline void set_storage_key(unsigned long addr, 30 | unsigned char skey, 31 | int nq) 32 | { 33 | if (nq) 34 | asm volatile(".insn rrf,0xb22b0000,%0,%1,8,0" 35 | : : "d" (skey), "a" (addr)); 36 | else 37 | asm volatile("sske %0,%1" : : "d" (skey), "a" (addr)); 38 | } 39 | 40 | static inline unsigned long set_storage_key_mb(unsigned long addr, 41 | unsigned char skey) 42 | { 43 | assert(test_facility(8)); 44 | 45 | asm volatile(".insn rrf,0xb22b0000,%[skey],%[addr],1,0" 46 | : [addr] "+a" (addr) : [skey] "d" (skey)); 47 | return addr; 48 | } 49 | 50 | static inline unsigned char get_storage_key(unsigned long addr) 51 | { 52 | unsigned char skey; 53 | 54 | asm volatile("iske %0,%1" : "=d" (skey) : "a" (addr)); 55 | return skey; 56 | } 57 | #endif 58 | -------------------------------------------------------------------------------- /lib/s390x/asm/page.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2017 Red Hat Inc 3 | * 4 | * Authors: 5 | * Thomas Huth 6 | * David Hildenbrand 7 | * 8 | * This code is free software; you can redistribute it and/or modify it 9 | * under the terms of the GNU Library General Public License version 2. 10 | */ 11 | #ifndef _ASMS390X_PAGE_H_ 12 | #define _ASMS390X_PAGE_H_ 13 | 14 | #include 15 | 16 | typedef uint64_t pgdval_t; /* Region-1 table entry */ 17 | typedef uint64_t p4dval_t; /* Region-2 table entry*/ 18 | typedef uint64_t pudval_t; /* Region-3 table entry */ 19 | typedef uint64_t pmdval_t; /* Segment table entry */ 20 | typedef uint64_t pteval_t; /* Page table entry */ 21 | 22 | typedef struct { pgdval_t pgd; } pgd_t; 23 | typedef struct { p4dval_t p4d; } p4d_t; 24 | typedef struct { pudval_t pud; } pud_t; 25 | typedef struct { pmdval_t pmd; } pmd_t; 26 | typedef struct { pteval_t pte; } pte_t; 27 | 28 | #define pgd_val(x) ((x).pgd) 29 | #define p4d_val(x) ((x).p4d) 30 | #define pud_val(x) ((x).pud) 31 | #define pmd_val(x) ((x).pmd) 32 | #define pte_val(x) ((x).pte) 33 | 34 | #define __pgd(x) ((pgd_t) { (x) } ) 35 | #define __p4d(x) ((p4d_t) { (x) } ) 36 | #define __pud(x) ((pud_t) { (x) } ) 37 | #define __pmd(x) ((pmd_t) { (x) } ) 38 | #define __pte(x) ((pte_t) { (x) } ) 39 | 40 | #endif 41 | -------------------------------------------------------------------------------- /lib/s390x/asm/sigp.h: -------------------------------------------------------------------------------- 1 | /* 2 | * SIGP related definitions. 3 | * 4 | * Copied from the Linux kernel file arch/s390/include/asm/sigp.h 5 | * 6 | * This work is licensed under the terms of the GNU GPL, version 7 | * 2. 8 | */ 9 | 10 | #ifndef ASM_S390X_SIGP_H 11 | #define ASM_S390X_SIGP_H 12 | 13 | /* SIGP order codes */ 14 | #define SIGP_SENSE 1 15 | #define SIGP_EXTERNAL_CALL 2 16 | #define SIGP_EMERGENCY_SIGNAL 3 17 | #define SIGP_START 4 18 | #define SIGP_STOP 5 19 | #define SIGP_RESTART 6 20 | #define SIGP_STOP_AND_STORE_STATUS 9 21 | #define SIGP_INITIAL_CPU_RESET 11 22 | #define SIGP_CPU_RESET 12 23 | #define SIGP_SET_PREFIX 13 24 | #define SIGP_STORE_STATUS_AT_ADDRESS 14 25 | #define SIGP_SET_ARCHITECTURE 18 26 | #define SIGP_COND_EMERGENCY_SIGNAL 19 27 | #define SIGP_SENSE_RUNNING 21 28 | #define SIGP_SET_MULTI_THREADING 22 29 | #define SIGP_STORE_ADDITIONAL_STATUS 23 30 | 31 | /* SIGP condition codes */ 32 | #define SIGP_CC_ORDER_CODE_ACCEPTED 0 33 | #define SIGP_CC_STATUS_STORED 1 34 | #define SIGP_CC_BUSY 2 35 | #define SIGP_CC_NOT_OPERATIONAL 3 36 | 37 | /* SIGP cpu status bits */ 38 | 39 | #define SIGP_STATUS_INVALID_ORDER 0x00000002UL 40 | #define SIGP_STATUS_CHECK_STOP 0x00000010UL 41 | #define SIGP_STATUS_STOPPED 0x00000040UL 42 | #define SIGP_STATUS_EXT_CALL_PENDING 0x00000080UL 43 | #define SIGP_STATUS_INVALID_PARAMETER 0x00000100UL 44 | #define SIGP_STATUS_INCORRECT_STATE 0x00000200UL 45 | #define SIGP_STATUS_NOT_RUNNING 0x00000400UL 46 | 47 | #ifndef __ASSEMBLER__ 48 | 49 | static inline void sigp_stop(void) 50 | { 51 | register unsigned long status asm ("1") = 0; 52 | register unsigned long cpu asm ("2") = 0; 53 | 54 | asm volatile( 55 | " sigp %0,%1,0(%2)\n" 56 | : "+d" (status) : "d" (cpu), "d" (SIGP_STOP) : "cc"); 57 | } 58 | 59 | #endif /* __ASSEMBLER__ */ 60 | #endif /* ASM_S390X_SIGP_H */ 61 | -------------------------------------------------------------------------------- /lib/s390x/asm/spinlock.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2017 Red Hat Inc 3 | * 4 | * Authors: 5 | * Thomas Huth 6 | * David Hildenbrand 7 | * 8 | * This code is free software; you can redistribute it and/or modify it 9 | * under the terms of the GNU Library General Public License version 2. 10 | */ 11 | #ifndef __ASMS390X_SPINLOCK_H 12 | #define __ASMS390X_SPINLOCK_H 13 | 14 | #include 15 | 16 | #endif 17 | -------------------------------------------------------------------------------- /lib/s390x/asm/stack.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2017 Red Hat Inc 3 | * 4 | * Authors: 5 | * Thomas Huth 6 | * David Hildenbrand 7 | * 8 | * This code is free software; you can redistribute it and/or modify it 9 | * under the terms of the GNU Library General Public License version 2. 10 | */ 11 | #ifndef _ASMS390X_STACK_H_ 12 | #define _ASMS390X_STACK_H_ 13 | 14 | #ifndef _STACK_H_ 15 | #error Do not directly include . Just use . 16 | #endif 17 | 18 | #define HAVE_ARCH_BACKTRACE_FRAME 19 | #define HAVE_ARCH_BACKTRACE 20 | 21 | #endif 22 | -------------------------------------------------------------------------------- /lib/s390x/io.c: -------------------------------------------------------------------------------- 1 | /* 2 | * s390x io implementation 3 | * 4 | * Copyright (c) 2017 Red Hat Inc 5 | * 6 | * Authors: 7 | * Thomas Huth 8 | * David Hildenbrand 9 | * 10 | * This code is free software; you can redistribute it and/or modify it 11 | * under the terms of the GNU Library General Public License version 2. 12 | */ 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include "sclp.h" 19 | 20 | extern char ipl_args[]; 21 | uint8_t stfl_bytes[NR_STFL_BYTES] __attribute__((aligned(8))); 22 | 23 | static struct spinlock lock; 24 | 25 | void setup(void); 26 | 27 | void puts(const char *s) 28 | { 29 | spin_lock(&lock); 30 | sclp_print(s); 31 | spin_unlock(&lock); 32 | } 33 | 34 | void setup(void) 35 | { 36 | setup_args_progname(ipl_args); 37 | setup_facilities(); 38 | sclp_console_setup(); 39 | sclp_memory_setup(); 40 | } 41 | 42 | void exit(int code) 43 | { 44 | printf("\nEXIT: STATUS=%d\n", ((code) << 1) | 1); 45 | while (1) { 46 | sigp_stop(); 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /lib/s390x/mmu.h: -------------------------------------------------------------------------------- 1 | /* 2 | * s390x mmu functions 3 | * 4 | * Copyright (c) 2018 IBM Corp 5 | * 6 | * Authors: 7 | * Janosch Frank 8 | * 9 | * This code is free software; you can redistribute it and/or modify it 10 | * under the terms of the GNU Library General Public License version 2. 11 | */ 12 | #ifndef _ASMS390X_MMU_H_ 13 | #define _ASMS390X_MMU_H_ 14 | 15 | void protect_page(void *vaddr, unsigned long prot); 16 | void protect_range(void *start, unsigned long len, unsigned long prot); 17 | void unprotect_page(void *vaddr, unsigned long prot); 18 | void unprotect_range(void *start, unsigned long len, unsigned long prot); 19 | 20 | #endif /* _ASMS390X_MMU_H_ */ 21 | -------------------------------------------------------------------------------- /lib/s390x/sclp-console.c: -------------------------------------------------------------------------------- 1 | /* 2 | * SCLP ASCII access driver 3 | * 4 | * Copyright (c) 2013 Alexander Graf 5 | * 6 | * This work is licensed under the terms of the GNU GPL, version 2 or (at 7 | * your option) any later version. See the COPYING file in the top-level 8 | * directory. 9 | */ 10 | 11 | #include 12 | #include 13 | #include 14 | #include "sclp.h" 15 | 16 | static void sclp_set_write_mask(void) 17 | { 18 | WriteEventMask *sccb = (void *)_sccb; 19 | 20 | sccb->h.length = sizeof(WriteEventMask); 21 | sccb->mask_length = sizeof(unsigned int); 22 | sccb->receive_mask = SCLP_EVENT_MASK_MSG_ASCII; 23 | sccb->cp_receive_mask = SCLP_EVENT_MASK_MSG_ASCII; 24 | sccb->send_mask = SCLP_EVENT_MASK_MSG_ASCII; 25 | sccb->cp_send_mask = SCLP_EVENT_MASK_MSG_ASCII; 26 | 27 | sclp_service_call(SCLP_CMD_WRITE_EVENT_MASK, sccb); 28 | } 29 | 30 | void sclp_console_setup(void) 31 | { 32 | sclp_set_write_mask(); 33 | } 34 | 35 | void sclp_print(const char *str) 36 | { 37 | int len = strlen(str); 38 | WriteEventData *sccb = (void *)_sccb; 39 | 40 | sccb->h.length = sizeof(WriteEventData) + len; 41 | sccb->h.function_code = SCLP_FC_NORMAL_WRITE; 42 | sccb->ebh.length = sizeof(EventBufferHeader) + len; 43 | sccb->ebh.type = SCLP_EVENT_ASCII_CONSOLE_DATA; 44 | sccb->ebh.flags = 0; 45 | memcpy(sccb->data, str, len); 46 | 47 | sclp_service_call(SCLP_CMD_WRITE_EVENT_DATA, sccb); 48 | } 49 | -------------------------------------------------------------------------------- /lib/s390x/stack.c: -------------------------------------------------------------------------------- 1 | /* 2 | * s390x stack implementation 3 | * 4 | * Copyright (c) 2017 Red Hat Inc 5 | * 6 | * Authors: 7 | * Thomas Huth 8 | * David Hildenbrand 9 | * 10 | * This code is free software; you can redistribute it and/or modify it 11 | * under the terms of the GNU Library General Public License version 2. 12 | */ 13 | #include 14 | #include 15 | 16 | int backtrace_frame(const void *frame, const void **return_addrs, int max_depth) 17 | { 18 | printf("TODO: Implement backtrace_frame(%p, %p, %d) function!\n", 19 | frame, return_addrs, max_depth); 20 | return 0; 21 | } 22 | 23 | int backtrace(const void **return_addrs, int max_depth) 24 | { 25 | printf("TODO: Implement backtrace(%p, %d) function!\n", 26 | return_addrs, max_depth); 27 | return 0; 28 | } 29 | -------------------------------------------------------------------------------- /lib/setjmp.h: -------------------------------------------------------------------------------- 1 | /* 2 | * setjmp/longjmp prototypes 3 | * 4 | * This code is free software; you can redistribute it and/or modify it 5 | * under the terms of the GNU Library General Public License version 2. 6 | */ 7 | #ifndef LIBCFLAT_SETJMP_H 8 | #define LIBCFLAT_SETJMP_H 1 9 | 10 | typedef struct jmp_buf_tag { 11 | long int regs[8]; 12 | } jmp_buf[1]; 13 | 14 | extern int setjmp (struct jmp_buf_tag env[1]); 15 | extern void longjmp (struct jmp_buf_tag env[1], int val) 16 | __attribute__ ((__noreturn__)); 17 | 18 | #endif /* setjmp.h */ 19 | -------------------------------------------------------------------------------- /lib/stack.c: -------------------------------------------------------------------------------- 1 | /* 2 | * stack related functions 3 | * 4 | * This code is free software; you can redistribute it and/or modify it 5 | * under the terms of the GNU Library General Public License version 2. 6 | */ 7 | 8 | #include 9 | #include 10 | 11 | #define MAX_DEPTH 20 12 | 13 | static void print_stack(const void **return_addrs, int depth, 14 | bool top_is_return_address) 15 | { 16 | int i = 0; 17 | 18 | printf("\tSTACK:"); 19 | 20 | /* @addr indicates a non-return address, as expected by the stack 21 | * pretty printer script. */ 22 | if (depth > 0 && !top_is_return_address) { 23 | printf(" @%lx", (unsigned long) return_addrs[0]); 24 | i++; 25 | } 26 | 27 | for (; i < depth; i++) { 28 | printf(" %lx", (unsigned long) return_addrs[i]); 29 | } 30 | printf("\n"); 31 | } 32 | 33 | void dump_stack(void) 34 | { 35 | const void *return_addrs[MAX_DEPTH]; 36 | int depth; 37 | 38 | depth = backtrace(return_addrs, MAX_DEPTH); 39 | print_stack(&return_addrs[1], depth ? depth - 1 : 0, true); 40 | } 41 | 42 | void dump_frame_stack(const void *instruction, const void *frame) 43 | { 44 | const void *return_addrs[MAX_DEPTH]; 45 | int depth; 46 | 47 | return_addrs[0] = instruction; 48 | depth = backtrace_frame(frame, &return_addrs[1], MAX_DEPTH - 1); 49 | print_stack(return_addrs, depth + 1, false); 50 | } 51 | 52 | #ifndef HAVE_ARCH_BACKTRACE 53 | int backtrace(const void **return_addrs, int max_depth) 54 | { 55 | static int walking; 56 | int depth = 0; 57 | void *addr; 58 | 59 | if (walking) { 60 | printf("RECURSIVE STACK WALK!!!\n"); 61 | return 0; 62 | } 63 | walking = 1; 64 | 65 | /* __builtin_return_address requires a compile-time constant argument */ 66 | #define GET_RETURN_ADDRESS(i) \ 67 | if (max_depth == i) \ 68 | goto done; \ 69 | addr = __builtin_return_address(i); \ 70 | if (!addr) \ 71 | goto done; \ 72 | return_addrs[i] = __builtin_extract_return_addr(addr); \ 73 | depth = i + 1; \ 74 | 75 | GET_RETURN_ADDRESS(0) 76 | GET_RETURN_ADDRESS(1) 77 | GET_RETURN_ADDRESS(2) 78 | GET_RETURN_ADDRESS(3) 79 | GET_RETURN_ADDRESS(4) 80 | GET_RETURN_ADDRESS(5) 81 | GET_RETURN_ADDRESS(6) 82 | GET_RETURN_ADDRESS(7) 83 | GET_RETURN_ADDRESS(8) 84 | GET_RETURN_ADDRESS(9) 85 | GET_RETURN_ADDRESS(10) 86 | GET_RETURN_ADDRESS(11) 87 | GET_RETURN_ADDRESS(12) 88 | GET_RETURN_ADDRESS(13) 89 | GET_RETURN_ADDRESS(14) 90 | GET_RETURN_ADDRESS(15) 91 | GET_RETURN_ADDRESS(16) 92 | GET_RETURN_ADDRESS(17) 93 | GET_RETURN_ADDRESS(18) 94 | GET_RETURN_ADDRESS(19) 95 | GET_RETURN_ADDRESS(20) 96 | 97 | #undef GET_RETURN_ADDRESS 98 | 99 | done: 100 | walking = 0; 101 | return depth; 102 | } 103 | #endif /* HAVE_ARCH_BACKTRACE */ 104 | -------------------------------------------------------------------------------- /lib/stack.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Header for stack related functions 3 | * 4 | * This code is free software; you can redistribute it and/or modify it 5 | * under the terms of the GNU Library General Public License version 2. 6 | */ 7 | #ifndef _STACK_H_ 8 | #define _STACK_H_ 9 | 10 | #include 11 | #include 12 | 13 | #ifdef HAVE_ARCH_BACKTRACE_FRAME 14 | extern int backtrace_frame(const void *frame, const void **return_addrs, 15 | int max_depth); 16 | #else 17 | static inline int 18 | backtrace_frame(const void *frame __unused, const void **return_addrs __unused, 19 | int max_depth __unused) 20 | { 21 | return 0; 22 | } 23 | #endif 24 | 25 | extern int backtrace(const void **return_addrs, int max_depth); 26 | 27 | #endif 28 | -------------------------------------------------------------------------------- /lib/string.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Header for libc string functions 3 | * 4 | * This code is free software; you can redistribute it and/or modify it 5 | * under the terms of the GNU Library General Public License version 2. 6 | */ 7 | #ifndef __STRING_H 8 | #define __STRING_H 9 | 10 | extern unsigned long strlen(const char *buf); 11 | extern char *strcat(char *dest, const char *src); 12 | extern char *strcpy(char *dest, const char *src); 13 | extern int strcmp(const char *a, const char *b); 14 | extern int strncmp(const char *a, const char *b, size_t n); 15 | extern char *strchr(const char *s, int c); 16 | extern char *strstr(const char *haystack, const char *needle); 17 | extern void *memset(void *s, int c, size_t n); 18 | extern void *memcpy(void *dest, const void *src, size_t n); 19 | extern int memcmp(const void *s1, const void *s2, size_t n); 20 | extern void *memmove(void *dest, const void *src, size_t n); 21 | extern void *memchr(const void *s, int c, size_t n); 22 | 23 | #endif /* _STRING_H */ 24 | -------------------------------------------------------------------------------- /lib/util.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2016, Red Hat Inc, Andrew Jones 3 | * 4 | * This work is licensed under the terms of the GNU LGPL, version 2. 5 | */ 6 | #include 7 | #include "util.h" 8 | 9 | int parse_keyval(char *s, long *val) 10 | { 11 | char *p; 12 | 13 | p = strchr(s, '='); 14 | if (!p) 15 | return -1; 16 | 17 | *val = atol(p+1); 18 | return p - s; 19 | } 20 | -------------------------------------------------------------------------------- /lib/util.h: -------------------------------------------------------------------------------- 1 | #ifndef _UTIL_H_ 2 | #define _UTIL_H_ 3 | /* 4 | * Collection of utility functions to share between unit tests. 5 | * 6 | * Copyright (C) 2016, Red Hat Inc, Andrew Jones 7 | * 8 | * This work is licensed under the terms of the GNU LGPL, version 2. 9 | */ 10 | 11 | /* 12 | * parse_keyval extracts the integer from a string formatted as 13 | * string=integer. This is useful for passing expected values to 14 | * the unit test on the command line, i.e. it helps parse QEMU 15 | * command lines that include something like -append var1=1 var2=2 16 | * @s is the input string, likely a command line parameter, and 17 | * @val is a pointer to where the integer will be stored. 18 | * 19 | * Returns the offset of the '=', or -1 if no keyval pair is found. 20 | */ 21 | extern int parse_keyval(char *s, long *val); 22 | 23 | #endif 24 | -------------------------------------------------------------------------------- /lib/virtio-mmio.h: -------------------------------------------------------------------------------- 1 | #ifndef _VIRTIO_MMIO_H_ 2 | #define _VIRTIO_MMIO_H_ 3 | /* 4 | * A minimal implementation of virtio-mmio. Adapted from the Linux Kernel. 5 | * 6 | * Copyright (C) 2017, Red Hat Inc, Andrew Jones 7 | * 8 | * This work is licensed under the terms of the GNU GPL, version 2. 9 | */ 10 | #include "libcflat.h" 11 | #include "asm/page.h" 12 | #include "virtio.h" 13 | 14 | #define VIRTIO_MMIO_MAGIC_VALUE 0x000 15 | #define VIRTIO_MMIO_VERSION 0x004 16 | #define VIRTIO_MMIO_DEVICE_ID 0x008 17 | #define VIRTIO_MMIO_VENDOR_ID 0x00c 18 | #define VIRTIO_MMIO_HOST_FEATURES 0x010 19 | #define VIRTIO_MMIO_HOST_FEATURES_SEL 0x014 20 | #define VIRTIO_MMIO_GUEST_FEATURES 0x020 21 | #define VIRTIO_MMIO_GUEST_FEATURES_SEL 0x024 22 | #define VIRTIO_MMIO_GUEST_PAGE_SIZE 0x028 23 | #define VIRTIO_MMIO_QUEUE_SEL 0x030 24 | #define VIRTIO_MMIO_QUEUE_NUM_MAX 0x034 25 | #define VIRTIO_MMIO_QUEUE_NUM 0x038 26 | #define VIRTIO_MMIO_QUEUE_ALIGN 0x03c 27 | #define VIRTIO_MMIO_QUEUE_PFN 0x040 28 | #define VIRTIO_MMIO_QUEUE_NOTIFY 0x050 29 | #define VIRTIO_MMIO_INTERRUPT_STATUS 0x060 30 | #define VIRTIO_MMIO_INTERRUPT_ACK 0x064 31 | #define VIRTIO_MMIO_STATUS 0x070 32 | #define VIRTIO_MMIO_CONFIG 0x100 33 | 34 | #define VIRTIO_MMIO_INT_VRING (1 << 0) 35 | #define VIRTIO_MMIO_INT_CONFIG (1 << 1) 36 | 37 | #define VIRTIO_MMIO_VRING_ALIGN PAGE_SIZE 38 | 39 | /* 40 | * The minimum queue size is 2*VIRTIO_MMIO_VRING_ALIGN, which 41 | * means the largest queue num for the minimum queue size is 128, i.e. 42 | * 2*VIRTIO_MMIO_VRING_ALIGN = vring_size(128, VIRTIO_MMIO_VRING_ALIGN), 43 | * where vring_size is 44 | * 45 | * unsigned vring_size(unsigned num, unsigned long align) 46 | * { 47 | * return ((sizeof(struct vring_desc) * num + sizeof(u16) * (3 + num) 48 | * + align - 1) & ~(align - 1)) 49 | * + sizeof(u16) * 3 + sizeof(struct vring_used_elem) * num; 50 | * } 51 | */ 52 | #define VIRTIO_MMIO_QUEUE_SIZE_MIN (2*VIRTIO_MMIO_VRING_ALIGN) 53 | #define VIRTIO_MMIO_QUEUE_NUM_MIN 128 54 | 55 | #define to_virtio_mmio_device(vdev_ptr) \ 56 | container_of(vdev_ptr, struct virtio_mmio_device, vdev) 57 | 58 | struct virtio_mmio_device { 59 | struct virtio_device vdev; 60 | void *base; 61 | }; 62 | 63 | extern struct virtio_device *virtio_mmio_bind(u32 devid); 64 | 65 | #endif /* _VIRTIO_MMIO_H_ */ 66 | -------------------------------------------------------------------------------- /lib/virtio.c: -------------------------------------------------------------------------------- 1 | /* 2 | * virtqueue support adapted from the Linux kernel. 3 | * 4 | * Copyright (C) 2017, Red Hat Inc, Andrew Jones 5 | * 6 | * This work is licensed under the terms of the GNU GPL, version 2. 7 | */ 8 | #include "libcflat.h" 9 | #include "asm/io.h" 10 | #include "virtio.h" 11 | #include "virtio-mmio.h" 12 | 13 | void vring_init(struct vring *vr, unsigned int num, void *p, 14 | unsigned long align) 15 | { 16 | vr->num = num; 17 | vr->desc = p; 18 | vr->avail = p + num*sizeof(struct vring_desc); 19 | vr->used = (void *)(((unsigned long)&vr->avail->ring[num] + sizeof(u16) 20 | + align-1) & ~(align - 1)); 21 | } 22 | 23 | void vring_init_virtqueue(struct vring_virtqueue *vq, unsigned index, 24 | unsigned num, unsigned vring_align, 25 | struct virtio_device *vdev, void *pages, 26 | bool (*notify)(struct virtqueue *), 27 | void (*callback)(struct virtqueue *), 28 | const char *name) 29 | { 30 | unsigned i; 31 | 32 | vring_init(&vq->vring, num, pages, vring_align); 33 | vq->vq.callback = callback; 34 | vq->vq.vdev = vdev; 35 | vq->vq.name = name; 36 | vq->vq.num_free = num; 37 | vq->vq.index = index; 38 | vq->notify = notify; 39 | vq->last_used_idx = 0; 40 | vq->num_added = 0; 41 | vq->free_head = 0; 42 | 43 | for (i = 0; i < num-1; i++) { 44 | vq->vring.desc[i].next = i+1; 45 | vq->data[i] = NULL; 46 | } 47 | vq->data[i] = NULL; 48 | } 49 | 50 | int virtqueue_add_outbuf(struct virtqueue *_vq, char *buf, unsigned int len) 51 | { 52 | struct vring_virtqueue *vq = to_vvq(_vq); 53 | unsigned avail; 54 | int head; 55 | 56 | assert(buf != NULL); 57 | assert(len != 0); 58 | 59 | if (!vq->vq.num_free) 60 | return -1; 61 | 62 | --vq->vq.num_free; 63 | 64 | head = vq->free_head; 65 | 66 | vq->vring.desc[head].flags = 0; 67 | vq->vring.desc[head].addr = virt_to_phys(buf); 68 | vq->vring.desc[head].len = len; 69 | 70 | vq->free_head = vq->vring.desc[head].next; 71 | 72 | vq->data[head] = buf; 73 | 74 | avail = (vq->vring.avail->idx & (vq->vring.num-1)); 75 | vq->vring.avail->ring[avail] = head; 76 | wmb(); 77 | vq->vring.avail->idx++; 78 | vq->num_added++; 79 | 80 | return 0; 81 | } 82 | 83 | bool virtqueue_kick(struct virtqueue *_vq) 84 | { 85 | struct vring_virtqueue *vq = to_vvq(_vq); 86 | mb(); 87 | return vq->notify(_vq); 88 | } 89 | 90 | void detach_buf(struct vring_virtqueue *vq, unsigned head) 91 | { 92 | unsigned i = head; 93 | 94 | vq->data[head] = NULL; 95 | 96 | while (vq->vring.desc[i].flags & VRING_DESC_F_NEXT) { 97 | i = vq->vring.desc[i].next; 98 | vq->vq.num_free++; 99 | } 100 | 101 | vq->vring.desc[i].next = vq->free_head; 102 | vq->free_head = head; 103 | vq->vq.num_free++; 104 | } 105 | 106 | void *virtqueue_get_buf(struct virtqueue *_vq, unsigned int *len) 107 | { 108 | struct vring_virtqueue *vq = to_vvq(_vq); 109 | u16 last_used; 110 | unsigned i; 111 | void *ret; 112 | 113 | rmb(); 114 | 115 | last_used = (vq->last_used_idx & (vq->vring.num-1)); 116 | i = vq->vring.used->ring[last_used].id; 117 | *len = vq->vring.used->ring[last_used].len; 118 | 119 | ret = vq->data[i]; 120 | detach_buf(vq, i); 121 | 122 | vq->last_used_idx++; 123 | 124 | return ret; 125 | } 126 | 127 | struct virtio_device *virtio_bind(u32 devid) 128 | { 129 | return virtio_mmio_bind(devid); 130 | } 131 | -------------------------------------------------------------------------------- /lib/vmalloc.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2012, 2017, Red Hat Inc. 3 | * 4 | * This allocator provides contiguous physical addresses with page 5 | * granularity. 6 | */ 7 | 8 | #include "libcflat.h" 9 | #include "asm/spinlock.h" 10 | #include "asm/page.h" 11 | #include "asm/io.h" 12 | #include "alloc.h" 13 | #include "alloc_phys.h" 14 | #include "alloc_page.h" 15 | #include "vmalloc.h" 16 | 17 | static struct spinlock lock; 18 | static void *vfree_top = 0; 19 | static void *page_root; 20 | 21 | void *alloc_vpages(ulong nr) 22 | { 23 | spin_lock(&lock); 24 | vfree_top -= PAGE_SIZE * nr; 25 | spin_unlock(&lock); 26 | return vfree_top; 27 | } 28 | 29 | void *alloc_vpage(void) 30 | { 31 | return alloc_vpages(1); 32 | } 33 | 34 | void init_alloc_vpage(void *top) 35 | { 36 | vfree_top = top; 37 | } 38 | 39 | void *vmap(phys_addr_t phys, size_t size) 40 | { 41 | void *mem, *p; 42 | unsigned pages; 43 | 44 | size = (size + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1); 45 | pages = size / PAGE_SIZE; 46 | mem = p = alloc_vpages(pages); 47 | 48 | phys &= ~(unsigned long long)(PAGE_SIZE - 1); 49 | while (pages--) { 50 | install_page(page_root, phys, p); 51 | phys += PAGE_SIZE; 52 | p += PAGE_SIZE; 53 | } 54 | return mem; 55 | } 56 | 57 | static void *vm_memalign(size_t alignment, size_t size) 58 | { 59 | void *mem, *p; 60 | unsigned pages; 61 | 62 | assert(alignment <= PAGE_SIZE); 63 | size = (size + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1); 64 | pages = size / PAGE_SIZE; 65 | mem = p = alloc_vpages(pages); 66 | while (pages--) { 67 | phys_addr_t pa = virt_to_phys(alloc_page()); 68 | install_page(page_root, pa, p); 69 | p += PAGE_SIZE; 70 | } 71 | return mem; 72 | } 73 | 74 | static void vm_free(void *mem, size_t size) 75 | { 76 | while (size) { 77 | free_page(phys_to_virt(virt_to_pte_phys(page_root, mem))); 78 | mem += PAGE_SIZE; 79 | size -= PAGE_SIZE; 80 | } 81 | } 82 | 83 | static struct alloc_ops vmalloc_ops = { 84 | .memalign = vm_memalign, 85 | .free = vm_free, 86 | .align_min = PAGE_SIZE, 87 | }; 88 | 89 | void setup_vm() 90 | { 91 | phys_addr_t base, top; 92 | 93 | if (alloc_ops == &vmalloc_ops) 94 | return; 95 | 96 | phys_alloc_get_unused(&base, &top); 97 | assert(base != top || page_alloc_initialized()); 98 | if (!page_alloc_initialized()) { 99 | base = (base + PAGE_SIZE - 1) & -PAGE_SIZE; 100 | top = top & -PAGE_SIZE; 101 | free_pages(phys_to_virt(base), top - base); 102 | } 103 | page_root = setup_mmu(top); 104 | alloc_ops = &vmalloc_ops; 105 | } 106 | -------------------------------------------------------------------------------- /lib/vmalloc.h: -------------------------------------------------------------------------------- 1 | #ifndef VMALLOC_H 2 | #define VMALLOC_H 1 3 | 4 | #include 5 | 6 | extern void *alloc_vpages(ulong nr); 7 | extern void *alloc_vpage(void); 8 | extern void init_alloc_vpage(void *top); 9 | extern void setup_vm(void); 10 | 11 | extern void *setup_mmu(phys_addr_t top); 12 | extern phys_addr_t virt_to_pte_phys(pgd_t *pgtable, void *virt); 13 | extern pteval_t *install_page(pgd_t *pgtable, phys_addr_t phys, void *virt); 14 | 15 | void *vmap(phys_addr_t phys, size_t size); 16 | 17 | #endif 18 | -------------------------------------------------------------------------------- /lib/x86/acpi.c: -------------------------------------------------------------------------------- 1 | #include "libcflat.h" 2 | #include "acpi.h" 3 | 4 | void* find_acpi_table_addr(u32 sig) 5 | { 6 | unsigned long addr; 7 | struct rsdp_descriptor *rsdp; 8 | struct rsdt_descriptor_rev1 *rsdt; 9 | void *end; 10 | int i; 11 | 12 | /* FACS is special... */ 13 | if (sig == FACS_SIGNATURE) { 14 | struct fadt_descriptor_rev1 *fadt; 15 | fadt = find_acpi_table_addr(FACP_SIGNATURE); 16 | if (!fadt) { 17 | return NULL; 18 | } 19 | return (void*)(ulong)fadt->firmware_ctrl; 20 | } 21 | 22 | for(addr = 0xf0000; addr < 0x100000; addr += 16) { 23 | rsdp = (void*)addr; 24 | if (rsdp->signature == 0x2052545020445352LL) 25 | break; 26 | } 27 | if (addr == 0x100000) { 28 | printf("Can't find RSDP\n"); 29 | return 0; 30 | } 31 | 32 | if (sig == RSDP_SIGNATURE) { 33 | return rsdp; 34 | } 35 | 36 | rsdt = (void*)(ulong)rsdp->rsdt_physical_address; 37 | if (!rsdt || rsdt->signature != RSDT_SIGNATURE) 38 | return 0; 39 | 40 | if (sig == RSDT_SIGNATURE) { 41 | return rsdt; 42 | } 43 | 44 | end = (void*)rsdt + rsdt->length; 45 | for (i=0; (void*)&rsdt->table_offset_entry[i] < end; i++) { 46 | struct acpi_table *t = (void*)(ulong)rsdt->table_offset_entry[i]; 47 | if (t && t->signature == sig) { 48 | return t; 49 | } 50 | } 51 | return NULL; 52 | } 53 | -------------------------------------------------------------------------------- /lib/x86/apic.h: -------------------------------------------------------------------------------- 1 | #ifndef CFLAT_APIC_H 2 | #define CFLAT_APIC_H 3 | 4 | #include 5 | #include "apic-defs.h" 6 | 7 | extern void *g_apic; 8 | extern void *g_ioapic; 9 | 10 | typedef struct { 11 | uint8_t vector; 12 | uint8_t delivery_mode:3; 13 | uint8_t dest_mode:1; 14 | uint8_t delivery_status:1; 15 | uint8_t polarity:1; 16 | uint8_t remote_irr:1; 17 | uint8_t trig_mode:1; 18 | uint8_t mask:1; 19 | uint8_t reserve:7; 20 | uint8_t reserved[4]; 21 | uint8_t dest_id; 22 | } ioapic_redir_entry_t; 23 | 24 | typedef enum trigger_mode { 25 | TRIGGER_EDGE = 0, 26 | TRIGGER_LEVEL, 27 | TRIGGER_MAX, 28 | } trigger_mode_t; 29 | 30 | void mask_pic_interrupts(void); 31 | 32 | void eoi(void); 33 | uint8_t apic_get_tpr(void); 34 | void apic_set_tpr(uint8_t tpr); 35 | 36 | void ioapic_write_redir(unsigned line, ioapic_redir_entry_t e); 37 | void ioapic_write_reg(unsigned reg, uint32_t value); 38 | ioapic_redir_entry_t ioapic_read_redir(unsigned line); 39 | uint32_t ioapic_read_reg(unsigned reg); 40 | 41 | void ioapic_set_redir(unsigned line, unsigned vec, 42 | trigger_mode_t trig_mode); 43 | 44 | void set_mask(unsigned line, int mask); 45 | 46 | void set_irq_line(unsigned line, int val); 47 | 48 | void enable_apic(void); 49 | uint32_t apic_read(unsigned reg); 50 | bool apic_read_bit(unsigned reg, int n); 51 | void apic_write(unsigned reg, uint32_t val); 52 | void apic_icr_write(uint32_t val, uint32_t dest); 53 | uint32_t apic_id(void); 54 | 55 | int enable_x2apic(void); 56 | void disable_apic(void); 57 | void reset_apic(void); 58 | 59 | /* Converts byte-addressable APIC register offset to 4-byte offset. */ 60 | static inline u32 apic_reg_index(u32 reg) 61 | { 62 | return reg >> 2; 63 | } 64 | 65 | static inline u32 x2apic_msr(u32 reg) 66 | { 67 | return APIC_BASE_MSR + (reg >> 4); 68 | } 69 | 70 | static inline bool x2apic_reg_reserved(u32 reg) 71 | { 72 | switch (reg) { 73 | case 0x000 ... 0x010: 74 | case 0x040 ... 0x070: 75 | case 0x0c0: 76 | case 0x0e0: 77 | case 0x290 ... 0x2e0: 78 | case 0x310: 79 | case 0x3a0 ... 0x3d0: 80 | case 0x3f0: 81 | return true; 82 | default: 83 | return false; 84 | } 85 | } 86 | 87 | #endif 88 | -------------------------------------------------------------------------------- /lib/x86/asm/barrier.h: -------------------------------------------------------------------------------- 1 | #ifndef _ASM_X86_BARRIER_H_ 2 | #define _ASM_X86_BARRIER_H_ 3 | /* 4 | * Copyright (C) 2016, Red Hat Inc, Alexander Gordeev 5 | * 6 | * This work is licensed under the terms of the GNU LGPL, version 2. 7 | */ 8 | 9 | #define mb() asm volatile("mfence":::"memory") 10 | #define rmb() asm volatile("lfence":::"memory") 11 | #define wmb() asm volatile("sfence":::"memory") 12 | 13 | #define smp_rmb() barrier() 14 | #define smp_wmb() barrier() 15 | 16 | /* REP NOP (PAUSE) is a good thing to insert into busy-wait loops. */ 17 | static inline void rep_nop(void) 18 | { 19 | asm volatile("rep; nop" ::: "memory"); 20 | } 21 | 22 | static inline void cpu_relax(void) 23 | { 24 | rep_nop(); 25 | } 26 | 27 | #endif 28 | -------------------------------------------------------------------------------- /lib/x86/asm/bitops.h: -------------------------------------------------------------------------------- 1 | #ifndef _ASMX86_BITOPS_H_ 2 | #define _ASMX86_BITOPS_H_ 3 | 4 | #ifndef _BITOPS_H_ 5 | #error only can be included directly 6 | #endif 7 | 8 | #ifdef __x86_64__ 9 | #define BITS_PER_LONG 64 10 | #else 11 | #define BITS_PER_LONG 32 12 | #endif 13 | 14 | #define HAVE_BUILTIN_FLS 1 15 | 16 | #endif 17 | -------------------------------------------------------------------------------- /lib/x86/asm/io.h: -------------------------------------------------------------------------------- 1 | #ifndef _ASM_X86_IO_H_ 2 | #define _ASM_X86_IO_H_ 3 | 4 | #include "libcflat.h" 5 | 6 | #define __iomem 7 | 8 | #define inb inb 9 | static inline uint8_t inb(unsigned long port) 10 | { 11 | unsigned char value; 12 | asm volatile("inb %w1, %0" : "=a" (value) : "Nd" ((unsigned short)port)); 13 | return value; 14 | } 15 | 16 | #define inw inw 17 | static inline uint16_t inw(unsigned long port) 18 | { 19 | unsigned short value; 20 | asm volatile("inw %w1, %0" : "=a" (value) : "Nd" ((unsigned short)port)); 21 | return value; 22 | } 23 | 24 | #define inl inl 25 | static inline uint32_t inl(unsigned long port) 26 | { 27 | unsigned int value; 28 | asm volatile("inl %w1, %0" : "=a" (value) : "Nd" ((unsigned short)port)); 29 | return value; 30 | } 31 | 32 | #define outb outb 33 | static inline void outb(uint8_t value, unsigned long port) 34 | { 35 | asm volatile("outb %b0, %w1" : : "a"(value), "Nd"((unsigned short)port)); 36 | } 37 | 38 | #define outw outw 39 | static inline void outw(uint16_t value, unsigned long port) 40 | { 41 | asm volatile("outw %w0, %w1" : : "a"(value), "Nd"((unsigned short)port)); 42 | } 43 | 44 | #define outl outl 45 | static inline void outl(uint32_t value, unsigned long port) 46 | { 47 | asm volatile("outl %0, %w1" : : "a"(value), "Nd"((unsigned short)port)); 48 | } 49 | 50 | #define virt_to_phys virt_to_phys 51 | static inline unsigned long virt_to_phys(const void *virt) 52 | { 53 | return (unsigned long)virt; 54 | } 55 | 56 | #define phys_to_virt phys_to_virt 57 | static inline void *phys_to_virt(unsigned long phys) 58 | { 59 | return (void *)phys; 60 | } 61 | 62 | #define ioremap ioremap 63 | void __iomem *ioremap(phys_addr_t phys_addr, size_t size); 64 | 65 | #include 66 | 67 | #endif 68 | -------------------------------------------------------------------------------- /lib/x86/asm/page.h: -------------------------------------------------------------------------------- 1 | #ifndef _ASM_X86_PAGE_H_ 2 | #define _ASM_X86_PAGE_H_ 3 | /* 4 | * Copyright (C) 2016, Red Hat Inc, Alexander Gordeev 5 | * 6 | * This work is licensed under the terms of the GNU LGPL, version 2. 7 | */ 8 | 9 | 10 | #include 11 | #include 12 | 13 | typedef unsigned long pteval_t; 14 | typedef unsigned long pgd_t; 15 | 16 | #define PAGE_SHIFT 12 17 | #define PAGE_SIZE (_AC(1,UL) << PAGE_SHIFT) 18 | #define PAGE_MASK (~(PAGE_SIZE-1)) 19 | 20 | #ifndef __ASSEMBLY__ 21 | 22 | #ifdef __x86_64__ 23 | #define LARGE_PAGE_SIZE (512 * PAGE_SIZE) 24 | #else 25 | #define LARGE_PAGE_SIZE (1024 * PAGE_SIZE) 26 | #endif 27 | 28 | #define PT_PRESENT_MASK (1ull << 0) 29 | #define PT_WRITABLE_MASK (1ull << 1) 30 | #define PT_USER_MASK (1ull << 2) 31 | #define PT_ACCESSED_MASK (1ull << 5) 32 | #define PT_DIRTY_MASK (1ull << 6) 33 | #define PT_PAGE_SIZE_MASK (1ull << 7) 34 | #define PT64_NX_MASK (1ull << 63) 35 | #define PT_ADDR_MASK GENMASK_ULL(51, 12) 36 | 37 | #define PT_AD_MASK (PT_ACCESSED_MASK | PT_DIRTY_MASK) 38 | 39 | #ifdef __x86_64__ 40 | #define PAGE_LEVEL 4 41 | #define PGDIR_WIDTH 9 42 | #define PGDIR_MASK 511 43 | #else 44 | #define PAGE_LEVEL 2 45 | #define PGDIR_WIDTH 10 46 | #define PGDIR_MASK 1023 47 | #endif 48 | 49 | #define PGDIR_BITS(lvl) (((lvl) - 1) * PGDIR_WIDTH + PAGE_SHIFT) 50 | #define PGDIR_OFFSET(va, lvl) (((va) >> PGDIR_BITS(lvl)) & PGDIR_MASK) 51 | 52 | #endif /* !__ASSEMBLY__ */ 53 | #endif 54 | -------------------------------------------------------------------------------- /lib/x86/asm/pci.h: -------------------------------------------------------------------------------- 1 | #ifndef ASM_PCI_H 2 | #define ASM_PCI_H 3 | /* 4 | * Copyright (C) 2013, Red Hat Inc, Michael S. Tsirkin 5 | * 6 | * This work is licensed under the terms of the GNU LGPL, version 2. 7 | */ 8 | #include "libcflat.h" 9 | #include "pci.h" 10 | #include "x86/asm/io.h" 11 | 12 | #define PCI_CONF1_ADDRESS(dev, reg) ((0x1 << 31) | (dev << 8) | reg) 13 | 14 | static inline uint8_t pci_config_readb(pcidevaddr_t dev, uint8_t reg) 15 | { 16 | outl(PCI_CONF1_ADDRESS(dev, reg), 0xCF8); 17 | return inb(0xCFC); 18 | } 19 | 20 | static inline uint16_t pci_config_readw(pcidevaddr_t dev, uint8_t reg) 21 | { 22 | outl(PCI_CONF1_ADDRESS(dev, reg), 0xCF8); 23 | return inw(0xCFC); 24 | } 25 | 26 | static inline uint32_t pci_config_readl(pcidevaddr_t dev, uint8_t reg) 27 | { 28 | outl(PCI_CONF1_ADDRESS(dev, reg), 0xCF8); 29 | return inl(0xCFC); 30 | } 31 | 32 | static inline void pci_config_writeb(pcidevaddr_t dev, uint8_t reg, 33 | uint8_t val) 34 | { 35 | outl(PCI_CONF1_ADDRESS(dev, reg), 0xCF8); 36 | outb(val, 0xCFC); 37 | } 38 | 39 | static inline void pci_config_writew(pcidevaddr_t dev, uint8_t reg, 40 | uint16_t val) 41 | { 42 | outl(PCI_CONF1_ADDRESS(dev, reg), 0xCF8); 43 | outw(val, 0xCFC); 44 | } 45 | 46 | static inline void pci_config_writel(pcidevaddr_t dev, uint8_t reg, 47 | uint32_t val) 48 | { 49 | outl(PCI_CONF1_ADDRESS(dev, reg), 0xCF8); 50 | outl(val, 0xCFC); 51 | } 52 | 53 | static inline 54 | phys_addr_t pci_translate_addr(pcidevaddr_t dev __unused, uint64_t addr) 55 | { 56 | return addr; 57 | } 58 | 59 | #endif 60 | -------------------------------------------------------------------------------- /lib/x86/asm/spinlock.h: -------------------------------------------------------------------------------- 1 | #ifndef __ASM_SPINLOCK_H 2 | #define __ASM_SPINLOCK_H 3 | 4 | #include 5 | 6 | #endif 7 | -------------------------------------------------------------------------------- /lib/x86/asm/stack.h: -------------------------------------------------------------------------------- 1 | #ifndef _X86ASM_STACK_H_ 2 | #define _X86ASM_STACK_H_ 3 | 4 | #ifndef _STACK_H_ 5 | #error Do not directly include . Just use . 6 | #endif 7 | 8 | #define HAVE_ARCH_BACKTRACE_FRAME 9 | #define HAVE_ARCH_BACKTRACE 10 | 11 | #endif 12 | -------------------------------------------------------------------------------- /lib/x86/atomic.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "atomic.h" 3 | 4 | #ifdef __i386__ 5 | 6 | u64 atomic64_cmpxchg(atomic64_t *v, u64 old, u64 new) 7 | { 8 | u32 low = new; 9 | u32 high = new >> 32; 10 | 11 | asm volatile("lock cmpxchg8b %1\n" 12 | : "+A" (old), 13 | "+m" (*(volatile long long *)&v->counter) 14 | : "b" (low), "c" (high) 15 | : "memory" 16 | ); 17 | 18 | return old; 19 | } 20 | 21 | #else 22 | 23 | u64 atomic64_cmpxchg(atomic64_t *v, u64 old, u64 new) 24 | { 25 | u64 ret; 26 | u64 _old = old; 27 | u64 _new = new; 28 | 29 | asm volatile("lock cmpxchgq %2,%1" 30 | : "=a" (ret), "+m" (*(volatile long *)&v->counter) 31 | : "r" (_new), "0" (_old) 32 | : "memory" 33 | ); 34 | return ret; 35 | } 36 | 37 | #endif 38 | -------------------------------------------------------------------------------- /lib/x86/delay.c: -------------------------------------------------------------------------------- 1 | #include "delay.h" 2 | 3 | void delay(u64 count) 4 | { 5 | while (count--) 6 | asm volatile("pause"); 7 | } 8 | 9 | -------------------------------------------------------------------------------- /lib/x86/delay.h: -------------------------------------------------------------------------------- 1 | #ifndef __X86_DELAY__ 2 | #define __X86_DELAY__ 3 | 4 | #include "libcflat.h" 5 | 6 | void delay(u64 count); 7 | 8 | #endif 9 | -------------------------------------------------------------------------------- /lib/x86/fake-apic.h: -------------------------------------------------------------------------------- 1 | #ifndef SILLY_APIC_H 2 | #define SILLY_APIC_H 3 | 4 | #define APIC_BASE 0x1000 5 | #define APIC_SIZE 0x100 6 | 7 | #define APIC_REG_NCPU 0x00 8 | #define APIC_REG_ID 0x04 9 | #define APIC_REG_SIPI_ADDR 0x08 10 | #define APIC_REG_SEND_SIPI 0x0c 11 | #define APIC_REG_IPI_VECTOR 0x10 12 | #define APIC_REG_SEND_IPI 0x14 13 | 14 | #endif 15 | -------------------------------------------------------------------------------- /lib/x86/fault_test.c: -------------------------------------------------------------------------------- 1 | #include "fault_test.h" 2 | 3 | jmp_buf jmpbuf; 4 | 5 | static void restore_exec_to_jmpbuf(void) 6 | { 7 | longjmp(jmpbuf, 1); 8 | } 9 | 10 | static void fault_test_fault(struct ex_regs *regs) 11 | { 12 | regs->rip = (unsigned long)&restore_exec_to_jmpbuf; 13 | } 14 | 15 | static bool fault_test(struct fault_test_arg *arg) 16 | { 17 | volatile uint64_t val; 18 | bool raised_vector = false; 19 | test_fault_func func = (test_fault_func) arg->func; 20 | /* Init as success in case there isn't callback */ 21 | bool callback_success = true; 22 | 23 | if (arg->usermode) { 24 | val = run_in_user((usermode_func) func, arg->fault_vector, 25 | arg->arg[0], arg->arg[1], arg->arg[2], 26 | arg->arg[3], &raised_vector); 27 | } else { 28 | handle_exception(arg->fault_vector, fault_test_fault); 29 | if (setjmp(jmpbuf) == 0) 30 | val = func(arg->arg[0], arg->arg[1], arg->arg[2], 31 | arg->arg[3]); 32 | else 33 | raised_vector = true; 34 | } 35 | 36 | if (!raised_vector) { 37 | arg->retval = val; 38 | if (arg->callback != NULL) 39 | callback_success = arg->callback(arg); 40 | } 41 | 42 | return arg->should_fault ? 43 | raised_vector : (!raised_vector && callback_success); 44 | } 45 | 46 | void test_run(struct fault_test *test) 47 | { 48 | bool passed = fault_test(&(test->arg)); 49 | 50 | report("%s", passed, test->name); 51 | } 52 | 53 | -------------------------------------------------------------------------------- /lib/x86/fault_test.h: -------------------------------------------------------------------------------- 1 | #ifndef __FAULT_TEST__ 2 | #define __FAULT_TEST__ 3 | 4 | #include "x86/msr.h" 5 | #include "x86/processor.h" 6 | #include "x86/apic-defs.h" 7 | #include "x86/apic.h" 8 | #include "x86/desc.h" 9 | #include "x86/isr.h" 10 | #include "alloc.h" 11 | #include "setjmp.h" 12 | #include "usermode.h" 13 | 14 | #include "libcflat.h" 15 | #include 16 | 17 | #define FAULT_TEST(nm, a) { .name = nm, .arg = a} 18 | 19 | struct fault_test_arg; 20 | 21 | typedef uint64_t (*test_fault_func)(uint64_t arg1, uint64_t arg2, 22 | uint64_t arg3, uint64_t arg4); 23 | typedef bool (*test_fault_callback)(struct fault_test_arg *arg); 24 | 25 | struct fault_test_arg { 26 | bool usermode; 27 | unsigned int fault_vector; 28 | bool should_fault; 29 | uint64_t arg[4]; 30 | uint64_t retval; 31 | test_fault_func func; 32 | test_fault_callback callback; 33 | }; 34 | 35 | struct fault_test { 36 | const char *name; 37 | struct fault_test_arg arg; 38 | }; 39 | 40 | void test_run(struct fault_test *test); 41 | 42 | #endif 43 | -------------------------------------------------------------------------------- /lib/x86/fwcfg.c: -------------------------------------------------------------------------------- 1 | #include "fwcfg.h" 2 | #include "smp.h" 3 | 4 | static struct spinlock lock; 5 | 6 | static uint64_t fwcfg_get_u(uint16_t index, int bytes) 7 | { 8 | uint64_t r = 0; 9 | uint8_t b; 10 | int i; 11 | 12 | spin_lock(&lock); 13 | asm volatile ("out %0, %1" : : "a"(index), "d"((uint16_t)BIOS_CFG_IOPORT)); 14 | for (i = 0; i < bytes; ++i) { 15 | asm volatile ("in %1, %0" : "=a"(b) : "d"((uint16_t)(BIOS_CFG_IOPORT + 1))); 16 | r |= (uint64_t)b << (i * 8); 17 | } 18 | spin_unlock(&lock); 19 | return r; 20 | } 21 | 22 | uint8_t fwcfg_get_u8(unsigned index) 23 | { 24 | return fwcfg_get_u(index, 1); 25 | } 26 | 27 | uint16_t fwcfg_get_u16(unsigned index) 28 | { 29 | return fwcfg_get_u(index, 2); 30 | } 31 | 32 | uint32_t fwcfg_get_u32(unsigned index) 33 | { 34 | return fwcfg_get_u(index, 4); 35 | } 36 | 37 | uint64_t fwcfg_get_u64(unsigned index) 38 | { 39 | return fwcfg_get_u(index, 8); 40 | } 41 | 42 | unsigned fwcfg_get_nb_cpus(void) 43 | { 44 | return fwcfg_get_u16(FW_CFG_NB_CPUS); 45 | } 46 | -------------------------------------------------------------------------------- /lib/x86/fwcfg.h: -------------------------------------------------------------------------------- 1 | #ifndef FWCFG_H 2 | #define FWCFG_H 3 | 4 | #include 5 | 6 | #define FW_CFG_SIGNATURE 0x00 7 | #define FW_CFG_ID 0x01 8 | #define FW_CFG_UUID 0x02 9 | #define FW_CFG_RAM_SIZE 0x03 10 | #define FW_CFG_NOGRAPHIC 0x04 11 | #define FW_CFG_NB_CPUS 0x05 12 | #define FW_CFG_MACHINE_ID 0x06 13 | #define FW_CFG_KERNEL_ADDR 0x07 14 | #define FW_CFG_KERNEL_SIZE 0x08 15 | #define FW_CFG_KERNEL_CMDLINE 0x09 16 | #define FW_CFG_INITRD_ADDR 0x0a 17 | #define FW_CFG_INITRD_SIZE 0x0b 18 | #define FW_CFG_BOOT_DEVICE 0x0c 19 | #define FW_CFG_NUMA 0x0d 20 | #define FW_CFG_BOOT_MENU 0x0e 21 | #define FW_CFG_MAX_CPUS 0x0f 22 | #define FW_CFG_MAX_ENTRY 0x10 23 | 24 | #define FW_CFG_WRITE_CHANNEL 0x4000 25 | #define FW_CFG_ARCH_LOCAL 0x8000 26 | #define FW_CFG_ENTRY_MASK ~(FW_CFG_WRITE_CHANNEL | FW_CFG_ARCH_LOCAL) 27 | 28 | #define FW_CFG_INVALID 0xffff 29 | 30 | #define BIOS_CFG_IOPORT 0x510 31 | 32 | #define FW_CFG_ACPI_TABLES (FW_CFG_ARCH_LOCAL + 0) 33 | #define FW_CFG_SMBIOS_ENTRIES (FW_CFG_ARCH_LOCAL + 1) 34 | #define FW_CFG_IRQ0_OVERRIDE (FW_CFG_ARCH_LOCAL + 2) 35 | 36 | uint8_t fwcfg_get_u8(unsigned index); 37 | uint16_t fwcfg_get_u16(unsigned index); 38 | uint32_t fwcfg_get_u32(unsigned index); 39 | uint64_t fwcfg_get_u64(unsigned index); 40 | 41 | unsigned fwcfg_get_nb_cpus(void); 42 | 43 | #endif 44 | 45 | -------------------------------------------------------------------------------- /lib/x86/io.c: -------------------------------------------------------------------------------- 1 | #include "libcflat.h" 2 | #include "smp.h" 3 | #include "asm/io.h" 4 | #include "asm/page.h" 5 | #include "vmalloc.h" 6 | #ifndef USE_SERIAL 7 | #define USE_SERIAL 8 | #endif 9 | 10 | static struct spinlock lock; 11 | static int serial_iobase = 0x3f8; 12 | static int serial_inited = 0; 13 | 14 | static void serial_outb(char ch) 15 | { 16 | u8 lsr; 17 | 18 | do { 19 | lsr = inb(serial_iobase + 0x05); 20 | } while (!(lsr & 0x20)); 21 | 22 | outb(ch, serial_iobase + 0x00); 23 | } 24 | 25 | static void serial_put(char ch) 26 | { 27 | /* Force carriage return to be performed on \n */ 28 | if (ch == '\n') 29 | serial_outb('\r'); 30 | serial_outb(ch); 31 | } 32 | 33 | static void serial_init(void) 34 | { 35 | u8 lcr; 36 | 37 | /* set DLAB */ 38 | lcr = inb(serial_iobase + 0x03); 39 | lcr |= 0x80; 40 | outb(lcr, serial_iobase + 0x03); 41 | 42 | /* set baud rate to 115200 */ 43 | outb(0x01, serial_iobase + 0x00); 44 | outb(0x00, serial_iobase + 0x01); 45 | 46 | /* clear DLAB */ 47 | lcr = inb(serial_iobase + 0x03); 48 | lcr &= ~0x80; 49 | outb(lcr, serial_iobase + 0x03); 50 | 51 | /* IER: disable interrupts */ 52 | outb(0x00, serial_iobase + 0x01); 53 | /* LCR: 8 bits, no parity, one stop bit */ 54 | outb(0x03, serial_iobase + 0x03); 55 | /* FCR: disable FIFO queues */ 56 | outb(0x00, serial_iobase + 0x02); 57 | /* MCR: RTS, DTR on */ 58 | outb(0x03, serial_iobase + 0x04); 59 | } 60 | 61 | static void print_serial(const char *buf) 62 | { 63 | unsigned long len = strlen(buf); 64 | #ifdef USE_SERIAL 65 | unsigned long i; 66 | if (!serial_inited) { 67 | serial_init(); 68 | serial_inited = 1; 69 | } 70 | 71 | for (i = 0; i < len; i++) { 72 | serial_put(buf[i]); 73 | } 74 | #else 75 | asm volatile ("rep/outsb" : "+S"(buf), "+c"(len) : "d"(0xf1)); 76 | #endif 77 | } 78 | 79 | void puts(const char *s) 80 | { 81 | spin_lock(&lock); 82 | print_serial(s); 83 | spin_unlock(&lock); 84 | } 85 | 86 | void exit(int code) 87 | { 88 | #ifdef USE_SERIAL 89 | static const char shutdown_str[8] = "Shutdown"; 90 | int i; 91 | 92 | /* test device exit (with status) */ 93 | outl(code, 0xf4); 94 | 95 | /* if that failed, try the Bochs poweroff port */ 96 | for (i = 0; i < 8; i++) { 97 | outb(shutdown_str[i], 0x8900); 98 | } 99 | #else 100 | asm volatile("out %0, %1" : : "a"(code), "d"((short)0xf4)); 101 | #endif 102 | __builtin_unreachable(); 103 | } 104 | 105 | void __iomem *ioremap(phys_addr_t phys_addr, size_t size) 106 | { 107 | phys_addr_t base = phys_addr & PAGE_MASK; 108 | phys_addr_t offset = phys_addr - base; 109 | 110 | /* 111 | * The kernel sets PTEs for an ioremap() with page cache disabled, 112 | * but we do not do that right now. It would make sense that I/O 113 | * mappings would be uncached - and may help us find bugs when we 114 | * properly map that way. 115 | */ 116 | return vmap(phys_addr, size) + offset; 117 | } 118 | -------------------------------------------------------------------------------- /lib/x86/isr.h: -------------------------------------------------------------------------------- 1 | #ifndef __ISR_TEST__ 2 | #define __ISR_TEST__ 3 | 4 | typedef struct { 5 | ulong regs[sizeof(ulong)*2]; 6 | ulong func; 7 | ulong rip; 8 | ulong cs; 9 | ulong rflags; 10 | } isr_regs_t; 11 | 12 | void handle_irq(unsigned vec, void (*func)(isr_regs_t *regs)); 13 | void handle_external_interrupt(int vector); 14 | #endif 15 | -------------------------------------------------------------------------------- /lib/x86/setjmp32.S: -------------------------------------------------------------------------------- 1 | .globl setjmp 2 | setjmp: 3 | mov (%esp), %ecx // get return EIP 4 | mov 4(%esp), %eax // get jmp_buf 5 | mov %ecx, (%eax) 6 | mov %esp, 4(%eax) 7 | mov %ebp, 8(%eax) 8 | mov %ebx, 12(%eax) 9 | mov %esi, 16(%eax) 10 | mov %edi, 20(%eax) 11 | xor %eax, %eax 12 | ret 13 | 14 | .globl longjmp 15 | longjmp: 16 | mov 8(%esp), %eax // get return value 17 | mov 4(%esp), %ecx // get jmp_buf 18 | mov 20(%ecx), %edi 19 | mov 16(%ecx), %esi 20 | mov 12(%ecx), %ebx 21 | mov 8(%ecx), %ebp 22 | mov 4(%ecx), %esp 23 | mov (%ecx), %ecx // get saved EIP 24 | mov %ecx, (%esp) // and store it on the stack 25 | ret 26 | -------------------------------------------------------------------------------- /lib/x86/setjmp64.S: -------------------------------------------------------------------------------- 1 | .globl setjmp 2 | setjmp: 3 | mov (%rsp), %rsi 4 | mov %rsi, (%rdi) 5 | mov %rsp, 0x8(%rdi) 6 | mov %rbp, 0x10(%rdi) 7 | mov %rbx, 0x18(%rdi) 8 | mov %r12, 0x20(%rdi) 9 | mov %r13, 0x28(%rdi) 10 | mov %r14, 0x30(%rdi) 11 | mov %r15, 0x38(%rdi) 12 | xor %eax, %eax 13 | ret 14 | 15 | .globl longjmp 16 | longjmp: 17 | mov %esi, %eax 18 | mov 0x38(%rdi), %r15 19 | mov 0x30(%rdi), %r14 20 | mov 0x28(%rdi), %r13 21 | mov 0x20(%rdi), %r12 22 | mov 0x18(%rdi), %rbx 23 | mov 0x10(%rdi), %rbp 24 | mov 0x8(%rdi), %rsp 25 | mov (%rdi), %rsi 26 | mov %rsi, (%rsp) 27 | ret 28 | -------------------------------------------------------------------------------- /lib/x86/setup.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Initialize machine setup information 3 | * 4 | * Copyright (C) 2017, Red Hat Inc, Andrew Jones 5 | * 6 | * This work is licensed under the terms of the GNU LGPL, version 2. 7 | */ 8 | #include "libcflat.h" 9 | #include "fwcfg.h" 10 | #include "alloc_phys.h" 11 | 12 | extern char edata; 13 | 14 | struct mbi_bootinfo { 15 | u32 flags; 16 | u32 mem_lower; 17 | u32 mem_upper; 18 | u32 boot_device; 19 | u32 cmdline; 20 | u32 mods_count; 21 | u32 mods_addr; 22 | u32 reserved[5]; /* 28-47 */ 23 | u32 mmap_addr; 24 | u32 reserved0[3]; /* 52-63 */ 25 | u32 bootloader; 26 | u32 reserved1[5]; /* 68-87 */ 27 | u32 size; 28 | }; 29 | 30 | struct mbi_module { 31 | u32 start, end; 32 | u32 cmdline; 33 | u32 unused; 34 | }; 35 | 36 | #define ENV_SIZE 16384 37 | 38 | void setup_env(char *env, int size); 39 | void setup_multiboot(struct mbi_bootinfo *bootinfo); 40 | void setup_libcflat(void); 41 | 42 | char *initrd; 43 | u32 initrd_size; 44 | 45 | static char env[ENV_SIZE]; 46 | 47 | void setup_multiboot(struct mbi_bootinfo *bootinfo) 48 | { 49 | struct mbi_module *mods; 50 | 51 | /* TODO: use e820 */ 52 | u64 end_of_memory = bootinfo->mem_upper * 1024ull; 53 | phys_alloc_init((uintptr_t) &edata, end_of_memory - (uintptr_t) &edata); 54 | 55 | if (bootinfo->mods_count != 1) 56 | return; 57 | 58 | mods = (struct mbi_module *)(uintptr_t) bootinfo->mods_addr; 59 | 60 | initrd = (char *)(uintptr_t) mods->start; 61 | initrd_size = mods->end - mods->start; 62 | } 63 | 64 | void setup_libcflat(void) 65 | { 66 | if (initrd) { 67 | /* environ is currently the only file in the initrd */ 68 | u32 size = MIN(initrd_size, ENV_SIZE); 69 | memcpy(env, initrd, size); 70 | setup_env(env, size); 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /lib/x86/smp.c: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #include "processor.h" 4 | #include "atomic.h" 5 | #include "smp.h" 6 | #include "apic.h" 7 | #include "fwcfg.h" 8 | #include "desc.h" 9 | 10 | #define IPI_VECTOR 0x20 11 | 12 | typedef void (*ipi_function_type)(void *data); 13 | 14 | static struct spinlock ipi_lock; 15 | static volatile ipi_function_type ipi_function; 16 | static void *volatile ipi_data; 17 | static volatile int ipi_done; 18 | static volatile bool ipi_wait; 19 | static int _cpu_count; 20 | static atomic_t active_cpus; 21 | 22 | static __attribute__((used)) void ipi(void) 23 | { 24 | void (*function)(void *data) = ipi_function; 25 | void *data = ipi_data; 26 | bool wait = ipi_wait; 27 | 28 | if (!wait) { 29 | ipi_done = 1; 30 | apic_write(APIC_EOI, 0); 31 | } 32 | function(data); 33 | atomic_dec(&active_cpus); 34 | if (wait) { 35 | ipi_done = 1; 36 | apic_write(APIC_EOI, 0); 37 | } 38 | } 39 | 40 | asm ( 41 | "ipi_entry: \n" 42 | " call ipi \n" 43 | #ifndef __x86_64__ 44 | " iret" 45 | #else 46 | " iretq" 47 | #endif 48 | ); 49 | 50 | int cpu_count(void) 51 | { 52 | return _cpu_count; 53 | } 54 | 55 | int smp_id(void) 56 | { 57 | unsigned id; 58 | 59 | asm ("mov %%gs:0, %0" : "=r"(id)); 60 | return id; 61 | } 62 | 63 | static void setup_smp_id(void *data) 64 | { 65 | asm ("mov %0, %%gs:0" : : "r"(apic_id()) : "memory"); 66 | } 67 | 68 | static void __on_cpu(int cpu, void (*function)(void *data), void *data, 69 | int wait) 70 | { 71 | spin_lock(&ipi_lock); 72 | if (cpu == smp_id()) 73 | function(data); 74 | else { 75 | atomic_inc(&active_cpus); 76 | ipi_done = 0; 77 | ipi_function = function; 78 | ipi_data = data; 79 | ipi_wait = wait; 80 | apic_icr_write(APIC_INT_ASSERT | APIC_DEST_PHYSICAL | APIC_DM_FIXED 81 | | IPI_VECTOR, 82 | cpu); 83 | while (!ipi_done) 84 | ; 85 | } 86 | spin_unlock(&ipi_lock); 87 | } 88 | 89 | void on_cpu(int cpu, void (*function)(void *data), void *data) 90 | { 91 | __on_cpu(cpu, function, data, 1); 92 | } 93 | 94 | void on_cpu_async(int cpu, void (*function)(void *data), void *data) 95 | { 96 | __on_cpu(cpu, function, data, 0); 97 | } 98 | 99 | void on_cpus(void (*function)(void *data), void *data) 100 | { 101 | int cpu; 102 | 103 | for (cpu = cpu_count() - 1; cpu >= 0; --cpu) 104 | on_cpu_async(cpu, function, data); 105 | 106 | while (cpus_active() > 1) 107 | pause(); 108 | } 109 | 110 | int cpus_active(void) 111 | { 112 | return atomic_read(&active_cpus); 113 | } 114 | 115 | void smp_init(void) 116 | { 117 | int i; 118 | void ipi_entry(void); 119 | 120 | _cpu_count = fwcfg_get_nb_cpus(); 121 | 122 | setup_idt(); 123 | set_idt_entry(IPI_VECTOR, ipi_entry, 0); 124 | 125 | setup_smp_id(0); 126 | for (i = 1; i < cpu_count(); ++i) 127 | on_cpu(i, setup_smp_id, 0); 128 | 129 | atomic_inc(&active_cpus); 130 | } 131 | -------------------------------------------------------------------------------- /lib/x86/smp.h: -------------------------------------------------------------------------------- 1 | #ifndef __SMP_H 2 | #define __SMP_H 3 | #include 4 | 5 | void smp_init(void); 6 | 7 | int cpu_count(void); 8 | int smp_id(void); 9 | int cpus_active(void); 10 | void on_cpu(int cpu, void (*function)(void *data), void *data); 11 | void on_cpu_async(int cpu, void (*function)(void *data), void *data); 12 | void on_cpus(void (*function)(void *data), void *data); 13 | 14 | #endif 15 | -------------------------------------------------------------------------------- /lib/x86/stack.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | int backtrace_frame(const void *frame, const void **return_addrs, int max_depth) 5 | { 6 | static int walking; 7 | int depth = 0; 8 | const unsigned long *bp = (unsigned long *) frame; 9 | 10 | if (walking) { 11 | printf("RECURSIVE STACK WALK!!!\n"); 12 | return 0; 13 | } 14 | walking = 1; 15 | 16 | for (depth = 0; bp && depth < max_depth; depth++) { 17 | return_addrs[depth] = (void *) bp[1]; 18 | if (return_addrs[depth] == 0) 19 | break; 20 | bp = (unsigned long *) bp[0]; 21 | } 22 | 23 | walking = 0; 24 | return depth; 25 | } 26 | 27 | int backtrace(const void **return_addrs, int max_depth) 28 | { 29 | return backtrace_frame(__builtin_frame_address(0), return_addrs, 30 | max_depth); 31 | } 32 | -------------------------------------------------------------------------------- /lib/x86/usermode.c: -------------------------------------------------------------------------------- 1 | #include "x86/msr.h" 2 | #include "x86/processor.h" 3 | #include "x86/apic-defs.h" 4 | #include "x86/apic.h" 5 | #include "x86/desc.h" 6 | #include "x86/isr.h" 7 | #include "alloc.h" 8 | #include "setjmp.h" 9 | #include "usermode.h" 10 | 11 | #include "libcflat.h" 12 | #include 13 | 14 | #define USERMODE_STACK_SIZE 0x2000 15 | #define RET_TO_KERNEL_IRQ 0x20 16 | 17 | jmp_buf jmpbuf; 18 | 19 | static void restore_exec_to_jmpbuf(void) 20 | { 21 | longjmp(jmpbuf, 1); 22 | } 23 | 24 | static void restore_exec_to_jmpbuf_exception_handler(struct ex_regs *regs) 25 | { 26 | /* longjmp must happen after iret, so do not do it now. */ 27 | regs->rip = (unsigned long)&restore_exec_to_jmpbuf; 28 | regs->cs = KERNEL_CS; 29 | } 30 | 31 | uint64_t run_in_user(usermode_func func, unsigned int fault_vector, 32 | uint64_t arg1, uint64_t arg2, uint64_t arg3, 33 | uint64_t arg4, bool *raised_vector) 34 | { 35 | extern char ret_to_kernel; 36 | uint64_t rax = 0; 37 | static unsigned char user_stack[USERMODE_STACK_SIZE]; 38 | 39 | *raised_vector = 0; 40 | set_idt_entry(RET_TO_KERNEL_IRQ, &ret_to_kernel, 3); 41 | handle_exception(fault_vector, 42 | restore_exec_to_jmpbuf_exception_handler); 43 | 44 | if (setjmp(jmpbuf) != 0) { 45 | *raised_vector = 1; 46 | return 0; 47 | } 48 | 49 | asm volatile ( 50 | /* Backing Up Stack in rdi */ 51 | "mov %%rsp, %%rdi\n\t" 52 | /* Load user_ds to DS and ES */ 53 | "mov %[user_ds], %%ax\n\t" 54 | "mov %%ax, %%ds\n\t" 55 | "mov %%ax, %%es\n\t" 56 | /* IRET into user mode */ 57 | "pushq %[user_ds]\n\t" 58 | "pushq %[user_stack_top]\n\t" 59 | "pushfq\n\t" 60 | "pushq %[user_cs]\n\t" 61 | "pushq $user_mode\n\t" 62 | "iretq\n" 63 | 64 | "user_mode:\n\t" 65 | /* Back up registers before invoking func */ 66 | "push %%rbx\n\t" 67 | "push %%rcx\n\t" 68 | "push %%rdx\n\t" 69 | "push %%r8\n\t" 70 | "push %%r9\n\t" 71 | "push %%r10\n\t" 72 | "push %%r11\n\t" 73 | "push %%rdi\n\t" 74 | "push %%rsi\n\t" 75 | /* Call user mode function */ 76 | "mov %[arg1], %%rdi\n\t" 77 | "mov %[arg2], %%rsi\n\t" 78 | "mov %[arg3], %%rdx\n\t" 79 | "mov %[arg4], %%rcx\n\t" 80 | "call *%[func]\n\t" 81 | /* Restore registers */ 82 | "pop %%rsi\n\t" 83 | "pop %%rdi\n\t" 84 | "pop %%r11\n\t" 85 | "pop %%r10\n\t" 86 | "pop %%r9\n\t" 87 | "pop %%r8\n\t" 88 | "pop %%rdx\n\t" 89 | "pop %%rcx\n\t" 90 | "pop %%rbx\n\t" 91 | /* Return to kernel via system call */ 92 | "int %[kernel_entry_vector]\n\t" 93 | /* Kernel Mode */ 94 | "ret_to_kernel:\n\t" 95 | "mov %%rdi, %%rsp\n\t" 96 | : 97 | "+a"(rax) 98 | : 99 | [arg1]"m"(arg1), 100 | [arg2]"m"(arg2), 101 | [arg3]"m"(arg3), 102 | [arg4]"m"(arg4), 103 | [func]"m"(func), 104 | [user_ds]"i"(USER_DS), 105 | [user_cs]"i"(USER_CS), 106 | [user_stack_top]"r"(user_stack + 107 | sizeof(user_stack)), 108 | [kernel_entry_vector]"i"(RET_TO_KERNEL_IRQ) 109 | : 110 | "rsi", "rdi", "rcx", "rdx"); 111 | 112 | return rax; 113 | } 114 | -------------------------------------------------------------------------------- /lib/x86/usermode.h: -------------------------------------------------------------------------------- 1 | #ifndef _USERMODE_H_ 2 | #define _USERMODE_H_ 3 | 4 | #include "x86/msr.h" 5 | #include "x86/processor.h" 6 | #include "x86/apic-defs.h" 7 | #include "x86/apic.h" 8 | #include "x86/desc.h" 9 | #include "x86/isr.h" 10 | #include "alloc.h" 11 | #include "setjmp.h" 12 | 13 | #include "libcflat.h" 14 | #include 15 | 16 | typedef uint64_t (*usermode_func)(void); 17 | 18 | /* 19 | * Run function in user mode 20 | * Supports running functions with up to 4 arguments. 21 | * fault_vector: exception vector that might get thrown during the function. 22 | * raised_vector: outputs true if exception occurred. 23 | * 24 | * returns: return value returned by function, or 0 if an exception occurred. 25 | */ 26 | uint64_t run_in_user(usermode_func func, unsigned int fault_vector, 27 | uint64_t arg1, uint64_t arg2, uint64_t arg3, 28 | uint64_t arg4, bool *raised_vector); 29 | 30 | #endif 31 | -------------------------------------------------------------------------------- /lib/x86/vm.h: -------------------------------------------------------------------------------- 1 | #ifndef VM_H 2 | #define VM_H 3 | 4 | #include "processor.h" 5 | #include "asm/page.h" 6 | #include "asm/io.h" 7 | 8 | void setup_5level_page_table(void); 9 | 10 | struct pte_search { 11 | int level; 12 | pteval_t *pte; 13 | }; 14 | 15 | static inline bool found_huge_pte(struct pte_search search) 16 | { 17 | return (search.level == 2 || search.level == 3) && 18 | (*search.pte & PT_PRESENT_MASK) && 19 | (*search.pte & PT_PAGE_SIZE_MASK); 20 | } 21 | 22 | static inline bool found_leaf_pte(struct pte_search search) 23 | { 24 | return search.level == 1 || found_huge_pte(search); 25 | } 26 | 27 | struct pte_search find_pte_level(pgd_t *cr3, void *virt, 28 | int lowest_level); 29 | pteval_t *get_pte(pgd_t *cr3, void *virt); 30 | pteval_t *get_pte_level(pgd_t *cr3, void *virt, int pte_level); 31 | pteval_t *install_pte(pgd_t *cr3, 32 | int pte_level, 33 | void *virt, 34 | pteval_t pte, 35 | pteval_t *pt_page); 36 | 37 | pteval_t *install_large_page(pgd_t *cr3, phys_addr_t phys, void *virt); 38 | void install_pages(pgd_t *cr3, phys_addr_t phys, size_t len, void *virt); 39 | bool any_present_pages(pgd_t *cr3, void *virt, size_t len); 40 | 41 | static inline void *current_page_table(void) 42 | { 43 | return phys_to_virt(read_cr3()); 44 | } 45 | 46 | void split_large_page(unsigned long *ptep, int level); 47 | void force_4k_page(void *addr); 48 | #endif 49 | -------------------------------------------------------------------------------- /scripts/asm-offsets.mak: -------------------------------------------------------------------------------- 1 | # 2 | # asm-offsets adapted from the kernel, see 3 | # Kbuild 4 | # scripts/Kbuild.include 5 | # scripts/Makefile.build 6 | # 7 | # Authors: Andrew Jones 8 | # 9 | 10 | define sed-y 11 | "/^->/{s:->#\(.*\):/* \1 */:; \ 12 | s:^->\([^ ]*\) [\$$#]*\([-0-9]*\) \(.*\):#define \1 \2 /* \3 */:; \ 13 | s:^->\([^ ]*\) [\$$#]*\([^ ]*\) \(.*\):#define \1 \2 /* \3 */:; \ 14 | s:->::; p;}" 15 | endef 16 | 17 | define make_asm_offsets 18 | (set -e; \ 19 | echo "#ifndef __ASM_OFFSETS_H__"; \ 20 | echo "#define __ASM_OFFSETS_H__"; \ 21 | echo "/*"; \ 22 | echo " * Generated file. DO NOT MODIFY."; \ 23 | echo " *"; \ 24 | echo " */"; \ 25 | echo ""; \ 26 | sed -ne $(sed-y) $<; \ 27 | echo ""; \ 28 | echo "#endif" ) > $@ 29 | endef 30 | 31 | $(asm-offsets:.h=.s): $(asm-offsets:.h=.c) 32 | $(CC) $(CFLAGS) -fverbose-asm -S -o $@ $< 33 | 34 | $(asm-offsets): $(asm-offsets:.h=.s) 35 | $(call make_asm_offsets) 36 | cp -f $(asm-offsets) lib/generated/ 37 | 38 | OBJDIRS += lib/generated 39 | 40 | asm_offsets_clean: 41 | $(RM) $(asm-offsets) $(asm-offsets:.h=.s) \ 42 | $(addprefix lib/generated/,$(notdir $(asm-offsets))) 43 | 44 | -------------------------------------------------------------------------------- /scripts/common.bash: -------------------------------------------------------------------------------- 1 | 2 | function for_each_unittest() 3 | { 4 | local unittests="$1" 5 | local cmd="$2" 6 | local testname 7 | local smp 8 | local kernel 9 | local opts 10 | local groups 11 | local arch 12 | local check 13 | local accel 14 | local timeout 15 | 16 | exec {fd}<"$unittests" 17 | 18 | while read -r -u $fd line; do 19 | if [[ "$line" =~ ^\[(.*)\]$ ]]; then 20 | "$cmd" "$testname" "$groups" "$smp" "$kernel" "$opts" "$arch" "$check" "$accel" "$timeout" 21 | testname=${BASH_REMATCH[1]} 22 | smp=1 23 | kernel="" 24 | opts="" 25 | groups="" 26 | arch="" 27 | check="" 28 | accel="" 29 | timeout="" 30 | elif [[ $line =~ ^file\ *=\ *(.*)$ ]]; then 31 | kernel=$TEST_DIR/${BASH_REMATCH[1]} 32 | elif [[ $line =~ ^smp\ *=\ *(.*)$ ]]; then 33 | smp=${BASH_REMATCH[1]} 34 | elif [[ $line =~ ^extra_params\ *=\ *(.*)$ ]]; then 35 | opts=${BASH_REMATCH[1]} 36 | elif [[ $line =~ ^groups\ *=\ *(.*)$ ]]; then 37 | groups=${BASH_REMATCH[1]} 38 | elif [[ $line =~ ^arch\ *=\ *(.*)$ ]]; then 39 | arch=${BASH_REMATCH[1]} 40 | elif [[ $line =~ ^check\ *=\ *(.*)$ ]]; then 41 | check=${BASH_REMATCH[1]} 42 | elif [[ $line =~ ^accel\ *=\ *(.*)$ ]]; then 43 | accel=${BASH_REMATCH[1]} 44 | elif [[ $line =~ ^timeout\ *=\ *(.*)$ ]]; then 45 | timeout=${BASH_REMATCH[1]} 46 | fi 47 | done 48 | "$cmd" "$testname" "$groups" "$smp" "$kernel" "$opts" "$arch" "$check" "$accel" "$timeout" 49 | exec {fd}<&- 50 | } 51 | -------------------------------------------------------------------------------- /scripts/git.difforder: -------------------------------------------------------------------------------- 1 | COPYRIGHT 2 | MAINTAINERS 3 | *README 4 | scripts/*.mak 5 | scripts/*.py 6 | scripts/*.bash 7 | scripts/*.sh 8 | scripts/* 9 | */run 10 | run_tests.sh 11 | configure 12 | *Makefile* 13 | *.mak 14 | lib/*.lds 15 | lib/linux/* 16 | lib/asm-generic/* 17 | lib/*/asm/* 18 | lib/*.h 19 | lib/*.S 20 | lib/*.c 21 | *.lds 22 | *.h 23 | *.S 24 | *.c 25 | *.cfg 26 | -------------------------------------------------------------------------------- /scripts/mkstandalone.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | if [ ! -f config.mak ]; then 4 | echo "run ./configure && make first. See ./configure -h" 5 | exit 1 6 | fi 7 | source config.mak 8 | source scripts/common.bash 9 | 10 | temp_file () 11 | { 12 | local var="$1" 13 | local file="${2:--}" 14 | 15 | echo "$var=\`mktemp\`" 16 | echo "cleanup=\"\$$var \$cleanup\"" 17 | echo "base64 -d << 'BIN_EOF' | zcat > \$$var || exit 2" 18 | 19 | gzip -c "$file" | base64 20 | 21 | echo "BIN_EOF" 22 | echo "chmod +x \$$var" 23 | } 24 | 25 | config_export () 26 | { 27 | echo "export $(grep ^${1}= config.mak)" 28 | } 29 | 30 | generate_test () 31 | { 32 | local args=() 33 | for arg in "${@}"; do 34 | args+=("$(printf "%q" "$arg")") 35 | done 36 | 37 | echo "#!/usr/bin/env bash" 38 | echo "export STANDALONE=yes" 39 | echo "export ENVIRON_DEFAULT=yes" 40 | echo "export HOST=\$(uname -m | sed -e 's/i.86/i386/;s/arm.*/arm/;s/ppc64.*/ppc64/')" 41 | echo "export PRETTY_PRINT_STACKS=no" 42 | 43 | config_export ARCH 44 | config_export ARCH_NAME 45 | config_export PROCESSOR 46 | 47 | echo "echo BUILD_HEAD=$(cat build-head)" 48 | 49 | if [ ! -f $kernel ]; then 50 | echo 'echo "skip '"$testname"' (test kernel not present)"' 51 | echo 'exit 2' 52 | return 53 | fi 54 | 55 | echo "trap 'rm -f \$cleanup' EXIT" 56 | 57 | if [ "$FIRMWARE" ]; then 58 | temp_file FIRMWARE "$FIRMWARE" 59 | echo 'export FIRMWARE' 60 | fi 61 | 62 | if [ "$ERRATATXT" ]; then 63 | temp_file ERRATATXT "$ERRATATXT" 64 | echo 'export ERRATATXT' 65 | fi 66 | 67 | temp_file bin "$kernel" 68 | args[3]='$bin' 69 | 70 | (echo "#!/usr/bin/env bash" 71 | cat scripts/arch-run.bash "$TEST_DIR/run") | temp_file RUNTIME_arch_run 72 | 73 | echo "exec {stdout}>&1" 74 | echo "RUNTIME_log_stdout () { cat >&\$stdout; }" 75 | echo "RUNTIME_log_stderr () { cat >&2; }" 76 | 77 | cat scripts/runtime.bash 78 | 79 | echo "run ${args[@]}" 80 | } 81 | 82 | function mkstandalone() 83 | { 84 | local testname="$1" 85 | 86 | if [ -z "$testname" ]; then 87 | return 88 | fi 89 | 90 | if [ -n "$one_testname" ] && [ "$testname" != "$one_testname" ]; then 91 | return 92 | fi 93 | 94 | standalone=tests/$testname 95 | 96 | generate_test "$@" > $standalone 97 | 98 | chmod +x $standalone 99 | echo Written $standalone. 100 | } 101 | 102 | trap 'rm -f $cfg' EXIT 103 | cfg=$(mktemp) 104 | 105 | unittests=$TEST_DIR/unittests.cfg 106 | one_kernel="$1" 107 | 108 | if [ "$one_kernel" ]; then 109 | [ ! -f $one_kernel ] && { 110 | echo "$one_kernel doesn't exist" 111 | exit 1 112 | } 113 | 114 | one_kernel_base=$(basename $one_kernel) 115 | one_testname="${2:-${one_kernel_base%.*}}" 116 | 117 | if grep -q "\[$one_testname\]" $unittests; then 118 | sed -n "/\\[$one_testname\\]/,/^\\[/p" $unittests \ 119 | | awk '!/^\[/ || NR == 1' > $cfg 120 | else 121 | echo "[$one_testname]" > $cfg 122 | echo "file = $one_kernel_base" >> $cfg 123 | fi 124 | else 125 | cp -f $unittests $cfg 126 | fi 127 | 128 | mkdir -p tests 129 | 130 | for_each_unittest $cfg mkstandalone 131 | -------------------------------------------------------------------------------- /scripts/pretty_print_stacks.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | import re 4 | import subprocess 5 | import sys 6 | import traceback 7 | 8 | config = {} 9 | 10 | # Subvert output buffering. 11 | def puts(string): 12 | sys.stdout.write(string) 13 | sys.stdout.flush() 14 | 15 | def pretty_print_stack(binary, line): 16 | addrs = line.split()[1:] 17 | # Addresses are return addresses unless preceded by a '@'. We want the 18 | # caller address so line numbers are more intuitive. Thus we subtract 1 19 | # from the address to get the call code. 20 | for i in range(len(addrs)): 21 | addr = addrs[i] 22 | if addr.startswith('@'): 23 | addrs[i] = addr[1:] 24 | else: 25 | addrs[i] = '%lx' % (int(addrs[i], 16) - 1) 26 | 27 | # Output like this: 28 | # 0x004002be: start64 at path/to/kvm-unit-tests/x86/cstart64.S:208 29 | # (inlined by) test_ept_violation at path/to/kvm-unit-tests/x86/vmx_tests.c:1719 (discriminator 1) 30 | cmd = [config.get('ADDR2LINE', 'addr2line'), '-e', binary, '-i', '-f', '--pretty', '--address'] 31 | cmd.extend(addrs) 32 | 33 | p = subprocess.Popen(cmd, stdout=subprocess.PIPE) 34 | out, err = p.communicate() 35 | if p.returncode != 0: 36 | puts(line) 37 | return 38 | 39 | for line in out.splitlines(): 40 | m = re.match(b'(.*) at [^ ]*/kvm-unit-tests/([^ ]*):([0-9]+)(.*)', line) 41 | if m is None: 42 | puts('%s\n' % line) 43 | return 44 | 45 | head, path, line, tail = m.groups() 46 | line = int(line) 47 | puts('%s at %s:%d%s\n' % (head.decode(), path.decode(), line, tail.decode())) 48 | try: 49 | lines = open(path).readlines() 50 | except IOError: 51 | continue 52 | if line > 1: 53 | puts(' %s\n' % lines[line - 2].rstrip()) 54 | puts(' > %s\n' % lines[line - 1].rstrip()) 55 | if line < len(lines): 56 | puts(' %s\n' % lines[line].rstrip()) 57 | 58 | def main(): 59 | if len(sys.argv) != 2: 60 | sys.stderr.write('usage: %s \n' % sys.argv[0]) 61 | sys.exit(1) 62 | 63 | binary = sys.argv[1].replace(".flat", ".elf") 64 | 65 | with open("config.mak") as config_file: 66 | for line in config_file: 67 | name, val = line.partition("=")[::2] 68 | config[name.strip()] = val.strip() 69 | 70 | try: 71 | while True: 72 | # Subvert input buffering. 73 | line = sys.stdin.readline() 74 | if line == '': 75 | break 76 | 77 | puts(line) 78 | 79 | if not line.strip().startswith('STACK:'): 80 | continue 81 | 82 | try: 83 | pretty_print_stack(binary, line) 84 | except Exception: 85 | puts('Error pretty printing stack:\n') 86 | puts(traceback.format_exc()) 87 | puts('Continuing without pretty printing...\n') 88 | while True: 89 | puts(line) 90 | line = sys.stdin.readline() 91 | if line == '': 92 | break 93 | except: 94 | sys.exit(1) 95 | 96 | if __name__ == '__main__': 97 | main() 98 | -------------------------------------------------------------------------------- /x86/Makefile: -------------------------------------------------------------------------------- 1 | include $(SRCDIR)/$(ASOR_DIR)/Makefile.$(ARCH) 2 | -------------------------------------------------------------------------------- /x86/Makefile.common: -------------------------------------------------------------------------------- 1 | #This is a make file with common rules for both x86 & x86-64 2 | 3 | all: directories asor_cases 4 | 5 | asorobjs += lib/pci.o 6 | asorobjs += lib/pci-edu.o 7 | asorobjs += lib/alloc.o 8 | asorobjs += lib/vmalloc.o 9 | asorobjs += lib/alloc_page.o 10 | asorobjs += lib/alloc_phys.o 11 | asorobjs += lib/elf.o 12 | asorobjs += lib/x86/setup.o 13 | asorobjs += lib/x86/io.o 14 | asorobjs += lib/x86/smp.o 15 | asorobjs += lib/x86/vm.o 16 | asorobjs += lib/x86/fwcfg.o 17 | asorobjs += lib/x86/apic.o 18 | asorobjs += lib/x86/atomic.o 19 | asorobjs += lib/x86/desc.o 20 | asorobjs += lib/x86/isr.o 21 | asorobjs += lib/x86/acpi.o 22 | asorobjs += lib/x86/stack.o 23 | asorobjs += lib/x86/fault_test.o 24 | asorobjs += lib/x86/delay.o 25 | asorobjs += x86/vmx.o 26 | asorobjs += x86/ept.o 27 | asorobjs += x86/vm.o 28 | 29 | OBJDIRS += lib/x86 30 | 31 | $(libasor): LDFLAGS += -nostdlib 32 | $(libasor): CFLAGS += -ffreestanding -I $(SRCDIR)/lib -I lib -I $(SRCDIR)/include 33 | 34 | COMMON_CFLAGS += -m$(bits) 35 | COMMON_CFLAGS += -O1 36 | 37 | # stack.o relies on frame pointers. 38 | KEEP_FRAME_POINTER := y 39 | 40 | libgcc := $(shell $(CC) -m$(bits) --print-libgcc-file-name) 41 | 42 | # We want to keep intermediate file: %.elf and %.o 43 | .PRECIOUS: %.elf %.o 44 | 45 | FLATLIBS = lib/libasor.a $(libgcc) 46 | %.elf: %.o $(FLATLIBS) $(SRCDIR)/x86/flat.lds $(cstart.o) 47 | $(CC) $(CFLAGS) -nostdlib -o $@ -Wl,-T,$(SRCDIR)/x86/flat.lds \ 48 | $(filter %.o, $^) $(FLATLIBS) 49 | @chmod a-x $@ 50 | 51 | %.flat: %.elf 52 | $(OBJCOPY) -O elf32-i386 $^ $@ 53 | @chmod a-x $@ 54 | 55 | asor_cases: $(asor) 56 | 57 | $(ASOR_DIR)/%.o: CFLAGS += -std=gnu99 -ffreestanding -I $(SRCDIR)/lib -I $(SRCDIR)/lib/x86 -I lib -I $(SRCDIR)/include 58 | 59 | arch_clean: 60 | $(RM) $(ASOR_DIR)/*.o $(ASOR_DIR)/*.flat $(ASOR_DIR)/*.elf $(ASOR_DIR)/.*.d \ 61 | lib/x86/.*.d driver/.*.d \ 62 | 63 | 64 | -------------------------------------------------------------------------------- /x86/Makefile.i386: -------------------------------------------------------------------------------- 1 | cstart.o = $(ASOR_DIR)/cstart.o 2 | bits = 32 3 | ldarch = elf32-i386 4 | 5 | asorobjs += lib/x86/setjmp32.o 6 | 7 | asor = $(ASOR_DIR)/asor.flat 8 | 9 | include $(SRCDIR)/$(ASOR_DIR)/Makefile.common 10 | -------------------------------------------------------------------------------- /x86/Makefile.x86_64: -------------------------------------------------------------------------------- 1 | cstart.o = $(ASOR_DIR)/cstart64.o 2 | bits = 64 3 | ldarch = elf64-x86-64 4 | COMMON_CFLAGS += -mno-red-zone -mno-sse -mno-sse2 -DX64 5 | 6 | asorobjs += lib/x86/setjmp64.o 7 | asorobjs += lib/x86/intel-iommu.o 8 | asorobjs += lib/x86/usermode.o 9 | 10 | asor = $(ASOR_DIR)/asor.flat 11 | 12 | include $(SRCDIR)/$(ASOR_DIR)/Makefile.common 13 | -------------------------------------------------------------------------------- /x86/asor.c: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0 2 | /* 3 | * ASOR Hypervisor. 4 | * 5 | * Author: Jie Deng 6 | */ 7 | 8 | #include "libcflat.h" 9 | #include "virt.h" 10 | #include "vmx.h" 11 | 12 | int asor_entry(void); 13 | int asor_entry(void) 14 | { 15 | setup_vm(); 16 | 17 | printf("Hello ASOR.\n"); 18 | 19 | register_virt_ops(get_x86_virt_arch_ops()); 20 | enable_hw_virt(); 21 | 22 | while (1) { 23 | asm volatile ("hlt"); 24 | } 25 | 26 | return 0; 27 | } 28 | -------------------------------------------------------------------------------- /x86/ept.h: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0 2 | /* 3 | * ASOR Hypervisor. 4 | * 5 | * Author: Jie Deng 6 | */ 7 | 8 | #ifndef __EPT_H__ 9 | #define __EPT_H__ 10 | 11 | #include "libcflat.h" 12 | 13 | int setup_ept(bool enable_ad); 14 | 15 | #endif /* __EPT_H__ */ 16 | 17 | -------------------------------------------------------------------------------- /x86/flat.lds: -------------------------------------------------------------------------------- 1 | SECTIONS 2 | { 3 | . = 4M + SIZEOF_HEADERS; 4 | stext = .; 5 | .text : { *(.init) *(.text) *(.text.*) } 6 | . = ALIGN(4K); 7 | .data : { 8 | *(.data) 9 | exception_table_start = .; 10 | *(.data.ex) 11 | exception_table_end = .; 12 | } 13 | . = ALIGN(16); 14 | .rodata : { *(.rodata) } 15 | . = ALIGN(16); 16 | .bss : { *(.bss) } 17 | . = ALIGN(4K); 18 | edata = .; 19 | } 20 | 21 | ENTRY(start) 22 | -------------------------------------------------------------------------------- /x86/run: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | if [ -z "$STANDALONE" ]; then 4 | if [ ! -f config.mak ]; then 5 | echo "run ./configure && make first. See ./configure -h" 6 | exit 2 7 | fi 8 | source config.mak 9 | source scripts/arch-run.bash 10 | fi 11 | 12 | ACCEL=$(get_qemu_accelerator) || 13 | exit $? 14 | 15 | qemu=$(search_qemu_binary) || 16 | exit $? 17 | 18 | if ! ${qemu} -device '?' 2>&1 | grep -F -e \"testdev\" -e \"pc-testdev\" > /dev/null; 19 | then 20 | echo "No Qemu test device support found" 21 | exit 2 22 | fi 23 | 24 | if 25 | ${qemu} -device '?' 2>&1 | grep -F "pci-testdev" > /dev/null; 26 | then 27 | pci_testdev="-device pci-testdev" 28 | else 29 | pci_testdev="" 30 | fi 31 | 32 | if 33 | ${qemu} -device '?' 2>&1 | grep -F "pc-testdev" > /dev/null; 34 | then 35 | pc_testdev="-device pc-testdev -device isa-debug-exit,iobase=0xf4,iosize=0x4" 36 | else 37 | pc_testdev="-device testdev,chardev=testlog -chardev file,id=testlog,path=msr.out" 38 | fi 39 | 40 | command="${qemu} -nodefaults $pc_testdev -vnc none -serial stdio $pci_testdev" 41 | command+=" -smp cpus=2 -machine accel=$ACCEL -kernel" 42 | command="$(timeout_cmd) $command" 43 | 44 | run_qemu ${command} "$@" 45 | -------------------------------------------------------------------------------- /x86/vm.c: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0 2 | /* 3 | * ASOR Hypervisor. 4 | * 5 | * Author: Jie Deng 6 | */ 7 | 8 | #include "libcflat.h" 9 | #include "vmx.h" 10 | 11 | static void asor_guest_main(void) 12 | { 13 | printf("Hello Guest\n"); 14 | } 15 | 16 | static int asor_guest_exit_handler(void) 17 | { 18 | print_vmexit_info(); 19 | return VMX_EXIT; 20 | } 21 | 22 | struct asor_guest asor_guests[] = { 23 | { "default guest", NULL, asor_guest_main, asor_guest_exit_handler, NULL, {0} }, 24 | { NULL, NULL, NULL, NULL, NULL, {0} }, 25 | }; 26 | 27 | --------------------------------------------------------------------------------