/*
 * boot_utils.h - TSAR bootloader utilities definition.
 * 
 * Authors :   Alain Greiner / Vu Son  (2016)
 *
 * Copyright (c) UPMC 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
 */

/****************************************************************************
 * This file defines various utility functions for the boot code.           *
 *                                                                          *
 * These functions are classified as follows:                               *
 *  - Remote accesses,                                                      *
 *  - Atomic operations,                                                    *
 *  - Memory functions,                                                     *
 *  - String functions,                                                     *
 *  - Display functions,                                                    *
 *  - Miscellaneous functions,                                              *
 *                                                                          *
 * Note that <stdint.h> and <stdarg.h> headers only contain macros, defined *
 * by the compiler itself, thus are accepted in the boot-loader, in         *
 * constrast to other headers in the C standard library.                    *
 ****************************************************************************/

#ifndef _BOOT_UTILS_H
#define _BOOT_UTILS_H

#include <hal_kernel_types.h>
#include <hard_config.h>

/****************************************************************************
 *                             Remote accesses.                             *
 ****************************************************************************/

/****************************************************************************
 * This function reads an aligned 32-bit word from a remote cluster.
 * @ xp     : extended pointer to the distant memory location.
 * @ returns the value read.      
 ****************************************************************************/
uint32_t boot_remote_lw(xptr_t xp);

/****************************************************************************
 * This function writes an aligned 32-bit word to a remote cluster.
 * @ xp     : extended pointer to the distant memory location.
 * @ data   : data value to be written.
 ****************************************************************************/
void boot_remote_sw(xptr_t xp, uint32_t data);

/****************************************************************************
 * This function atomically adds a value 'val' to the current value stored 
 * in a remote cluster.
 * @ xp     : extended pointer to the distant memory location.
 * @ val    : signed value to be added.
 * @ returns the value stored BEFORE the atomic operation.
 ****************************************************************************/
int32_t boot_remote_atomic_add(xptr_t xp, int32_t val);

/****************************************************************************
 * This function copies 'size' bytes from the buffer pointed to by 'src'
 * to the buffer pointed to by 'dest'. These 2 addresses may be in any 
 * different memory address spaces.  
 * @ dest   : extended pointer to the destination buffer. 
 * @ src    : extended pointer to the source buffer. 
 * @ size   : size of memory block to be copied (in bytes).   
 ****************************************************************************/
void boot_remote_memcpy(xptr_t dest, xptr_t src, uint32_t size);

/****************************************************************************
 *                            Atomic operations.                            *
 ****************************************************************************/

/****************************************************************************
 * This function atomically adds an value 'val' to the current variable  
 * pointed to by 'ptr'. It only returns when the atomic operation is 
 * successful.  
 * @ ptr    : pointer to the variable to be modified.  
 * @ val    : signed value to be added.
 * @ returns the value of the variable BEFORE the atomic operation.  
 ****************************************************************************/
int32_t boot_atomic_add(int32_t* ptr, int32_t val);

/****************************************************************************
 *                            Memory functions.                             *
 ****************************************************************************/

/****************************************************************************
 * This function performs a local memory copy (destination and source  
 * addresses are in the same memory space) of 'size' bytes from 'src' 
 * address to 'dest' address.                    
 * @ dest   : destination physical address,  
 * @ src    : source physical address,   
 * @ size   : size of memory block to be copied in bytes.
 ****************************************************************************/
void boot_memcpy(void* dest, void* src, uint32_t size);

/****************************************************************************
 * This function fills the first 'size' bytes of the local memory area, 
 * pointed to by 'base' with a constant value 'val'.                  
 * @ base   : base address of the memory area to be initialized,   
 * @ val    : value of the constant byte to initialize the area, 
 * @ size   : size of memory block to be filled in bytes.   
 ****************************************************************************/
void boot_memset(void* base, int val,   uint32_t size);

/****************************************************************************
 *                            String functions                              *
 ****************************************************************************/

/****************************************************************************
 * This function converts the letter 'c' to lower case, if possible. 
 * @ c  : letter to be converted.                   
 * @ returns the converted letter, or 'c' if conversion not possible.
 ****************************************************************************/
static inline unsigned char boot_to_lower(unsigned char c)
{
    return ((c >= 'A') && (c <= 'Z')) ? (c | 0x20) : c;

} // boot_to_lower()

/****************************************************************************
 * This function converts the letter 'c' to upper case, if possible.
 * @ c  : letter to be converted. 
 * @ returns the converted letter, or 'c' if conversion not possible.
 ****************************************************************************/
static inline unsigned char boot_to_upper(unsigned char c)
{
    return ((c >= 'a') && (c <= 'z')) ? (c & ~(0x20)) : c;

} // boot_to_upper()

/****************************************************************************
 * This function copies the string pointed to by 'src' (the terminating 
 * null byte '\0' NOT included) to the buffer pointed to by 'dest'. 
 * @ src    : pointer to the string to be copied.  
 * @ dest   : pointer to the destination string. 
 ****************************************************************************/
void boot_strcpy(char* dest, char* src);

/****************************************************************************
 * This function calculates the length of the string pointed to by 's',
 * excluding the terminating null byte '\0'.  
 * @ s  : pointer to the string whose length is to be computed. 
 * @ returns the number of bytes in the string. 
 ****************************************************************************/
uint32_t boot_strlen(char* s);

/****************************************************************************
 * This function compares the 2 strings pointed to by 's1' and 's2'.
 * @ s1 : pointer to the first string to be compared.
 * @ s2 : pointer to the second string to be compared.
 * @ returns 0 if these 2 strings match, 1 otherwise. 
 ****************************************************************************/
int boot_strcmp(char* s1, char* s2);

/****************************************************************************
 *                            Display functions                             *
 ****************************************************************************/

/****************************************************************************
 * This function writes the NUL terminated string pointed to by 'str' 
 * to the boot TTY terminal.                            
 * @ str    : pointer to the string to be printed on the boot TTY terminal.
 ****************************************************************************/
void boot_puts(char* str);

/****************************************************************************
 * This function produces output, according to the 'format' format, to the 
 * boot TTY terminal.
 * @ format : the string defining the format of the output. It is composed 
 *            of 0 or more directives:                                  
 *            - ordinary characters (not %), which are copied unchanged to
 *              the boot TTY terminal.                                  
 *            - conversion specifications (introduced by the character %, 
 *              ended by a conversion specifier), each of which results in 
 *              fetching 0 or more subsequent arguments. The arguments must
 *              correspond properly (after type promotion) with the  
 *              conversion specifier.                            
 *                                                            
 * Conversion specifiers:                                  
 *  - %d : 32-bit signed decimal notation of an integer,  
 *  - %u : 32-bit unsigned decimal notation of an integer,
 *  - %x : 32-bit unsigned hexadecimal notation of an integer, 
 *  - %l : 64-bit unsigned hexadecimal notation of an integer,
 *  - %c : character,                                     
 *  - %s : NUL terminated string.  
 ****************************************************************************/
void boot_printf(char* format, ...);

/****************************************************************************
 *                            Misc. functions.                              *
 ****************************************************************************/

/****************************************************************************
 * This function causes a termination during the boot procedure once the 
 * boot code detects an error. 
 ****************************************************************************/
void boot_exit( void ) __attribute__((noreturn));

/****************************************************************************
 * This function returns the cycle count stored in the CP0_COUNT register 
 * of the currently running processor.  
 * @ returns the processor cycle count. 
 ****************************************************************************/
uint32_t boot_get_proctime( void );

/****************************************************************************
 * This function returns the global hardware identifier gid stored in the 
 * CP0_PROCID register of the currently running processor.
 * @ returns the processor gid
 ****************************************************************************/
uint32_t boot_get_procid( void );

/****************************************************************************
 * This structure defines a toggling barrier, that can be used to  
 * synchronize a group of cores, whether or not they are in a same cluster,
 * without any specific initialization.   
 ****************************************************************************/
typedef struct boot_remote_barrier_s
{
    uint32_t current;                      // Number of arrived cores
    uint32_t sense;                        // Toggle barrier state
    uint32_t pad[(CACHE_LINE_SIZE>>2)-2];  // Padding
}
boot_remote_barrier_t;

/****************************************************************************
 * This function blocks all processors arriving at the barrier pointed to 
 * by the extend pointer 'xp_barrier' and only returns when all 'count' 
 * expected processors reach the barrier.  
 * @ xp_barrier : extended pointer to a toggling barrier. 
 * @ count      : number of expected processors.  
 ****************************************************************************/
void boot_remote_barrier( xptr_t   xp_barrier, 
                          uint32_t count );

/****************************************************************************
 * This structure defines a remote queuing spinlock, that can be used to 
 * synchronize a group of cores, whether or not they are in a same cluster,
 * without any specific initialization.  
 ****************************************************************************/
typedef struct boot_remote_spinlock_s
{
    uint32_t     ticket;                       // next free ticket index        
    uint32_t     current;                      // current owner index
    uint32_t     pad[(CACHE_LINE_SIZE>>2)-2];  // Padding
} 
boot_remote_spinlock_t;

/****************************************************************************
 * This blocking function returns only when the lock is successfully taken.
 * @ lock_xp    : extended pointer on lock.
 ****************************************************************************/
void boot_remote_lock( xptr_t  lock_xp );

/****************************************************************************
 * This function release the lock.
 * @ lock_xp    : extended pointer on lock.
 ****************************************************************************/
void boot_remote_unlock( xptr_t  lock_xp );


#endif // _BOOT_UTILS_H
