Index: c/src/lib/libbsp/i386/pc386/Makefile.am =================================================================== RCS file: /usr1/CVS/rtems/c/src/lib/libbsp/i386/pc386/Makefile.am,v retrieving revision 1.60 diff -u -r1.60 Makefile.am --- c/src/lib/libbsp/i386/pc386/Makefile.am 19 Jun 2011 21:16:36 -0000 1.60 +++ c/src/lib/libbsp/i386/pc386/Makefile.am 27 Jul 2011 18:43:54 -0000 @@ -31,6 +31,11 @@ ../../shared/include/irq-generic.h \ ../../shared/include/irq-info.h +if HAS_SMP +include_bsp_HEADERS += ../../i386/shared/irq/apic.h +include_bsp_HEADERS += ../../i386/shared/smp/smp-imps.h +endif + include_HEADERS += include/crt.h nodist_include_HEADERS += ../../shared/include/coverhd.h @@ -109,8 +114,19 @@ libbsp_a_SOURCES += ide/idecfg.c ide/ide.c if HAS_SMP -libbsp_a_SOURCES += ../../shared/smp/getcpuid.c ../../shared/smp/smp_stub.c \ - ../../shared/smp/bspsmp_wait_for.c +libbsp_a_SOURCES += ../../i386/shared/smp/getcpuid.c +libbsp_a_SOURCES += ../../i386/shared/smp/smp-imps.c + +project_lib_DATA += appstart.$(OBJEXT) +appcpustart.$(OBJEXT): start/start16.S + $(CPPASCOMPILE) $(AM_CPPFLAGS) -DSMP_SECONDARY_CORE -o $@ -c $< + +appstart.$(OBJEXT): appcpustart.$(OBJEXT) + $(LD) -N -T $(top_srcdir)/startup/linkcmds \ + -Ttext 0x70000 -e app_processor_start -nostdlib \ + -o appstart_tmp.exe $< + $(OBJCOPY) -O binary appstart_tmp.exe appstart.bin + $(OBJCOPY) -I binary -O elf32-i386 -B i386 appstart.bin $@ endif if HAS_NETWORKING @@ -144,6 +160,11 @@ libbsp_a_LIBADD = ../../../libcpu/@RTEMS_CPU@/cache.rel \ ../../../libcpu/@RTEMS_CPU@/page.rel \ ../../../libcpu/@RTEMS_CPU@/score.rel + +if HAS_SMP +libbsp_a_LIBADD += appstart.$(OBJEXT) +endif + # We only build the Network library if HAS_NETWORKING was defined # dec21140 is supported via libchip if HAS_NETWORKING Index: c/src/lib/libbsp/i386/pc386/configure.ac =================================================================== RCS file: /usr1/CVS/rtems/c/src/lib/libbsp/i386/pc386/configure.ac,v retrieving revision 1.41 diff -u -r1.41 configure.ac --- c/src/lib/libbsp/i386/pc386/configure.ac 16 Mar 2011 20:05:13 -0000 1.41 +++ c/src/lib/libbsp/i386/pc386/configure.ac 27 Jul 2011 18:43:54 -0000 @@ -85,6 +85,12 @@ [Always defined when on a pc386 to enable the pc386 support for determining the CPU core number in an SMP configuration.]) +## The PC386 BSP supports SMP configurations if this is enabled. +RTEMS_BSPOPTS_SET([BSP_HAS_SMP],[*],[1]) +RTEMS_BSPOPTS_HELP([BSP_HAS_SMP], +[Always defined when on a pc386 to enable the pc386 support for + determining the CPU core number in an SMP configuration.]) + ## if this is an i386, does gas have good code16 support? RTEMS_I386_GAS_CODE16 AM_CONDITIONAL(RTEMS_GAS_CODE16,[test "$RTEMS_GAS_CODE16" = "yes"]) Index: c/src/lib/libbsp/i386/pc386/preinstall.am =================================================================== RCS file: /usr1/CVS/rtems/c/src/lib/libbsp/i386/pc386/preinstall.am,v retrieving revision 1.10 diff -u -r1.10 preinstall.am --- c/src/lib/libbsp/i386/pc386/preinstall.am 14 Mar 2011 14:57:00 -0000 1.10 +++ c/src/lib/libbsp/i386/pc386/preinstall.am 27 Jul 2011 18:43:54 -0000 @@ -73,6 +73,15 @@ $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/bsp/irq-info.h PREINSTALL_FILES += $(PROJECT_INCLUDE)/bsp/irq-info.h +if HAS_SMP +$(PROJECT_INCLUDE)/bsp/apic.h: ../../i386/shared/irq/apic.h $(PROJECT_INCLUDE)/bsp/$(dirstamp) + $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/bsp/apic.h +PREINSTALL_FILES += $(PROJECT_INCLUDE)/bsp/apic.h + +$(PROJECT_INCLUDE)/bsp/smp-imps.h: ../../i386/shared/smp/smp-imps.h $(PROJECT_INCLUDE)/bsp/$(dirstamp) + $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/bsp/smp-imps.h +PREINSTALL_FILES += $(PROJECT_INCLUDE)/bsp/smp-imps.h +endif $(PROJECT_INCLUDE)/crt.h: include/crt.h $(PROJECT_INCLUDE)/$(dirstamp) $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/crt.h PREINSTALL_FILES += $(PROJECT_INCLUDE)/crt.h @@ -122,6 +131,11 @@ $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/uart.h PREINSTALL_FILES += $(PROJECT_INCLUDE)/uart.h +if HAS_SMP +$(PROJECT_LIB)/appstart.$(OBJEXT): appstart.$(OBJEXT) $(PROJECT_LIB)/$(dirstamp) + $(INSTALL_DATA) $< $(PROJECT_LIB)/appstart.$(OBJEXT) +TMPINSTALL_FILES += $(PROJECT_LIB)/appstart.$(OBJEXT) +endif if HAS_NETWORKING $(PROJECT_INCLUDE)/wd80x3.h: include/wd80x3.h $(PROJECT_INCLUDE)/$(dirstamp) $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/wd80x3.h Index: c/src/lib/libbsp/i386/pc386/clock/ckinit.c =================================================================== RCS file: /usr1/CVS/rtems/c/src/lib/libbsp/i386/pc386/clock/ckinit.c,v retrieving revision 1.24 diff -u -r1.24 ckinit.c --- c/src/lib/libbsp/i386/pc386/clock/ckinit.c 10 Mar 2010 17:16:01 -0000 1.24 +++ c/src/lib/libbsp/i386/pc386/clock/ckinit.c 27 Jul 2011 18:43:54 -0000 @@ -18,7 +18,7 @@ * found in the file LICENSE in this distribution or at * http://www.rtems.com/license/LICENSE. * - * $Id: ckinit.c,v 1.24 2010/03/10 17:16:01 joel Exp $ + * $Id$ */ #include @@ -234,6 +234,8 @@ } pc386_clock_click_count = US_TO_TICK(pc386_microseconds_per_isr); + BSP_irq_enable_at_i8259s( BSP_PERIODIC_TIMER - BSP_IRQ_VECTOR_BASE ); + #if 0 printk( "configured usecs per tick=%d \n", rtems_configuration_get_microseconds_per_tick() ); @@ -271,15 +273,33 @@ rtems_isr Clock_isr( rtems_vector_number vector ); + +bool Clock_isr_enabled = false; +void Clock_isr_handler( + rtems_irq_hdl_param param +) +{ + if ( Clock_isr_enabled ) + Clock_isr( 0 ); +} + static rtems_irq_connect_data clockIrqData = { BSP_PERIODIC_TIMER, - (void *)Clock_isr, + Clock_isr_handler, 0, clockOn, clockOff, clockIsOn }; +void Clock_driver_install_handler(void) +{ + if (!BSP_install_rtems_irq_handler (&clockIrqData)) { + printk("Unable to install system clock ISR handler\n"); + rtems_fatal_error_occurred(1); + } +} + void Clock_driver_support_initialize_hardware(void) { bool use_tsc = false; @@ -318,11 +338,7 @@ Clock_driver_nanoseconds_since_last_tick ); - if (!BSP_install_rtems_irq_handler (&clockIrqData)) { - printk("Unable to initialize system clock\n"); - rtems_fatal_error_occurred(1); - } - + Clock_isr_enabled = true; } #define Clock_driver_support_shutdown_hardware() \ Index: c/src/lib/libbsp/i386/pc386/start/start16.S =================================================================== RCS file: /usr1/CVS/rtems/c/src/lib/libbsp/i386/pc386/start/start16.S,v retrieving revision 1.14 diff -u -r1.14 start16.S --- c/src/lib/libbsp/i386/pc386/start/start16.S 20 Jul 2011 16:50:19 -0000 1.14 +++ c/src/lib/libbsp/i386/pc386/start/start16.S 27 Jul 2011 18:43:54 -0000 @@ -37,35 +37,57 @@ | Constants +----------------------------------------------------------------------------*/ +#if defined(SMP_SECONDARY_CORE) +.set PROT_CODE_SEG, 0x08 # offset of code segment descriptor into GDT +#else .set PROT_CODE_SEG, 0x0 # offset of code segment descriptor into GDT +#endif + .set PROT_DATA_SEG, 0x10 # offset of code segment descriptor into GDT .set CR0_PE, 1 # protected mode flag on CR0 register .set HDRSTART, HEADERADDR # address of start of bin2boot header .set HDROFF, 0x24 # offset into bin2boot header of start32 addr .set STACKOFF, 0x200-0x10 # offset to load into %esp, from start of image - /* #define NEW_GAS */ +/* #define NEW_GAS */ +#ifdef NEW_GAS + #define LJMPL ljmpl +#else + #define LJMPL ljmp +#endif + /*----------------------------------------------------------------------------+ | CODE section +----------------------------------------------------------------------------*/ .text - +#if defined(SMP_SECONDARY_CORE) + .globl app_processor_start # entry point +app_processor_start: +#else .globl _start16 # entry point .globl start16 start16: _start16: +#endif .code16 cli # DISABLE INTERRUPTS!!! +#if defined(SMP_SECONDARY_CORE) + jmp 1f + .align 4 +app_cpu_start: + .long 0 +app_cpu_stack: + .long 0 +1: +#endif + movw %cs, %ax # Initialize the rest of + movw %ax, %ds # segment registers + movw %ax, %es + movw %ax, %ss - movw %cs, %ax # - movw %ax, %ds # set the rest of real mode registers - movw %ax, %es # - movw %ax, %ss # - -#if (RTEMS_VIDEO_80x50 == 1) - +#if !defined(SMP_SECONDARY_CODE) && (RTEMS_VIDEO_80x50 == 1) movl $0x0040,%eax # use 32 bit constant to ensure 16 MSB=0 mov %ax,%es movw %es:0x4a, %ax # get 16 bit number of columns @@ -87,26 +109,30 @@ movb $0x01, %ah # define cursor (scan lines 0 to 7) movw $0x0007, %cx int $0x10 - 1: -#endif /* RTEMS_VIDEO_80x50 */ +#endif /* !SMP_SECONDARY_CODE and RTEMS_VIDEO_80x50 */ /*---------------------------------------------------------------------+ | Bare PC machines boot in real mode! We have to turn protected mode on. +---------------------------------------------------------------------*/ +#if defined(SMP_SECONDARY_CORE) + lgdt gdtptr - app_processor_start # load Global Descriptor Table +#else lgdt gdtptr - start16 # load Global Descriptor Table +#endif /* SMP_SECONDARY_CORE */ + movl %cr0, %eax orl $CR0_PE, %eax movl %eax, %cr0 # turn on protected mode - -#ifdef NEW_GAS - ljmpl $PROT_CODE_SEG, $1f # flush prefetch queue, and reload %cs +#if defined(SMP_SECONDARY_CORE) + LJMPL $PROT_CODE_SEG, $2f # flush prefetch queue, and reload %cs #else - ljmp $PROT_CODE_SEG, $1f # flush prefetch queue, and reload %cs + LJMPL $PROT_CODE_SEG, $2f # flush prefetch queue, and reload %cs #endif .code32 -1: +2: + /*---------------------------------------------------------------------+ | load the other segment registers +---------------------------------------------------------------------*/ @@ -114,8 +140,13 @@ movw %ax, %ds movw %ax, %es movw %ax, %ss +#if defined(SMP_SECONDARY_CORE) + movl app_cpu_stack, %esp # stack pointer + movl app_cpu_stack, %ebp # base pointer + #else movl $start16 + STACKOFF, %esp # set up stack pointer addl $start16 + STACKOFF, %ebp # set up stack pointer +#endif /* SMP_SECONDARY_CORE */ /*---------------------------------------------------------------------+ | we have to enable A20 in order to access memory above 1MByte @@ -132,9 +163,14 @@ call pc386_delay call pc386_delay - movl %cs:HDRSTART + HDROFF, %eax # - pushl %eax # jump to start of 32 bit code - ret # +#if defined(SMP_SECONDARY_CORE) + movl app_cpu_start, %eax # jump to app CPU start +#else + movl %cs:HDRSTART + HDROFF, %eax # jump to start of 32 bit code +#endif /* SMP_SECONDARY_CORE */ + pushl %eax + ret + /*----------------------------------------------------------------------------+ | pc386_delay Index: c/src/lib/libbsp/i386/pc386/startup/bspstart.c =================================================================== RCS file: /usr1/CVS/rtems/c/src/lib/libbsp/i386/pc386/startup/bspstart.c,v retrieving revision 1.50 diff -u -r1.50 bspstart.c --- c/src/lib/libbsp/i386/pc386/startup/bspstart.c 28 Jan 2011 20:35:34 -0000 1.50 +++ c/src/lib/libbsp/i386/pc386/startup/bspstart.c 27 Jul 2011 18:43:54 -0000 @@ -27,10 +27,11 @@ | * http://www.rtems.com/license/LICENSE. | ************************************************************************** | -| $Id: bspstart.c,v 1.50 2011/01/28 20:35:34 joel Exp $ +| $Id$ +--------------------------------------------------------------------------*/ #include +#include #include #include @@ -40,6 +41,7 @@ extern void Calibrate_loop_1ms(void); extern void rtems_irq_mngt_init(void); extern void bsp_size_memory(void); +void Clock_driver_install_handler(void); /*-------------------------------------------------------------------------+ | Function: bsp_start @@ -80,6 +82,8 @@ printk("PCI bus: could not initialize PCI BIOS interface\n"); } + Clock_driver_install_handler(); + bsp_ide_cmdline_init(); } /* bsp_start */ Index: c/src/lib/libbsp/i386/pc386/startup/ldsegs.S =================================================================== RCS file: /usr1/CVS/rtems/c/src/lib/libbsp/i386/pc386/startup/ldsegs.S,v retrieving revision 1.20 diff -u -r1.20 ldsegs.S --- c/src/lib/libbsp/i386/pc386/startup/ldsegs.S 28 Jan 2011 20:35:34 -0000 1.20 +++ c/src/lib/libbsp/i386/pc386/startup/ldsegs.S 27 Jul 2011 18:43:54 -0000 @@ -32,7 +32,7 @@ | * http://www.rtems.com/license/LICENSE. | ************************************************************************** | -| $Id: ldsegs.S,v 1.20 2011/01/28 20:35:34 joel Exp $ +| $Id: ldsegs.S,v 1.2 2011/04/01 15:50:05 jennifer Exp $ +--------------------------------------------------------------------------*/ #include @@ -96,7 +96,7 @@ SYM (_load_segments): lgdt SYM(gdtdesc) - lidt SYM(idtdesc) + lidt SYM(IDT_Descriptor) /* Load CS, flush prefetched queue */ ljmp $0x8, $next_step @@ -211,7 +211,8 @@ +--------------------------------------------------------------------------*/ .p2align 4 -SYM(idtdesc): + PUBLIC(IDT_Descriptor) +SYM(IDT_Descriptor): .word (256*8 - 1) .long SYM (Interrupt_descriptor_table) Index: c/src/lib/libbsp/i386/shared/irq/irq_asm.S =================================================================== RCS file: /usr1/CVS/rtems/c/src/lib/libbsp/i386/shared/irq/irq_asm.S,v retrieving revision 1.25 diff -u -r1.25 irq_asm.S --- c/src/lib/libbsp/i386/shared/irq/irq_asm.S 11 Apr 2011 17:16:50 -0000 1.25 +++ c/src/lib/libbsp/i386/shared/irq/irq_asm.S 27 Jul 2011 18:43:54 -0000 @@ -11,7 +11,7 @@ * found in found in the file LICENSE in this distribution or at * http://www.rtems.com/license/LICENSE. * - * $Id: irq_asm.S,v 1.25 2011/04/11 17:16:50 joel Exp $ + * $Id: irq_asm.S,v 1.4 2011/06/09 21:12:54 joel Exp $ */ #include @@ -32,7 +32,7 @@ #define EBP_OFF 12 /* code restoring ebp/esp relies on */ #define ESP_OFF 16 /* esp being on top of ebp! */ #ifdef __SSE__ -/* need to be on 16 byte boundary for SSE */ +/* need to be on 16 byte boundary for SSE, add 12 to do that */ #define FRM_SIZ (20+12+512) #define SSE_OFF 32 #else @@ -46,17 +46,9 @@ * Before this was point is reached the vectors unique * entry point did the following: * - * 1. saved scratch registers registers eax edx ecx" + * 1. saved scratch registers registers eax edx ecx * 2. put the vector number in ecx. * - * BEGINNING OF ESTABLISH SEGMENTS - * - * WARNING: If an interrupt can occur when the segments are - * not correct, then this is where we should establish - * the segments. In addition to establishing the - * segments, it may be necessary to establish a stack - * in the current data area on the outermost interrupt. - * * NOTE: If the previous values of the segment registers are * pushed, do not forget to adjust SAVED_REGS. * @@ -104,9 +96,48 @@ ldmxcsr ARG_OFF(esp) /* clean-slate MXCSR */ #endif +.check_stack_switch: + movl esp, ebp /* ebp = previous stack pointer */ +#if defined(RTEMS_SMP) && defined(BSP_HAS_SMP) + movl $SYM(_Per_CPU_Information_p), ebx + call SYM(bsp_smp_processor_id) + mov (ebx,eax,4), ebx + pushl ecx + call SYM(_ISR_SMP_Enter) + popl ecx + cmpl $0, eax + jne .i8259 + movl PER_CPU_INTERRUPT_STACK_HIGH(ebx), esp + +#else + movl $SYM(_Per_CPU_Information), ebx + + /* + * Is this the outermost interrupt? + * Switch stacks if necessary + */ + cmpl $0, PER_CPU_ISR_NEST_LEVEL(ebx) + jne nested /* No, then continue */ + movl PER_CPU_INTERRUPT_STACK_HIGH(ebx), esp + + /* + * We want to insure that the old stack pointer is in ebp + * By saving it on every interrupt, all we have to do is + * movl ebp->esp near the end of every interrupt. + */ + +nested: + incl PER_CPU_ISR_NEST_LEVEL(ebx) /* one nest level deeper */ + incl SYM (_Thread_Dispatch_disable_level) /* disable multitasking */ +#endif + /* + * i8259 Management + */ + +.i8259: /* Do not disable any 8259 interrupts if this isn't from one */ cmp ecx, 16 /* is this a PIC IRQ? */ - jge .check_stack_switch + jge .end_of_i8259 /* * acknowledge the interrupt @@ -136,44 +167,7 @@ outb $PIC_SLAVE_COMMAND_IO_PORT .master: outb $PIC_MASTER_COMMAND_IO_PORT - - /* - * Now switch stacks if necessary - */ - -PUBLIC (ISR_STOP) -ISR_STOP: -.check_stack_switch: - movl esp, ebp /* ebp = previous stack pointer */ -#if defined(RTEMS_SMP) && defined(BSP_HAS_SMP) - movl $SYM(_Per_CPU_Information_p), ebx - call SYM(bsp_smp_processor_id) - mov (ebx,eax,4), ebx -#else - movl $SYM(_Per_CPU_Information), ebx -#endif - - /* is this the outermost interrupt? */ - cmpl $0, PER_CPU_ISR_NEST_LEVEL(ebx) - jne nested /* No, then continue */ - movl PER_CPU_INTERRUPT_STACK_HIGH(ebx), esp - - /* - * We want to insure that the old stack pointer is in ebp - * By saving it on every interrupt, all we have to do is - * movl ebp->esp near the end of every interrupt. - */ - -nested: - incl PER_CPU_ISR_NEST_LEVEL(ebx) /* one nest level deeper */ - incl SYM (_Thread_Dispatch_disable_level) /* disable multitasking */ - - /* - * GCC versions starting with 4.3 no longer place the cld - * instruction before string operations. We need to ensure - * it is set correctly for ISR handlers. - */ - cld +.end_of_i8259: /* * re-enable interrupts at processor level as the current @@ -216,8 +210,14 @@ outb $PIC_MASTER_IMR_IO_PORT movb ah, al outb $PIC_SLAVE_IMR_IO_PORT - .dont_restore_i8259: + + +#if defined(RTEMS_SMP) && defined(BSP_HAS_SMP) + call SYM(_ISR_SMP_Exit) + testl eax, eax + je .exit +#else decl PER_CPU_ISR_NEST_LEVEL(ebx) /* one less ISR nest level */ /* If interrupts are nested, */ /* then dispatching is disabled */ @@ -231,6 +231,7 @@ /* Is task switch necessary? */ jne .schedule /* Yes, then call the scheduler */ jmp .exit /* No, exit */ +#endif .schedule: /* Index: c/src/lib/libbsp/i386/shared/smp/smp-imps.c =================================================================== RCS file: /usr1/CVS/rtems/c/src/lib/libbsp/i386/shared/smp/smp-imps.c,v retrieving revision 1.3 diff -u -r1.3 smp-imps.c --- c/src/lib/libbsp/i386/shared/smp/smp-imps.c 18 Jul 2011 16:33:30 -0000 1.3 +++ c/src/lib/libbsp/i386/shared/smp/smp-imps.c 27 Jul 2011 18:43:54 -0000 @@ -47,6 +47,16 @@ #define _SMP_IMPS_C /* + * Includes here + */ +#if 0 +#define IMPS_DEBUG +#endif + +#include +#include + +/* * XXXXX The following absolutely must be defined!!! * * The "KERNEL_PRINT" could be made a null macro with no danger, of @@ -63,17 +73,69 @@ #define UDELAY(x) /* delay roughly at least "x" microsecs */ #define TEST_BOOTED(x) /* test bootaddr x to see if CPU started */ #define READ_MSR_LO(x) /* Read MSR low function */ -#endif +#else +#include +#include +#include +#include +#include +#include + +extern void _pc386_delay(void); + +/* #define KERNEL_PRINT(_format) printk(_format) */ + +static void CMOS_WRITE_BYTE( + unsigned int offset, + unsigned char value +) +{ + if ( offset < 128 ) { + outport_byte( 0x70, offset ); + outport_byte( 0x71, value ); + } else { + outport_byte( 0x72, offset ); + outport_byte( 0x73, value ); + } +} -/* - * Includes here - */ +static unsigned char CMOS_READ_BYTE( + unsigned int offset +) +{ + unsigned char value; + if ( offset < 128 ) { + outport_byte( 0x70, offset ); + inport_byte( 0x71, value ); + } else { + outport_byte( 0x72, offset ); + inport_byte( 0x73, value ); + } + return value; +} -#define IMPS_DEBUG +#define PHYS_TO_VIRTUAL(_x) _x +#define VIRTUAL_TO_PHYS(_x) _x +static void UDELAY(int x) +{ int _i = x; + while ( _i-- ) + _pc386_delay(); +} + +#define READ_MSR_LO(_x) \ + (unsigned int)(read_msr(_x) & 0xffffffff) -#include "apic.h" -#include "smp-imps.h" +#define TEST_BOOTED(_cpu) \ + (_Per_CPU_Information[_cpu].state == RTEMS_BSP_SMP_CPU_INITIALIZED) +static inline unsigned long long read_msr(unsigned int msr) +{ + unsigned long long value; + + asm volatile("rdmsr" : "=A" (value) : "c" (msr)); + return value; +} +#endif /* * Defines that are here so as not to be in the global header file. @@ -92,7 +154,6 @@ #define DEF_ENTRIES 23 -static int lapic_dummy = 0; static struct { imps_processor proc[2]; imps_bus bus[2]; @@ -132,10 +193,12 @@ volatile int imps_release_cpus = 0; int imps_enabled = 0; int imps_num_cpus = 1; -unsigned imps_lapic_addr = ((unsigned)(&lapic_dummy)) - LAPIC_ID; unsigned char imps_cpu_apic_map[IMPS_MAX_CPUS]; unsigned char imps_apic_cpu_map[IMPS_MAX_CPUS]; +/* now defined in getcpuid.c */ +extern unsigned imps_lapic_addr; + /* * MPS checksum function * @@ -180,10 +243,10 @@ * This must be modified to perform whatever OS-specific initialization * that is required. */ -static int +int boot_cpu(imps_processor *proc) { - int apicid = proc->apic_id, success = 1, to; + int apicid = proc->apic_id, success = 1; unsigned bootaddr, accept_status; unsigned bios_reset_vector = PHYS_TO_VIRTUAL(BIOS_RESET_VECTOR); @@ -195,10 +258,19 @@ * under the 1MB boundary. */ - extern char patch_code_start[]; - extern char patch_code_end[]; + uint32_t *reset; + bootaddr = (512-64)*1024; - memcpy((char *)bootaddr, patch_code_start, patch_code_end - patch_code_start); + reset= (uint32_t *)bootaddr; + + memcpy( + (char *) bootaddr, + _binary_appstart_bin_start, + (size_t)_binary_appstart_bin_size + ); + + reset[1] = (uint32_t)rtems_smp_secondary_cpu_initialize; + reset[2] = (uint32_t)_Per_CPU_Information[apicid].interrupt_stack_high; /* * Generic CPU startup sequence starts here. @@ -214,8 +286,9 @@ /* assert INIT IPI */ send_ipi( - apicid, LAPIC_ICR_TM_LEVEL | LAPIC_ICR_LEVELASSERT | LAPIC_ICR_DM_INIT); - + apicid, + LAPIC_ICR_TM_LEVEL | LAPIC_ICR_LEVELASSERT | LAPIC_ICR_DM_INIT + ); UDELAY(10000); /* de-assert INIT IPI */ @@ -238,14 +311,17 @@ /* * Check to see if other processor has started. */ - to = 0; - while (!TEST_BOOTED(bootaddr) && to++ < 100) - UDELAY(10000); - if (to >= 100) { - KERNEL_PRINT(("CPU Not Responding, DISABLED")); + bsp_smp_wait_for( + (volatile unsigned int *)&_Per_CPU_Information[imps_num_cpus].state, + RTEMS_BSP_SMP_CPU_INITIALIZED, + 1600 + ); + if ( _Per_CPU_Information[imps_num_cpus].state == + RTEMS_BSP_SMP_CPU_INITIALIZED ) + printk("#%d Application Processor (AP)", imps_num_cpus); + else { + printk("CPU Not Responding, DISABLED"); success = 0; - } else { - KERNEL_PRINT(("#%d Application Processor (AP)", imps_num_cpus)); } /* @@ -260,7 +336,7 @@ CMOS_WRITE_BYTE(CMOS_RESET_CODE, 0); *((volatile unsigned *) bios_reset_vector) = 0; - KERNEL_PRINT(("\n")); + printk("\n"); return success; } @@ -273,14 +349,13 @@ { int apicid = proc->apic_id; - KERNEL_PRINT((" Processor [APIC id %d ver %d]: ", - apicid, proc->apic_ver)); + printk(" Processor [APIC id %d ver %d]: ", apicid, proc->apic_ver); if (!(proc->flags & IMPS_FLAG_ENABLED)) { - KERNEL_PRINT(("DISABLED\n")); + printk("DISABLED\n"); return; } if (proc->flags & (IMPS_CPUFLAG_BOOT)) { - KERNEL_PRINT(("#0 BootStrap Processor (BSP)\n")); + printk("#0 BootStrap Processor (BSP)\n"); return; } if (boot_cpu(proc)) { @@ -301,7 +376,7 @@ memcpy(str, bus->bus_type, 6); str[6] = 0; - KERNEL_PRINT((" Bus id %d is %s\n", bus->id, str)); + printk(" Bus id %d is %s\n", bus->id, str); /* XXXXX add OS-specific code here */ } @@ -309,13 +384,13 @@ static void add_ioapic(imps_ioapic *ioapic) { - KERNEL_PRINT((" I/O APIC id %d ver %d, address: 0x%x ", - ioapic->id, ioapic->ver, ioapic->addr)); + printk(" I/O APIC id %d ver %d, address: 0x%x ", + ioapic->id, ioapic->ver, ioapic->addr); if (!(ioapic->flags & IMPS_FLAG_ENABLED)) { - KERNEL_PRINT(("DISABLED\n")); + printk("DISABLED\n"); return; } - KERNEL_PRINT(("\n")); + printk("\n"); /* XXXXX add OS-specific code here */ } @@ -326,7 +401,10 @@ while (count-- > 0) { switch (*((unsigned char *)start)) { case IMPS_BCT_PROCESSOR: - add_processor((imps_processor *)start); + if ( imps_num_cpus < rtems_configuration_smp_maximum_processors ) { + add_processor((imps_processor *)start); + } else + imps_num_cpus++; start += 12; /* 20 total */ break; case IMPS_BCT_BUS: @@ -350,6 +428,15 @@ } start += 8; } + if ( imps_num_cpus > rtems_configuration_smp_maximum_processors ) { + printk( + "WARNING!! Found more CPUs (%d) than configured for (%d)!!\n", + imps_num_cpus - 1, + rtems_configuration_smp_maximum_processors + ); + imps_num_cpus = rtems_configuration_smp_maximum_processors; + return; + } } static int @@ -360,8 +447,8 @@ = (imps_cth *) PHYS_TO_VIRTUAL(fps_ptr->cth_ptr); if (fps_ptr->feature_info[0] > IMPS_FPS_DEFAULT_MAX) { - KERNEL_PRINT((" Invalid MP System Configuration type %d\n", - fps_ptr->feature_info[0])); + printk(" Invalid MP System Configuration type %d\n", + fps_ptr->feature_info[0]); return 1; } @@ -369,17 +456,17 @@ sum = get_checksum((unsigned)local_cth_ptr, local_cth_ptr->base_length); if (local_cth_ptr->sig != IMPS_CTH_SIGNATURE || sum) { - KERNEL_PRINT( - (" Bad MP Config Table sig 0x%x and/or checksum 0x%x\n", + printk( + " Bad MP Config Table sig 0x%x and/or checksum 0x%x\n", (unsigned)(fps_ptr->cth_ptr), - sum) + sum ); return 1; } if (local_cth_ptr->spec_rev != fps_ptr->spec_rev) { - KERNEL_PRINT( - (" Bad MP Config Table sub-revision # %d\n", - local_cth_ptr->spec_rev) + printk( + " Bad MP Config Table sub-revision # %d\n", + local_cth_ptr->spec_rev ); return 1; } @@ -389,12 +476,12 @@ local_cth_ptr->extended_length) + local_cth_ptr->extended_checksum) & 0xFF; if (sum) { - KERNEL_PRINT((" Bad Extended MP Config Table checksum 0x%x\n", sum)); + printk(" Bad Extended MP Config Table checksum 0x%x\n", sum); return 1; } } } else if (!fps_ptr->feature_info[0]) { - KERNEL_PRINT((" Missing configuration information\n")); + printk(" Missing configuration information\n"); return 1; } @@ -410,15 +497,15 @@ = (imps_cth *)PHYS_TO_VIRTUAL(fps_ptr->cth_ptr); char *str_ptr; - KERNEL_PRINT(("Intel MultiProcessor Spec 1.%d BIOS support detected\n", - fps_ptr->spec_rev)); + printk("Intel MultiProcessor Spec 1.%d BIOS support detected\n", + fps_ptr->spec_rev); /* * Do all checking of errors which would definitely * lead to failure of the SMP boot here. */ if (imps_bad_bios(fps_ptr)) { - KERNEL_PRINT((" Disabling MPS support\n")); + printk(" Disabling MPS support\n"); return; } @@ -432,10 +519,10 @@ } else { imps_lapic_addr = LAPIC_ADDR_DEFAULT; } - KERNEL_PRINT((" APIC config: \"%s mode\" Local APIC address: 0x%x\n", - str_ptr, imps_lapic_addr)); + printk(" APIC config: \"%s mode\" Local APIC address: 0x%x\n", + str_ptr, imps_lapic_addr); if (imps_lapic_addr != (READ_MSR_LO(0x1b) & 0xFFFFF000)) { - KERNEL_PRINT(("Inconsistent Local APIC address, Disabling SMP support\n")); + printk("Inconsistent Local APIC address, Disabling SMP support\n"); return; } imps_lapic_addr = PHYS_TO_VIRTUAL(imps_lapic_addr); @@ -455,7 +542,7 @@ str1[8] = 0; memcpy(str2, local_cth_ptr->prod_id, 12); str2[12] = 0; - KERNEL_PRINT((" OEM id: %s Product id: %s\n", str1, str2)); + printk(" OEM id: %s Product id: %s\n", str1, str2); cth_start = ((unsigned) local_cth_ptr) + sizeof(imps_cth); cth_count = local_cth_ptr->entry_count; } else { @@ -518,8 +605,7 @@ static int imps_scan(unsigned start, unsigned length) { - IMPS_DEBUG_PRINT(("Scanning from 0x%x for %d bytes\n", - start, length)); + printk("Scanning from 0x%x for %d bytes\n", start, length); while (length > 0) { imps_fps *fps_ptr = (imps_fps *) PHYS_TO_VIRTUAL(start); @@ -528,7 +614,7 @@ && fps_ptr->length == 1 && (fps_ptr->spec_rev == 1 || fps_ptr->spec_rev == 4) && !get_checksum(start, 16)) { - IMPS_DEBUG_PRINT(("Found MP Floating Structure Pointer at %x\n", start)); + printk("Found MP Floating Structure Pointer at %x\n", start); imps_read_bios(fps_ptr); return 1; } @@ -540,6 +626,7 @@ return 0; } +#if !defined(__rtems__) /* * This is the primary function to "force" SMP support, with * the assumption that you have consecutively numbered APIC ids. @@ -550,7 +637,7 @@ int apicid, i; imps_processor p; - KERNEL_PRINT(("Intel MultiProcessor \"Force\" Support\n")); + printk("Intel MultiProcessor \"Force\" Support\n"); imps_lapic_addr = (READ_MSR_LO(0x1b) & 0xFFFFF000); imps_lapic_addr = PHYS_TO_VIRTUAL(imps_lapic_addr); @@ -580,6 +667,7 @@ return imps_num_cpus; } +#endif /* * This is the primary function for probing for MPS compatible hardware @@ -661,3 +749,116 @@ return 0; } +/* + * RTEMS SMP BSP Support + */ +void smp_apic_ack(void) +{ + (void) IMPS_LAPIC_READ(LAPIC_SPIV); /* dummy read */ + IMPS_LAPIC_WRITE(LAPIC_EOI, 0 ); /* ACK the interrupt */ +} + +rtems_isr ap_ipi_isr( + rtems_vector_number vector +) +{ + smp_apic_ack(); + + rtems_smp_process_interrupt(); +} + +#include + +static rtems_irq_connect_data apIPIIrqData = { + 16, + (void *)ap_ipi_isr, + 0, + NULL, /* On */ + NULL, /* Off */ + NULL, /* IsOn */ +}; + +extern void bsp_reset(void); +void ipi_install_irq(void) +{ + if (!BSP_install_rtems_irq_handler (&apIPIIrqData)) { + printk("Unable to initialize IPI\n"); + bsp_reset(); + } +} + +#ifdef __SSE__ +extern void enable_sse(void); +#endif + +/* pc386 specific initialization */ +void bsp_smp_secondary_cpu_initialize(int cpu) +{ + int apicid; + + asm volatile( "lidt IDT_Descriptor" ); + + apicid = IMPS_LAPIC_READ(LAPIC_SPIV); + IMPS_LAPIC_WRITE(LAPIC_SPIV, apicid|LAPIC_SPIV_ENABLE_APIC); + +#ifdef __SSE__ + enable_sse(); +#endif +} + +#include +int bsp_smp_initialize( + int maximum +) +{ + int cores; + /* XXX need to deal with finding too many cores */ + + cores = imps_probe(); + + if ( cores > 1 ) + ipi_install_irq(); + return cores; +} + +void bsp_smp_interrupt_cpu( + int cpu +) +{ + send_ipi( cpu, 0x30 ); +} + +void bsp_smp_broadcast_interrupt(void) +{ + /* Single broadcast interrupt */ + send_ipi( 0, LAPIC_ICR_DS_ALLEX | 0x30 ); +} + +void bsp_smp_wait_for( + volatile unsigned int *address, + unsigned int desired, + int maximum_usecs +) +{ + int iterations; + volatile int i; + volatile unsigned int *p = (volatile unsigned int *)address; + + for (iterations=0 ; iterations < maximum_usecs ; iterations++ ) { + if ( *p == desired ) + break; + #ifdef __SSE3__ + __builtin_ia32_monitor( (const void *)address, 0, 0 ); + if ( *p == desired ) + break; + __builtin_ia32_mwait( 0, 0 ); + #endif + + /* + * Until i386 ms delay does not depend upon the clock we + * will use this less sophisticated delay. + */ + for(i=5000; i>0; i--) + ; + } +} Index: c/src/lib/libbsp/i386/shared/smp/smp-imps.h =================================================================== RCS file: /usr1/CVS/rtems/c/src/lib/libbsp/i386/shared/smp/smp-imps.h,v retrieving revision 1.3 diff -u -r1.3 smp-imps.h --- c/src/lib/libbsp/i386/shared/smp/smp-imps.h 18 Jul 2011 16:33:30 -0000 1.3 +++ c/src/lib/libbsp/i386/shared/smp/smp-imps.h 27 Jul 2011 18:43:54 -0000 @@ -37,6 +37,22 @@ * Intel literature center. */ +/* + * This file is based upon code by Eric Boleyn as documented above. + * RTEMS support was added and minimal other changes were made. + * This should make it easier to compare this file with the original + * version. + * + * COPYRIGHT (c) 2011. + * On-Line Applications Research Corporation (OAR). + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + */ + #ifndef _SMP_IMPS_H #define _SMP_IMPS_H @@ -194,47 +210,14 @@ */ /* - * "imps_enabled" is non-zero if the probe sequence found IMPS - * information and was successful. - */ -extern int imps_enabled; - -/* - * This contains the local APIC hardware address. - */ -extern unsigned imps_lapic_addr; - -/* - * This represents the number of CPUs found. - */ -extern int imps_num_cpus; - -/* * These map from virtual cpu numbers to APIC id's and back. */ extern unsigned char imps_cpu_apic_map[IMPS_MAX_CPUS]; extern unsigned char imps_apic_cpu_map[IMPS_MAX_CPUS]; -/* - * This is the primary function for probing for Intel MPS 1.1/1.4 - * compatible hardware and BIOS information. While probing the CPUs - * information returned from the BIOS, this also starts up each CPU - * and gets it ready for use. - * - * Call this during the early stages of OS startup, before memory can - * be messed up. - * - * Returns N if IMPS information was found (for number of CPUs started) - * and is valid, else 0. - */ -int imps_probe(void); - -/* - * This one is used as a "force" function. Give it the number of CPUs - * to start, and it will assume a certain number and try it. - */ -int imps_force(int ncpus); - +/* base address of application processor reset code at 0x70000 */ +extern char _binary_appstart_bin_start[]; +extern char _binary_appstart_bin_size[]; /* * Defines that use variables