/* * kernel_init.c - kernel parallel initialization * * Authors : Mohamed Lamine Karaoui (2015) * Alain Greiner (2016,2017,2018,2019) * * 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 #include #include #include /////////////////////////////////////////////////////////////////////////////////////////// // All the following 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 built by the bootloader, and used by kernel_init. // it must be the 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 variable defines the TXT_TX[0] chdev __attribute__((section(".kdata"))) chdev_t txt0_tx_chdev CONFIG_CACHE_LINE_ALIGNED; // This variable defines the TXT_RX[0] chdev __attribute__((section(".kdata"))) chdev_t txt0_rx_chdev 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 a set of 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 IOPIC controller __attribute__((section(".kdata"))) iopic_input_t iopic_input CONFIG_CACHE_LINE_ALIGNED; // This variable contains the input IRQ indexes for the LAPIC controller __attribute__((section(".kdata"))) lapic_input_t lapic_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 is used for core[0] cores synchronisation in kernel_init() __attribute__((section(".kdata"))) xbarrier_t global_barrier CONFIG_CACHE_LINE_ALIGNED; // This variable is used for local cores synchronisation 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 array is used for debug, and describes the kernel locks usage, // It must be kept consistent with the defines in kernel_config.h file. __attribute__((section(".kdata"))) char * lock_type_str[] = { "unused_0", // 0 "CLUSTER_KCM", // 1 "SCHED_STATE", // 2 "VMM_STACK", // 3 "VMM_MMAP", // 4 "VFS_CTX", // 5 "KCM_STATE", // 6 "KHM_STATE", // 7 "HTAB_STATE", // 8 "PPM_FREE", // 9 "THREAD_JOIN", // 10 "XHTAB_STATE", // 11 "CHDEV_QUEUE", // 12 "CHDEV_TXT0", // 13 "CHDEV_TXTLIST", // 14 "PAGE_STATE", // 15 "MUTEX_STATE", // 16 "CONDVAR_STATE", // 17 "SEM_STATE", // 18 "PROCESS_CWD", // 19 "BARRIER_STATE", // 20 "CLUSTER_PREFTBL", // 21 "PPM_DIRTY", // 22 "CLUSTER_LOCALS", // 23 "CLUSTER_COPIES", // 24 "PROCESS_CHILDREN", // 25 "PROCESS_USERSYNC", // 26 "PROCESS_FDARRAY", // 27 "PROCESS_DIR", // 28 "unused_29", // 29 "PROCESS_THTBL", // 30 "MAPPER_STATE", // 31 "VFS_SIZE", // 32 "VFS_FILE", // 33 "VMM_VSL", // 34 "VFS_MAIN", // 35 "FATFS_FAT", // 36 }; // debug variables to analyse the sys_read() and sys_write() syscalls timing #if DEBUG_SYS_READ uint32_t enter_sys_read; uint32_t exit_sys_read; uint32_t enter_devfs_read; uint32_t exit_devfs_read; uint32_t enter_txt_read; uint32_t exit_txt_read; uint32_t enter_chdev_cmd_read; uint32_t exit_chdev_cmd_read; uint32_t enter_chdev_server_read; uint32_t exit_chdev_server_read; uint32_t enter_tty_cmd_read; uint32_t exit_tty_cmd_read; uint32_t enter_tty_isr_read; uint32_t exit_tty_isr_read; #endif // these debug variables are used to analyse the sys_write() syscall timing #if DEBUG_SYS_WRITE uint32_t enter_sys_write; uint32_t exit_sys_write; uint32_t enter_devfs_write; uint32_t exit_devfs_write; uint32_t enter_txt_write; uint32_t exit_txt_write; uint32_t enter_chdev_cmd_write; uint32_t exit_chdev_cmd_write; uint32_t enter_chdev_server_write; uint32_t exit_chdev_server_write; uint32_t enter_tty_cmd_write; uint32_t exit_tty_cmd_write; uint32_t enter_tty_isr_write; uint32_t exit_tty_isr_write; #endif // intrumentation variables : cumulated costs per syscall type in cluster #if CONFIG_INSTRUMENTATION_SYSCALLS __attribute__((section(".kdata"))) uint32_t syscalls_cumul_cost[SYSCALLS_NR]; __attribute__((section(".kdata"))) uint32_t syscalls_occurences[SYSCALLS_NR]; #endif /////////////////////////////////////////////////////////////////////////////////////////// // 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 %s / %d cluster(s) / %d core(s) per cluster\n\n", CONFIG_VERSION , nclusters , ncores ); } /////////////////////////////////////////////////////////////////////////////////////////// // This function initializes the TXT_TX[0] and TXT_RX[0] chdev descriptors, implementing // the "kernel terminal", shared by all kernel instances for debug messages. // These chdev are implemented as global variables (replicated in all clusters), // because this terminal is used before the kmem allocator initialisation, but only // the chdevs in cluster 0 are registered in the "chdev_dir" directory. // 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. // Note: The TXT_RX[0] chdev is created, but is not used by ALMOS-MKH (september 2018). /////////////////////////////////////////////////////////////////////////////////////////// // @ info : pointer on the local boot-info structure. /////////////////////////////////////////////////////////////////////////////////////////// static void __attribute__ ((noinline)) 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 func; // device functional 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; func = FUNC_FROM_TYPE( dev_tbl[i].type ); impl = IMPL_FROM_TYPE( dev_tbl[i].type ); if (func == DEV_FUNC_TXT ) { // initialize TXT_TX[0] chdev txt0_tx_chdev.func = func; txt0_tx_chdev.impl = impl; txt0_tx_chdev.channel = 0; txt0_tx_chdev.base = base; txt0_tx_chdev.is_rx = false; remote_busylock_init( XPTR( local_cxy , &txt0_tx_chdev.wait_lock ), LOCK_CHDEV_TXT0 ); // initialize TXT_RX[0] chdev txt0_rx_chdev.func = func; txt0_rx_chdev.impl = impl; txt0_rx_chdev.channel = 0; txt0_rx_chdev.base = base; txt0_rx_chdev.is_rx = true; remote_busylock_init( XPTR( local_cxy , &txt0_rx_chdev.wait_lock ), LOCK_CHDEV_TXT0 ); // make TXT specific initialisations dev_txt_init( &txt0_tx_chdev ); dev_txt_init( &txt0_rx_chdev ); // register TXT_TX[0] & TXT_RX[0] in chdev_dir[x][y] // for all valid clusters for( x = 0 ; x < info->x_size ; x++ ) { for( y = 0 ; y < info->y_size ; y++ ) { cxy_t cxy = HAL_CXY_FROM_XY( x , y ); if( cluster_is_active( cxy ) ) { hal_remote_s64( XPTR( cxy , &chdev_dir.txt_tx[0] ) , XPTR( local_cxy , &txt0_tx_chdev ) ); hal_remote_s64( XPTR( cxy , &chdev_dir.txt_rx[0] ) , XPTR( local_cxy , &txt0_rx_chdev ) ); } } } hal_fence(); } } // end loop on devices } // end txt0_device_init() /////////////////////////////////////////////////////////////////////////////////////////// // This function allocates memory and initializes the chdev descriptors for the internal // peripherals contained in the local cluster, other than the LAPIC, as specified by // the boot_info, including the linking with the driver for the specified implementation. // The relevant entries in all copies of the devices directory are initialised. /////////////////////////////////////////////////////////////////////////////////////////// // @ info : pointer on the local boot-info structure. /////////////////////////////////////////////////////////////////////////////////////////// static void __attribute__ ((noinline)) internal_devices_init( boot_info_t * info ) { boot_device_t * dev_tbl; // pointer on array of internaldevices in boot_info uint32_t dev_nr; // actual number of devices in this cluster xptr_t base; // remote pointer on segment base 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; // number of channels uint32_t channel; // channel index chdev_t * chdev_ptr; // local pointer on created chdev // get number of internal peripherals and base from boot_info dev_nr = info->int_dev_nr; dev_tbl = info->int_dev; // loop on internal peripherals for( i = 0 ; i < dev_nr ; i++ ) { base = dev_tbl[i].base; channels = dev_tbl[i].channels; func = FUNC_FROM_TYPE( dev_tbl[i].type ); impl = IMPL_FROM_TYPE( dev_tbl[i].type ); ////////////////////////// if( func == DEV_FUNC_MMC ) { // check channels if( channels != 1 ) { printk("\n[PANIC] in %s : MMC device must be single channel\n", __FUNCTION__ ); hal_core_sleep(); } // create chdev in local cluster chdev_ptr = chdev_create( func, impl, 0, // channel false, // direction base ); // check memory if( chdev_ptr == NULL ) { printk("\n[PANIC] in %s : cannot create MMC chdev\n", __FUNCTION__ ); hal_core_sleep(); } // make MMC specific initialisation dev_mmc_init( chdev_ptr ); // set the MMC field in all chdev_dir[x][y] structures for( x = 0 ; x < info->x_size ; x++ ) { for( y = 0 ; y < info->y_size ; y++ ) { cxy_t cxy = HAL_CXY_FROM_XY( x , y ); if( cluster_is_active( cxy ) ) { hal_remote_s64( XPTR( cxy , &chdev_dir.mmc[local_cxy] ), XPTR( local_cxy , chdev_ptr ) ); } } } #if( DEBUG_KERNEL_INIT & 0x1 ) if( hal_time_stamp() > DEBUG_KERNEL_INIT ) printk("\n[%s] : created MMC in cluster %x / chdev = %x\n", __FUNCTION__ , local_cxy , chdev_ptr ); #endif } /////////////////////////////// else if( func == DEV_FUNC_DMA ) { // create one chdev per channel in local cluster for( channel = 0 ; channel < channels ; channel++ ) { // create chdev[channel] in local cluster chdev_ptr = chdev_create( func, impl, channel, false, // direction base ); // check memory if( chdev_ptr == NULL ) { printk("\n[PANIC] in %s : cannot create DMA chdev\n", __FUNCTION__ ); hal_core_sleep(); } // 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] = XPTR( local_cxy , chdev_ptr ); #if( DEBUG_KERNEL_INIT & 0x1 ) if( hal_time_stamp() > DEBUG_KERNEL_INIT ) printk("\n[%s] : created DMA[%d] in cluster %x / chdev = %x\n", __FUNCTION__ , channel , local_cxy , chdev_ptr ); #endif } } } } // end internal_devices_init() /////////////////////////////////////////////////////////////////////////////////////////// // This function allocates memory and initializes the chdev descriptors for the // external (shared) peripherals other than the IOPIC, as specified by the boot_info. // This includes the dynamic linking with the driver for the specified implementation. // These chdev descriptors are distributed on all clusters, using a modulo on a global // index, identically computed in all clusters. // This function is executed in all clusters by the core[0] core, that computes a global index // for all external chdevs. Each core[0] core creates only the chdevs that must be placed in // the local cluster, because the global index matches the local index. // The relevant entries in all copies of the devices directory are initialised. /////////////////////////////////////////////////////////////////////////////////////////// // @ 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 external devices in boot_info uint32_t dev_nr; // actual number of external devices xptr_t base; // remote pointer on segment base 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; // number of channels uint32_t channel; // channel index uint32_t directions; // number of directions (1 or 2) uint32_t rx; // direction index (0 or 1) chdev_t * chdev; // local pointer on one channel_device descriptor uint32_t ext_chdev_gid; // global index of external chdev // get number of peripherals and base of devices array from boot_info dev_nr = info->ext_dev_nr; dev_tbl = info->ext_dev; // initializes global index (PIC is already placed in cluster 0 ext_chdev_gid = 1; // loop on external peripherals for( i = 0 ; i < dev_nr ; i++ ) { base = dev_tbl[i].base; channels = dev_tbl[i].channels; func = FUNC_FROM_TYPE( dev_tbl[i].type ); impl = IMPL_FROM_TYPE( dev_tbl[i].type ); // There is one chdev per direction for NIC and for TXT if((func == DEV_FUNC_NIC) || (func == DEV_FUNC_TXT)) directions = 2; else directions = 1; // do nothing for ROM, that does not require a device descriptor. if( func == DEV_FUNC_ROM ) continue; // do nothing for PIC, that is already initialized if( func == DEV_FUNC_PIC ) continue; // check PIC device initialized if( chdev_dir.pic == XPTR_NULL ) { printk("\n[PANIC] in %s : PIC device must be initialized first\n", __FUNCTION__ ); hal_core_sleep(); } // check external device functionnal type if( (func != DEV_FUNC_IOB) && (func != DEV_FUNC_IOC) && (func != DEV_FUNC_TXT) && (func != DEV_FUNC_NIC) && (func != DEV_FUNC_FBF) ) { printk("\n[PANIC] in %s : undefined peripheral type\n", __FUNCTION__ ); hal_core_sleep(); } // loops on channels for( channel = 0 ; channel < channels ; channel++ ) { // loop on directions for( rx = 0 ; rx < directions ; rx++ ) { // skip TXT0 that has already been initialized if( (func == DEV_FUNC_TXT) && (channel == 0) ) continue; // all kernel instances compute the target cluster for all chdevs, // computing the global index ext_chdev_gid[func,channel,direction] cxy_t target_cxy; while( 1 ) { uint32_t offset = ext_chdev_gid % ( info->x_size * info->y_size ); uint32_t x = offset / info->y_size; uint32_t y = offset % info->y_size; target_cxy = HAL_CXY_FROM_XY( x , y ); // exit loop if target cluster is active if( cluster_is_active( target_cxy ) ) break; // increment global index otherwise ext_chdev_gid++; } // allocate and initialize a local chdev // when local cluster matches target cluster if( target_cxy == local_cxy ) { chdev = chdev_create( func, impl, channel, rx, // direction base ); if( chdev == NULL ) { printk("\n[PANIC] in %s : cannot allocate chdev\n", __FUNCTION__ ); hal_core_sleep(); } // make device type specific initialisation 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_FBF ) dev_fbf_init( chdev ); // 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 = NULL; if(func==DEV_FUNC_IOB ) entry = &chdev_dir.iob; if(func==DEV_FUNC_IOC ) entry = &chdev_dir.ioc[channel]; if(func==DEV_FUNC_FBF ) entry = &chdev_dir.fbf[channel]; if((func==DEV_FUNC_TXT) && (rx==0)) entry = &chdev_dir.txt_tx[channel]; if((func==DEV_FUNC_TXT) && (rx==1)) entry = &chdev_dir.txt_rx[channel]; if((func==DEV_FUNC_NIC) && (rx==0)) entry = &chdev_dir.nic_tx[channel]; if((func==DEV_FUNC_NIC) && (rx==1)) entry = &chdev_dir.nic_rx[channel]; for( x = 0 ; x < info->x_size ; x++ ) { for( y = 0 ; y < info->y_size ; y++ ) { cxy_t cxy = HAL_CXY_FROM_XY( x , y ); if( cluster_is_active( cxy ) && ( entry != NULL ) ) { hal_remote_s64( XPTR( cxy , entry ), XPTR( local_cxy , chdev ) ); } } } #if( DEBUG_KERNEL_INIT & 0x1 ) if( hal_time_stamp() > DEBUG_KERNEL_INIT ) printk("\n[%s] : create chdev %s / channel = %d / rx = %d / cluster %x / chdev = %x\n", __FUNCTION__ , chdev_func_str( func ), channel , rx , local_cxy , chdev ); #endif } // end if match // increment chdev global index (matching or not) ext_chdev_gid++; } // end loop on directions } // end loop on channels } // end loop on devices } // end external_devices_init() /////////////////////////////////////////////////////////////////////////////////////////// // This function is called by core[0] in cluster 0 to allocate memory and initialize the PIC // device, namely the informations attached to the external IOPIC controller, that // must be replicated in all clusters (struct iopic_input). // This initialisation must be done before other devices initialisation because the IRQ // routing infrastructure is required for both internal and external devices init. /////////////////////////////////////////////////////////////////////////////////////////// // @ info : pointer on the local boot-info structure. /////////////////////////////////////////////////////////////////////////////////////////// static void __attribute__ ((noinline)) iopic_init( boot_info_t * info ) { boot_device_t * dev_tbl; // pointer on boot_info external devices array uint32_t dev_nr; // actual number of external devices xptr_t base; // remote pointer on segment base uint32_t func; // device functionnal index uint32_t impl; // device implementation index uint32_t i; // device index in dev_tbl uint32_t x; // cluster X coordinate uint32_t y; // cluster Y coordinate bool_t found; // IOPIC found chdev_t * chdev; // pointer on PIC chdev descriptor // get number of external peripherals and base of array from boot_info dev_nr = info->ext_dev_nr; dev_tbl = info->ext_dev; // avoid GCC warning base = XPTR_NULL; impl = 0; // loop on external peripherals to get the IOPIC for( i = 0 , found = false ; i < dev_nr ; i++ ) { func = FUNC_FROM_TYPE( dev_tbl[i].type ); if( func == DEV_FUNC_PIC ) { base = dev_tbl[i].base; impl = IMPL_FROM_TYPE( dev_tbl[i].type ); found = true; break; } } // check PIC existence if( found == false ) { printk("\n[PANIC] in %s : PIC device not found\n", __FUNCTION__ ); hal_core_sleep(); } // allocate and initialize the PIC chdev in cluster 0 chdev = chdev_create( DEV_FUNC_PIC, impl, 0, // channel 0, // direction, base ); // check memory if( chdev == NULL ) { printk("\n[PANIC] in %s : no memory for PIC chdev\n", __FUNCTION__ ); hal_core_sleep(); } // make PIC device type specific initialisation dev_pic_init( chdev ); // register, in all clusters, the extended pointer // on PIC chdev in "chdev_dir" array xptr_t * entry = &chdev_dir.pic; for( x = 0 ; x < info->x_size ; x++ ) { for( y = 0 ; y < info->y_size ; y++ ) { cxy_t cxy = HAL_CXY_FROM_XY( x , y ); if( cluster_is_active( cxy ) ) { hal_remote_s64( XPTR( cxy , entry ) , XPTR( local_cxy , chdev ) ); } } } // initialize, in all clusters, the "iopic_input" structure // defining how external IRQs are connected to IOPIC // register default value for unused inputs for( x = 0 ; x < info->x_size ; x++ ) { for( y = 0 ; y < info->y_size ; y++ ) { cxy_t cxy = HAL_CXY_FROM_XY( x , y ); if( cluster_is_active( cxy ) ) { hal_remote_memset( XPTR( cxy , &iopic_input ), 0xFF , sizeof(iopic_input_t) ); } } } // register input IRQ index for valid inputs uint32_t id; // input IRQ index uint8_t valid; // input IRQ is connected uint32_t type; // source device type uint8_t channel; // source device channel uint8_t is_rx; // source device direction uint32_t * ptr = NULL; // local pointer on one field in iopic_input stucture for( id = 0 ; id < CONFIG_MAX_EXTERNAL_IRQS ; id++ ) { valid = dev_tbl[i].irq[id].valid; type = dev_tbl[i].irq[id].dev_type; channel = dev_tbl[i].irq[id].channel; is_rx = dev_tbl[i].irq[id].is_rx; func = FUNC_FROM_TYPE( type ); // get pointer on relevant field in iopic_input if( valid ) { if ( func == DEV_FUNC_IOC ) ptr = &iopic_input.ioc[channel]; else if((func == DEV_FUNC_TXT) && (is_rx == 0)) ptr = &iopic_input.txt_tx[channel]; else if((func == DEV_FUNC_TXT) && (is_rx != 0)) ptr = &iopic_input.txt_rx[channel]; else if((func == DEV_FUNC_NIC) && (is_rx == 0)) ptr = &iopic_input.nic_tx[channel]; else if((func == DEV_FUNC_NIC) && (is_rx != 0)) ptr = &iopic_input.nic_rx[channel]; else if( func == DEV_FUNC_IOB ) ptr = &iopic_input.iob; else { printk("\n[PANIC] in %s : illegal source device for IOPIC input\n", __FUNCTION__ ); hal_core_sleep(); } // set one entry in all "iopic_input" structures for( x = 0 ; x < info->x_size ; x++ ) { for( y = 0 ; y < info->y_size ; y++ ) { cxy_t cxy = HAL_CXY_FROM_XY( x , y ); if( cluster_is_active( cxy ) ) { hal_remote_s64( XPTR( cxy , ptr ) , id ); } } } } } #if( DEBUG_KERNEL_INIT & 0x1 ) if( hal_time_stamp() > DEBUG_KERNEL_INIT ) { printk("\n[%s] created PIC chdev in cluster %x at cycle %d\n", __FUNCTION__ , local_cxy , (uint32_t)hal_time_stamp() ); dev_pic_inputs_display(); } #endif } // end iopic_init() /////////////////////////////////////////////////////////////////////////////////////////// // This function is called by all core[0]s in all cluster to complete the PIC device // initialisation, namely the informations attached to the LAPIC controller. // This initialisation must be done after the IOPIC initialisation, but before other // devices initialisation because the IRQ routing infrastructure is required for both // internal and external devices initialisation. /////////////////////////////////////////////////////////////////////////////////////////// // @ info : pointer on the local boot-info structure. /////////////////////////////////////////////////////////////////////////////////////////// static void __attribute__ ((noinline)) lapic_init( boot_info_t * info ) { boot_device_t * dev_tbl; // pointer on boot_info internal devices array uint32_t dev_nr; // number of internal devices uint32_t i; // device index in dev_tbl xptr_t base; // remote pointer on segment base uint32_t func; // device functionnal type in boot_info bool_t found; // LAPIC found // get number of internal peripherals and base dev_nr = info->int_dev_nr; dev_tbl = info->int_dev; // loop on internal peripherals to get the lapic device for( i = 0 , found = false ; i < dev_nr ; i++ ) { func = FUNC_FROM_TYPE( dev_tbl[i].type ); if( func == DEV_FUNC_ICU ) { base = dev_tbl[i].base; found = true; break; } } // if the LAPIC controller is not defined in the boot_info, // we simply don't initialize the PIC extensions in the kernel, // making the assumption that the LAPIC related informations // are hidden in the hardware specific PIC driver. if( found ) { // initialise the PIC extensions for // the core descriptor and core manager extensions dev_pic_extend_init( (uint32_t *)GET_PTR( base ) ); // initialize the "lapic_input" structure // defining how internal IRQs are connected to LAPIC uint32_t id; uint8_t valid; uint8_t channel; uint32_t func; for( id = 0 ; id < CONFIG_MAX_INTERNAL_IRQS ; id++ ) { valid = dev_tbl[i].irq[id].valid; func = FUNC_FROM_TYPE( dev_tbl[i].irq[id].dev_type ); channel = dev_tbl[i].irq[id].channel; if( valid ) // only valid local IRQs are registered { if ( func == DEV_FUNC_MMC ) lapic_input.mmc = id; else if( func == DEV_FUNC_DMA ) lapic_input.dma[channel] = id; else { printk("\n[PANIC] in %s : illegal source device for LAPIC input\n", __FUNCTION__ ); hal_core_sleep(); } } } } } // end lapic_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 __attribute__ ((noinline)) 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; } ///////////////////////////////// // kleenex debug function ///////////////////////////////// void display_fat( uint32_t step ) { fatfs_ctx_t * fatfs_ctx = fs_context[FS_TYPE_FATFS].extend; if( fatfs_ctx != NULL ) { printk("\n[%s] step %d at cycle %d\n", __FUNCTION__, step, (uint32_t)hal_get_cycles() ); xptr_t mapper_xp = fatfs_ctx->fat_mapper_xp; mapper_display_page( mapper_xp , 0 , 128 ); } else { printk("\n[%s] step %d : fatfs context not initialized\n", __FUNCTION__, step ); } } /////////////////////////////////////////////////////////////////////////////////////////// // This function is the entry point for the kernel initialisation. // It is executed by all cores in all clusters, but only core[0] 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. // Only core[0] in cluster 0 print the log messages. /////////////////////////////////////////////////////////////////////////////////////////// // @ 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 xptr_t vfs_root_inode_xp; // extended pointer on VFS root inode xptr_t devfs_dev_inode_xp; // extended pointer on DEVFS dev inode xptr_t devfs_external_inode_xp; // extended pointer on DEVFS external inode xptr_t devfs_internal_inode_xp; // extended pointer on DEVFS internal inode error_t error; reg_t status; // running core status register ///////////////////////////////////////////////////////////////////////////////// // STEP 1 : Each core get its core identifier from boot_info, and makes // a partial initialisation of its private idle thread descriptor. // core[0] initializes the "local_cxy" global variable. // core[0] in cluster[0] initializes the TXT0 chdev for log messages. ///////////////////////////////////////////////////////////////////////////////// error = get_core_identifiers( info, &core_lid, &core_cxy, &core_gid ); // core[0] initialize cluster identifier if( core_lid == 0 ) local_cxy = info->cxy; // each core gets a 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 ); // each core register core descriptor pointer in idle thread descriptor thread->core = &LOCAL_CLUSTER->core_tbl[core_lid]; // each core initializes the idle thread locks counters thread->busylocks = 0; #if DEBUG_BUSYLOCK // each core initialise the idle thread list of busylocks xlist_root_init( XPTR( local_cxy , &thread->busylocks_root ) ); #endif // core[0] initializes cluster info if( core_lid == 0 ) cluster_info_init( info ); // core[0] in cluster[0] initialises TXT0 chdev descriptor if( (core_lid == 0) && (core_cxy == 0) ) txt0_device_init( info ); // all cores check identifiers if( error ) { printk("\n[PANIC] in %s : illegal core : gid %x / cxy %x / lid %d", __FUNCTION__, core_lid, core_cxy, core_lid ); hal_core_sleep(); } ///////////////////////////////////////////////////////////////////////////////// if( core_lid == 0 ) xbarrier_wait( XPTR( 0 , &global_barrier ), (info->x_size * info->y_size) ); barrier_wait( &local_barrier , info->cores_nr ); ///////////////////////////////////////////////////////////////////////////////// #if DEBUG_KERNEL_INIT if( (core_lid == 0) & (local_cxy == 0) ) printk("\n[%s] exit barrier 1 : TXT0 initialized / cycle %d\n", __FUNCTION__, (uint32_t)hal_get_cycles() ); #endif ///////////////////////////////////////////////////////////////////////////////// // STEP 2 : core[0] initializes the cluter manager, // including the physical memory allocator. ///////////////////////////////////////////////////////////////////////////////// // core[0] initialises DQDT (only core[0] in cluster 0 build the quad-tree) if( core_lid == 0 ) dqdt_init(); // core[0] initialize other cluster manager complex structures if( core_lid == 0 ) { error = cluster_manager_init( info ); if( error ) { printk("\n[PANIC] in %s : cannot initialize cluster manager in cluster %x\n", __FUNCTION__, local_cxy ); hal_core_sleep(); } } ///////////////////////////////////////////////////////////////////////////////// if( core_lid == 0 ) xbarrier_wait( XPTR( 0 , &global_barrier ), (info->x_size * info->y_size) ); barrier_wait( &local_barrier , info->cores_nr ); ///////////////////////////////////////////////////////////////////////////////// #if DEBUG_KERNEL_INIT if( (core_lid == 0) & (local_cxy == 0) ) printk("\n[%s] exit barrier 2 : cluster manager initialized / cycle %d\n", __FUNCTION__, (uint32_t)hal_get_cycles() ); #endif ///////////////////////////////////////////////////////////////////////////////// // STEP 3 : all cores initialize the idle thread descriptor. // core[0] initializes the process_zero descriptor, // including the kernel VMM (both GPT and VSL) ///////////////////////////////////////////////////////////////////////////////// // all cores get pointer on local cluster manager & core descriptor cluster = &cluster_manager; core = &cluster->core_tbl[core_lid]; // all cores update the register(s) defining the kernel // entry points for interrupts, exceptions and syscalls, // this must be done before VFS initialisation, because // kernel_init() uses RPCs requiring IPIs... hal_set_kentry(); // all cores initialize the idle thread descriptor thread_idle_init( thread, THREAD_IDLE, &thread_idle_func, NULL, core_lid ); // core[0] initializes the process_zero descriptor, if( core_lid == 0 ) process_zero_create( &process_zero , info ); ///////////////////////////////////////////////////////////////////////////////// if( core_lid == 0 ) xbarrier_wait( XPTR( 0 , &global_barrier ), (info->x_size * info->y_size) ); barrier_wait( &local_barrier , info->cores_nr ); ///////////////////////////////////////////////////////////////////////////////// #if DEBUG_KERNEL_INIT if( (core_lid == 0) & (local_cxy == 0) ) printk("\n[%s] exit barrier 3 : kernel processs initialized / cycle %d\n", __FUNCTION__, (uint32_t)hal_get_cycles() ); #endif ///////////////////////////////////////////////////////////////////////////////// // STEP 4 : all cores initialize their private MMU // core[0] in cluster 0 initializes the IOPIC device. ///////////////////////////////////////////////////////////////////////////////// // all cores initialise their MMU hal_mmu_init( &process_zero.vmm.gpt ); // core[0] in cluster[0] initializes the PIC chdev, if( (core_lid == 0) && (local_cxy == 0) ) iopic_init( info ); //////////////////////////////////////////////////////////////////////////////// if( core_lid == 0 ) xbarrier_wait( XPTR( 0 , &global_barrier ), (info->x_size * info->y_size) ); barrier_wait( &local_barrier , info->cores_nr ); //////////////////////////////////////////////////////////////////////////////// #if DEBUG_KERNEL_INIT if( (core_lid == 0) & (local_cxy == 0) ) printk("\n[%s] exit barrier 4 : MMU and IOPIC initialized / cycle %d\n", __FUNCTION__, (uint32_t)hal_get_cycles() ); #endif //////////////////////////////////////////////////////////////////////////////// // STEP 5 : core[0] initializes the distibuted LAPIC descriptor. // core[0] initializes the internal chdev descriptors // core[0] initialize the local external chdev descriptors //////////////////////////////////////////////////////////////////////////////// // all core[0]s initialize their local LAPIC extension, if( core_lid == 0 ) lapic_init( info ); // core[0] scan the internal (private) peripherals, // and allocates memory for the corresponding chdev descriptors. if( core_lid == 0 ) internal_devices_init( info ); // All core[0]s contribute to initialise external peripheral chdev descriptors. // Each core[0][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 ); ///////////////////////////////////////////////////////////////////////////////// if( core_lid == 0 ) xbarrier_wait( XPTR( 0 , &global_barrier ), (info->x_size * info->y_size) ); barrier_wait( &local_barrier , info->cores_nr ); ///////////////////////////////////////////////////////////////////////////////// #if DEBUG_KERNEL_INIT if( (core_lid == 0) & (local_cxy == 0) ) printk("\n[%s] exit barrier 5 : chdevs initialised / cycle %d\n", __FUNCTION__, (uint32_t)hal_get_cycles() ); #endif #if( DEBUG_KERNEL_INIT & 1 ) if( (core_lid == 0) & (local_cxy == 0) ) chdev_dir_display(); #endif ///////////////////////////////////////////////////////////////////////////////// // STEP 6 : all cores enable IPI (Inter Procesor Interrupt), // all cores unblock the idle thread, and register it in scheduler. // core[0] in cluster[0] creates the VFS root inode. // It access the boot device to initialize the file system context. ///////////////////////////////////////////////////////////////////////////////// // All cores enable IPI dev_pic_enable_ipi(); hal_enable_irq( &status ); // all cores unblock the idle thread, and register it in scheduler thread_unblock( XPTR( local_cxy , thread ) , THREAD_BLOCKED_GLOBAL ); core->scheduler.idle = thread; // core[O] in cluster[0] creates the VFS root if( (core_lid == 0) && (local_cxy == 0 ) ) { vfs_root_inode_xp = XPTR_NULL; // Only FATFS is supported yet, // other File System can be introduced here if( CONFIG_VFS_ROOT_IS_FATFS ) { // 1. allocate memory for FATFS context in cluster 0 fatfs_ctx_t * fatfs_ctx = fatfs_ctx_alloc(); if( fatfs_ctx == NULL ) { printk("\n[PANIC] in %s : cannot create FATFS context in cluster 0\n", __FUNCTION__ ); hal_core_sleep(); } // 2. access boot device to initialize FATFS context fatfs_ctx_init( fatfs_ctx ); // 3. get various informations from FATFS context uint32_t root_dir_cluster = fatfs_ctx->root_dir_cluster; uint32_t cluster_size = fatfs_ctx->bytes_per_sector * fatfs_ctx->sectors_per_cluster; uint32_t total_clusters = fatfs_ctx->fat_sectors_count << 7; // 4. create VFS root inode in cluster 0 error = vfs_inode_create( FS_TYPE_FATFS, // fs_type 0, // attr 0, // rights 0, // uid 0, // gid &vfs_root_inode_xp ); // return if( error ) { printk("\n[PANIC] in %s : cannot create VFS root inode in cluster 0\n", __FUNCTION__ ); hal_core_sleep(); } // 5. update FATFS root inode "type" and "extend" fields cxy_t vfs_root_cxy = GET_CXY( vfs_root_inode_xp ); vfs_inode_t * vfs_root_ptr = GET_PTR( vfs_root_inode_xp ); hal_remote_s32( XPTR( vfs_root_cxy , &vfs_root_ptr->type ), INODE_TYPE_DIR ); hal_remote_spt( XPTR( vfs_root_cxy , &vfs_root_ptr->extend ), (void*)(intptr_t)root_dir_cluster ); // 6. initialize the generic VFS context for FATFS vfs_ctx_init( FS_TYPE_FATFS, // fs type 0, // attributes: unused total_clusters, // number of clusters cluster_size, // bytes vfs_root_inode_xp, // VFS root fatfs_ctx ); // extend } else { printk("\n[PANIC] in %s : unsupported VFS type in cluster 0\n", __FUNCTION__ ); hal_core_sleep(); } // create the <.> and <..> dentries in VFS root directory // the VFS root parent inode is the VFS root inode itself vfs_add_special_dentries( vfs_root_inode_xp, vfs_root_inode_xp ); // register VFS root inode in process_zero descriptor of cluster 0 process_zero.vfs_root_xp = vfs_root_inode_xp; process_zero.cwd_xp = vfs_root_inode_xp; } ///////////////////////////////////////////////////////////////////////////////// if( core_lid == 0 ) xbarrier_wait( XPTR( 0 , &global_barrier ), (info->x_size * info->y_size) ); barrier_wait( &local_barrier , info->cores_nr ); ///////////////////////////////////////////////////////////////////////////////// #if DEBUG_KERNEL_INIT if( (core_lid == 0) & (local_cxy == 0) ) printk("\n[%s] exit barrier 6 : VFS root (%x,%x) in cluster 0 / cycle %d\n", __FUNCTION__, GET_CXY(process_zero.vfs_root_xp), GET_PTR(process_zero.vfs_root_xp), (uint32_t)hal_get_cycles() ); #endif ///////////////////////////////////////////////////////////////////////////////// // STEP 7 : In all other clusters than cluster[0], the core[0] allocates memory // for the selected FS context, and initialise the local FS context and // the local VFS context from values stored in cluster 0. // They get the VFS root inode extended pointer from cluster 0. ///////////////////////////////////////////////////////////////////////////////// if( (core_lid == 0) && (local_cxy != 0) ) { // File System must be FATFS in this implementation, // but other File System can be introduced here if( CONFIG_VFS_ROOT_IS_FATFS ) { // 1. allocate memory for local FATFS context fatfs_ctx_t * local_fatfs_ctx = fatfs_ctx_alloc(); // check memory if( local_fatfs_ctx == NULL ) { printk("\n[PANIC] in %s : cannot create FATFS context in cluster %x\n", __FUNCTION__ , local_cxy ); hal_core_sleep(); } // 2. get local pointer on VFS context for FATFS vfs_ctx_t * vfs_ctx = &fs_context[FS_TYPE_FATFS]; // 3. get local pointer on FATFS context in cluster 0 fatfs_ctx_t * remote_fatfs_ctx = hal_remote_lpt( XPTR( 0 , &vfs_ctx->extend ) ); // 4. copy FATFS context from cluster 0 to local cluster hal_remote_memcpy( XPTR( local_cxy , local_fatfs_ctx ), XPTR( 0 , remote_fatfs_ctx ), sizeof(fatfs_ctx_t) ); // 5. copy VFS context from cluster 0 to local cluster hal_remote_memcpy( XPTR( local_cxy , vfs_ctx ), XPTR( 0 , vfs_ctx ), sizeof(vfs_ctx_t) ); // 6. update extend field in local copy of VFS context vfs_ctx->extend = local_fatfs_ctx; if( ((fatfs_ctx_t *)vfs_ctx->extend)->sectors_per_cluster != 8 ) { printk("\n[PANIC] in %s : illegal FATFS context in cluster %x\n", __FUNCTION__ , local_cxy ); hal_core_sleep(); } } // get extended pointer on VFS root inode from cluster 0 vfs_root_inode_xp = hal_remote_l64( XPTR( 0 , &process_zero.vfs_root_xp ) ); // update local process_zero descriptor process_zero.vfs_root_xp = vfs_root_inode_xp; process_zero.cwd_xp = vfs_root_inode_xp; } ///////////////////////////////////////////////////////////////////////////////// if( core_lid == 0 ) xbarrier_wait( XPTR( 0 , &global_barrier ), (info->x_size * info->y_size) ); barrier_wait( &local_barrier , info->cores_nr ); ///////////////////////////////////////////////////////////////////////////////// #if DEBUG_KERNEL_INIT if( (core_lid == 0) & (local_cxy == 1) ) printk("\n[%s] exit barrier 7 : VFS root (%x,%x) in cluster 1 / cycle %d\n", __FUNCTION__, GET_CXY(process_zero.vfs_root_xp), GET_PTR(process_zero.vfs_root_xp), (uint32_t)hal_get_cycles() ); #endif ///////////////////////////////////////////////////////////////////////////////// // STEP 8 : core[0] in cluster 0 makes the global DEVFS initialisation: // It initializes the DEVFS context, and creates the DEVFS // "dev" and "external" inodes in cluster 0. ///////////////////////////////////////////////////////////////////////////////// if( (core_lid == 0) && (local_cxy == 0) ) { // 1. allocate memory for DEVFS context extension in cluster 0 devfs_ctx_t * devfs_ctx = devfs_ctx_alloc(); if( devfs_ctx == NULL ) { printk("\n[PANIC] in %s : cannot create DEVFS context in cluster 0\n", __FUNCTION__ , local_cxy ); hal_core_sleep(); } // 2. initialize the DEVFS entry in the vfs_context[] array vfs_ctx_init( FS_TYPE_DEVFS, // fs type 0, // attributes: unused 0, // total_clusters: unused 0, // cluster_size: unused vfs_root_inode_xp, // VFS root devfs_ctx ); // extend // 3. create "dev" and "external" inodes (directories) devfs_global_init( process_zero.vfs_root_xp, &devfs_dev_inode_xp, &devfs_external_inode_xp ); // 4. initializes DEVFS context extension devfs_ctx_init( devfs_ctx, devfs_dev_inode_xp, devfs_external_inode_xp ); } ///////////////////////////////////////////////////////////////////////////////// if( core_lid == 0 ) xbarrier_wait( XPTR( 0 , &global_barrier ), (info->x_size * info->y_size) ); barrier_wait( &local_barrier , info->cores_nr ); ///////////////////////////////////////////////////////////////////////////////// #if DEBUG_KERNEL_INIT if( (core_lid == 0) & (local_cxy == 0) ) printk("\n[%s] exit barrier 8 : DEVFS root initialized in cluster 0 / cycle %d\n", __FUNCTION__, (uint32_t)hal_get_cycles() ); #endif ///////////////////////////////////////////////////////////////////////////////// // STEP 9 : In all clusters in parallel, core[0] completes DEVFS initialization. // Each core[0] get the "dev" and "external" extended pointers from // values stored in cluster(0), creates the DEVFS "internal" directory, // and creates the pseudo-files for all chdevs in local cluster. ///////////////////////////////////////////////////////////////////////////////// if( core_lid == 0 ) { // get extended pointer on "extend" field of VFS context for DEVFS in cluster 0 xptr_t extend_xp = XPTR( 0 , &fs_context[FS_TYPE_DEVFS].extend ); // get pointer on DEVFS context in cluster 0 devfs_ctx_t * devfs_ctx = hal_remote_lpt( extend_xp ); devfs_dev_inode_xp = hal_remote_l64( XPTR( 0 , &devfs_ctx->dev_inode_xp ) ); devfs_external_inode_xp = hal_remote_l64( XPTR( 0 , &devfs_ctx->external_inode_xp ) ); // populate DEVFS in all clusters devfs_local_init( devfs_dev_inode_xp, devfs_external_inode_xp, &devfs_internal_inode_xp ); } ///////////////////////////////////////////////////////////////////////////////// if( core_lid == 0 ) xbarrier_wait( XPTR( 0 , &global_barrier ), (info->x_size * info->y_size) ); barrier_wait( &local_barrier , info->cores_nr ); ///////////////////////////////////////////////////////////////////////////////// #if DEBUG_KERNEL_INIT if( (core_lid == 0) & (local_cxy == 0) ) printk("\n[%s] exit barrier 9 : DEVFS initialized in cluster 0 / cycle %d\n", __FUNCTION__, (uint32_t)hal_get_cycles() ); #endif #if( DEBUG_KERNEL_INIT & 1 ) if( (core_lid == 0) & (local_cxy == 0) ) vfs_display( vfs_root_inode_xp ); #endif ///////////////////////////////////////////////////////////////////////////////// // STEP 10 : core[0] in cluster 0 creates the first user process (process_init). // This include the first user process VMM (GPT and VSL) creation. // Finally, it prints the ALMOS-MKH banner. ///////////////////////////////////////////////////////////////////////////////// if( (core_lid == 0) && (local_cxy == 0) ) { process_init_create(); } #if DEBUG_KERNEL_INIT if( (core_lid == 0) & (local_cxy == 0) ) printk("\n[%s] exit barrier 10 : process_init created in cluster 0 / cycle %d\n", __FUNCTION__, (uint32_t)hal_get_cycles() ); #endif #if (DEBUG_KERNEL_INIT & 1) if( (core_lid == 0) & (local_cxy == 0) ) sched_display( 0 ); #endif if( (core_lid == 0) && (local_cxy == 0) ) { print_banner( (info->x_size * info->y_size) , info->cores_nr ); } #if CONFIG_INSTRUMENTATION_FOOTPRINT if( (core_lid == 0) & (local_cxy == 0) ) printk("\n\n***** memory fooprint for main kernel objects\n\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 descriptor : %d bytes\n" " - vseg descriptor : %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" " - vfs inode : %d bytes\n" " - vfs dentry : %d bytes\n" " - vfs file : %d bytes\n" " - vfs context : %d bytes\n" " - xhtab root : %d bytes\n" " - list item : %d bytes\n" " - xlist item : %d bytes\n" " - busylock : %d bytes\n" " - remote busylock : %d bytes\n" " - queuelock : %d bytes\n" " - remote queuelock : %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( remote_fifo_t ), sizeof( page_t ), sizeof( mapper_t ), sizeof( vseg_t ), sizeof( ppm_t ), sizeof( kcm_t ), sizeof( khm_t ), sizeof( vmm_t ), sizeof( gpt_t ), sizeof( vfs_inode_t ), sizeof( vfs_dentry_t ), sizeof( vfs_file_t ), sizeof( vfs_ctx_t ), sizeof( xhtab_t ), sizeof( list_entry_t ), sizeof( xlist_entry_t ), sizeof( busylock_t ), sizeof( remote_busylock_t ), sizeof( queuelock_t ), sizeof( remote_queuelock_t ), sizeof( rwlock_t ), sizeof( remote_rwlock_t )); #endif // each core activates its private TICK IRQ dev_pic_enable_timer( CONFIG_SCHED_TICK_MS_PERIOD ); ///////////////////////////////////////////////////////////////////////////////// if( core_lid == 0 ) xbarrier_wait( XPTR( 0 , &global_barrier ), (info->x_size * info->y_size) ); barrier_wait( &local_barrier , info->cores_nr ); ///////////////////////////////////////////////////////////////////////////////// #if DEBUG_KERNEL_INIT thread_t * this = CURRENT_THREAD; printk("\n[%s] : thread[%x,%x] on core[%x,%d] jumps to thread_idle_func() / cycle %d\n", __FUNCTION__ , this->process->pid, this->trdid, local_cxy, core_lid, (uint32_t)hal_get_cycles() ); #endif // each core jump to thread_idle_func thread_idle_func(); } // end kernel_init()