📄 pcmb_smp.c
字号:
//==========================================================================
//
// pcmb_smp.c
//
// HAL SMP implementation
//
//==========================================================================
//####ECOSGPLCOPYRIGHTBEGIN####
// -------------------------------------------
// This file is part of eCos, the Embedded Configurable Operating System.
// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
//
// eCos is free software; you can redistribute it and/or modify it under
// the terms of the GNU General Public License as published by the Free
// Software Foundation; either version 2 or (at your option) any later version.
//
// eCos is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
// for more details.
//
// You should have received a copy of the GNU General Public License along
// with eCos; if not, write to the Free Software Foundation, Inc.,
// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
//
// As a special exception, if other files instantiate templates or use macros
// or inline functions from this file, or you compile this file and link it
// with other works to produce a work based on this file, this file does not
// by itself cause the resulting work to be covered by the GNU General Public
// License. However the source code for this file must still be made available
// in accordance with section (3) of the GNU General Public License.
//
// This exception does not invalidate any other reasons why a work based on
// this file might be covered by the GNU General Public License.
//
// Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
// at http://sources.redhat.com/ecos/ecos-license/
// -------------------------------------------
//####ECOSGPLCOPYRIGHTEND####
//==========================================================================
//#####DESCRIPTIONBEGIN####
//
// Author(s): nickg
// Contributors: nickg
// Date: 2001-08-03
// Purpose: HAL SMP implementation
// Description: This file contains SMP support functions.
//
//####DESCRIPTIONEND####
//
//========================================================================*/
#include <pkgconf/hal.h>
#include <pkgconf/hal_i386.h>
#include <pkgconf/hal_i386_pcmb.h>
#ifdef CYGPKG_HAL_SMP_SUPPORT
#ifdef CYGPKG_KERNEL
#include <pkgconf/kernel.h>
#endif
#include <cyg/infra/cyg_type.h> // Base types
#include <cyg/infra/cyg_trac.h> // tracing macros
#include <cyg/infra/cyg_ass.h> // assertion macros
#include <cyg/infra/diag.h>
#include <cyg/hal/hal_intr.h>
#include <cyg/hal/hal_io.h>
#include <cyg/hal/hal_smp.h>
// ------------------------------------------------------------------------
// Debugging/diagnostic controls
// Setting this to 1 causes the parsing of the MP structures and the
// initialization of the APIC and IOAPIC to be reported on the
// diagnostic channel.
#define SHOW_DIAGNOSTICS 0
// Setting this to 1 causes various things to be displayed on the PC
// screen during normal operation. These are mostly for my own use,
// and may be somewhat obscure to anyone else.
#define SCREEN_DIAGNOSTICS 0
#if SCREEN_DIAGNOSTICS==0
#undef PC_WRITE_SCREEN
#undef PC_WRITE_SCREEN_8
#undef PC_WRITE_SCREEN_16
#undef PC_WRITE_SCREEN_32
#define PC_WRITE_SCREEN( pos, ch )
#define PC_WRITE_SCREEN_8( pos, val )
#define PC_WRITE_SCREEN_16( pos, val )
#define PC_WRITE_SCREEN_32( pos, val )
#endif
// ------------------------------------------------------------------------
static int streq( const char *s1, const char *s2 )
{
while( *s1 == *s2 && *s1 && *s2 ) s1++,s2++;
return !(*s2-*s1);
}
/*------------------------------------------------------------------------*/
// MP FPS structure:
#define MP_FPS_SIGNATURE 0
#define MP_FPS_MPCT 4
#define MP_FPS_LENGTH 8
#define MP_FPS_REV 9
#define MP_FPS_CSUM 10
#define MP_FPS_FEATURE1 11
#define MP_FPS_FEATURE2 12
#define MP_FPS_FEATURE3 13
#define MP_FPS_FEATURE4 14
#define MP_FPS_FEATURE5 15
#define MP_FPS_SIZE 16
#define MP_FPS_SIGNATURE_VALUE 0x5f504d5f
/*------------------------------------------------------------------------*/
// MP config table structure
// Header structure:
#define MPCT_HDR_SIGNATURE 0
#define MPCT_HDR_LENGTH 4
#define MPCT_HDR_REV 6
#define MPCT_HDR_CHECKSUM 7
#define MPCT_HDR_OEM_ID 8
#define MPCT_HDR_PROD_ID 16
#define MPCT_HDR_OEM_TAB 28
#define MPCT_HDR_OEM_TAB_SIZE 32
#define MPCT_HDR_ENTRY_COUNT 34
#define MPCT_HDR_LOCAL_APIC 36
#define MPCT_HDR_XTAB_LENGTH 40
#define MPCT_HDR_XTAB_CHECKSUM 42
#define MPCT_HDR_SIZE 44
#define MPCT_HDR_SIGNATURE_VAL 0x504d4350
#define MPCT_ENTRY_TYPE_PROCESSOR 0
#define MPCT_ENTRY_TYPE_BUS 1
#define MPCT_ENTRY_TYPE_IOAPIC 2
#define MPCT_ENTRY_TYPE_INTERRUPT_IO 3
#define MPCT_ENTRY_TYPE_INTERRUPT_LOCAL 4
#define MPCT_ENTRY_PROC_TYPE 0
#define MPCT_ENTRY_PROC_APIC_ID 1
#define MPCT_ENTRY_PROC_APIC_VER 2
#define MPCT_ENTRY_PROC_CPU_FLAGS 3
#define MPCT_ENTRY_PROC_CPU_SIGNATURE 4
#define MPCT_ENTRY_PROC_FEATURE_FLAGS 8
#define MPCT_ENTRY_PROC_RESERVED0 12
#define MPCT_ENTRY_PROC_RESERVED1 16
#define MPCT_ENTRY_PROC_SIZE 20
#define MPCT_ENTRY_BUS_TYPE 0
#define MPCT_ENTRY_BUS_ID 1
#define MPCT_ENTRY_BUS_TYPE_STRING 2
#define MPCT_ENTRY_BUS_SIZE 8
#define MPCT_ENTRY_IOAPIC_TYPE 0
#define MPCT_ENTRY_IOAPIC_ID 1
#define MPCT_ENTRY_IOAPIC_VER 2
#define MPCT_ENTRY_IOAPIC_FLAGS 3
#define MPCT_ENTRY_IOAPIC_ADDRESS 4
#define MPCT_ENTRY_IOAPIC_SIZE 8
#define MPCT_ENTRY_IOINT_TYPE 0
#define MPCT_ENTRY_IOINT_INT_TYPE 1
#define MPCT_ENTRY_IOINT_FLAGS 2
#define MPCT_ENTRY_IOINT_SOURCE_BUS 4
#define MPCT_ENTRY_IOINT_SOURCE_IRQ 5
#define MPCT_ENTRY_IOINT_DEST_APIC 6
#define MPCT_ENTRY_IOINT_DEST_INT 7
#define MPCT_ENTRY_IOINT_SIZE 8
#define MPCT_ENTRY_LOCINT_TYPE 0
#define MPCT_ENTRY_LOCINT_INT_TYPE 1
#define MPCT_ENTRY_LOCINT_FLAGS 2
#define MPCT_ENTRY_LOCINT_SOURCE_BUS 4
#define MPCT_ENTRY_LOCINT_SOURCE_IRQ 5
#define MPCT_ENTRY_LOCINT_DEST_APIC 6
#define MPCT_ENTRY_LOCINT_DEST_INT 7
#define MPCT_ENTRY_LOCINT_SIZE 8
/*------------------------------------------------------------------------*/
// Exported SMP configuration
CYG_ADDRESS cyg_hal_smp_local_apic;
CYG_ADDRESS cyg_hal_smp_io_apic;
CYG_WORD32 cyg_hal_smp_cpu_count = 0;
CYG_BYTE cyg_hal_smp_cpu_flags[HAL_SMP_CPU_MAX];
CYG_BYTE cyg_hal_isa_bus_id = 0xff;
CYG_BYTE cyg_hal_isa_bus_irq[16];
CYG_BYTE cyg_hal_pci_bus_id = 0xff;
CYG_BYTE cyg_hal_pci_bus_irq[4];
HAL_SPINLOCK_TYPE cyg_hal_ioapic_lock;
/*------------------------------------------------------------------------*/
// Statics
static CYG_ADDRESS mp_fps;
static CYG_ADDRESS mpct;
/*------------------------------------------------------------------------*/
static CYG_WORD32 mp_checksum(CYG_BYTE *p, CYG_WORD32 len)
{
CYG_WORD32 sum = 0;
while (len--) sum += *p++;
return sum & 0xFF;
}
/*------------------------------------------------------------------------*/
static cyg_bool cyg_hal_scan_smp_config( CYG_ADDRESS base, CYG_ADDRWORD size )
{
#if SHOW_DIAGNOSTICS
diag_printf("Scan for MP struct: %08x..%08x\n",base,base+size);
#endif
while( size > 0 )
{
CYG_WORD32 sig;
HAL_READMEM_UINT32( base, sig );
if( sig == MP_FPS_SIGNATURE_VALUE )
{
CYG_BYTE val8;
// We have a candidate for the floating structure
#if SHOW_DIAGNOSTICS
diag_printf("MP_FPS candidate found at %08x\n",base);
#endif
HAL_READMEM_UINT8( base+MP_FPS_LENGTH, val8 );
if( val8 != 1 )
break;
HAL_READMEM_UINT8( base+MP_FPS_REV, val8 );
if( val8 != 1 && val8 != 4 )
break;
if( mp_checksum( (CYG_BYTE *)base, MP_FPS_SIZE ) != 0 )
break;
mp_fps = base;
HAL_READMEM_UINT32( base+MP_FPS_MPCT, mpct );
#if SHOW_DIAGNOSTICS
diag_printf("MPCT at %08x\n",mpct);
#endif
return 1;
}
base += 16;
size -= 16;
}
return 0;
}
/*------------------------------------------------------------------------*/
static cyg_bool cyg_hal_find_smp_config( void )
{
// check bottom 1k
if( cyg_hal_scan_smp_config(0x00000, 0x00400 ) )
return 1;
// check top 1k of RAM
if( cyg_hal_scan_smp_config(0x9fc00, 0x00400 ) )
return 1;
// check BIOS ROM
if( cyg_hal_scan_smp_config(0xf0000, 0x10000 ) )
return 1;
}
/*------------------------------------------------------------------------*/
static cyg_bool cyg_hal_parse_smp_config( void )
{
CYG_WORD32 val32;
CYG_WORD16 val16;
CYG_BYTE val8;
int i;
#if SHOW_DIAGNOSTICS
{
diag_printf("FPS address: %08x\n",mp_fps);
HAL_READMEM_UINT32( mp_fps+MP_FPS_SIGNATURE, val32);
diag_printf("FPS signature: %08x\n",val32);
HAL_READMEM_UINT32( mp_fps+MP_FPS_MPCT, val32);
diag_printf("FPS MPCT address: %08x\n",val32);
HAL_READMEM_UINT8( mp_fps+MP_FPS_LENGTH, val8);
diag_printf("FPS length: %02x\n",val8);
HAL_READMEM_UINT8( mp_fps+MP_FPS_REV, val8);
diag_printf("FPS spec rev: %02x\n",val8);
HAL_READMEM_UINT8( mp_fps+MP_FPS_CSUM, val8);
diag_printf("FPS checksum: %02x\n",val8);
for( i = 0; i < 5; i++ )
{
HAL_READMEM_UINT8( mp_fps+MP_FPS_FEATURE1, val8);
diag_printf("FPS feature byte %d: %02x\n",i,val8);
}
}
#endif
if( mpct )
{
HAL_READMEM_UINT32( mpct+MPCT_HDR_SIGNATURE, val32);
if( val32 != MPCT_HDR_SIGNATURE_VAL )
return 0;
HAL_READMEM_UINT16( mpct+MPCT_HDR_LENGTH, val16);
if( mp_checksum( (CYG_BYTE *)mpct, val16 ) != 0 )
return 0;
#if SHOW_DIAGNOSTICS
{
char id[13];
diag_printf("MPCT address: %08x\n",mpct);
HAL_READMEM_UINT32( mpct+MPCT_HDR_SIGNATURE, val32);
diag_printf("MPCT signature: %08x\n",val32);
HAL_READMEM_UINT16( mpct+MPCT_HDR_LENGTH, val16);
diag_printf("MPCT length: %04x\n",val16);
HAL_READMEM_UINT8( mpct+MPCT_HDR_REV, val8);
diag_printf("MPCT spec rev: %02x\n",val8);
HAL_READMEM_UINT8( mpct+MPCT_HDR_CHECKSUM, val8);
diag_printf("MPCT checksum: %02x\n",val8);
for( i = 0; i < 8; i++ )
{
HAL_READMEM_UINT8( mpct+MPCT_HDR_OEM_ID+i, val8);
id[i] = val8;
}
id[i] = 0;
diag_printf("MPCT OEM Id: %s\n",id);
for( i = 0; i < 12; i++ )
{
HAL_READMEM_UINT8( mpct+MPCT_HDR_PROD_ID+i, val8);
id[i] = val8;
}
id[i] = 0;
diag_printf("MPCT Product Id: %s\n",id);
HAL_READMEM_UINT32( mpct+MPCT_HDR_OEM_TAB, val32);
diag_printf("MPCT OEM table: %08x\n",val32);
HAL_READMEM_UINT16( mpct+MPCT_HDR_OEM_TAB_SIZE, val16);
diag_printf("MPCT OEM table size: %04x\n",val16);
HAL_READMEM_UINT16( mpct+MPCT_HDR_ENTRY_COUNT, val16);
diag_printf("MPCT entry count: %04x\n",val16);
HAL_READMEM_UINT32( mpct+MPCT_HDR_LOCAL_APIC, val32);
diag_printf("MPCT local APIC: %08x\n",val32);
HAL_READMEM_UINT16( mpct+MPCT_HDR_XTAB_LENGTH, val16);
diag_printf("MPCT extended table length: %04x\n",val16);
HAL_READMEM_UINT8( mpct+MPCT_HDR_XTAB_CHECKSUM, val8);
diag_printf("MPCT extended table checksum: %02x\n",val8);
}
#endif
// Extract the data we need from the structure
HAL_READMEM_UINT32( mpct+MPCT_HDR_LOCAL_APIC, cyg_hal_smp_local_apic);
// now parse the base table, looking for processor and IOAPIC entries.
{
CYG_WORD16 entries;
CYG_ADDRESS entry = mpct + MPCT_HDR_SIZE;
HAL_READMEM_UINT16( mpct+MPCT_HDR_ENTRY_COUNT, entries);
#if SHOW_DIAGNOSTICS
diag_printf("\nBase table:\n");
#endif
while( entries-- )
{
CYG_BYTE type;
HAL_READMEM_UINT8( entry, type );
switch( type )
{
case MPCT_ENTRY_TYPE_PROCESSOR:
#if SHOW_DIAGNOSTICS
diag_printf(" Processor\n");
HAL_READMEM_UINT8( entry+MPCT_ENTRY_PROC_APIC_ID, val8 );
diag_printf(" APIC ID: %02x\n",val8);
HAL_READMEM_UINT8( entry+MPCT_ENTRY_PROC_APIC_VER, val8 );
diag_printf(" APIC Version: %02x\n",val8);
HAL_READMEM_UINT8( entry+MPCT_ENTRY_PROC_CPU_FLAGS, val8 );
diag_printf(" CPU Flags: %02x\n",val8);
HAL_READMEM_UINT8( entry+MPCT_ENTRY_PROC_CPU_SIGNATURE, val32 );
diag_printf(" CPU Signature: %08x\n",val32);
HAL_READMEM_UINT8( entry+MPCT_ENTRY_PROC_FEATURE_FLAGS, val32 );
diag_printf(" Feature flags: %08x\n",val32);
#endif
{
CYG_BYTE cpuid;
// Index CPUs by their APIC IDs
HAL_READMEM_UINT8( entry+MPCT_ENTRY_PROC_APIC_ID, cpuid );
// Get flags for this CPU.
HAL_READMEM_UINT8(entry+MPCT_ENTRY_PROC_CPU_FLAGS, cyg_hal_smp_cpu_flags[cpuid]);
cyg_hal_smp_cpu_count++; // count another CPU
}
entry += MPCT_ENTRY_PROC_SIZE;
break;
case MPCT_ENTRY_TYPE_BUS:
{
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -