├── Makefile ├── README.md ├── benchmark ├── Makefile ├── hypercall.c ├── idle.c ├── idt_test.c ├── in.c ├── ipi.c ├── lgdt.c ├── memory-cold.c ├── memory-hot.c ├── memory-pt.c ├── out.c ├── print.c ├── pushf_popf.c ├── set-cr3.c ├── sgdt.c ├── sidt.c └── smsw.c ├── harness ├── Makefile └── harness.c ├── host ├── Makefile ├── host.c └── rdtsc.h ├── include ├── apic.h ├── asm.h ├── atomic.h ├── benchmark.h ├── defs.h ├── desc.h ├── io.h ├── ioram.h ├── memlayout.h ├── mmu.h ├── mp.h ├── msr.h ├── multiboot.h ├── page.h ├── param.h ├── proc.h ├── processor.h ├── rdtsc.h ├── spinlock.h ├── stack.h ├── traps.h └── types.h ├── lib ├── abort.c ├── printf.c ├── stack.c └── string.c ├── script ├── hyperbench.hvm ├── pin ├── qemu └── xen └── x86_64 ├── Makefile ├── apic.c ├── console.c ├── cstart.S ├── desc.c ├── entryother.S ├── heap.c ├── kernel.ld ├── main.c ├── mp.c ├── proc.c ├── serial.c └── util.S /Makefile: -------------------------------------------------------------------------------- 1 | BASEDIR := $(shell pwd) 2 | ARCH := $(shell uname -m) 3 | OUT := $(BASEDIR)/out 4 | HYPERBENCH_DIRS := $(ARCH) lib benchmark 5 | 6 | HYPERBENCH := hyperbench 7 | HYPERBENCH64 := hyperbench.64 8 | HYPERBENCH32 := hyperbench.32 9 | HOST := host/host 10 | 11 | CC = gcc 12 | AS = gas 13 | LD = ld 14 | AR = ar 15 | OBJDUMP = objdump 16 | OBJCOPY = objcopy 17 | 18 | OBJS += \ 19 | lib/printf.o\ 20 | lib/string.o\ 21 | lib/stack.o\ 22 | lib/abort.o 23 | 24 | include $(ARCH)/Makefile 25 | include benchmark/Makefile 26 | include harness/Makefile 27 | 28 | # auto depend flags 29 | autodepend-flags = -MMD -MF $(dir $*).$(notdir $*).d 30 | 31 | 32 | CFLAGS += -mno-red-zone -mno-sse -mno-sse2 33 | CFLAGS += -m64 34 | CFLAGS += -O0 35 | CFLAGS += -g3 $(autodepend-flags) 36 | # uncomment when compile HyperBench for host machine 37 | #CFLAGS += -D __BARE_METAL 38 | CFLAGS += -Werror 39 | CFLAGS += -ffreestanding 40 | CFLAGS += -fno-omit-frame-pointer 41 | CFLAGS += -fno-pic 42 | CFLAGS += -fno-builtin 43 | CFLAGS += -nostdlib 44 | CFLAGS += -std=gnu99 45 | CFLAGS += -I $(BASEDIR)/include 46 | 47 | 48 | ASFLAGS = -m64 -I $(BASEDIR)/include 49 | 50 | #kernel: $(OBJS) $(ARCH)/cstart.o entryother 51 | $(HYPERBENCH): $(OBJS) $(ARCH)/cstart.o $(HOST) 52 | mkdir $(OUT) 53 | $(LD) $(LDFLAGS) -T $(ARCH)/kernel.ld -o $(OUT)/hyperbench.64 $(ARCH)/cstart.o $(OBJS) 54 | objcopy --input-target=elf64-x86-64 --output-target=elf32-i386 $(OUT)/$(HYPERBENCH64) $(OUT)/$(HYPERBENCH32) 55 | $(OBJDUMP) -S $(OUT)/$(HYPERBENCH32) > $(OUT)/hyperbench32.asm 56 | $(OBJDUMP) -t $(OUT)/$(HYPERBENCH32) | sed '1,/SYMBOL TABLE/d; s/ .* / /; /^$$/d' > $(OUT)/hyperbench32.sym 57 | 58 | 59 | $(HOST): 60 | make -C host 61 | 62 | clean: 63 | rm -f $(ARCH)/*.o $(ARCH)/.*.d lib/*.o lib/.*.d 64 | rm -f harness/*.o harness/.*.d 65 | rm -f benchmark/*.o benchmark/.*.d 66 | rm -rf $(OUT) 67 | make -C host/ clean 68 | 69 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | # HyperBench-A Benchmark Suite for Virtualization Capabilities 3 | 4 | HyperBench is a set of micro-benchmarks for analyzing how much hardware mechanisms and hypervisor designs support virtualization. 5 | We designed and implemented HyperBench from ground up as a custom kernel. 6 | It contains 15 micro-benchmarks currently covering CPU, memory system, and I/O. 7 | These benchmarks cause various hypervisor-level events, such as transitions between VMs and the hypervisor, two-dimensional page walk, notification from front-end to back-end driver. 8 | HyperBench is aimed at quantifying those costs. 9 | 10 | For information, please read: 11 | 12 | Wei S, Zhang K, Tu B. HyperBench: A Benchmark Suite for Virtualization Capabilities[C]//Abstracts of the 2019 SIGMETRICS/Performance Joint International Conference on Measurement and Modeling of Computer Systems. ACM, 2019: 73-74. 13 | 14 | Wei S, Zhang K, Tu B. HyperBench: A Benchmark Suite for Virtualization Capabilities[J]. Proceedings of the ACM on Measurement and Analysis of Computing Systems, 2019, 3(2): 24. 15 | 16 | 17 | 18 | 19 | Table of Contents 20 | ================= 21 | 22 | * [HyperBench-A Benchmark Suite for Virtualization Capabilities](#hyperbench-a-benchmark-suite-for-virtualization-capabilities) 23 | * [Quick Start](#quick-start) 24 | * [Download](#download) 25 | * [Compiling HyperBench](#compiling-hyperbench) 26 | * [CPU Frequency](#cpu-frequency) 27 | * [Start on host machine](#start-on-host-machine) 28 | * [Start on QEMU-KVM](#start-on-qemu-kvm) 29 | * [Start on Xen](#start-on-xen) 30 | * [Benchmarks](#benchmarks) 31 | * [Idle](#idle) 32 | * [Sensitive Instruction](#sensitive-instruction) 33 | * [Virtualization Extention Instructions](#virtualization-extension-instructions) 34 | * [Memory](#memory) 35 | * [I/O](#io) 36 | * [HyperBench kernel Details](#hyperbench-kernel-details) 37 | * [Initialization Before Running Benchmarks](#initialization-before-running-benchmarks) 38 | * [Startup Memory Layout](#startup-memory-layout) 39 | 40 | 41 | 42 | ## Quick Start 43 | 44 | ### Download 45 | Download HyperBench into the directory /opt/. 46 | ``` 47 | # cd /opt 48 | # git clone https://github.com/Second222None/HyperBench.git 49 | ``` 50 | 51 | ### Compiling HyperBench 52 | * If you want to run HyperBench on host machine, uncomment the **CFLAGS += -D __BARE_METAL** in the Makefile. 53 | * If you want to run HyperBench on virtualization platforms, comment the **CFLAGS += -D __BARE_METAL** in the Makefile. 54 | 55 | After modification, type the following instruction directly. 56 | ``` 57 | # make 58 | ``` 59 | 60 | ### CPU Frequency 61 | HyperBench measures CPU cycles using the RDTSCP instruction. 62 | Sometimes Time Stamp Counter clock and CPU core clock are different. 63 | What's more, to save energy the CPU chip adjusts the CPU core frequency dynamicly. 64 | Before starting HyperBench, you would better pin the CPU at a fixed frequency to avoid the error. 65 | Typing the following command multiple times to determine the CPU frequency is stable. 66 | ``` 67 | cat /proc/cpuinfo | grep MHz | uniq 68 | ``` 69 | ``` 70 | cat /proc/cpuinfo | grep constant_tsc 71 | ``` 72 | ### Start on host machine 73 | 1. uncomment the **CFLAGS += -D __BARE_METAL** in the Makefile. 74 | 2. The parameter **NCPU** in **include/param.h** is the number of physical cores in the host machine. Modify it according to the physical machine or the program will get stuck. 75 | 3. Copy the **out/hyperbench.64** to /boot/ directory and then adding the following entry in the grub configuration file. Note that the following is just an example. You'd better imitate other grub menus in you grub.cfg file. 76 | ``` 77 | menuentry 'HyperBench'{ 78 | insmod part_msdos 79 | insmod ext2 80 | set root='hd0,msdos1' 81 | multiboot /boot/hyperbench.64 82 | } 83 | ``` 84 | ### Start on QEMU-KVM 85 | Enter HyperBench directory and run the following script. 86 | 87 | ``` 88 | # qemu-system-x86_64 -enable-kvm -smp 2 -m 4096 -kernel out/hyperbench.32 -nographic | host/host 89 | ``` 90 | 91 | ### Start on Xen 92 | 1. Empty the content of script/pin because Xen itself can pin vcpus in configuration file. 93 | 2. [Prepare HyperBench image](https://github.com/Second222None/HyperBench/wiki/HyperBench-Image) and store the image in /opt/os 94 | ``` 95 | # ./script/xen | host/host 96 | ``` 97 | 98 | ## Benchmarks 99 | 100 | ### Idle 101 | Idle benchmark performs two consecutive reads of the time counter. It is used to check the stability of the measurement results. Ideally, the 102 | result is zero. 103 | 104 | ### Sensitive Instruction 105 | 106 | #### SGDT SLDT SIDT 107 | Store the corresponding register value into memory repeatedly. 108 | #### PUSHF-POPF 109 | The PUSHF and POPF instructions execute alternately on the current stack. 110 | The time between the first PUSHF instruction and the last POPF instruction is measured. 111 | #### LGDT SET-CR3 112 | Read the current value of the register during the initialization phase and load the value into the corresponding register repeatedly in the test phase. 113 | 114 | ### Virtualization Extension Instructions 115 | #### Hypercall 116 | Execute an instruction in the VM which leads to a transition to the hypervisor and return without doing much work in the hypervisor. 117 | #### IPI 118 | Issue an IPI from a CPU to another CPU which is in the halt state. 119 | IPI benchmark measures the time between sending the IPI until the sending CPU receives the response from the receiving CPU without 120 | doing much work on the receiving CPU. 121 | In the virtualized environment, this benchmark emulates an IPI between two VCPUs running on two separate physical CPUs (PCPUs). 122 | 123 | ### Memory 124 | #### Hot-Memory-Access 125 | Read many different memory pages twice and the time of the second memory access is measured. The default guest page size is 4KB. 126 | #### Cold-Memory-Access 127 | This benchmark reserves a large portion of memory that has never been accessed before and performs one memory read at the start address of each page. 128 | The reading over different pages eliminates TLB hits due to the prefetcher, as the prefetcher cannot access data across page 129 | boundaries. The default guest page size is 4KB. 130 | #### Set-Page-Table 131 | Map the whole physical memory 1:1 to the virtual address space. This 132 | benchmark creates a lot of page table entries, which is a frequent 133 | operation in heavy memory allocation. The default guest page size is 134 | 4KB. 135 | #### TLB-Shutdown 136 | ...... 137 | 138 | ### I/O 139 | #### IN 140 | Polling and interrupt are two main approaches for notifications from 141 | host to guest. This benchmark reads the register of the serial port 142 | through the register I/O instructions repeatedly, which emulates the 143 | polling mechanism. 144 | #### OUT 145 | OUT benchmark outputs a character to the register of the serial port 146 | repeatedly. 147 | #### Print 148 | This benchmark outputs a string to the serial port through the I/O 149 | address space, which is handled through the string I/O instructions. 150 | 151 | ## HyperBench kernel Details 152 | HyperBench kernel is designed as a standalone kernel. It can run as a test VM on various hypervisors and run directly on bare-metal. 153 | 154 | ### Initialization Before Running Benchmarks 155 | 156 | 1. When the CPU are initialized by BIOS, the bootstrap processor (BSP) begins executing the grub code. Grub calls the HyperBench kernel. 157 | 2. Since HyperBench kernel is in multiboot format, it can get the information delieverey by grub. 158 | 3. The BSP set up a stack for itself and enter long mode. The first action of entering long mode is load the predefined global descriptor table. Then, turn on page size extension for 2Mbyte pages. Set CR3. Enables IA-32e mode operation. Turn on paging. 159 | 4. Jump into 64-bit code mode and call **main** function. 160 | 5. Get the memory layout information. 161 | 6. Enable local APIC. 162 | 7. Detect the application processors (APs). Get the APIC ID of each AP and store them in an array. 163 | 8. Initialize APs(step 3 to step 6) in serial mode. 164 | 9. Enable x2APIC. 165 | 10. Execute benchmarks one by one. 166 | 167 | ### Startup Memory Layout 168 | Linear-Address Translation to a 2-MByte Page using 4-Level Paging. 169 | 170 | * PML4(page map level 4): A 4-KByte naturally aligned PML4 table which is located at the physical address specified in bits 51:12 of CR3. There is only one 64-bit entry (PML4E). 171 | * PDPT(page-directory pointers table): A 4-KByte naturally aligned page-directory-pointer table is located at the physical address specified in bits 51:12 of the PML4E. There is only 4 64-bit entries 172 | (PDPTEs). 173 | * PDT(page-directory table): A 4-KByte aligned PDT which is located at the physical address specified in bits 51:12 of the PDPTE. The page-directory table contains 2048 64-bit entries 174 | (PDEs). 175 | 176 | 177 | -------------------------------------------------------------------------------- /benchmark/Makefile: -------------------------------------------------------------------------------- 1 | 2 | # IDLE 3 | OBJS += benchmark/idle.o 4 | 5 | # CPU benchmarks 6 | OBJS += benchmark/sgdt.o 7 | OBJS += benchmark/sidt.o 8 | OBJS += benchmark/smsw.o 9 | OBJS += benchmark/pushf_popf.o 10 | OBJS += benchmark/lgdt.o 11 | OBJS += benchmark/set-cr3.o 12 | #OBJS += benchmark/hypercall.o 13 | OBJS += benchmark/ipi.o 14 | 15 | # Memory benchmarks 16 | OBJS += benchmark/memory-cold.o 17 | OBJS += benchmark/memory-hot.o 18 | OBJS += benchmark/memory-pt.o 19 | 20 | # I/O benchmarks 21 | OBJS += benchmark/in.o 22 | OBJS += benchmark/out.o 23 | OBJS += benchmark/print.o 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /benchmark/hypercall.c: -------------------------------------------------------------------------------- 1 | #ifndef __BARE_METAL 2 | 3 | #include "benchmark.h" 4 | 5 | #define ITERATION HYPERCALL 6 | 7 | #define KVM_HYPERCALL_INTEL ".byte 0x0f,0x01,0xc1" 8 | #define KVM_HYPERCALL_AMD ".byte 0x0f,0x01,0xd9" 9 | 10 | static inline long kvm_hypercall0_intel(unsigned int nr) 11 | { 12 | long ret; 13 | asm volatile(KVM_HYPERCALL_INTEL 14 | : "=a"(ret) 15 | : "a"(nr)); 16 | return ret; 17 | } 18 | 19 | static inline long kvm_hypercall0_amd(unsigned int nr) 20 | { 21 | long ret; 22 | asm volatile(KVM_HYPERCALL_AMD 23 | : "=a"(ret) 24 | : "a"(nr)); 25 | return ret; 26 | } 27 | 28 | int i; 29 | 30 | static void init() 31 | { 32 | /* 33 | */ 34 | } 35 | 36 | static inline void ALIGN kernel() 37 | { 38 | unsigned long a = 0, b, c ,d; 39 | for(i = 0; i < ITERATION; i++){ 40 | // asm volatile("vmcall" : "+a"(a), "=b"(b), "=c"(c), "=d"(d)); 41 | kvm_hypercall0_intel(-1u); 42 | } 43 | } 44 | 45 | static inline void control() 46 | { 47 | for(i = 0; i < ITERATION; i++){ 48 | 49 | } 50 | } 51 | 52 | static void cleanup() 53 | { 54 | 55 | } 56 | 57 | DEFINE_BENCHMARK(hypercall) = 58 | { 59 | .name = "hypercall", 60 | .category = "exception", 61 | .init = init, 62 | .benchmark = kernel, 63 | .benchmark_control = control, 64 | .cleanup = cleanup, 65 | .iteration_count = ITERATION 66 | }; 67 | 68 | #endif 69 | 70 | -------------------------------------------------------------------------------- /benchmark/idle.c: -------------------------------------------------------------------------------- 1 | #include "benchmark.h" 2 | 3 | int i; 4 | 5 | static void init() 6 | { 7 | /* 8 | */ 9 | } 10 | 11 | static inline void ALIGN kernel() 12 | { 13 | for(i = 0; i < IDLE; i++){ 14 | 15 | } 16 | } 17 | 18 | static inline void control() 19 | { 20 | for(i = 0; i < IDLE; i++){ 21 | 22 | } 23 | } 24 | 25 | static void cleanup() 26 | { 27 | 28 | } 29 | 30 | DEFINE_BENCHMARK(idle) = 31 | { 32 | .name = "idle", 33 | .category = "idle", 34 | .init = init, 35 | .benchmark = kernel, 36 | .benchmark_control = control, 37 | .cleanup = cleanup, 38 | .iteration_count = IDLE 39 | }; 40 | 41 | 42 | -------------------------------------------------------------------------------- /benchmark/idt_test.c: -------------------------------------------------------------------------------- 1 | #include "benchmark.h" 2 | #include "desc.h" 3 | 4 | #define ITERATION 1 5 | 6 | int i; 7 | unsigned long tmp; 8 | 9 | static inline int test_gp(bool *rflags_rf) 10 | { 11 | 12 | /* 13 | #define ASM_TRY(catch) \ 14 | "movl $0, %%gs:4 \n\t" \ 15 | ".pushsection .data.ex \n\t" \ 16 | ".quad 1111f, " catch "\n\t" \ 17 | ".popsection \n\t" \ 18 | "1111:" 19 | */ 20 | 21 | asm volatile( 22 | "mov $0xffffffff, %0 \n\t" 23 | ASM_TRY("1f") 24 | "mov %0, %%cr4\n\t" 25 | "1:" 26 | : "=a"(tmp)); 27 | *rflags_rf = exception_rflags_rf(); 28 | return exception_vector(); 29 | } 30 | 31 | static inline int test_ud2(bool *rflags_rf) 32 | { 33 | asm volatile( 34 | ASM_TRY("1f") 35 | "ud2 \n\t" 36 | // "int $6 \n\t" 37 | "1:" :); 38 | *rflags_rf = exception_rflags_rf(); 39 | return exception_vector(); 40 | } 41 | 42 | static void init() 43 | { 44 | //setup_idt(); 45 | 46 | } 47 | 48 | static inline void ALIGN kernel() 49 | { 50 | //setup_vm(); 51 | int r; 52 | bool rflags_rf; 53 | 54 | setup_idt(); 55 | 56 | r = test_ud2(&rflags_rf); 57 | // if (r == UD_VECTOR) 58 | // fprintf(OUTPUT, "Invalid Opcode Exception!!!"); 59 | 60 | /* 61 | r = test_gp(&rflags_rf); 62 | if (r == GP_VECTOR) 63 | fprintf(OUTPUT, "General Protection Exception!!!"); 64 | */ 65 | } 66 | 67 | static inline void control() 68 | { 69 | 70 | } 71 | 72 | static void cleanup() 73 | { 74 | 75 | } 76 | 77 | DEFINE_BENCHMARK(ud2) = 78 | { 79 | .name = "ud2", 80 | .category = "exception", 81 | .init = init, 82 | .benchmark = kernel, 83 | .benchmark_control = control, 84 | .cleanup = cleanup, 85 | .iteration_count = ITERATION 86 | }; 87 | 88 | -------------------------------------------------------------------------------- /benchmark/in.c: -------------------------------------------------------------------------------- 1 | #include "benchmark.h" 2 | #include "io.h" 3 | 4 | #define ITERATION IN_SERIAL_PORT 5 | 6 | int i; 7 | char c; 8 | 9 | static void init() 10 | { 11 | /* 12 | */ 13 | } 14 | 15 | static inline void ALIGN kernel() 16 | { 17 | for(i = 0; i < ITERATION; i++){ 18 | // inb(0x3f8 + 0x05); 19 | inb(0x3f8 + 0x03); 20 | } 21 | } 22 | 23 | static inline void control() 24 | { 25 | for(i = 0; i < ITERATION; i++){ 26 | asm volatile(" "); 27 | } 28 | } 29 | 30 | static void cleanup() 31 | { 32 | 33 | } 34 | 35 | DEFINE_BENCHMARK(in) = 36 | { 37 | .name = "in-serial", 38 | .category = "io", 39 | .init = init, 40 | .benchmark = kernel, 41 | .benchmark_control = control, 42 | .cleanup = cleanup, 43 | .iteration_count = ITERATION 44 | }; 45 | 46 | 47 | 48 | -------------------------------------------------------------------------------- /benchmark/ipi.c: -------------------------------------------------------------------------------- 1 | #include "defs.h" 2 | #include "benchmark.h" 3 | 4 | #define ITERATION IPI 5 | 6 | int i; 7 | 8 | static inline void nop(void *junk) 9 | { 10 | 11 | } 12 | 13 | static inline void ipi(void) 14 | { 15 | on_cpu(1,nop,0); 16 | } 17 | 18 | static void init() 19 | { 20 | /* */ 21 | smp_init(); 22 | setup_mmu(1ul << 32); 23 | } 24 | 25 | static inline void ALIGN kernel() 26 | { 27 | for(i = 0; i < ITERATION; i++){ 28 | ipi(); 29 | } 30 | } 31 | 32 | static inline void control() 33 | { 34 | for(i = 0; i < ITERATION; i++){ 35 | 36 | } 37 | } 38 | 39 | static void cleanup() 40 | { 41 | switch_to_start_cr3(); 42 | } 43 | 44 | DEFINE_BENCHMARK(ipi) = 45 | { 46 | .name = "ipi", 47 | .category = "exception", 48 | .init = init, 49 | .benchmark = kernel, 50 | .benchmark_control = control, 51 | .cleanup = cleanup, 52 | .iteration_count = ITERATION 53 | }; 54 | 55 | -------------------------------------------------------------------------------- /benchmark/lgdt.c: -------------------------------------------------------------------------------- 1 | #include "benchmark.h" 2 | #include "ioram.h" 3 | #include "processor.h" 4 | 5 | #define ITERATION LGDT 6 | 7 | int i; 8 | 9 | void *mem; 10 | static unsigned long t=0x0000; 11 | 12 | static inline void save_gdt() 13 | { 14 | /* 15 | asm volatile("sgdt (%[mem]) \n\t" 16 | "mov (%[mem]), %[t]" 17 | :[mem]"=r"(mem), [t]"=r"(t) 18 | : 19 | :"memory"); 20 | 21 | printf("%lx", t); 22 | */ 23 | 24 | asm volatile("sgdt (%[mem])" 25 | :[mem]"=r"(mem) 26 | : 27 | :"memory"); 28 | 29 | } 30 | 31 | static void init() 32 | { 33 | /* 34 | */ 35 | setup_mmu(1ul << 32); 36 | mem = alloc_vpages(2); 37 | 38 | install_page((void *)read_cr3(), IORAM_BASE_PHYS, mem); 39 | install_page((void *)read_cr3(), IORAM_BASE_PHYS, mem + 4096); 40 | save_gdt(); 41 | } 42 | 43 | static inline void ALIGN kernel() 44 | { 45 | for(i = 0; i < ITERATION; i++){ 46 | //test_sgdt(); 47 | asm volatile("lgdt (%[mem])" 48 | : 49 | :[mem]"r"(mem) 50 | :); 51 | } 52 | } 53 | 54 | static inline void control() 55 | { 56 | for(i = 0; i < ITERATION; i++){ 57 | // test_sgdt(); 58 | } 59 | } 60 | 61 | static void cleanup() 62 | { 63 | switch_to_start_cr3(); 64 | } 65 | 66 | DEFINE_BENCHMARK(lgdt) = 67 | { 68 | .name = "lgdt", 69 | .category = "privileged", 70 | .init = init, 71 | .benchmark = kernel, 72 | .benchmark_control = control, 73 | .cleanup = cleanup, 74 | .iteration_count = ITERATION 75 | }; 76 | 77 | -------------------------------------------------------------------------------- /benchmark/memory-cold.c: -------------------------------------------------------------------------------- 1 | #include "benchmark.h" 2 | #include "processor.h" 3 | 4 | #define ITERATION COLD_ACCESS 5 | 6 | int i; 7 | unsigned long ptr = 0; 8 | 9 | static void init() 10 | { 11 | /* 12 | */ 13 | // write_cr0(0xC0000011); 14 | // setup_pt(); 15 | setup_mmu(1ul << 33); 16 | } 17 | 18 | static inline void ALIGN kernel() 19 | { 20 | // ptr = 0; 21 | ptr = 0x4000; 22 | for(i = 0; i < ITERATION; i++){ 23 | (*(volatile uint8_t *)(ptr * 4096)); 24 | ptr += 1; 25 | ptr = ptr % (1 << 30); 26 | /* 27 | if(ptr >= (1<<24)){ 28 | printf("Out of memory"); 29 | while(1); 30 | } 31 | */ 32 | } 33 | } 34 | 35 | static inline void control() 36 | { 37 | ptr = 0; 38 | ptr = 0x4000; 39 | for(i = 0; i < ITERATION; i++){ 40 | //(*(volatile uint8_t *)(ptr)); 41 | asm volatile (" "); 42 | ptr += 1; 43 | ptr = ptr % (1 << 30); 44 | } 45 | } 46 | 47 | static void cleanup() 48 | { 49 | switch_to_start_cr3(); 50 | } 51 | 52 | DEFINE_BENCHMARK(memory_cold) = 53 | { 54 | .name = "cold-access", 55 | .category = "memory", 56 | .init = init, 57 | .benchmark = kernel, 58 | .benchmark_control = control, 59 | .cleanup = cleanup, 60 | .iteration_count = ITERATION 61 | }; 62 | 63 | 64 | -------------------------------------------------------------------------------- /benchmark/memory-hot.c: -------------------------------------------------------------------------------- 1 | #include "benchmark.h" 2 | #include "processor.h" 3 | 4 | #define ITERATION HOT_ACCESS 5 | 6 | int i; 7 | uintptr_t address = 0x100000; 8 | 9 | static void init() 10 | { 11 | /* 12 | */ 13 | 14 | // write_cr0(0x80000011); 15 | // printf("cr0 = %lx\ncr4 = %lx\n", read_cr0(), read_cr4()); 16 | // setup_pt(); 17 | setup_mmu(1ul << 32); 18 | 19 | address = 0x100000; 20 | for(i = 0; i < ITERATION; i++){ 21 | (*(volatile uint8_t *)(address)); 22 | address += 0x1000; 23 | //address += 4; 24 | address = address % (1 << 30); 25 | } 26 | 27 | 28 | } 29 | 30 | static inline void ALIGN kernel() 31 | { 32 | address = 0x100000; 33 | for(i = 0; i < ITERATION; i++){ 34 | (*(volatile uint8_t *)(address)); 35 | address += 0x1000; 36 | //address += 4; 37 | address = address % (1 << 30); 38 | } 39 | } 40 | 41 | static inline void control() 42 | { 43 | address = 0; 44 | for(i = 0; i < ITERATION; i++){ 45 | //(*(volatile uint8_t *)(address)); 46 | asm volatile (" "); 47 | address += 0x1000; 48 | //address += 4; 49 | address = address % (1 << 30); 50 | } 51 | } 52 | 53 | static void cleanup() 54 | { 55 | switch_to_start_cr3(); 56 | // write_cr0(0xC0000011); 57 | } 58 | 59 | DEFINE_BENCHMARK(memory_hot) = 60 | { 61 | .name = "hot-access", 62 | .category = "memory", 63 | .init = init, 64 | .benchmark = kernel, 65 | .benchmark_control = control, 66 | .cleanup = cleanup, 67 | .iteration_count = ITERATION 68 | }; 69 | 70 | 71 | -------------------------------------------------------------------------------- /benchmark/memory-pt.c: -------------------------------------------------------------------------------- 1 | #include "benchmark.h" 2 | 3 | int i; 4 | 5 | static void init() 6 | { 7 | /* 8 | */ 9 | } 10 | 11 | static inline void ALIGN kernel() 12 | { 13 | /* 14 | for(i = 0; i < IDLE; i++){ 15 | 16 | } 17 | */ 18 | setup_mmu(1ul << 32); 19 | } 20 | 21 | static inline void control() 22 | { 23 | /* 24 | for(i = 0; i < IDLE; i++){ 25 | 26 | } 27 | */ 28 | } 29 | 30 | static void cleanup() 31 | { 32 | switch_to_start_cr3(); 33 | //early_mem_init(); 34 | } 35 | 36 | DEFINE_BENCHMARK(memory_pt) = 37 | { 38 | .name = "set-pt", 39 | .category = "memory", 40 | .init = init, 41 | .benchmark = kernel, 42 | .benchmark_control = control, 43 | .cleanup = cleanup, 44 | .iteration_count = 1 45 | }; 46 | 47 | 48 | -------------------------------------------------------------------------------- /benchmark/out.c: -------------------------------------------------------------------------------- 1 | #include "benchmark.h" 2 | #include "io.h" 3 | 4 | #define ITERATION OUT_SERIAL_PORT 5 | 6 | int i; 7 | u8 lcr; 8 | 9 | static void init() 10 | { 11 | /* 12 | */ 13 | lcr = inb(0x3f8 + 0x03); 14 | } 15 | 16 | static inline void ALIGN kernel() 17 | { 18 | for(i = 0; i < ITERATION; i++){ 19 | /* 20 | do { 21 | lsr = inb(0x3f8 + 0x05); 22 | } while (!(lsr & 0x20)); 23 | 24 | outb('x', 0x3f8 + 0x00); 25 | */ 26 | outb(lcr, 0x3f8 + 0x03); 27 | // outb(lcr, 0x3fb); 28 | } 29 | 30 | } 31 | 32 | static inline void control() 33 | { 34 | for(i = 0; i < ITERATION; i++){ 35 | asm volatile(" "); 36 | /* 37 | do { 38 | lsr = inb(0x3f8 + 0x05); 39 | } while (!(lsr & 0x20)); 40 | */ 41 | } 42 | } 43 | 44 | static void cleanup() 45 | { 46 | 47 | } 48 | 49 | DEFINE_BENCHMARK(out) = 50 | { 51 | .name = "out-serial", 52 | .category = "io", 53 | .init = init, 54 | .benchmark = kernel, 55 | .benchmark_control = control, 56 | .cleanup = cleanup, 57 | .iteration_count = ITERATION 58 | }; 59 | 60 | 61 | 62 | -------------------------------------------------------------------------------- /benchmark/print.c: -------------------------------------------------------------------------------- 1 | #include "benchmark.h" 2 | #include "io.h" 3 | 4 | #define ITERATION PRINTF 5 | 6 | int i; 7 | char a[] = "aaaaaaaaaaaaaaaaaaaaaaaaaa"; 8 | 9 | char *buf = a; 10 | unsigned long len; 11 | 12 | static void init() 13 | { 14 | /* 15 | */ 16 | len = strlen(buf); 17 | } 18 | 19 | static inline void ALIGN kernel() 20 | { 21 | for(i = 0; i < ITERATION; i++){ 22 | outbs(buf, len, 0x3f8); 23 | } 24 | } 25 | 26 | static inline void control() 27 | { 28 | for(i = 0; i < ITERATION; i++){ 29 | asm volatile(" "); 30 | } 31 | } 32 | 33 | static void cleanup() 34 | { 35 | 36 | } 37 | 38 | DEFINE_BENCHMARK(print) = 39 | { 40 | .name = "print", 41 | .category = "io", 42 | .init = init, 43 | .benchmark = kernel, 44 | .benchmark_control = control, 45 | .cleanup = cleanup, 46 | .iteration_count = ITERATION 47 | }; 48 | 49 | 50 | -------------------------------------------------------------------------------- /benchmark/pushf_popf.c: -------------------------------------------------------------------------------- 1 | #include "benchmark.h" 2 | 3 | #define ITERATION PUSHF_POPF 4 | 5 | int i; 6 | 7 | static inline void test_pushf_popf() 8 | { 9 | asm volatile("pushf \n\t" 10 | "popf \n\t" 11 | "pushf \n\t" 12 | "popf \n\t" 13 | "pushf \n\t" 14 | "popf \n\t" 15 | "pushf \n\t" 16 | "popf \n\t" 17 | "pushf \n\t" 18 | "popf \n\t" 19 | 20 | "pushf \n\t" 21 | "popf \n\t" 22 | "pushf \n\t" 23 | "popf \n\t" 24 | "pushf \n\t" 25 | "popf \n\t" 26 | "pushf \n\t" 27 | "popf \n\t" 28 | "pushf \n\t" 29 | "popf \n\t" 30 | 31 | ); 32 | 33 | } 34 | 35 | static void init() 36 | { 37 | /* 38 | */ 39 | 40 | } 41 | 42 | static inline void ALIGN kernel() 43 | { 44 | for(i = 0; i < ITERATION; i++){ 45 | test_pushf_popf(); 46 | } 47 | } 48 | 49 | static inline void control() 50 | { 51 | for(i = 0; i < ITERATION; i++){ 52 | // test_pushf_popf(); 53 | } 54 | } 55 | 56 | static void cleanup() 57 | { 58 | 59 | } 60 | 61 | DEFINE_BENCHMARK(pushf_popf) = 62 | { 63 | .name = "pushf-popf", 64 | .category = "critical", 65 | .init = init, 66 | .benchmark = kernel, 67 | .benchmark_control = control, 68 | .cleanup = cleanup, 69 | .iteration_count = ITERATION * 10 70 | }; 71 | 72 | -------------------------------------------------------------------------------- /benchmark/set-cr3.c: -------------------------------------------------------------------------------- 1 | #include "benchmark.h" 2 | #include "ioram.h" 3 | #include "processor.h" 4 | 5 | #define ITERATION SET_CR3 6 | 7 | int i; 8 | 9 | unsigned long cr3; 10 | 11 | static void init() 12 | { 13 | /* 14 | */ 15 | setup_mmu(1ul << 32); 16 | cr3 = read_cr3(); 17 | } 18 | 19 | static inline void ALIGN kernel() 20 | { 21 | for(i = 0; i < ITERATION; i++){ 22 | asm volatile ("mov %0, %%cr3" : : "r"(cr3) : "memory"); 23 | } 24 | } 25 | 26 | static inline void control() 27 | { 28 | for(i = 0; i < ITERATION; i++){ 29 | asm volatile(" "); 30 | } 31 | } 32 | 33 | static void cleanup() 34 | { 35 | switch_to_start_cr3(); 36 | } 37 | 38 | DEFINE_BENCHMARK(set_cr3) = 39 | { 40 | .name = "set-cr3", 41 | .category = "privileged", 42 | .init = init, 43 | .benchmark = kernel, 44 | .benchmark_control = control, 45 | .cleanup = cleanup, 46 | .iteration_count = ITERATION 47 | }; 48 | 49 | -------------------------------------------------------------------------------- /benchmark/sgdt.c: -------------------------------------------------------------------------------- 1 | #include "defs.h" 2 | #include "benchmark.h" 3 | #include "processor.h" 4 | 5 | #define ITERATION SGDT 6 | 7 | #define IORAM_BASE_PHYS 0xff000000UL 8 | #define IORAM_LEN 0x10000UL 9 | 10 | int i; 11 | 12 | void *mem; 13 | static unsigned long t=0x0000; 14 | 15 | static inline void test_sgdt() 16 | { 17 | /* 18 | asm volatile("sgdt (%[mem]) \n\t" 19 | "mov (%[mem]), %[t]" 20 | :[mem]"=r"(mem), [t]"=r"(t) 21 | : 22 | :"memory"); 23 | 24 | printf("%lx", t); 25 | */ 26 | 27 | asm volatile("sgdt (%[mem])" 28 | :[mem]"=r"(mem) 29 | : 30 | :"memory"); 31 | 32 | } 33 | 34 | static void init() 35 | { 36 | /* 37 | */ 38 | //setup_pt(); 39 | setup_mmu(1ul << 32); 40 | mem = alloc_vpages(2); 41 | 42 | install_page((void *)read_cr3(), IORAM_BASE_PHYS, mem); 43 | install_page((void *)read_cr3(), IORAM_BASE_PHYS, mem + 4096); 44 | } 45 | 46 | static inline void ALIGN kernel() 47 | { 48 | for(i = 0; i < ITERATION; i++){ 49 | test_sgdt(); 50 | } 51 | } 52 | 53 | static inline void control() 54 | { 55 | for(i = 0; i < ITERATION; i++){ 56 | // test_sgdt(); 57 | } 58 | } 59 | 60 | static void cleanup() 61 | { 62 | switch_to_start_cr3(); 63 | } 64 | 65 | DEFINE_BENCHMARK(sgdt) = 66 | { 67 | .name = "sgdt", 68 | .category = "critical", 69 | .init = init, 70 | .benchmark = kernel, 71 | .benchmark_control = control, 72 | .cleanup = cleanup, 73 | .iteration_count = ITERATION 74 | }; 75 | 76 | -------------------------------------------------------------------------------- /benchmark/sidt.c: -------------------------------------------------------------------------------- 1 | #include "benchmark.h" 2 | #include "ioram.h" 3 | #include "processor.h" 4 | 5 | 6 | #define ITERATION SIDT 7 | 8 | int i; 9 | 10 | void *mem; 11 | static unsigned long t=0x0000; 12 | 13 | static inline void test_sidt() 14 | { 15 | /* 16 | asm volatile("sidt (%[mem]) \n\t" 17 | "mov (%[mem]), %[t]" 18 | :[mem]"=r"(mem), [t]"=r"(t) 19 | : 20 | :"memory"); 21 | 22 | printf("%lx", t); 23 | */ 24 | 25 | asm volatile("sidt (%[mem])" 26 | :[mem]"=r"(mem) 27 | : 28 | :"memory"); 29 | 30 | } 31 | 32 | static void init() 33 | { 34 | /* 35 | */ 36 | setup_mmu(1ul << 32); 37 | mem = alloc_vpages(2); 38 | 39 | install_page((void *)read_cr3(), IORAM_BASE_PHYS, mem); 40 | install_page((void *)read_cr3(), IORAM_BASE_PHYS, mem + 4096); 41 | 42 | //mem = mem + 4096; 43 | } 44 | 45 | static inline void ALIGN kernel() 46 | { 47 | for(i = 0; i < ITERATION; i++){ 48 | test_sidt(); 49 | } 50 | } 51 | 52 | static inline void control() 53 | { 54 | for(i = 0; i < ITERATION; i++){ 55 | 56 | } 57 | } 58 | 59 | static void cleanup() 60 | { 61 | switch_to_start_cr3(); 62 | } 63 | 64 | DEFINE_BENCHMARK(sidt) = 65 | { 66 | .name = "sidt", 67 | .category = "critical", 68 | .init = init, 69 | .benchmark = kernel, 70 | .benchmark_control = control, 71 | .cleanup = cleanup, 72 | .iteration_count = ITERATION 73 | }; 74 | 75 | -------------------------------------------------------------------------------- /benchmark/smsw.c: -------------------------------------------------------------------------------- 1 | #include "benchmark.h" 2 | #include "processor.h" 3 | 4 | #define ITERATION SMSW 5 | 6 | int i; 7 | 8 | unsigned short msw, msw_orig; 9 | 10 | static void init() 11 | { 12 | /* 13 | */ 14 | msw_orig = read_cr0(); 15 | //printf("%d\n", msw_orig); 16 | } 17 | 18 | static inline void ALIGN kernel() 19 | { 20 | for(i = 0; i < ITERATION; i++){ 21 | asm volatile("smsw %0 \n\t" 22 | "smsw %0 \n\t" 23 | "smsw %0 \n\t" 24 | "smsw %0 \n\t" 25 | "smsw %0 \n\t" 26 | "smsw %0 \n\t" 27 | "smsw %0 \n\t" 28 | "smsw %0 \n\t" 29 | "smsw %0 \n\t" 30 | "smsw %0 \n\t" 31 | : "=r"(msw)); 32 | 33 | } 34 | //printf("%d\n", msw); 35 | } 36 | 37 | static inline void control() 38 | { 39 | for(i = 0; i < ITERATION; i++){ 40 | // asm("smsw %0" : "=r"(msw)); 41 | asm volatile(" "); 42 | } 43 | } 44 | 45 | static void cleanup() 46 | { 47 | 48 | } 49 | 50 | DEFINE_BENCHMARK(smsw) = 51 | { 52 | .name = "smsw", 53 | .category = "critical", 54 | .init = init, 55 | .benchmark = kernel, 56 | .benchmark_control = control, 57 | .cleanup = cleanup, 58 | .iteration_count = ITERATION * 10 59 | }; 60 | 61 | -------------------------------------------------------------------------------- /harness/Makefile: -------------------------------------------------------------------------------- 1 | OBJS += harness/harness.o 2 | 3 | -------------------------------------------------------------------------------- /harness/harness.c: -------------------------------------------------------------------------------- 1 | #include "benchmark.h" 2 | #include "rdtsc.h" 3 | 4 | 5 | #define STR_BENCHMARK_BEGIN "[BENCHMARKS BEGIN]\r\n" 6 | #define STR_BENCHMARK_END "[BENCHMARKS END]\r\n" 7 | 8 | extern const benchmark_t _BENCHMARKS_START[], _BENCHMARKS_END[]; 9 | 10 | 11 | static void harness_execute(const benchmark_t *benchmark) 12 | { 13 | unsigned cycles_low, cycles_high, cycles_low1, cycles_high1; 14 | unsigned cycles_low2, cycles_high2, cycles_low3, cycles_high3; 15 | uint64_t start, end, start1, end1; 16 | uint64_t time_control, time_kernel; 17 | 18 | // fprintf(OUTPUT, "%s -> %s", benchmark->category, benchmark->name); 19 | printf("%-15s%-15s", benchmark->category, benchmark->name); 20 | if(benchmark->init) benchmark->init(); 21 | 22 | printf("%-10ld", benchmark->iteration_count); 23 | 24 | /* test begin */ 25 | #ifdef __BARE_METAL 26 | //before(cycles_low, cycles_high); 27 | rdtsc(cycles_low, cycles_high); 28 | 29 | #else 30 | printf("{"); 31 | #endif 32 | benchmark->benchmark_control(); 33 | #ifdef __BARE_METAL 34 | //printf("bare metal"); 35 | //after(cycles_low1, cycles_high1); 36 | rdtsc(cycles_low1, cycles_high1); 37 | #else 38 | printf("}"); 39 | #endif 40 | 41 | #ifdef __BARE_METAL 42 | //printf("bare metal"); 43 | //before(cycles_low2, cycles_high2); 44 | rdtsc(cycles_low2, cycles_high2); 45 | #else 46 | printf("["); 47 | #endif 48 | benchmark->benchmark(); 49 | #ifdef __BARE_METAL 50 | //printf("bare metal"); 51 | //after(cycles_low3, cycles_high3); 52 | rdtsc(cycles_low3, cycles_high3); 53 | #else 54 | printf("]\r\n"); 55 | #endif 56 | 57 | benchmark->cleanup(); 58 | 59 | #ifdef __BARE_METAL 60 | start = ( ((uint64_t)cycles_high << 32) | cycles_low ); 61 | end = ( ((uint64_t)cycles_high1 << 32) | cycles_low1 ); 62 | start1 = ( ((uint64_t)cycles_high2 << 32) | cycles_low2 ); 63 | end1 = ( ((uint64_t)cycles_high3 << 32) | cycles_low3 ); 64 | time_control = (end - start); 65 | time_kernel = (end1 - start1); 66 | printf("%-15lu", time_control); 67 | printf("%-15lu", time_kernel); 68 | printf("%ld\n", time_kernel - time_control); 69 | #endif 70 | 71 | 72 | } 73 | 74 | 75 | void harness_main() 76 | { 77 | const benchmark_t *benchmark; 78 | 79 | unsigned long long cycles1, cycles2; 80 | 81 | /* inform host to pin VCPUs */ 82 | printf("*\r\n"); 83 | #ifdef __BARE_METAL 84 | 85 | #else 86 | /* waiting until finished VCPUs pin */ 87 | cycles2 = cycles1 = currentcycles(); 88 | while(cycles2 - cycles1 < 60000000000){ 89 | cycles2 = currentcycles(); 90 | } 91 | #endif 92 | 93 | printf("%-15s%-15s%-10s\r\n", "category","name","iteration"); 94 | printf(STR_BENCHMARK_BEGIN); 95 | 96 | for(benchmark = &_BENCHMARKS_START[0]; benchmark < _BENCHMARKS_END; benchmark++) 97 | { 98 | 99 | harness_execute(benchmark); 100 | 101 | } 102 | 103 | printf(STR_BENCHMARK_END); 104 | printf(STR_BENCHMARK_END); 105 | } 106 | 107 | 108 | -------------------------------------------------------------------------------- /host/Makefile: -------------------------------------------------------------------------------- 1 | 2 | host : host.c 3 | # @echo "CCLD $@" 4 | gcc $^ -o $@ -g -O0 5 | 6 | clean: 7 | # @echo "RM host" 8 | rm -f host 9 | 10 | -------------------------------------------------------------------------------- /host/host.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include "rdtsc.h" 5 | #include 6 | 7 | #define STR_BENCHMARK_BEGIN "[BENCHMARKS BEGIN]\r\n" 8 | #define STR_BENCHMARK_END "[BENCHMARKS END]\r\n" 9 | 10 | 11 | typedef unsigned long long int uint64_t; 12 | 13 | static char read_symbol() 14 | { 15 | while(1){ 16 | char c = fgetc(stdin); 17 | 18 | switch(c) { 19 | case '[': 20 | case '{': 21 | case '*': 22 | return c; 23 | default: 24 | return 0; 25 | } 26 | } 27 | } 28 | 29 | int read_start(const char *str) 30 | { 31 | char *lineptr = NULL; 32 | size_t lineptrsize = 0; 33 | while(1) 34 | { 35 | if(getline(&lineptr, &lineptrsize, stdin) < 0) return 1; 36 | if(!strcmp(str, lineptr)) { break; } 37 | } 38 | free(lineptr); 39 | printf("%s", str); 40 | 41 | return 0; 42 | } 43 | 44 | 45 | static char read_time_start_char() 46 | { 47 | while(1){ 48 | char c = fgetc(stdin); 49 | 50 | switch(c) { 51 | case '[': 52 | case '{': 53 | return c; 54 | default: 55 | return 0; 56 | } 57 | } 58 | } 59 | 60 | static char read_time_end_char(char target) 61 | { 62 | while(1){ 63 | char c = fgetc(stdin); 64 | if(c == target) return target; 65 | } 66 | } 67 | 68 | 69 | int read_benchmark() 70 | { 71 | char category[128]; 72 | char benchmark[128]; 73 | uint64_t iterations; 74 | 75 | //if(fscanf(stdin, "%s -> %s %llx ", category, benchmark, &iterations) != 3) return 1; 76 | if(fscanf(stdin, "%s%s%lld ", category, benchmark, &iterations) != 3) return 1; 77 | printf("%-15s%-20s%-15llu", category, benchmark, iterations); 78 | 79 | return 0; 80 | 81 | } 82 | 83 | static char* do_command(const char *cmd) 84 | { 85 | FILE *f; 86 | 87 | static char buf[512]; 88 | 89 | f = popen(cmd, "r"); 90 | if(!f) 91 | return 0; 92 | fread(buf, sizeof(char), sizeof(buf),f); 93 | pclose(f); 94 | printf("PIN:%s\n",buf); 95 | return buf; 96 | } 97 | 98 | int main(int argc, void **arg) 99 | { 100 | unsigned cycles_low, cycles_high, cycles_low1, cycles_high1; 101 | unsigned cycles_low2, cycles_high2, cycles_low3, cycles_high3; 102 | uint64_t start, end, start1, end1; 103 | uint64_t time_control, time_kernel; 104 | char time_start_char, time_end_char; 105 | 106 | char str[128]; 107 | 108 | 109 | 110 | /* pin each VCPU to a specific PCPU */ 111 | // if(read_symbol() == '*'){ 112 | // do_command("./script/pin"); 113 | // } 114 | if(!read_start("*\r\n")){ 115 | do_command("./script/pin"); 116 | } 117 | 118 | 119 | if(!read_start(STR_BENCHMARK_BEGIN)) { 120 | 121 | printf("%-15s%-20s%-15s%-15s%-15s%s\r\n", "category", "benchmark", "iterations","control-time","kernel-time","cycles"); 122 | 123 | while(!read_benchmark()){ 124 | 125 | time_start_char = read_time_start_char(); 126 | if(time_start_char == '{') { 127 | before(cycles_low, cycles_high); 128 | //rdtsc(cycles_low, cycles_high); 129 | time_end_char = read_time_end_char('}'); 130 | after(cycles_low1, cycles_high1); 131 | //rdtsc(cycles_low1, cycles_high1); 132 | } 133 | 134 | time_start_char = read_time_start_char(); 135 | if(time_start_char == '['){ 136 | before(cycles_low2, cycles_high2); 137 | //rdtsc(cycles_low2, cycles_high2); 138 | time_end_char = read_time_end_char(']'); 139 | after(cycles_low3, cycles_high3); 140 | //rdtsc(cycles_low3, cycles_high3); 141 | } 142 | 143 | start = ( ((uint64_t)cycles_high << 32) | cycles_low ); 144 | end = ( ((uint64_t)cycles_high1 << 32) | cycles_low1 ); 145 | start1 = ( ((uint64_t)cycles_high2 << 32) | cycles_low2 ); 146 | end1 = ( ((uint64_t)cycles_high3 << 32) | cycles_low3 ); 147 | time_control = (end - start); 148 | time_kernel = (end1 - start1); 149 | printf("%-15llu", time_control); 150 | printf("%-15llu", time_kernel); 151 | printf("%lld\r\n", time_kernel - time_control); 152 | } 153 | 154 | } 155 | /* waiting until finished */ 156 | read_start(STR_BENCHMARK_END); 157 | //printf("%s\n",str); 158 | } 159 | 160 | 161 | -------------------------------------------------------------------------------- /host/rdtsc.h: -------------------------------------------------------------------------------- 1 | 2 | #define before(low,high) \ 3 | asm volatile( \ 4 | "cpuid\n\t" \ 5 | "rdtsc\n\t" \ 6 | "mov %%edx, %0\n\t" \ 7 | "mov %%eax, %1\n\t": "=r" (high), "=r" (low):: \ 8 | "%rax", "%rbx", "%rcx", "%rdx") 9 | 10 | #define after(low,high) \ 11 | asm volatile( \ 12 | "rdtscp\n\t" \ 13 | "mov %%edx, %0\n\t" \ 14 | "mov %%eax, %1\n\t" \ 15 | "cpuid\n\t": "=r" (high), "=r" (low):: \ 16 | "%rax", "%rbx", "%rcx", "%rdx") 17 | 18 | #define rdtsc(low,high) \ 19 | __asm__ __volatile__("rdtscp":"=a"(low),"=d"(high)) 20 | 21 | #define rdtscll(val) \ 22 | __asm__ __volatile__("rdtscp":"=A"(val)) 23 | 24 | static inline unsigned long long currentcycles(){ 25 | unsigned long long cycles; 26 | __asm__ __volatile__("rdtsc":"=A"(cycles)); 27 | return cycles; 28 | } 29 | 30 | 31 | -------------------------------------------------------------------------------- /include/apic.h: -------------------------------------------------------------------------------- 1 | 2 | #ifndef __APIC_H 3 | #define __APIC_H 4 | 5 | /* 6 | * Constants for various Intel APICs. (local APIC, IOAPIC, etc.) 7 | * 8 | * Alan Cox , 1995. 9 | * Ingo Molnar , 1999, 2000 10 | */ 11 | 12 | #define APIC_DEFAULT_PHYS_BASE 0xfee00000 13 | #define APIC_BSP (1UL << 8) 14 | #define APIC_EXTD (1UL << 10) 15 | #define APIC_EN (1UL << 11) 16 | 17 | #define APIC_ID 0x20 18 | 19 | #define APIC_LVR 0x30 20 | #define APIC_LVR_MASK 0xFF00FF 21 | #define GET_APIC_VERSION(x) ((x) & 0xFFu) 22 | #define GET_APIC_MAXLVT(x) (((x) >> 16) & 0xFFu) 23 | #ifdef CONFIG_X86_32 24 | # define APIC_INTEGRATED(x) ((x) & 0xF0u) 25 | #else 26 | # define APIC_INTEGRATED(x) (1) 27 | #endif 28 | #define APIC_XAPIC(x) ((x) >= 0x14) 29 | #define APIC_TASKPRI 0x80 30 | #define APIC_TPRI_MASK 0xFFu 31 | #define APIC_ARBPRI 0x90 32 | #define APIC_ARBPRI_MASK 0xFFu 33 | #define APIC_PROCPRI 0xA0 34 | #define APIC_EOI 0xB0 35 | #define APIC_EIO_ACK 0x0 36 | #define APIC_RRR 0xC0 37 | #define APIC_LDR 0xD0 38 | #define APIC_LDR_MASK (0xFFu << 24) 39 | #define GET_APIC_LOGICAL_ID(x) (((x) >> 24) & 0xFFu) 40 | #define SET_APIC_LOGICAL_ID(x) (((x) << 24)) 41 | #define APIC_ALL_CPUS 0xFFu 42 | #define APIC_DFR 0xE0 43 | #define APIC_DFR_CLUSTER 0x0FFFFFFFul 44 | #define APIC_DFR_FLAT 0xFFFFFFFFul 45 | #define APIC_SPIV 0xF0 46 | #define APIC_SPIV_FOCUS_DISABLED (1 << 9) 47 | #define APIC_SPIV_APIC_ENABLED (1 << 8) 48 | #define APIC_ISR 0x100 49 | #define APIC_ISR_NR 0x8 /* Number of 32 bit ISR registers. */ 50 | #define APIC_TMR 0x180 51 | #define APIC_IRR 0x200 52 | #define APIC_ESR 0x280 53 | #define APIC_ESR_SEND_CS 0x00001 54 | #define APIC_ESR_RECV_CS 0x00002 55 | #define APIC_ESR_SEND_ACC 0x00004 56 | #define APIC_ESR_RECV_ACC 0x00008 57 | #define APIC_ESR_SENDILL 0x00020 58 | #define APIC_ESR_RECVILL 0x00040 59 | #define APIC_ESR_ILLREGA 0x00080 60 | #define APIC_ICR 0x300 61 | #define APIC_DEST_SELF 0x40000 62 | #define APIC_DEST_ALLINC 0x80000 63 | #define APIC_DEST_ALLBUT 0xC0000 64 | #define APIC_ICR_RR_MASK 0x30000 65 | #define APIC_ICR_RR_INVALID 0x00000 66 | #define APIC_ICR_RR_INPROG 0x10000 67 | #define APIC_ICR_RR_VALID 0x20000 68 | #define APIC_INT_LEVELTRIG 0x08000 69 | #define APIC_INT_ASSERT 0x04000 70 | #define APIC_ICR_BUSY 0x01000 71 | #define APIC_DEST_LOGICAL 0x00800 72 | #define APIC_DEST_PHYSICAL 0x00000 73 | #define APIC_DM_FIXED 0x00000 74 | #define APIC_DM_LOWEST 0x00100 75 | #define APIC_DM_SMI 0x00200 76 | #define APIC_DM_REMRD 0x00300 77 | #define APIC_DM_NMI 0x00400 78 | #define APIC_DM_INIT 0x00500 79 | #define APIC_DM_STARTUP 0x00600 80 | #define APIC_DM_EXTINT 0x00700 81 | #define APIC_VECTOR_MASK 0x000FF 82 | #define APIC_ICR2 0x310 83 | #define GET_APIC_DEST_FIELD(x) (((x) >> 24) & 0xFF) 84 | #define SET_APIC_DEST_FIELD(x) ((x) << 24) 85 | #define APIC_LVTT 0x320 86 | #define APIC_LVTTHMR 0x330 87 | #define APIC_LVTPC 0x340 88 | #define APIC_LVT0 0x350 89 | #define APIC_LVT_TIMER_BASE_MASK (0x3 << 18) 90 | #define GET_APIC_TIMER_BASE(x) (((x) >> 18) & 0x3) 91 | #define SET_APIC_TIMER_BASE(x) (((x) << 18)) 92 | #define APIC_TIMER_BASE_CLKIN 0x0 93 | #define APIC_TIMER_BASE_TMBASE 0x1 94 | #define APIC_TIMER_BASE_DIV 0x2 95 | #define APIC_LVT_TIMER_MASK (3 << 17) 96 | #define APIC_LVT_TIMER_ONESHOT (0 << 17) 97 | #define APIC_LVT_TIMER_PERIODIC (1 << 17) 98 | #define APIC_LVT_TIMER_TSCDEADLINE (2 << 17) 99 | #define APIC_LVT_MASKED (1 << 16) 100 | #define APIC_LVT_LEVEL_TRIGGER (1 << 15) 101 | #define APIC_LVT_REMOTE_IRR (1 << 14) 102 | #define APIC_INPUT_POLARITY (1 << 13) 103 | #define APIC_SEND_PENDING (1 << 12) 104 | #define APIC_MODE_MASK 0x700 105 | #define GET_APIC_DELIVERY_MODE(x) (((x) >> 8) & 0x7) 106 | #define SET_APIC_DELIVERY_MODE(x, y) (((x) & ~0x700) | ((y) << 8)) 107 | #define APIC_MODE_FIXED 0x0 108 | #define APIC_MODE_NMI 0x4 109 | #define APIC_MODE_EXTINT 0x7 110 | #define APIC_LVT1 0x360 111 | #define APIC_LVTERR 0x370 112 | #define APIC_TMICT 0x380 113 | #define APIC_TMCCT 0x390 114 | #define APIC_TDCR 0x3E0 115 | #define APIC_SELF_IPI 0x3F0 116 | #define APIC_TDR_DIV_TMBASE (1 << 2) 117 | #define APIC_TDR_DIV_1 0xB 118 | #define APIC_TDR_DIV_2 0x0 119 | #define APIC_TDR_DIV_4 0x1 120 | #define APIC_TDR_DIV_8 0x2 121 | #define APIC_TDR_DIV_16 0x3 122 | #define APIC_TDR_DIV_32 0x8 123 | #define APIC_TDR_DIV_64 0x9 124 | #define APIC_TDR_DIV_128 0xA 125 | #define APIC_EILVT0 0x500 126 | #define APIC_EILVT_NR_AMD_K8 1 /* # of extended interrupts */ 127 | #define APIC_EILVT_NR_AMD_10H 4 128 | #define APIC_EILVT_LVTOFF(x) (((x) >> 4) & 0xF) 129 | #define APIC_EILVT_MSG_FIX 0x0 130 | #define APIC_EILVT_MSG_SMI 0x2 131 | #define APIC_EILVT_MSG_NMI 0x4 132 | #define APIC_EILVT_MSG_EXT 0x7 133 | #define APIC_EILVT_MASKED (1 << 16) 134 | #define APIC_EILVT1 0x510 135 | #define APIC_EILVT2 0x520 136 | #define APIC_EILVT3 0x530 137 | 138 | #define APIC_BASE_MSR 0x800 139 | 140 | extern void *g_apic; 141 | extern void *g_ioapic; 142 | 143 | typedef struct { 144 | uint8_t vector; 145 | uint8_t delivery_mode:3; 146 | uint8_t dest_mode:1; 147 | uint8_t delivery_status:1; 148 | uint8_t polarity:1; 149 | uint8_t remote_irr:1; 150 | uint8_t trig_mode:1; 151 | uint8_t mask:1; 152 | uint8_t reserve:7; 153 | uint8_t reserved[4]; 154 | uint8_t dest_id; 155 | } ioapic_redir_entry_t; 156 | 157 | typedef enum trigger_mode { 158 | TRIGGER_EDGE = 0, 159 | TRIGGER_LEVEL, 160 | TRIGGER_MAX, 161 | } trigger_mode_t; 162 | 163 | void mask_pic_interrupts(void); 164 | 165 | void eoi(void); 166 | uint8_t apic_get_tpr(void); 167 | void apic_set_tpr(uint8_t tpr); 168 | 169 | void ioapic_write_redir(unsigned line, ioapic_redir_entry_t e); 170 | void ioapic_write_reg(unsigned reg, uint32_t value); 171 | ioapic_redir_entry_t ioapic_read_redir(unsigned line); 172 | uint32_t ioapic_read_reg(unsigned reg); 173 | 174 | void ioapic_set_redir(unsigned line, unsigned vec, 175 | trigger_mode_t trig_mode); 176 | 177 | void set_mask(unsigned line, int mask); 178 | 179 | void set_irq_line(unsigned line, int val); 180 | 181 | void enable_apic(void); 182 | uint32_t apic_read(unsigned reg); 183 | bool apic_read_bit(unsigned reg, int n); 184 | void apic_write(unsigned reg, uint32_t val); 185 | void apic_icr_write(uint32_t val, uint32_t dest); 186 | uint32_t apic_id(void); 187 | 188 | int enable_x2apic(void); 189 | void disable_apic(void); 190 | void reset_apic(void); 191 | 192 | 193 | #endif /* __APIC_H */ 194 | 195 | -------------------------------------------------------------------------------- /include/asm.h: -------------------------------------------------------------------------------- 1 | // 2 | // assembler macros to create x86 segments 3 | // 4 | 5 | #define SEG_NULLASM \ 6 | .word 0, 0; \ 7 | .byte 0, 0, 0, 0 8 | 9 | // The 0xC0 means the limit is in 4096-byte units 10 | // and (for executable segments) 32-bit mode. 11 | #define SEG_ASM(type,base,lim) \ 12 | .word (((lim) >> 12) & 0xffff), ((base) & 0xffff); \ 13 | .byte (((base) >> 16) & 0xff), (0x90 | (type)), \ 14 | (0xC0 | (((lim) >> 28) & 0xf)), (((base) >> 24) & 0xff) 15 | 16 | #define STA_X 0x8 // Executable segment 17 | #define STA_W 0x2 // Writeable (non-executable segments) 18 | #define STA_R 0x2 // Readable (executable segments) 19 | -------------------------------------------------------------------------------- /include/atomic.h: -------------------------------------------------------------------------------- 1 | #ifndef __ATOMIC_H 2 | #define __ATOMIC_H 3 | 4 | //#include "asm-generic/atomic.h" 5 | 6 | #ifndef __ASM_GENERIC_ATOMIC_H__ 7 | #define __ASM_GENERIC_ATOMIC_H__ 8 | 9 | /* From QEMU include/qemu/atomic.h */ 10 | #define atomic_fetch_inc(ptr) __sync_fetch_and_add(ptr, 1) 11 | #define atomic_fetch_dec(ptr) __sync_fetch_and_add(ptr, -1) 12 | #define atomic_fetch_add(ptr, n) __sync_fetch_and_add(ptr, n) 13 | #define atomic_fetch_sub(ptr, n) __sync_fetch_and_sub(ptr, n) 14 | #define atomic_fetch_and(ptr, n) __sync_fetch_and_and(ptr, n) 15 | #define atomic_fetch_or(ptr, n) __sync_fetch_and_or(ptr, n) 16 | #define atomic_fetch_xor(ptr, n) __sync_fetch_and_xor(ptr, n) 17 | 18 | #define atomic_inc_fetch(ptr) __sync_add_and_fetch(ptr, 1) 19 | #define atomic_dec_fetch(ptr) __sync_add_and_fetch(ptr, -1) 20 | #define atomic_add_fetch(ptr, n) __sync_add_and_fetch(ptr, n) 21 | #define atomic_sub_fetch(ptr, n) __sync_sub_and_fetch(ptr, n) 22 | #define atomic_and_fetch(ptr, n) __sync_and_and_fetch(ptr, n) 23 | #define atomic_or_fetch(ptr, n) __sync_or_and_fetch(ptr, n) 24 | #define atomic_xor_fetch(ptr, n) __sync_xor_and_fetch(ptr, n) 25 | 26 | #endif 27 | 28 | 29 | typedef struct { 30 | volatile int counter; 31 | } atomic_t; 32 | 33 | #ifdef __i386__ 34 | 35 | /** 36 | * atomic_read - read atomic variable 37 | * @v: pointer of type atomic_t 38 | * 39 | * Atomically reads the value of @v. 40 | */ 41 | static inline int atomic_read(const atomic_t *v) 42 | { 43 | return v->counter; 44 | } 45 | 46 | /** 47 | * atomic_set - set atomic variable 48 | * @v: pointer of type atomic_t 49 | * @i: required value 50 | * 51 | * Atomically sets the value of @v to @i. 52 | */ 53 | static inline void atomic_set(atomic_t *v, int i) 54 | { 55 | v->counter = i; 56 | } 57 | 58 | /** 59 | * atomic_inc - increment atomic variable 60 | * @v: pointer of type atomic_t 61 | * 62 | * Atomically increments @v by 1. 63 | */ 64 | static inline void atomic_inc(atomic_t *v) 65 | { 66 | asm volatile("lock incl %0" 67 | : "+m" (v->counter)); 68 | } 69 | 70 | /** 71 | * atomic_dec - decrement atomic variable 72 | * @v: pointer of type atomic_t 73 | * 74 | * Atomically decrements @v by 1. 75 | */ 76 | static inline void atomic_dec(atomic_t *v) 77 | { 78 | asm volatile("lock decl %0" 79 | : "+m" (v->counter)); 80 | } 81 | 82 | typedef struct { 83 | u64 __attribute__((aligned(8))) counter; 84 | } atomic64_t; 85 | 86 | #define ATOMIC64_INIT(val) { (val) } 87 | 88 | /** 89 | * atomic64_read - read atomic64 variable 90 | * @ptr: pointer to type atomic64_t 91 | * 92 | * Atomically reads the value of @ptr and returns it. 93 | */ 94 | static inline u64 atomic64_read(atomic64_t *ptr) 95 | { 96 | u64 res; 97 | 98 | /* 99 | * Note, we inline this atomic64_t primitive because 100 | * it only clobbers EAX/EDX and leaves the others 101 | * untouched. We also (somewhat subtly) rely on the 102 | * fact that cmpxchg8b returns the current 64-bit value 103 | * of the memory location we are touching: 104 | */ 105 | asm volatile("mov %%ebx, %%eax\n\t" 106 | "mov %%ecx, %%edx\n\t" 107 | "lock cmpxchg8b %1\n" 108 | : "=&A" (res) 109 | : "m" (*ptr) 110 | ); 111 | return res; 112 | } 113 | 114 | u64 atomic64_cmpxchg(atomic64_t *v, u64 old, u64 new); 115 | 116 | #elif defined(__x86_64__) 117 | 118 | /** 119 | * atomic_read - read atomic variable 120 | * @v: pointer of type atomic_t 121 | * 122 | * Atomically reads the value of @v. 123 | */ 124 | static inline int atomic_read(const atomic_t *v) 125 | { 126 | return v->counter; 127 | } 128 | 129 | /** 130 | * atomic_set - set atomic variable 131 | * @v: pointer of type atomic_t 132 | * @i: required value 133 | * 134 | * Atomically sets the value of @v to @i. 135 | */ 136 | static inline void atomic_set(atomic_t *v, int i) 137 | { 138 | v->counter = i; 139 | } 140 | 141 | /** 142 | * atomic_inc - increment atomic variable 143 | * @v: pointer of type atomic_t 144 | * 145 | * Atomically increments @v by 1. 146 | */ 147 | static inline void atomic_inc(atomic_t *v) 148 | { 149 | asm volatile("lock incl %0" 150 | : "=m" (v->counter) 151 | : "m" (v->counter)); 152 | } 153 | 154 | /** 155 | * atomic_dec - decrement atomic variable 156 | * @v: pointer of type atomic_t 157 | * 158 | * Atomically decrements @v by 1. 159 | */ 160 | static inline void atomic_dec(atomic_t *v) 161 | { 162 | asm volatile("lock decl %0" 163 | : "=m" (v->counter) 164 | : "m" (v->counter)); 165 | } 166 | 167 | typedef struct { 168 | long long counter; 169 | } atomic64_t; 170 | 171 | #define ATOMIC64_INIT(i) { (i) } 172 | 173 | /** 174 | * atomic64_read - read atomic64 variable 175 | * @v: pointer of type atomic64_t 176 | * 177 | * Atomically reads the value of @v. 178 | * Doesn't imply a read memory barrier. 179 | */ 180 | static inline long atomic64_read(const atomic64_t *v) 181 | { 182 | return v->counter; 183 | } 184 | 185 | u64 atomic64_cmpxchg(atomic64_t *v, u64 old, u64 new); 186 | 187 | #endif 188 | 189 | #endif 190 | -------------------------------------------------------------------------------- /include/benchmark.h: -------------------------------------------------------------------------------- 1 | #include "defs.h" 2 | 3 | #define IDLE 1 4 | #define LGDT 100000 5 | #define SET_CR3 100000 6 | #define SGDT 100000 7 | #define SIDT 100000 8 | #define SLDT 100000 9 | #define SMSW 100000 10 | #define PUSHF_POPF 100000 11 | #define IPI 100 12 | #define HYPERCALL 1000 13 | #define SET_PAGE_TABLE 1 14 | #define COLD_ACCESS 100000 15 | #define HOT_ACCESS 100000 16 | #define IN_SERIAL_PORT 1000 17 | #define OUT_SERIAL_PORT 1000 18 | #define PRINTF 1000 19 | 20 | #define ALIGN __attribute__((aligned(4096))) 21 | 22 | typedef void (*function_t)(); 23 | 24 | typedef struct { 25 | const char *name; 26 | const char *category; 27 | function_t init; 28 | function_t benchmark; 29 | function_t benchmark_control; 30 | function_t cleanup; 31 | uint64_t iteration_count; 32 | }benchmark_t; 33 | 34 | 35 | #define DEFINE_BENCHMARK(__name) const benchmark_t __attribute__((section(".benchmarks"))) __attribute__((aligned(__alignof__(unsigned long)))) __benchmark_##__name 36 | 37 | 38 | -------------------------------------------------------------------------------- /include/defs.h: -------------------------------------------------------------------------------- 1 | 2 | #ifndef __DEFS_H 3 | #define __DEFS_H 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | #include "types.h" 11 | #include "multiboot.h" 12 | 13 | #define __unused __attribute__((__unused__)) 14 | 15 | #define MIN(a, b) ((a) < (b) ? (a) : (b)) 16 | #define MAX(a, b) ((a) > (b) ? (a) : (b)) 17 | 18 | // 19 | extern void __fast_zero_page(void *page); 20 | extern void sipi_entry_mov(void); 21 | 22 | //harness.c 23 | void harness_main(void); 24 | 25 | //mp.c 26 | void mpinit(void); 27 | extern void smp_init(void); 28 | extern void on_cpu(int cpu, void (*function)(void *data), void *data); 29 | 30 | //proc.c 31 | struct cpu* mycpu(void); 32 | int cpuid(); 33 | 34 | //heap.c 35 | void *heap_alloc_page(); 36 | void switch_to_start_cr3(void); 37 | void *alloc_vpages(ulong nr); 38 | void early_mem_init(uintptr_t base_addr, struct mbi_bootinfo *bootinfo); 39 | void *setup_mmu(phys_addr_t end_of_memory); 40 | pteval_t *install_page(pgd_t *cr3, phys_addr_t phys, void *virt); 41 | 42 | //abort.c 43 | extern void exit(int code); 44 | extern void abort(void); 45 | 46 | //apic.c 47 | extern volatile uint* lapic; 48 | int lapicid(void); 49 | void mask_pic_interrupts(void); 50 | void enable_apic(void); 51 | int enable_x2apic(void); 52 | void lapicstartap(uchar, uint); 53 | 54 | //stack.c 55 | extern void dump_stack(void); 56 | 57 | //printf.c 58 | extern void puts(const char *s); 59 | 60 | extern int printf(const char *fmt, ...) 61 | __attribute__((format(printf, 1, 2))); 62 | extern int snprintf(char *buf, int size, const char *fmt, ...) 63 | __attribute__((format(printf, 3, 4))); 64 | extern int vsnprintf(char *buf, int size, const char *fmt, va_list va) 65 | __attribute__((format(printf, 3, 0))); 66 | extern int vprintf(const char *fmt, va_list va) 67 | __attribute__((format(printf, 1, 0))); 68 | 69 | /* 70 | * One byte per bit, a ' between each group of 4 bits, and a null terminator. 71 | */ 72 | #define BINSTR_SZ (sizeof(unsigned long) * 8 + sizeof(unsigned long) * 2) 73 | void binstr(unsigned long x, char out[BINSTR_SZ]); 74 | void print_binstr(unsigned long x); 75 | 76 | #define assert(cond) \ 77 | do { \ 78 | if (!(cond)) { \ 79 | printf("%s:%d: assert failed: %s\n", \ 80 | __FILE__, __LINE__, #cond); \ 81 | dump_stack(); \ 82 | abort(); \ 83 | } \ 84 | } while (0) 85 | 86 | //string.c 87 | long atol(const char *ptr); 88 | 89 | // console.c 90 | void console_init(void); 91 | void console_putc(char ch); 92 | void console_puts(const char *buf); 93 | 94 | #endif //END __DEFS_H 95 | 96 | -------------------------------------------------------------------------------- /include/desc.h: -------------------------------------------------------------------------------- 1 | #ifndef __IDT_TEST__ 2 | #define __IDT_TEST__ 3 | 4 | #include "types.h" 5 | #include "setjmp.h" 6 | 7 | void setup_idt(void); 8 | void setup_alt_stack(void); 9 | 10 | struct ex_regs { 11 | unsigned long rax, rcx, rdx, rbx; 12 | unsigned long dummy, rbp, rsi, rdi; 13 | #ifdef __x86_64__ 14 | unsigned long r8, r9, r10, r11; 15 | unsigned long r12, r13, r14, r15; 16 | #endif 17 | unsigned long vector; 18 | unsigned long error_code; 19 | unsigned long rip; 20 | unsigned long cs; 21 | unsigned long rflags; 22 | }; 23 | 24 | typedef void (*handler)(struct ex_regs *regs); 25 | 26 | typedef struct { 27 | u16 prev; 28 | u16 res1; 29 | u32 esp0; 30 | u16 ss0; 31 | u16 res2; 32 | u32 esp1; 33 | u16 ss1; 34 | u16 res3; 35 | u32 esp2; 36 | u16 ss2; 37 | u16 res4; 38 | u32 cr3; 39 | u32 eip; 40 | u32 eflags; 41 | u32 eax, ecx, edx, ebx, esp, ebp, esi, edi; 42 | u16 es; 43 | u16 res5; 44 | u16 cs; 45 | u16 res6; 46 | u16 ss; 47 | u16 res7; 48 | u16 ds; 49 | u16 res8; 50 | u16 fs; 51 | u16 res9; 52 | u16 gs; 53 | u16 res10; 54 | u16 ldt; 55 | u16 res11; 56 | u16 t:1; 57 | u16 res12:15; 58 | u16 iomap_base; 59 | } tss32_t; 60 | 61 | typedef struct __attribute__((packed)) { 62 | u32 res1; 63 | u64 rsp0; 64 | u64 rsp1; 65 | u64 rsp2; 66 | u64 res2; 67 | u64 ist1; 68 | u64 ist2; 69 | u64 ist3; 70 | u64 ist4; 71 | u64 ist5; 72 | u64 ist6; 73 | u64 ist7; 74 | u64 res3; 75 | u16 res4; 76 | u16 iomap_base; 77 | } tss64_t; 78 | 79 | #define ASM_TRY(catch) \ 80 | "movl $0, %%gs:4 \n\t" \ 81 | ".pushsection .data.ex \n\t" \ 82 | ".quad 1111f, " catch "\n\t" \ 83 | ".popsection \n\t" \ 84 | "1111:" 85 | 86 | #define DB_VECTOR 1 87 | #define BP_VECTOR 3 88 | #define UD_VECTOR 6 89 | #define GP_VECTOR 13 90 | 91 | /* 92 | * selector 32-bit 64-bit 93 | * 0x00 NULL descriptor NULL descriptor 94 | * 0x08 ring-0 code segment (32-bit) ring-0 code segment (64-bit) 95 | * 0x10 ring-0 data segment (32-bit) ring-0 data segment (32/64-bit) 96 | * 0x18 ring-0 code segment (P=0) ring-0 code segment (64-bit, P=0) 97 | * 0x20 intr_alt_stack TSS ring-0 code segment (32-bit) 98 | * 0x28 ring-0 code segment (16-bit) same 99 | * 0x30 ring-0 data segment (16-bit) same 100 | * 0x38 (0x3b) ring-3 code segment (32-bit) same 101 | * 0x40 (0x43) ring-3 data segment (32-bit) ring-3 data segment (32/64-bit) 102 | * 0x48 (0x4b) **unused** ring-3 code segment (64-bit) 103 | * 0x50--0x78 free to use for test cases same 104 | * 0x80 primary TSS (CPU 0) same 105 | * 106 | * Note that the same segment can be used for 32-bit and 64-bit data segments 107 | * (the L bit is only defined for code segments) 108 | * 109 | * Selectors 0x08-0x10 and 0x3b-0x4b are set up for use with the SYSCALL 110 | * and SYSRET instructions. 111 | */ 112 | 113 | #define KERNEL_CS 0x08 114 | #define KERNEL_DS 0x10 115 | #define NP_SEL 0x18 116 | #ifdef __x86_64__ 117 | #define KERNEL_CS32 0x20 118 | #else 119 | #define TSS_INTR 0x20 120 | #endif 121 | #define KERNEL_CS16 0x28 122 | #define KERNEL_DS16 0x30 123 | #define USER_CS32 0x3b 124 | #define USER_DS 0x43 125 | #ifdef __x86_64__ 126 | #define USER_CS64 0x4b 127 | #endif 128 | 129 | /* Synonyms */ 130 | #define KERNEL_DS32 KERNEL_DS 131 | #define USER_DS32 USER_DS 132 | 133 | #ifdef __x86_64__ 134 | #define KERNEL_CS64 KERNEL_CS 135 | #define USER_CS USER_CS64 136 | #define KERNEL_DS64 KERNEL_DS 137 | #define USER_DS64 USER_DS 138 | #else 139 | #define KERNEL_CS32 KERNEL_CS 140 | #define USER_CS USER_CS32 141 | #endif 142 | 143 | #define FIRST_SPARE_SEL 0x50 144 | #define TSS_MAIN 0x80 145 | 146 | typedef struct { 147 | unsigned short offset0; 148 | unsigned short selector; 149 | unsigned short ist : 3; 150 | unsigned short : 5; 151 | unsigned short type : 4; 152 | unsigned short : 1; 153 | unsigned short dpl : 2; 154 | unsigned short p : 1; 155 | unsigned short offset1; 156 | #ifdef __x86_64__ 157 | unsigned offset2; 158 | unsigned reserved; 159 | #endif 160 | } idt_entry_t; 161 | 162 | typedef struct { 163 | u16 limit_low; 164 | u16 base_low; 165 | u8 base_middle; 166 | u8 access; 167 | u8 granularity; 168 | u8 base_high; 169 | } gdt_entry_t; 170 | 171 | struct segment_desc64 { 172 | uint16_t limit1; 173 | uint16_t base1; 174 | uint8_t base2; 175 | union { 176 | uint16_t type_limit_flags; /* Type and limit flags */ 177 | struct { 178 | uint16_t type:4; 179 | uint16_t s:1; 180 | uint16_t dpl:2; 181 | uint16_t p:1; 182 | uint16_t limit:4; 183 | uint16_t avl:1; 184 | uint16_t l:1; 185 | uint16_t db:1; 186 | uint16_t g:1; 187 | } __attribute__((__packed__)); 188 | } __attribute__((__packed__)); 189 | uint8_t base3; 190 | uint32_t base4; 191 | uint32_t zero; 192 | } __attribute__((__packed__)); 193 | 194 | #define DESC_BUSY ((uint64_t) 1 << 41) 195 | 196 | //extern idt_entry_t boot_idt[256]; 197 | idt_entry_t boot_idt[256]; 198 | 199 | #ifndef __x86_64__ 200 | extern gdt_entry_t gdt32[]; 201 | extern tss32_t tss; 202 | extern tss32_t tss_intr; 203 | void set_gdt_task_gate(u16 tss_sel, u16 sel); 204 | void set_idt_task_gate(int vec, u16 sel); 205 | void set_intr_task_gate(int vec, void *fn); 206 | void setup_tss32(void); 207 | #else 208 | extern tss64_t tss; 209 | #endif 210 | 211 | unsigned exception_vector(void); 212 | unsigned exception_error_code(void); 213 | bool exception_rflags_rf(void); 214 | void set_idt_entry(int vec, void *addr, int dpl); 215 | void set_idt_sel(int vec, u16 sel); 216 | void set_idt_dpl(int vec, u16 dpl); 217 | void set_gdt_entry(int sel, u32 base, u32 limit, u8 access, u8 gran); 218 | void set_intr_alt_stack(int e, void *fn); 219 | void print_current_tss_info(void); 220 | handler handle_exception(u8 v, handler fn); 221 | 222 | bool test_for_exception(unsigned int ex, void (*trigger_func)(void *data), 223 | void *data); 224 | void __set_exception_jmpbuf(jmp_buf *addr); 225 | #define set_exception_jmpbuf(jmpbuf) \ 226 | (setjmp(jmpbuf) ? : (__set_exception_jmpbuf(&(jmpbuf)), 0)) 227 | 228 | #endif 229 | -------------------------------------------------------------------------------- /include/io.h: -------------------------------------------------------------------------------- 1 | #ifndef _ASM_X86_IO_H_ 2 | #define _ASM_X86_IO_H_ 3 | 4 | #define __iomem 5 | 6 | #define inb inb 7 | static inline uint8_t inb(unsigned long port) 8 | { 9 | unsigned char value; 10 | asm volatile("inb %w1, %0" : "=a" (value) : "Nd" ((unsigned short)port)); 11 | return value; 12 | } 13 | 14 | #define inw inw 15 | static inline uint16_t inw(unsigned long port) 16 | { 17 | unsigned short value; 18 | asm volatile("inw %w1, %0" : "=a" (value) : "Nd" ((unsigned short)port)); 19 | return value; 20 | } 21 | 22 | #define inl inl 23 | static inline uint32_t inl(unsigned long port) 24 | { 25 | unsigned int value; 26 | asm volatile("inl %w1, %0" : "=a" (value) : "Nd" ((unsigned short)port)); 27 | return value; 28 | } 29 | 30 | #define outb outb 31 | static inline void outb(uint8_t value, unsigned long port) 32 | { 33 | asm volatile("outb %b0, %w1" : : "a"(value), "Nd"((unsigned short)port)); 34 | } 35 | 36 | #define outw outw 37 | static inline void outw(uint16_t value, unsigned long port) 38 | { 39 | asm volatile("outw %w0, %w1" : : "a"(value), "Nd"((unsigned short)port)); 40 | } 41 | 42 | #define outl outl 43 | static inline void outl(uint32_t value, unsigned long port) 44 | { 45 | asm volatile("outl %0, %w1" : : "a"(value), "Nd"((unsigned short)port)); 46 | } 47 | 48 | #define outbs outbs 49 | static inline void outbs(char *buf, unsigned long len, unsigned long port) 50 | { 51 | //asm volatile ("rep/outsb" : "+S"(buf), "+c"(len) : "d"(port)); 52 | asm volatile ("rep/outsb" : "+S"(buf), "+c"(len) : "d"(port)); 53 | } 54 | 55 | 56 | #define virt_to_phys virt_to_phys 57 | static inline unsigned long virt_to_phys(const void *virt) 58 | { 59 | return (unsigned long)virt; 60 | } 61 | 62 | #define phys_to_virt phys_to_virt 63 | static inline void *phys_to_virt(unsigned long phys) 64 | { 65 | return (void *)phys; 66 | } 67 | /* 68 | #define ioremap ioremap 69 | void __iomem *ioremap(phys_addr_t phys_addr, size_t size); 70 | 71 | #include 72 | 73 | */ 74 | #endif 75 | 76 | -------------------------------------------------------------------------------- /include/ioram.h: -------------------------------------------------------------------------------- 1 | #ifndef __IO_RAM_H 2 | #define __IO_RAM_H 3 | 4 | #define IORAM_BASE_PHYS 0xff000000UL 5 | #define IORAM_LEN 0x10000UL 6 | 7 | #endif 8 | -------------------------------------------------------------------------------- /include/memlayout.h: -------------------------------------------------------------------------------- 1 | // Memory layout 2 | 3 | #define EXTMEM 0x100000 // Start of extended memory 4 | #define PHYSTOP 0xE000000 // Top physical memory 5 | #define DEVSPACE 0xFE000000 // Other devices are at high addresses 6 | 7 | // Key addresses for address space layout (see kmap in vm.c for layout) 8 | #define KERNBASE 0x80000000 // First kernel virtual address 9 | #define KERNLINK (KERNBASE+EXTMEM) // Address where kernel is linked 10 | 11 | #define V2P(a) (((uint) (a)) - KERNBASE) 12 | #define P2V(a) ((void *)(((char *) (a)) + KERNBASE)) 13 | 14 | #define V2P_WO(x) ((x) - KERNBASE) // same as V2P, but without casts 15 | #define P2V_WO(x) ((x) + KERNBASE) // same as P2V, but without casts 16 | -------------------------------------------------------------------------------- /include/mmu.h: -------------------------------------------------------------------------------- 1 | // This file contains definitions for the 2 | // x86 memory management unit (MMU). 3 | 4 | // Eflags register 5 | #define FL_IF 0x00000200 // Interrupt Enable 6 | 7 | // Control Register flags 8 | #define CR0_PE 0x00000001 // Protection Enable 9 | #define CR0_WP 0x00010000 // Write Protect 10 | #define CR0_PG 0x80000000 // Paging 11 | 12 | #define CR4_PSE 0x00000010 // Page size extension 13 | 14 | // various segment selectors. 15 | #define SEG_KCODE 1 // kernel code 16 | #define SEG_KDATA 2 // kernel data+stack 17 | #define SEG_UCODE 3 // user code 18 | #define SEG_UDATA 4 // user data+stack 19 | #define SEG_TSS 5 // this process's task state 20 | 21 | // cpu->gdt[NSEGS] holds the above segments. 22 | #define NSEGS 6 23 | 24 | #ifndef __ASSEMBLER__ 25 | // Segment Descriptor 26 | struct segdesc { 27 | uint lim_15_0 : 16; // Low bits of segment limit 28 | uint base_15_0 : 16; // Low bits of segment base address 29 | uint base_23_16 : 8; // Middle bits of segment base address 30 | uint type : 4; // Segment type (see STS_ constants) 31 | uint s : 1; // 0 = system, 1 = application 32 | uint dpl : 2; // Descriptor Privilege Level 33 | uint p : 1; // Present 34 | uint lim_19_16 : 4; // High bits of segment limit 35 | uint avl : 1; // Unused (available for software use) 36 | uint rsv1 : 1; // Reserved 37 | uint db : 1; // 0 = 16-bit segment, 1 = 32-bit segment 38 | uint g : 1; // Granularity: limit scaled by 4K when set 39 | uint base_31_24 : 8; // High bits of segment base address 40 | }; 41 | 42 | // Normal segment 43 | #define SEG(type, base, lim, dpl) (struct segdesc) \ 44 | { ((lim) >> 12) & 0xffff, (uint)(base) & 0xffff, \ 45 | ((uint)(base) >> 16) & 0xff, type, 1, dpl, 1, \ 46 | (uint)(lim) >> 28, 0, 0, 1, 1, (uint)(base) >> 24 } 47 | #define SEG16(type, base, lim, dpl) (struct segdesc) \ 48 | { (lim) & 0xffff, (uint)(base) & 0xffff, \ 49 | ((uint)(base) >> 16) & 0xff, type, 1, dpl, 1, \ 50 | (uint)(lim) >> 16, 0, 0, 1, 0, (uint)(base) >> 24 } 51 | #endif 52 | 53 | #define DPL_USER 0x3 // User DPL 54 | 55 | // Application segment type bits 56 | #define STA_X 0x8 // Executable segment 57 | #define STA_W 0x2 // Writeable (non-executable segments) 58 | #define STA_R 0x2 // Readable (executable segments) 59 | 60 | // System segment type bits 61 | #define STS_T32A 0x9 // Available 32-bit TSS 62 | #define STS_IG32 0xE // 32-bit Interrupt Gate 63 | #define STS_TG32 0xF // 32-bit Trap Gate 64 | 65 | // A virtual address 'la' has a three-part structure as follows: 66 | // 67 | // +--------10------+-------10-------+---------12----------+ 68 | // | Page Directory | Page Table | Offset within Page | 69 | // | Index | Index | | 70 | // +----------------+----------------+---------------------+ 71 | // \--- PDX(va) --/ \--- PTX(va) --/ 72 | 73 | // page directory index 74 | #define PDX(va) (((uint)(va) >> PDXSHIFT) & 0x3FF) 75 | 76 | // page table index 77 | #define PTX(va) (((uint)(va) >> PTXSHIFT) & 0x3FF) 78 | 79 | // construct virtual address from indexes and offset 80 | #define PGADDR(d, t, o) ((uint)((d) << PDXSHIFT | (t) << PTXSHIFT | (o))) 81 | 82 | // Page directory and page table constants. 83 | #define NPDENTRIES 1024 // # directory entries per page directory 84 | #define NPTENTRIES 1024 // # PTEs per page table 85 | #define PGSIZE (1ul << 12) // bytes mapped by a page 86 | 87 | #define PTXSHIFT 12 // offset of PTX in a linear address 88 | #define PDXSHIFT 22 // offset of PDX in a linear address 89 | 90 | #define PGROUNDUP(sz) (((sz)+PGSIZE-1) & ~(PGSIZE-1)) 91 | #define PGROUNDDOWN(a) (((a)) & ~(PGSIZE-1)) 92 | 93 | // Page table/directory entry flags. 94 | #define PTE_P 0x001 // Present 95 | #define PTE_W 0x002 // Writeable 96 | #define PTE_U 0x004 // User 97 | #define PTE_PS 0x080 // Page Size 98 | 99 | // Address in page table or page directory entry 100 | #define PTE_ADDR(pte) ((uint)(pte) & ~0xFFF) 101 | #define PTE_FLAGS(pte) ((uint)(pte) & 0xFFF) 102 | 103 | #ifndef __ASSEMBLER__ 104 | typedef uint pte_t; 105 | 106 | // Task state segment format 107 | struct taskstate { 108 | uint link; // Old ts selector 109 | uint esp0; // Stack pointers and segment selectors 110 | ushort ss0; // after an increase in privilege level 111 | ushort padding1; 112 | uint *esp1; 113 | ushort ss1; 114 | ushort padding2; 115 | uint *esp2; 116 | ushort ss2; 117 | ushort padding3; 118 | void *cr3; // Page directory base 119 | uint *eip; // Saved state from last task switch 120 | uint eflags; 121 | uint eax; // More saved state (registers) 122 | uint ecx; 123 | uint edx; 124 | uint ebx; 125 | uint *esp; 126 | uint *ebp; 127 | uint esi; 128 | uint edi; 129 | ushort es; // Even more saved state (segment selectors) 130 | ushort padding4; 131 | ushort cs; 132 | ushort padding5; 133 | ushort ss; 134 | ushort padding6; 135 | ushort ds; 136 | ushort padding7; 137 | ushort fs; 138 | ushort padding8; 139 | ushort gs; 140 | ushort padding9; 141 | ushort ldt; 142 | ushort padding10; 143 | ushort t; // Trap on task switch 144 | ushort iomb; // I/O map base address 145 | }; 146 | 147 | // Gate descriptors for interrupts and traps 148 | struct gatedesc { 149 | uint off_15_0 : 16; // low 16 bits of offset in segment 150 | uint cs : 16; // code segment selector 151 | uint args : 5; // # args, 0 for interrupt/trap gates 152 | uint rsv1 : 3; // reserved(should be zero I guess) 153 | uint type : 4; // type(STS_{IG32,TG32}) 154 | uint s : 1; // must be 0 (system) 155 | uint dpl : 2; // descriptor(meaning new) privilege level 156 | uint p : 1; // Present 157 | uint off_31_16 : 16; // high bits of offset in segment 158 | }; 159 | 160 | // Set up a normal interrupt/trap gate descriptor. 161 | // - istrap: 1 for a trap (= exception) gate, 0 for an interrupt gate. 162 | // interrupt gate clears FL_IF, trap gate leaves FL_IF alone 163 | // - sel: Code segment selector for interrupt/trap handler 164 | // - off: Offset in code segment for interrupt/trap handler 165 | // - dpl: Descriptor Privilege Level - 166 | // the privilege level required for software to invoke 167 | // this interrupt/trap gate explicitly using an int instruction. 168 | #define SETGATE(gate, istrap, sel, off, d) \ 169 | { \ 170 | (gate).off_15_0 = (uint)(off) & 0xffff; \ 171 | (gate).cs = (sel); \ 172 | (gate).args = 0; \ 173 | (gate).rsv1 = 0; \ 174 | (gate).type = (istrap) ? STS_TG32 : STS_IG32; \ 175 | (gate).s = 0; \ 176 | (gate).dpl = (d); \ 177 | (gate).p = 1; \ 178 | (gate).off_31_16 = (uint)(off) >> 16; \ 179 | } 180 | 181 | #endif 182 | -------------------------------------------------------------------------------- /include/mp.h: -------------------------------------------------------------------------------- 1 | // See MultiProcessor Specification Version 1.[14] 2 | 3 | struct mp { // floating pointer 4 | uchar signature[4]; // "_MP_" 5 | //void *physaddr; // phys addr of MP config table, 32bits 6 | uint32_t physaddr; // phys addr of MP config table, 32bits 7 | uchar length; // 1 8 | uchar specrev; // [14] 9 | uchar checksum; // all bytes must add up to 0 10 | uchar type; // MP system config type 11 | uchar imcrp; 12 | uchar reserved[3]; 13 | }; 14 | 15 | struct mpconf { // configuration table header 16 | uchar signature[4]; // "PCMP" 17 | ushort length; // total table length 18 | uchar version; // [14] 19 | uchar checksum; // all bytes must add up to 0 20 | uchar product[20]; // product id 21 | // uint *oemtable; // OEM table pointer 22 | uint32_t oemtable; // OEM table pointer 23 | ushort oemlength; // OEM table length 24 | ushort entry; // entry count 25 | // uint *lapicaddr; // address of local APIC 26 | uint32_t lapicaddr; // address of local APIC 27 | ushort xlength; // extended table length 28 | uchar xchecksum; // extended table checksum 29 | uchar reserved; 30 | }; 31 | 32 | struct mpproc { // processor table entry 33 | uchar type; // entry type (0) 34 | uchar apicid; // local APIC id 35 | uchar version; // local APIC verison 36 | uchar flags; // CPU flags 37 | #define MPBOOT 0x02 // This proc is the bootstrap processor. 38 | uchar signature[4]; // CPU signature 39 | uint feature; // feature flags from CPUID instruction 40 | uchar reserved[8]; 41 | }; 42 | 43 | struct mpioapic { // I/O APIC table entry 44 | uchar type; // entry type (2) 45 | uchar apicno; // I/O APIC id 46 | uchar version; // I/O APIC version 47 | uchar flags; // I/O APIC flags 48 | // uint *addr; // I/O APIC address 49 | int addr; // I/O APIC address 50 | }; 51 | 52 | // Table entry types 53 | #define MPPROC 0x00 // One per processor 54 | #define MPBUS 0x01 // One per bus 55 | #define MPIOAPIC 0x02 // One per I/O APIC 56 | #define MPIOINTR 0x03 // One per bus interrupt source 57 | #define MPLINTR 0x04 // One per system interrupt source 58 | 59 | //PAGEBREAK! 60 | // Blank page. 61 | -------------------------------------------------------------------------------- /include/msr.h: -------------------------------------------------------------------------------- 1 | #ifndef _ASM_X86_MSR_INDEX_H 2 | #define _ASM_X86_MSR_INDEX_H 3 | 4 | /* CPU model specific register (MSR) numbers */ 5 | 6 | /* x86-64 specific MSRs */ 7 | #define MSR_EFER 0xc0000080 /* extended feature register */ 8 | #define MSR_STAR 0xc0000081 /* legacy mode SYSCALL target */ 9 | #define MSR_LSTAR 0xc0000082 /* long mode SYSCALL target */ 10 | #define MSR_CSTAR 0xc0000083 /* compat mode SYSCALL target */ 11 | #define MSR_SYSCALL_MASK 0xc0000084 /* EFLAGS mask for syscall */ 12 | #define MSR_FS_BASE 0xc0000100 /* 64bit FS base */ 13 | #define MSR_GS_BASE 0xc0000101 /* 64bit GS base */ 14 | #define MSR_KERNEL_GS_BASE 0xc0000102 /* SwapGS GS shadow */ 15 | #define MSR_TSC_AUX 0xc0000103 /* Auxiliary TSC */ 16 | 17 | /* EFER bits: */ 18 | #define _EFER_SCE 0 /* SYSCALL/SYSRET */ 19 | #define _EFER_LME 8 /* Long mode enable */ 20 | #define _EFER_LMA 10 /* Long mode active (read-only) */ 21 | #define _EFER_NX 11 /* No execute enable */ 22 | #define _EFER_SVME 12 /* Enable virtualization */ 23 | #define _EFER_LMSLE 13 /* Long Mode Segment Limit Enable */ 24 | #define _EFER_FFXSR 14 /* Enable Fast FXSAVE/FXRSTOR */ 25 | 26 | #define EFER_SCE (1<<_EFER_SCE) 27 | #define EFER_LME (1<<_EFER_LME) 28 | #define EFER_LMA (1<<_EFER_LMA) 29 | #define EFER_NX (1<<_EFER_NX) 30 | #define EFER_SVME (1<<_EFER_SVME) 31 | #define EFER_LMSLE (1<<_EFER_LMSLE) 32 | #define EFER_FFXSR (1<<_EFER_FFXSR) 33 | 34 | /* Intel MSRs. Some also available on other CPUs */ 35 | #define MSR_IA32_SPEC_CTRL 0x00000048 36 | #define MSR_IA32_PRED_CMD 0x00000049 37 | 38 | #define MSR_IA32_PERFCTR0 0x000000c1 39 | #define MSR_IA32_PERFCTR1 0x000000c2 40 | #define MSR_FSB_FREQ 0x000000cd 41 | 42 | #define MSR_MTRRcap 0x000000fe 43 | #define MSR_IA32_BBL_CR_CTL 0x00000119 44 | 45 | #define MSR_IA32_SYSENTER_CS 0x00000174 46 | #define MSR_IA32_SYSENTER_ESP 0x00000175 47 | #define MSR_IA32_SYSENTER_EIP 0x00000176 48 | 49 | #define MSR_IA32_MCG_CAP 0x00000179 50 | #define MSR_IA32_MCG_STATUS 0x0000017a 51 | #define MSR_IA32_MCG_CTL 0x0000017b 52 | 53 | #define MSR_IA32_PEBS_ENABLE 0x000003f1 54 | #define MSR_IA32_DS_AREA 0x00000600 55 | #define MSR_IA32_PERF_CAPABILITIES 0x00000345 56 | 57 | #define MSR_MTRRfix64K_00000 0x00000250 58 | #define MSR_MTRRfix16K_80000 0x00000258 59 | #define MSR_MTRRfix16K_A0000 0x00000259 60 | #define MSR_MTRRfix4K_C0000 0x00000268 61 | #define MSR_MTRRfix4K_C8000 0x00000269 62 | #define MSR_MTRRfix4K_D0000 0x0000026a 63 | #define MSR_MTRRfix4K_D8000 0x0000026b 64 | #define MSR_MTRRfix4K_E0000 0x0000026c 65 | #define MSR_MTRRfix4K_E8000 0x0000026d 66 | #define MSR_MTRRfix4K_F0000 0x0000026e 67 | #define MSR_MTRRfix4K_F8000 0x0000026f 68 | #define MSR_MTRRdefType 0x000002ff 69 | 70 | #define MSR_IA32_CR_PAT 0x00000277 71 | 72 | #define MSR_IA32_DEBUGCTLMSR 0x000001d9 73 | #define MSR_IA32_LASTBRANCHFROMIP 0x000001db 74 | #define MSR_IA32_LASTBRANCHTOIP 0x000001dc 75 | #define MSR_IA32_LASTINTFROMIP 0x000001dd 76 | #define MSR_IA32_LASTINTTOIP 0x000001de 77 | 78 | /* DEBUGCTLMSR bits (others vary by model): */ 79 | #define DEBUGCTLMSR_LBR (1UL << 0) /* last branch recording */ 80 | #define DEBUGCTLMSR_BTF (1UL << 1) /* single-step on branches */ 81 | #define DEBUGCTLMSR_TR (1UL << 6) 82 | #define DEBUGCTLMSR_BTS (1UL << 7) 83 | #define DEBUGCTLMSR_BTINT (1UL << 8) 84 | #define DEBUGCTLMSR_BTS_OFF_OS (1UL << 9) 85 | #define DEBUGCTLMSR_BTS_OFF_USR (1UL << 10) 86 | #define DEBUGCTLMSR_FREEZE_LBRS_ON_PMI (1UL << 11) 87 | 88 | #define MSR_IA32_MC0_CTL 0x00000400 89 | #define MSR_IA32_MC0_STATUS 0x00000401 90 | #define MSR_IA32_MC0_ADDR 0x00000402 91 | #define MSR_IA32_MC0_MISC 0x00000403 92 | 93 | #define MSR_IA32_MCx_CTL(x) (MSR_IA32_MC0_CTL + 4*(x)) 94 | #define MSR_IA32_MCx_STATUS(x) (MSR_IA32_MC0_STATUS + 4*(x)) 95 | #define MSR_IA32_MCx_ADDR(x) (MSR_IA32_MC0_ADDR + 4*(x)) 96 | #define MSR_IA32_MCx_MISC(x) (MSR_IA32_MC0_MISC + 4*(x)) 97 | 98 | /* These are consecutive and not in the normal 4er MCE bank block */ 99 | #define MSR_IA32_MC0_CTL2 0x00000280 100 | #define MSR_IA32_MCx_CTL2(x) (MSR_IA32_MC0_CTL2 + (x)) 101 | 102 | #define CMCI_EN (1ULL << 30) 103 | #define CMCI_THRESHOLD_MASK 0xffffULL 104 | 105 | #define MSR_P6_PERFCTR0 0x000000c1 106 | #define MSR_P6_PERFCTR1 0x000000c2 107 | #define MSR_P6_EVNTSEL0 0x00000186 108 | #define MSR_P6_EVNTSEL1 0x00000187 109 | 110 | /* AMD64 MSRs. Not complete. See the architecture manual for a more 111 | complete list. */ 112 | 113 | #define MSR_AMD64_PATCH_LEVEL 0x0000008b 114 | #define MSR_AMD64_NB_CFG 0xc001001f 115 | #define MSR_AMD64_PATCH_LOADER 0xc0010020 116 | #define MSR_AMD64_OSVW_ID_LENGTH 0xc0010140 117 | #define MSR_AMD64_OSVW_STATUS 0xc0010141 118 | #define MSR_AMD64_DC_CFG 0xc0011022 119 | #define MSR_AMD64_IBSFETCHCTL 0xc0011030 120 | #define MSR_AMD64_IBSFETCHLINAD 0xc0011031 121 | #define MSR_AMD64_IBSFETCHPHYSAD 0xc0011032 122 | #define MSR_AMD64_IBSOPCTL 0xc0011033 123 | #define MSR_AMD64_IBSOPRIP 0xc0011034 124 | #define MSR_AMD64_IBSOPDATA 0xc0011035 125 | #define MSR_AMD64_IBSOPDATA2 0xc0011036 126 | #define MSR_AMD64_IBSOPDATA3 0xc0011037 127 | #define MSR_AMD64_IBSDCLINAD 0xc0011038 128 | #define MSR_AMD64_IBSDCPHYSAD 0xc0011039 129 | #define MSR_AMD64_IBSCTL 0xc001103a 130 | 131 | /* Fam 10h MSRs */ 132 | #define MSR_FAM10H_MMIO_CONF_BASE 0xc0010058 133 | #define FAM10H_MMIO_CONF_ENABLE (1<<0) 134 | #define FAM10H_MMIO_CONF_BUSRANGE_MASK 0xf 135 | #define FAM10H_MMIO_CONF_BUSRANGE_SHIFT 2 136 | #define FAM10H_MMIO_CONF_BASE_MASK 0xfffffff 137 | #define FAM10H_MMIO_CONF_BASE_SHIFT 20 138 | #define MSR_FAM10H_NODE_ID 0xc001100c 139 | 140 | /* K8 MSRs */ 141 | #define MSR_K8_TOP_MEM1 0xc001001a 142 | #define MSR_K8_TOP_MEM2 0xc001001d 143 | #define MSR_K8_SYSCFG 0xc0010010 144 | #define MSR_K8_INT_PENDING_MSG 0xc0010055 145 | /* C1E active bits in int pending message */ 146 | #define K8_INTP_C1E_ACTIVE_MASK 0x18000000 147 | #define MSR_K8_TSEG_ADDR 0xc0010112 148 | #define K8_MTRRFIXRANGE_DRAM_ENABLE 0x00040000 /* MtrrFixDramEn bit */ 149 | #define K8_MTRRFIXRANGE_DRAM_MODIFY 0x00080000 /* MtrrFixDramModEn bit */ 150 | #define K8_MTRR_RDMEM_WRMEM_MASK 0x18181818 /* Mask: RdMem|WrMem */ 151 | 152 | /* K7 MSRs */ 153 | #define MSR_K7_EVNTSEL0 0xc0010000 154 | #define MSR_K7_PERFCTR0 0xc0010004 155 | #define MSR_K7_EVNTSEL1 0xc0010001 156 | #define MSR_K7_PERFCTR1 0xc0010005 157 | #define MSR_K7_EVNTSEL2 0xc0010002 158 | #define MSR_K7_PERFCTR2 0xc0010006 159 | #define MSR_K7_EVNTSEL3 0xc0010003 160 | #define MSR_K7_PERFCTR3 0xc0010007 161 | #define MSR_K7_CLK_CTL 0xc001001b 162 | #define MSR_K7_HWCR 0xc0010015 163 | #define MSR_K7_FID_VID_CTL 0xc0010041 164 | #define MSR_K7_FID_VID_STATUS 0xc0010042 165 | 166 | /* K6 MSRs */ 167 | #define MSR_K6_EFER 0xc0000080 168 | #define MSR_K6_STAR 0xc0000081 169 | #define MSR_K6_WHCR 0xc0000082 170 | #define MSR_K6_UWCCR 0xc0000085 171 | #define MSR_K6_EPMR 0xc0000086 172 | #define MSR_K6_PSOR 0xc0000087 173 | #define MSR_K6_PFIR 0xc0000088 174 | 175 | /* Centaur-Hauls/IDT defined MSRs. */ 176 | #define MSR_IDT_FCR1 0x00000107 177 | #define MSR_IDT_FCR2 0x00000108 178 | #define MSR_IDT_FCR3 0x00000109 179 | #define MSR_IDT_FCR4 0x0000010a 180 | 181 | #define MSR_IDT_MCR0 0x00000110 182 | #define MSR_IDT_MCR1 0x00000111 183 | #define MSR_IDT_MCR2 0x00000112 184 | #define MSR_IDT_MCR3 0x00000113 185 | #define MSR_IDT_MCR4 0x00000114 186 | #define MSR_IDT_MCR5 0x00000115 187 | #define MSR_IDT_MCR6 0x00000116 188 | #define MSR_IDT_MCR7 0x00000117 189 | #define MSR_IDT_MCR_CTRL 0x00000120 190 | 191 | /* VIA Cyrix defined MSRs*/ 192 | #define MSR_VIA_FCR 0x00001107 193 | #define MSR_VIA_LONGHAUL 0x0000110a 194 | #define MSR_VIA_RNG 0x0000110b 195 | #define MSR_VIA_BCR2 0x00001147 196 | 197 | /* Transmeta defined MSRs */ 198 | #define MSR_TMTA_LONGRUN_CTRL 0x80868010 199 | #define MSR_TMTA_LONGRUN_FLAGS 0x80868011 200 | #define MSR_TMTA_LRTI_READOUT 0x80868018 201 | #define MSR_TMTA_LRTI_VOLT_MHZ 0x8086801a 202 | 203 | /* Intel defined MSRs. */ 204 | #define MSR_IA32_P5_MC_ADDR 0x00000000 205 | #define MSR_IA32_P5_MC_TYPE 0x00000001 206 | #define MSR_IA32_TSC 0x00000010 207 | #define MSR_IA32_PLATFORM_ID 0x00000017 208 | #define MSR_IA32_EBL_CR_POWERON 0x0000002a 209 | #define MSR_IA32_FEATURE_CONTROL 0x0000003a 210 | #define MSR_IA32_TSC_ADJUST 0x0000003b 211 | 212 | #define FEATURE_CONTROL_LOCKED (1<<0) 213 | #define FEATURE_CONTROL_VMXON_ENABLED_INSIDE_SMX (1<<1) 214 | #define FEATURE_CONTROL_VMXON_ENABLED_OUTSIDE_SMX (1<<2) 215 | 216 | #define MSR_IA32_APICBASE 0x0000001b 217 | #define MSR_IA32_APICBASE_BSP (1<<8) 218 | #define MSR_IA32_APICBASE_ENABLE (1<<11) 219 | #define MSR_IA32_APICBASE_BASE (0xfffff<<12) 220 | 221 | #define MSR_IA32_UCODE_WRITE 0x00000079 222 | #define MSR_IA32_UCODE_REV 0x0000008b 223 | 224 | #define MSR_IA32_PERF_STATUS 0x00000198 225 | #define MSR_IA32_PERF_CTL 0x00000199 226 | 227 | #define MSR_IA32_MPERF 0x000000e7 228 | #define MSR_IA32_APERF 0x000000e8 229 | 230 | #define MSR_IA32_THERM_CONTROL 0x0000019a 231 | #define MSR_IA32_THERM_INTERRUPT 0x0000019b 232 | 233 | #define THERM_INT_LOW_ENABLE (1 << 0) 234 | #define THERM_INT_HIGH_ENABLE (1 << 1) 235 | 236 | #define MSR_IA32_THERM_STATUS 0x0000019c 237 | 238 | #define THERM_STATUS_PROCHOT (1 << 0) 239 | 240 | #define MSR_THERM2_CTL 0x0000019d 241 | 242 | #define MSR_THERM2_CTL_TM_SELECT (1ULL << 16) 243 | 244 | #define MSR_IA32_MISC_ENABLE 0x000001a0 245 | 246 | #define MSR_IA32_TEMPERATURE_TARGET 0x000001a2 247 | 248 | /* MISC_ENABLE bits: architectural */ 249 | #define MSR_IA32_MISC_ENABLE_FAST_STRING (1ULL << 0) 250 | #define MSR_IA32_MISC_ENABLE_TCC (1ULL << 1) 251 | #define MSR_IA32_MISC_ENABLE_EMON (1ULL << 7) 252 | #define MSR_IA32_MISC_ENABLE_BTS_UNAVAIL (1ULL << 11) 253 | #define MSR_IA32_MISC_ENABLE_PEBS_UNAVAIL (1ULL << 12) 254 | #define MSR_IA32_MISC_ENABLE_ENHANCED_SPEEDSTEP (1ULL << 16) 255 | #define MSR_IA32_MISC_ENABLE_MWAIT (1ULL << 18) 256 | #define MSR_IA32_MISC_ENABLE_LIMIT_CPUID (1ULL << 22) 257 | #define MSR_IA32_MISC_ENABLE_XTPR_DISABLE (1ULL << 23) 258 | #define MSR_IA32_MISC_ENABLE_XD_DISABLE (1ULL << 34) 259 | 260 | /* MISC_ENABLE bits: model-specific, meaning may vary from core to core */ 261 | #define MSR_IA32_MISC_ENABLE_X87_COMPAT (1ULL << 2) 262 | #define MSR_IA32_MISC_ENABLE_TM1 (1ULL << 3) 263 | #define MSR_IA32_MISC_ENABLE_SPLIT_LOCK_DISABLE (1ULL << 4) 264 | #define MSR_IA32_MISC_ENABLE_L3CACHE_DISABLE (1ULL << 6) 265 | #define MSR_IA32_MISC_ENABLE_SUPPRESS_LOCK (1ULL << 8) 266 | #define MSR_IA32_MISC_ENABLE_PREFETCH_DISABLE (1ULL << 9) 267 | #define MSR_IA32_MISC_ENABLE_FERR (1ULL << 10) 268 | #define MSR_IA32_MISC_ENABLE_FERR_MULTIPLEX (1ULL << 10) 269 | #define MSR_IA32_MISC_ENABLE_TM2 (1ULL << 13) 270 | #define MSR_IA32_MISC_ENABLE_ADJ_PREF_DISABLE (1ULL << 19) 271 | #define MSR_IA32_MISC_ENABLE_SPEEDSTEP_LOCK (1ULL << 20) 272 | #define MSR_IA32_MISC_ENABLE_L1D_CONTEXT (1ULL << 24) 273 | #define MSR_IA32_MISC_ENABLE_DCU_PREF_DISABLE (1ULL << 37) 274 | #define MSR_IA32_MISC_ENABLE_TURBO_DISABLE (1ULL << 38) 275 | #define MSR_IA32_MISC_ENABLE_IP_PREF_DISABLE (1ULL << 39) 276 | 277 | /* P4/Xeon+ specific */ 278 | #define MSR_IA32_MCG_EAX 0x00000180 279 | #define MSR_IA32_MCG_EBX 0x00000181 280 | #define MSR_IA32_MCG_ECX 0x00000182 281 | #define MSR_IA32_MCG_EDX 0x00000183 282 | #define MSR_IA32_MCG_ESI 0x00000184 283 | #define MSR_IA32_MCG_EDI 0x00000185 284 | #define MSR_IA32_MCG_EBP 0x00000186 285 | #define MSR_IA32_MCG_ESP 0x00000187 286 | #define MSR_IA32_MCG_EFLAGS 0x00000188 287 | #define MSR_IA32_MCG_EIP 0x00000189 288 | #define MSR_IA32_MCG_RESERVED 0x0000018a 289 | 290 | /* Pentium IV performance counter MSRs */ 291 | #define MSR_P4_BPU_PERFCTR0 0x00000300 292 | #define MSR_P4_BPU_PERFCTR1 0x00000301 293 | #define MSR_P4_BPU_PERFCTR2 0x00000302 294 | #define MSR_P4_BPU_PERFCTR3 0x00000303 295 | #define MSR_P4_MS_PERFCTR0 0x00000304 296 | #define MSR_P4_MS_PERFCTR1 0x00000305 297 | #define MSR_P4_MS_PERFCTR2 0x00000306 298 | #define MSR_P4_MS_PERFCTR3 0x00000307 299 | #define MSR_P4_FLAME_PERFCTR0 0x00000308 300 | #define MSR_P4_FLAME_PERFCTR1 0x00000309 301 | #define MSR_P4_FLAME_PERFCTR2 0x0000030a 302 | #define MSR_P4_FLAME_PERFCTR3 0x0000030b 303 | #define MSR_P4_IQ_PERFCTR0 0x0000030c 304 | #define MSR_P4_IQ_PERFCTR1 0x0000030d 305 | #define MSR_P4_IQ_PERFCTR2 0x0000030e 306 | #define MSR_P4_IQ_PERFCTR3 0x0000030f 307 | #define MSR_P4_IQ_PERFCTR4 0x00000310 308 | #define MSR_P4_IQ_PERFCTR5 0x00000311 309 | #define MSR_P4_BPU_CCCR0 0x00000360 310 | #define MSR_P4_BPU_CCCR1 0x00000361 311 | #define MSR_P4_BPU_CCCR2 0x00000362 312 | #define MSR_P4_BPU_CCCR3 0x00000363 313 | #define MSR_P4_MS_CCCR0 0x00000364 314 | #define MSR_P4_MS_CCCR1 0x00000365 315 | #define MSR_P4_MS_CCCR2 0x00000366 316 | #define MSR_P4_MS_CCCR3 0x00000367 317 | #define MSR_P4_FLAME_CCCR0 0x00000368 318 | #define MSR_P4_FLAME_CCCR1 0x00000369 319 | #define MSR_P4_FLAME_CCCR2 0x0000036a 320 | #define MSR_P4_FLAME_CCCR3 0x0000036b 321 | #define MSR_P4_IQ_CCCR0 0x0000036c 322 | #define MSR_P4_IQ_CCCR1 0x0000036d 323 | #define MSR_P4_IQ_CCCR2 0x0000036e 324 | #define MSR_P4_IQ_CCCR3 0x0000036f 325 | #define MSR_P4_IQ_CCCR4 0x00000370 326 | #define MSR_P4_IQ_CCCR5 0x00000371 327 | #define MSR_P4_ALF_ESCR0 0x000003ca 328 | #define MSR_P4_ALF_ESCR1 0x000003cb 329 | #define MSR_P4_BPU_ESCR0 0x000003b2 330 | #define MSR_P4_BPU_ESCR1 0x000003b3 331 | #define MSR_P4_BSU_ESCR0 0x000003a0 332 | #define MSR_P4_BSU_ESCR1 0x000003a1 333 | #define MSR_P4_CRU_ESCR0 0x000003b8 334 | #define MSR_P4_CRU_ESCR1 0x000003b9 335 | #define MSR_P4_CRU_ESCR2 0x000003cc 336 | #define MSR_P4_CRU_ESCR3 0x000003cd 337 | #define MSR_P4_CRU_ESCR4 0x000003e0 338 | #define MSR_P4_CRU_ESCR5 0x000003e1 339 | #define MSR_P4_DAC_ESCR0 0x000003a8 340 | #define MSR_P4_DAC_ESCR1 0x000003a9 341 | #define MSR_P4_FIRM_ESCR0 0x000003a4 342 | #define MSR_P4_FIRM_ESCR1 0x000003a5 343 | #define MSR_P4_FLAME_ESCR0 0x000003a6 344 | #define MSR_P4_FLAME_ESCR1 0x000003a7 345 | #define MSR_P4_FSB_ESCR0 0x000003a2 346 | #define MSR_P4_FSB_ESCR1 0x000003a3 347 | #define MSR_P4_IQ_ESCR0 0x000003ba 348 | #define MSR_P4_IQ_ESCR1 0x000003bb 349 | #define MSR_P4_IS_ESCR0 0x000003b4 350 | #define MSR_P4_IS_ESCR1 0x000003b5 351 | #define MSR_P4_ITLB_ESCR0 0x000003b6 352 | #define MSR_P4_ITLB_ESCR1 0x000003b7 353 | #define MSR_P4_IX_ESCR0 0x000003c8 354 | #define MSR_P4_IX_ESCR1 0x000003c9 355 | #define MSR_P4_MOB_ESCR0 0x000003aa 356 | #define MSR_P4_MOB_ESCR1 0x000003ab 357 | #define MSR_P4_MS_ESCR0 0x000003c0 358 | #define MSR_P4_MS_ESCR1 0x000003c1 359 | #define MSR_P4_PMH_ESCR0 0x000003ac 360 | #define MSR_P4_PMH_ESCR1 0x000003ad 361 | #define MSR_P4_RAT_ESCR0 0x000003bc 362 | #define MSR_P4_RAT_ESCR1 0x000003bd 363 | #define MSR_P4_SAAT_ESCR0 0x000003ae 364 | #define MSR_P4_SAAT_ESCR1 0x000003af 365 | #define MSR_P4_SSU_ESCR0 0x000003be 366 | #define MSR_P4_SSU_ESCR1 0x000003bf /* guess: not in manual */ 367 | 368 | #define MSR_P4_TBPU_ESCR0 0x000003c2 369 | #define MSR_P4_TBPU_ESCR1 0x000003c3 370 | #define MSR_P4_TC_ESCR0 0x000003c4 371 | #define MSR_P4_TC_ESCR1 0x000003c5 372 | #define MSR_P4_U2L_ESCR0 0x000003b0 373 | #define MSR_P4_U2L_ESCR1 0x000003b1 374 | 375 | #define MSR_P4_PEBS_MATRIX_VERT 0x000003f2 376 | 377 | /* Intel Core-based CPU performance counters */ 378 | #define MSR_CORE_PERF_FIXED_CTR0 0x00000309 379 | #define MSR_CORE_PERF_FIXED_CTR1 0x0000030a 380 | #define MSR_CORE_PERF_FIXED_CTR2 0x0000030b 381 | #define MSR_CORE_PERF_FIXED_CTR_CTRL 0x0000038d 382 | #define MSR_CORE_PERF_GLOBAL_STATUS 0x0000038e 383 | #define MSR_CORE_PERF_GLOBAL_CTRL 0x0000038f 384 | #define MSR_CORE_PERF_GLOBAL_OVF_CTRL 0x00000390 385 | 386 | /* Geode defined MSRs */ 387 | #define MSR_GEODE_BUSCONT_CONF0 0x00001900 388 | 389 | /* Intel VT MSRs */ 390 | #define MSR_IA32_VMX_BASIC 0x00000480 391 | #define MSR_IA32_VMX_PINBASED_CTLS 0x00000481 392 | #define MSR_IA32_VMX_PROCBASED_CTLS 0x00000482 393 | #define MSR_IA32_VMX_EXIT_CTLS 0x00000483 394 | #define MSR_IA32_VMX_ENTRY_CTLS 0x00000484 395 | #define MSR_IA32_VMX_MISC 0x00000485 396 | #define MSR_IA32_VMX_CR0_FIXED0 0x00000486 397 | #define MSR_IA32_VMX_CR0_FIXED1 0x00000487 398 | #define MSR_IA32_VMX_CR4_FIXED0 0x00000488 399 | #define MSR_IA32_VMX_CR4_FIXED1 0x00000489 400 | #define MSR_IA32_VMX_VMCS_ENUM 0x0000048a 401 | #define MSR_IA32_VMX_PROCBASED_CTLS2 0x0000048b 402 | #define MSR_IA32_VMX_EPT_VPID_CAP 0x0000048c 403 | #define MSR_IA32_VMX_TRUE_PIN 0x0000048d 404 | #define MSR_IA32_VMX_TRUE_PROC 0x0000048e 405 | #define MSR_IA32_VMX_TRUE_EXIT 0x0000048f 406 | #define MSR_IA32_VMX_TRUE_ENTRY 0x00000490 407 | 408 | #define MSR_IA32_TSCDEADLINE 0x000006e0 409 | 410 | /* AMD-V MSRs */ 411 | 412 | #define MSR_VM_CR 0xc0010114 413 | #define MSR_VM_IGNNE 0xc0010115 414 | #define MSR_VM_HSAVE_PA 0xc0010117 415 | 416 | #endif /* _ASM_X86_MSR_INDEX_H */ 417 | -------------------------------------------------------------------------------- /include/multiboot.h: -------------------------------------------------------------------------------- 1 | #include "types.h" 2 | 3 | struct mbi_bootinfo { 4 | u32 flags; 5 | u32 mem_lower; 6 | u32 mem_upper; 7 | u32 boot_device; 8 | u32 cmdline; 9 | u32 mods_count; 10 | u32 mods_addr; 11 | u32 reserved[4]; /* 28-39 */ 12 | u32 mmap_length; 13 | u32 mmap_addr; 14 | u32 reserved0[3]; /* 52-63 */ 15 | u32 bootloader; 16 | u32 reserved1[5]; /* 68-87 */ 17 | u32 size; 18 | }; 19 | 20 | 21 | 22 | typedef struct mmap_entry_t 23 | { 24 | uint32_t size; 25 | uint64_t base_addr; 26 | uint64_t length; 27 | uint32_t type; 28 | }__attribute__((packed)) mmap_entry_t; 29 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /include/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 | 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 | #ifdef __x86_64__ 21 | #define LARGE_PAGE_SIZE (512 * PAGE_SIZE) 22 | #else 23 | #define LARGE_PAGE_SIZE (1024 * PAGE_SIZE) 24 | #endif 25 | 26 | #define PT_PRESENT_MASK (1ull << 0) 27 | #define PT_WRITABLE_MASK (1ull << 1) 28 | #define PT_USER_MASK (1ull << 2) 29 | #define PT_ACCESSED_MASK (1ull << 5) 30 | #define PT_DIRTY_MASK (1ull << 6) 31 | #define PT_PAGE_SIZE_MASK (1ull << 7) 32 | #define PT64_NX_MASK (1ull << 63) 33 | //#define PT_ADDR_MASK GENMASK_ULL(51, 12) 34 | /* 35 | * Create a contiguous bitmask starting at bit position @l and ending at 36 | * position @h. For example 37 | * GENMASK_ULL(39, 21) gives us the 64bit vector 0x000000ffffe00000. 38 | */ 39 | 40 | #define GENMASK_ULL(h, l) \ 41 | (((~0ULL) << (l)) & (~0ULL >> (64 - 1 - (h)))) 42 | #define PT_ADDR_MASK GENMASK_ULL(51, 12) 43 | 44 | #define PT_AD_MASK (PT_ACCESSED_MASK | PT_DIRTY_MASK) 45 | 46 | #ifdef __x86_64__ 47 | #define PAGE_LEVEL 4 48 | #define PGDIR_WIDTH 9 49 | #define PGDIR_MASK 511 50 | #else 51 | #define PAGE_LEVEL 2 52 | #define PGDIR_WIDTH 10 53 | #define PGDIR_MASK 1023 54 | #endif 55 | 56 | #define PGDIR_BITS(lvl) (((lvl) - 1) * PGDIR_WIDTH + PAGE_SHIFT) 57 | #define PGDIR_OFFSET(va, lvl) (((va) >> PGDIR_BITS(lvl)) & PGDIR_MASK) 58 | 59 | #endif /* !__ASSEMBLY__ */ 60 | #endif 61 | -------------------------------------------------------------------------------- /include/param.h: -------------------------------------------------------------------------------- 1 | #define NPROC 64 // maximum number of processes 2 | #define KSTACKSIZE 4096 // size of per-process kernel stack 3 | #define NCPU 64 // maximum number of CPUs 4 | #define NOFILE 16 // open files per process 5 | #define NFILE 100 // open files per system 6 | #define NINODE 50 // maximum number of active i-nodes 7 | #define NDEV 10 // maximum major device number 8 | #define ROOTDEV 1 // device number of file system root disk 9 | #define MAXARG 32 // max exec arguments 10 | #define MAXOPBLOCKS 10 // max # of blocks any FS op writes 11 | #define LOGSIZE (MAXOPBLOCKS*3) // max data blocks in on-disk log 12 | #define NBUF (MAXOPBLOCKS*3) // size of disk block cache 13 | #define FSSIZE 1000 // size of file system in blocks 14 | 15 | -------------------------------------------------------------------------------- /include/proc.h: -------------------------------------------------------------------------------- 1 | // Per-CPU state 2 | struct cpu { 3 | uchar apicid; // Local APIC ID 4 | struct context *scheduler; // swtch() here to enter scheduler 5 | struct taskstate ts; // Used by x86 to find stack for interrupt 6 | struct segdesc gdt[NSEGS]; // x86 global descriptor table 7 | volatile uint started; // Has the CPU started? 8 | int ncli; // Depth of pushcli nesting. 9 | int intena; // Were interrupts enabled before pushcli? 10 | struct proc *proc; // The process running on this cpu or null 11 | }; 12 | 13 | extern struct cpu cpus[NCPU]; 14 | extern int ncpu; 15 | 16 | //PAGEBREAK: 17 17 | // Saved registers for kernel context switches. 18 | // Don't need to save all the segment registers (%cs, etc), 19 | // because they are constant across kernel contexts. 20 | // Don't need to save %eax, %ecx, %edx, because the 21 | // x86 convention is that the caller has saved them. 22 | // Contexts are stored at the bottom of the stack they 23 | // describe; the stack pointer is the address of the context. 24 | // The layout of the context matches the layout of the stack in swtch.S 25 | // at the "Switch stacks" comment. Switch doesn't save eip explicitly, 26 | // but it is on the stack and allocproc() manipulates it. 27 | struct context { 28 | uint edi; 29 | uint esi; 30 | uint ebx; 31 | uint ebp; 32 | uint eip; 33 | }; 34 | 35 | enum procstate { UNUSED, EMBRYO, SLEEPING, RUNNABLE, RUNNING, ZOMBIE }; 36 | 37 | // Per-process state 38 | struct proc { 39 | uint sz; // Size of process memory (bytes) 40 | pde_t* pgdir; // Page table 41 | char *kstack; // Bottom of kernel stack for this process 42 | enum procstate state; // Process state 43 | int pid; // Process ID 44 | struct proc *parent; // Parent process 45 | struct trapframe *tf; // Trap frame for current syscall 46 | struct context *context; // swtch() here to run process 47 | void *chan; // If non-zero, sleeping on chan 48 | int killed; // If non-zero, have been killed 49 | struct file *ofile[NOFILE]; // Open files 50 | struct inode *cwd; // Current directory 51 | char name[16]; // Process name (debugging) 52 | }; 53 | 54 | // Process memory is laid out contiguously, low addresses first: 55 | // text 56 | // original data and bss 57 | // fixed-size stack 58 | // expandable heap 59 | -------------------------------------------------------------------------------- /include/processor.h: -------------------------------------------------------------------------------- 1 | #include "desc.h" 2 | 3 | #ifdef __x86_64__ 4 | # define R "r" 5 | # define W "q" 6 | # define S "8" 7 | #else 8 | # define R "e" 9 | # define W "l" 10 | # define S "4" 11 | #endif 12 | 13 | static inline void lidt(idt_entry_t *p, int size) 14 | { 15 | struct { 16 | uint16_t limit; 17 | uint64_t base; 18 | } __attribute__((packed)) IDTR; 19 | 20 | IDTR.base = (uint64_t)p; 21 | IDTR.limit = (uint16_t)size; 22 | 23 | // asm volatile("lidt (%0)" : : "r" (IDTR)); 24 | asm volatile("lidtq %0\n" :: "m"(IDTR)); 25 | 26 | } 27 | 28 | 29 | static inline u16 read_cs(void) 30 | { 31 | unsigned val; 32 | 33 | asm volatile ("mov %%cs, %0" : "=mr"(val)); 34 | return val; 35 | } 36 | 37 | static inline void write_cr0(ulong val) 38 | { 39 | asm volatile ("mov %0, %%cr0" : : "r"(val) : "memory"); 40 | } 41 | 42 | static inline ulong read_cr0(void) 43 | { 44 | ulong val; 45 | asm volatile ("mov %%cr0, %0" : "=r"(val) : : "memory"); 46 | return val; 47 | } 48 | 49 | static inline void write_cr2(ulong val) 50 | { 51 | asm volatile ("mov %0, %%cr2" : : "r"(val) : "memory"); 52 | } 53 | 54 | static inline ulong read_cr2(void) 55 | { 56 | ulong val; 57 | asm volatile ("mov %%cr2, %0" : "=r"(val) : : "memory"); 58 | return val; 59 | } 60 | 61 | 62 | static inline void write_cr3(ulong val) 63 | { 64 | asm volatile ("mov %0, %%cr3" : : "r"(val) : "memory"); 65 | } 66 | 67 | static inline ulong read_cr3(void) 68 | { 69 | ulong val; 70 | asm volatile ("mov %%cr3, %0" : "=r"(val) : : "memory"); 71 | return val; 72 | } 73 | 74 | 75 | static inline void write_cr4(ulong val) 76 | { 77 | asm volatile ("mov %0, %%cr4" : : "r"(val) : "memory"); 78 | } 79 | 80 | static inline ulong read_cr4(void) 81 | { 82 | ulong val; 83 | asm volatile ("mov %%cr4, %0" : "=r"(val) : : "memory"); 84 | return val; 85 | } 86 | 87 | static inline void write_cr8(ulong val) 88 | { 89 | asm volatile ("mov %0, %%cr8" : : "r"(val) : "memory"); 90 | } 91 | 92 | static inline ulong read_cr8(void) 93 | { 94 | ulong val; 95 | asm volatile ("mov %%cr8, %0" : "=r"(val) : : "memory"); 96 | return val; 97 | } 98 | 99 | static inline u64 rdmsr(u32 index) 100 | { 101 | u32 a, d; 102 | asm volatile ("rdmsr" : "=a"(a), "=d"(d) : "c"(index) : "memory"); 103 | return a | ((u64)d << 32); 104 | } 105 | 106 | static inline void wrmsr(u32 index, u64 val) 107 | { 108 | u32 a = val, d = val >> 32; 109 | asm volatile ("wrmsr" : : "a"(a), "d"(d), "c"(index) : "memory"); 110 | } 111 | 112 | static inline void pause(void) 113 | { 114 | asm volatile ("pause"); 115 | } 116 | 117 | static inline void cli(void) 118 | { 119 | asm volatile ("cli"); 120 | } 121 | 122 | static inline void sti(void) 123 | { 124 | asm volatile ("sti"); 125 | } 126 | 127 | static inline uint64_t 128 | readeflags(void) 129 | { 130 | uint64_t eflags; 131 | asm volatile("pushf; pop %0" : "=r" (eflags)); 132 | return eflags; 133 | } 134 | 135 | static inline uint 136 | xchg(volatile uint *addr, uint newval) 137 | { 138 | uint result; 139 | 140 | // The + in "+m" denotes a read-modify-write operand. 141 | asm volatile("lock; xchgl %0, %1" : 142 | "+m" (*addr), "=a" (result) : 143 | "1" (newval) : 144 | "cc"); 145 | return result; 146 | } 147 | 148 | 149 | -------------------------------------------------------------------------------- /include/rdtsc.h: -------------------------------------------------------------------------------- 1 | 2 | #ifndef __RDTSC_H 3 | #define __RDTSC_H 4 | 5 | 6 | #define before(low,high) \ 7 | asm volatile( \ 8 | "cpuid\n\t" \ 9 | "rdtscp\n\t" \ 10 | "mov %%edx, %0\n\t" \ 11 | "mov %%eax, %1\n\t": "=r" (high), "=r" (low):: \ 12 | "%rax", "%rbx", "%rcx", "%rdx") 13 | 14 | #define after(low,high) \ 15 | asm volatile( \ 16 | "rdtscp\n\t" \ 17 | "mov %%edx, %0\n\t" \ 18 | "mov %%eax, %1\n\t" \ 19 | "cpuid\n\t" \ 20 | : "=r" (high), "=r" (low):: \ 21 | "%rax", "%rbx", "%rcx", "%rdx") 22 | 23 | #define rdtsc(low,high) \ 24 | __asm__ __volatile__("rdtsc":"=a"(low),"=d"(high)) 25 | 26 | #define rdtscll(val) \ 27 | __asm__ __volatile__("rdtsc":"=A"(val)) 28 | 29 | static inline unsigned long long currentcycles(){ 30 | unsigned long long cycles; 31 | __asm__ __volatile__("rdtsc":"=A"(cycles)); 32 | return cycles; 33 | } 34 | 35 | 36 | #endif 37 | 38 | 39 | -------------------------------------------------------------------------------- /include/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 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /include/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 "defs.h" 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 | -------------------------------------------------------------------------------- /include/traps.h: -------------------------------------------------------------------------------- 1 | // x86 trap and interrupt constants. 2 | 3 | // Processor-defined: 4 | #define T_DIVIDE 0 // divide error 5 | #define T_DEBUG 1 // debug exception 6 | #define T_NMI 2 // non-maskable interrupt 7 | #define T_BRKPT 3 // breakpoint 8 | #define T_OFLOW 4 // overflow 9 | #define T_BOUND 5 // bounds check 10 | #define T_ILLOP 6 // illegal opcode 11 | #define T_DEVICE 7 // device not available 12 | #define T_DBLFLT 8 // double fault 13 | // #define T_COPROC 9 // reserved (not used since 486) 14 | #define T_TSS 10 // invalid task switch segment 15 | #define T_SEGNP 11 // segment not present 16 | #define T_STACK 12 // stack exception 17 | #define T_GPFLT 13 // general protection fault 18 | #define T_PGFLT 14 // page fault 19 | // #define T_RES 15 // reserved 20 | #define T_FPERR 16 // floating point error 21 | #define T_ALIGN 17 // aligment check 22 | #define T_MCHK 18 // machine check 23 | #define T_SIMDERR 19 // SIMD floating point error 24 | 25 | // These are arbitrarily chosen, but with care not to overlap 26 | // processor defined exceptions or interrupt vectors. 27 | #define T_SYSCALL 64 // system call 28 | #define T_DEFAULT 500 // catchall 29 | 30 | #define T_IRQ0 32 // IRQ 0 corresponds to int T_IRQ 31 | 32 | #define IRQ_TIMER 0 33 | #define IRQ_KBD 1 34 | #define IRQ_COM1 4 35 | #define IRQ_IDE 14 36 | #define IRQ_ERROR 19 37 | #define IRQ_SPURIOUS 31 38 | 39 | -------------------------------------------------------------------------------- /include/types.h: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | 4 | typedef uint8_t u8; 5 | typedef int8_t s8; 6 | typedef uint16_t u16; 7 | typedef int16_t s16; 8 | typedef uint32_t u32; 9 | typedef int32_t s32; 10 | typedef uint64_t u64; 11 | typedef int64_t s64; 12 | typedef unsigned long ulong; 13 | 14 | typedef _Bool bool; 15 | #define false 0 16 | #define true 1 17 | 18 | // 32 16 8 19 | typedef unsigned int uint; 20 | typedef unsigned short ushort; 21 | typedef unsigned char uchar; 22 | typedef uint pde_t; 23 | 24 | typedef uint64_t phys_addr_t; 25 | typedef unsigned long uintptr_t; 26 | typedef unsigned long size_t; 27 | typedef unsigned long pteval_t; 28 | typedef unsigned long pgd_t; 29 | 30 | 31 | -------------------------------------------------------------------------------- /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 "types.h" 7 | #include "defs.h" 8 | 9 | /* 10 | * When exit(code) is invoked, qemu will exit with ((code << 1) | 1), 11 | * leaving us 128 exit status codes. To avoid confusion with signal 12 | * status, we further limit exit codes to those resulting in qemu 13 | * exiting with a status < 128. We give abort() the highest (127), 14 | * leaving the lower status codes for unit tests. 15 | */ 16 | #define ABORT_EXIT_STATUS 63 /* 127 exit status from qemu */ 17 | 18 | void abort(void) 19 | { 20 | exit(ABORT_EXIT_STATUS); 21 | } 22 | 23 | 24 | -------------------------------------------------------------------------------- /lib/printf.c: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | * libc printf and friends 4 | * 5 | * This code is free software; you can redistribute it and/or modify it 6 | * under the terms of the GNU Library General Public License version 2. 7 | */ 8 | 9 | #include "types.h" 10 | #include "defs.h" 11 | 12 | #define BUFSZ 2000 13 | 14 | 15 | typedef struct pstream { 16 | char *buffer; 17 | int remain; 18 | int added; 19 | } pstream_t; 20 | 21 | typedef struct strprops { 22 | char pad; 23 | int npad; 24 | bool alternate; 25 | } strprops_t; 26 | 27 | static void addchar(pstream_t *p, char c) 28 | { 29 | if (p->remain) { 30 | *p->buffer++ = c; 31 | --p->remain; 32 | } 33 | ++p->added; 34 | } 35 | 36 | static void print_str(pstream_t *p, const char *s, strprops_t props) 37 | { 38 | const char *s_orig = s; 39 | int npad = props.npad; 40 | 41 | if (npad > 0) { 42 | npad -= strlen(s_orig); 43 | while (npad > 0) { 44 | addchar(p, props.pad); 45 | --npad; 46 | } 47 | } 48 | 49 | while (*s) 50 | addchar(p, *s++); 51 | 52 | if (npad < 0) { 53 | props.pad = ' '; /* ignore '0' flag with '-' flag */ 54 | npad += strlen(s_orig); 55 | while (npad < 0) { 56 | addchar(p, props.pad); 57 | ++npad; 58 | } 59 | } 60 | } 61 | 62 | static char digits[16] = "0123456789abcdef"; 63 | 64 | static void print_int(pstream_t *ps, long long n, int base, strprops_t props) 65 | { 66 | char buf[sizeof(long) * 3 + 2], *p = buf; 67 | int s = 0, i; 68 | 69 | if (n < 0) { 70 | n = -n; 71 | s = 1; 72 | } 73 | 74 | while (n) { 75 | *p++ = digits[n % base]; 76 | n /= base; 77 | } 78 | 79 | if (s) 80 | *p++ = '-'; 81 | 82 | if (p == buf) 83 | *p++ = '0'; 84 | 85 | for (i = 0; i < (p - buf) / 2; ++i) { 86 | char tmp; 87 | 88 | tmp = buf[i]; 89 | buf[i] = p[-1-i]; 90 | p[-1-i] = tmp; 91 | } 92 | 93 | *p = 0; 94 | 95 | print_str(ps, buf, props); 96 | } 97 | 98 | static void print_unsigned(pstream_t *ps, unsigned long long n, int base, 99 | strprops_t props) 100 | { 101 | char buf[sizeof(long) * 3 + 3], *p = buf; 102 | int i; 103 | 104 | while (n) { 105 | *p++ = digits[n % base]; 106 | n /= base; 107 | } 108 | 109 | if (p == buf) 110 | *p++ = '0'; 111 | else if (props.alternate && base == 16) { 112 | if (props.pad == '0') { 113 | addchar(ps, '0'); 114 | addchar(ps, 'x'); 115 | 116 | if (props.npad > 0) 117 | props.npad = MAX(props.npad - 2, 0); 118 | } else { 119 | *p++ = 'x'; 120 | *p++ = '0'; 121 | } 122 | } 123 | 124 | for (i = 0; i < (p - buf) / 2; ++i) { 125 | char tmp; 126 | 127 | tmp = buf[i]; 128 | buf[i] = p[-1-i]; 129 | p[-1-i] = tmp; 130 | } 131 | 132 | *p = 0; 133 | 134 | print_str(ps, buf, props); 135 | } 136 | 137 | static int fmtnum(const char **fmt) 138 | { 139 | const char *f = *fmt; 140 | int len = 0, num; 141 | 142 | if (*f == '-') 143 | ++f, ++len; 144 | 145 | while (*f >= '0' && *f <= '9') 146 | ++f, ++len; 147 | 148 | num = atol(*fmt); 149 | *fmt += len; 150 | return num; 151 | } 152 | 153 | int vsnprintf(char *buf, int size, const char *fmt, va_list va) 154 | { 155 | pstream_t s; 156 | 157 | s.buffer = buf; 158 | s.remain = size - 1; 159 | s.added = 0; 160 | while (*fmt) { 161 | char f = *fmt++; 162 | int nlong = 0; 163 | strprops_t props; 164 | memset(&props, 0, sizeof(props)); 165 | props.pad = ' '; 166 | 167 | if (f != '%') { 168 | addchar(&s, f); 169 | continue; 170 | } 171 | morefmt: 172 | f = *fmt++; 173 | switch (f) { 174 | case '%': 175 | addchar(&s, '%'); 176 | break; 177 | case 'c': 178 | addchar(&s, va_arg(va, int)); 179 | break; 180 | case '\0': 181 | --fmt; 182 | break; 183 | case '#': 184 | props.alternate = true; 185 | goto morefmt; 186 | case '0': 187 | props.pad = '0'; 188 | ++fmt; 189 | /* fall through */ 190 | case '1'...'9': 191 | case '-': 192 | --fmt; 193 | props.npad = fmtnum(&fmt); 194 | goto morefmt; 195 | case 'l': 196 | ++nlong; 197 | goto morefmt; 198 | case 't': 199 | case 'z': 200 | /* Here we only care that sizeof(size_t) == sizeof(long). 201 | * On a 32-bit platform it doesn't matter that size_t is 202 | * typedef'ed to int or long; va_arg will work either way. 203 | * Same for ptrdiff_t (%td). 204 | */ 205 | nlong = 1; 206 | goto morefmt; 207 | case 'd': 208 | switch (nlong) { 209 | case 0: 210 | print_int(&s, va_arg(va, int), 10, props); 211 | break; 212 | case 1: 213 | print_int(&s, va_arg(va, long), 10, props); 214 | break; 215 | default: 216 | print_int(&s, va_arg(va, long long), 10, props); 217 | break; 218 | } 219 | break; 220 | case 'u': 221 | switch (nlong) { 222 | case 0: 223 | print_unsigned(&s, va_arg(va, unsigned), 10, props); 224 | break; 225 | case 1: 226 | print_unsigned(&s, va_arg(va, unsigned long), 10, props); 227 | break; 228 | default: 229 | print_unsigned(&s, va_arg(va, unsigned long long), 10, props); 230 | break; 231 | } 232 | break; 233 | case 'x': 234 | switch (nlong) { 235 | case 0: 236 | print_unsigned(&s, va_arg(va, unsigned), 16, props); 237 | break; 238 | case 1: 239 | print_unsigned(&s, va_arg(va, unsigned long), 16, props); 240 | break; 241 | default: 242 | print_unsigned(&s, va_arg(va, unsigned long long), 16, props); 243 | break; 244 | } 245 | break; 246 | case 'p': 247 | props.alternate = true; 248 | print_unsigned(&s, (unsigned long)va_arg(va, void *), 16, props); 249 | break; 250 | case 's': 251 | print_str(&s, va_arg(va, const char *), props); 252 | break; 253 | default: 254 | addchar(&s, f); 255 | break; 256 | } 257 | } 258 | *s.buffer = 0; 259 | return s.added; 260 | } 261 | 262 | 263 | int snprintf(char *buf, int size, const char *fmt, ...) 264 | { 265 | va_list va; 266 | int r; 267 | 268 | va_start(va, fmt); 269 | r = vsnprintf(buf, size, fmt, va); 270 | va_end(va); 271 | return r; 272 | } 273 | 274 | int vprintf(const char *fmt, va_list va) 275 | { 276 | char buf[BUFSZ]; 277 | int r; 278 | 279 | r = vsnprintf(buf, sizeof(buf), fmt, va); 280 | puts(buf); 281 | return r; 282 | } 283 | 284 | int printf(const char *fmt, ...) 285 | { 286 | va_list va; 287 | char buf[BUFSZ]; 288 | int r; 289 | 290 | va_start(va, fmt); 291 | r = vsnprintf(buf, sizeof buf, fmt, va); 292 | va_end(va); 293 | #ifdef __BARE_METAL 294 | console_puts(buf); 295 | #else 296 | puts(buf); 297 | #endif 298 | return r; 299 | } 300 | 301 | void binstr(unsigned long x, char out[BINSTR_SZ]) 302 | { 303 | int i; 304 | char *c; 305 | int n; 306 | 307 | n = sizeof(unsigned long) * 8; 308 | i = 0; 309 | c = &out[0]; 310 | for (;;) { 311 | *c++ = (x & (1ul << (n - i - 1))) ? '1' : '0'; 312 | i++; 313 | 314 | if (i == n) { 315 | *c = '\0'; 316 | break; 317 | } 318 | if (i % 4 == 0) 319 | *c++ = '\''; 320 | } 321 | assert(c + 1 - &out[0] == BINSTR_SZ); 322 | } 323 | 324 | void print_binstr(unsigned long x) 325 | { 326 | char out[BINSTR_SZ]; 327 | binstr(x, out); 328 | printf("%s", out); 329 | } 330 | 331 | /********************************************************************/ 332 | 333 | 334 | -------------------------------------------------------------------------------- /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 "types.h" 9 | #include 10 | #include "defs.h" 11 | 12 | #define MAX_DEPTH 20 13 | 14 | static void print_stack(const void **return_addrs, int depth, 15 | bool top_is_return_address) 16 | { 17 | int i = 0; 18 | 19 | printf("\tSTACK:"); 20 | 21 | /* @addr indicates a non-return address, as expected by the stack 22 | * pretty printer script. */ 23 | if (depth > 0 && !top_is_return_address) { 24 | printf(" @%lx", (unsigned long) return_addrs[0]); 25 | i++; 26 | } 27 | 28 | for (; i < depth; i++) { 29 | printf(" %lx", (unsigned long) return_addrs[i]); 30 | } 31 | printf("\n"); 32 | } 33 | 34 | void dump_stack(void) 35 | { 36 | const void *return_addrs[MAX_DEPTH]; 37 | int depth; 38 | 39 | depth = backtrace(return_addrs, MAX_DEPTH); 40 | print_stack(&return_addrs[1], depth ? depth - 1 : 0, true); 41 | } 42 | 43 | void dump_frame_stack(const void *instruction, const void *frame) 44 | { 45 | const void *return_addrs[MAX_DEPTH]; 46 | int depth; 47 | 48 | return_addrs[0] = instruction; 49 | depth = backtrace_frame(frame, &return_addrs[1], MAX_DEPTH - 1); 50 | print_stack(return_addrs, depth + 1, false); 51 | } 52 | 53 | #ifndef HAVE_ARCH_BACKTRACE 54 | int backtrace(const void **return_addrs, int max_depth) 55 | { 56 | static int walking; 57 | int depth = 0; 58 | void *addr; 59 | 60 | if (walking) { 61 | printf("RECURSIVE STACK WALK!!!\n"); 62 | return 0; 63 | } 64 | walking = 1; 65 | 66 | /* __builtin_return_address requires a compile-time constant argument */ 67 | #define GET_RETURN_ADDRESS(i) \ 68 | if (max_depth == i) \ 69 | goto done; \ 70 | addr = __builtin_return_address(i); \ 71 | if (!addr) \ 72 | goto done; \ 73 | return_addrs[i] = __builtin_extract_return_addr(addr); \ 74 | depth = i + 1; \ 75 | 76 | GET_RETURN_ADDRESS(0) 77 | GET_RETURN_ADDRESS(1) 78 | GET_RETURN_ADDRESS(2) 79 | GET_RETURN_ADDRESS(3) 80 | GET_RETURN_ADDRESS(4) 81 | GET_RETURN_ADDRESS(5) 82 | GET_RETURN_ADDRESS(6) 83 | GET_RETURN_ADDRESS(7) 84 | GET_RETURN_ADDRESS(8) 85 | GET_RETURN_ADDRESS(9) 86 | GET_RETURN_ADDRESS(10) 87 | GET_RETURN_ADDRESS(11) 88 | GET_RETURN_ADDRESS(12) 89 | GET_RETURN_ADDRESS(13) 90 | GET_RETURN_ADDRESS(14) 91 | GET_RETURN_ADDRESS(15) 92 | GET_RETURN_ADDRESS(16) 93 | GET_RETURN_ADDRESS(17) 94 | GET_RETURN_ADDRESS(18) 95 | GET_RETURN_ADDRESS(19) 96 | GET_RETURN_ADDRESS(20) 97 | 98 | #undef GET_RETURN_ADDRESS 99 | 100 | done: 101 | walking = 0; 102 | return depth; 103 | } 104 | #endif /* HAVE_ARCH_BACKTRACE */ 105 | -------------------------------------------------------------------------------- /lib/string.c: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | * libc string functions 4 | * 5 | * This code is free software; you can redistribute it and/or modify it 6 | * under the terms of the GNU Library General Public License version 2. 7 | */ 8 | 9 | #include "types.h" 10 | #include "defs.h" 11 | 12 | unsigned long strlen(const char *buf) 13 | { 14 | unsigned long len = 0; 15 | 16 | while (*buf++) 17 | ++len; 18 | return len; 19 | } 20 | 21 | char *strcat(char *dest, const char *src) 22 | { 23 | char *p = dest; 24 | 25 | while (*p) 26 | ++p; 27 | while ((*p++ = *src++) != 0) 28 | ; 29 | return dest; 30 | } 31 | 32 | char *strcpy(char *dest, const char *src) 33 | { 34 | *dest = 0; 35 | return strcat(dest, src); 36 | } 37 | 38 | int strncmp(const char *a, const char *b, size_t n) 39 | { 40 | for (; n--; ++a, ++b) 41 | if (*a != *b || *a == '\0') 42 | return *a - *b; 43 | 44 | return 0; 45 | } 46 | 47 | int strcmp(const char *a, const char *b) 48 | { 49 | return strncmp(a, b, SIZE_MAX); 50 | } 51 | 52 | char *strchr(const char *s, int c) 53 | { 54 | while (*s != (char)c) 55 | if (*s++ == '\0') 56 | return NULL; 57 | return (char *)s; 58 | } 59 | 60 | char *strstr(const char *s1, const char *s2) 61 | { 62 | size_t l1, l2; 63 | 64 | l2 = strlen(s2); 65 | if (!l2) 66 | return (char *)s1; 67 | l1 = strlen(s1); 68 | while (l1 >= l2) { 69 | l1--; 70 | if (!memcmp(s1, s2, l2)) 71 | return (char *)s1; 72 | s1++; 73 | } 74 | return NULL; 75 | } 76 | 77 | void *memset(void *s, int c, size_t n) 78 | { 79 | size_t i; 80 | char *a = s; 81 | 82 | for (i = 0; i < n; ++i) 83 | a[i] = c; 84 | 85 | return s; 86 | } 87 | 88 | void *memcpy(void *dest, const void *src, size_t n) 89 | { 90 | size_t i; 91 | char *a = dest; 92 | const char *b = src; 93 | 94 | for (i = 0; i < n; ++i) 95 | a[i] = b[i]; 96 | 97 | return dest; 98 | } 99 | 100 | int memcmp(const void *s1, const void *s2, size_t n) 101 | { 102 | const unsigned char *a = s1, *b = s2; 103 | int ret = 0; 104 | 105 | while (n--) { 106 | ret = *a - *b; 107 | if (ret) 108 | break; 109 | ++a, ++b; 110 | } 111 | return ret; 112 | } 113 | 114 | void *memmove(void *dest, const void *src, size_t n) 115 | { 116 | const unsigned char *s = src; 117 | unsigned char *d = dest; 118 | 119 | if (d <= s) { 120 | while (n--) 121 | *d++ = *s++; 122 | } else { 123 | d += n, s += n; 124 | while (n--) 125 | *--d = *--s; 126 | } 127 | return dest; 128 | } 129 | 130 | void *memchr(const void *s, int c, size_t n) 131 | { 132 | const unsigned char *str = s, chr = (unsigned char)c; 133 | 134 | while (n--) 135 | if (*str++ == chr) 136 | return (void *)(str - 1); 137 | return NULL; 138 | } 139 | 140 | long atol(const char *ptr) 141 | { 142 | long acc = 0; 143 | const char *s = ptr; 144 | int neg, c; 145 | 146 | while (*s == ' ' || *s == '\t') 147 | s++; 148 | if (*s == '-'){ 149 | neg = 1; 150 | s++; 151 | } else { 152 | neg = 0; 153 | if (*s == '+') 154 | s++; 155 | } 156 | 157 | while (*s) { 158 | if (*s < '0' || *s > '9') 159 | break; 160 | c = *s - '0'; 161 | acc = acc * 10 + c; 162 | s++; 163 | } 164 | 165 | if (neg) 166 | acc = -acc; 167 | 168 | return acc; 169 | } 170 | /* 171 | extern char **environ; 172 | 173 | char *getenv(const char *name) 174 | { 175 | char **envp = environ, *delim; 176 | 177 | while (*envp) { 178 | delim = strchr(*envp, '='); 179 | if (delim && strncmp(name, *envp, delim - *envp) == 0) 180 | return delim + 1; 181 | ++envp; 182 | } 183 | return NULL; 184 | } 185 | */ 186 | /* Very simple glob matching. Allows '*' at beginning and end of pattern. */ 187 | bool simple_glob(const char *text, const char *pattern) 188 | { 189 | bool star_start = false; 190 | bool star_end = false; 191 | size_t n = strlen(pattern); 192 | char copy[n + 1]; 193 | 194 | if (pattern[0] == '*') { 195 | pattern += 1; 196 | n -= 1; 197 | star_start = true; 198 | } 199 | 200 | strcpy(copy, pattern); 201 | 202 | if (n > 0 && pattern[n - 1] == '*') { 203 | n -= 1; 204 | copy[n] = '\0'; 205 | star_end = true; 206 | } 207 | 208 | if (star_start && star_end) 209 | return strstr(text, copy); 210 | 211 | if (star_end) 212 | return strstr(text, copy) == text; 213 | 214 | if (star_start) { 215 | size_t text_len = strlen(text); 216 | const char *suffix; 217 | 218 | if (n > text_len) 219 | return false; 220 | suffix = text + text_len - n; 221 | return !strcmp(suffix, copy); 222 | } 223 | 224 | return !strcmp(text, copy); 225 | } 226 | 227 | -------------------------------------------------------------------------------- /script/hyperbench.hvm: -------------------------------------------------------------------------------- 1 | # ===================================================================== 2 | # Example HVM guest configuration 3 | # ===================================================================== 4 | # 5 | # This is a fairly minimal example of what is required for an 6 | # HVM guest. For a more complete guide see xl.cfg(5) 7 | 8 | # This configures an HVM rather than PV guest 9 | builder = "hvm" 10 | 11 | # Guest name 12 | name = "hyperbench" 13 | 14 | # 128-bit UUID for the domain as a hexadecimal number. 15 | # Use "uuidgen" to generate one if required. 16 | # The default behavior is to generate a new UUID each time the guest is started. 17 | #uuid = "XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX" 18 | 19 | # Enable Microsoft Hyper-V compatibile paravirtualisation / 20 | # enlightenment interfaces. Turning this on can improve Windows guest 21 | # performance and is therefore recommended 22 | #viridian = 1 23 | 24 | # Initial memory allocation (MB) 25 | memory = 4096 26 | 27 | # Maximum memory (MB) 28 | # If this is greater than `memory' then the slack will start ballooned 29 | # (this assumes guest kernel support for ballooning) 30 | #maxmem = 512 31 | 32 | # Number of VCPUS 33 | vcpus = 2 34 | cpus = ["0", "1"] 35 | #cpus = ["4", "4"] 36 | 37 | # Network devices 38 | # A list of 'vifspec' entries as described in 39 | # docs/misc/xl-network-configuration.markdown 40 | #vif = [ '' ] 41 | 42 | # Disk Devices 43 | # A list of `diskspec' entries as described in 44 | # docs/misc/xl-disk-configuration.txt 45 | disk = [ '/opt/os.img,raw,hda,rw' ] 46 | 47 | # Guest VGA console configuration, either SDL or VNC 48 | #sdl = 1 49 | #vnc = 1 50 | 51 | ## custom 52 | serial = 'pty' 53 | nograhpic = 1 54 | -------------------------------------------------------------------------------- /script/pin: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | #var_test=`ps -eLo ruser,pid,ppid,lwp,psr,args | grep qemu | grep -v grep` 4 | #echo $var_test 5 | 6 | var=`ps -eLo ruser,pid,ppid,lwp,psr,args | grep qemu | grep -v grep | awk '{print $4}'` 7 | var_length=0 8 | var_index=0 9 | vcpu=0 10 | 11 | for i in $var 12 | do 13 | let var_length++ 14 | done 15 | 16 | 17 | for i in $var 18 | do 19 | echo "pin $i" 20 | if [ $var_index -gt $((var_length-3)) ] 21 | then 22 | taskset -p $((2<>16) & 0xFF) >= 4) 74 | lapicw(PCINT, MASKED); 75 | // Map error interrupt to IRQ_ERROR. 76 | lapicw(ERROR, T_IRQ0 + IRQ_ERROR); 77 | 78 | // Clear error status register (requires back-to-back writes). 79 | lapicw(ESR, 0); 80 | lapicw(ESR, 0); 81 | 82 | // Ack any outstanding interrupts. 83 | lapicw(EOI, 0); 84 | /* 85 | // Send an Init Level De-Assert to synchronise arbitration ID's. 86 | lapicw(ICRHI, 0); 87 | lapicw(ICRLO, BCAST | INIT | LEVEL); 88 | while(lapic[ICRLO] & DELIVS) 89 | ; 90 | */ 91 | // Enable interrupts on the APIC (but not on the processor). 92 | lapicw(TPR, 0); 93 | } 94 | 95 | 96 | // Spin for a given number of microseconds. 97 | // On real hardware would want to tune this dynamically. 98 | void 99 | microdelay(int us) 100 | { 101 | } 102 | 103 | #define CMOS_PORT 0x70 104 | #define CMOS_RETURN 0x71 105 | 106 | 107 | // Start additional processor running entry code at addr. 108 | void 109 | lapicstartap(uchar apicid, uint addr) 110 | { 111 | int i; 112 | ushort *wrv; 113 | // "The BSP must initialize CMOS shutdown code to 0AH 114 | // and the warm reset vector (DWORD based at 40:67) to point at 115 | // the AP startup code prior to the [universal startup algorithm]." 116 | outb(0xF, CMOS_PORT); // offset 0xF is shutdown code 117 | outb(0x0A, CMOS_PORT+1); 118 | wrv = (ushort*)(0x40<<4 | 0x67); // Warm reset vector 119 | wrv[0] = 0; 120 | wrv[1] = addr >> 4; 121 | 122 | // "Universal startup algorithm." 123 | // Send INIT (level-triggered) interrupt to reset other CPU. 124 | lapicw(ICRHI, apicid<<24); 125 | lapicw(ICRLO, INIT | LEVEL | ASSERT); 126 | microdelay(200); 127 | lapicw(ICRLO, INIT | LEVEL); 128 | microdelay(100); // should be 10ms, but too slow in Bochs! 129 | 130 | // Send startup IPI (twice!) to enter code. 131 | // Regular hardware is supposed to only accept a STARTUP 132 | // when it is in the halted state due to an INIT. So the second 133 | // should be ignored, but it is part of the official Intel algorithm. 134 | // Bochs complains about the second one. Too bad for Bochs. 135 | for(i = 0; i < 2; i++){ 136 | lapicw(ICRHI, apicid<<24); 137 | lapicw(ICRLO, STARTUP | (addr>>12)); 138 | microdelay(200); 139 | } 140 | 141 | } 142 | 143 | 144 | 145 | // Local APIC registers, divided by 4 for use as uint[] indices. 146 | #define ID (0x0020/4) // ID 147 | 148 | 149 | void *g_apic = (void *)0xfee00000; 150 | void *g_ioapic = (void *)0xfec00000; 151 | 152 | 153 | struct apic_ops { 154 | u32 (*reg_read)(unsigned reg); 155 | void (*reg_write)(unsigned reg, u32 val); 156 | void (*icr_write)(u32 val, u32 dest); 157 | u32 (*id)(void); 158 | }; 159 | /* 160 | static void outb(unsigned char data, unsigned short port) 161 | { 162 | asm volatile ("out %0, %1" : : "a"(data), "d"(port)); 163 | } 164 | */ 165 | void eoi(void) 166 | { 167 | apic_write(APIC_EOI, 0); 168 | } 169 | 170 | static u32 xapic_read(unsigned reg) 171 | { 172 | return *(volatile u32 *)(g_apic + reg); 173 | } 174 | 175 | static void xapic_write(unsigned reg, u32 val) 176 | { 177 | *(volatile u32 *)(g_apic + reg) = val; 178 | } 179 | 180 | static void xapic_icr_write(u32 val, u32 dest) 181 | { 182 | while (xapic_read(APIC_ICR) & APIC_ICR_BUSY) 183 | ; 184 | xapic_write(APIC_ICR2, dest << 24); 185 | xapic_write(APIC_ICR, val); 186 | } 187 | 188 | static uint32_t xapic_id(void) 189 | { 190 | return xapic_read(APIC_ID) >> 24; 191 | } 192 | 193 | static const struct apic_ops xapic_ops = { 194 | .reg_read = xapic_read, 195 | .reg_write = xapic_write, 196 | .icr_write = xapic_icr_write, 197 | .id = xapic_id, 198 | }; 199 | 200 | static const struct apic_ops *apic_ops = &xapic_ops; 201 | 202 | static u32 x2apic_read(unsigned reg) 203 | { 204 | unsigned a, d; 205 | 206 | asm volatile ("rdmsr" : "=a"(a), "=d"(d) : "c"(APIC_BASE_MSR + reg/16)); 207 | return a | (u64)d << 32; 208 | } 209 | 210 | static void x2apic_write(unsigned reg, u32 val) 211 | { 212 | asm volatile ("wrmsr" : : "a"(val), "d"(0), "c"(APIC_BASE_MSR + reg/16)); 213 | } 214 | 215 | static void x2apic_icr_write(u32 val, u32 dest) 216 | { 217 | asm volatile ("wrmsr" : : "a"(val), "d"(dest), 218 | "c"(APIC_BASE_MSR + APIC_ICR/16)); 219 | } 220 | 221 | static uint32_t x2apic_id(void) 222 | { 223 | return x2apic_read(APIC_ID); 224 | } 225 | 226 | static const struct apic_ops x2apic_ops = { 227 | .reg_read = x2apic_read, 228 | .reg_write = x2apic_write, 229 | .icr_write = x2apic_icr_write, 230 | .id = x2apic_id, 231 | }; 232 | 233 | u32 apic_read(unsigned reg) 234 | { 235 | return apic_ops->reg_read(reg); 236 | } 237 | 238 | void apic_write(unsigned reg, u32 val) 239 | { 240 | apic_ops->reg_write(reg, val); 241 | } 242 | 243 | bool apic_read_bit(unsigned reg, int n) 244 | { 245 | reg += (n >> 5) << 4; 246 | n &= 31; 247 | return (apic_read(reg) & (1 << n)) != 0; 248 | } 249 | 250 | void apic_icr_write(u32 val, u32 dest) 251 | { 252 | apic_ops->icr_write(val, dest); 253 | } 254 | 255 | uint32_t apic_id(void) 256 | { 257 | return apic_ops->id(); 258 | } 259 | 260 | uint8_t apic_get_tpr(void) 261 | { 262 | unsigned long tpr; 263 | 264 | #ifdef __x86_64__ 265 | asm volatile ("mov %%cr8, %0" : "=r"(tpr)); 266 | #else 267 | tpr = apic_read(APIC_TASKPRI) >> 4; 268 | #endif 269 | return tpr; 270 | } 271 | 272 | void apic_set_tpr(uint8_t tpr) 273 | { 274 | #ifdef __x86_64__ 275 | asm volatile ("mov %0, %%cr8" : : "r"((unsigned long) tpr)); 276 | #else 277 | apic_write(APIC_TASKPRI, tpr << 4); 278 | #endif 279 | } 280 | 281 | int enable_x2apic(void) 282 | { 283 | unsigned a, b, c, d; 284 | 285 | asm ("cpuid" : "=a"(a), "=b"(b), "=c"(c), "=d"(d) : "0"(1)); 286 | 287 | if (c & (1 << 21)) { 288 | asm ("rdmsr" : "=a"(a), "=d"(d) : "c"(MSR_IA32_APICBASE)); 289 | a |= 1 << 10; 290 | asm ("wrmsr" : : "a"(a), "d"(d), "c"(MSR_IA32_APICBASE)); 291 | apic_ops = &x2apic_ops; 292 | return 1; 293 | } else { 294 | return 0; 295 | } 296 | } 297 | 298 | void disable_apic(void) 299 | { 300 | wrmsr(MSR_IA32_APICBASE, rdmsr(MSR_IA32_APICBASE) & ~(APIC_EN | APIC_EXTD)); 301 | apic_ops = &xapic_ops; 302 | } 303 | 304 | void reset_apic(void) 305 | { 306 | disable_apic(); 307 | wrmsr(MSR_IA32_APICBASE, rdmsr(MSR_IA32_APICBASE) | APIC_EN); 308 | } 309 | 310 | u32 ioapic_read_reg(unsigned reg) 311 | { 312 | *(volatile u32 *)g_ioapic = reg; 313 | return *(volatile u32 *)(g_ioapic + 0x10); 314 | } 315 | 316 | void ioapic_write_reg(unsigned reg, u32 value) 317 | { 318 | *(volatile u32 *)g_ioapic = reg; 319 | *(volatile u32 *)(g_ioapic + 0x10) = value; 320 | } 321 | 322 | void ioapic_write_redir(unsigned line, ioapic_redir_entry_t e) 323 | { 324 | ioapic_write_reg(0x10 + line * 2 + 0, ((u32 *)&e)[0]); 325 | ioapic_write_reg(0x10 + line * 2 + 1, ((u32 *)&e)[1]); 326 | } 327 | 328 | ioapic_redir_entry_t ioapic_read_redir(unsigned line) 329 | { 330 | ioapic_redir_entry_t e; 331 | 332 | ((u32 *)&e)[0] = ioapic_read_reg(0x10 + line * 2 + 0); 333 | ((u32 *)&e)[1] = ioapic_read_reg(0x10 + line * 2 + 1); 334 | return e; 335 | 336 | } 337 | 338 | void ioapic_set_redir(unsigned line, unsigned vec, 339 | trigger_mode_t trig_mode) 340 | { 341 | ioapic_redir_entry_t e = { 342 | .vector = vec, 343 | .delivery_mode = 0, 344 | .trig_mode = trig_mode, 345 | }; 346 | 347 | ioapic_write_redir(line, e); 348 | } 349 | 350 | void set_mask(unsigned line, int mask) 351 | { 352 | ioapic_redir_entry_t e = ioapic_read_redir(line); 353 | 354 | e.mask = mask; 355 | ioapic_write_redir(line, e); 356 | } 357 | 358 | void set_irq_line(unsigned line, int val) 359 | { 360 | asm volatile("out %0, %1" : : "a"((u8)val), "d"((u16)(0x2000 + line))); 361 | } 362 | 363 | void enable_apic(void) 364 | { 365 | printf("enabling apic\r\n"); 366 | xapic_write(0xf0, 0x1ff); /* spurious vector register */ 367 | } 368 | 369 | /* 370 | PIC (8259A) 371 | master port address 0x20, 0x21 372 | slave port address 0xA0, 0xA1 373 | */ 374 | void mask_pic_interrupts(void) 375 | { 376 | outb(0xff, 0x21); 377 | outb(0xff, 0xa1); 378 | } 379 | 380 | int 381 | lapicid(void) 382 | { 383 | if (!lapic) 384 | return 0; 385 | //printf("lapicid = %d\n",lapic[ID]); 386 | return lapic[ID] >> 24; 387 | } 388 | 389 | 390 | -------------------------------------------------------------------------------- /x86_64/console.c: -------------------------------------------------------------------------------- 1 | 2 | #include "types.h" 3 | #include "defs.h" 4 | #include "spinlock.h" 5 | 6 | #define ROWS 25 7 | #define COLUMNS 80 8 | 9 | static struct spinlock lock; 10 | 11 | static int console_cleared = 0; 12 | 13 | static unsigned int cur_x, cur_y; 14 | static uint16_t *vga = (uint16_t *)0xb8000; 15 | 16 | static inline uint16_t *slot_from_xy(unsigned int x, unsigned int y) 17 | { 18 | if (x >= COLUMNS) return 0; 19 | if (y >= ROWS) return 0; 20 | 21 | return &vga[x + (y * COLUMNS)]; 22 | } 23 | 24 | void console_clear() 25 | { 26 | int i; 27 | 28 | for (i = 0; i < ROWS * COLUMNS; i++) { 29 | vga[i] = 0; 30 | } 31 | 32 | cur_x = 0; 33 | cur_y = 0; 34 | } 35 | 36 | 37 | static void write_reg(char reg, char val) 38 | { 39 | asm volatile("outb %0, %1\n" :: "a"(reg), "d"((unsigned short)0x3d4)); 40 | asm volatile("outb %0, %1\n" :: "a"(val), "d"((unsigned short)0x3d5)); 41 | } 42 | 43 | void console_init() 44 | { 45 | // Disable the cursor 46 | write_reg(0x0a, 0x20); 47 | console_clear(); 48 | } 49 | 50 | static void new_line() 51 | { 52 | int y, x; 53 | 54 | cur_x = 0; 55 | 56 | cur_y++; 57 | if (cur_y >= ROWS) { 58 | cur_y = ROWS - 1; 59 | 60 | for (y = 0; y < ROWS - 1; y++) { 61 | for (x = 0; x < COLUMNS; x++) { 62 | *slot_from_xy(x, y) = *slot_from_xy(x, y + 1); 63 | } 64 | } 65 | 66 | for (x = 0; x < COLUMNS; x++) { 67 | *slot_from_xy(x, ROWS - 1) = 0; 68 | } 69 | } 70 | } 71 | 72 | void console_putc(char ch) 73 | { 74 | if (ch == '\n') { 75 | new_line(); 76 | } else if (ch == '\r') { 77 | cur_x = 0; 78 | } else { 79 | uint16_t *slot = slot_from_xy(cur_x, cur_y); 80 | *slot = 0x0700 | ch; 81 | 82 | cur_x++; 83 | if (cur_x >= COLUMNS) { 84 | new_line(); 85 | } 86 | } 87 | } 88 | 89 | void console_puts(const char *buf) 90 | { 91 | spin_lock(&lock); 92 | unsigned long len = strlen(buf); 93 | unsigned long i; 94 | 95 | if (!console_cleared) { 96 | console_init(); 97 | console_cleared = 1; 98 | } 99 | 100 | for(i = 0; i < len; i++){ 101 | console_putc(buf[i]); 102 | } 103 | spin_unlock(&lock); 104 | } 105 | 106 | 107 | 108 | -------------------------------------------------------------------------------- /x86_64/cstart.S: -------------------------------------------------------------------------------- 1 | 2 | # Using GRUB 2, you can boot HyperBench kernel from a file stored in a 3 | # Linux file system by copying kernel to /boot 4 | # and then adding this entry 5 | 6 | # menuentry 'HyperBench'{ 7 | # insmod part_msdos 8 | # insmod ext2 9 | # set root='hd0,msdos1' 10 | # multiboot /boot/hyperbench.64 11 | # } 12 | 13 | #include "asm.h" 14 | #include "memlayout.h" 15 | #include "mmu.h" 16 | #include "param.h" 17 | 18 | #define MULTIBOOT_HEADER_MAGIC 0x1BADB002 19 | #define MULTIBOOT_HEADER_FLAGS 0x00000000 20 | 21 | //.globl boot_idt 22 | //.globl idt_descr 23 | .globl gdt64_desc 24 | 25 | //boot_idt = 0 26 | 27 | .code32 28 | # multiboot header 29 | .long MULTIBOOT_HEADER_MAGIC 30 | .long MULTIBOOT_HEADER_FLAGS 31 | .long -(MULTIBOOT_HEADER_MAGIC + MULTIBOOT_HEADER_FLAGS) 32 | 33 | # By convention, the "start" symbol specifies the ELF entry point. 34 | # Since we haven't set up virtual memory yet, our entry point is 35 | # the physical address of '_start'. 36 | //.globl _start 37 | //_start = V2P_WO(entry) 38 | 39 | # Entering HyperBench kernel on boot processor, with paging off. 40 | 41 | .globl entry 42 | entry: 43 | mov %ebx, mb_boot_info 44 | mov %eax, mb_magic 45 | mov $stacktop, %esp 46 | call prepare_64 47 | jmpl $8, $start64 48 | 49 | prepare_64: 50 | lgdt gdt64_desc 51 | 52 | enter_long_mode: 53 | # Turn on page size extension for 4Mbyte pages 54 | mov %cr4, %eax 55 | bts $5, %eax 56 | mov %eax, %cr4 57 | # Set page directory 58 | // mov $(V2P_WO(entrypml4e)), %eax 59 | mov pt_root, %eax 60 | mov %eax, %cr3 61 | 62 | # IA32_EFER.LME = 1, Enables IA-32e mode operation. 63 | efer = 0xC0000080 64 | mov $efer, %ecx 65 | rdmsr 66 | bts $8, %eax 67 | wrmsr 68 | 69 | # Turn on paging 70 | mov %cr0, %eax 71 | bts $0, %eax 72 | bts $31, %eax 73 | mov %eax, %cr0 74 | ret 75 | 76 | .code64 77 | 78 | start64: 79 | // lidtq idt_descr 80 | mov mb_boot_info(%rip), %rbx 81 | mov %rbx, %rdi 82 | mov mb_magic(%rip), %rbx 83 | mov %rbx, %rsi 84 | // call sipi_entry_mov 85 | call main 86 | 87 | /***********************************************************************/ 88 | smp_stacktop: .long 0xa0000 89 | .code16 90 | sipi_entry: 91 | mov %cr0, %eax 92 | or $1, %eax 93 | mov %eax, %cr0 94 | lgdtl gdt32_descr - sipi_entry 95 | ljmpl $8, $ap_start32 96 | 97 | gdt32_descr: 98 | .word gdt32_end -gdt32 -1 99 | .long gdt32 100 | 101 | gdt32: 102 | .quad 0 103 | .quad 0x00cf9b000000ffff // flat 32-bit code segment 104 | .quad 0x00cf93000000ffff // flat 32-bit data segment 105 | gdt32_end: 106 | 107 | sipi_end: 108 | 109 | .code32 110 | ap_start32: 111 | # Set up the protected-mode data segment registers 112 | mov $(SEG_KDATA<<3), %ax # Our data segment selector 113 | mov %ax, %ds 114 | mov %ax, %es 115 | mov %ax, %fs 116 | mov %ax, %gs 117 | mov %ax, %ss 118 | mov $-4096, %esp 119 | lock/xaddl %esp, smp_stacktop 120 | call prepare_64 121 | ljmpl $8, $ap_start64 122 | 123 | .code64 124 | ap_start64: 125 | call mpenter 126 | sti // Enable external Interrupt 127 | nop 128 | 1: 129 | hlt 130 | jmp 1b 131 | 132 | .globl sipi_entry_mov 133 | sipi_entry_mov: 134 | cld 135 | lea sipi_entry, %rsi 136 | xor %rdi, %rdi 137 | mov $(sipi_end - sipi_entry), %rcx 138 | rep/movsb 139 | // call DEBUG 140 | ret 141 | 142 | /***********************************************************************/ 143 | .data 144 | 145 | pt_root: .quad ptl4 146 | mb_boot_info: .quad 0 147 | mb_magic: .quad 0 148 | 149 | //idt_descr: 150 | // .word 16 * 256 - 1 151 | // .quad boot_idt 152 | 153 | /* Linear-Address Translation to a 2-MByte Page using 4-Level Paging */ 154 | .align 4096 155 | .globl ptl2 156 | ptl2: 157 | i = 0 158 | .rept 512 * 4 159 | .quad 0x1e7 | (i << 21) 160 | i = i + 1 161 | .endr 162 | 163 | .align 4096 164 | ptl3: 165 | .quad ptl2 + 7 + 0 * 4096 166 | .quad ptl2 + 7 + 1 * 4096 167 | .quad ptl2 + 7 + 2 * 4096 168 | .quad ptl2 + 7 + 3 * 4096 169 | 170 | .align 4096 171 | ptl4: 172 | .quad ptl3 + 7 173 | 174 | .align 4096 175 | 176 | 177 | gdt64_desc: 178 | .word gdt64_end - gdt64 - 1 179 | .quad gdt64 180 | 181 | gdt64: 182 | .quad 0 183 | .quad 0x00af9b000000ffff // 64-bit code segment, selector = 0x08 184 | .quad 0x00cf93000000ffff // 32/64-bit data segment, selector = 0x10 185 | .quad 0x00af1b000000ffff // 64-bit code segment, not present, 0x18 186 | .quad 0x00cf9b000000ffff // 32-bit code segment, 0x20 187 | .quad 0x008f9b000000FFFF // 16-bit code segment, 0x28 188 | .quad 0x008f93000000FFFF // 16-bit data segment, 0x30 189 | .quad 0x00cffb000000ffff // 32-bit code segment (user), 0x38 190 | .quad 0x00cff3000000ffff // 32/64-bit data segment (user), 0x40 191 | .quad 0x00affb000000ffff // 64-bit code segment (user), 0x48 192 | /* 6 spare selectors */ 193 | .word 0xffff, 0x0, 0x9200, 0x00cf // IDT Selector, 0x50 194 | .quad 0 195 | .quad 0 196 | .quad 0 197 | .quad 0 198 | .quad 0 199 | gdt64_end: 200 | 201 | /*******************************************************************************/ 202 | max_cpus = 64 203 | .align 4096 204 | .bss 205 | . = . + 4096 * max_cpus 206 | .align 16 207 | stacktop: 208 | . = . + 4096 209 | .align 16 210 | ring0stacktop: 211 | 212 | 213 | 214 | 215 | 216 | -------------------------------------------------------------------------------- /x86_64/desc.c: -------------------------------------------------------------------------------- 1 | #include "defs.h" 2 | #include "desc.h" 3 | #include "processor.h" 4 | #include "string.h" 5 | 6 | static handler exception_handlers[256]; 7 | extern struct ex_record exception_table_start, exception_table_end; 8 | 9 | void set_idt_entry(int vec, void *addr, int dpl) 10 | { 11 | idt_entry_t *e = &boot_idt[vec]; 12 | memset(e, 0, sizeof *e); 13 | e->offset0 = (unsigned long)addr; 14 | e->selector = read_cs(); 15 | e->ist = 0; 16 | e->type = 14; 17 | e->dpl = dpl; 18 | e->p = 1; 19 | e->offset1 = (unsigned long)addr >> 16; 20 | #ifdef __x86_64__ 21 | e->offset2 = (unsigned long)addr >> 32; 22 | #endif 23 | } 24 | 25 | struct ex_record { 26 | unsigned long rip; 27 | unsigned long handler; 28 | }; 29 | 30 | static const char* exception_mnemonic(int vector) 31 | { 32 | switch(vector) { 33 | case 0: return "#DE"; 34 | case 1: return "#DB"; 35 | case 2: return "#NMI"; 36 | case 3: return "#BP"; 37 | case 4: return "#OF"; 38 | case 5: return "#BR"; 39 | case 6: return "#UD"; 40 | case 7: return "#NM"; 41 | case 8: return "#DF"; 42 | case 10: return "#TS"; 43 | case 11: return "#NP"; 44 | case 12: return "#SS"; 45 | case 13: return "#GP"; 46 | case 14: return "#PF"; 47 | case 16: return "#MF"; 48 | case 17: return "#AC"; 49 | case 18: return "#MC"; 50 | case 19: return "#XM"; 51 | default: return "#??"; 52 | } 53 | } 54 | 55 | static void unhandled_exception(struct ex_regs *regs, bool cpu) 56 | { 57 | printf("Unhandled %sexception %ld %s at ip %016lx\n", 58 | cpu ? "cpu " : "", regs->vector, 59 | exception_mnemonic(regs->vector), regs->rip); 60 | if (regs->vector == 14) 61 | printf("PF at %#lx addr %#lx\n", regs->rip, read_cr2()); 62 | 63 | printf("error_code=%04lx rflags=%08lx cs=%08lx\n" 64 | "rax=%016lx rcx=%016lx rdx=%016lx rbx=%016lx\n" 65 | "rbp=%016lx rsi=%016lx rdi=%016lx\n" 66 | #ifdef __x86_64__ 67 | " r8=%016lx r9=%016lx r10=%016lx r11=%016lx\n" 68 | "r12=%016lx r13=%016lx r14=%016lx r15=%016lx\n" 69 | #endif 70 | "cr0=%016lx cr2=%016lx cr3=%016lx cr4=%016lx\n" 71 | #ifdef __x86_64__ 72 | "cr8=%016lx\n" 73 | #endif 74 | , 75 | regs->error_code, regs->rflags, regs->cs, 76 | regs->rax, regs->rcx, regs->rdx, regs->rbx, 77 | regs->rbp, regs->rsi, regs->rdi, 78 | #ifdef __x86_64__ 79 | regs->r8, regs->r9, regs->r10, regs->r11, 80 | regs->r12, regs->r13, regs->r14, regs->r15, 81 | #endif 82 | read_cr0(), read_cr2(), read_cr3(), read_cr4() 83 | #ifdef __x86_64__ 84 | , read_cr8() 85 | #endif 86 | ); 87 | //dump_frame_stack((void*) regs->rip, (void*) regs->rbp); 88 | //abort(); 89 | //platform_shutdown(); 90 | while(1); 91 | } 92 | 93 | 94 | static void check_exception_table(struct ex_regs *regs) 95 | { 96 | 97 | struct ex_record *ex; 98 | unsigned ex_val; 99 | 100 | ex_val = regs->vector | (regs->error_code << 16) | 101 | (((regs->rflags >> 16) & 1) << 8); 102 | 103 | //fprintf(OUTPUT, "regs->vector = %x\n", regs->vector); 104 | 105 | asm("mov %0, %%gs:4" : : "r"(ex_val)); 106 | 107 | for (ex = &exception_table_start; ex != &exception_table_end; ++ex) { 108 | if (ex->rip == regs->rip) { 109 | // fprintf(OUTPUT, "=====\n"); 110 | regs->rip = ex->handler; 111 | return; 112 | } 113 | } 114 | unhandled_exception(regs, false); 115 | //fprintf(OUTPUT, "After\n"); 116 | } 117 | 118 | 119 | handler handle_exception(u8 v, handler fn) 120 | { 121 | handler old; 122 | 123 | old = exception_handlers[v]; 124 | if (v < 256) 125 | exception_handlers[v] = fn; 126 | return old; 127 | } 128 | 129 | #ifndef __x86_64__ 130 | __attribute__((regparm(1))) 131 | #endif 132 | void do_handle_exception(struct ex_regs *regs) 133 | { 134 | if (regs->vector < 256 && exception_handlers[regs->vector]) { 135 | exception_handlers[regs->vector](regs); 136 | return; 137 | } 138 | 139 | unhandled_exception(regs, true); 140 | } 141 | 142 | 143 | #define EX(NAME, N) extern char NAME##_fault; \ 144 | asm (".pushsection .text \n\t" \ 145 | #NAME"_fault: \n\t" \ 146 | "push"W" $0 \n\t" \ 147 | "push"W" $"#N" \n\t" \ 148 | "jmp __handle_exception \n\t" \ 149 | ".popsection") 150 | 151 | #define EX_E(NAME, N) extern char NAME##_fault; \ 152 | asm (".pushsection .text \n\t" \ 153 | #NAME"_fault: \n\t" \ 154 | "push"W" $"#N" \n\t" \ 155 | "jmp __handle_exception \n\t" \ 156 | ".popsection") 157 | 158 | EX(de, 0); 159 | EX(db, 1); 160 | EX(nmi, 2); 161 | EX(bp, 3); 162 | EX(of, 4); 163 | EX(br, 5); 164 | EX(ud, 6); 165 | EX(nm, 7); 166 | EX_E(df, 8); 167 | EX_E(ts, 10); 168 | EX_E(np, 11); 169 | EX_E(ss, 12); 170 | EX_E(gp, 13); 171 | EX_E(pf, 14); 172 | EX(mf, 16); 173 | EX_E(ac, 17); 174 | EX(mc, 18); 175 | EX(xm, 19); 176 | 177 | //EX(syscall, 128); 178 | 179 | asm (".pushsection .text \n\t" 180 | "__handle_exception: \n\t" 181 | #ifdef __x86_64__ 182 | "push %r15; push %r14; push %r13; push %r12 \n\t" 183 | "push %r11; push %r10; push %r9; push %r8 \n\t" 184 | #endif 185 | "push %"R "di; push %"R "si; push %"R "bp; sub $"S", %"R "sp \n\t" 186 | "push %"R "bx; push %"R "dx; push %"R "cx; push %"R "ax \n\t" 187 | #ifdef __x86_64__ 188 | "mov %"R "sp, %"R "di \n\t" 189 | #else 190 | "mov %"R "sp, %"R "ax \n\t" 191 | #endif 192 | // "call do_test \n\t" 193 | "call do_handle_exception \n\t" 194 | // "call do_test \n\t" 195 | "pop %"R "ax; pop %"R "cx; pop %"R "dx; pop %"R "bx \n\t" 196 | "add $"S", %"R "sp; pop %"R "bp; pop %"R "si; pop %"R "di \n\t" 197 | #ifdef __x86_64__ 198 | "pop %r8; pop %r9; pop %r10; pop %r11 \n\t" 199 | "pop %r12; pop %r13; pop %r14; pop %r15 \n\t" 200 | #endif 201 | "add $"S", %"R "sp \n\t" 202 | "add $"S", %"R "sp \n\t" 203 | "iret"W" \n\t" 204 | ".popsection"); 205 | 206 | static void *idt_handlers[256] = { 207 | [0] = &de_fault, 208 | [1] = &db_fault, 209 | [2] = &nmi_fault, 210 | [3] = &bp_fault, 211 | [4] = &of_fault, 212 | [5] = &br_fault, 213 | [6] = &ud_fault, 214 | [7] = &nm_fault, 215 | [8] = &df_fault, 216 | [10] = &ts_fault, 217 | [11] = &np_fault, 218 | [12] = &ss_fault, 219 | [13] = &gp_fault, 220 | [14] = &pf_fault, 221 | [16] = &mf_fault, 222 | [17] = &ac_fault, 223 | [18] = &mc_fault, 224 | [19] = &xm_fault, 225 | // [128] = &syscall_fault, 226 | }; 227 | 228 | void setup_idt() 229 | { 230 | int i; 231 | static bool idt_initialized = false; 232 | 233 | if (idt_initialized) { 234 | return; 235 | } 236 | idt_initialized = true; 237 | for (i = 0; i < 32; i++){ 238 | if (idt_handlers[i]) 239 | set_idt_entry(i, idt_handlers[i], 0); 240 | } 241 | // set_idt_entry(IPI_VECTOR, ipi_entry, 0); 242 | // set_idt_entry(128, idt_handlers[128], 3); 243 | handle_exception(0, check_exception_table); 244 | handle_exception(6, check_exception_table); 245 | handle_exception(13, check_exception_table); 246 | // handle_exception(128, do_syscall); 247 | // printf("sizeof(boot_idt) = %d\n", sizeof(boot_idt)); 248 | lidt(boot_idt, sizeof(boot_idt)); 249 | } 250 | 251 | unsigned exception_vector(void) 252 | { 253 | unsigned char vector; 254 | 255 | asm("movb %%gs:4, %0" : "=q"(vector)); 256 | return vector; 257 | } 258 | 259 | 260 | bool exception_rflags_rf(void) 261 | { 262 | unsigned char rf_flag; 263 | 264 | asm("movb %%gs:5, %b0" : "=q"(rf_flag)); 265 | return rf_flag & 1; 266 | } 267 | 268 | 269 | 270 | -------------------------------------------------------------------------------- /x86_64/entryother.S: -------------------------------------------------------------------------------- 1 | #include "asm.h" 2 | #include "memlayout.h" 3 | #include "mmu.h" 4 | 5 | # Each non-boot CPU ("AP") is started up in response to a STARTUP 6 | # IPI from the boot CPU. Section B.4.2 of the Multi-Processor 7 | # Specification says that the AP will start in real mode with CS:IP 8 | # set to XY00:0000, where XY is an 8-bit value sent with the 9 | # STARTUP. Thus this code must start at a 4096-byte boundary. 10 | # 11 | # Because this code sets DS to zero, it must sit 12 | # at an address in the low 2^16 bytes. 13 | # 14 | # Startothers (in main.c) sends the STARTUPs one at a time. 15 | # It copies this code (start) at 0x7000. It puts the address of 16 | # a newly allocated per-core stack in start-4,the address of the 17 | # place to jump to (mpenter) in start-8, and the physical address 18 | # of entrypgdir in start-12. 19 | # 20 | # This code combines elements of bootasm.S and entry.S. 21 | 22 | .code16 23 | .globl start 24 | start: 25 | cli 26 | 27 | # Zero data segment registers DS, ES, and SS. 28 | xorw %ax,%ax 29 | movw %ax,%ds 30 | movw %ax,%es 31 | movw %ax,%ss 32 | 33 | # Switch from real to protected mode. Use a bootstrap GDT that makes 34 | # virtual addresses map directly to physical addresses so that the 35 | # effective memory map doesn't change during the transition. 36 | lgdt gdtdesc 37 | movl %cr0, %eax 38 | orl $CR0_PE, %eax 39 | movl %eax, %cr0 40 | 41 | # Complete the transition to 32-bit protected mode by using a long jmp 42 | # to reload %cs and %eip. The segment descriptors are set up with no 43 | # translation, so that the mapping is still the identity mapping. 44 | ljmpl $(SEG_KCODE<<3), $(start32) 45 | 46 | //PAGEBREAK! 47 | .code32 # Tell assembler to generate 32-bit code now. 48 | start32: 49 | # Set up the protected-mode data segment registers 50 | movw $(SEG_KDATA<<3), %ax # Our data segment selector 51 | movw %ax, %ds # -> DS: Data Segment 52 | movw %ax, %es # -> ES: Extra Segment 53 | movw %ax, %ss # -> SS: Stack Segment 54 | movw $0, %ax # Zero segments not ready for use 55 | movw %ax, %fs # -> FS 56 | movw %ax, %gs # -> GS 57 | 58 | prepare_64: 59 | lgdt gdt64_desc 60 | # Turn on page size extension for 2Mbyte pages 61 | mov %cr4, %eax 62 | orl $(CR4_PSE), %eax 63 | mov %eax, %cr4 64 | 65 | efer = 0xC0000080 66 | mov $efer, %ecx 67 | rdmsr 68 | bts $8, %eax 69 | wrmsr 70 | 71 | # Use entrypgdir as our initial page table 72 | movl (start-24), %eax 73 | movl %eax, %cr3 74 | 75 | # Turn on paging. 76 | movl %cr0, %eax 77 | orl $(CR0_PE|CR0_PG), %eax 78 | movl %eax, %cr0 79 | 80 | ljmpl $8, $ap_start64 81 | 82 | 83 | .code64 84 | ap_start64: 85 | 86 | # Switch to the stack allocated by startothers() 87 | movl (start-8), %esp 88 | # Call mpenter() 89 | call *(start-16) 90 | 91 | movw $0x8a00, %ax 92 | movw %ax, %dx 93 | outw %ax, %dx 94 | movw $0x8ae0, %ax 95 | outw %ax, %dx 96 | spin: 97 | hlt 98 | jmp spin 99 | 100 | .p2align 2 101 | gdt: 102 | .quad 0 103 | SEG_ASM(STA_X|STA_R, 0, 0xffffffff) 104 | SEG_ASM(STA_W, 0, 0xffffffff) 105 | 106 | 107 | gdtdesc: 108 | .word (gdtdesc - gdt - 1) 109 | .long gdt 110 | 111 | gdt64: 112 | .quad 0 113 | .quad 0x00af9b000000ffff // 64-bit code segment 114 | .quad 0x00cf93000000ffff // 32/64-bit data segment 115 | .quad 0x00af1b000000ffff // 64-bit code segment, not present 116 | .quad 0x00cf9b000000ffff // 32-bit code segment 117 | .quad 0x008f9b000000FFFF // 16-bit code segment 118 | .quad 0x008f93000000FFFF // 16-bit data segment 119 | .quad 0x00cffb000000ffff // 32-bit code segment (user) 120 | .quad 0x00cff3000000ffff // 32/64-bit data segment (user) 121 | .quad 0x00affb000000ffff // 64-bit code segment (user) 122 | 123 | .quad 0 // 6 spare selectors 124 | .quad 0 125 | .quad 0 126 | .quad 0 127 | .quad 0 128 | .quad 0 129 | 130 | gdt64_end: 131 | 132 | gdt64_desc: 133 | .word gdt64_end - gdt64 - 1 134 | .quad gdt64 135 | 136 | 137 | -------------------------------------------------------------------------------- /x86_64/heap.c: -------------------------------------------------------------------------------- 1 | #include "types.h" 2 | #include "defs.h" 3 | //#include "multiboot.h" 4 | #include "mmu.h" 5 | #include "page.h" 6 | #include "processor.h" 7 | #include "spinlock.h" 8 | 9 | static void *vfree_top = 0; 10 | static struct spinlock lock; 11 | 12 | 13 | uintptr_t heap_base, heap_end; 14 | static void *freelist = 0; 15 | 16 | static bool first_mem_init = false; 17 | 18 | uintptr_t start_cr3; 19 | 20 | 21 | /* 22 | Get the memory map of the machine provided by the BIOS. 23 | */ 24 | void get_memory_map(struct mbi_bootinfo *glb_mboot_ptr) 25 | { 26 | uint32_t mmap_addr = glb_mboot_ptr->mmap_addr; 27 | uint32_t mmap_length = glb_mboot_ptr->mmap_length; 28 | 29 | mmap_entry_t *mmap = (mmap_entry_t *)(uint64_t) mmap_addr; 30 | 31 | heap_end = 0; 32 | 33 | for ( ; (uint64_t)mmap < mmap_addr + mmap_length; mmap++) 34 | { 35 | heap_end = heap_end + mmap->length; 36 | // printf("%x\n",(uint64_t) mmap->length); 37 | } 38 | } 39 | 40 | /* 41 | * Place the pages after _HEAP_START on free list. 42 | */ 43 | void *get_free_pages(void *mem, unsigned long size) 44 | { 45 | 46 | void *old_freelist; 47 | void *end; 48 | 49 | if(size == 0) { 50 | 51 | return 0; 52 | } 53 | 54 | old_freelist = freelist; 55 | freelist = mem; 56 | end = mem + size; 57 | 58 | while (mem + PAGE_SIZE != end) { 59 | *(void **)mem = (mem + PAGE_SIZE); 60 | mem += PAGE_SIZE; 61 | } 62 | 63 | *(void **)mem = old_freelist; 64 | 65 | return freelist; 66 | } 67 | 68 | /* 69 | 70 | */ 71 | void early_mem_init(uintptr_t base_addr, struct mbi_bootinfo *bootinfo) 72 | { 73 | u64 end_of_memory = bootinfo->mem_upper * 1024ull; 74 | printf("mbi->mem_upper = %lx\n", end_of_memory); 75 | // printf("mbi->mmap_length = %x\n", bootinfo->mmap_length); 76 | if(!first_mem_init){ 77 | first_mem_init = true; 78 | 79 | get_memory_map(bootinfo); 80 | 81 | heap_base = (base_addr + PAGE_SIZE - 1) & (-PAGE_SIZE); 82 | heap_end = heap_end & (-PAGE_SIZE); 83 | #ifdef __BARE_METAL 84 | printf("Memory Start: %lx B\n", heap_base); 85 | printf("Memory End: %lx B\n", heap_end); 86 | printf("Total Memory: %ld MB\n", heap_end >> 20); 87 | #endif 88 | } 89 | 90 | freelist = 0; 91 | if(freelist == 0){ 92 | get_free_pages((void *)heap_base, end_of_memory - heap_base); 93 | // get_free_pages((void *)heap_base, 1ul << 31); 94 | } 95 | 96 | } 97 | 98 | /* 99 | Allocate one 4096-byte page of physical memory. 100 | Returns a pointer that the kernel can use. 101 | Returns 0 if the memory cannot be allocated. 102 | */ 103 | void *heap_alloc_page(void) 104 | { 105 | void *page; 106 | //fprintf(OUTPUT, "%p ", freelist); 107 | if (!freelist) { 108 | printf("freelist uninitialized!\n"); 109 | return 0; 110 | } 111 | 112 | page = freelist; 113 | freelist = *(void **)freelist; 114 | 115 | __fast_zero_page(page); 116 | return page; 117 | } 118 | 119 | /**********************************************************************/ 120 | /* 121 | * pte: the physical address of a page frame 122 | * 123 | */ 124 | pteval_t *install_pte(pgd_t *cr3, 125 | int pte_level, 126 | void *virt, 127 | pteval_t pte, 128 | pteval_t *pt_page) 129 | { 130 | int level; 131 | pteval_t *pt = cr3; 132 | unsigned offset; 133 | 134 | for(level = PAGE_LEVEL; level > pte_level; --level) { 135 | offset = PGDIR_OFFSET((uintptr_t)virt, level); 136 | if(!(pt[offset] & PT_PRESENT_MASK)) { 137 | pteval_t *new_pt = pt_page; 138 | if(!new_pt) 139 | new_pt = heap_alloc_page(); 140 | else 141 | pt_page = 0; 142 | memset(new_pt, 0, PAGE_SIZE); 143 | pt[offset] = (unsigned long)new_pt | PT_PRESENT_MASK | PT_WRITABLE_MASK | PT_USER_MASK; 144 | } 145 | pt = (void *)((unsigned long)(pt[offset] & PT_ADDR_MASK)); 146 | } 147 | offset = PGDIR_OFFSET((uintptr_t)virt, level); 148 | pt[offset] = pte; 149 | return &pt[offset]; 150 | } 151 | 152 | pteval_t *install_large_page(pgd_t *cr3, phys_addr_t phys, void *virt) 153 | { 154 | return install_pte(cr3, 2, virt, 155 | phys | PT_PRESENT_MASK | PT_WRITABLE_MASK | PT_USER_MASK | PT_PAGE_SIZE_MASK, 0); 156 | } 157 | 158 | pteval_t *install_page(pgd_t *cr3, phys_addr_t phys, void *virt) 159 | { 160 | return install_pte(cr3, 1, virt, phys | PT_PRESENT_MASK | PT_WRITABLE_MASK | PT_USER_MASK, 0); 161 | } 162 | 163 | void install_pages(pgd_t *cr3, phys_addr_t phys, size_t len, void *virt) 164 | { 165 | phys_addr_t max = (u64)len + (u64)phys; 166 | // assert(phys % PAGE_SIZE == 0); 167 | // assert((uintptr_t) virt % PAGE_SIZE == 0); 168 | // assert(len % PAGE_SIZE == 0); 169 | 170 | while (phys + PAGE_SIZE <= max) { 171 | install_page(cr3, phys, virt); 172 | phys += PAGE_SIZE; 173 | virt = (char *) virt + PAGE_SIZE; 174 | } 175 | } 176 | 177 | void *setup_mmu(phys_addr_t end_of_memory) 178 | { 179 | uintptr_t *cr3 = heap_alloc_page(); 180 | 181 | if(end_of_memory == 0) 182 | end_of_memory = (1ul << 32); /* map 1:1 */ 183 | 184 | install_pages(cr3, 0, end_of_memory, (void *)0); 185 | // save the original @cr3 and set the new page table root 186 | start_cr3 = read_cr3(); 187 | write_cr3((uintptr_t)cr3); 188 | 189 | return cr3; 190 | } 191 | 192 | 193 | void switch_to_start_cr3() 194 | { 195 | write_cr3(start_cr3); 196 | } 197 | /* 198 | void reset_freelist() 199 | { 200 | get_free_pages((void *)heap_base, 1ul << 31); 201 | } 202 | */ 203 | 204 | /******************************************************************************************************/ 205 | 206 | void *alloc_vpages(ulong nr) 207 | { 208 | spin_lock(&lock); 209 | vfree_top -= PAGE_SIZE * nr; 210 | spin_unlock(&lock); 211 | return vfree_top; 212 | } 213 | 214 | 215 | 216 | -------------------------------------------------------------------------------- /x86_64/kernel.ld: -------------------------------------------------------------------------------- 1 | 2 | OUTPUT_FORMAT("elf64-x86-64") 3 | OUTPUT_ARCH(i386:x86-64) 4 | 5 | SECTIONS 6 | { 7 | . = 4M + SIZEOF_HEADERS; 8 | 9 | _TEXT_START = .; 10 | .text : { *(.init) *(.text) *(.text.*) } 11 | _TEXT_END = .; 12 | 13 | _DATA_START = .; 14 | . = ALIGN(4K); 15 | .data : { 16 | *(.data) 17 | exception_table_start = .; 18 | *(.data.ex) 19 | exception_table_end = .; 20 | } 21 | 22 | . = ALIGN(4K); 23 | .rodata : { *(.rodata) } 24 | 25 | . = ALIGN(4K); 26 | .bss : { *(.bss) } 27 | 28 | . = ALIGN(4K); 29 | .benchmarks : 30 | { 31 | . = ALIGN(8); 32 | _BENCHMARKS_START = .; 33 | KEEP(*(.benchmarks)); 34 | _BENCHMARKS_END = .; 35 | } 36 | _DATA_END = .; 37 | 38 | . = ALIGN(4k); 39 | _HEAP_START = .; 40 | 41 | } 42 | 43 | ENTRY(entry) 44 | 45 | -------------------------------------------------------------------------------- /x86_64/main.c: -------------------------------------------------------------------------------- 1 | 2 | #include "types.h" 3 | #include "defs.h" 4 | #include "param.h" 5 | #include "mmu.h" 6 | #include "proc.h" 7 | #include "processor.h" 8 | 9 | // An address symbol in kernel.ld 10 | extern char _HEAP_START; 11 | 12 | static void startothers(void); 13 | //static void mpmain(void) __attribute__((noreturn)); 14 | static void list_apicid(void); 15 | 16 | // 17 | void platform_shutdown(); 18 | 19 | // Bootstrap processor starts running C code here. 20 | int main(void *mb_info, int magic) 21 | { 22 | #ifdef __BARE_METAL 23 | printf("magic = %x, mb_info = %p\n", magic, mb_info); 24 | #endif 25 | early_mem_init((uintptr_t)&_HEAP_START, mb_info); 26 | mask_pic_interrupts(); 27 | enable_apic(); 28 | mpinit(); // detect other processors 29 | startothers(); // start Application Processors 30 | enable_x2apic(); 31 | harness_main(); // run benchmarks 32 | // printf("sizeof(void *) = %d\r\n", (int)sizeof(void *)); 33 | #ifdef __BARE_METAL 34 | while(1); //hold the physical machine, or it will restart infinitely 35 | #else 36 | platform_shutdown(); 37 | #endif 38 | } 39 | 40 | 41 | // Other CPUs jump here from cstart.S. 42 | //static void mpenter(void) 43 | void mpenter(void) 44 | { 45 | printf("cpu%d: starting %d\r\n", cpuid(), cpuid()); 46 | lidt(boot_idt, sizeof(boot_idt)-1); 47 | enable_apic(); 48 | xchg(&(mycpu()->started), 1); // tell startothers() we're up 49 | enable_x2apic(); // This funciton must behind xchg(&(mycpu()->started), 1), why? 50 | // asm volatile("sti"); 51 | // asm volatile("nop"); 52 | } 53 | 54 | /* 55 | Start the non-boot (AP) processors. 56 | */ 57 | static void startothers(void) 58 | { 59 | struct cpu *c; 60 | char *stack; 61 | /* 62 | The BSP should place the BIOS AP initialization code at 000VV000H, 63 | where VV is the vector contained in the SIPI message. 64 | Write entry code to unused memory at 0x0000. 65 | */ 66 | sipi_entry_mov(); 67 | 68 | for(c = cpus; c < cpus+ncpu; c++){ 69 | if(c == mycpu()) // We've started already. 70 | continue; 71 | 72 | lapicstartap(c->apicid, 0x00); 73 | // wait for cpu to finish mpenter() 74 | while(c->started == 0); 75 | } 76 | 77 | } 78 | 79 | /* 80 | List the apic id of each processors. 81 | */ 82 | static void list_apicid(void) 83 | { 84 | int i; 85 | printf("The number of processors : %d\n", ncpu); 86 | for(i = 0; i < ncpu; i++){ 87 | printf("%5d ",cpus[i].apicid); 88 | } 89 | printf("\n"); 90 | } 91 | 92 | void DEBUG() 93 | { 94 | printf("move done!\n"); 95 | } 96 | 97 | void platform_shutdown() 98 | { 99 | asm volatile ("mov $0x80000b80, %eax"); 100 | asm volatile ("movw $0xcf8, %dx"); 101 | asm volatile ("outl %eax, %dx"); 102 | asm volatile ("movw $0xcfc, %dx"); 103 | asm volatile ("inb %dx, %al"); 104 | asm volatile ("orb $1, %al"); 105 | asm volatile ("outb %al, %dx"); 106 | 107 | asm volatile ("movl $0x80000b40, %eax"); 108 | asm volatile ("movw $0xcf8, %dx"); 109 | asm volatile ("outl %eax, %dx"); 110 | asm volatile ("movl $0x7001, %eax"); 111 | asm volatile ("movw $0xcfc, %dx"); 112 | asm volatile ("outl %eax, %dx"); 113 | asm volatile ("movw $0x2000, %ax"); 114 | asm volatile ("movw $0x7004, %dx"); 115 | asm volatile ("outw %ax, %dx"); 116 | } 117 | 118 | -------------------------------------------------------------------------------- /x86_64/mp.c: -------------------------------------------------------------------------------- 1 | // Multiprocessor support 2 | // Search memory for MP description structures. 3 | // http://developer.intel.com/design/pentium/datashts/24201606.pdf 4 | 5 | #include "types.h" 6 | #include "defs.h" 7 | #include "param.h" 8 | #include "memlayout.h" 9 | #include "mp.h" 10 | //#include "x86.h" 11 | #include "processor.h" 12 | #include "mmu.h" 13 | #include "proc.h" 14 | #include "io.h" 15 | #include "apic.h" 16 | #include "atomic.h" 17 | #include "spinlock.h" 18 | 19 | #define IPI_VECTOR 0x20 20 | 21 | struct cpu cpus[NCPU]; 22 | int ncpu; 23 | uchar ioapicid; 24 | 25 | /************************************************************************/ 26 | typedef void (*ipi_function_type)(void *data); 27 | 28 | static struct spinlock ipi_lock; 29 | static volatile ipi_function_type ipi_function; 30 | static void *volatile ipi_data; 31 | static volatile int ipi_done; 32 | static volatile bool ipi_wait; 33 | static int _cpu_count; 34 | static atomic_t active_cpus; 35 | 36 | static __attribute__((used)) void ipi() 37 | { 38 | /* 39 | void (*function)(void *data) = ipi_function; 40 | void *data = ipi_data; 41 | bool wait = ipi_wait; 42 | if (!wait) { 43 | ipi_done = 1; 44 | apic_write(APIC_EOI, 0); 45 | } 46 | function(data); 47 | atomic_dec(&active_cpus); 48 | if (wait) { 49 | ipi_done = 1; 50 | apic_write(APIC_EOI, 0); 51 | } 52 | */ 53 | ipi_done = 1; 54 | apic_write(APIC_EOI, 0); 55 | } 56 | 57 | asm ( 58 | "ipi_entry: \n" 59 | " call ipi \n" 60 | #ifndef __x86_64__ 61 | " iret" 62 | #else 63 | " iretq" 64 | #endif 65 | ); 66 | 67 | 68 | static void setup_smp_id(void *data) 69 | { 70 | asm ("mov %0, %%gs:0" : : "r"(apic_id()) : "memory"); 71 | } 72 | 73 | int smp_id(void) 74 | { 75 | unsigned id; 76 | 77 | asm ("mov %%gs:0, %0" : "=r"(id)); 78 | return id; 79 | } 80 | 81 | 82 | //static void do_test(struct ex_regs *regs) 83 | static void do_test() 84 | { 85 | printf("STOP"); 86 | while(1); 87 | } 88 | 89 | 90 | static void __on_cpu(int cpu, void (*function)(void *data), void *data, 91 | int wait) 92 | { 93 | /* 94 | spin_lock(&ipi_lock); 95 | if (cpu == smp_id()) 96 | function(data); 97 | else { 98 | atomic_inc(&active_cpus); 99 | ipi_done = 0; 100 | ipi_function = function; 101 | ipi_data = data; 102 | ipi_wait = wait; 103 | apic_icr_write(APIC_INT_ASSERT | APIC_DEST_PHYSICAL | APIC_DM_FIXED 104 | | IPI_VECTOR, 105 | cpu); 106 | while (!ipi_done); 107 | } 108 | spin_unlock(&ipi_lock); 109 | */ 110 | spin_lock(&ipi_lock); 111 | ipi_done = 0; 112 | apic_icr_write(APIC_INT_ASSERT | APIC_DEST_PHYSICAL | APIC_DM_FIXED 113 | | IPI_VECTOR, 114 | cpu); 115 | while(!ipi_done); 116 | spin_unlock(&ipi_lock); 117 | } 118 | 119 | void on_cpu(int cpu, void (*function)(void *data), void *data) 120 | { 121 | // __on_cpu(cpu, function, data, 1); 122 | __on_cpu(cpus[cpu].apicid, function, data, 1); 123 | } 124 | 125 | /* 126 | Prepare idt needed for the ipi. 127 | */ 128 | void smp_init(void) 129 | { 130 | int i; 131 | void ipi_entry(void); 132 | 133 | setup_idt(); 134 | set_idt_entry(IPI_VECTOR, ipi_entry, 0); 135 | /* 136 | setup_smp_id(0); 137 | 138 | for (i = 1; i < ncpu; ++i){ 139 | on_cpu(i, setup_smp_id, 0); 140 | } 141 | 142 | atomic_inc(&active_cpus); 143 | */ 144 | } 145 | 146 | 147 | 148 | /**********************************************************************/ 149 | 150 | static uchar sum(uchar *addr, int len) 151 | { 152 | int i, sum; 153 | 154 | sum = 0; 155 | for(i=0; iphysaddr == 0) 240 | return 0; 241 | // conf = (struct mpconf*) P2V((uint) mp->physaddr); 242 | conf = (struct mpconf*) ((uint64_t) mp->physaddr); 243 | if(memcmp(conf, "PCMP", 4) != 0) 244 | return 0; 245 | if(conf->version != 1 && conf->version != 4) 246 | return 0; 247 | if(sum((uchar*)conf, conf->length) != 0) 248 | return 0; 249 | *pmp = mp; 250 | return conf; 251 | } 252 | 253 | /* 254 | apicid may differ from different chips 255 | */ 256 | void mpinit(void) 257 | { 258 | uchar *p, *e; 259 | int ismp; 260 | struct mp *mp; 261 | struct mpconf *conf; 262 | struct mpproc *proc; 263 | struct mpioapic *ioapic; 264 | 265 | if((conf = mpconfig(&mp)) == 0) 266 | //panic("Expect to run on an SMP"); 267 | printf("Expect to run on an SMP"); 268 | ismp = 1; 269 | lapic = (uint*)((uint64_t)(conf->lapicaddr)); 270 | //printf("lapic = %p\n", lapic); 271 | for(p=(uchar*)(conf+1), e=(uchar*)conf+conf->length; papicid; // apicid may differ from ncpu 277 | ncpu++; 278 | } 279 | p += sizeof(struct mpproc); 280 | continue; 281 | case MPIOAPIC: 282 | ioapic = (struct mpioapic*)p; 283 | ioapicid = ioapic->apicno; 284 | p += sizeof(struct mpioapic); 285 | continue; 286 | case MPBUS: 287 | case MPIOINTR: 288 | case MPLINTR: 289 | p += 8; 290 | continue; 291 | default: 292 | ismp = 0; 293 | break; 294 | } 295 | } 296 | if(!ismp) 297 | //panic("Didn't find a suitable machine"); 298 | printf("Didn't find a suitable machine"); 299 | /* 300 | if(mp->imcrp){ 301 | // Bochs doesn't support IMCR, so this doesn't run on Bochs. 302 | // But it would on real hardware. 303 | //outb(0x22, 0x70); // Select IMCR 304 | outb(0x70, 0x22); // Select IMCR 305 | //outb(0x23, inb(0x23) | 1); // Mask external interrupts. 306 | outb(inb(0x23) | 1, 0x23); // Mask external interrupts. 307 | } 308 | */ 309 | } 310 | 311 | 312 | -------------------------------------------------------------------------------- /x86_64/proc.c: -------------------------------------------------------------------------------- 1 | #include "types.h" 2 | #include "defs.h" 3 | #include "param.h" 4 | #include "memlayout.h" 5 | #include "mmu.h" 6 | #include "processor.h" 7 | #include "proc.h" 8 | 9 | 10 | // Must be called with interrupts disabled 11 | int 12 | cpuid() { 13 | return mycpu()-cpus; 14 | } 15 | 16 | // Must be called with interrupts disabled to avoid the caller being 17 | // rescheduled between reading lapicid and running through the loop. 18 | struct cpu* mycpu(void) 19 | { 20 | int apicid, i; 21 | 22 | if(readeflags()&FL_IF) 23 | printf("mycpu called with interrupts enabled\n"); 24 | 25 | apicid = lapicid(); 26 | //apicid = apic_id(); 27 | // APIC IDs are not guaranteed to be contiguous. Maybe we should have 28 | // a reverse map, or reserve a register to store &cpus[i]. 29 | for (i = 0; i < ncpu; ++i) { 30 | if (cpus[i].apicid == apicid) 31 | return &cpus[i]; 32 | } 33 | printf("unknown apicid\n"); 34 | } 35 | 36 | 37 | 38 | -------------------------------------------------------------------------------- /x86_64/serial.c: -------------------------------------------------------------------------------- 1 | 2 | #include "types.h" 3 | #include "defs.h" 4 | #include "io.h" 5 | #include "spinlock.h" 6 | 7 | static struct spinlock lock; 8 | static int serial_iobase = 0x3f8; 9 | static int serial_inited = 0; 10 | 11 | static void serial_outb(char ch) 12 | { 13 | u8 lsr; 14 | 15 | do { 16 | lsr = inb(serial_iobase + 0x05); 17 | } while (!(lsr & 0x20)); 18 | 19 | outb(ch, serial_iobase + 0x00); 20 | } 21 | 22 | //static void serial_init(void) 23 | void serial_init(void) 24 | { 25 | u8 lcr; 26 | 27 | /* set DLAB */ 28 | lcr = inb(serial_iobase + 0x03); 29 | lcr |= 0x80; 30 | outb(lcr, serial_iobase + 0x03); 31 | 32 | /* set baud rate to 115200 */ 33 | outb(0x01, serial_iobase + 0x00); 34 | outb(0x00, serial_iobase + 0x01); 35 | 36 | /* clear DLAB */ 37 | lcr = inb(serial_iobase + 0x03); 38 | lcr &= ~0x80; 39 | outb(lcr, serial_iobase + 0x03); 40 | } 41 | 42 | static void print_serial(const char *buf) 43 | { 44 | unsigned long len = strlen(buf); 45 | #ifdef USE_SERIAL 46 | 47 | unsigned long i; 48 | if (!serial_inited) { 49 | serial_init(); 50 | serial_inited = 1; 51 | } 52 | 53 | for (i = 0; i < len; i++) { 54 | serial_outb(buf[i]); 55 | } 56 | 57 | 58 | //asm volatile ("rep/outsb" : "+S"(buf), "+c"(len) : "d"(0x3f8)); 59 | #else 60 | asm volatile ("rep/outsb" : "+S"(buf), "+c"(len) : "d"(0x3f8)); 61 | #endif 62 | } 63 | 64 | void puts(const char *s) 65 | { 66 | spin_lock(&lock); 67 | print_serial(s); 68 | spin_unlock(&lock); 69 | } 70 | 71 | void exit(int code) 72 | { 73 | #ifdef USE_SERIAL 74 | static const char shutdown_str[8] = "Shutdown"; 75 | int i; 76 | 77 | /* test device exit (with status) */ 78 | outl(code, 0xf4); 79 | 80 | /* if that failed, try the Bochs poweroff port */ 81 | for (i = 0; i < 8; i++) { 82 | outb(shutdown_str[i], 0x8900); 83 | } 84 | #else 85 | asm volatile("out %0, %1" : : "a"(code), "d"((short)0xf4)); 86 | #endif 87 | } 88 | 89 | void wait() 90 | { 91 | #ifdef __BARE_METAL 92 | while(1); 93 | #endif 94 | } 95 | 96 | //void __iomem *ioremap(phys_addr_t phys_addr, size_t size) 97 | //{ 98 | // phys_addr_t base = phys_addr & PAGE_MASK; 99 | // phys_addr_t offset = phys_addr - base; 100 | 101 | /* 102 | * The kernel sets PTEs for an ioremap() with page cache disabled, 103 | * but we do not do that right now. It would make sense that I/O 104 | * mappings would be uncached - and may help us find bugs when we 105 | * properly map that way. 106 | */ 107 | // return vmap(phys_addr, size) + offset; 108 | //} 109 | 110 | /**************************************************************************/ 111 | 112 | static inline int is_transmit_empty() 113 | { 114 | return !!(inb(serial_iobase + 5) & 0x20); 115 | } 116 | 117 | void serial_putc(char ch) 118 | { 119 | while (!is_transmit_empty()) asm volatile("pause\n"); 120 | 121 | outb(ch, serial_iobase); 122 | } 123 | 124 | -------------------------------------------------------------------------------- /x86_64/util.S: -------------------------------------------------------------------------------- 1 | .globl __fast_zero_page 2 | __fast_zero_page: 3 | xor %eax, %eax 4 | mov $0x200, %ecx 5 | cld 6 | rep stosq %rax, %es:(%rdi) 7 | ret 8 | 9 | --------------------------------------------------------------------------------