Applied, thanks! Damien Zammit, le mar. 31 janv. 2023 09:35:21 +0000, a ecrit: > Also-by: Almudena Garcia <[email protected]> > --- > i386/i386/apic.c | 87 ++++++++++++++++++++++++++++++--- > i386/i386/apic.h | 114 ++++++++++++++++++++++++++++++++++++++++--- > i386/i386/smp.c | 89 ++++++++++++++++++++++++++++++++- > i386/i386/smp.h | 7 +++ > i386/i386at/ioapic.c | 97 ++++++++++-------------------------- > 5 files changed, 307 insertions(+), 87 deletions(-) > > diff --git a/i386/i386/apic.c b/i386/i386/apic.c > index d30084e2..e53d4749 100644 > --- a/i386/i386/apic.c > +++ b/i386/i386/apic.c > @@ -19,6 +19,8 @@ > Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. */ > > #include <i386/apic.h> > +#include <i386/cpu.h> > +#include <i386at/idt.h> > #include <string.h> > #include <vm/vm_kern.h> > #include <kern/printf.h> > @@ -112,7 +114,7 @@ acpi_get_irq_override(uint8_t pin) > * apic_get_cpu_apic_id: returns the apic_id of a cpu. > * Receives as input the kernel ID of a CPU. > */ > -uint16_t > +int > apic_get_cpu_apic_id(int kernel_id) > { > if (kernel_id >= NCPUS) > @@ -121,6 +123,24 @@ apic_get_cpu_apic_id(int kernel_id) > return apic_data.cpu_lapic_list[kernel_id]; > } > > + > +/* > + * apic_get_cpu_kernel_id: returns the kernel_id of a cpu. > + * Receives as input the APIC ID of a CPU. > + */ > +int > +apic_get_cpu_kernel_id(uint16_t apic_id) > +{ > + int i; > + > + for (i = 0; i < apic_data.ncpus; i++) { > + if (apic_data.cpu_lapic_list[i] == apic_id) > + return i; > + } > + > + return -1; > +} > + > /* apic_get_lapic: returns a reference to the common memory address for > Local APIC. */ > volatile ApicLocalUnit* > apic_get_lapic(void) > @@ -158,17 +178,13 @@ apic_get_num_ioapics(void) > /* > * apic_get_current_cpu: returns the apic_id of current cpu. > */ > -uint16_t > +int > apic_get_current_cpu(void) > { > - uint16_t apic_id; > - > if(lapic == NULL) > - apic_id = 0; > - else > - apic_id = lapic->apic_id.r; > + return -1; > > - return apic_id; > + return (lapic->apic_id.r >> 24) & 0xff; > } > > > @@ -235,6 +251,61 @@ void apic_print_info(void) > } > } > > +void apic_send_ipi(unsigned dest_shorthand, unsigned deliv_mode, unsigned > dest_mode, unsigned level, unsigned trig_mode, unsigned vector, unsigned > dest_id) > +{ > + IcrLReg icrl_values; > + IcrHReg icrh_values; > + > + icrl_values.destination_shorthand = dest_shorthand; > + icrl_values.delivery_mode = deliv_mode; > + icrl_values.destination_mode = dest_mode; > + icrl_values.level = level; > + icrl_values.trigger_mode = trig_mode; > + icrl_values.vector = vector; > + icrh_values.destination_field = dest_id; > + > + lapic->icr_high = icrh_values; > + lapic->icr_low = icrl_values; > +} > + > +void > +lapic_enable(void) > +{ > + unsigned long flags; > + int apic_id; > + volatile uint32_t dummy; > + > + cpu_intr_save(&flags); > + > + apic_id = apic_get_current_cpu(); > + > + dummy = lapic->dest_format.r; > + lapic->dest_format.r = 0xffffffff; /* flat model */ > + dummy = lapic->logical_dest.r; > + lapic->logical_dest.r = lapic->apic_id.r; /* target self */ > + dummy = lapic->lvt_lint0.r; > + lapic->lvt_lint0.r = dummy | LAPIC_DISABLE; > + dummy = lapic->lvt_lint1.r; > + lapic->lvt_lint1.r = dummy | LAPIC_DISABLE; > + dummy = lapic->lvt_performance_monitor.r; > + lapic->lvt_performance_monitor.r = dummy | LAPIC_DISABLE; > + if (apic_id != 0) > + { > + dummy = lapic->lvt_timer.r; > + lapic->lvt_timer.r = dummy | LAPIC_DISABLE; > + } > + dummy = lapic->task_pri.r; > + lapic->task_pri.r = 0; > + > + /* Enable LAPIC to send or recieve IPI/SIPIs */ > + dummy = lapic->spurious_vector.r; > + lapic->spurious_vector.r = dummy | LAPIC_ENABLE; > + > + lapic->error_status.r = 0; > + > + cpu_intr_restore(flags); > +} > + > void > lapic_eoi(void) > { > diff --git a/i386/i386/apic.h b/i386/i386/apic.h > index 0bb1bd73..ac083d26 100644 > --- a/i386/i386/apic.h > +++ b/i386/i386/apic.h > @@ -61,10 +61,99 @@ union ioapic_route_entry_union { > struct ioapic_route_entry both; > }; > > + > +/* Grateful to trasterlabs for this snippet */ > + > +typedef union u_icr_low > +{ > + uint32_t value[4]; > + struct > + { > + uint32_t r; // FEE0 0300H - 4 bytes > + unsigned :32; // FEE0 0304H > + unsigned :32; // FEE0 0308H > + unsigned :32; // FEE0 030CH > + }; > + struct > + { > + unsigned vector: 8; /* Vector of interrupt. Lowest 8 bits of routine > address */ > + unsigned delivery_mode : 3; > + unsigned destination_mode: 1; > + unsigned delivery_status: 1; > + unsigned :1; > + unsigned level: 1; > + unsigned trigger_mode: 1; > + unsigned :2; > + unsigned destination_shorthand: 2; > + unsigned :12; > + }; > +} IcrLReg; > + > +typedef union u_icr_high > +{ > + uint32_t value[4]; > + struct > + { > + uint32_t r; // FEE0 0310H - 4 bytes > + unsigned :32; // FEE0 0314H > + unsigned :32; // FEE0 0318H > + unsigned :32; // FEE0 031CH > + }; > + struct > + { > + unsigned :24; // FEE0 0310H - 4 bytes > + unsigned destination_field :8; /* APIC ID (in physical mode) or MDA > (in logical) of destination processor */ > + }; > +} IcrHReg; > + > + > +typedef enum e_icr_dest_shorthand > +{ > + NO_SHORTHAND = 0, > + SELF = 1, > + ALL_INCLUDING_SELF = 2, > + ALL_EXCLUDING_SELF = 3 > +} icr_dest_shorthand; > + > +typedef enum e_icr_deliv_mode > +{ > + FIXED = 0, > + LOWEST_PRIORITY = 1, > + SMI = 2, > + NMI = 4, > + INIT = 5, > + STARTUP = 6, > +} icr_deliv_mode; > + > +typedef enum e_icr_dest_mode > +{ > + PHYSICAL = 0, > + LOGICAL = 1 > +} icr_dest_mode; > + > +typedef enum e_icr_deliv_status > +{ > + IDLE = 0, > + SEND_PENDING = 1 > +} icr_deliv_status; > + > +typedef enum e_icr_level > +{ > + DE_ASSERT = 0, > + ASSERT = 1 > +} icr_level; > + > +typedef enum e_irc_trigger_mode > +{ > + EDGE = 0, > + LEVEL = 1 > +} irc_trigger_mode; > + > + > typedef struct ApicLocalUnit { > ApicReg reserved0; /* 0x000 */ > ApicReg reserved1; /* 0x010 */ > - ApicReg apic_id; /* 0x020 */ > + ApicReg apic_id; /* 0x020. Hardware ID of current > processor */ > ApicReg version; /* 0x030 */ > ApicReg reserved4; /* 0x040 */ > ApicReg reserved5; /* 0x050 */ > @@ -84,8 +173,8 @@ typedef struct ApicLocalUnit { > ApicReg error_status; /* 0x280 */ > ApicReg reserved28[6]; /* 0x290 */ > ApicReg lvt_cmci; /* 0x2f0 */ > - ApicReg icr_low; /* 0x300 */ > - ApicReg icr_high; /* 0x310 */ > + IcrLReg icr_low; /* 0x300. Store the information to > send an IPI (Inter-processor Interrupt) */ > + IcrHReg icr_high; /* 0x310. Store the IPI destination > */ > ApicReg lvt_timer; /* 0x320 */ > ApicReg lvt_thermal; /* 0x330 */ > ApicReg lvt_performance_monitor; /* 0x340 */ > @@ -138,24 +227,27 @@ void apic_add_cpu(uint16_t apic_id); > void apic_lapic_init(ApicLocalUnit* lapic_ptr); > void apic_add_ioapic(struct IoApicData); > void apic_add_irq_override(struct IrqOverrideData irq_over); > +void apic_send_ipi(unsigned dest_shorthand, unsigned deliv_mode, unsigned > dest_mode, unsigned level, unsigned trig_mode, unsigned vector, unsigned > dest_id); > IrqOverrideData *acpi_get_irq_override(uint8_t gsi); > -uint16_t apic_get_cpu_apic_id(int kernel_id); > +int apic_get_cpu_apic_id(int kernel_id); > +int apic_get_cpu_kernel_id(uint16_t apic_id); > volatile ApicLocalUnit* apic_get_lapic(void); > struct IoApicData *apic_get_ioapic(int kernel_id); > uint8_t apic_get_numcpus(void); > uint8_t apic_get_num_ioapics(void); > -uint16_t apic_get_current_cpu(void); > +int apic_get_current_cpu(void); > void apic_print_info(void); > int apic_refit_cpulist(void); > void picdisable(void); > void lapic_eoi(void); > void ioapic_irq_eoi(int pin); > +void lapic_enable(void); > void lapic_enable_timer(void); > void ioapic_mask_irqs(void); > void ioapic_toggle(int pin, int mask); > void ioapic_configure(void); > > -extern int timer_pin; > +extern int duplicate_pin; > extern void intnull(int unit); > extern volatile ApicLocalUnit* lapic; > > @@ -172,9 +264,13 @@ extern volatile ApicLocalUnit* lapic; > # define IMCR_USE_PIC 0 > # define IMCR_USE_APIC 1 > > +#define LAPIC_LOW_PRIO 0x100 > +#define LAPIC_NMI 0x400 > +#define LAPIC_EXTINT 0x700 > +#define LAPIC_LEVEL_TRIGGERED 0x8000 > + > #define LAPIC_ENABLE 0x100 > #define LAPIC_FOCUS 0x200 > -#define LAPIC_NMI 0x400 > #define LAPIC_ENABLE_DIRECTED_EOI 0x1000 > #define LAPIC_DISABLE 0x10000 > #define LAPIC_TIMER_PERIODIC 0x20000 > @@ -198,6 +294,10 @@ extern volatile ApicLocalUnit* lapic; > #define IOAPIC_MASK_ENABLED 0 > #define IOAPIC_MASK_DISABLED 1 > > +#define APIC_MSR 0x1b > +#define APIC_MSR_BSP 0x100 /* Processor is a BSP */ > +#define APIC_MSR_ENABLE 0x800 > + > /* Set or clear a bit in a 255-bit APIC mask register. > These registers are spread through eight 32-bit registers. */ > #define APIC_SET_MASK_BIT(reg, bit) \ > diff --git a/i386/i386/smp.c b/i386/i386/smp.c > index d7523a73..c351efaa 100644 > --- a/i386/i386/smp.c > +++ b/i386/i386/smp.c > @@ -18,11 +18,18 @@ > along with this program; if not, write to the Free Software > Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. */ > > -#include <i386/i386/apic.h> > -#include <i386/i386/smp.h> > +#include <i386/apic.h> > +#include <i386/smp.h> > +#include <i386/cpu.h> > +#include <i386/pit.h> > +#include <i386at/idt.h> > +#include <i386at/acpi_parse_apic.h> > +#include <kern/printf.h> > +#include <mach/machine.h> > > #include <kern/smp.h> > > +#define pause_memory asm volatile ("pause" : : : "memory") > > /* > * smp_data_init: initialize smp_data structure > @@ -33,6 +40,84 @@ static void smp_data_init(void) > { > uint8_t numcpus = apic_get_numcpus(); > smp_set_numcpus(numcpus); > + > + for(int i = 0; i < numcpus; i++){ > + machine_slot[i].is_cpu = TRUE; > + } > + > +} > + > +void smp_pmap_update(unsigned apic_id) > +{ > + unsigned long flags; > + > + cpu_intr_save(&flags); > + > + printf("Sending IPI(%u) to call TLB shootdown...", apic_id); > + apic_send_ipi(NO_SHORTHAND, FIXED, PHYSICAL, ASSERT, EDGE, > CALL_SINGLE_FUNCTION_BASE, apic_id); > + > + do { > + pause_memory; > + } while(lapic->icr_low.delivery_status == SEND_PENDING); > + > + printf("done\n"); > + > + cpu_intr_restore(flags); > +} > + > +/* See Intel IA32/64 Software Developer's Manual 3A Section 8.4.4.1 */ > +void smp_startup_cpu(unsigned apic_id, unsigned vector) > +{ > + /* Clear APIC errors */ > + lapic->error_status.r = 0; > + > + printf("Sending IPIs to APIC ID %u...", apic_id); > + > + /* Assert INIT IPI */ > + apic_send_ipi(NO_SHORTHAND, INIT, PHYSICAL, ASSERT, LEVEL, 0, apic_id); > + > + /* Wait for delivery */ > + do { > + pause_memory; > + } while(lapic->icr_low.delivery_status == SEND_PENDING); > + > + /* Deassert INIT IPI */ > + apic_send_ipi(NO_SHORTHAND, INIT, PHYSICAL, DE_ASSERT, LEVEL, 0, > apic_id); > + > + /* Wait for delivery */ > + do { > + pause_memory; > + } while(lapic->icr_low.delivery_status == SEND_PENDING); > + > + /* Wait 10 msec */ > + pit_mdelay(10); > + > + /* Clear APIC errors */ > + lapic->error_status.r = 0; > + > + /* First StartUp IPI */ > + apic_send_ipi(NO_SHORTHAND, STARTUP, PHYSICAL, ASSERT, LEVEL, vector >> > 12, apic_id); > + > + /* Wait 200 usec */ > + pit_udelay(200); > + > + /* Wait for delivery */ > + do { > + pause_memory; > + } while(lapic->icr_low.delivery_status == SEND_PENDING); > + > + /* Second StartUp IPI */ > + apic_send_ipi(NO_SHORTHAND, STARTUP, PHYSICAL, ASSERT, LEVEL, vector >> > 12, apic_id); > + > + /* Wait 200 usec */ > + pit_udelay(200); > + > + /* Wait for delivery */ > + do { > + pause_memory; > + } while(lapic->icr_low.delivery_status == SEND_PENDING); > + > + printf("done\n"); > } > > /* > diff --git a/i386/i386/smp.h b/i386/i386/smp.h > index b36ead08..79337022 100644 > --- a/i386/i386/smp.h > +++ b/i386/i386/smp.h > @@ -18,4 +18,11 @@ > along with this program; if not, write to the Free Software > Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. */ > > +#ifndef _SMP_H_ > +#define _SMP_H_ > + > int smp_init(void); > +void smp_pmap_update(unsigned apic_id); > +void smp_startup_cpu(unsigned apic_id, unsigned vector); > + > +#endif > diff --git a/i386/i386at/ioapic.c b/i386/i386at/ioapic.c > index c5eb3536..d4269ef0 100644 > --- a/i386/i386at/ioapic.c > +++ b/i386/i386at/ioapic.c > @@ -32,8 +32,7 @@ > #include <kern/printf.h> > > static int has_irq_specific_eoi = 1; /* FIXME: Assume all machines have this > */ > -static int timer_gsi; > -int timer_pin; > +int duplicate_pin; > > uint32_t lapic_timer_val = 0; > uint32_t calibrated_ticks = 0; > @@ -78,6 +77,7 @@ void > picdisable(void) > { > asm("cli"); > + curr_ipl = SPLHI; > > /* > ** Disable PIC > @@ -147,40 +147,13 @@ ioapic_toggle_entry(int apic, int pin, int mask) > ioapic_write(apic, APIC_IO_REDIR_LOW(pin), entry.lo); > } > > -static void > -cpu_rdmsr(uint32_t msr, uint32_t *lo, uint32_t *hi) > -{ > - __asm__ __volatile__("rdmsr" : "=a"(*lo), "=d"(*hi) : "c"(msr)); > -} > - > -static void > -cpu_wrmsr(uint32_t msr, uint32_t lo, uint32_t hi) > -{ > - __asm__ __volatile__("wrmsr" : : "a"(lo), "d"(hi), "c"(msr)); > -} > - > -static void > -global_enable_apic(void) > -{ > - uint32_t lo = 0; > - uint32_t hi = 0; > - uint32_t msr = 0x1b; > - > - cpu_rdmsr(msr, &lo, &hi); > - > - if (!(lo & (1 << 11))) { > - lo |= (1 << 11); > - cpu_wrmsr(msr, lo, hi); > - } > -} > - > static uint32_t > pit_measure_apic_hz(void) > { > uint32_t start = 0xffffffff; > > - /* Prepare accurate delay for 1/100 seconds */ > - pit_prepare_sleep(100); > + /* Prepare accurate delay for 1/hz seconds */ > + pit_prepare_sleep(hz); > > /* Set APIC timer */ > lapic->init_count.r = start; > @@ -189,7 +162,7 @@ pit_measure_apic_hz(void) > pit_sleep(); > > /* Stop APIC timer */ > - lapic->lvt_timer.r = LAPIC_DISABLE; > + lapic->lvt_timer.r |= LAPIC_DISABLE; > > return start - lapic->cur_count.r; > } > @@ -203,26 +176,18 @@ void lapic_update_timer(void) > void > lapic_enable_timer(void) > { > - spl_t s; > - > - s = sploff(); > - asm("cli"); > - > /* Set up counter */ > lapic->init_count.r = calibrated_ticks; > lapic->divider_config.r = LAPIC_TIMER_DIVIDE_16; > > /* Set the timer to interrupt periodically on remapped timer GSI */ > - lapic->lvt_timer.r = (IOAPIC_INT_BASE + timer_gsi) | > LAPIC_TIMER_PERIODIC; > + lapic->lvt_timer.r = IOAPIC_INT_BASE | LAPIC_TIMER_PERIODIC; > > /* Some buggy hardware requires this set again */ > lapic->divider_config.r = LAPIC_TIMER_DIVIDE_16; > > - /* Unmask the remapped timer pin and pin 0 always */ > - ioapic_toggle(0, IOAPIC_MASK_ENABLED); > - ioapic_toggle(timer_pin, IOAPIC_MASK_ENABLED); > - > - splon(s); > + /* Enable interrupts for the first time on BSP */ > + asm("sti"); > printf("LAPIC timer configured\n"); > } > > @@ -239,6 +204,9 @@ ioapic_irq_eoi(int pin) > int apic = 0; > union ioapic_route_entry_union oldentry, entry; > > + if (pin == 0) > + goto skip_specific_eoi; > + > if (!has_irq_specific_eoi) { > /* Workaround for old IOAPICs with no specific EOI */ > > @@ -258,6 +226,7 @@ ioapic_irq_eoi(int pin) > ioapic->eoi.r = entry.both.vector; > } > > +skip_specific_eoi: > lapic_eoi (); > } > > @@ -303,12 +272,12 @@ ioapic_configure(void) > /* Assume first IO APIC maps to GSI base 0 */ > int gsi, apic = 0, bsp = 0, pin; > IrqOverrideData *irq_over; > + int timer_gsi; > > /* Disable IOAPIC interrupts and set spurious interrupt */ > lapic->spurious_vector.r = IOAPIC_SPURIOUS_BASE; > > union ioapic_route_entry_union entry = {{0, 0}}; > - union ioapic_route_entry_union timer_entry = {{0, 0}}; > > entry.both.delvmode = IOAPIC_FIXED; > entry.both.destmode = IOAPIC_PHYSICAL; > @@ -332,16 +301,17 @@ ioapic_configure(void) > if (pin == 0) { > /* Save timer info */ > timer_gsi = gsi; > - timer_entry = entry; > } else { > - /* Get the actual timer pin by assuming that the pin > - * with duplicated gsi from pin 0 maps to the timer pin */ > + /* Disable duplicated timer gsi */ > if (gsi == timer_gsi) { > - timer_pin = pin; > - /* Remap pin 0 interrupt vector to GSI base > + duplicate_pin = pin; > + /* Remap this interrupt pin to GSI base > * so we don't duplicate vectors */ > - timer_entry.both.vector = IOAPIC_INT_BASE; > - ioapic_write_entry(apic, 0, timer_entry.both); > + entry.both.vector = IOAPIC_INT_BASE; > + ioapic_write_entry(apic, duplicate_pin, entry.both); > + /* Mask the ioapic pin with deduplicated vector as > + * we will never use it, since timer is on another gsi */ > + mask_irq(duplicate_pin); > } > } > } > @@ -361,16 +331,7 @@ ioapic_configure(void) > } > > /* Start the IO APIC receiving interrupts */ > - lapic->apic_id.r = apic_get_cpu_apic_id(bsp); > - lapic->dest_format.r = 0xffffffff; /* flat model */ > - lapic->logical_dest.r = 0x01000000; /* target bsp */ > - lapic->lvt_timer.r = LAPIC_DISABLE; > - lapic->lvt_performance_monitor.r = LAPIC_NMI; > - lapic->lvt_lint0.r = LAPIC_DISABLE; > - lapic->lvt_lint1.r = LAPIC_DISABLE; > - lapic->task_pri.r = 0; > - > - global_enable_apic(); > + lapic_enable(); > > /* Enable IOAPIC processor focus */ > lapic->spurious_vector.r |= LAPIC_FOCUS; > @@ -381,23 +342,19 @@ ioapic_configure(void) > lapic->spurious_vector.r |= LAPIC_ENABLE_DIRECTED_EOI; > } > > - /* Enable IOAPIC interrupts */ > - lapic->spurious_vector.r |= LAPIC_ENABLE; > - > /* Set one-shot timer */ > lapic->divider_config.r = LAPIC_TIMER_DIVIDE_16; > - lapic->lvt_timer.r = IOAPIC_INT_BASE + timer_gsi; > + lapic->lvt_timer.r = IOAPIC_INT_BASE; > > - /* Measure number of APIC timer ticks in 10ms */ > - calibrated_ticks = pit_measure_apic_hz(); > + /* Measure number of APIC timer ticks in 1/hz seconds > + * but calibrate the timer to expire at rate of hz */ > + calibrated_ticks = pit_measure_apic_hz() * hz; > > /* Set up counter later */ > lapic->lvt_timer.r = LAPIC_DISABLE; > > - /* Install clock interrupt handler on both remapped timer pin and pin 0 > - * since nobody knows how all x86 timers are wired up */ > + /* Install clock interrupt handler on pin 0 */ > ivect[0] = (interrupt_handler_fn)hardclock; > - ivect[timer_pin] = (interrupt_handler_fn)hardclock; > > printf("IOAPIC 0 configured\n"); > } > -- > 2.34.1 > > >
-- Samuel --- Pour une évaluation indépendante, transparente et rigoureuse ! Je soutiens la Commission d'Évaluation de l'Inria.
