File indexing completed on 2025-05-11 08:24:10
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024
0025
0026
0027
0028
0029
0030
0031
0032
0033
0034
0035
0036 #include <acpi/acpi.h>
0037 #include <apic.h>
0038 #include <assert.h>
0039 #include <bsp.h>
0040 #include <pic.h>
0041 #include <rtems/score/idt.h>
0042
0043 extern void apic_spurious_handler(void);
0044
0045 volatile uint32_t* amd64_lapic_base;
0046
0047 #ifdef RTEMS_SMP
0048
0049 uint8_t amd64_lapic_to_cpu_map[xAPIC_MAX_APIC_ID + 1];
0050 static uint8_t cpu_to_lapic_map[xAPIC_MAX_APIC_ID + 1];
0051 static uint32_t lapic_count = 0;
0052 #endif
0053
0054
0055
0056
0057
0058
0059
0060
0061
0062
0063 static bool has_lapic_support(void)
0064 {
0065 uint32_t eax, ebx, ecx, edx;
0066 cpuid(1, &eax, &ebx, &ecx, &edx);
0067 return (edx >> 9) & 1;
0068 }
0069
0070
0071
0072
0073
0074
0075 static void madt_subtables_handler(ACPI_SUBTABLE_HEADER* entry)
0076 {
0077 switch (entry->Type) {
0078 #ifdef RTEMS_SMP
0079 case ACPI_MADT_TYPE_LOCAL_APIC:
0080 ACPI_MADT_LOCAL_APIC* lapic_entry = (ACPI_MADT_LOCAL_APIC*) entry;
0081
0082 if (lapic_count >= xAPIC_MAX_APIC_ID + 1 ||
0083 lapic_get_id() == lapic_entry->Id) {
0084 break;
0085 }
0086
0087 amd64_lapic_to_cpu_map[lapic_entry->Id] = (uint8_t) lapic_count;
0088 cpu_to_lapic_map[lapic_count++] = lapic_entry->Id;
0089 break;
0090 #endif
0091 case ACPI_MADT_TYPE_LOCAL_APIC_OVERRIDE:
0092 ACPI_MADT_LOCAL_APIC_OVERRIDE* lapic_override =
0093 (ACPI_MADT_LOCAL_APIC_OVERRIDE*) entry;
0094 amd64_lapic_base = (uint32_t*) lapic_override->Address;
0095 break;
0096 default:
0097 break;
0098 }
0099 }
0100
0101
0102
0103
0104
0105
0106 static bool parse_madt(void)
0107 {
0108 ACPI_STATUS status;
0109 ACPI_TABLE_MADT* madt;
0110
0111 status = AcpiGetTable(ACPI_SIG_MADT, 1, (ACPI_TABLE_HEADER**) &madt);
0112 if (status != (AE_OK)) {
0113 return false;
0114 }
0115
0116 #ifdef RTEMS_SMP
0117
0118 uint8_t lapic_id = lapic_get_id();
0119 amd64_lapic_to_cpu_map[lapic_id] = (uint8_t) lapic_count;
0120 cpu_to_lapic_map[lapic_count++] = lapic_id;
0121 #endif
0122
0123 amd64_lapic_base = (uint32_t*) ((uintptr_t) madt->Address);
0124 acpi_walk_subtables(
0125 (ACPI_TABLE_HEADER*) madt,
0126 sizeof(ACPI_TABLE_MADT),
0127 madt_subtables_handler
0128 );
0129
0130 return true;
0131 }
0132
0133
0134
0135
0136
0137
0138 static uint32_t lapic_timer_calc_ticks_per_sec(void)
0139 {
0140
0141 amd64_lapic_base[LAPIC_REGISTER_LVT_TIMER] = BSP_VECTOR_APIC_TIMER;
0142 amd64_lapic_base[LAPIC_REGISTER_TIMER_DIV] = LAPIC_TIMER_SELECT_DIVIDER;
0143
0144 uint8_t chan2_value;
0145 PIT_CHAN2_ENABLE(chan2_value);
0146
0147
0148
0149
0150
0151
0152
0153
0154
0155 rtems_interrupt_level level;
0156 rtems_interrupt_local_disable(level);
0157
0158 uint32_t pit_ticks = PIT_CALIBRATE_TICKS;
0159 PIT_CHAN2_WRITE_TICKS(pit_ticks);
0160
0161
0162 const uint32_t lapic_calibrate_init_count = 0xffffffff;
0163
0164 PIT_CHAN2_START_DELAY(chan2_value);
0165 amd64_lapic_base[LAPIC_REGISTER_TIMER_INITCNT] = lapic_calibrate_init_count;
0166
0167 PIT_CHAN2_WAIT_DELAY(pit_ticks);
0168 uint32_t lapic_currcnt = amd64_lapic_base[LAPIC_REGISTER_TIMER_CURRCNT];
0169
0170 DBG_PRINTF("PIT stopped at 0x%" PRIx32 "\n", pit_ticks);
0171
0172
0173 amd64_lapic_base[LAPIC_REGISTER_LVT_TIMER] = LAPIC_LVT_MASK;
0174
0175
0176 uint32_t lapic_ticks_per_sec = lapic_calibrate_init_count - lapic_currcnt;
0177
0178 DBG_PRINTF(
0179 "APIC ticks passed in 1/%d of a second: 0x%" PRIx32 "\n",
0180 PIT_CALIBRATE_DIVIDER,
0181 lapic_ticks_per_sec
0182 );
0183
0184
0185 lapic_ticks_per_sec = lapic_ticks_per_sec * PIT_CALIBRATE_DIVIDER;
0186
0187
0188 rtems_interrupt_local_enable(level);
0189
0190
0191 assert(lapic_ticks_per_sec != 0 &&
0192 lapic_ticks_per_sec != lapic_calibrate_init_count);
0193
0194 DBG_PRINTF(
0195 "CPU frequency: 0x%" PRIu64 "\nAPIC ticks/sec: 0x%" PRIu32 "\n",
0196
0197 (uint64_t) lapic_ticks_per_sec * LAPIC_TIMER_DIVIDE_VALUE,
0198 lapic_ticks_per_sec
0199 );
0200
0201 return lapic_ticks_per_sec;
0202 }
0203
0204 #ifdef RTEMS_SMP
0205
0206
0207
0208
0209
0210
0211 static void send_ipi(uint8_t dest_id, uint32_t icr_low)
0212 {
0213 amd64_lapic_base[LAPIC_REGISTER_ICR_HIGH] =
0214 (amd64_lapic_base[LAPIC_REGISTER_ICR_HIGH] & LAPIC_ICR_HIGH_MASK) | (dest_id << 24);
0215
0216 amd64_lapic_base[LAPIC_REGISTER_ICR_LOW] =
0217 (amd64_lapic_base[LAPIC_REGISTER_ICR_LOW] & LAPIC_ICR_LOW_MASK) | icr_low;
0218 }
0219
0220 static void wait_ipi(void)
0221 {
0222 while (amd64_lapic_base[LAPIC_REGISTER_ICR_LOW] & LAPIC_ICR_DELIV_STAT_PEND) {
0223 amd64_spinwait();
0224 }
0225 }
0226 #endif
0227
0228 bool lapic_initialize(void)
0229 {
0230 if (has_lapic_support() == false || parse_madt() == false) {
0231 return false;
0232 }
0233
0234
0235 uint64_t apic_base_msr = rdmsr(APIC_BASE_MSR);
0236 wrmsr(
0237 APIC_BASE_MSR,
0238 apic_base_msr | APIC_BASE_MSR_ENABLE,
0239 apic_base_msr >> 32
0240 );
0241
0242 DBG_PRINTF("APIC is at 0x%" PRIxPTR "\n", (uintptr_t) amd64_lapic_base);
0243 DBG_PRINTF(
0244 "APIC ID at *0x%" PRIxPTR "=0x%" PRIx32 "\n",
0245 (uintptr_t) &amd64_lapic_base[LAPIC_REGISTER_ID],
0246 amd64_lapic_base[LAPIC_REGISTER_ID]
0247 );
0248
0249 DBG_PRINTF(
0250 "APIC spurious vector register *0x%" PRIxPTR "=0x%" PRIx32 "\n",
0251 (uintptr_t) &amd64_lapic_base[LAPIC_REGISTER_SPURIOUS],
0252 amd64_lapic_base[LAPIC_REGISTER_SPURIOUS]
0253 );
0254
0255
0256
0257
0258 uintptr_t old;
0259 amd64_install_raw_interrupt(
0260 BSP_VECTOR_SPURIOUS,
0261 (uintptr_t) apic_spurious_handler,
0262 &old
0263 );
0264 amd64_lapic_base[LAPIC_REGISTER_SPURIOUS] =
0265 LAPIC_SPURIOUS_ENABLE | BSP_VECTOR_SPURIOUS;
0266
0267 DBG_PRINTF(
0268 "APIC spurious vector register *0x%" PRIxPTR "=0x%" PRIx32 "\n",
0269 (uintptr_t) &amd64_lapic_base[LAPIC_REGISTER_SPURIOUS],
0270 amd64_lapic_base[LAPIC_REGISTER_SPURIOUS]
0271 );
0272
0273
0274
0275
0276
0277 pic_remap(PIC1_REMAP_DEST, PIC2_REMAP_DEST);
0278 pic_disable();
0279
0280 return true;
0281 }
0282
0283 uint32_t lapic_timer_calc_ticks(uint64_t desired_freq_hz)
0284 {
0285 uint32_t lapic_ticks_per_sec = 0;
0286 uint64_t lapic_tick_total = 0;
0287 for (uint32_t i = 0; i < LAPIC_TIMER_NUM_CALIBRATIONS; i++) {
0288 lapic_tick_total += lapic_timer_calc_ticks_per_sec();
0289 }
0290 lapic_ticks_per_sec = lapic_tick_total / LAPIC_TIMER_NUM_CALIBRATIONS;
0291
0292
0293
0294
0295
0296
0297
0298
0299
0300
0301
0302 return lapic_ticks_per_sec / desired_freq_hz;
0303 }
0304
0305 void lapic_timer_enable(uint32_t reload_value)
0306 {
0307 amd64_lapic_base[LAPIC_REGISTER_LVT_TIMER] = BSP_VECTOR_APIC_TIMER | LAPIC_SELECT_TMR_PERIODIC;
0308 amd64_lapic_base[LAPIC_REGISTER_TIMER_DIV] = LAPIC_TIMER_SELECT_DIVIDER;
0309 amd64_lapic_base[LAPIC_REGISTER_TIMER_INITCNT] = reload_value;
0310 }
0311
0312 #ifdef RTEMS_SMP
0313 uint32_t lapic_get_num_of_procesors(void)
0314 {
0315 return lapic_count;
0316 }
0317
0318 void lapic_send_ipi(uint32_t target_cpu_index, uint8_t isr_vector)
0319 {
0320 uint8_t target_lapic_id = cpu_to_lapic_map[target_cpu_index];
0321 send_ipi(target_lapic_id, isr_vector);
0322 wait_ipi();
0323 }
0324
0325
0326
0327
0328
0329 void lapic_start_ap(uint32_t cpu_index, uint8_t page_vector)
0330 {
0331 if (cpu_index >= lapic_count) {
0332 return;
0333 }
0334
0335 uint8_t lapic_id = cpu_to_lapic_map[cpu_index];
0336
0337 uint8_t chan2_value;
0338 PIT_CHAN2_ENABLE(chan2_value);
0339 uint32_t pit_ticks = PIT_FREQUENCY/100;
0340 PIT_CHAN2_WRITE_TICKS(pit_ticks);
0341
0342
0343 send_ipi(lapic_id, LAPIC_ICR_DELIV_INIT | LAPIC_ICR_ASSERT | LAPIC_ICR_TRIG_LEVEL);
0344 wait_ipi();
0345
0346 send_ipi(lapic_id, LAPIC_ICR_DELIV_INIT | LAPIC_ICR_TRIG_LEVEL);
0347
0348 PIT_CHAN2_START_DELAY(chan2_value);
0349 PIT_CHAN2_WAIT_DELAY(pit_ticks);
0350
0351 pit_ticks = PIT_FREQUENCY/5000;
0352 PIT_CHAN2_WRITE_TICKS(pit_ticks);
0353
0354
0355 send_ipi(lapic_id, LAPIC_ICR_DELIV_START | page_vector);
0356 wait_ipi();
0357
0358 PIT_CHAN2_START_DELAY(chan2_value);
0359 PIT_CHAN2_WAIT_DELAY(pit_ticks);
0360
0361
0362
0363
0364 send_ipi(lapic_id, LAPIC_ICR_DELIV_START | page_vector);
0365 }
0366 #endif