/* * kernel_init.c - kernel parallel initialization * * Authors : Mohamed Lamine Karaoui (2015) * Alain Greiner (2016,2017) * * Copyright (c) Sorbonne Universites * * This file is part of ALMOS-MKH. * * ALMOS-MKH 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; version 2.0 of the License. * * ALMOS-MKH 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 ALMOS-MKH; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define KERNEL_INIT_SYNCHRO 0xA5A5B5B5 /////////////////////////////////////////////////////////////////////////////////////////// // All these global variables are replicated in all clusters. // They are initialised by the kernel_init() function. // // WARNING : The section names have been defined to control the base addresses of the // boot_info structure and the idle thread descriptors, through the kernel.ld script: // - the boot_info structure is build by the bootloader, and used by kernel_init. // it must be first object in the kdata segment. // - the array of idle threads descriptors must be placed on the first page boundary after // the boot_info structure in the kdata segment. /////////////////////////////////////////////////////////////////////////////////////////// // This variable defines the local boot_info structure __attribute__((section(".kinfo"))) boot_info_t boot_info; // This variable defines the "idle" threads descriptors array __attribute__((section(".kidle"))) char idle_threads[CONFIG_THREAD_DESC_SIZE * CONFIG_MAX_LOCAL_CORES] CONFIG_PPM_PAGE_ALIGNED; // This variable defines the local cluster manager __attribute__((section(".kdata"))) cluster_t cluster_manager CONFIG_CACHE_LINE_ALIGNED; // This variables define the kernel process0 descriptor __attribute__((section(".kdata"))) process_t process_zero CONFIG_CACHE_LINE_ALIGNED; // This variable defines extended pointers on the distributed chdevs __attribute__((section(".kdata"))) chdev_directory_t chdev_dir CONFIG_CACHE_LINE_ALIGNED; // This variable contains the input IRQ indexes for the PIC device __attribute__((section(".kdata"))) chdev_pic_input_t chdev_pic_input CONFIG_CACHE_LINE_ALIGNED; // This variable contains the input IRQ indexes for the ICU device __attribute__((section(".kdata"))) chdev_icu_input_t chdev_icu_input CONFIG_CACHE_LINE_ALIGNED; // This variable defines the local cluster identifier __attribute__((section(".kdata"))) cxy_t local_cxy CONFIG_CACHE_LINE_ALIGNED; // This variable defines the TXT0 chdev descriptor __attribute__((section(".kdata"))) chdev_t txt0_chdev CONFIG_CACHE_LINE_ALIGNED; // This variable is used for CP0 cores sychronisation in kernel_init() __attribute__((section(".kdata"))) remote_barrier_t global_barrier CONFIG_CACHE_LINE_ALIGNED; // This variable is used for local cores sychronisation in kernel_init() __attribute__((section(".kdata"))) barrier_t local_barrier CONFIG_CACHE_LINE_ALIGNED; // This variable defines the array of supported File System contexts __attribute__((section(".kdata"))) vfs_ctx_t fs_context[FS_TYPES_NR] CONFIG_CACHE_LINE_ALIGNED; /////////////////////////////////////////////////////////////////////////////////////////// // This function displays the ALMOS_MKH banner. /////////////////////////////////////////////////////////////////////////////////////////// static void print_banner( uint32_t nclusters , uint32_t ncores ) { printk("\n" " _ __ __ _____ ______ __ __ _ __ _ _ \n" " /\\ | | | \\ / | / ___ \\ / _____| | \\ / | | | / / | | | | \n" " / \\ | | | \\/ | | / \\ | | / | \\/ | | |/ / | | | | \n" " / /\\ \\ | | | |\\ /| | | | | | | |_____ ___ | |\\ /| | | / | |___| | \n" " / /__\\ \\ | | | | \\/ | | | | | | \\_____ \\ |___| | | \\/ | | | \\ | ___ | \n" " / ______ \\ | | | | | | | | | | | | | | | | | |\\ \\ | | | | \n" " / / \\ \\ | |____ | | | | | \\___/ | _____/ | | | | | | | \\ \\ | | | | \n" " /_/ \\_\\ |______| |_| |_| \\_____/ |______/ |_| |_| |_| \\_\\ |_| |_| \n" "\n\n\t\t Advanced Locality Management Operating System / Multi Kernel Hybrid\n" "\n\n\t\t\t Version 0.0 : %d clusters / %d cores per cluster\n\n", nclusters , ncores ); } /////////////////////////////////////////////////////////////////////////////////////////// // This static function initializes the TXT0 chdev descriptor, associated to the "kernel // terminal", and shared by all kernel instances for debug messages. It also register it // in the chdev directory, containing extended pointers on all chdevs. // The global variable txt0_chdev is replicated in all clusters, but only the chdev // allocated in I/O cluster is used by ALMOS-MKH. // Therefore, this function must be called by a thread running in the I/O cluster. // As this TXT0 chdev supports only the TXT_SYNC_WRITE command, we don't create // a server thread, we don't allocate a WTI, and we don't initialize the waiting queue. /////////////////////////////////////////////////////////////////////////////////////////// // @ info : pointer on the local boot-info structure. /////////////////////////////////////////////////////////////////////////////////////////// static void txt0_device_init( boot_info_t * info ) { boot_device_t * dev_tbl; // pointer on array of devices in boot_info uint32_t dev_nr; // actual number of devices in this cluster xptr_t base; // remote pointer on segment base uint32_t type; // peripheral type uint32_t func; // device functionnal index uint32_t impl; // device implementation index uint32_t i; // device index in dev_tbl uint32_t x; // X cluster coordinate uint32_t y; // Y cluster coordinate // get number of peripherals and base of devices array from boot_info dev_nr = info->ext_dev_nr; dev_tbl = info->ext_dev; // loop on external peripherals to find TXT device for( i = 0 ; i < dev_nr ; i++ ) { base = dev_tbl[i].base; type = dev_tbl[i].type; func = FUNC_FROM_TYPE( type ); impl = IMPL_FROM_TYPE( type ); if (func == DEV_FUNC_TXT ) { // initialize basic fields txt0_chdev.func = func; txt0_chdev.impl = impl; txt0_chdev.channel = 0; txt0_chdev.is_rx = 0; txt0_chdev.base = base; // initialize lock remote_spinlock_init( XPTR( local_cxy , &txt0_chdev.wait_lock ) ); // complete TXT-specific initialization hal_drivers_txt_init( &txt0_chdev ); // initialize the replicated chdev_dir[x][y] structures for( x = 0 ; x < info->x_size ; x++ ) { for( y = 0 ; y < info->y_size ; y++ ) { cxy_t cxy = (x<y_width) + y; hal_remote_swd( XPTR( cxy , &chdev_dir.txt[0] ) , XPTR( local_cxy , &txt0_chdev ) ); } } kinit_dmsg("\n[INFO] %s : core[%x][0] created TXT0 chdev" " / paddr = %l at cycle %d\n", __FUNCTION__ , local_cxy , chdev_func_str( func ), XPTR(local_cxy , &txt0_chdev) , hal_time_stamp() ); } } // end loop on devices } // end txt0_device_init() /////////////////////////////////////////////////////////////////////////////////////////// // This static function allocates memory for the chdev (channel_device) descriptors // associated to the internal peripherals contained in the local cluster. These internal // devices (ICU, MMC, DMA) chdev descriptors are placed in the local cluster. // It initialises these device descriptors as specified by the boot_info_t structure, // including the dynamic linking with the driver for the specified implementation. // Finally, all copies of the devices directory are initialised. /////////////////////////////////////////////////////////////////////////////////////////// // @ info : pointer on the local boot-info structure. /////////////////////////////////////////////////////////////////////////////////////////// static void internal_devices_init( boot_info_t * info ) { boot_device_t * dev; // pointer on boot_info device (ICU/MMC/DMA) uint32_t x; // X cluster coordinate uint32_t y; // Y cluster coordinate chdev_t * chdev_ptr; // local pointer on chdev descriptor xptr_t chdev_xp; // extended pointer on chdev descriptor /////////// ICU ////////// dev = &info->dev_icu; assert( ((info->cores_nr == 0) || (dev->channels != 0)) , __FUNCTION__ , "ICU device must exist in cluster containing cores" ); assert( (dev->channels == 1) , __FUNCTION__ , "channels number must be 1 for ICU device" ); assert( (FUNC_FROM_TYPE( dev->type ) == DEV_FUNC_ICU ) , __FUNCTION__ , " inconsistent ICU device type"); // create one chdev in local cluster chdev_ptr = chdev_create( FUNC_FROM_TYPE( dev->type ), IMPL_FROM_TYPE( dev->type ), 0, // channel false, // TX dev->base ); assert( (chdev_ptr != NULL) , __FUNCTION__ , "cannot allocate ICU chdev" ); // get extended pointer on chdev descriptor chdev_xp = XPTR( local_cxy , chdev_ptr ); // make ICU specific initialisation // TODO remove these three parameters dev_icu_init( chdev_ptr , dev->param0 , dev->param1 , dev->param2 ); // initialize the ICU field in the chdev_dir[x][y] structures // replicated in all clusters, and containing extended pointers // on all remotely accessible devices for( x = 0 ; x < info->x_size ; x++ ) { for( y = 0 ; y < info->y_size ; y++ ) { cxy_t cxy = (x<y_width) + y; hal_remote_swd( XPTR( cxy , &chdev_dir.icu[local_cxy] ) , chdev_xp ); } } // initialize the entries of the local chdev_icu_input structure // defining how internal peripherals are connected to ICU uint32_t id; uint8_t valid; uint32_t src_type; uint8_t src_ch; uint32_t src_func; for( id = 0 ; id < CONFIG_MAX_HWIS_PER_ICU ; id++ ) { valid = dev->irq[id].valid; src_type = dev->irq[id].dev_type; src_ch = dev->irq[id].channel; src_func = FUNC_FROM_TYPE( src_type ); if( valid ) // only valid local IRQs are registered { if ( src_func == DEV_FUNC_MMC ) chdev_icu_input.mmc = id; else if( src_func == DEV_FUNC_DMA ) chdev_icu_input.dma[src_ch] = id; else assert( false , __FUNCTION__ , "illegal source device for ICU input" ); } } kinit_dmsg("\n[INFO] %s : core[%x][0] created ICU chdev at cycle %d\n", __FUNCTION__ , local_cxy , hal_time_stamp() ); /////////// MMC internal chdev /////////// dev = &info->dev_mmc; if( dev->channels != 0 ) // MMC device is defined { assert( (dev->channels == 1) , __FUNCTION__ , "channels number must be 1 for MMC device" ); assert( (FUNC_FROM_TYPE( dev->type ) == DEV_FUNC_MMC ) , __FUNCTION__ , " inconsistent MMC device type"); // create one chdev in local cluster chdev_ptr = chdev_create( FUNC_FROM_TYPE( dev->type ), IMPL_FROM_TYPE( dev->type ), 0, // channel false, // TX dev->base ); assert( (chdev_ptr != NULL) , __FUNCTION__ , "cannot allocate MMC chdev" ); // get extended pointer on chdev descriptor chdev_xp = XPTR( local_cxy , chdev_ptr ); // make MMC specific initialisation dev_mmc_init( chdev_ptr ); // initialize the MMC field in the chdev_dir[x][y] structures // replicated in all clusters, and containing extended pointers // on all remotely accessible devices for( x = 0 ; x < info->x_size ; x++ ) { for( y = 0 ; y < info->y_size ; y++ ) { cxy_t cxy = (x<y_width) + y; hal_remote_swd( XPTR( cxy , &chdev_dir.mmc[local_cxy] ) , chdev_xp ); } } kinit_dmsg("\n[INFO] %s : core[%x][0] created MMC chdev at cycle %d\n", __FUNCTION__ , local_cxy , hal_time_stamp() ); } /////////// DMA internal chdevs ////////// dev = &info->dev_dma; if( dev->channels != 0 ) // DMA device is defined { assert( (FUNC_FROM_TYPE( dev->type ) == DEV_FUNC_DMA ) , __FUNCTION__ , " inconsistent DMA device type"); // create one chdev per channel in local cluster uint32_t channel; for( channel = 0 ; channel < dev->channels ; channel++ ) { chdev_ptr = chdev_create( FUNC_FROM_TYPE( dev->type ), IMPL_FROM_TYPE( dev->type ), channel, // channel false, // TX dev->base ); assert( (chdev_ptr != NULL) , __FUNCTION__ , "cannot allocate DMA chdev" ); // get extended pointer on channel descriptor chdev_xp = XPTR( local_cxy , chdev_ptr ); // make DMA specific initialisation dev_dma_init( chdev_ptr ); // initialize only the DMA[channel] field in the local chdev_dir[x][y] // structure because the DMA device is not remotely accessible. chdev_dir.dma[channel] = chdev_xp; kinit_dmsg("\n[INFO] %s : core[%x][0] created DMA[%d] chdev at cycle %d\n", __FUNCTION__ , local_cxy , channel , hal_time_stamp() ); } } } // end internal_devices_init() /////////////////////////////////////////////////////////////////////////////////////////// // This static function allocates memory for the chdev descriptors associated // to the external (shared) peripherals contained in the local cluster. These external // devices (IOB, IOC, TXT, NIC, etc ) are distributed on all clusters. // It initialises these device descriptors as specified by the boot_info_t structure, // including the dynamic linking with the driver for the specified implementation. // Finally, all copies of the devices directory are initialised. // // The number of channel_devices depends on the device functionnal type. // There is three nested loops to build the full set of external channel_devices: // - loop on external devices. // - loop on channels for multi-channels devices. // - loop on directions (RX/TX) for NIC device. // The set of channel_devices is indexed by the chdev_gid global index, that is used // to select the cluster containing a given chdev[func,channel,direction]. // All clusters scan the full set of chdevs, but only the cluster matching // (chdev_gid % (x_size*y_size)) create the corresponding chdev. // // TODO check that cluster IO contains a PIC [AG] // TODO make a default initialisation for the chdev_dir structure (XPTR_NULL ) [AG] /////////////////////////////////////////////////////////////////////////////////////////// // @ info : pointer on the local boot-info structure. /////////////////////////////////////////////////////////////////////////////////////////// static void external_devices_init( boot_info_t * info ) { boot_device_t * dev_tbl; // pointer on array of devices in boot_info uint32_t dev_nr; // actual number of devices in this cluster xptr_t base; // remote pointer on segment base uint32_t type; // peripheral type uint32_t func; // device functionnal index uint32_t impl; // device implementation index uint32_t i; // device index in dev_tbl uint32_t x; // X cluster coordinate uint32_t y; // Y cluster coordinate uint32_t channels_nr; // number of channels uint32_t channel; // channel index uint32_t directions_nr; // number of directions uint32_t direction; // direction index uint32_t p0; // device parameter 0 uint32_t p1; // device parameter 1 uint32_t p2; // device parameter 2 uint32_t p3; // device parameter 3 uint32_t first_channel; // used in loop on channels chdev_t * chdev; // local pointer on one channel_device descriptor xptr_t chdev_xp; // extended pointer on channel_device descriptor uint32_t chdev_gid = 0; // global index of channel_device descriptor // get number of peripherals and base of devices array from boot_info dev_nr = info->ext_dev_nr; dev_tbl = info->ext_dev; // loop on external peripherals for( i = 0 ; i < dev_nr ; i++ ) { base = dev_tbl[i].base; type = dev_tbl[i].type; channels_nr = dev_tbl[i].channels; p0 = dev_tbl[i].param0; p1 = dev_tbl[i].param1; p2 = dev_tbl[i].param2; p3 = dev_tbl[i].param3; func = FUNC_FROM_TYPE( type ); impl = IMPL_FROM_TYPE( type ); // There is one chdev per direction for NIC if (func == DEV_FUNC_NIC) directions_nr = 2; else directions_nr = 1; // The TXT0 chdev has already been created if (func == DEV_FUNC_TXT) first_channel = 1; else first_channel = 0; // do nothing for ROM, that does not require a device descriptor. if( func == DEV_FUNC_ROM ) continue; // check external device functionnal type if( (func != DEV_FUNC_IOB) && (func != DEV_FUNC_PIC) && (func != DEV_FUNC_IOC) && (func != DEV_FUNC_TXT) && (func != DEV_FUNC_NIC) && (func != DEV_FUNC_FBF) ) { assert( false , __FUNCTION__ , "undefined external peripheral type" ); } // loops on channels for( channel = first_channel ; channel < channels_nr ; channel++ ) { // loop on directions for( direction = 0 ; direction < directions_nr ; direction++ ) { // get target cluster for chdev[func,channel,direction] uint32_t offset = chdev_gid % ( info->x_size * info->y_size ); uint32_t cx = offset / info->y_size; uint32_t cy = offset % info->y_size; uint32_t target_cxy = (cx<y_width) + cy; // allocate and initialize a local chdev // if local cluster matches target cluster if( target_cxy == local_cxy ) { chdev = chdev_create( func, impl, channel, direction, base ); assert( (chdev != NULL), __FUNCTION__ , "cannot allocate external device" ); // get extended pointer on chdev chdev_xp = XPTR( local_cxy , chdev ); // make device type specific initialisation // the number of parameters depends on the device type // TODO : remove the parameters that must be provided by the drivers if ( func == DEV_FUNC_IOB ) dev_iob_init( chdev ); else if( func == DEV_FUNC_IOC ) dev_ioc_init( chdev ); else if( func == DEV_FUNC_TXT ) dev_txt_init( chdev ); else if( func == DEV_FUNC_NIC ) dev_nic_init( chdev ); else if( func == DEV_FUNC_PIC ) dev_pic_init( chdev , p0 ); else if( func == DEV_FUNC_FBF ) dev_fbf_init( chdev , p0 , p1 ); else { assert( false , __FUNCTION__ , "undefined device type" ); } // all external (shared) devices are remotely accessible // initialize the replicated chdev_dir[x][y] structures // defining the extended pointers on chdev descriptors xptr_t * entry; if( func == DEV_FUNC_IOB ) entry = &chdev_dir.iob; if( func == DEV_FUNC_PIC ) entry = &chdev_dir.pic; if( func == DEV_FUNC_TXT ) entry = &chdev_dir.txt[channel]; if( func == DEV_FUNC_IOC ) entry = &chdev_dir.ioc[channel]; if( func == DEV_FUNC_FBF ) entry = &chdev_dir.fbf[channel]; if( func == DEV_FUNC_NIC ) entry = &chdev_dir.nic_tx[channel]; for( x = 0 ; x < info->x_size ; x++ ) { for( y = 0 ; y < info->y_size ; y++ ) { cxy_t cxy = (x<y_width) + y; hal_remote_swd( XPTR( cxy , entry ) , chdev_xp ); } } kinit_dmsg("\n[INFO] %s : core[%x][0] create chdev %s[%d] at cycle %d\n", __FUNCTION__ , local_cxy , chdev_func_str( func ), channel , hal_time_stamp() ); } // end if match // increment chdev global index (matching or not) chdev_gid++; } // end loop on directions } // end loop on channels // initialize the entries of the local chdev_pic_input structure // defining how external peripherals are connected to PIC if( func == DEV_FUNC_PIC ) { uint32_t id; uint8_t valid; uint32_t dev_type; uint8_t channel; uint8_t is_rx; // loop on PIC inputs for( id = 0 ; id < CONFIG_MAX_IRQS_PER_PIC ; id++ ) { valid = dev_tbl[i].irq[id].valid; dev_type = dev_tbl[i].irq[id].dev_type; channel = dev_tbl[i].irq[id].channel; is_rx = dev_tbl[i].irq[id].is_rx; if( valid ) // only valid inputs are registered { uint32_t * index; // local pointer on one entry uint16_t dev_func = FUNC_FROM_TYPE( dev_type ); if( dev_func == DEV_FUNC_TXT ) { index = &chdev_pic_input.txt[channel]; } else if( dev_func == DEV_FUNC_IOC ) { index = &chdev_pic_input.ioc[channel]; } else if( (dev_func == DEV_FUNC_NIC) && (is_rx == 0) ) { index = &chdev_pic_input.nic_tx[channel]; } else if( (dev_func == DEV_FUNC_NIC) && (is_rx != 0) ) { index = &chdev_pic_input.nic_rx[channel]; } else { assert( false , __FUNCTION__ , "illegal source device for PIC input" ); } // set entry in local structure *index = id; } } // end loop on PIC inputs } // end PIC } // end loop on devices } // end external_devices_init() /////////////////////////////////////////////////////////////////////////////////////////// // This static function returns the identifiers of the calling core. /////////////////////////////////////////////////////////////////////////////////////////// // @ info : pointer on boot_info structure. // @ lid : [out] core local index in cluster. // @ cxy : [out] cluster identifier. // @ lid : [out] core global identifier (hardware). // @ return 0 if success / return EINVAL if not found. /////////////////////////////////////////////////////////////////////////////////////////// static error_t get_core_identifiers( boot_info_t * info, lid_t * lid, cxy_t * cxy, gid_t * gid ) { uint32_t i; gid_t global_id; // get global identifier from hardware register global_id = hal_get_gid(); // makes an associative search in boot_info to get (cxy,lid) from global_id for( i = 0 ; i < info->cores_nr ; i++ ) { if( global_id == info->core[i].gid ) { *lid = info->core[i].lid; *cxy = info->core[i].cxy; *gid = global_id; return 0; } } return EINVAL; } /////////////////////////////////////////////////////////////////////////////////////////// // This function is the entry point for the kernel initialisation. // It is executed by all cores in all clusters, but only core[0], called CP0, // initializes the shared resources such as the cluster manager, or the local peripherals. // To comply with the multi-kernels paradigm, it accesses only local cluster memory, using // only information contained in the local boot_info_t structure, set by the bootloader. /////////////////////////////////////////////////////////////////////////////////////////// // @ info : pointer on the local boot-info structure. /////////////////////////////////////////////////////////////////////////////////////////// void kernel_init( boot_info_t * info ) { lid_t core_lid = -1; // running core local index cxy_t core_cxy = -1; // running core cluster identifier gid_t core_gid; // running core hardware identifier cluster_t * cluster; // pointer on local cluster manager core_t * core; // pointer on running core descriptor thread_t * thread; // pointer on idle thread descriptor error_t error; // all cores get core identifiers error = get_core_identifiers( info, &core_lid, &core_cxy, &core_gid ); // CP0 initialise cluster identifier if( core_lid == 0 ) local_cxy = info->cxy; // each core get pointer on its private idle thread descriptor thread = (thread_t *)( idle_threads + (core_lid * CONFIG_THREAD_DESC_SIZE) ); // each core registers this thread pointer in hardware register hal_set_current_thread( thread ); #ifdef __HAL_x86_64__ return; #endif // CP0 in I/O cluster initialises TXT0 chdev descriptor if( (core_lid == 0) && (core_cxy == info->io_cxy) ) txt0_device_init( info ); ///////////////////////////////////////////////////////////////////////////////// // global & local synchro to protect access to TXT0 terminal if( core_lid == 0 ) remote_barrier( XPTR( info->io_cxy , &global_barrier ), (info->x_size * info->y_size) ); barrier_wait( &local_barrier , info->cores_nr ); ///////////////////////////////////////////////////////////////////////////////// kinit_dmsg("\n[INFO] %s : core[%x][%d] exit barrier 0 at cycle %d\n", __FUNCTION__ , core_cxy , core_lid , hal_time_stamp() ); // all cores check core identifiers if( error ) { printk("\n[PANIC] in %s : illegal core identifiers" " gid = %x / cxy = %x / lid = %d\n", __FUNCTION__ , core_lid , core_cxy , core_lid ); hal_core_sleep(); } // CP0 initializes the local cluster manager (cores and memory allocators) if( core_lid == 0 ) { error = cluster_init( info ); if( error ) { printk("\n[PANIC] in %s : cannot initialise cluster manager in cluster %x", __FUNCTION__ , local_cxy ); hal_core_sleep(); } } ///////////////////////////////////////////////////////////////////////////////// // global & local synchro, to protect access to cluster manager if( core_lid == 0 ) remote_barrier( XPTR( info->io_cxy , &global_barrier ), (info->x_size * info->y_size) ); barrier_wait( &local_barrier , info->cores_nr ); ///////////////////////////////////////////////////////////////////////////////// kinit_dmsg("\n[INFO] %s : core[%x][%d] exit barrier 1 at cycle %d\n", __FUNCTION__ , core_cxy , core_lid , hal_time_stamp() ); // all cores get pointer on local cluster manager and on core descriptor cluster = &cluster_manager; core = &cluster->core_tbl[core_lid]; // CP0 initializes the process_zero descriptor if( core_lid == 0 ) process_zero_init( info ); // CP0 allocates and initialises the internal peripheral chdev descriptors. // Each CP0[cxy] scan the set of its internal (private) peripherals, // and allocate memory for the corresponding chdev descriptors. if( core_lid == 0 ) internal_devices_init( info ); // CP0 allocates one WTI mailbbox per core for Inter Processor Interrupt // this must be done after ICU chdev initialisation, by CP0 only, and before // external devices initialisation to enforce the rule : // "The WTI index for the IPI routed to core[lid] is lid" if( core_lid == 0 ) { uint32_t wti_id; uint32_t lid; for( lid = 0 ; lid < LOCAL_CLUSTER->cores_nr ; lid++ ) { wti_id = dev_icu_wti_alloc(); if( wti_id != lid ) { printk("\n[PANIC] in %s : WTI index for IPI = %d / core_lid = %d", __FUNCTION__ , wti_id , lid ); hal_core_sleep(); } dev_icu_enable_irq( lid , WTI_TYPE , wti_id , NULL ); } } // All CP0s contribute to initialise external peripheral chdev descriptors. // Each CP0[cxy] scan the set of external (shared) peripherals (but the TXT0), // and allocates memory for the chdev descriptors that must be placed // on the (cxy) cluster according to the global index value. if( core_lid == 0 ) external_devices_init( info ); ///////////////////////////////////////////////////////////////////////////////// // global &local synchro to protect access to peripherals if( core_lid == 0 ) remote_barrier( XPTR( info->io_cxy , &global_barrier ), (info->x_size * info->y_size) ); barrier_wait( &local_barrier , info->cores_nr ); ///////////////////////////////////////////////////////////////////////////////// kinit_dmsg("\n[INFO] %s : core[%x][%d] exit barrier 2 at cycle %d\n", __FUNCTION__ , core_cxy , core_lid , hal_time_stamp() ); error = thread_kernel_init( thread, THREAD_IDLE, &thread_idle_func, NULL, core_lid ); if( error ) { printk("\n[PANIC] in %s : core[%x][%d] cannot initialize idle thread\n", __FUNCTION__ , local_cxy , core_lid ); hal_core_sleep(); } else { // register idle thread in scheduler core->scheduler.idle = thread; // activate the idle thread thread_unblock( XPTR( local_cxy , thread ) , THREAD_BLOCKED_GLOBAL ); kinit_dmsg("\n[INFO] %s : core[%x][%d] created idle thread %x at cycle %d\n", __FUNCTION__ , core_cxy , core_lid , thread , hal_time_stamp()); } // CP0 in all clusters initializes cooperatively VFS and DEVFS if( (core_lid == 0) ) { xptr_t root_inode_xp; // initialize root File System (must be FATFS in this implementation) if( CONFIG_VFS_ROOT_IS_FATFS ) { root_inode_xp = fatfs_init(); } else { printk("\n[PANIC] in %s : root FS must be FATFS\n", __FUNCTION__ ); hal_core_sleep(); } if( root_inode_xp == XPTR_NULL ) { printk("\n[PANIC] in %s : core[%x][%d] cannot initialize file system\n", __FUNCTION__ , local_cxy , core_lid ); hal_core_sleep(); } // mount the DEVFS File system devfs_mount( root_inode_xp , "dev" ); } // CP0 in I/O cluster print banner if( (core_lid == 0) && (local_cxy == info->io_cxy) ) { print_banner( (info->x_size * info->y_size) , info->cores_nr ); kinit_dmsg("\n\n*** memory fooprint of main kernet objects ***\n" " - thread descriptor : %d bytes\n" " - process descriptor : %d bytes\n" " - cluster manager : %d bytes\n" " - chdev descriptor : %d bytes\n" " - core descriptor : %d bytes\n" " - scheduler : %d bytes\n" " - rpc fifo : %d bytes\n" " - page descriptor : %d bytes\n" " - mapper root : %d bytes\n" " - ppm manager : %d bytes\n" " - kcm manager : %d bytes\n" " - khm manager : %d bytes\n" " - vmm manager : %d bytes\n" " - gpt root : %d bytes\n" " - list item : %d bytes\n" " - xlist item : %d bytes\n" " - spinlock : %d bytes\n" " - remote spinlock : %d bytes\n" " - rwlock : %d bytes\n" " - remote rwlock : %d bytes\n", sizeof( thread_t ), sizeof( process_t ), sizeof( cluster_t ), sizeof( chdev_t ), sizeof( core_t ), sizeof( scheduler_t ), sizeof( rpc_fifo_t ), sizeof( page_t ), sizeof( mapper_t ), sizeof( ppm_t ), sizeof( kcm_t ), sizeof( khm_t ), sizeof( vmm_t ), sizeof( gpt_t ), sizeof( list_entry_t ), sizeof( xlist_entry_t ), sizeof( spinlock_t ), sizeof( remote_spinlock_t ), sizeof( rwlock_t ), sizeof( remote_rwlock_t )); } ///////////////////////////////////////////////////////////////////////////////// // global syncho to protect access to File System if( core_lid == 0 ) remote_barrier( XPTR( info->io_cxy , &global_barrier ), (info->x_size * info->y_size) ); barrier_wait( &local_barrier , info->cores_nr ); ///////////////////////////////////////////////////////////////////////////////// kinit_dmsg("\n[INFO] %s : core[%x][%d] exit barrier 3 at cycle %d\n", __FUNCTION__ , core_cxy , core_lid , hal_time_stamp() ); // each core activates its private PTI IRQ dev_icu_set_period( core_lid , CONFIG_SCHED_TICK_PERIOD ); dev_icu_enable_irq( core_lid , PTI_TYPE , core_lid , NULL ); // each core get its private IRQ masks values and uint32_t hwi_mask; uint32_t wti_mask; uint32_t pti_mask; dev_icu_get_masks( core_lid , &hwi_mask , &wti_mask , &pti_mask ); thread_dmsg("\n[INFO] %s : core[%x][%d] activates scheduler at cycle %d\n" " hwi_mask = %x / wti_mask = %x / pti_mask = %x\n", __FUNCTION__ , local_cxy , core_lid , hal_time_stamp() , hwi_mask , wti_mask , pti_mask ); // each core jump to idle thread thread_idle_func(); } // end kernel_init()