Skip to content

Commit

Permalink
Function headers
Browse files Browse the repository at this point in the history
  • Loading branch information
phaubertin committed Jan 11, 2025
1 parent 40236e9 commit 05e151a
Show file tree
Hide file tree
Showing 2 changed files with 159 additions and 6 deletions.
120 changes: 114 additions & 6 deletions kernel/infrastructure/i686/cpuinfo.c
Original file line number Diff line number Diff line change
Expand Up @@ -41,10 +41,18 @@

cpuinfo_t bsp_cpuinfo;

/**
* Report CPU is too old to be supported and panic
*
* This function never returns.
*/
static void too_old(void) {
panic("Pentium CPU or later is required");
}

/**
* Check whether the CPUID instruction is supported, panic otherwise
*/
static void check_cpuid_is_supported(void) {
/* The CPUID instruction is available if we can change the value of eflags
* bit 21 (ID) */
Expand All @@ -58,6 +66,11 @@ static void check_cpuid_is_supported(void) {
}
}

/**
* Call the CPUID instruction and fill the provided CPUID leafs structure
*
* @param leafs CPUID leafs structure (OUT)
*/
static void call_cpuid(x86_cpuid_leafs *leafs) {
memset(leafs, 0, sizeof(x86_cpuid_leafs));

Expand Down Expand Up @@ -92,10 +105,10 @@ static void call_cpuid(x86_cpuid_leafs *leafs) {
}

typedef struct {
int vendor;
uint32_t vendor_dw0;
uint32_t vendor_dw1;
uint32_t vendor_dw2;
int vendor;
uint32_t vendor_dw0;
uint32_t vendor_dw1;
uint32_t vendor_dw2;
} cpuid_vendor_t;

static const cpuid_vendor_t cpuid_vendors[] = {
Expand All @@ -113,6 +126,12 @@ static const cpuid_vendor_t cpuid_vendors[] = {
}
};

/**
* Identify the CPU vendor based on CPUID results
*
* @param cpuinfo structure in which to set the vendor (OUT)
* @param leafs CPUID leafs structure filled by a call_cpuid()
*/
static void identify_vendor(cpuinfo_t *cpuinfo, const x86_cpuid_leafs *leafs) {
const x86_cpuid_regs_t *regs = &leafs->basic0;

Expand All @@ -136,6 +155,12 @@ static void identify_vendor(cpuinfo_t *cpuinfo, const x86_cpuid_leafs *leafs) {
cpuinfo->vendor = CPUINFO_VENDOR_GENERIC;
}

/**
* Identify the CPU family, model and stepping
*
* @param cpuinfo structure in which to set the information (OUT)
* @param leafs CPUID leafs structure filled by a call_cpuid()
*/
static void identify_model(cpuinfo_t *cpuinfo, const x86_cpuid_leafs *leafs) {
uint32_t signature = leafs->basic1.eax;
cpuinfo->family = (signature>>8) & 0xf;
Expand All @@ -151,6 +176,14 @@ static void identify_model(cpuinfo_t *cpuinfo, const x86_cpuid_leafs *leafs) {
}
}

/**
* Identify the data cache alignment
*
* Defaults to 32 if the data cache alignment is not reported by the CPUID instruction.
*
* @param cpuinfo structure in which to set the cache alignment (OUT)
* @param leafs CPUID leafs structure filled by a call_cpuid()
*/
static void identify_dcache_alignment(cpuinfo_t *cpuinfo, const x86_cpuid_leafs *leafs) {
const x86_cpuid_regs_t *regs = &leafs->basic1;

Expand All @@ -161,18 +194,45 @@ static void identify_dcache_alignment(cpuinfo_t *cpuinfo, const x86_cpuid_leafs
}
}

/**
* Utility function that determines whether CPU vendor is AMD
*
* @param cpuinfo CPU information structure
* @return true if CPU vendor is AMD, false otherwise
*/
static bool is_amd(const cpuinfo_t *cpuinfo) {
return cpuinfo->vendor == CPUINFO_VENDOR_AMD;
}

/**
* Utility function that determines whether CPU vendor is Intel
*
* @param cpuinfo CPU information structure
* @return true if CPU vendor is Intel, false otherwise
*/
static bool is_intel(const cpuinfo_t *cpuinfo) {
return cpuinfo->vendor == CPUINFO_VENDOR_INTEL;
}

/**
* Utility function that determines whether CPU vendor is AMD or Intel
*
* @param cpuinfo CPU information structure
* @return true if CPU vendor is AMD or Intel, false otherwise
*/
static bool is_amd_or_intel(const cpuinfo_t *cpuinfo) {
return cpuinfo->vendor == CPUINFO_VENDOR_AMD || cpuinfo->vendor == CPUINFO_VENDOR_INTEL;
}

/**
* Detect whether the CPU supports the SYSENTER fast system call instruction
*
* Sets the CPUINFO_FEATURE_SYSENTER feature flag if the SYSENTER instruction
* is supported.
*
* @param cpuinfo structure in which to set the feature flag (OUT)
* @param leafs CPUID leafs structure filled by a call_cpuid()
*/
static void detect_sysenter_instruction(cpuinfo_t *cpuinfo, const x86_cpuid_leafs *leafs) {
if(!(leafs->basic1.edx & CPUID_FEATURE_SEP)) {
return;
Expand All @@ -185,6 +245,15 @@ static void detect_sysenter_instruction(cpuinfo_t *cpuinfo, const x86_cpuid_leaf
cpuinfo->features |= CPUINFO_FEATURE_SYSENTER;
}

/**
* Detect whether the CPU supports the SYSCALL fast system call instruction
*
* Sets the CPUINFO_FEATURE_SYSCALL feature flag if the SYSCALL instruction
* is supported.
*
* @param cpuinfo structure in which to set the feature flag (OUT)
* @param leafs CPUID leafs structure filled by a call_cpuid()
*/
static void detect_syscall_instruction(cpuinfo_t *cpuinfo, const x86_cpuid_leafs *leafs) {
if(!is_amd(cpuinfo)) {
return;
Expand All @@ -195,6 +264,15 @@ static void detect_syscall_instruction(cpuinfo_t *cpuinfo, const x86_cpuid_leafs
}
}

/**
* Enumerate CPU features
*
* This function detects various features that may be supported by the CPU and
* sets feature flag in the CPU information structure accordingly.
*
* @param cpuinfo structure in which to set the feature flags (OUT)
* @param leafs CPUID leafs structure filled by a call_cpuid()
*/
static void enumerate_features(cpuinfo_t *cpuinfo, const x86_cpuid_leafs *leafs) {
uint32_t flags = leafs->basic1.edx;
uint32_t ext_flags = leafs->ext1.edx;
Expand Down Expand Up @@ -230,6 +308,12 @@ static void enumerate_features(cpuinfo_t *cpuinfo, const x86_cpuid_leafs *leafs)
}
}

/**
* Identify the number of bits of physical addresses
*
* @param cpuinfo structure in which to set the number of address bits (OUT)
* @param leafs CPUID leafs structure filled by a call_cpuid()
*/
static void identify_maxphyaddr(cpuinfo_t *cpuinfo, const x86_cpuid_leafs *leafs) {
if((cpuinfo->features & CPUINFO_FEATURE_PAE) && leafs->ext8_valid) {
cpuinfo->maxphyaddr = leafs->ext8.eax & 0xff;
Expand All @@ -238,6 +322,11 @@ static void identify_maxphyaddr(cpuinfo_t *cpuinfo, const x86_cpuid_leafs *leafs
}
}

/**
* Log a string representation of the CPU feature flags
*
* @param cpuinfo CPU information structure
*/
static void dump_features(const cpuinfo_t *cpuinfo) {
char buffer[40];

Expand All @@ -256,6 +345,12 @@ static void dump_features(const cpuinfo_t *cpuinfo) {
info("CPU features:%s", buffer);
}

/**
* Return the name of the CPU vendor
*
* @param cpuinfo CPU information structure
* @return CPU vendor name string
*/
static const char *get_vendor_string(const cpuinfo_t *cpuinfo) {
switch(cpuinfo->vendor) {
case CPUINFO_VENDOR_AMD:
Expand All @@ -267,7 +362,12 @@ static const char *get_vendor_string(const cpuinfo_t *cpuinfo) {
}
}

static void dump_cpuinfo(const cpuinfo_t *cpuinfo) {
/**
* Log the contents of the CPU information structure
*
* @param cpuinfo CPU information structure
*/
static void dump_cpu_features(const cpuinfo_t *cpuinfo) {
info(
"CPU vendor: %s family: %u model: %u stepping: %u",
get_vendor_string(cpuinfo),
Expand All @@ -282,6 +382,9 @@ static void dump_cpuinfo(const cpuinfo_t *cpuinfo) {
info("CPU physical address size: %u bits", cpuinfo->maxphyaddr);
}

/**
* Detect the features of the bootstrap processor (BSP)
*/
void detect_cpu_features(void) {
check_cpuid_is_supported();

Expand All @@ -298,9 +401,14 @@ void detect_cpu_features(void) {

identify_maxphyaddr(&bsp_cpuinfo, &cpuid_leafs);

dump_cpuinfo(&bsp_cpuinfo);
dump_cpu_features(&bsp_cpuinfo);
}

/**
* Get the data cache alignment of the BSP
*
* @return data cache alignment in bytes
*/
unsigned int machine_get_cpu_dcache_alignment(void) {
return bsp_cpuinfo.dcache_alignment;
}
45 changes: 45 additions & 0 deletions kernel/infrastructure/i686/percpu.c
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,11 @@
#include <kernel/machine/tls.h>
#include <string.h>

/**
* Initialize the Task State Segment (TSS) in a per-CPU structure
*
* @param percpu per-CPU structure (OUT)
*/
static void initialize_tss(percpu_t *percpu) {
tss_t *tss = &percpu->tss;

Expand All @@ -56,6 +61,17 @@ static void initialize_tss(percpu_t *percpu) {
tss->iomap = TSS_LIMIT;
}

/**
* Initialize a Global Descriptor Table (GDT) entry for a code or data segment
*
* The type argument should be set to the bitwise OR of the following:
* - SEG_TYPE_CODE (code segment) or SEG_TYPE_DATA (data segment)
* - SEG_FLAG_KERNEL (kernel segment) or SEG_FLAG_USER (user segment)
*
* @param percpu per-CPU structure (OUT)
* @param index index of the GDT entry
* @param type type flags
*/
static void set_normal_segment(percpu_t *percpu, int index, int type) {
percpu->gdt[index] = SEG_DESCRIPTOR(
0,
Expand All @@ -64,6 +80,13 @@ static void set_normal_segment(percpu_t *percpu, int index, int type) {
);
}

/**
* Set the Thread-Local Storage (TLS) segment the GDT
*
* @param percpu per-CPU structure (OUT)
* @param addr address of the TLS
* @param size size of the TLS in bytes
*/
static void set_tls_segment(percpu_t *percpu, void *addr, size_t size) {
percpu->gdt[GDT_USER_TLS_DATA] = SEG_DESCRIPTOR(
addr,
Expand All @@ -72,6 +95,18 @@ static void set_tls_segment(percpu_t *percpu, void *addr, size_t size) {
);
}

/**
* Initialize the Global Descriptor Table (GDT) in a per-CPU structure
*
* Each CPU has its own GDT because of these segments:
* - The kernel per-CPU data segment (GDT_PER_CPU_DATA)
* - The TSS segment (GDT_TSS) which contains the kernel stack address of the
* thread currently running on the current CPU.
* - The thread local storage segment (GDT_USER_TLS_DATA) which represents the
* TLS of the thread currently running on the current CPU.
*
* @param percpu per-CPU structure (OUT)
*/
static void initialize_gdt(percpu_t *percpu) {
percpu->gdt[GDT_NULL] = SEG_DESCRIPTOR(0, 0, 0);

Expand Down Expand Up @@ -103,6 +138,11 @@ static void initialize_gdt(percpu_t *percpu) {
set_tls_segment(percpu, NULL, 0);
}

/**
* Initialize per-CPU data structure for the current CPU
*
* @param percpu per-CPU structure (OUT)
*/
void init_percpu_data(percpu_t *percpu) {
/* initialize with zeroes */
memset(percpu, '\0', sizeof(percpu_t));
Expand All @@ -114,6 +154,11 @@ void init_percpu_data(percpu_t *percpu) {
initialize_gdt(percpu);
}

/**
* Set the TLS segment for the currently running thread
*
* @param thread current thread
*/
void machine_set_thread_local_storage(const thread_t *thread) {
percpu_t *percpu = get_percpu_data();
set_tls_segment(percpu, thread->local_storage_addr, thread->local_storage_size);
Expand Down

0 comments on commit 05e151a

Please sign in to comment.