⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 pcmb_smp.c

📁 开放源码实时操作系统源码.
💻 C
📖 第 1 页 / 共 3 页
字号:
                        CYG_BYTE id;
                        char bustype[7];
                        HAL_READMEM_UINT8( entry+MPCT_ENTRY_BUS_ID, id );
#if SHOW_DIAGNOSTICS                    
                        diag_printf("        Bus\n");
                        diag_printf("                ID:                       %02x\n",id);
#endif
                        {
                            int i;
                            for( i = 0; i < 6; i++ )
                            {
                                HAL_READMEM_UINT8( entry+MPCT_ENTRY_BUS_TYPE_STRING+i, val8 );
                                bustype[i] = val8;
                            }
                            bustype[i] = 0;
#if SHOW_DIAGNOSTICS
                            diag_printf("                Type:                     %s\n",&bustype[0]);
#endif                            
                        }

                        if( streq( bustype, "ISA   " ) )
                        {
                            cyg_hal_isa_bus_id = id;
                            for( i = 0; i < 16; i++ )
                                cyg_hal_isa_bus_irq[i] = 100;
                        }
                        if( streq( bustype, "PCI   " ) )
                        {
                            cyg_hal_pci_bus_id = id;
                        }
                    }

                    entry += MPCT_ENTRY_BUS_SIZE;
                    break;

                case MPCT_ENTRY_TYPE_IOAPIC:
#if SHOW_DIAGNOSTICS                    
                    diag_printf("        I/O APIC\n");
                    HAL_READMEM_UINT8( entry+MPCT_ENTRY_IOAPIC_ID, val8 );
                    diag_printf("                ID:                       %02x\n",val8);
                    HAL_READMEM_UINT8( entry+MPCT_ENTRY_IOAPIC_VER, val8 );
                    diag_printf("                Version:                  %02x\n",val8);
                    HAL_READMEM_UINT8( entry+MPCT_ENTRY_IOAPIC_FLAGS, val8 );
                    diag_printf("                Flags:                    %02x\n",val8);
                    HAL_READMEM_UINT32( entry+MPCT_ENTRY_IOAPIC_ADDRESS, val32 );
                    diag_printf("                Address:                  %08x\n",val32);
#endif

                    HAL_READMEM_UINT32( entry+MPCT_ENTRY_IOAPIC_ADDRESS, cyg_hal_smp_io_apic );
                    entry += MPCT_ENTRY_IOAPIC_SIZE;                
                    break;

                case MPCT_ENTRY_TYPE_INTERRUPT_IO:
                    {
                        CYG_BYTE bus, irq, dst;
                        HAL_READMEM_UINT8( entry+MPCT_ENTRY_IOINT_SOURCE_BUS, bus );
                        HAL_READMEM_UINT8( entry+MPCT_ENTRY_IOINT_SOURCE_IRQ, irq );
                        HAL_READMEM_UINT8( entry+MPCT_ENTRY_IOINT_DEST_INT, dst );
#if SHOW_DIAGNOSTICS                    
                        diag_printf("        I/O interrupt assignment\n");
                        HAL_READMEM_UINT8( entry+MPCT_ENTRY_IOINT_TYPE, val8 );
                        diag_printf("                Type:                     %02x\n",val8);
                        HAL_READMEM_UINT16( entry+MPCT_ENTRY_IOINT_TYPE, val16 );
                        diag_printf("                Flags:                    %04x\n",val16);
                        diag_printf("                Source bus:               %02x\n",bus);
                        diag_printf("                Source IRQ:               %02x\n",irq);
                        HAL_READMEM_UINT8( entry+MPCT_ENTRY_IOINT_DEST_APIC, val8 );
                        diag_printf("                Dest APIC:                %02x\n",val8);
                        diag_printf("                Dest Interrupt:           %02x\n",dst);
#endif

                        if( bus == cyg_hal_isa_bus_id )
                            cyg_hal_isa_bus_irq[irq] = dst;
//                        if( bus == cyg_hal_pci_bus_id )
//                            cyg_hal_pci_bus_irq[irq] = dst;
                    
                    }
                    entry += MPCT_ENTRY_IOINT_SIZE;
                    break;

                case MPCT_ENTRY_TYPE_INTERRUPT_LOCAL:
#if SHOW_DIAGNOSTICS                    
                    diag_printf("        Local interrupt assignment\n");
                    HAL_READMEM_UINT8( entry+MPCT_ENTRY_IOINT_TYPE, val8 );
                    diag_printf("                Type:                     %02x\n",val8);
                    HAL_READMEM_UINT16( entry+MPCT_ENTRY_IOINT_TYPE, val16 );
                    diag_printf("                Flags:                    %04x\n",val16);
                    HAL_READMEM_UINT8( entry+MPCT_ENTRY_IOINT_SOURCE_BUS, val8 );
                    diag_printf("                Source bus:               %02x\n",val8);
                    HAL_READMEM_UINT8( entry+MPCT_ENTRY_IOINT_SOURCE_IRQ, val8 );
                    diag_printf("                Source IRQ:               %02x\n",val8);
                    HAL_READMEM_UINT8( entry+MPCT_ENTRY_IOINT_DEST_APIC, val8 );
                    diag_printf("                Dest APIC:                %02x\n",val8);
                    HAL_READMEM_UINT8( entry+MPCT_ENTRY_IOINT_DEST_INT, val8 );
                    diag_printf("                Dest Interrupt:           %02x\n",val8);
#endif
                    entry += MPCT_ENTRY_LOCINT_SIZE;
                    break;
                
                default:
#if SHOW_DIAGNOSTICS                    
                    diag_printf("        MPCT Entry: unknown type %02x\n",type);
#endif                    
                    entry += 8;
                    break;
                }
            
            }
        
        }
    }

#if SHOW_DIAGNOSTICS

    diag_printf("Exported configuration:\n");
    diag_printf("        Local APIC: %08x\n", cyg_hal_smp_local_apic );
    diag_printf("        I/O APIC:   %08x\n", cyg_hal_smp_io_apic );
    diag_printf("        CPU count:  %d\n", cyg_hal_smp_cpu_count );

    for( i = 0; i < cyg_hal_smp_cpu_count; i++ )
    {
        diag_printf("            CPU %d %sactive %s\n",i,
                    ((cyg_hal_smp_cpu_flags[i]&1)?"":"in"),
                    ((cyg_hal_smp_cpu_flags[i]&2)?"master":"slave")
            );
    }

    diag_printf("        ISA IRQ map:\n");

    for( i = 0; i < 16; i++ )
    {
        diag_printf("            IRQ %2d -> IOAPIC INT %2d\n",i,cyg_hal_isa_bus_irq[i]);
    }
    
#endif    
    
    return 1;
}

/*------------------------------------------------------------------------*/
// Init local APIC

static cyg_bool cyg_hal_smp_init_apic(void)
{
    
    cyg_uint32 maxlvt;
    cyg_uint32 val;
    HAL_SMP_CPU_TYPE cpu;
    
    HAL_APIC_READ(HAL_APIC_ID, val );
    cpu = val>>24;
    
#if SHOW_DIAGNOSTICS
    diag_printf("Local APIC: %08x\n",cyg_hal_smp_local_apic);
    diag_printf("        ID:             %08x\n",val);
#endif    
    // get max local vector table entry offset
    HAL_APIC_READ(HAL_APIC_VER, maxlvt );
#if SHOW_DIAGNOSTICS
    diag_printf("        VERSION:        %08x\n",maxlvt);
#endif
    maxlvt >>= 16;
    maxlvt &= 0xFF;

    
#if SHOW_DIAGNOSTICS
    diag_printf("maxlvt = %d\n",maxlvt);
#endif

    // Start by ensuring that all interrupt sources are disabled. The
    // following code ensures that this happens cleanly.
    
    // Local timer vector
    HAL_APIC_READ( HAL_APIC_LVT_TIMER, val );
    val |= HAL_APIC_LVT_MASK ;
    HAL_APIC_WRITE( HAL_APIC_LVT_TIMER, val );

#if SHOW_DIAGNOSTICS
    diag_printf("        APIC_LVT_TIMER: %08x\n",val);
#endif
    
    // Local interrupt vectors
    HAL_APIC_READ( HAL_APIC_LVT_INT0, val );
    val |= HAL_APIC_LVT_MASK ;
    HAL_APIC_WRITE( HAL_APIC_LVT_INT0, val );

#if SHOW_DIAGNOSTICS
    diag_printf("        APIC_LVT_INT0:  %08x\n",val);
#endif

    HAL_APIC_READ( HAL_APIC_LVT_INT1, val );
    val |= HAL_APIC_LVT_MASK ;
    HAL_APIC_WRITE( HAL_APIC_LVT_INT1, val );

#if SHOW_DIAGNOSTICS
    diag_printf("        APIC_LVT_INT1:  %08x\n",val);
#endif
 
    if (maxlvt >= 3 )
    {
        HAL_APIC_READ( HAL_APIC_LVT_ERROR, val );
        val |= HAL_APIC_LVT_MASK ;
        HAL_APIC_WRITE( HAL_APIC_LVT_ERROR, val );
#if SHOW_DIAGNOSTICS
        diag_printf("        APIC_LVT_ERROR: %08x\n",val);
#endif 
    }
    if (maxlvt >= 4 )
    {
        HAL_APIC_READ( HAL_APIC_LVT_PC, val );
        val |= HAL_APIC_LVT_MASK ;
        HAL_APIC_WRITE( HAL_APIC_LVT_PC, val );
#if SHOW_DIAGNOSTICS
        diag_printf("        APIC_LVT_PC:    %08x\n",val);
#endif 
    }

    // Now initialize the local vector table.
    
    HAL_APIC_WRITE( HAL_APIC_LVT_TIMER, HAL_APIC_LVT_MASK );
    HAL_APIC_WRITE( HAL_APIC_LVT_INT0, HAL_APIC_LVT_MASK );
    HAL_APIC_WRITE( HAL_APIC_LVT_INT1, HAL_APIC_LVT_MASK );
    if( maxlvt >= 3 )
        HAL_APIC_WRITE( HAL_APIC_LVT_ERROR, HAL_APIC_LVT_MASK );
    if( maxlvt >= 4 )
        HAL_APIC_WRITE( HAL_APIC_LVT_PC, HAL_APIC_LVT_MASK );


    // Set up DFR to flat delivery mode.
    HAL_APIC_WRITE( HAL_APIC_DFR, 0xffffffff );

    // Set up logical destination id. We set bit 1<<cpuid in the LDR
    // register.

    HAL_APIC_READ( HAL_APIC_LDR, val );
    val |= 1<<(cpu+24);
    HAL_APIC_WRITE( HAL_APIC_LDR, val );

    // Set TPR register to accept all.
    HAL_APIC_WRITE( HAL_APIC_TPR, 0 );

    // Enable APIC in SPIV
    HAL_APIC_WRITE( HAL_APIC_SPIV, 0x00000100 );

    
    if( cyg_hal_smp_cpu_flags[HAL_SMP_CPU_THIS()] & 2 )
    {
        // This is the boot CPU, switch its PIC into APIC mode
        // Non-boot CPUs are already in APIC mode.
        
        HAL_WRITE_UINT8( 0x22, 0x70 );
        HAL_WRITE_UINT8( 0x23, 0x01 );
    }
    
    return 1;
}

/*------------------------------------------------------------------------*/
// Initialize I/O APIC

static cyg_bool cyg_hal_smp_init_ioapic(void)
{
    CYG_WORD32 val;
    cyg_uint32 tabsize = 0;
    int i;
    HAL_SMP_CPU_TYPE cpu_this = HAL_SMP_CPU_THIS();

    HAL_SPINLOCK_CLEAR( cyg_hal_ioapic_lock );
    HAL_SPINLOCK_SPIN( cyg_hal_ioapic_lock );
    
    HAL_IOAPIC_READ( HAL_IOAPIC_REG_APICVER, val );
    tabsize = (val>>16)&0xFF;

    // Set up ISA interrupts
    for( i = 0; i < 16; i++ )
    {
        if( cyg_hal_isa_bus_irq[i] != 100 )
        {
            CYG_WORD32 tehi = 0, telo = 0x00010000;

            tehi |= cpu_this<<24;

            telo |= CYGNUM_HAL_ISR_MIN+i;
            
            HAL_IOAPIC_WRITE( HAL_IOAPIC_REG_REDIR_LO(cyg_hal_isa_bus_irq[i]), telo );
            HAL_IOAPIC_WRITE( HAL_IOAPIC_REG_REDIR_HI(cyg_hal_isa_bus_irq[i]), tehi );
        }
    }

    
#if SHOW_DIAGNOSTICS    
    diag_printf("I/O APIC: %08x\n",cyg_hal_smp_io_apic);

    HAL_IOAPIC_READ( HAL_IOAPIC_REG_APICID, val );
    diag_printf("        ID: %08x\n",val);

    HAL_IOAPIC_READ( HAL_IOAPIC_REG_APICVER, val );
    diag_printf("        VER: %08x\n",val);

    HAL_IOAPIC_READ( HAL_IOAPIC_REG_APICARB, val );
    diag_printf("        ARB: %08x\n",val);

    diag_printf("        Redirection Table:\n");
    for( i = 0; i < tabsize; i++ )
    {
        CYG_WORD32 tehi, telo;

        HAL_IOAPIC_READ( HAL_IOAPIC_REG_REDIR_LO(i), telo );
        HAL_IOAPIC_READ( HAL_IOAPIC_REG_REDIR_HI(i), tehi );
        diag_printf("            %02d: %08x %08x\n",i,tehi,telo);
    }
#endif

    HAL_SPINLOCK_CLEAR( cyg_hal_ioapic_lock );

    return 1;
}

/*------------------------------------------------------------------------*/

static volatile CYG_WORD32 init_deasserted;

__externC volatile CYG_WORD32 cyg_hal_smp_cpu_sync_flag[HAL_SMP_CPU_MAX];
__externC volatile CYG_WORD32 cyg_hal_smp_cpu_sync[HAL_SMP_CPU_MAX];
__externC volatile void (*cyg_hal_smp_cpu_entry[HAL_SMP_CPU_MAX])(void);
__externC volatile CYG_WORD32 cyg_hal_smp_vsr_sync_flag;
__externC volatile CYG_WORD32 cyg_hal_smp_cpu_running[HAL_SMP_CPU_MAX];

/*------------------------------------------------------------------------*/

__externC void cyg_hal_smp_start(void);

__externC CYG_BYTE cyg_hal_slave_trampoline[];
__externC CYG_BYTE cyg_hal_slave_trampoline_end[];

#define HAL_SLAVE_START_ADDRESS 0x00002000

__externC void cyg_hal_cpu_start( HAL_SMP_CPU_TYPE cpu )
{
#if 1
    CYG_WORD32 icrlo, icrhi;
    CYG_BYTE *p = &cyg_hal_slave_trampoline[0];
    CYG_BYTE *q = (CYG_BYTE *)HAL_SLAVE_START_ADDRESS;
    CYG_BYTE old_cmos;
    int i;
    
    // Copy the trampoline over...
    do
    {
        *q++ = *p++;
    } while( p != &cyg_hal_slave_trampoline_end[0]);

    // Init synchronization spinlock to locked to halt slave CPU in
    // cyg_hal_smp_startup().

    init_deasserted = 0;
    
    // We now have to execute the grungy and unpleasant AP startup
    // sequence to get the cpu running. I'm sure that not all of this
    // is strictly necessary, but it works and it is too much effort
    // to work out the minimal subset.

    // Write warm-reset code into CMOS RAM and write the address of
    // the trampoline entry point into location 40:67.
    HAL_READ_CMOS( 0x0f, old_cmos );
    HAL_WRITE_CMOS( 0x0f, 0x0a );
    HAL_WRITEMEM_UINT16( 0x467, HAL_SLAVE_START_ADDRESS & 0xf );
    HAL_WRITEMEM_UINT16( 0x469, HAL_SLAVE_START_ADDRESS>>4 );
    
    
    // Send an INIT interrupt to the dest CPU
    icrhi = cpu<<24;
    icrlo = 0x0000C500;

    HAL_APIC_WRITE( HAL_APIC_ICR_HI, icrhi );
    HAL_APIC_WRITE( HAL_APIC_ICR_LO, icrlo );

    hal_delay_us( 10 * 1000 );  // Wait 10ms

    // Wait for the ICR to become inactive
    do {
        HAL_APIC_READ( HAL_APIC_ICR_LO, icrlo );
    } while( (icrlo & 0x00001000) != 0 );

    // Now de-assert INIT

    icrlo = 0x00008500;

    HAL_APIC_WRITE( HAL_APIC_ICR_HI, icrhi );    
    HAL_APIC_WRITE( HAL_APIC_ICR_LO, icrlo );

    init_deasserted = 1;

    // Now we send two STARTUP IPIs

    for( i = 0; i < 2; i++ )
    {
        icrlo = 0x00000600 | (HAL_SLAVE_START_ADDRESS>>12);

        // Send the STARTUP IPI
        HAL_APIC_WRITE( HAL_APIC_ICR_HI, icrhi );
        HAL_APIC_WRITE( HAL_APIC_ICR_LO, icrlo );

        hal_delay_us( 300 );
        
        // Wait for the ICR to become inactive
        do {
            HAL_APIC_READ( HAL_APIC_ICR_LO, icrlo );
        } while( (icrlo & 0x00001000) != 0 );

        hal_delay_us( 300 );
    }
    
    HAL_WRITE_CMOS( 0x0f, old_cmos );

//    PC_WRITE_SCREEN( PC_SCREEN_LINE(5)+0, '!' );    

    hal_delay_us( 300 );
    
//    PC_WRITE_SCREEN( PC_SCREEN_LINE(5)+1, '!' );    

#endif    
}

/*------------------------------------------------------------------------*/

__externC void cyg_hal_smp_start(void);
__externC void cyg_hal_smp_startup(void);

__externC void cyg_hal_cpu_release( HAL_SMP_CPU_TYPE cpu )
{
//    PC_WRITE_SCREEN( PC_SCREEN_LINE(13), '!' );            
//    PC_WRITE_SCREEN_8( PC_SCREEN_LINE(13), cpu );
    
    cyg_hal_smp_cpu_entry[cpu] = cyg_hal_smp_start;

    while( cyg_hal_smp_cpu_entry[cpu] != 0 )
    {
//        PC_WRITE_SCREEN_32( PC_SCREEN_LINE(13)+4, cyg_hal_smp_cpu_entry[cpu] );
        hal_delay_us( 100 );
         continue;
    }
}

/*------------------------------------------------------------------------*/

__externC void cyg_hal_smp_startup(void)

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -