From a6736c86444b240859e959e1edaa1a5e1bd80472 Mon Sep 17 00:00:00 2001 From: Michael Clark Date: Sat, 5 Mar 2022 15:56:38 +1300 Subject: [PATCH 1/7] compile with -ffunction-sections and link with --gc-sections --- Makefile | 8 ++++---- user/kexts/Makefile | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Makefile b/Makefile index 872cc99..d86363c 100644 --- a/Makefile +++ b/Makefile @@ -69,7 +69,7 @@ AS = $(TOOLPREFIX)gas LD = $(TOOLPREFIX)ld OBJCOPY = $(TOOLPREFIX)objcopy OBJDUMP = $(TOOLPREFIX)objdump -CFLAGS = -fno-pic -static -fno-builtin -fno-strict-aliasing -Wall -MD -g -ggdb -fno-omit-frame-pointer +CFLAGS = -fno-pic -static -fno-builtin -fno-strict-aliasing -Wall -MD -g -ggdb -fno-omit-frame-pointer -ffunction-sections CFLAGS += -ffreestanding -fno-common -nostdlib -Iinclude -gdwarf-2 $(XFLAGS) $(OPT) CFLAGS += $(shell $(CC) -fno-stack-protector -E -x c /dev/null >/dev/null 2>&1 && echo -fno-stack-protector) ASFLAGS = -fno-pic -gdwarf-2 -Wa,-divide -Iinclude $(XFLAGS) @@ -167,13 +167,13 @@ ULIB = uobj/ulib.o uobj/usys.o uobj/printf.o uobj/umalloc.o uobj/string.o fs/bin/%: uobj/%.o $(ULIB) @mkdir -p fs out fs/bin - $(LD) $(LDFLAGS) -N -e main -Ttext 0 -o $@ $^ + $(LD) $(LDFLAGS) --gc-sections -N -e main -Ttext 0 -o $@ $^ $(OBJDUMP) -S $@ > out/$*.asm $(OBJDUMP) -t $@ | sed '1,/SYMBOL TABLE/d; s/ .* / /; /^$$/d' > bin/$*.sym fs/%: uobj/%.o $(ULIB) @mkdir -p fs out fs/bin - $(LD) $(LDFLAGS) -N -e main -Ttext 0 -o $@ $^ + $(LD) $(LDFLAGS) --gc-sections -N -e main -Ttext 0 -o $@ $^ $(OBJDUMP) -S $@ > out/$*.asm $(OBJDUMP) -t $@ | sed '1,/SYMBOL TABLE/d; s/ .* / /; /^$$/d' > bin/$*.sym @@ -181,7 +181,7 @@ fs/forktest: uobj/forktest.o $(ULIB) @mkdir -p fs # forktest has less library code linked in - needs to be small # in order to be able to max out the proc table. - $(LD) $(LDFLAGS) -N -e main -Ttext 0 -o fs/forktest uobj/forktest.o uobj/ulib.o uobj/usys.o + $(LD) $(LDFLAGS) --gc-sections -N -e main -Ttext 0 -o fs/forktest uobj/forktest.o uobj/ulib.o uobj/usys.o $(OBJDUMP) -S fs/forktest > out/forktest.asm out/mkfs: tools/mkfs.c include/vfs.h diff --git a/user/kexts/Makefile b/user/kexts/Makefile index 400231c..e8e3031 100644 --- a/user/kexts/Makefile +++ b/user/kexts/Makefile @@ -23,4 +23,4 @@ all: $(PROGS) %: %.c $(CC) $(CFLAGS) -c -o $@.o $@.c - $(LD) $(LDFLAGS) -N -e main -Ttext 0 -o $(FSPATH)/kexts/$@ $@.o $(ULIB) + $(LD) $(LDFLAGS) --gc-sections -N -e main -Ttext 0 -o $(FSPATH)/kexts/$@ $@.o $(ULIB) From 3834609f772205b2b4b7424bd46fff23a8dea572 Mon Sep 17 00:00:00 2001 From: Michael Clark Date: Sat, 5 Mar 2022 15:57:42 +1300 Subject: [PATCH 2/7] building image with loopback device requires sudo --- Makefile | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/Makefile b/Makefile index d86363c..db8d0fc 100644 --- a/Makefile +++ b/Makefile @@ -236,12 +236,10 @@ fs.img: out/mkfs fs/LICENSE $(UPROGS) $(SUBPROGS) dd if=/dev/zero of=bin/fs-ext2.img bs=1k count=2000 mkfs -t ext2 -i 1024 -b 1024 -F bin/fs-ext2.img - mkdir /tmp/loop - mount -o loop bin/fs-ext2.img /tmp/loop - cp -r ./fs/ /tmp/loop/ - umount /tmp/loop - - + mkdir -p /tmp/loop + sudo mount -o loop bin/fs-ext2.img /tmp/loop + sudo cp -r ./fs/ /tmp/loop/ + sudo umount /tmp/loop -include */*.d clean: @@ -259,7 +257,7 @@ binaries : fs.img boot.img cp -r fs ./bin/ cd ./bin/ && tar -xvzf Xv64.vmwarevm.tar.gz && rm Xv64.vmwarevm.tar.gz && cd .. qemu-img convert boot.img -O vmdk bin/Xv64.vmwarevm/boot.vmdk - mkdir bin/artifacts + mkdir -p bin/artifacts cp -r uobj bin/artifacts/ cp -r kobj bin/artifacts/ cp -r out bin/artifacts/ From 3aade702beeaa64db910843cc49648c2b252580e Mon Sep 17 00:00:00 2001 From: Michael Clark Date: Sat, 5 Mar 2022 15:58:59 +1300 Subject: [PATCH 3/7] compiling 32-bit code requires typedef long long for uint64 --- include/types.h | 2 +- include/unix/stdint.h | 4 ++-- ulib/unix/string.c | 1 + 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/include/types.h b/include/types.h index c7a9ae2..43f3b19 100644 --- a/include/types.h +++ b/include/types.h @@ -6,7 +6,7 @@ typedef unsigned char uchar; typedef unsigned char uint8; typedef unsigned short uint16; typedef unsigned int uint32; -typedef unsigned long uint64; +typedef unsigned long long uint64; //explicit-length signed ints typedef char int8; diff --git a/include/unix/stdint.h b/include/unix/stdint.h index 2fc5d2c..91ad7c5 100644 --- a/include/unix/stdint.h +++ b/include/unix/stdint.h @@ -4,10 +4,10 @@ typedef char int8_t; typedef short int16_t; typedef int int32_t; -typedef long int64_t; +typedef long long int64_t; typedef unsigned char uint8_t; typedef unsigned short uint16_t; typedef unsigned int uint32_t; -typedef unsigned long uint64_t; +typedef unsigned long long uint64_t; diff --git a/ulib/unix/string.c b/ulib/unix/string.c index 79f8f9c..0c66ca2 100644 --- a/ulib/unix/string.c +++ b/ulib/unix/string.c @@ -1,6 +1,7 @@ #include "unix/string.h" #include "unix/stddef.h" #include "syscalls.h" +#include "types.h" #include "x86.h" #include "fcntl.h" From 88ad55163ee689105f135c1d7d11ae27acab84d5 Mon Sep 17 00:00:00 2001 From: Michael Clark Date: Sat, 5 Mar 2022 16:00:12 +1300 Subject: [PATCH 4/7] dynamic irqs require adding T_IRQ0 to irq numbers --- kernel/trap.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/kernel/trap.c b/kernel/trap.c index e86f502..2d37246 100644 --- a/kernel/trap.c +++ b/kernel/trap.c @@ -121,20 +121,20 @@ void trap(struct trapframe* tf){ } uint8 irq_register_handler(uint16 irq, irqhandler handler) { - if(irq >= MAX_IRQS) { + if(irq - T_IRQ0 >= MAX_IRQS) { return 0; //sorry } acquire(&irqHandlersLock); - irqHandlers[irq] = handler; + irqHandlers[irq - T_IRQ0] = handler; release(&irqHandlersLock); return 1; } irqhandler get_registered_handler(uint16 irq) { irqhandler result = 0; - if(irq < MAX_IRQS) { + if(irq - T_IRQ0 < MAX_IRQS) { acquire(&irqHandlersLock); - result = irqHandlers[irq]; + result = irqHandlers[irq - T_IRQ0]; release(&irqHandlersLock); } return result; From 24f03cdc3dc18d3f5a8ee63e46fc24b4a9089a4f Mon Sep 17 00:00:00 2001 From: Michael Clark Date: Sat, 5 Mar 2022 16:01:08 +1300 Subject: [PATCH 5/7] add additional cpuid and msr register definitions --- include/mmu.h | 17 +-- include/x86_defs.h | 251 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 253 insertions(+), 15 deletions(-) create mode 100644 include/x86_defs.h diff --git a/include/mmu.h b/include/mmu.h index f219ae2..67c9019 100644 --- a/include/mmu.h +++ b/include/mmu.h @@ -1,6 +1,8 @@ // This file contains definitions for the // x86 memory management unit (MMU). +#include "x86_defs.h" + // Eflags register #define FL_CF 0x00000001 // Carry Flag #define FL_PF 0x00000004 // Parity Flag @@ -24,21 +26,6 @@ #define FL_VIP 0x00100000 // Virtual Interrupt Pending #define FL_ID 0x00200000 // ID flag -// Control Register flags -#define CR0_PE 0x00000001 // Protection Enable -#define CR0_MP 0x00000002 // Monitor coProcessor -#define CR0_EM 0x00000004 // Emulation -#define CR0_TS 0x00000008 // Task Switched -#define CR0_ET 0x00000010 // Extension Type -#define CR0_NE 0x00000020 // Numeric Errror -#define CR0_WP 0x00010000 // Write Protect -#define CR0_AM 0x00040000 // Alignment Mask -#define CR0_NW 0x20000000 // Not Writethrough -#define CR0_CD 0x40000000 // Cache Disable -#define CR0_PG 0x80000000 // Paging - -#define CR4_PSE 0x00000010 // Page size extension - #define SEG_KCODE 1 // kernel code #define SEG_KDATA 2 // kernel data+stack #define SEG_KCPU 3 // kernel per-cpu data diff --git a/include/x86_defs.h b/include/x86_defs.h new file mode 100644 index 0000000..6ce4a67 --- /dev/null +++ b/include/x86_defs.h @@ -0,0 +1,251 @@ +// See LICENSE for license details. + +#ifndef _CPUDEF_H_ +#define _CPUDEF_H_ + +/* cr0 */ +#define CR0_PG (1 << 31) /* Paging */ +#define CR0_CD (1 << 30) /* Cache Disable */ +#define CR0_NW (1 << 29) /* Not Write-through */ +#define CR0_AM (1 << 18) /* Alignment Mask */ +#define CR0_WP (1 << 16) /* Write Protect */ +#define CR0_NE (1 << 5) /* Numeric Error enable */ +#define CR0_ET (1 << 4) /* Extension Type */ +#define CR0_TS (1 << 3) /* Task Switched */ +#define CR0_EM (1 << 2) /* Emulation */ +#define CR0_MP (1 << 1) /* Monitor Coprocessor */ +#define CR0_PE (1 << 0) /* Protected mode Enable */ + +/* cr2 */ +#define CR2_PFLA -1L /* 63:0 Page Fault Linear Address */ + +/* cr3 */ +#define CR3_PTPA 0xffffffffff000 /* 51:12 Page Table Physical Address */ +#define CR3_PCD (1 << 4) /* Page-level Cache Disable */ +#define CR3_PWT (1 << 3) /* Page-level Write-Through */ + +/* cr4 */ +#define CR4_PKE (1 << 22) /* Protection-Key-Enable */ +#define CR4_SMAP (1 << 21) /* Supervisor Mode Access Protection */ +#define CR4_SMEP (1 << 20) /* Supervisor Mode Execute Protection */ +#define CR4_OSXSAVE (1 << 18) /* XSAVE and Extended States-Enable */ +#define CR4_PCIDE (1 << 17) /* PCID Enable */ +#define CR4_FSGS (1 << 16) /* FSGSBASE Enable */ +#define CR4_SMXE (1 << 14) /* Safer Mode Extensions Enable */ +#define CR4_VMXE (1 << 13) /* Virtual Machine Extensions Enable */ +#define CR4_LA57 (1 << 12) /* Five-Level Paging */ +#define CR4_UMIP (1 << 11) /* User-Mode Instruction Prevention */ +#define CR4_OSXMMEXCPT (1 << 10) /* Unmasked SIMD FP Exceptions */ +#define CR4_OSFXSR (1 << 9) /* FXSAVE and FXRSTOR Enable */ +#define CR4_PCE (1 << 8) /* Performance Counter Enable */ +#define CR4_PGE (1 << 7) /* Page Global Enable */ +#define CR4_MCE (1 << 6) /* Machine-Check Enable */ +#define CR4_PAE (1 << 5) /* Physical Address Extensions */ +#define CR4_PSE (1 << 4) /* Page Size Extensions */ +#define CR4_DE (1 << 3) /* Debugging Extensions */ +#define CR4_TSD (1 << 2) /* Time Stamp Disable */ +#define CR4_PVI (1 << 1) /* Protected-Mode Virtual Interrupts */ +#define CR4_VME (1 << 0) /* Virtual-8086 Mode Extensions */ + +/* cr8 */ +#define CR8_TPL 0x0000000f /* Task Priority Level [0:3] */ + +/* ia32-efer */ +#define IA32_EFER_NXE (1 << 11) /* No Execute Extension */ +#define IA32_EFER_LMA (1 << 10) /* Long Mode Active */ +#define IA32_EFER_LME (1 << 8) /* Long Mode Enable */ +#define IA32_EFER_SCE (1 << 0) /* System Call Extension */ + +/* eax=0x00000001; ecx */ +#define CPUID_SSE3 (1 << 0) /* Streaming SIMD Extensions 3 (SSE3) */ +#define CPUID_PCLMULQDQ (1 << 1) /* GF(2^k) Carry-less multiplication */ +#define CPUID_DTES64 (1 << 2) /* 64-bit DS Area */ +#define CPUID_MONITOR (1 << 3) /* MONITOR/MWAIT instructions */ +#define CPUID_DSCPL (1 << 4) /* CPL Qualified Debug Store */ +#define CPUID_VMX (1 << 5) /* Virtual Machine Extensions */ +#define CPUID_SMX (1 << 6) /* Safer Mode Exentions */ +#define CPUID_EST (1 << 7) /* Enhanced SpeedStep Technology */ +#define CPUID_TM2 (1 << 8) /* Thermal Monitor 2 */ +#define CPUID_SSSE3 (1 << 9) /* Supplemental Streaming SIMD Extensions 3 */ +#define CPUID_CNXT_ID (1 << 10) /* L1 Context ID */ +#define CPUID_SDBG (1 << 11) /* Silicon Debug */ +#define CPUID_FMA (1 << 12) /* Fused Multiply Add */ +#define CPUID_CMPXCHG16B (1 << 13) /* CMPXCHG16B instruction */ +#define CPUID_XTPR (1 << 14) /* xTPR Update Control */ +#define CPUID_PDCM (1 << 15) /* Perfmon and Debug Capability */ +#define CPUID_PCID (1 << 17) /* Process Context Identifiers */ +#define CPUID_DCA (1 << 18) /* Direct cache access for DMA writes */ +#define CPUID_SSE4_1 (1 << 19) /* SSE4.1 instructions */ +#define CPUID_SSE4_2 (1 << 20) /* SSE4.2 instructions */ +#define CPUID_X2APIC (1 << 21) /* x2APIC support */ +#define CPUID_MOVBE (1 << 22) /* MOVBE instruction */ +#define CPUID_POPCNT (1 << 23) /* POPCNT instruction */ +#define CPUID_TSCDT (1 << 24) /* TSC Deadline Timer */ +#define CPUID_AESNI (1 << 25) /* AESNI instructions */ +#define CPUID_XSAVE (1 << 26) /* XSAVE/XRSTOR/XSETBV/XGETBV and XCR0 */ +#define CPUID_OSXSAVE (1 << 27) /* CR4.OSXSAVE enabled to support XSAVE/XRSTOR */ +#define CPUID_AVX (1 << 28) /* AVX instruction extensions */ +#define CPUID_F16C (1 << 29) /* 16-bit floating-point conversion instructions */ +#define CPUID_RDRND (1 << 30) /* RDRAND instruction */ +#define CPUID_HV (1 << 31) /* Running in Hypervisor */ + +/* eax=0x00000001; edx */ +#define CPUID_FPU (1 << 0) /* x87 FPU */ +#define CPUID_VME (1 << 1) /* Virtual 8086 mode extensions */ +#define CPUID_DE (1 << 2) /* Debugging extensions (CR4.DE) */ +#define CPUID_PSE (1 << 3) /* Page Size Extension */ +#define CPUID_TSC (1 << 4) /* Time Stamp Counter */ +#define CPUID_MSR (1 << 5) /* Model-specific Registers */ +#define CPUID_PAE (1 << 6) /* Physical Address Extensions */ +#define CPUID_MCE (1 << 7) /* Machine Check Excdeptions */ +#define CPUID_CX8 (1 << 8) /* Compare and Swap instructions */ +#define CPUID_APIC (1 << 9) /* Advanced Programmable Interrupt Controller */ +#define CPUID_SEP (1 << 11) /* SYSENTER and SYSEXIT instructions */ +#define CPUID_MTRR (1 << 12) /* Memory Type Range Registers */ +#define CPUID_PGE (1 << 13) /* Page Global bit (CR4.PGE) */ +#define CPUID_MCA (1 << 14) /* Machine Check Architecture */ +#define CPUID_CMOV (1 << 15) /* Conditional Move Instruction */ +#define CPUID_PAT (1 << 16) /* Page Attribute Table */ +#define CPUID_PSE36 (1 << 17) /* 36-Bit Page Size Extension (4MiB pages) */ +#define CPUID_PSN (1 << 18) /* Processor Serial Number */ +#define CPUID_CLFLSH (1 << 19) /* CLFLUSH instruction */ +#define CPUID_DS (1 << 21) /* Debug store: save trace of executed jumps */ +#define CPUID_ACPI (1 << 22) /* Thermal Monitor and Clock MSRs */ +#define CPUID_MMX (1 << 23) /* MMX instructions */ +#define CPUID_FXSR (1 << 24) /* FXSAVE, FXRESTOR instructions (CR4.OSFXSR) */ +#define CPUID_SSE (1 << 25) /* SSE instructions */ +#define CPUID_SSE2 (1 << 26) /* SSE2 instructions */ +#define CPUID_SS (1 << 27) /* CPU cache supports self-snoop */ +#define CPUID_HTT (1 << 28) /* Max APIC IDs reserved field is valid */ +#define CPUID_TM (1 << 29) /* Thermal monitor limits temperature */ +#define CPUID_PBE (1 << 31) /* Pending Break Enable */ + +/* eax=0x00000006; eax */ +#define CPUID_ARAT (1 << 2) /* APIC-Timer-always-running feature */ + +/* eax=0x00000007; ebx */ +#define CPUID_FSGSBASE (1 << 0) /* Access to FS and GS MSRs */ +#define CPUID_TSC_ADJ (1 << 1) /* TSC adjust MSR */ +#define CPUID_SGX (1 << 2) /* Sotware Guard Extensions */ +#define CPUID_BMI1 (1 << 3) /* Bit Manipulation Instruction Set 1 */ +#define CPUID_HLE (1 << 4) /* Hardware Lock Elision */ +#define CPUID_AVX2 (1 << 5) /* Advanced Vector Extensions 2 */ +#define CPUID_SMEP (1 << 7) /* Supervisor-Mode Execution Prevention */ +#define CPUID_BMI2 (1 << 8) /* Bit Manipulation Instruction Set 2 */ +#define CPUID_ERMS (1 << 9) /* Enhanced REP MOVSB/STOSB */ +#define CPUID_INVPCID (1 << 10) /* INVPCID instruction */ +#define CPUID_RTM (1 << 11) /* Transactional Synchronization Extensions */ +#define CPUID_PQM (1 << 12) /* Platform Quality of Service Monitoring */ +#define CPUID_DFPUCSDS (1 << 13) /* Deprecates FPU CS and FPU DS */ +#define CPUID_MPX (1 << 14) /* Memory Protection Extensions */ +#define CPUID_PQE (1 << 15) /* Platform Quality of Service Enforcement */ +#define CPUID_AVX512F (1 << 16) /* AVX512 Foundation */ +#define CPUID_AVX512DQ (1 << 17) /* AVX512 Doubleword and Quadword Instructions */ +#define CPUID_RDSEED (1 << 18) /* RDSEED instruction */ +#define CPUID_ADX (1 << 19) /* Add-Carry Instruction Extensions */ +#define CPUID_SMAP (1 << 20) /* Supervisor Mode Access Prevention */ +#define CPUID_AVX512IMFA (1 << 21) /* AVX-512 Integer Fused Multiply-Add Instructions */ +#define CPUID_PCOMMIT (1 << 22) /* PCOMMIT instruction */ +#define CPUID_CLFLUSHOPT (1 << 23) /* CLFLUSHOPT instruction */ +#define CPUID_CLWB (1 << 24) /* CLWB instruction */ +#define CPUID_INTEL_PT (1 << 25) /* Intel Processor Tracec */ +#define CPUID_AVX512PF (1 << 26) /* AVX-512 Prefetch Instructions */ +#define CPUID_AVX512ER (1 << 27) /* AVX-512 Exponential and Reciprocal Instructions */ +#define CPUID_AVX512CD (1 << 28) /* AVX-512 Conflict Detection Instructions */ +#define CPUID_SHA (1 << 29) /* Intel SHA extensions */ +#define CPUID_AVX512BW (1 << 30) /* AVX-512 Byte and Word Instructions */ +#define CPUID_AVX512VL (1 << 31) /* AVX-512 Vector Length Extensions */ + +/* eax=0x00000007; ecx */ +#define CPUID_PREFETCHWT1 (1 << 0) /* PREFETCHWT1 instruction */ +#define CPUID_AVX512VBMI (1 << 1) /* AVX-512 Vector Bit Manipulation Instructions */ +#define CPUID_UMIP (1 << 2) /* User-mode Instruction Prevention */ +#define CPUID_PKU (1 << 3) /* Memory Protection Keys for User-mode pages */ +#define CPUID_OSPKE (1 << 4) /* PKU enabled by OS */ +#define CPUID_AVX512VBMI2 (1 << 6) /* AVX-512 Vector Bit Manipulation Instructions 2 */ +#define CPUID_GFNI (1 << 8) /* Galois Field instructions */ +#define CPUID_VAES (1 << 9) /* Vector AES instruction set (VEX-256/EVEX) */ +#define CPUID_VPCLMULQDQ (1 << 10) /* CLMUL instruction set (VEX-256/EVEX) */ +#define CPUID_AVX512VNNI (1 << 11) /* AVX-512 Vector Neural Network Instructions */ +#define CPUID_AVX512BITALG (1 << 12) /* AVX-512 BITALG instructions */ +#define CPUID_AVX512VPOPCNTDQ (1 << 14) /* AVX-512 Vector POPCNt Doubleword and Quadword */ +#define CPUID_MAWAU1 (1 << 17) /* MPX Address-Width Adjust 1 */ +#define CPUID_MAWAU2 (1 << 18) /* MPX Address-Width Adjust 2 */ +#define CPUID_MAWAU3 (1 << 19) /* MPX Address-Width Adjust 3 */ +#define CPUID_MAWAU4 (1 << 20) /* MPX Address-Width Adjust 4 */ +#define CPUID_MAWAU5 (1 << 21) /* MPX Address-Width Adjust 5 */ +#define CPUID_RDPID (1 << 22) /* Read Processor ID */ +#define CPUID_SGX_LC (1 << 30) /* SGX Launch Configuration */ + +/* eax=0x00000007; edx */ +#define CPUID_AVX512_4VNNIW (1 << 2) /* AVX-512 4-register Neural Network Instructions */ +#define CPUID_AVX512_4FMAPS (1 << 3) /* AVX-512 4-register Multiply Accumulation Single precision */ +#define CPUID_AVX512_PCONFIG (1 << 18) /* Platform configuration (Memory Encryption) */ +#define CPUID_SPEC_CTRL_IBRS (1 << 26) /* Indirect Branch Speculation Control IBRS/IBPB */ +#define CPUID_SPEC_CTRL_STIBP (1 << 27) /* Single Thread Indirect Branch Predictor (STIBP) */ + +/* eax=0x80000001; ecx */ +#define CPUID_LAHF_LM (1 << 0) /* LAHF/SAHF in long mode */ +#define CPUID_LZCNT (1 << 5) /* LZCNT instruction */ +#define CPUID_PREFETCHW (1 << 8) /* PREFETCHW instruction */ + +/* eax=0x80000001; edx */ +#define CPUID_SYSCALL (1 << 11) /* SYSCALL and SYSRET instructions */ +#define CPUID_NX (1 << 20) /* No Execute */ +#define CPUID_PDPE1GB (1 << 26) /* Gigabyte pages */ +#define CPUID_RDTSCP (1 << 27) /* RDTSCP instruction */ +#define CPUID_LM (1 << 29) /* Long mode */ + +/* eax=0x80000007; edx */ +#define CPUID_INVARIANT_TSC (1 << 8) /* Invariant TSC */ + +/* MSRs */ +#define MSR_IA32_APIC_BASE 0x0000001BU /* APIC base physical address */ + +/* X2APIC MSRs */ +#define MSR_IA32_EXT_APIC_ID 0x00000802U /* x2APIC ID */ +#define MSR_IA32_EXT_APIC_VERSION 0x00000803U /* x2APIC version */ +#define MSR_IA32_EXT_APIC_TPR 0x00000808U /* x2APIC task priority */ +#define MSR_IA32_EXT_APIC_PPR 0x0000080AU /* x2APIC processor priority */ +#define MSR_IA32_EXT_APIC_EOI 0x0000080BU /* x2APIC EOI */ +#define MSR_IA32_EXT_APIC_LDR 0x0000080DU /* x2APIC logical destination */ +#define MSR_IA32_EXT_APIC_SIVR 0x0000080FU /* x2APIC spurious interrupt vector */ +#define MSR_IA32_EXT_APIC_ISR0 0x00000810U /* x2APIC in-service register 0 */ +#define MSR_IA32_EXT_APIC_ISR1 0x00000811U /* x2APIC in-service register 1 */ +#define MSR_IA32_EXT_APIC_ISR2 0x00000812U /* x2APIC in-service register 2 */ +#define MSR_IA32_EXT_APIC_ISR3 0x00000813U /* x2APIC in-service register 3 */ +#define MSR_IA32_EXT_APIC_ISR4 0x00000814U /* x2APIC in-service register 4 */ +#define MSR_IA32_EXT_APIC_ISR5 0x00000815U /* x2APIC in-service register 5 */ +#define MSR_IA32_EXT_APIC_ISR6 0x00000816U /* x2APIC in-service register 6 */ +#define MSR_IA32_EXT_APIC_ISR7 0x00000817U /* x2APIC in-service register 7 */ +#define MSR_IA32_EXT_APIC_TMR0 0x00000818U /* x2APIC trigger mode register 0 */ +#define MSR_IA32_EXT_APIC_TMR1 0x00000819U /* x2APIC trigger mode register 1 */ +#define MSR_IA32_EXT_APIC_TMR2 0x0000081AU /* x2APIC trigger mode register 2 */ +#define MSR_IA32_EXT_APIC_TMR3 0x0000081BU /* x2APIC trigger mode register 3 */ +#define MSR_IA32_EXT_APIC_TMR4 0x0000081CU /* x2APIC trigger mode register 4 */ +#define MSR_IA32_EXT_APIC_TMR5 0x0000081DU /* x2APIC trigger mode register 5 */ +#define MSR_IA32_EXT_APIC_TMR6 0x0000081EU /* x2APIC trigger mode register 6 */ +#define MSR_IA32_EXT_APIC_TMR7 0x0000081FU /* x2APIC trigger mode register 7 */ +#define MSR_IA32_EXT_APIC_IRR0 0x00000820U /* x2APIC interrupt request register 0 */ +#define MSR_IA32_EXT_APIC_IRR1 0x00000821U /* x2APIC interrupt request register 1 */ +#define MSR_IA32_EXT_APIC_IRR2 0x00000822U /* x2APIC interrupt request register 2 */ +#define MSR_IA32_EXT_APIC_IRR3 0x00000823U /* x2APIC interrupt request register 3 */ +#define MSR_IA32_EXT_APIC_IRR4 0x00000824U /* x2APIC interrupt request register 4 */ +#define MSR_IA32_EXT_APIC_IRR5 0x00000825U /* x2APIC interrupt request register 5 */ +#define MSR_IA32_EXT_APIC_IRR6 0x00000826U /* x2APIC interrupt request register 6 */ +#define MSR_IA32_EXT_APIC_IRR7 0x00000827U /* x2APIC interrupt request register 7 */ +#define MSR_IA32_EXT_APIC_ESR 0x00000828U /* x2APIC error status */ +#define MSR_IA32_EXT_APIC_LVT_CMCI 0x0000082FU /* x2APIC LVT corrected machine check interrupt register */ +#define MSR_IA32_EXT_APIC_ICR 0x00000830U /* x2APIC interrupt command register */ +#define MSR_IA32_EXT_APIC_LVT_TIMER 0x00000832U /* x2APIC LVT timer interrupt register */ +#define MSR_IA32_EXT_APIC_LVT_THERMAL 0x00000833U /* x2APIC LVT thermal sensor interrupt register */ +#define MSR_IA32_EXT_APIC_LVT_PMI 0x00000834U /* x2APIC LVT performance monitor interrupt register */ +#define MSR_IA32_EXT_APIC_LVT_LINT0 0x00000835U /* x2APIC LVT LINT0 register */ +#define MSR_IA32_EXT_APIC_LVT_LINT1 0x00000836U /* x2APIC LVT LINT1 register */ +#define MSR_IA32_EXT_APIC_LVT_ERROR 0x00000837U /* x2APIC LVT error register */ +#define MSR_IA32_EXT_APIC_INIT_COUNT 0x00000838U /* x2APIC initial count register */ +#define MSR_IA32_EXT_APIC_CUR_COUNT 0x00000839U /* x2APIC current count register */ +#define MSR_IA32_EXT_APIC_DIV_CONF 0x0000083EU /* x2APIC divide configuration register */ +#define MSR_IA32_EXT_APIC_SELF_IPI 0x0000083FU /* x2APIC self IPI register */ + +#endif /* !_CPUDEF_H_ */ From 99ebdecb090c7f4cde12dc38e7c8741ba4abce0b Mon Sep 17 00:00:00 2001 From: Michael Clark Date: Sat, 5 Mar 2022 16:07:25 +1300 Subject: [PATCH 6/7] add -x flag to ./run.sh to enable kvm x2apic acceleration --- run.sh | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/run.sh b/run.sh index 042431c..36c3727 100755 --- a/run.sh +++ b/run.sh @@ -1,8 +1,8 @@ #!/bin/bash -unset REBUILD IDE_MODE DEBUG EXT2 BIG +unset REBUILD IDE_MODE DEBUG EXT2 BIG ACCEL -while getopts 'rldeb' c +while getopts 'rldebx' c do case $c in r) REBUILD=TRUE ;; @@ -10,6 +10,7 @@ do d) DEBUG=TRUE ;; e) EXT2=TRUE ;; b) BIG=TRUE ;; + x) ACCEL=TRUE ;; esac done @@ -36,7 +37,9 @@ if [ -n "$IDE_MODE" ]; then ROOT_DISK="-hdd ./bin/$ROOT_IMG" fi CPU="-cpu phenom-v1 -smp sockets=1 -smp cores=4 -smp threads=1" -if [ -n "$BIG" ]; then +if [ -n "$ACCEL" ]; then + CPU="-machine pc,accel=kvm,kernel-irqchip=on -cpu host,vmware-cpuid-freq=on,tsc-frequency=2600000000 -smp sockets=1 -smp cores=4 -smp threads=1" +elif [ -n "$BIG" ]; then CPU="-cpu IvyBridge-v2 -smp sockets=2 -smp cores=12 -smp threads=2" fi From 8f555980cf74227f3ce58bbcb69302e71cc65f38 Mon Sep 17 00:00:00 2001 From: Michael Clark Date: Sat, 5 Mar 2022 16:02:40 +1300 Subject: [PATCH 7/7] implement x2APIC support and enable if cpuid bit present --- include/defs.h | 4 +- include/proc.h | 4 ++ include/x86.h | 38 ++++++++++- kernel/lapic.c | 173 +++++++++++++++++++++++++++++++++++++++---------- kernel/main.c | 92 ++++++++++++++++---------- 5 files changed, 241 insertions(+), 70 deletions(-) diff --git a/include/defs.h b/include/defs.h index 2fb65a0..85a9592 100644 --- a/include/defs.h +++ b/include/defs.h @@ -78,8 +78,10 @@ int cpunum(void); extern volatile uint* lapic; void lapiceoi(void); void lapicinit(void); -void lapicstartap(uchar, uint); void microdelay(int); +void lapicstartap(uchar, uint); +void lapicx2enable(uint); +void lapicsendipi(uint, uint); // log.c void initlog(void); diff --git a/include/proc.h b/include/proc.h index 6d81029..f3b3426 100644 --- a/include/proc.h +++ b/include/proc.h @@ -18,6 +18,10 @@ struct cpu { // Cpu-local storage variables; see below void *local; struct proc *proc; + + char name[50]; // cpuid name + char vendor[13]; // cpuid vendor + uint32 model; // cpuid model }; extern struct cpu cpus[NCPU]; diff --git a/include/x86.h b/include/x86.h index 7a37eeb..ee7b685 100644 --- a/include/x86.h +++ b/include/x86.h @@ -180,7 +180,18 @@ static inline unsigned int amd64_xchg(volatile unsigned int *addr, unsigned long unsigned int result; // The + in "+m" denotes a read-modify-write operand. - asm volatile ("lock; xchgl %0, %1" : + asm volatile ("lock xchgl %0, %1" : + "+m" (*addr), "=a" (result) : + "1" (newval) : + "cc"); + return result; +} + +static inline unsigned int amd64_xadd(volatile unsigned int *addr, unsigned long newval) { + unsigned int result; + + // The + in "+m" denotes a read-modify-write operand. + asm volatile ("lock xaddl %1, %0" : "+m" (*addr), "=a" (result) : "1" (newval) : "cc"); @@ -203,6 +214,31 @@ static inline void amd64_cpuid(unsigned int ax, unsigned int *p) { : "0" (ax)); } +static inline uint64 amd64_rdmsr(uint msr) { + uint32 low, high; + asm volatile ("rdmsr" + : "=a" (low), "=d" (high) + : "c" (msr)); + return (uint64)low | ((uint64)high << 32); +} + +static inline void amd64_wrmsr(uint msr, uint64 newval) { + uint32 low = newval; + uint32 high = newval >> 32; + asm volatile ("wrmsr" + : + : "a" (low), "d" (high), "c" (msr)); +} + +static inline uint64 amd64_rdtsc() +{ + uint32 low, high; + + asm volatile("rdtsc" : "=a" (low), "=d" (high)); + return (uint64)low | ((uint64)high << 32); +} + + // lie about some register names in 64bit mode to avoid // clunky ifdefs in proc.c and trap.c. struct trapframe { diff --git a/kernel/lapic.c b/kernel/lapic.c index 7e59865..9697959 100644 --- a/kernel/lapic.c +++ b/kernel/lapic.c @@ -10,14 +10,22 @@ #include "proc.h" // Local APIC registers, divided by 4 for use as uint[] indices. -#define ID (0x0020 / 4) // ID -#define VER (0x0030 / 4) // Version -#define TPR (0x0080 / 4) // Task Priority -#define EOI (0x00B0 / 4) // EOI -#define SVR (0x00F0 / 4) // Spurious Interrupt Vector +#define ID 0x02 // ID +#define VER 0x03 // Version +#define TPR 0x08 // Task Priority +#define EOI 0x0B // EOI +#define LDR 0x0D // Logical destination +#define SVR 0x0F // Spurious Interrupt Vector #define ENABLE 0x00000100 // Unit Enable -#define ESR (0x0280 / 4) // Error Status -#define ICRLO (0x0300 / 4) // Interrupt Command +#define ISR0 0x10 // In-service bits 0:31 +#define ISR7 0x17 // In-service bits 224:255 +#define TMR0 0x18 // Trigger mode bits 0:31 +#define TMR7 0x1F // Trigger mode bits 224:255 +#define IRR0 0x20 // Interrupt request bits 0:31 +#define IRR7 0x27 // Interrupt request bits 224:255 +#define ESR 0x28 // Error Status +#define ICRLO 0x30 // Interrupt Command [31:0] +#define ICRHI 0x31 // Interrupt Command [63:32] #define INIT 0x00000500 // INIT/RESET #define STARTUP 0x00000600 // Startup IPI #define DELIVS 0x00001000 // Delivery status @@ -27,30 +35,87 @@ #define BCAST 0x00080000 // Send to all APICs, including self. #define BUSY 0x00001000 #define FIXED 0x00000000 -#define ICRHI (0x0310 / 4) // Interrupt Command [63:32] -#define TIMER (0x0320 / 4) // Local Vector Table 0 (TIMER) +#define TIMER 0x32 // Local Vector Table 0 (TIMER) #define X1 0x0000000B // divide counts by 1 #define PERIODIC 0x00020000 // Periodic -#define PCINT (0x0340 / 4) // Performance Counter LVT -#define LINT0 (0x0350 / 4) // Local Vector Table 1 (LINT0) -#define LINT1 (0x0360 / 4) // Local Vector Table 2 (LINT1) -#define ERROR (0x0370 / 4) // Local Vector Table 3 (ERROR) +#define THERMAL 0x33 // Thermal Monitoring LVT +#define PCINT 0x34 // Performance Counter LVT +#define LINT0 0x35 // Local Vector Table 1 (LINT0) +#define LINT1 0x36 // Local Vector Table 2 (LINT1) +#define ERROR 0x37 // Local Vector Table 3 (ERROR) #define MASKED 0x00010000 // Interrupt masked -#define TICR (0x0380 / 4) // Timer Initial Count -#define TCCR (0x0390 / 4) // Timer Current Count -#define TDCR (0x03E0 / 4) // Timer Divide Configuration +#define TICR 0x38 // Timer Initial Count +#define TCCR 0x39 // Timer Current Count +#define TDCR 0x3E // Timer Divide Configuration volatile uint* lapic; // Initialized in mp.c +const int wants_x2apic = 1; +__thread volatile int using_x2apic = 0; -static void lapicw(int index, int value){ - lapic[index] = value; - lapic[ID]; // wait for write to finish, by reading +static inline int has_x2apic() { + uint32 cpuid_1[4]; + enum { eax, ebx, ecx, edx }; + amd64_cpuid(1, cpuid_1); + return !!(cpuid_1[ecx] & CPUID_X2APIC); +} + +static inline void lapicw(int index, int value) { + if (using_x2apic) { + amd64_wrmsr(0x800+index, value); + } else { + lapic[index*4] = value; + lapic[ID*4]; // wait for write to finish, by reading + } +} + +static inline uint64 lapicr(int index) { + if (using_x2apic) { + return amd64_rdmsr(0x800+index); + } else { + return lapic[index*4]; + } +} + +static inline void lapic_wicr(uint32 id, uint32 value) +{ + if (using_x2apic) { + amd64_wrmsr(0x800+ICRLO, ((uint64)id << 32) | (uint64)value); + } else { + lapicw(ICRHI, (int32)id); + lapicw(ICRLO, (int32)value); + } +} + +static inline uint64 lapic_ricr() +{ + if (using_x2apic) { + return amd64_rdmsr(0x800+ICRLO); + } else { + return ((uint64)lapicr(ICRHI) << 32) | (uint64)lapicr(ICRLO); + } } void lapicinit(void){ if (!lapic) return; + // Enable x2apic mode if available + lapicx2enable(wants_x2apic); + + // Read and report APIC base, id, and version fields + uint64 apicbase = amd64_rdmsr(MSR_IA32_APIC_BASE); + uint64 apicaddr = apicbase & ~((1ul << 12) - 1); + uint xapic = !!(apicbase & (1ul << 11)); + uint x2apic = !!(apicbase & (1ul << 10)); + uint bsp = !!(apicbase & (1ul << 8)); + uint apicid = lapicr(ID) >> (using_x2apic ? 0 : 24); + uint apicver = lapicr(VER); + uint version = apicver & 0xff; + uint maxlvt = (apicver >> 16) & 0xFF; + + cprintf("cpu-%d: lapicinit: lapic#%x @%x, version=0x%x, maxlvt=%d, xapic=%d, x2apic=%d, bsp=%d\n", + cpu->id, apicid, apicaddr, version, maxlvt, xapic, x2apic, bsp); + // Enable local APIC; set spurious interrupt vector. lapicw(SVR, ENABLE | (T_IRQ0 + IRQ_SPURIOUS)); @@ -66,10 +131,12 @@ void lapicinit(void){ lapicw(LINT0, MASKED); lapicw(LINT1, MASKED); - // Disable performance counter overflow interrupts - // on machines that provide that interrupt entry. - if (((lapic[VER] >> 16) & 0xFF) >= 4) + // Disable performance counter and thermal interrupts + // on machines that provide those LVT entries. + if (maxlvt >= 5) { lapicw(PCINT, MASKED); + lapicw(THERMAL, MASKED); + } // Map error interrupt to IRQ_ERROR. lapicw(ERROR, T_IRQ0 + IRQ_ERROR); @@ -79,12 +146,23 @@ void lapicinit(void){ lapicw(ESR, 0); // Ack any outstanding interrupts. - lapicw(EOI, 0); + if (using_x2apic) { + for (uint isr_reg = ISR7; isr_reg >= ISR0; isr_reg--) { + for (uint i = 0U; i < 32U; i++) { + if (lapicr(isr_reg) != 0U) { + lapicw(EOI, 0U); + } else { + break; + } + } + } + } else { + lapicw(EOI, 0); + } // Send an Init Level De-Assert to synchronise arbitration ID's. - lapicw(ICRHI, 0); - lapicw(ICRLO, BCAST | INIT | LEVEL); - while (lapic[ICRLO] & DELIVS) + lapic_wicr(0, BCAST | INIT | LEVEL); + while (lapic_ricr() & DELIVS) ; // Enable interrupts on the APIC (but not on the processor). @@ -111,7 +189,7 @@ int cpunum(void){ if (!lapic) return 0; - id = lapic[ID] >> 24; + id = lapicr(ID) >> (using_x2apic ? 0 : 24); for (n = 0; n < ncpu; n++) if (id == cpus[n].apicid) return n; @@ -125,9 +203,13 @@ void lapiceoi(void){ lapicw(EOI, 0); } -// Spin for a given number of microseconds. -// On real hardware would want to tune this dynamically. +extern uint32 tscfreq; + +// Spin for a given number of microseconds using the tsc void microdelay(int us){ + uint64 tc, ts = amd64_rdtsc(), tf = ts + (uint64)tscfreq * (uint64)us; + while ((tc = amd64_rdtsc()) < tf) + ; } #define IO_RTC 0x70 @@ -147,12 +229,13 @@ void lapicstartap(uchar apicid, uint addr){ wrv[0] = 0; wrv[1] = addr >> 4; + uint destid = apicid << (using_x2apic ? 0 : 24); + // "Universal startup algorithm." // Send INIT (level-triggered) interrupt to reset other CPU. - lapicw(ICRHI, apicid << 24); - lapicw(ICRLO, INIT | LEVEL | ASSERT); + lapic_wicr(destid, INIT | LEVEL | ASSERT); microdelay(200); - lapicw(ICRLO, INIT | LEVEL); + lapic_wicr(destid, INIT | LEVEL); microdelay(100); // should be 10ms, but too slow in Bochs! // Send startup IPI (twice!) to enter code. @@ -161,8 +244,30 @@ void lapicstartap(uchar apicid, uint addr){ // should be ignored, but it is part of the official Intel algorithm. // Bochs complains about the second one. Too bad for Bochs. for (i = 0; i < 2; i++) { - lapicw(ICRHI, apicid << 24); - lapicw(ICRLO, STARTUP | (addr >> 12)); + lapic_wicr(destid, STARTUP | (addr >> 12)); microdelay(200); } } + +// enable x2apic mode +void lapicx2enable(uint enable) +{ + enum { X2APIC_ENABLE = (1ul << 10) }; + + uint64 apicbase = amd64_rdmsr(MSR_IA32_APIC_BASE); + + if (!has_x2apic()) return; + + if (enable && (apicbase & X2APIC_ENABLE) == 0) { + amd64_wrmsr(MSR_IA32_APIC_BASE, (apicbase |= X2APIC_ENABLE)); + } else if (!enable && (apicbase & X2APIC_ENABLE) == X2APIC_ENABLE) { + amd64_wrmsr(MSR_IA32_APIC_BASE, (apicbase &= ~X2APIC_ENABLE)); + } + using_x2apic = !!enable; +} + +// send ipi to another processor +void lapicsendipi(uint irq, uint cpunum) +{ + lapic_wicr(using_x2apic ? cpunum : cpunum << 24, irq); +} diff --git a/kernel/main.c b/kernel/main.c index 6212f1e..cbce2c9 100644 --- a/kernel/main.c +++ b/kernel/main.c @@ -8,6 +8,7 @@ #include "acpi.h" #include "pci.h" #include "buf.h" +#include "irq.h" #include "kernel/string.h" static void identcpu(); @@ -17,17 +18,12 @@ static void mpmain(void) __attribute__((noreturn)); extern pde_t* kpgdir; uint64 ROOT_DEV = 1; -char CPU_NAME[50]; -char CPU_VENDOR[13]; -uint32 CPU_MODEL; - extern char end[]; // first address after kernel loaded from ELF file // Bootstrap processor starts running C code here. // Allocate a real stack and switch to it, first // doing some setup required for memory allocator to work. int main(void){ - identcpu(); uartearlyinit(); kinit1(P2V(KALLOC_START), P2V(KALLOC_START + 4 * 1024 * 1024)); // phys page allocator kvmalloc(); // kernel page table @@ -37,18 +33,26 @@ int main(void){ if (!ismp) panic("too few processors"); //really, it's the year 2021. - lapicinit(); seginit(); // set up segments - cprintf("\ncpu%d: starting Xv64\n\n", cpu->id); - credits(); + tvinit(); // trap vectors picinit(); // interrupt controller ioapicinit(); // another interrupt controller - consoleinit(); // I/O devices & their interrupts uartinit(); // serial port - cprintf("%s CPU detected (%s - %d)\n", CPU_NAME, CPU_VENDOR, CPU_MODEL); pinit(); // process table + identcpu(); + lapicinit(); + startothers(); // start other processors + + // Finish setting up this processor in mpmain. + mpmain(); +} + +void postinit() +{ + consoleinit(); // I/O devices & their interrupts + cprintf("\ncpu%d: starting Xv64\n\n", cpu->id); + credits(); procloopinit();// setup proc loop device - tvinit(); // trap vectors pciinit(); // initialize PCI bus (AHCI also) binit(); // buffer cache fileinit(); // file table @@ -58,12 +62,7 @@ int main(void){ vfsinit(); // bootstrap fs init // (must happen after all disk types are initialized) - startothers(); // start other processors - kinit2(P2V(KALLOC_START + 4 * 1024 * 1024), P2V(PHYSTOP)); // must come after startothers() userinit(); // first user process - - // Finish setting up this processor in mpmain. - mpmain(); } void credits(){ @@ -74,6 +73,7 @@ void credits(){ void mpenter(void){ switchkvm(); seginit(); + identcpu(); lapicinit(); mpmain(); } @@ -82,12 +82,13 @@ void mpenter(void){ static void mpmain(void){ idtinit(); // load idt register if(cpu->id == 0) { + kinit2(P2V(KALLOC_START + 4 * 1024 * 1024), P2V(PHYSTOP)); // must come after startothers() cpu->capabilities = CPU_RESERVED_BLESS; + cprintf("%d-way SMP kernel online.\n", ncpu); + postinit(); + cprintf("starting scheduler\n"); } amd64_xchg(&cpu->started, 1); // tell startothers() we're up - if(cpu->id == 0){ - cprintf("%d-way SMP kernel fully online.\nentering user space...\n", ncpu); - } scheduler(); // start running processes } @@ -126,22 +127,45 @@ static void startothers(void){ } } +uint32 tscfreq; + +enum { eax, ebx, ecx, edx }; + void identcpu() { - uint32 vendor[4]; - uint32 regs[4]; - - amd64_cpuid(0, regs); - vendor[0] = regs[1]; - vendor[1] = regs[3]; - vendor[2] = regs[2]; - vendor[4] = (uint32)'\0'; - memmove(&CPU_VENDOR, (char *)vendor, sizeof(CPU_VENDOR)); - CPU_MODEL = regs[0]; - - memset(&CPU_NAME, 0, sizeof(CPU_NAME)); - amd64_cpuid(0x80000002, (void *)&CPU_NAME); - amd64_cpuid(0x80000003, ((void *)&CPU_NAME) + 0x10); - amd64_cpuid(0x80000004, ((void *)&CPU_NAME) + 0x20); + uint32 cpuid_0[4]; + uint32 cpuid_8_2[4]; + uint32 cpuid_8_3[4]; + uint32 cpuid_8_4[4]; + uint32 cpuid_16[4]; + uint32 cpuid_vmw[4]; + + amd64_cpuid(0, cpuid_0); + amd64_cpuid(0x80000002, cpuid_8_2); + amd64_cpuid(0x80000003, cpuid_8_3); + amd64_cpuid(0x80000004, cpuid_8_4); + + memset(cpu->vendor, 0, sizeof(cpu->vendor)); + memmove(cpu->vendor + 0, &cpuid_0[1], 4); + memmove(cpu->vendor + 4, &cpuid_0[3], 4); + memmove(cpu->vendor + 8, &cpuid_0[2], 4); + cpu->model = cpuid_0[0]; + + memset(cpu->name, 0, sizeof(cpu->name)); + memmove(cpu->name + 0x00, cpuid_8_2, 0x10); + memmove(cpu->name + 0x10, cpuid_8_3, 0x10); + memmove(cpu->name + 0x20, cpuid_8_4, 0x10); + + amd64_cpuid(0x40000010, cpuid_vmw); + amd64_cpuid(0x16, cpuid_16); + + if (cpuid_16[eax]) { + tscfreq = cpuid_16[eax] & 0xffff; + } else if (cpuid_vmw[eax] > 100000) { + tscfreq = cpuid_vmw[eax] / 1000; + } + + cprintf("cpu-%d: name: %s vendor: %s model: %d tscfreq: %d\n", + cpu->id, cpu->name, cpu->vendor, cpu->model, tscfreq); } void sys_reboot(){