/* * kernel_init.c - kernel parallel initialization * * Authors : Mohamed Lamine Karaoui (2015) * Alain Greiner (2016,2017,2018,2019,2020) * * 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 #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 must be unused to help debug "CLUSTER_KCM", // 1 "SCHED_STATE", // 2 "VMM_STACK", // 3 "VMM_MMAP", // 4 "KCM_STATE", // 5 "KHM_STATE", // 6 "HTAB_STATE", // 7 "CORE_ALARMS", // 8 "VFS_CTX", // 9 "PPM_FREE", // 10 "THREAD_JOIN", // 11 "XHTAB_STATE", // 12 "CHDEV_QUEUE", // 13 "CHDEV_TXT0", // 14 "CHDEV_TXTLIST", // 15 "PAGE_STATE", // 16 "MUTEX_STATE", // 17 "CONDVAR_STATE", // 18 "SEM_STATE", // 19 "PROCESS_CWD", // 20 "BARRIER_STATE", // 21 "LISTEN_SOCKET", // 22 "CLUSTER_PREFTBL", // 23 "SOCKET_STATE", // 24 "PPM_DIRTY", // 25 "CLUSTER_LOCALS", // 26 "CLUSTER_COPIES", // 27 "PROCESS_CHILDREN", // 28 "PROCESS_USERSYNC", // 29 "PROCESS_FDARRAY", // 30 "PROCESS_DIR", // 31 "VMM_VSL", // 32 "PROCESS_THTBL", // 33 "MAPPER_STATE", // 34 "VFS_SIZE", // 35 "VFS_FILE", // 36 "VFS_MAIN", // 37 "FATFS_FAT", // 38 "FBF_WINDOWS", // 39 }; // debug variables to analyse the sys_read() 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 // debug variables 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 ); // make TXT specific initialisations dev_txt_init( &txt0_tx_chdev ); // 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_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 ) { // create chdev in local cluster chdev_ptr = chdev_create( func, impl, 0, // channel false, // direction base ); if( chdev_ptr == NULL ) { printk("\n[PANIC] in %s : cannot create MMC chdev\n", __FUNCTION__ ); hal_core_sleep(); } #if (DEBUG_KERNEL_INIT & 0x1) if( hal_time_stamp() > DEBUG_KERNEL_INIT ) printk("\n[%s] created chdev[%x,%x] for MMC\n", __FUNCTION__ , local_cxy , chdev_ptr ); #endif // 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] initialised chdev[%x,%x] for MMC\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 ); if( chdev_ptr == NULL ) { printk("\n[PANIC] in %s : cannot create DMA chdev\n", __FUNCTION__ ); hal_core_sleep(); } #if (DEBUG_KERNEL_INIT & 0x1) if( hal_time_stamp() > DEBUG_KERNEL_INIT ) printk("\n[%s] cxy %x : created chdev[%x,%x] for DMA[%d]\n", __FUNCTION__ , local_cxy , chdev_ptr , channel ); #endif // 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] initialised chdev[%x,%x] for DMA[%d]\n", __FUNCTION__ , local_cxy , chdev_ptr , channel ); #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], 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(); } // loop 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, // and 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(); } #if (DEBUG_KERNEL_INIT & 0x1) if( hal_time_stamp() > DEBUG_KERNEL_INIT ) printk("\n[%s] created chdev[%x,%x] for %s[%d] / is_rx %d\n", __FUNCTION__ , local_cxy , chdev , chdev_func_str(func) , channel , rx ); #endif // 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 & 1 ) if( hal_time_stamp() > DEBUG_KERNEL_INIT ) printk("\n[%s] initialised chdev[%x,%x] for %s\n", __FUNCTION__ , local_cxy, chdev , chdev->name ); #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][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 -1 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 -1; } /////////////////////////////////////////////////////////////////////////////////////////// // This function is the entry point for the kernel initialisation. // It is executed by all cores in all clusters, but only core[cxy][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 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 cluster manager, // including the physical memory allocators. ///////////////////////////////////////////////////////////////////////////////// // core[0] initialises DQDT (only core[0][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] initialize the distibuted LAPIC descriptor. // core[0] initialize 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 CONFIG_INSTRUMENTATION_CHDEVS 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. // The core[0] in cluster defined by the CONFIG_VFS_ROOT_CXY parameter, // access the IOC device to initialize the VFS for the FS identified // by the CONFIG_VFS_ROOT_IS_*** parameter. It does the following // actions in the VFS_ROOT cluster : // 1. allocate and initialize the selected FS context, // 2. create and initializes the VFS root inodes, // 3. initialize the VFS context for FATFS (in fs_context[] array), // 4. create the <.> and <..> dentries in VFS root directory, // 5. register the VFS root inode in process_zero descriptor, // 6. allocate the DEVFS context, // 7. initialize the VFS context for DEVFS (in fs_context[] array), // 8. create the and inodes, // 9. initialize the DEVFS 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 VFS_ROOT cluster creates the VFS root if( (core_lid == 0) && (local_cxy == CONFIG_VFS_ROOT_CXY ) ) { // Only FATFS is supported yet, // TODO other File System can be introduced below if( CONFIG_VFS_ROOT_IS_FATFS ) { // 1. allocate memory and initialize FATFS context in VFS_ROOT cluster xptr_t fatfs_ctx_xp = fatfs_ctx_alloc( CONFIG_VFS_ROOT_CXY ); if( fatfs_ctx_xp == XPTR_NULL ) { printk("\n[PANIC] in %s : cannot allocate FATFS context in cluster %x\n", __FUNCTION__ , CONFIG_VFS_ROOT_CXY ); hal_core_sleep(); } // initialise FATFS context in VFS_ROOT cluster from IOC device (boot_record) error = fatfs_ctx_init( fatfs_ctx_xp ); if( error ) { printk("\n[PANIC] in %s : cannot initialize FATFS context in cluster %x\n", __FUNCTION__ , CONFIG_VFS_ROOT_CXY ); hal_core_sleep(); } #if( DEBUG_KERNEL_INIT & 1 ) printk("\n[%s] initialized FATFS context in cluster %x\n", __FUNCTION__, CONFIG_VFS_ROOT_CXY ); #endif // get various informations from FATFS context fatfs_ctx_t * fatfs_ctx_ptr = GET_PTR( fatfs_ctx_xp ); uint32_t root_dir_cluster = hal_remote_l32( XPTR( CONFIG_VFS_ROOT_CXY, &fatfs_ctx_ptr->root_dir_cluster ) ); uint32_t bytes_per_sector = hal_remote_l32( XPTR( CONFIG_VFS_ROOT_CXY, &fatfs_ctx_ptr->bytes_per_sector ) ); uint32_t sectors_per_cluster = hal_remote_l32( XPTR( CONFIG_VFS_ROOT_CXY, &fatfs_ctx_ptr->sectors_per_cluster ) ); uint32_t cluster_size = bytes_per_sector * sectors_per_cluster; uint32_t fat_sectors_count = hal_remote_l32( XPTR( CONFIG_VFS_ROOT_CXY, &fatfs_ctx_ptr->fat_sectors_count ) ) << 7; uint32_t total_clusters = fat_sectors_count << 7; // 2. create VFS root inode in VFS_ROOT cluster // TODO define attr, rights, uid, gid error = vfs_inode_create( CONFIG_VFS_ROOT_CXY, // target cluster 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 %x\n", __FUNCTION__ , CONFIG_VFS_ROOT_CXY ); hal_core_sleep(); } #if( DEBUG_KERNEL_INIT & 1 ) vfs_inode_t * root_inode = GET_PTR( vfs_root_inode_xp ); printk("\n[%s] created root inode %x in cluster %x / ctx %x\n", __FUNCTION__, root_inode, CONFIG_VFS_ROOT_CXY, root_inode->ctx ); #endif // update FATFS root inode "type" and "extend" fields vfs_inode_t * vfs_root_inode_ptr = GET_PTR( vfs_root_inode_xp ); hal_remote_s32( XPTR( CONFIG_VFS_ROOT_CXY , &vfs_root_inode_ptr->type ), FILE_TYPE_DIR ); hal_remote_spt( XPTR( CONFIG_VFS_ROOT_CXY , &vfs_root_inode_ptr->extend ), (void*)(intptr_t)root_dir_cluster ); // 3. initialize the VFS context for FATFS in VFS_ROOT cluster vfs_ctx_init( CONFIG_VFS_ROOT_CXY, // target cluster FS_TYPE_FATFS, // fs type total_clusters, // number of clusters cluster_size, // bytes vfs_root_inode_xp, // VFS root fatfs_ctx_ptr ); // extend #if( DEBUG_KERNEL_INIT & 1 ) vfs_ctx_t * vfs_for_fatfs_ctx = &fs_context[FS_TYPE_FATFS]; printk("\n[%s] initialized VFS_for_FATFS context in cluster %x / ctx %x / fs_type %d\n", __FUNCTION__, CONFIG_VFS_ROOT_CXY, vfs_for_fatfs_ctx, vfs_for_fatfs_ctx->type ); #endif } else { printk("\n[PANIC] in %s : unsupported VFS type in cluster %x\n", __FUNCTION__ , CONFIG_VFS_ROOT_CXY ); hal_core_sleep(); } // 4. 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 ); // 5. register VFS root inode in target cluster process_zero descriptor hal_remote_s64( XPTR( CONFIG_VFS_ROOT_CXY , &process_zero.vfs_root_xp ), vfs_root_inode_xp ); hal_remote_s64( XPTR( CONFIG_VFS_ROOT_CXY , &process_zero.cwd_xp ), vfs_root_inode_xp ); // 6. allocate memory for DEVFS context in VFS_ROOT cluster xptr_t devfs_ctx_xp = devfs_ctx_alloc( CONFIG_VFS_ROOT_CXY ); if( devfs_ctx_xp == XPTR_NULL ) { printk("\n[PANIC] in %s : cannot create DEVFS context in cluster %x\n", __FUNCTION__ , CONFIG_VFS_ROOT_CXY ); hal_core_sleep(); } // 7. initialize the VFS context for DEVFS in VFS_ROOT cluster vfs_ctx_init( CONFIG_VFS_ROOT_CXY, // target cluster FS_TYPE_DEVFS, // fs type 0, // total_clusters: unused 0, // cluster_size: unused vfs_root_inode_xp, // VFS root GET_PTR( devfs_ctx_xp ) ); // extend #if( DEBUG_KERNEL_INIT & 1 ) vfs_ctx_t * vfs_for_devfs_ctx = &fs_context[FS_TYPE_DEVFS]; printk("\n[%s] initialized VFS_for_DEVFS context in cluster %x / ctx %x / fs_type %d\n", __FUNCTION__, CONFIG_VFS_ROOT_CXY, vfs_for_devfs_ctx, vfs_for_devfs_ctx->type ); #endif // 8. create "dev" and "external" inodes (directories) devfs_global_init( vfs_root_inode_xp, &devfs_dev_inode_xp, &devfs_external_inode_xp ); // 9. initializes DEVFS context in VFS_ROOT cluster devfs_ctx_init( devfs_ctx_xp, 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 == CONFIG_VFS_ROOT_CXY) ) printk("\n[%s] exit barrier 6 : VFS root inode (%x) created in cluster (%x) / cycle %d\n", __FUNCTION__, GET_CXY(vfs_root_inode_xp), GET_PTR(vfs_root_inode_xp), (uint32_t)hal_get_cycles() ); #endif ///////////////////////////////////////////////////////////////////////////////// // STEP 7 : In all clusters other than the VFS_ROOT cluster, the core[0] makes // the following local actions to complete the VFS initialisation : // 1. allocate a local context for the selected FS extension, // 2. copy FS context from VFS_ROOT cluster to local cluster, // 3. copy VFS_for_FATFS context from VFS_ROOT cluster to local cluster, // 4. allocate a local context for the DEVFS extension, // 5. copy DEVFS context from VFS_ROOT cluster to local cluster, // 6. update the local "root_inode_xp" field in process_zero. ///////////////////////////////////////////////////////////////////////////////// if( (core_lid == 0) && (local_cxy != CONFIG_VFS_ROOT_CXY) ) { // only FATFS is supported yet // TODO other File System can be introduced below if( CONFIG_VFS_ROOT_IS_FATFS ) { // 1. allocate a local FATFS context extension xptr_t local_fatfs_ctx_xp = fatfs_ctx_alloc( local_cxy ); if( local_fatfs_ctx_xp == XPTR_NULL ) { printk("\n[PANIC] in %s : cannot create FATFS context in cluster %x\n", __FUNCTION__ , local_cxy ); hal_core_sleep(); } // get local pointer on VFS_for_FATFS context (same in all clusters) vfs_ctx_t * vfs_fat_ctx_ptr = &fs_context[FS_TYPE_FATFS]; // build extended pointer on VFS_for_FATFS "extend" field in VFS_ROOT cluster xptr_t fatfs_extend_xp = XPTR( CONFIG_VFS_ROOT_CXY , &vfs_fat_ctx_ptr->extend ); // get local pointer on FATFS context in VFS_ROOT cluster fatfs_ctx_t * remote_fatfs_ctx_ptr = hal_remote_lpt( fatfs_extend_xp ); // build extended pointer on FATFS context in VFS_ROOT cluster xptr_t remote_fatfs_ctx_xp = XPTR( CONFIG_VFS_ROOT_CXY , remote_fatfs_ctx_ptr ); // 2. copy FATFS context from VFS_ROOT cluster to local cluster hal_remote_memcpy( local_fatfs_ctx_xp, remote_fatfs_ctx_xp, sizeof(fatfs_ctx_t) ); // build extended pointer on remote VFS_for_FATFS context xptr_t remote_vfs_ctx_xp = XPTR( CONFIG_VFS_ROOT_CXY , vfs_fat_ctx_ptr ); // build extended pointer on local VFS_for_FATFS context xptr_t local_vfs_ctx_xp = XPTR( local_cxy , vfs_fat_ctx_ptr ); // 3. copy VFS_for_FATFS context from VFS_ROOT cluster to local cluster hal_remote_memcpy( local_vfs_ctx_xp, remote_vfs_ctx_xp, sizeof(vfs_ctx_t) ); // update "extend" field in local VFS_for_FATFS context vfs_fat_ctx_ptr->extend = GET_PTR( local_fatfs_ctx_xp ); // check local FATFS and VFS context copies assert( __FUNCTION__, (((fatfs_ctx_t *)vfs_fat_ctx_ptr->extend)->sectors_per_cluster == 8), "illegal FATFS context" ); } else { printk("\n[PANIC] in %s : unsupported VFS type in cluster %x\n", __FUNCTION__ , local_cxy ); hal_core_sleep(); } // 4. allocate a local DEVFS context extension, xptr_t local_devfs_ctx_xp = devfs_ctx_alloc( local_cxy ); // get local pointer on VFS_for_DEVFS context (same in all clusters) vfs_ctx_t * vfs_dev_ctx_ptr = &fs_context[FS_TYPE_DEVFS]; // build extended pointer on VFS_for_DEVFS extend field in VFS_ROOT cluster xptr_t remote_extend_xp = XPTR( CONFIG_VFS_ROOT_CXY , &vfs_dev_ctx_ptr->extend ); // get local pointer on DEVFS context in VFS_ROOT cluster devfs_ctx_t * remote_devfs_ctx_ptr = hal_remote_lpt( remote_extend_xp ); // build extended pointer on FATFS context in VFS_ROOT cluster xptr_t remote_devfs_ctx_xp = XPTR( CONFIG_VFS_ROOT_CXY , remote_devfs_ctx_ptr ); // 5. copy DEVFS context from VFS_ROOT cluster to local cluster hal_remote_memcpy( local_devfs_ctx_xp, remote_devfs_ctx_xp, sizeof(devfs_ctx_t) ); // update "extend" field in local VFS_for_DEVFS context vfs_dev_ctx_ptr->extend = GET_PTR( local_devfs_ctx_xp ); // get extended pointer on VFS root inode from VFS_ROOT cluster vfs_root_inode_xp = hal_remote_l64( XPTR( CONFIG_VFS_ROOT_CXY, &process_zero.vfs_root_xp ) ); // 6. 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 == 0) ) printk("\n[%s] exit barrier 7 : VFS & DEVFS contexts replicated in all clusters / cycle %d\n", __FUNCTION__ , (uint32_t)hal_get_cycles() ); #endif ///////////////////////////////////////////////////////////////////////////////// // STEP 8 : In all clusters in parallel, core[0] completes DEVFS initialization. // Each core[0] creates the local DEVFS "internal" directory, // and creates the pseudo-files for chdevs placed in local cluster. ///////////////////////////////////////////////////////////////////////////////// if( core_lid == 0 ) { // get local pointer on local DEVFS context devfs_ctx_t * ctx = fs_context[FS_TYPE_DEVFS].extend; // populate DEVFS in all clusters devfs_local_init( ctx->dev_inode_xp, ctx->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 initialized in all clusters / 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 9 : core[0] in cluster 0 creates the first user process (process_init). // This include the 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 9 : process_init created in cluster 0 / cycle %d\n", __FUNCTION__, (uint32_t)hal_get_cycles() ); #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" " - socket descriptor : %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" " - vmm manager : %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( socket_t ), sizeof( remote_fifo_t ), sizeof( page_t ), sizeof( mapper_t ), sizeof( vseg_t ), sizeof( ppm_t ), sizeof( kcm_t ), sizeof( vmm_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 // number of cycles per TICK (depends on the actual system clock frequency uint32_t cycles_per_tick = cluster->sys_clk / CONFIG_SCHED_TICKS_PER_SECOND; // each core activates its private TICK IRQ dev_pic_enable_timer( cycles_per_tick ); ///////////////////////////////////////////////////////////////////////////////// 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()