From: <nmd...@us...> - 2008-08-07 10:57:21
|
Revision: 314 http://aceos.svn.sourceforge.net/aceos/?rev=314&view=rev Author: nmdilipsimha Date: 2008-08-07 10:57:29 +0000 (Thu, 07 Aug 2008) Log Message: ----------- Added/modified code for apic. Modified Paths: -------------- src/include/kernel/apic.h src/include/kernel/ioapic.h src/kernel/i386/arch.c src/kernel/i386/interrupt.c src/kernel/main.c src/kernel/pic/apic.c src/kernel/pic/ioapic.c Modified: src/include/kernel/apic.h =================================================================== --- src/include/kernel/apic.h 2008-08-07 10:55:15 UTC (rev 313) +++ src/include/kernel/apic.h 2008-08-07 10:57:29 UTC (rev 314) @@ -4,7 +4,7 @@ \version 3.0 \date Created: Sat Jun 14, 2008 06:19PM - Last modified: Thu Aug 07, 2008 12:01AM + Last modified: Thu Aug 07, 2008 03:30PM \brief */ @@ -14,7 +14,8 @@ #include <ace.h> -#define MAX_IOAPIC 4 +#define LAPIC_BASE_MSR_START 0xfee00000 +#define AM_I_BOOTSTRAP_PROCESSOR ia32_lapic_base_msr.bsp /* Enums */ @@ -246,27 +247,18 @@ }EOI_REG, * EOI_REG_PTR; - -/* IOAPIC */ -typedef struct ioapic -{ - UINT32 ioapic_id; - UINT32 physical_address; -}IOAPIC, *IOAPIC_PTR; - - /* Declaration of the variables defined in apic.c */ -extern IA32_APIC_BASE_MSR_PTR ia32_ioapic_base_msr; +extern IA32_APIC_BASE_MSR_PTR lapic_base_msr; /* Functions */ int DetectAPIC(UINT8 cpu_id); void UseAPIC(int enable); -INT32 GetApicId(); -void RelocateBaseApicAddress(UINT32 addr); -INT16 IssueInterprocessorInterrupt(UINT32 vector, UINT32 apic_id, enum ICR_DELIVERY_MODE delivery_mode, - enum ICR_DESTINATION_SHORTHAND destination_shorthand, BYTE init_de_assert); void InitAPIC(void); +void SendEndOfInterrupt(int int_no); +void RelocateBaseLAPICAddress(UINT32 addr); void InitSmp(void); +INT16 IssueInterprocessorInterrupt(UINT32 vector, UINT32 apic_id, enum ICR_DELIVERY_MODE delivery_mode, + enum ICR_DESTINATION_SHORTHAND destination_shorthand, BYTE init_de_assert); #endif Modified: src/include/kernel/ioapic.h =================================================================== --- src/include/kernel/ioapic.h 2008-08-07 10:55:15 UTC (rev 313) +++ src/include/kernel/ioapic.h 2008-08-07 10:57:29 UTC (rev 314) @@ -4,7 +4,7 @@ \version 3.0 \date Created: Wed Aug 06, 2008 11:25PM - Last modified: Wed Aug 06, 2008 11:59PM + Last modified: Thu Aug 07, 2008 03:37PM \brief Contains IO-APIC stuff. */ @@ -14,9 +14,22 @@ #include <ace.h> +#define MAX_IOAPIC 4 #define IOAPIC_STARTING_VECTOR_NUMBER 32 +#define IOAPIC_BASE_MSR_START 0xfec00000 + //IOAPIC registers + +/* IOAPIC */ +typedef struct ioapic +{ + UINT32 ioapic_id; + UINT32 physical_address; + UINT32 starting_vector; + UINT32 max_entries; +}IOAPIC, *IOAPIC_PTR; + enum IOAPIC_REGISTER { IOAPIC_REGISTER_IOAPIC_ID=0, @@ -48,6 +61,8 @@ IOAPIC_REGISTER_REDIRECT_TABLE23=0x3E }; + +/* This structure is reimposed with IA32_APIC_BASE_MSR structure. So be careful in handling the reserved fields. */ typedef struct ioapic_reg { //First byte specifies the register which has to be accessed. @@ -133,15 +148,18 @@ IOAPIC_DELIVERY_MODE_ExtINT //7 }; +extern IOAPIC ioapic[MAX_IOAPIC]; +extern UINT8 count_ioapic; +void RelocateBaseIOAPICAddress(UINT32 addr, UINT32 index); void InitIOAPIC(void); -void ReadFromIOAPIC(enum IOAPIC_REGISTER reg, UINT32 *data); -void WriteToIOAPIC(enum IOAPIC_REGISTER reg, UINT32 data); -UINT8 GetIOAPICId(void); -void SetIOAPICId(UINT8 ioapic_id); -UINT8 GetMaximumIOAPICRedirectionEntries(void); -void GetIOAPICRedirectionTableEntry(enum IOAPIC_REGISTER reg, IOAPIC_REDIRECT_TABLE_PTR table); -void SetIOAPICRedirectionTableEntry(enum IOAPIC_REGISTER reg, IOAPIC_REDIRECT_TABLE_PTR table); -int InitIOAPICRedirectionTable(int starting_vector); +void ReadFromIOAPIC(enum IOAPIC_REGISTER reg, UINT32 *data, UINT8 index); +void WriteToIOAPIC(enum IOAPIC_REGISTER reg, UINT32 data, UINT8 index); +UINT8 GetIOAPICId(UINT8 index); +void SetIOAPICId(UINT8 ioapic_id, UINT8 index); +UINT8 GetMaximumIOAPICRedirectionEntries(UINT8 index); +void GetIOAPICRedirectionTableEntry(enum IOAPIC_REGISTER reg, IOAPIC_REDIRECT_TABLE_PTR table, UINT8 index); +void SetIOAPICRedirectionTableEntry(enum IOAPIC_REGISTER reg, IOAPIC_REDIRECT_TABLE_PTR table, UINT8 index); +int InitIOAPICRedirectionTable(int starting_vector, UINT8 index); #endif Modified: src/kernel/i386/arch.c =================================================================== --- src/kernel/i386/arch.c 2008-08-07 10:55:15 UTC (rev 313) +++ src/kernel/i386/arch.c 2008-08-07 10:57:29 UTC (rev 314) @@ -4,7 +4,7 @@ \version 3.0 \date Created: 26/09/07 15:21 - Last modified: Tue May 27, 2008 11:05AM + Last modified: Thu Aug 07, 2008 03:43PM \brief contains architecture related interface routines. */ #include <string.h> @@ -51,7 +51,7 @@ sys_kernel_cmd_line = (char *)BOOT_TO_KERNEL_ADDRESS(mbi->cmdline); /*enable interrupt only after setting up idt*/ - __asm__ __volatile__ ("sti"); + // __asm__ __volatile__ ("sti"); } Modified: src/kernel/i386/interrupt.c =================================================================== --- src/kernel/i386/interrupt.c 2008-08-07 10:55:15 UTC (rev 313) +++ src/kernel/i386/interrupt.c 2008-08-07 10:57:29 UTC (rev 314) @@ -1,10 +1,10 @@ /*! - \file interrupt.c + \file kernel/i386/interrupt.c \author DilipSimha N M \version 3.0 \date Created: Thu Oct 11, 2007 02:27PM - Last modified: Thu Aug 07, 2008 12:01AM + Last modified: Thu Aug 07, 2008 10:19AM \brief This file contains routiens necessary to handle and setup IRQ(Interrupt requests) on the system. All the interrupts from 33-48 will be redirected to InterruptHandler(). @@ -31,8 +31,6 @@ */ void SetupInterruptStubs() { - InitAPIC(); - SetIdtGate(32, (unsigned)InterruptStub0); SetIdtGate(33, (unsigned)InterruptStub1); SetIdtGate(34, (unsigned)InterruptStub2); Modified: src/kernel/main.c =================================================================== --- src/kernel/main.c 2008-08-07 10:55:15 UTC (rev 313) +++ src/kernel/main.c 2008-08-07 10:57:29 UTC (rev 314) @@ -4,7 +4,7 @@ \version 3.0 \date Created: Fri Sep 21, 2007 02:26PM - Last modified: Mon Aug 04, 2008 04:09PM + Last modified: Thu Aug 07, 2008 10:45AM \brief */ #include <version.h> @@ -69,6 +69,7 @@ InitAPIC(); kprintf("APIC initialized\n"); + __asm__ __volatile__ ("sti"); InitSmp(); kprintf("SMP initialised\n"); Modified: src/kernel/pic/apic.c =================================================================== --- src/kernel/pic/apic.c 2008-08-07 10:55:15 UTC (rev 313) +++ src/kernel/pic/apic.c 2008-08-07 10:57:29 UTC (rev 314) @@ -4,7 +4,7 @@ \version 3.0 \date Created: Sat Jun 14, 2008 06:16PM - Last modified: Thu Aug 07, 2008 12:00AM + Last modified: Thu Aug 07, 2008 04:18PM \brief Provides support for Advanced programmable interrupt controller on P4 machine. */ @@ -17,9 +17,15 @@ #include <kernel/debug.h> #include <kernel/arch.h> #include <kernel/processor.h> +#include <kernel/mm/vm.h> +#include <kernel/i386/pmem.h> +#include <kernel/io.h> static void BootOtherProcessors(void); static void StartProcessor(UINT32 apic_id); +static void InitLAPICRegisters(UINT32 base_address); +static void InitLAPIC(void); +static void GetProcessorInfoFromACPI(void); #define X2APIC_ENABLE_BIT 21 #define APIC_ENABLE_BIT 9 @@ -27,13 +33,8 @@ #define LOGICAL_DESTINATION_REGISTER_OFFSET 0xD0 #define DESTINATION_FORMAT_REGISTER_OFFSET 0xE0 -IA32_APIC_BASE_MSR_PTR ia32_apic_base_msr; -IA32_APIC_BASE_MSR_PTR ia32_ioapic_base_msr; -#define IA32_APIC_BASE_MSR_START 0xfee00000 -#define IA32_IOAPIC_BASE_MSR_START 0xfec00000 +IA32_APIC_BASE_MSR_PTR lapic_base_msr; -#define AM_I_BOOTSTRAP_PROCESSOR ia32_apic_base_msr.bsp - INTERRUPT_COMMAND_REGISTER_PTR interrupt_command_register; #define INTERRUPT_COMMAND_REGISTER_LOW_OFFSET 0x300 /*(0-31 bits)*/ #define INTERRUPT_COMMAND_REGISTER_HIGH_OFFSET 0x310 /*(32-63 bits)*/ @@ -110,9 +111,6 @@ #define EOI_REGISTER_RESET 0x0 -IOAPIC ioapic[MAX_IOAPIC]; -UINT32 count_ioapic; - /*! \brief Detects if APIC support is present on the processor by looking into CPUID. @@ -142,205 +140,93 @@ { if(enable) { - ia32_apic_base_msr->enable = 1; + lapic_base_msr->enable = 1; + _outp(0x70, 0x22); + _outp(0x01, 0x23); } else { - ia32_apic_base_msr->enable = 0; + lapic_base_msr->enable = 0; } } /*! - \brief Provides the following support: - 1: To send an interrupt to another processor. - 2: To allow a processor to forward an interrupt, that it received but did not service, to another processor for servicing. - 3: To direct the processor to interrupt itself (perform a self interrupt). - 4: To deliver special IPIs, such as the start-up IPI (SIPI) message, to other processors. + \brief Initialize APIC by getting information from ACPI. This is called from main.c. + This initializes LAPIC and IOAPIC by calling their respective functions. - \param vector: Vector number of the interrupt being sent. - apic_id: apic id of the processor to which an interrupt is to be sent. - delivery_mode: Specifies the type of IPI to be sent. - \return -*/ -INT16 IssueInterprocessorInterrupt(UINT32 vector, UINT32 apic_id, enum ICR_DELIVERY_MODE delivery_mode, - enum ICR_DESTINATION_SHORTHAND destination_shorthand, BYTE init_de_assert) -{ - INTERRUPT_COMMAND_REGISTER cmd; - - cmd.vector = vector; - cmd.delivery_mode = delivery_mode; - cmd.destination_mode = ICR_DESTINATION_MODE_PHYSICAL; - cmd.level = ICR_LEVEL_ASSERT; - cmd.destination_field = apic_id; + \param void - switch(delivery_mode) - { - case ICR_DELIVERY_MODE_FIXED: break; - case ICR_DELIVERY_MODE_LOWEST_PRIORITY: break; - case ICR_DELIVERY_MODE_SMI: cmd.vector = 0; /*This is for future compatibility as described in specs. */ - break; - case ICR_DELIVERY_MODE_NMI: break; - case ICR_DELIVERY_MODE_INIT: - if(init_de_assert) { - cmd.level = ICR_LEVEL_DE_ASSERT; - } - cmd.trigger_mode = ICR_TRIGGER_MODE_LEVEL; - cmd.vector = 0; /*This is for future compatibility as described in specs. */ - break; - case ICR_DELIVERY_MODE_SIPI: cmd.trigger_mode = ICR_TRIGGER_MODE_EDGE; - break; - case ICR_DELIVERY_MODE_ExtINT: cmd.trigger_mode = ICR_TRIGGER_MODE_LEVEL; break; - default: break; - } - - switch(destination_shorthand) - { - case ICR_DESTINATION_SHORTHAND_NO_SHORTHAND: break; - case ICR_DESTINATION_SHORTHAND_SELF: break; - case ICR_DESTINATION_SHORTHAND_ALL_INCLUDING_SELF: cmd.destination_field = 0XFF; - break; - case ICR_DESTINATION_SHORTHAND_ALL_EXCLUDING_SELF: cmd.destination_field = 0XFF; - break; - } - - /* Now copy these register contents to actual location of interrupt command register */ - memcpy( interrupt_command_register, &cmd, sizeof(INTERRUPT_COMMAND_REGISTER) ); //dst, src, len - /* This act of writing into ICR will make APIC to generate an interrupt */ - return 0; -} - -/*! - \brief This routine memory maps all the APIC registers from the specified starting base. - - \param base_address: starting address of APIC registers. - \return void */ -static void InitAPICRegisters(UINT32 base_address) +void InitAPIC(void) { - interrupt_command_register = (INTERRUPT_COMMAND_REGISTER_PTR)(base_address + INTERRUPT_COMMAND_REGISTER_LOW_OFFSET); - timer_register = (TIMER_REGISTER_PTR)(TIMER_REGISTER_OFFSET + base_address); - lint0_reg = (LINT0_REG_PTR)(base_address + LINT0_REGISTER_OFFSET); - lint1_reg = (LINT1_REG_PTR)(base_address + LINT1_REGISTER_OFFSET); - error_reg = (ERROR_REG_PTR)(base_address + ERROR_REGISTER_OFFSET); - performance_monitor_count_reg = (PERFORMANCE_MONITOR_COUNT_REG_PTR)(base_address + PERF_MON_CNT_REGISTER_OFFSET); - thermal_sensor_reg = (THERMAL_SENSOR_REG_PTR)(base_address + THERMAL_SENSOR_REGISTER_OFFSET); - error_status_reg = (ERROR_STATUS_REG_PTR)(base_address + ERROR_STATUS_REGISTER_OFFSET); - local_apic_version_reg = (LOCAL_APIC_VERSION_REG_PTR)(base_address + LOCAl_APIC_VERSION_REGISTER_OFFSET); - logical_destination_reg = (LOGICAL_DESTINATION_REG_PTR)(base_address + LOGICAL_DESTINATION_REGISTER_OFFSET); - destination_format_reg = (DESTINATION_FORMAT_REG_PTR)(base_address + DESTINATION_FORMAT_REGISTER_OFFSET); - arbitration_priority_reg = (ARBITRATION_PRIORITY_REG_PTR)(base_address + ARBITRATION_PRIORITY_REGISTER_OFFSET); - task_priority_reg = (TASK_PRIORITY_REG_PTR)(base_address + TASK_PRIORITY_REGISTER_OFFSET); - processor_priority_reg = (PROCESSOR_PRIORITY_REG_PTR)(base_address + PROCESSOR_PRIORITY_REGISTER_OFFSET); - interrupt_request_reg = (INTERRUPT_REQUEST_REG_PTR)(base_address + INTERRUPT_REQUEST_REGISTER_OFFSET); - in_service_reg = (IN_SERVICE_REG_PTR)(base_address + IN_SERVICE_REGISTER_OFFSET); - trigger_mode_reg = (TRIGGER_MODE_REG_PTR)(base_address + TRIGGER_MODE_REGISTER_OFFSET); - eoi_reg = (EOI_REG_PTR)(base_address + EOI_REGISTER_OFFSET); + GetProcessorInfoFromACPI(); + //Init lapic and ioapic registers. + InitLAPIC(); + InitIOAPIC(); + UseAPIC(1); + kprintf("APIC is in use now\n"); return; } /*! - \brief Sets the base address of apic to this new address. - It then calls InitAllAPICRegisters to set all APIC registers to offset from the new base address. + \brief The act of writing anything to this register will cause an EOI to be issued. - \param addr: The new base address of apic registers. + \param int_no: Interrupt number \return void */ -void RelocateBaseAPICAddress(UINT32 addr) +void SendEndOfInterrupt(int int_no) { - /* backup the present contents of base register */ - IA32_APIC_BASE_MSR temp; - temp.bsp = ia32_apic_base_msr->bsp; - temp.enable = ia32_apic_base_msr->enable; - - /* Change the base address to new address */ - ia32_apic_base_msr = (IA32_APIC_BASE_MSR_PTR)(addr); - temp.base_low = ia32_apic_base_msr->base_low; - temp.base_high = ia32_apic_base_msr->base_high; - - memcpy((void*)(ia32_apic_base_msr), (void*)(&temp), sizeof(IA32_APIC_BASE_MSR)); - - InitAPICRegisters(addr); + eoi_reg->zero = 0; } - /*! - \brief Get apic information by calling ACPI. + \brief Initialize LAPIC registers and LAPIC base address. \param void \return void */ -void GetProcessorInfoFromACPI(void) +static void InitLAPIC(void) { - ACPI_TABLE_MADT *madt_ptr; - if ( AcpiGetTable ("APIC", 1, (ACPI_TABLE_HEADER**)(&madt_ptr)) != AE_OK ) - kprintf("AcpiGetTable() failed\n"); - else - { - kprintf("LAPIC Address %p [%s]\n", madt_ptr->Address, madt_ptr->Flags&1?"APIC and Dual 8259 Support":"Only APIC" ); - ACPI_SUBTABLE_HEADER *sub_header, *table_end; - sub_header = (ACPI_SUBTABLE_HEADER *) ( ((UINT32)madt_ptr) + sizeof(ACPI_TABLE_MADT) ); - table_end = (ACPI_SUBTABLE_HEADER *) ( ((UINT32)madt_ptr) + madt_ptr->Header.Length ); + UINT32 va, kernel_stack_pages=2; - count_running_processors = 0; - while ( sub_header < table_end ) - { - if ( sub_header->Type == ACPI_MADT_TYPE_LOCAL_APIC ) - { - ACPI_MADT_LOCAL_APIC *p = ( ACPI_MADT_LOCAL_APIC * ) sub_header; - kprintf("Processor ID %d LAPIC Id = %d [%s]\n", p->ProcessorId, p->Id, ( (p->LapicFlags & 1) ? "Online" : "Offline") ); - processor[count_running_processors].apic_id = p->Id; - processor[count_running_processors].state = ( (p->LapicFlags & 1) ? (PROCESSOR_STATE_ONLINE) : (PROCESSOR_STATE_OFFLINE) ); - kprintf("processor loaded..\n"); - count_running_processors++; - } - else if ( sub_header->Type == ACPI_MADT_TYPE_IO_APIC ) - { - ACPI_MADT_IO_APIC *p = ( ACPI_MADT_IO_APIC * ) sub_header; - kprintf("IOAPIC ID %d IOAPIC Physical Address = %p GlobalIRQBase %d\n", p->Id, p->Address, p->GlobalIrqBase); - ioapic[count_ioapic].ioapic_id = p->Id; - ioapic[count_ioapic].physical_address = p->Address; - count_ioapic++; - } - else - kprintf("Type = %d\n", sub_header->Type); + if ( AllocateVirtualMemory(&kernel_map, &va, 0, PAGE_SIZE * kernel_stack_pages, 0, 0) != ERROR_SUCCESS ) + panic("VA not available for starting secondary CPU\n"); + lapic_base_msr = (IA32_APIC_BASE_MSR_PTR)va; - sub_header = (ACPI_SUBTABLE_HEADER *) ( ((UINT32)sub_header) + sub_header->Length ); - } - kprintf("while done\n"); - } + if ( CreatePhysicalMapping(kernel_map.physical_map, (UINT32)lapic_base_msr, va, 0) != ERROR_SUCCESS ) + panic("VA to PA mapping failed\n"); + + InitLAPICRegisters(LAPIC_BASE_MSR_START); + return; } - - /*! - \brief Initialize APIC by getting information from ACPI. This is called from main.c. + \brief Sets the base address of LAPIC to this new address. - \param void + \param addr: The new physical base address of LAPIC base register. \return void */ -void InitAPIC(void) +void RelocateBaseLAPICAddress(UINT32 addr) { - GetProcessorInfoFromACPI(); - InitIOAPIC(); - return; -} + /* backup the present contents of base register */ + IA32_APIC_BASE_MSR temp; + temp.bsp = lapic_base_msr->bsp; + temp.enable = lapic_base_msr->enable; + if ( CreatePhysicalMapping(kernel_map.physical_map, (UINT32)lapic_base_msr, addr, 0) != ERROR_SUCCESS ) + panic("VA to PA mapping failed\n"); -/*! - \brief The act of writing anything to this register will cause an EOI to be issued. + /* Change the base address to new address */ + lapic_base_msr = (IA32_APIC_BASE_MSR_PTR)(addr); + temp.base_low = lapic_base_msr->base_low; + temp.base_high = lapic_base_msr->base_high; - \param int_no: Interrupt number - - \return void -*/ -void SendEndOfInterrupt(int int_no) -{ - eoi_reg->zero = 0; + memcpy((void*)(lapic_base_msr), (void*)(&temp), sizeof(IA32_APIC_BASE_MSR)); } @@ -380,7 +266,6 @@ } - /*! \brief Start a application processor by issuing IPI messages in the order: INIT, SIPI, SIPI. @@ -421,3 +306,144 @@ } return; } + + +/*! + \brief This routine memory maps all the LAPIC registers from the specified starting base. + + \param base_address: starting address of LAPIC registers. + + \return void +*/ +static void InitLAPICRegisters(UINT32 base_address) +{ + interrupt_command_register = (INTERRUPT_COMMAND_REGISTER_PTR)(base_address + INTERRUPT_COMMAND_REGISTER_LOW_OFFSET); + timer_register = (TIMER_REGISTER_PTR)(TIMER_REGISTER_OFFSET + base_address); + lint0_reg = (LINT0_REG_PTR)(base_address + LINT0_REGISTER_OFFSET); + lint1_reg = (LINT1_REG_PTR)(base_address + LINT1_REGISTER_OFFSET); + error_reg = (ERROR_REG_PTR)(base_address + ERROR_REGISTER_OFFSET); + performance_monitor_count_reg = (PERFORMANCE_MONITOR_COUNT_REG_PTR)(base_address + PERF_MON_CNT_REGISTER_OFFSET); + thermal_sensor_reg = (THERMAL_SENSOR_REG_PTR)(base_address + THERMAL_SENSOR_REGISTER_OFFSET); + error_status_reg = (ERROR_STATUS_REG_PTR)(base_address + ERROR_STATUS_REGISTER_OFFSET); + local_apic_version_reg = (LOCAL_APIC_VERSION_REG_PTR)(base_address + LOCAl_APIC_VERSION_REGISTER_OFFSET); + logical_destination_reg = (LOGICAL_DESTINATION_REG_PTR)(base_address + LOGICAL_DESTINATION_REGISTER_OFFSET); + destination_format_reg = (DESTINATION_FORMAT_REG_PTR)(base_address + DESTINATION_FORMAT_REGISTER_OFFSET); + arbitration_priority_reg = (ARBITRATION_PRIORITY_REG_PTR)(base_address + ARBITRATION_PRIORITY_REGISTER_OFFSET); + task_priority_reg = (TASK_PRIORITY_REG_PTR)(base_address + TASK_PRIORITY_REGISTER_OFFSET); + processor_priority_reg = (PROCESSOR_PRIORITY_REG_PTR)(base_address + PROCESSOR_PRIORITY_REGISTER_OFFSET); + interrupt_request_reg = (INTERRUPT_REQUEST_REG_PTR)(base_address + INTERRUPT_REQUEST_REGISTER_OFFSET); + in_service_reg = (IN_SERVICE_REG_PTR)(base_address + IN_SERVICE_REGISTER_OFFSET); + trigger_mode_reg = (TRIGGER_MODE_REG_PTR)(base_address + TRIGGER_MODE_REGISTER_OFFSET); + eoi_reg = (EOI_REG_PTR)(base_address + EOI_REGISTER_OFFSET); + return; +} + + +/*! + \brief Get apic information by calling ACPI. + + \param void + + \return void +*/ +static void GetProcessorInfoFromACPI(void) +{ + ACPI_TABLE_MADT *madt_ptr; + if ( AcpiGetTable ("APIC", 1, (ACPI_TABLE_HEADER**)(&madt_ptr)) != AE_OK ) + kprintf("AcpiGetTable() failed\n"); + else + { + kprintf("LAPIC Address %p [%s]\n", madt_ptr->Address, madt_ptr->Flags&1?"APIC and Dual 8259 Support":"Only APIC" ); + ACPI_SUBTABLE_HEADER *sub_header, *table_end; + sub_header = (ACPI_SUBTABLE_HEADER *) ( ((UINT32)madt_ptr) + sizeof(ACPI_TABLE_MADT) ); + table_end = (ACPI_SUBTABLE_HEADER *) ( ((UINT32)madt_ptr) + madt_ptr->Header.Length ); + + count_running_processors = 0; + while ( sub_header < table_end ) + { + if ( sub_header->Type == ACPI_MADT_TYPE_LOCAL_APIC ) + { + ACPI_MADT_LOCAL_APIC *p = ( ACPI_MADT_LOCAL_APIC * ) sub_header; + kprintf("Processor ID %d LAPIC Id = %d [%s]\n", p->ProcessorId, p->Id, ( (p->LapicFlags & 1) ? "Online" : "Offline") ); + processor[count_running_processors].apic_id = p->Id; + processor[count_running_processors].state = ( (p->LapicFlags & 1) ? (PROCESSOR_STATE_ONLINE) : (PROCESSOR_STATE_OFFLINE) ); + kprintf("processor loaded..\n"); + count_running_processors++; + } + else if ( sub_header->Type == ACPI_MADT_TYPE_IO_APIC ) + { + ACPI_MADT_IO_APIC *p = ( ACPI_MADT_IO_APIC * ) sub_header; + kprintf("IOAPIC ID %d IOAPIC Physical Address = %p GlobalIRQBase %d\n", p->Id, p->Address, p->GlobalIrqBase); + ioapic[count_ioapic].ioapic_id = p->Id; + ioapic[count_ioapic].physical_address = p->Address; + ioapic[count_ioapic].starting_vector = p->GlobalIrqBase; + count_ioapic++; + } + else + kprintf("Type = %d\n", sub_header->Type); + + sub_header = (ACPI_SUBTABLE_HEADER *) ( ((UINT32)sub_header) + sub_header->Length ); + } + kprintf("while done\n"); + } +} + + +/*! + \brief Provides the following support: + 1: To send an interrupt to another processor. + 2: To allow a processor to forward an interrupt, that it received but did not service, to another processor for servicing. + 3: To direct the processor to interrupt itself (perform a self interrupt). + 4: To deliver special IPIs, such as the start-up IPI (SIPI) message, to other processors. + + \param vector: Vector number of the interrupt being sent. + apic_id: apic id of the processor to which an interrupt is to be sent. + delivery_mode: Specifies the type of IPI to be sent. + \return +*/ +INT16 IssueInterprocessorInterrupt(UINT32 vector, UINT32 apic_id, enum ICR_DELIVERY_MODE delivery_mode, + enum ICR_DESTINATION_SHORTHAND destination_shorthand, BYTE init_de_assert) +{ + INTERRUPT_COMMAND_REGISTER cmd; + + cmd.vector = vector; + cmd.delivery_mode = delivery_mode; + cmd.destination_mode = ICR_DESTINATION_MODE_PHYSICAL; + cmd.level = ICR_LEVEL_ASSERT; + cmd.destination_field = apic_id; + + switch(delivery_mode) + { + case ICR_DELIVERY_MODE_FIXED: break; + case ICR_DELIVERY_MODE_LOWEST_PRIORITY: break; + case ICR_DELIVERY_MODE_SMI: cmd.vector = 0; /*This is for future compatibility as described in specs. */ + break; + case ICR_DELIVERY_MODE_NMI: break; + case ICR_DELIVERY_MODE_INIT: + if(init_de_assert) { + cmd.level = ICR_LEVEL_DE_ASSERT; + } + cmd.trigger_mode = ICR_TRIGGER_MODE_LEVEL; + cmd.vector = 0; /*This is for future compatibility as described in specs. */ + break; + case ICR_DELIVERY_MODE_SIPI: cmd.trigger_mode = ICR_TRIGGER_MODE_EDGE; + break; + case ICR_DELIVERY_MODE_ExtINT: cmd.trigger_mode = ICR_TRIGGER_MODE_LEVEL; break; + default: break; + } + + switch(destination_shorthand) + { + case ICR_DESTINATION_SHORTHAND_NO_SHORTHAND: break; + case ICR_DESTINATION_SHORTHAND_SELF: break; + case ICR_DESTINATION_SHORTHAND_ALL_INCLUDING_SELF: cmd.destination_field = 0XFF; + break; + case ICR_DESTINATION_SHORTHAND_ALL_EXCLUDING_SELF: cmd.destination_field = 0XFF; + break; + } + + /* Now copy these register contents to actual location of interrupt command register */ + memcpy( interrupt_command_register, &cmd, sizeof(INTERRUPT_COMMAND_REGISTER) ); //dst, src, len + /* This act of writing into ICR will make APIC to generate an interrupt */ + return 0; +} Modified: src/kernel/pic/ioapic.c =================================================================== --- src/kernel/pic/ioapic.c 2008-08-07 10:55:15 UTC (rev 313) +++ src/kernel/pic/ioapic.c 2008-08-07 10:57:29 UTC (rev 314) @@ -4,18 +4,84 @@ \version 3.0 \date Created: - Last modified: Wed Aug 06, 2008 11:58PM + Last modified: Thu Aug 07, 2008 03:56PM \brief Contains APIC stuff in general and LAPIC. */ #include <ace.h> #include <kernel/ioapic.h> #include <kernel/apic.h> +#include <kernel/mm/vm.h> +#include <kernel/mm/pmem.h> +#include <kernel/error.h> +#include <kernel/mm/virtual_page.h> +#include <kernel/debug.h> +#include <string.h> -IOAPIC_REG_PTR ioapic_reg; +IOAPIC_REG_PTR ioapic_base_reg[MAX_IOAPIC]; //This can also be used as IA32_APIC_BASE_MSR_PTR +IOAPIC ioapic[MAX_IOAPIC]; +UINT8 count_ioapic; + +static int FindIOAPIC(UINT8 ioapic_id); + + /*! + \brief Search for IOAPIC using ioapic id as the primary key. + + \param ioapic_id: unique id associated with each ioapic. + + \return index of ioapic(Positive number): success + -1: Failure +*/ +static int FindIOAPIC(UINT8 ioapic_id) +{ + UINT32 index; + + for(index = 0; index < count_ioapic; index++) + { + if( ioapic_id == GetIOAPICId(index)) //found + return index; + } + + return -1; +} + +/*! + \brief Sets the base address of IOAPIC to this new address. + + \param addr: The new physical base address of IOAPIC base register. + ioapic_id: id of the IOAPIC whose address is to be relocated. + + \return void +*/ +void RelocateBaseIOAPICAddress(UINT32 addr, UINT32 index) +{ + /* backup the present contents of base register */ + IOAPIC_REG temp; + //find the ioapic matching the given ioapic_id. + ( (IA32_APIC_BASE_MSR_PTR)(&temp) )->enable = ( (IA32_APIC_BASE_MSR_PTR)(ioapic_base_reg[index]) )->enable; + temp.reg = (ioapic_base_reg[index])->reg; + + if ( CreatePhysicalMapping(kernel_map.physical_map, (UINT32)( ioapic_base_reg[index] ), addr, 0) != ERROR_SUCCESS ) + panic("VA to PA mapping failed\n"); + + + /* Change the base address to new address */ + ioapic_base_reg[index] = (IOAPIC_REG_PTR)(&addr); + ( (IA32_APIC_BASE_MSR_PTR)(&temp) )->base_low = ( (IA32_APIC_BASE_MSR_PTR)(ioapic_base_reg[index]) )->base_low; + ( (IA32_APIC_BASE_MSR_PTR)(&temp) )->base_high = ( (IA32_APIC_BASE_MSR_PTR)(ioapic_base_reg[index]) )->base_high; + + /* Now write first 32 bits of the memory(As per specs). This is from LSB */ + memcpy((void*)(ioapic_base_reg[index]), (void*)(&temp), sizeof(UINT32)); + + /* Now write the next 32 bits of the memory in temp structure which contains base_high */ + memcpy((void*)(ioapic_base_reg[index]), (void*)((char*)(&temp) + 32), sizeof(UINT32)); +} + + +/*! \brief Initializies IOAPIC memory mapped registers and redirection table. \param void @@ -24,10 +90,23 @@ */ void InitIOAPIC(void) { - //First initialise our 2 memory mapped registers. - ioapic_reg = (IOAPIC_REG_PTR)(ia32_ioapic_base_msr); - //Now setup the redirection table. - InitIOAPICRedirectionTable(IOAPIC_STARTING_VECTOR_NUMBER); + UINT32 va, kernel_stack_pages=2, index; + + for (index=0; index < count_ioapic; index++) + { + if ( AllocateVirtualMemory(&kernel_map, &va, 0, PAGE_SIZE * kernel_stack_pages, 0, 0) != ERROR_SUCCESS ) + panic("VA not available for starting secondary CPU\n"); + + if ( CreatePhysicalMapping(kernel_map.physical_map, (UINT32)( ioapic_base_reg[index] ), (ioapic[index]).physical_address, 0) != ERROR_SUCCESS ) + panic("VA to PA mapping failed\n"); + + //Now setup the redirection table in each of the ioapic. + /* Each IOAPIC is initialized from acpi and we load the GlobalIrqBase count in starting_vector. + * So use that info in getting the starting vector number for each of the apic. + */ + InitIOAPICRedirectionTable(IOAPIC_STARTING_VECTOR_NUMBER + (ioapic[index]).starting_vector, index); + } + return; } @@ -40,10 +119,10 @@ \return void */ -void ReadFromIOAPIC(enum IOAPIC_REGISTER reg, UINT32 *data) +void ReadFromIOAPIC(enum IOAPIC_REGISTER reg, UINT32 *data, UINT8 index) { - ioapic_reg->reg = reg; - *data = ioapic_reg->data; + (ioapic_base_reg[index])->reg = reg; + *data = (ioapic_base_reg[index])->data; } @@ -55,25 +134,25 @@ \return void */ -void WriteToIOAPIC(enum IOAPIC_REGISTER reg, UINT32 data) +void WriteToIOAPIC(enum IOAPIC_REGISTER reg, UINT32 data, UINT8 index) { - ioapic_reg->reg = reg; - ioapic_reg->data = data; + (ioapic_base_reg[index])->reg = reg; + (ioapic_base_reg[index])->data = data; } /*! \brief Fetch the IOAPIC ID. - \param void + \param index: index to the IOAPIC inside ioapic_base_reg array. \return 4 bit IOAPIC id. */ -UINT8 GetIOAPICId(void) +UINT8 GetIOAPICId(UINT8 index) { UINT32 data; - ioapic_reg->reg = IOAPIC_REGISTER_IOAPIC_ID; - data = ioapic_reg->data; + (ioapic_base_reg[index])->reg = IOAPIC_REGISTER_IOAPIC_ID; + data = (ioapic_base_reg[index])->data; return (UINT8)( ((IOAPIC_ID_PTR)data)->ioapic_id ); } @@ -84,12 +163,12 @@ \return void */ -void SetIOAPICId(UINT8 ioapic_id) +void SetIOAPICId(UINT8 ioapic_id, UINT8 index) { UINT32 data; ((IOAPIC_ID_PTR)&data)->ioapic_id = ioapic_id; - ioapic_reg->reg = IOAPIC_REGISTER_IOAPIC_ID; - ioapic_reg->data = data; + (ioapic_base_reg[index])->reg = IOAPIC_REGISTER_IOAPIC_ID; + (ioapic_base_reg[index])->data = data; return; } @@ -101,11 +180,11 @@ \return Positive number of redirection entries. */ -UINT8 GetMaximumIOAPICRedirectionEntries(void) +UINT8 GetMaximumIOAPICRedirectionEntries(UINT8 index) { UINT32 data; - ioapic_reg->reg = IOAPIC_REGISTER_IOAPIC_VERSION; - data = ioapic_reg->data; + (ioapic_base_reg[index])->reg = IOAPIC_REGISTER_IOAPIC_VERSION; + data = (ioapic_base_reg[index])->data; return (UINT8)( ((IOAPIC_VERSION_PTR)&data)->max_redirection_entries ); } @@ -119,16 +198,16 @@ \return void */ -void GetIOAPICRedirectionTableEntry(enum IOAPIC_REGISTER reg, IOAPIC_REDIRECT_TABLE_PTR table) +void GetIOAPICRedirectionTableEntry(enum IOAPIC_REGISTER reg, IOAPIC_REDIRECT_TABLE_PTR table, UINT8 index) { UINT32 data; - ioapic_reg->reg = reg; - data = ioapic_reg->data; + (ioapic_base_reg[index])->reg = reg; + data = (ioapic_base_reg[index])->data; *table = *((IOAPIC_REDIRECT_TABLE_PTR)(&data)); - ioapic_reg->reg = reg + 0x1; - data = ioapic_reg->data; + (ioapic_base_reg[index])->reg = reg + 0x1; + data = (ioapic_base_reg[index])->data; table->destination_field = (data & 0xff000000); //get the MSB 8 bits return; @@ -143,16 +222,16 @@ \return void */ -void SetIOAPICRedirectionTableEntry(enum IOAPIC_REGISTER reg, IOAPIC_REDIRECT_TABLE_PTR table) +void SetIOAPICRedirectionTableEntry(enum IOAPIC_REGISTER reg, IOAPIC_REDIRECT_TABLE_PTR table, UINT8 index) { UINT32 data = (UINT32)((char*)(table)); - ioapic_reg->reg = reg; - ioapic_reg->data = data; + (ioapic_base_reg[index])->reg = reg; + (ioapic_base_reg[index])->data = data; data = (UINT32)( (table->destination_field) << 24 ); - ioapic_reg->reg = reg + 0x1; - ioapic_reg->data = data; + (ioapic_base_reg[index])->reg = reg + 0x1; + (ioapic_base_reg[index])->data = data; return; } @@ -167,7 +246,7 @@ -1: Invalid starting vector number. -2: Invalid max entries in redirection table. */ -int InitIOAPICRedirectionTable(int starting_vector) +int InitIOAPICRedirectionTable(int starting_vector, UINT8 index) { UINT8 max_entries, i; IOAPIC_REDIRECT_TABLE redirect_table; @@ -177,15 +256,17 @@ return -1; //Get the number of maximum redirection table entries supported on this IOAPIC. - max_entries = GetMaximumIOAPICRedirectionEntries(); + max_entries = GetMaximumIOAPICRedirectionEntries(index); if( max_entries > 24) return -2; + ioapic[index].max_entries = max_entries; + for(i=0; i< max_entries; i++) { redirect_table.interrupt_vector = starting_vector + i; reg = (enum IOAPIC_REGISTER)(0x10 + i*2); - SetIOAPICRedirectionTableEntry(reg, &redirect_table); + SetIOAPICRedirectionTableEntry(reg, &redirect_table, index); } return 0; } This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |