📄 pcmb_smp.c
字号:
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 + -