You cannot select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
	
	
		
			83 lines
		
	
	
		
			2.5 KiB
		
	
	
	
		
			C++
		
	
			
		
		
	
	
			83 lines
		
	
	
		
			2.5 KiB
		
	
	
	
		
			C++
		
	
| #include "startup_ap.h"
 | |
| 
 | |
| #include "../arch/core_interrupt.h"
 | |
| #include "../arch/gdt.h"
 | |
| #include "../arch/lapic.h"
 | |
| #include "../arch/pit.h"
 | |
| #include "../debug/assert.h"
 | |
| #include "../debug/output.h"
 | |
| #include "../utils/size.h"
 | |
| #include "../utils/string.h"
 | |
| 
 | |
| namespace ApplicationProcessor {
 | |
| 
 | |
| // Make sure that the RELOCATED_SETUP is in low memory (< 1 MiB)
 | |
| static_assert((RELOCATED_SETUP & ~0x000ff000) == 0,
 | |
|               "Not a valid 1 MB address for RELOCATED_SETUP!");
 | |
| 
 | |
| /*! \brief Temporary Global Descriptor Table
 | |
|  *
 | |
|  * Blue print, to be copied into real mode code
 | |
|  */
 | |
| constinit GDT::SegmentDescriptor ap_gdt[] = {
 | |
|     // nullptr-Deskriptor
 | |
|     {},
 | |
| 
 | |
|     // XXX: Can't we just use GDT::protected_mode?
 | |
|     // code segment
 | |
|     GDT::SegmentDescriptor::Segment(0, UINT32_MAX, true, 0, GDT::SIZE_32BIT),
 | |
| 
 | |
|     // data segment
 | |
|     GDT::SegmentDescriptor::Segment(0, UINT32_MAX, false, 0, GDT::SIZE_32BIT),
 | |
| };
 | |
| 
 | |
| void relocateSetupCode() {
 | |
|   // Relocated setup code
 | |
|   memcpy(reinterpret_cast<void*>(RELOCATED_SETUP), &___SETUP_AP_START__,
 | |
|          &___SETUP_AP_END__ - &___SETUP_AP_START__);
 | |
| 
 | |
|   // Adjust GDT:
 | |
|   // Calculate offset for real mode GDT and GDT descriptor
 | |
|   uintptr_t ap_gdt_offset = reinterpret_cast<uintptr_t>(&setup_ap_gdt) -
 | |
|                             reinterpret_cast<uintptr_t>(&___SETUP_AP_START__);
 | |
|   uintptr_t ap_gdtd_offset = reinterpret_cast<uintptr_t>(&setup_ap_gdtd) -
 | |
|                              reinterpret_cast<uintptr_t>(&___SETUP_AP_START__);
 | |
| 
 | |
|   // Copy blue print of real mode GDT to the relocated memory
 | |
|   void* relocated_ap_gdt =
 | |
|       reinterpret_cast<void*>(RELOCATED_SETUP + ap_gdt_offset);
 | |
|   memcpy(relocated_ap_gdt, &ap_gdt, sizeof(ap_gdt));
 | |
| 
 | |
|   // Calculate GDT descriptor for relocated address
 | |
|   GDT::Pointer* relocated_ap_gdtd =
 | |
|       reinterpret_cast<GDT::Pointer*>(RELOCATED_SETUP + ap_gdtd_offset);
 | |
|   relocated_ap_gdtd->set(relocated_ap_gdt, size(ap_gdt));
 | |
| }
 | |
| 
 | |
| void boot(void) {
 | |
|   assert(!Core::Interrupt::isEnabled() &&
 | |
|          "Interrupts should not be enabled before APs have booted!");
 | |
| 
 | |
|   // Relocate setup code
 | |
|   relocateSetupCode();
 | |
| 
 | |
|   // Calculate Init-IPI vector based on address of relocated setup_ap()
 | |
|   uint8_t vector = RELOCATED_SETUP >> 12;
 | |
| 
 | |
|   // Send Init-IPI to all APs
 | |
|   LAPIC::IPI::sendInit();
 | |
| 
 | |
|   // wait at least 10ms
 | |
|   PIT::delay(10000);
 | |
| 
 | |
|   // Send Startup-IPI twice
 | |
|   DBG_VERBOSE << "Sending STARTUP IPI #1" << endl;
 | |
|   LAPIC::IPI::sendStartup(vector);
 | |
|   // wait at least 200us
 | |
|   PIT::delay(200);
 | |
| 
 | |
|   DBG_VERBOSE << "Sending STARTUP IPI #2" << endl;
 | |
|   LAPIC::IPI::sendStartup(vector);
 | |
| }
 | |
| }  // namespace ApplicationProcessor
 |