From: <nmd...@us...> - 2008-08-06 18:52:07
|
Revision: 312 http://aceos.svn.sourceforge.net/aceos/?rev=312&view=rev Author: nmdilipsimha Date: 2008-08-06 18:52:15 +0000 (Wed, 06 Aug 2008) Log Message: ----------- Added ioapic code but not tested. Modified Paths: -------------- src/include/kernel/apic.h src/kernel/i386/interrupt.c src/kernel/pic/apic.c Added Paths: ----------- src/include/kernel/ioapic.h src/kernel/pic/ioapic.c Modified: src/include/kernel/apic.h =================================================================== --- src/include/kernel/apic.h 2008-08-06 17:14:54 UTC (rev 311) +++ src/include/kernel/apic.h 2008-08-06 18:52:15 UTC (rev 312) @@ -4,7 +4,7 @@ \version 3.0 \date Created: Sat Jun 14, 2008 06:19PM - Last modified: Mon Aug 04, 2008 03:59PM + Last modified: Thu Aug 07, 2008 12:01AM \brief */ @@ -14,9 +14,9 @@ #include <ace.h> - #define MAX_IOAPIC 4 + /* Enums */ enum ICR_DELIVERY_MODE { @@ -255,6 +255,9 @@ }IOAPIC, *IOAPIC_PTR; +/* Declaration of the variables defined in apic.c */ +extern IA32_APIC_BASE_MSR_PTR ia32_ioapic_base_msr; + /* Functions */ int DetectAPIC(UINT8 cpu_id); @@ -263,8 +266,7 @@ 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 SetupAPIC(void); +void InitAPIC(void); void InitSmp(void); -void InitAPIC(void); #endif Added: src/include/kernel/ioapic.h =================================================================== --- src/include/kernel/ioapic.h (rev 0) +++ src/include/kernel/ioapic.h 2008-08-06 18:52:15 UTC (rev 312) @@ -0,0 +1,147 @@ +/*! + \file kernel/ioapic.h + \author DilipSimha N M + \version 3.0 + \date + Created: Wed Aug 06, 2008 11:25PM + Last modified: Wed Aug 06, 2008 11:59PM + \brief Contains IO-APIC stuff. +*/ + + +#ifndef _IOAPIC_H_ +#define _IOAPIC_H_ + +#include <ace.h> + +#define IOAPIC_STARTING_VECTOR_NUMBER 32 +//IOAPIC registers + +enum IOAPIC_REGISTER +{ + IOAPIC_REGISTER_IOAPIC_ID=0, + IOAPIC_REGISTER_IOAPIC_VERSION=1, + IOAPIC_REGISTER_IOAPIC_ARBITRATION=2, + IOAPIC_REGISTER_REDIRECT_TABLE0=0x10, + IOAPIC_REGISTER_REDIRECT_TABLE1=0x12, + IOAPIC_REGISTER_REDIRECT_TABLE2=0x14, + IOAPIC_REGISTER_REDIRECT_TABLE3=0x16, + IOAPIC_REGISTER_REDIRECT_TABLE4=0x18, + IOAPIC_REGISTER_REDIRECT_TABLE5=0x1A, + IOAPIC_REGISTER_REDIRECT_TABLE6=0x1C, + IOAPIC_REGISTER_REDIRECT_TABLE7=0x1E, + IOAPIC_REGISTER_REDIRECT_TABLE8=0x20, + IOAPIC_REGISTER_REDIRECT_TABLE9=0x22, + IOAPIC_REGISTER_REDIRECT_TABLE10=0x24, + IOAPIC_REGISTER_REDIRECT_TABLE11=0x26, + IOAPIC_REGISTER_REDIRECT_TABLE12=0x28, + IOAPIC_REGISTER_REDIRECT_TABLE13=0x2A, + IOAPIC_REGISTER_REDIRECT_TABLE14=0x2C, + IOAPIC_REGISTER_REDIRECT_TABLE15=0x2E, + IOAPIC_REGISTER_REDIRECT_TABLE16=0x30, + IOAPIC_REGISTER_REDIRECT_TABLE17=0x32, + IOAPIC_REGISTER_REDIRECT_TABLE18=0x34, + IOAPIC_REGISTER_REDIRECT_TABLE19=0x36, + IOAPIC_REGISTER_REDIRECT_TABLE20=0x38, + IOAPIC_REGISTER_REDIRECT_TABLE21=0x3A, + IOAPIC_REGISTER_REDIRECT_TABLE22=0x3C, + IOAPIC_REGISTER_REDIRECT_TABLE23=0x3E +}; + +typedef struct ioapic_reg +{ + //First byte specifies the register which has to be accessed. + UINT32 reg:8, //IO_REG_SEL register + reserved1:24; + UINT32 reserved2[3]; + + //at an offset of 4 bytes from base, specify the data. + UINT32 data; //IO_WIN register. This must be accessed as an Dword only. +}IOAPIC_REG, *IOAPIC_REG_PTR; + +typedef struct ioapic_id +{ + UINT32 reserved1 : 24, //0-23 + ioapic_id : 4, //24-27 + reserved2 : 4; //28-31 +}IOAPIC_ID, *IOAPIC_ID_PTR; + +typedef struct ioapic_version +{ + UINT32 apic_version : 8, //0-7 + reserved1 : 8, //8-15 + max_redirection_entries : 8, //16-23 + reserved2 : 8; //24-31 +}IOAPIC_VERSION, *IOAPIC_VERSION_PTR; + +typedef struct ioapic_arbitration +{ + UINT32 reserved1 : 24, //0-23 + arbitration_id : 4, //24-27 + reserved2 : 4; //28-31 +}IOAPIC_ARBITRATION, *IOAPIC_ARBITRATION_PTR; + +typedef struct ioapic_redirect_table +{ + UINT32 interrupt_vector : 8, //0-7 + delivery_mode : 3, //8-10 + destination_mode : 1, //1 + delivery_status : 1, //12 + input_polarity : 1, //13 + remote_irr : 1, //14 + trigger_mode : 1, //15 + interrupt_mask : 1, //16 + reserved1 : 15; //17-31 + + UINT32 reserved2 : 24, //31-55 + destination_field : 8; //56-63 +}IOAPIC_REDIRECT_TABLE, *IOAPIC_REDIRECT_TABLE_PTR; + +enum IOAPIC_TRIGGER_MODE +{ + IOAPIC_TRIGGER_MODE_EDGE, //0 + IOAPIC_TRIGGER_MODE_LEVEL //1 +}; + +enum IOAPIC_INPUT_POLARITY +{ + IOAPIC_INPUT_POLARITY_HIGH_ACTIVE, //0 + IOAPIC_INPUT_POLARITY_LOW_ACTIVE //1 +}; + +enum IOAPIC_DELIVERY_STATUS +{ + IOAPIC_DELIVERY_STATUS_IDLE, //0 + IOAPIC_DELIVERY_STATUS_SEND_PENDING //1 +}; + +enum IOAPIC_DESTINATION_MODE +{ + IOAPIC_DESTINATION_MODE_PHYSICAL, //0 + IOAPIC_DESTINATION_MODE_LOGICAL //1 +}; + +enum IOAPIC_DELIVERY_MODE +{ + IOAPIC_DELIVERY_MODE_FIXED, //0 + IOAPIC_DELIVERY_MODE_LOWEST_PRIORITY, //1 + IOAPIC_DELIVERY_MODE_SMI, //2 + IOAPIC_DELIVERY_MODE_RESERVED1, //3 + IOAPIC_DELIVERY_MODE_NMI, //4 + IOAPIC_DELIVERY_MODE_INIT, //5 + IOAPIC_DELIVERY_MODE_RESERVED2, //6 + IOAPIC_DELIVERY_MODE_ExtINT //7 +}; + + +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); + +#endif Modified: src/kernel/i386/interrupt.c =================================================================== --- src/kernel/i386/interrupt.c 2008-08-06 17:14:54 UTC (rev 311) +++ src/kernel/i386/interrupt.c 2008-08-06 18:52:15 UTC (rev 312) @@ -4,7 +4,7 @@ \version 3.0 \date Created: Thu Oct 11, 2007 02:27PM - Last modified: Mon Aug 04, 2008 02:58PM + Last modified: Thu Aug 07, 2008 12:01AM \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,7 +31,7 @@ */ void SetupInterruptStubs() { - SetupAPIC(); + InitAPIC(); SetIdtGate(32, (unsigned)InterruptStub0); SetIdtGate(33, (unsigned)InterruptStub1); Modified: src/kernel/pic/apic.c =================================================================== --- src/kernel/pic/apic.c 2008-08-06 17:14:54 UTC (rev 311) +++ src/kernel/pic/apic.c 2008-08-06 18:52:15 UTC (rev 312) @@ -4,7 +4,7 @@ \version 3.0 \date Created: Sat Jun 14, 2008 06:16PM - Last modified: Mon Aug 04, 2008 04:24PM + Last modified: Thu Aug 07, 2008 12:00AM \brief Provides support for Advanced programmable interrupt controller on P4 machine. */ @@ -12,6 +12,7 @@ #include <kernel/i386/cpuid.h> #include <string.h> #include <kernel/apic.h> +#include <kernel/ioapic.h> #include <kernel/acpi/acpi.h> #include <kernel/debug.h> #include <kernel/arch.h> @@ -215,26 +216,26 @@ \return void */ -static void InitAllAPICRegisters(UINT32 base_address) +static void InitAPICRegisters(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); + 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; } @@ -260,10 +261,19 @@ memcpy((void*)(ia32_apic_base_msr), (void*)(&temp), sizeof(IA32_APIC_BASE_MSR)); - InitAllAPICRegisters(addr); + InitAPICRegisters(addr); } -void GetProcessorInfoFromACPI() + + +/*! + \brief Get apic information by calling ACPI. + + \param void + + \return void +*/ +void GetProcessorInfoFromACPI(void) { ACPI_TABLE_MADT *madt_ptr; if ( AcpiGetTable ("APIC", 1, (ACPI_TABLE_HEADER**)(&madt_ptr)) != AE_OK ) @@ -316,19 +326,11 @@ void InitAPIC(void) { GetProcessorInfoFromACPI(); + InitIOAPIC(); return; } - -void SetupAPIC(void) -{ - //Interrupt 0 from APIC should actually be marked as vector number 32 in IDT. -// asm("cli;"); - return; -} - - /*! \brief The act of writing anything to this register will cause an EOI to be issued. @@ -338,11 +340,10 @@ */ void SendEndOfInterrupt(int int_no) { - eoi_reg->zero = 1; + eoi_reg->zero = 0; } - /*! \brief Initialise SMP environment @@ -357,6 +358,15 @@ BootOtherProcessors(); } + + +/*! + \brief Boot all application processors by calling StartProcessor for each of the processors on the system. + + \param void + + \return void +*/ static void BootOtherProcessors(void) { UINT32 apic_id, processor_count; @@ -369,6 +379,15 @@ } } + + +/*! + \brief Start a application processor by issuing IPI messages in the order: INIT, SIPI, SIPI. + + \param apic_id: apic id of the processor which is to be started. + + \return void +*/ static void StartProcessor(UINT32 apic_id) { int temp_count_processors = count_running_processors; @@ -382,17 +401,17 @@ IssueInterprocessorInterrupt(vector, apic_id, ICR_DELIVERY_MODE_INIT, ICR_DESTINATION_SHORTHAND_NO_SHORTHAND, 0); //delay(10); //I want to sleep for 10m sec - for(temp_loop=0; temp_loop < 1000000; temp_loop++); + for(temp_loop=0; temp_loop < 1000000; temp_loop++); //just an approximate. IssueInterprocessorInterrupt(vector, apic_id, ICR_DELIVERY_MODE_SIPI, ICR_DESTINATION_SHORTHAND_NO_SHORTHAND, 0); //delay(200Micr sec); - for(temp_loop=0; temp_loop < 20000; temp_loop++); + for(temp_loop=0; temp_loop < 20000; temp_loop++); //just an approximate IssueInterprocessorInterrupt(vector, apic_id, ICR_DELIVERY_MODE_SIPI, ICR_DESTINATION_SHORTHAND_NO_SHORTHAND, 0); //delay(200Micr sec); - for(temp_loop=0; temp_loop < 20000; temp_loop++); + for(temp_loop=0; temp_loop < 20000; temp_loop++); //Just an approximate //Now check if AP has started running? if ( temp_count_processors != (count_running_processors + 1) ) @@ -402,4 +421,3 @@ } return; } - Added: src/kernel/pic/ioapic.c =================================================================== --- src/kernel/pic/ioapic.c (rev 0) +++ src/kernel/pic/ioapic.c 2008-08-06 18:52:15 UTC (rev 312) @@ -0,0 +1,191 @@ +/*! + \file ioapic.c + \author DilipSimha N M + \version 3.0 + \date + Created: + Last modified: Wed Aug 06, 2008 11:58PM + \brief Contains APIC stuff in general and LAPIC. +*/ + +#include <ace.h> +#include <kernel/ioapic.h> +#include <kernel/apic.h> + + +IOAPIC_REG_PTR ioapic_reg; + +/*! + \brief Initializies IOAPIC memory mapped registers and redirection table. + + \param void + + \return void +*/ +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); + return; +} + + +/*! + \brief Read data from IOAPIC for the given register. + + \param reg: IOAPIC register to be accessed. + data: Pointer to 32 bit memory in which data is filled from IOAPIC. + + \return void +*/ +void ReadFromIOAPIC(enum IOAPIC_REGISTER reg, UINT32 *data) +{ + ioapic_reg->reg = reg; + *data = ioapic_reg->data; +} + + +/*! + \brief Write to the specified register in IOAPIC. + + \param reg: IOAPIC register to be accessed. + data: 32 bit data that has to be written into the specified register. + + \return void +*/ +void WriteToIOAPIC(enum IOAPIC_REGISTER reg, UINT32 data) +{ + ioapic_reg->reg = reg; + ioapic_reg->data = data; +} + + +/*! + \brief Fetch the IOAPIC ID. + + \param void + + \return 4 bit IOAPIC id. +*/ +UINT8 GetIOAPICId(void) +{ + UINT32 data; + ioapic_reg->reg = IOAPIC_REGISTER_IOAPIC_ID; + data = ioapic_reg->data; + return (UINT8)( ((IOAPIC_ID_PTR)data)->ioapic_id ); +} + +/*! + \brief Set the IOAPIC ID. + + \param ioapic_id: unique id for IOAPIC which is to be set. + + \return void +*/ +void SetIOAPICId(UINT8 ioapic_id) +{ + UINT32 data; + ((IOAPIC_ID_PTR)&data)->ioapic_id = ioapic_id; + ioapic_reg->reg = IOAPIC_REGISTER_IOAPIC_ID; + ioapic_reg->data = data; + return; +} + + +/*! + \brief Get the maximum number of entries in IOAPIC redirection table. These many Interrupt lines are avilable. + + \param void + + \return Positive number of redirection entries. +*/ +UINT8 GetMaximumIOAPICRedirectionEntries(void) +{ + UINT32 data; + ioapic_reg->reg = IOAPIC_REGISTER_IOAPIC_VERSION; + data = ioapic_reg->data; + return (UINT8)( ((IOAPIC_VERSION_PTR)&data)->max_redirection_entries ); +} + + + +/*! + \brief Load the redirection table structure with details obtained from IOAPIC for the required vector. + + \param reg: IOAPIC register that is to be accessed. + table: Pointer to redirection table which has to be loaded with details from IOAPIC. + + \return void +*/ +void GetIOAPICRedirectionTableEntry(enum IOAPIC_REGISTER reg, IOAPIC_REDIRECT_TABLE_PTR table) +{ + UINT32 data; + ioapic_reg->reg = reg; + data = ioapic_reg->data; + + *table = *((IOAPIC_REDIRECT_TABLE_PTR)(&data)); + + ioapic_reg->reg = reg + 0x1; + data = ioapic_reg->data; + + table->destination_field = (data & 0xff000000); //get the MSB 8 bits + return; +} + + +/*! + \brief Set the IOAPIC redirection table with given details. + + \param reg: IOAPIC register that is to be accessed. + table: Pointer to redirection table which has to be loaded with details from IOAPIC. + + \return void +*/ +void SetIOAPICRedirectionTableEntry(enum IOAPIC_REGISTER reg, IOAPIC_REDIRECT_TABLE_PTR table) +{ + UINT32 data = (UINT32)((char*)(table)); + ioapic_reg->reg = reg; + ioapic_reg->data = data; + + data = (UINT32)( (table->destination_field) << 24 ); + + ioapic_reg->reg = reg + 0x1; + ioapic_reg->data = data; + + return; +} + + +/*! + \brief Initial set up the redirection table entry to deliver Interrupts as vector number starting from <starting_vector> + + \param starting_vector: The starting vector number from which interrupts have to be redirected. + + \return 0: Success + -1: Invalid starting vector number. + -2: Invalid max entries in redirection table. +*/ +int InitIOAPICRedirectionTable(int starting_vector) +{ + UINT8 max_entries, i; + IOAPIC_REDIRECT_TABLE redirect_table; + enum IOAPIC_REGISTER reg; + + if (starting_vector < 16 || starting_vector > 230) //254-24 = 230 + return -1; + + //Get the number of maximum redirection table entries supported on this IOAPIC. + max_entries = GetMaximumIOAPICRedirectionEntries(); + if( max_entries > 24) + return -2; + + 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); + } + return 0; +} This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |