// SPDX-License-Identifier: MPL-2.0 #include "cpu/ap.h" #include "devs/apic/lapic.h" #include "devs/input/kbd.h" #include "memory/memory.h" #include "kernel/log.h" #include "std/stdlib.h" sh_ap_AP_BOOTSTRAP *ap_bootstrap_struct=(sh_ap_AP_BOOTSTRAP*)SH_AP_BOOTSTRAP_PA; sh_uint8 *is_ap_started=SH_NULLPTR; static sh_ap_CPU_STRUCT bsp_cpu_struct; static sh_ap_PER_CPU bsp_per_cpu; SH_STATUS sh_ap_load_gdt_32() { if (sh_page_is_allocated((sh_uint8*)sh_page_get_physical_bitmap_ptr(),SH_AP_GDT_32_PA)) return SH_STATUS_OUT_OF_MEMORY; SH_STATUS status=sh_memory_identity_map(SH_AP_GDT_32_PA,1,SH_PAGE_RW | SH_PAGE_PRESENT | SH_PAGE_NX); if (sh_status_error(status)) return status; sh_gdt_GDT_32 *gdt_32=(sh_gdt_GDT_32*)(sh_uint8*)SH_AP_GDT_32_PA; status=sh_gdt_fill_gdt_32(gdt_32); if (sh_status_error(status)) return status; return SH_STATUS_SUCCESS; } SH_STATUS sh_ap_prepare_for_smp_launch(sh_lapic_DEVICE **lapic_dev_array,sh_uint64 max_lapic_id,sh_uint64 expected_lapic_found,sh_conf_BOOT_CONFIG *boot_config,sh_idt_IDT *idt) { if (lapic_dev_array==SH_NULLPTR || expected_lapic_found==0 || max_lapic_id>255) return SH_STATUS_INVALID_PARAMETER; SH_STATUS status=sh_memory_identity_map(SH_AP_BOOTSTRAP_PA,1,SH_PAGE_PRESENT | SH_PAGE_RW | SH_PAGE_NX); if (sh_status_error(status)) return status; sh_ap_AP_BOOTSTRAP *ap_bootstrap=(sh_ap_AP_BOOTSTRAP*)(sh_uint8*)SH_AP_BOOTSTRAP_PA; ap_bootstrap->c_entry_point_va=(sh_uint64)&sh_ap_entry_point; ap_bootstrap->page_table_pa=boot_config->page_table_pool_pa; sh_int16 current_lapic_id=sh_lapic_get_current_core(); if (current_lapic_id<0) return SH_STATUS_INVALID_STATE; sh_lapic_DEVICE *lapic_device_default=SH_NULLPTR; sh_uint64 lapic_found=0; for (sh_iter64 i=0;ilapic_base_pa=(sh_uint64)(sh_uint8*)lapic_device_default->base; sh_uint8 *cpu_struct_base_ptr=sh_malloc(sizeof(sh_ap_CPU_STRUCT)*(max_lapic_id+1)); if (!cpu_struct_base_ptr) return SH_STATUS_ERROR_NULLPTR_RETURNED; sh_ap_CPU_STRUCT *cpu_struct_base=(sh_ap_CPU_STRUCT*)cpu_struct_base_ptr; ap_bootstrap->cpu_struct_base_area=(sh_uint64)cpu_struct_base_ptr; sh_uint8 *tss_array_ptr=sh_malloc(sizeof(sh_tss_TSS)*(lapic_found-1)); sh_tss_TSS *tss_array=(sh_tss_TSS*)tss_array_ptr; sh_uint64 cpu_count=0; sh_uint64 cpu_index=1; for (sh_iter64 i=0;iapic_id==current_lapic_id) continue; sh_uint8 *c_entry_point_stack=sh_malloc(64*SH_PAGE_SIZE); if (!c_entry_point_stack) return SH_STATUS_ERROR_NULLPTR_RETURNED; cpu_struct_base[i].c_entry_point_stack_top_va=(sh_uint64)c_entry_point_stack+64*SH_PAGE_SIZE; cpu_struct_base[i].lapic_id=lapic_dev->apic_id; status=sh_tss_fill_tss(&tss_array[cpu_count]); if (sh_status_error(status)) return status; cpu_struct_base[i].tss_selector=(sh_uint16)(0x28+cpu_count*sizeof(sh_gdt_GDT_ENTRY_128)); cpu_struct_base[i].per_cpu=(sh_ap_PER_CPU*)sh_malloc(sizeof(sh_ap_PER_CPU)); if (!cpu_struct_base[i].per_cpu) return SH_STATUS_ERROR_NULLPTR_RETURNED; cpu_struct_base[i].per_cpu->cpu_id=cpu_index; cpu_struct_base[i].per_cpu->bytes_outputed=0; cpu_struct_base[i].per_cpu->timer_state=SH_FALSE; cpu_struct_base[i].per_cpu->temp_buffer=sh_malloc(256); if (!cpu_struct_base[i].per_cpu->temp_buffer) return SH_STATUS_ERROR_NULLPTR_RETURNED; cpu_struct_base[i].per_cpu->temp_buffer_size=256; cpu_count++; cpu_index++; } sh_uint8 *global_gdt_ptr=sh_malloc(sizeof(sh_gdt_GDT_AP)); sh_gdt_GDT_AP *global_gdt=(sh_gdt_GDT_AP*)global_gdt_ptr; status=sh_gdt_fill_gdt_ap(tss_array,cpu_count,global_gdt); if (sh_status_error(status)) return status; ap_bootstrap->shared_gdt_64_va=(sh_uint64)global_gdt; ap_bootstrap->gdt_64_gdtr=sh_gdt_make_gdtr_ap(global_gdt); ap_bootstrap->idt=idt; sh_smp_set_cpu_count((sh_int16)cpu_index); is_ap_started=sh_malloc(cpu_index); if (!is_ap_started) return SH_STATUS_ERROR_NULLPTR_RETURNED; sh_mem_set_8(is_ap_started,SH_AP_STATE_PENDING,cpu_index); return SH_STATUS_SUCCESS; } void sh_ap_entry_point() { sh_lapic_DEVICE *lapic_dev=sh_lapic_get_dev_apic_id(sh_smp_gs_base()->lapic_id); if (!lapic_dev) { sh_print(SH_FATAL,"Couldn't obtain LAPIC of this AP."); is_ap_started[sh_smp_gs_base()->per_cpu->cpu_id]=SH_AP_STATE_NO_LAPIC; while (SH_TRUE) {}; } SH_STATUS status=sh_lapic_init_dev(0xFF,lapic_dev); if (sh_status_error(status)) { sh_print(SH_FATAL,"Couldn't initialize LAPIC."); is_ap_started[sh_smp_gs_base()->per_cpu->cpu_id]=SH_AP_STATE_NO_LAPIC; while (SH_TRUE) {}; } sh_idt_load_idtr(ap_bootstrap_struct->idt); sh_asm_sti(); sh_printf(SH_LOG,"Thread with lapic_id=%4u and cpu_id=%8u successfully reached C entry point.\n",sh_smp_gs_base()->lapic_id,sh_smp_gs_base()->per_cpu->cpu_id); sh_mb(); is_ap_started[sh_smp_gs_base()->per_cpu->cpu_id]=SH_AP_STATE_OK; sh_mb(); while (SH_TRUE) {}; } SH_STATUS sh_ap_start_ap_boot_procedure(sh_conf_BOOT_CONFIG *boot_config) { SH_STATUS status=sh_memory_identity_map(SH_AP_AP_TRAMPOLINE,1,SH_PAGE_RW | SH_PAGE_PRESENT); if (sh_status_error(status)) return status; sh_mem_copy((sh_uint8*)SH_AP_AP_TRAMPOLINE,(sh_uint8*)SH_AP_TRAMPOLINE_PAYLOAD,4096); sh_lapic_DEVICE *lapic_dev=sh_lapic_get_dev_apic_id((sh_uint64)sh_lapic_get_current_core()); if (lapic_dev==SH_NULLPTR) return SH_STATUS_ERROR_NULLPTR_RETURNED; bsp_cpu_struct.c_entry_point_stack_top_va=0; bsp_cpu_struct.lapic_id=(sh_uint32)sh_lapic_get_current_core(); bsp_cpu_struct.tss_selector=0; bsp_per_cpu.cpu_id=0; bsp_per_cpu.bytes_outputed=0; bsp_per_cpu.timer_state=SH_FALSE; bsp_per_cpu.temp_buffer=sh_malloc(256); if (!bsp_per_cpu.temp_buffer) return SH_STATUS_ERROR_NULLPTR_RETURNED; bsp_per_cpu.temp_buffer_size=256; bsp_cpu_struct.per_cpu=(&bsp_per_cpu); sh_smp_write_gs_base((sh_uint64)&bsp_cpu_struct); is_ap_started[sh_smp_gs_base()->per_cpu->cpu_id]=SH_AP_STATE_OK; sh_log_debug("Trying sending INIT IPI...",SH_LOG_SOURCE_SMP); status=sh_lapic_send_ipi(lapic_dev,SH_LAPIC_IPI_TYPE_INIT,SH_LAPIC_IPI_DESTINATION_ALL_EXCLUDING_SELF,SH_LAPIC_IPI_NO_DESTINATION,0); if (sh_status_error(status)) return status; sh_log_debug("Sent INIT IPI. Waiting 10 ms.",SH_LOG_SOURCE_SMP); status=sh_lapic_timer_one_shot_us(lapic_dev,10000); if (sh_status_error(status)) return status; sh_log_debug("Trying sending first SIPI...",SH_LOG_SOURCE_SMP); status=sh_print_setup_ring_buffers_per_ap(boot_config); if (sh_status_error(status)) return status; status=sh_lapic_send_ipi(lapic_dev,SH_LAPIC_IPI_TYPE_STARTUP,SH_LAPIC_IPI_DESTINATION_ALL_EXCLUDING_SELF,SH_LAPIC_IPI_NO_DESTINATION,SH_AP_AP_TRAMPOLINE); if (sh_status_error(status)) return status; sh_log_disable_global_logging_ring(); sh_print(SH_DEBUG,"Sent first SIPI.\n"); while (SH_TRUE) { sh_mb(); sh_int16 cpu_good=0; for (sh_int16 i=0;i