HV:treewide:C99-friendly per_cpu implementation change the per_cpu method

The current implementation of per_cpu relies on several non-c99 features,
and in additional involves arbitrary pointer arithmetic which is not MIS-
RA C friendly.

This patch introduces struct per_cpu_region which holds all the per_cpu
variables. Allocation of per_cpu data regions and access to per_cpu vari-
ables are greatly simplified, at the cost of making all per_cpu varaibl-
es accessible in files.

Signed-off-by: Huihuang Shi <huihuang.shi@intel.com>
This commit is contained in:
Huihuang Shi
2018-06-05 15:25:07 +08:00
committed by lijinxia
parent cbb692d910
commit e591315a65
20 changed files with 95 additions and 130 deletions

View File

@@ -161,68 +161,33 @@ extern uint8_t _ld_cpu_secondary_reset_start[];
extern const uint64_t _ld_cpu_secondary_reset_size;
extern uint8_t _ld_bss_start[];
extern uint8_t _ld_bss_end[];
extern uint8_t _ld_cpu_data_start[];
extern uint8_t _ld_cpu_data_end[];
extern int ibrs_type;
/*
* To support per_cpu access, we use a special section ".cpu_data" to define
* To support per_cpu access, we use a special struct "per_cpu_region" to hold
* the pattern of per CPU data. And we allocate memory for per CPU data
* according to multiple this section size and pcpu number.
* according to multiple this struct size and pcpu number.
*
* +------------------+------------------+---+------------------+
* | percpu for pcpu0 | percpu for pcpu1 |...| percpu for pcpuX |
* +------------------+------------------+---+------------------+
* ^ ^
* | |
* --.cpu_data size--
* +-------------------+------------------+---+------------------+
* | percpu for pcpu0 | percpu for pcpu1 |...| percpu for pcpuX |
* +-------------------+------------------+---+------------------+
* ^ ^
* | |
* <per_cpu_region size>
*
* To access per cpu data, we use:
* per_cpu_data_base_ptr + curr_pcpu_id * cpu_data_section_size +
* offset_of_symbol_in_cpu_data_section
* per_cpu_base_ptr + sizeof(struct per_cpu_region) * curr_pcpu_id
* + offset_of_member_per_cpu_region
* to locate the per cpu data.
*/
/* declare per cpu data */
#define EXTERN_CPU_DATA(type, name) \
extern __typeof__(type) cpu_data_##name
EXTERN_CPU_DATA(uint8_t, lapic_id);
EXTERN_CPU_DATA(void *, vcpu);
EXTERN_CPU_DATA(uint8_t[STACK_SIZE], stack) __aligned(16);
/* define per cpu data */
#define DEFINE_CPU_DATA(type, name) \
__typeof__(type) cpu_data_##name \
__attribute__((__section__(".cpu_data")))
extern void *per_cpu_data_base_ptr;
extern int phy_cpu_num;
extern uint64_t pcpu_active_bitmap;
#define PER_CPU_DATA_OFFSET(sym_addr) \
((uint64_t)(sym_addr) - (uint64_t)(_ld_cpu_data_start))
#define PER_CPU_DATA_SIZE \
((uint64_t)_ld_cpu_data_end - (uint64_t)(_ld_cpu_data_start))
/*
* get percpu data for pcpu_id.
*
* It returns:
* per_cpu_data_##name[pcpu_id];
*/
#define per_cpu(name, pcpu_id) \
(*({ uint64_t base = (uint64_t)per_cpu_data_base_ptr; \
uint64_t off = PER_CPU_DATA_OFFSET(&cpu_data_##name); \
((typeof(&cpu_data_##name))(base + \
(pcpu_id) * PER_CPU_DATA_SIZE + off)); \
}))
/* get percpu data for current pcpu */
#define get_cpu_var(name) per_cpu(name, get_cpu_id())
/* CPUID feature words */
enum feature_word {
FEAT_1_ECX = 0, /* CPUID[1].ECX */
@@ -254,6 +219,13 @@ struct cpuinfo_x86 {
char model_name[64];
struct cpu_state_info state_info;
};
#ifdef STACK_PROTECTOR
struct stack_canary {
/* Gcc generates extra code, using [fs:40] to access canary */
uint8_t reserved[40];
uint64_t canary;
};
#endif
extern struct cpuinfo_x86 boot_cpu_data;

View File

@@ -279,12 +279,6 @@ extern struct host_gdt HOST_GDT;
extern struct host_gdt_descriptor HOST_GDTR;
void load_gdtr_and_tr(void);
EXTERN_CPU_DATA(struct tss_64, tss);
EXTERN_CPU_DATA(struct host_gdt, gdt);
EXTERN_CPU_DATA(uint8_t[STACK_SIZE], mc_stack) __aligned(16);
EXTERN_CPU_DATA(uint8_t[STACK_SIZE], df_stack) __aligned(16);
EXTERN_CPU_DATA(uint8_t[STACK_SIZE], sf_stack) __aligned(16);
#endif /* end #ifndef ASSEMBLER */
#endif /* GDT_H */

View File

@@ -0,0 +1,52 @@
#ifndef PER_CPU_H
#define PER_CPU_H
#include <hypervisor.h>
#include <bsp_extern.h>
#include <schedule.h>
#include <version.h>
#include <irq.h>
#include <sbuf.h>
#include <gdt.h>
#include <timer.h>
#include <logmsg.h>
#include "arch/x86/guest/instr_emul_wrapper.h"
struct per_cpu_region {
uint64_t *sbuf[ACRN_SBUF_ID_MAX];
uint64_t irq_count[NR_MAX_IRQS];
uint64_t vmexit_cnt[64];
uint64_t vmexit_time[64];
uint64_t softirq_pending;
uint64_t spurious;
struct dev_handler_node *timer_node;
struct shared_buf *earlylog_sbuf;
void *vcpu;
#ifdef STACK_PROTECTOR
struct stack_canary stack_canary;
#endif
struct per_cpu_timers cpu_timers;
struct sched_context sched_ctx;
struct emul_cnx g_inst_ctxt;
struct host_gdt gdt;
struct tss_64 tss;
int state;
uint8_t mc_stack[STACK_SIZE] __aligned(16);
uint8_t df_stack[STACK_SIZE] __aligned(16);
uint8_t sf_stack[STACK_SIZE] __aligned(16);
uint8_t stack[STACK_SIZE] __aligned(16);
char logbuf[LOG_MESSAGE_MAX_SIZE];
uint8_t lapic_id;
} __aligned(CPU_PAGE_SIZE); //per_cpu_region size aligned with CPU_PAGE_SIZE
extern struct per_cpu_region *per_cpu_data_base_ptr;
extern int phy_cpu_num;
extern uint64_t pcpu_active_bitmap;
/*
* get percpu data for pcpu_id.
*/
#define per_cpu(name, pcpu_id) \
(per_cpu_data_base_ptr[pcpu_id].name)
/* get percpu data for current pcpu */
#define get_cpu_var(name) per_cpu(name, get_cpu_id())
#endif

View File

@@ -14,6 +14,9 @@ enum tick_mode {
TICK_MODE_PERIODIC,
};
struct per_cpu_timers {
struct list_head timer_list; /* it's for runtime active timer list */
};
struct timer {
struct list_head node; /* link all timers */