mirror of
				https://gitlab.com/qemu-project/ipxe.git
				synced 2025-10-30 07:56:50 +08:00 
			
		
		
		
	Compare commits
	
		
			3 Commits
		
	
	
		
			c69f9589cc
			...
			21940425c4
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 21940425c4 | |||
| b23204b383 | |||
| fa1c24d14b | 
| @ -10,6 +10,7 @@ INCDIRS		:= arch/$(ARCH)/include arch/riscv/include $(INCDIRS) | ||||
| # RISCV-specific directories containing source files | ||||
| # | ||||
| SRCDIRS		+= arch/riscv/core | ||||
| SRCDIRS		+= arch/riscv/interface/sbi | ||||
|  | ||||
| # RISCV-specific flags | ||||
| # | ||||
|  | ||||
| @ -14,6 +14,8 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); | ||||
|  * @{ | ||||
|  */ | ||||
|  | ||||
| #define ERRFILE_sbi_reboot	( ERRFILE_ARCH | ERRFILE_CORE | 0x00000000 ) | ||||
|  | ||||
| /** @} */ | ||||
|  | ||||
| #endif /* _BITS_ERRFILE_H */ | ||||
|  | ||||
							
								
								
									
										14
									
								
								src/arch/riscv/include/bits/reboot.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										14
									
								
								src/arch/riscv/include/bits/reboot.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,14 @@ | ||||
| #ifndef _BITS_REBOOT_H | ||||
| #define _BITS_REBOOT_H | ||||
|  | ||||
| /** @file | ||||
|  * | ||||
|  * RISCV-specific reboot API implementations | ||||
|  * | ||||
|  */ | ||||
|  | ||||
| FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); | ||||
|  | ||||
| #include <ipxe/sbi_reboot.h> | ||||
|  | ||||
| #endif /* _BITS_REBOOT_H */ | ||||
							
								
								
									
										167
									
								
								src/arch/riscv/include/ipxe/sbi.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										167
									
								
								src/arch/riscv/include/ipxe/sbi.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,167 @@ | ||||
| #ifndef _IPXE_SBI_H | ||||
| #define _IPXE_SBI_H | ||||
|  | ||||
| /** @file | ||||
|  * | ||||
|  * Supervisor Binary Interface (SBI) | ||||
|  * | ||||
|  */ | ||||
|  | ||||
| FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); | ||||
|  | ||||
| #include <stdint.h> | ||||
|  | ||||
| /** An SBI function return value */ | ||||
| struct sbi_return { | ||||
| 	/** Error status (returned in a0) */ | ||||
| 	long error; | ||||
| 	/** Data value (returned in a1) */ | ||||
| 	long value; | ||||
| }; | ||||
|  | ||||
| /** | ||||
|  * @defgroup sbierrors SBI errors | ||||
|  * | ||||
|  * *{ | ||||
|  */ | ||||
| #define SBI_SUCCESS 0			/**< Completed successfully */ | ||||
| #define SBI_ERR_FAILED -1		/**< Failed */ | ||||
| #define SBI_ERR_NOT_SUPPORTED -2	/**< Not supported */ | ||||
| #define SBI_ERR_INVALID_PARAM -3	/**< Invalid parameter(s) */ | ||||
| #define SBI_ERR_DENIED -4		/**< Denied or not allowed */ | ||||
| #define SBI_ERR_INVALID_ADDRESS -5	/**< Invalid address(es) */ | ||||
| #define SBI_ERR_ALREADY_AVAILABLE -6	/**< Already available */ | ||||
| #define SBI_ERR_ALREADY_STARTED -7	/**< Already started */ | ||||
| #define SBI_ERR_ALREADY_STOPPED -8	/**< Already stopped */ | ||||
| #define SBI_ERR_NO_SHMEM -9		/**< Shared memory not available */ | ||||
| #define SBI_ERR_INVALID_STATE -10	/**< Invalid state */ | ||||
| #define SBI_ERR_BAD_RANGE -11		/**< Bad (or invalid) range */ | ||||
| #define SBI_ERR_TIMEOUT -12		/**< Failed due to timeout */ | ||||
| #define SBI_ERR_IO -13			/**< Input/output error */ | ||||
| /** @} */ | ||||
|  | ||||
| /** Construct SBI extension ID */ | ||||
| #define SBI_EID( c1, c2, c3, c4 ) \ | ||||
| 	( (int) ( ( (c1) << 24 ) | ( (c2) << 16 ) | ( (c3) << 8 ) | (c4) ) ) | ||||
|  | ||||
| /** | ||||
|  * Call supervisor with no parameters | ||||
|  * | ||||
|  * @v eid		Extension ID | ||||
|  * @v fid		Function ID | ||||
|  * @ret ret		Return value | ||||
|  */ | ||||
| static inline __attribute__ (( always_inline )) struct sbi_return | ||||
| sbi_ecall_0 ( int eid, int fid ) { | ||||
| 	register unsigned long a7 asm ( "a7" ) = ( ( long ) eid ); | ||||
| 	register unsigned long a6 asm ( "a6" ) = ( ( long ) fid ); | ||||
| 	register unsigned long a0 asm ( "a0" ); | ||||
| 	register unsigned long a1 asm ( "a1" ); | ||||
| 	struct sbi_return ret; | ||||
|  | ||||
| 	__asm__ __volatile__ ( "ecall" | ||||
| 			       : "=r" ( a0 ), "=r" ( a1 ) | ||||
| 			       : "r" ( a6 ), "r" ( a7 ) | ||||
| 			       : "memory" ); | ||||
| 	ret.error = a0; | ||||
| 	ret.value = a1; | ||||
| 	return ret; | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * Call supervisor with one parameter | ||||
|  * | ||||
|  * @v eid		Extension ID | ||||
|  * @v fid		Function ID | ||||
|  * @v param0		Parameter 0 | ||||
|  * @ret ret		Return value | ||||
|  */ | ||||
| static inline __attribute__ (( always_inline )) struct sbi_return | ||||
| sbi_ecall_1 ( int eid, int fid, unsigned long p0 ) { | ||||
| 	register unsigned long a7 asm ( "a7" ) = ( ( long ) eid ); | ||||
| 	register unsigned long a6 asm ( "a6" ) = ( ( long ) fid ); | ||||
| 	register unsigned long a0 asm ( "a0" ) = p0; | ||||
| 	register unsigned long a1 asm ( "a1" ); | ||||
| 	struct sbi_return ret; | ||||
|  | ||||
| 	__asm__ __volatile__ ( "ecall" | ||||
| 			       : "+r" ( a0 ), "=r" ( a1 ) | ||||
| 			       : "r" ( a6 ), "r" ( a7 ) | ||||
| 			       : "memory" ); | ||||
| 	ret.error = a0; | ||||
| 	ret.value = a1; | ||||
| 	return ret; | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * Call supervisor with two parameters | ||||
|  * | ||||
|  * @v eid		Extension ID | ||||
|  * @v fid		Function ID | ||||
|  * @v param0		Parameter 0 | ||||
|  * @v param1		Parameter 1 | ||||
|  * @ret ret		Return value | ||||
|  */ | ||||
| static inline __attribute__ (( always_inline )) struct sbi_return | ||||
| sbi_ecall_2 ( int eid, int fid, unsigned long p0, unsigned long p1 ) { | ||||
| 	register unsigned long a7 asm ( "a7" ) = ( ( long ) eid ); | ||||
| 	register unsigned long a6 asm ( "a6" ) = ( ( long ) fid ); | ||||
| 	register unsigned long a0 asm ( "a0" ) = p0; | ||||
| 	register unsigned long a1 asm ( "a1" ) = p1; | ||||
| 	struct sbi_return ret; | ||||
|  | ||||
| 	__asm__ __volatile__ ( "ecall" | ||||
| 			       : "+r" ( a0 ), "+r" ( a1 ) | ||||
| 			       : "r" ( a6 ), "r" ( a7 ) | ||||
| 			       : "memory" ); | ||||
| 	ret.error = a0; | ||||
| 	ret.value = a1; | ||||
| 	return ret; | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * Call supervisor with three parameters | ||||
|  * | ||||
|  * @v eid		Extension ID | ||||
|  * @v fid		Function ID | ||||
|  * @v param0		Parameter 0 | ||||
|  * @v param1		Parameter 1 | ||||
|  * @v param2		Parameter 2 | ||||
|  * @ret ret		Return value | ||||
|  */ | ||||
| static inline __attribute__ (( always_inline )) struct sbi_return | ||||
| sbi_ecall_3 ( int eid, int fid, unsigned long p0, unsigned long p1, | ||||
| 	      unsigned long p2 ) { | ||||
| 	register unsigned long a7 asm ( "a7" ) = ( ( long ) eid ); | ||||
| 	register unsigned long a6 asm ( "a6" ) = ( ( long ) fid ); | ||||
| 	register unsigned long a0 asm ( "a0" ) = p0; | ||||
| 	register unsigned long a1 asm ( "a1" ) = p1; | ||||
| 	register unsigned long a2 asm ( "a2" ) = p2; | ||||
| 	struct sbi_return ret; | ||||
|  | ||||
| 	__asm__ __volatile__ ( "ecall" | ||||
| 			       : "+r" ( a0 ), "+r" ( a1 ) | ||||
| 			       : "r" ( a2 ), "r" ( a6 ), "r" ( a7 ) | ||||
| 			       : "memory" ); | ||||
| 	ret.error = a0; | ||||
| 	ret.value = a1; | ||||
| 	return ret; | ||||
| } | ||||
|  | ||||
| /** Convert an SBI error code to an iPXE status code */ | ||||
| #define ESBI( error ) EPLATFORM ( EINFO_EPLATFORM, error ) | ||||
|  | ||||
| /** System reset extension */ | ||||
| #define SBI_SRST SBI_EID ( 'S', 'R', 'S', 'T' ) | ||||
| #define SBI_SRST_SYSTEM_RESET 0x00	/**< Reset system */ | ||||
| #define SBI_RESET_SHUTDOWN 0x00000000	/**< Shutdown */ | ||||
| #define SBI_RESET_COLD 0x00000001	/**< Cold reboot */ | ||||
| #define SBI_RESET_WARM 0x00000002	/**< Warm reboot */ | ||||
|  | ||||
| /** Debug console extension */ | ||||
| #define SBI_DBCN SBI_EID ( 'D', 'B', 'C', 'N' ) | ||||
| #define SBI_DBCN_WRITE 0x00		/**< Console Write */ | ||||
| #define SBI_DBCN_READ 0x01		/**< Console Read */ | ||||
| #define SBI_DBCN_WRITE_BYTE 0x02	/**< Console Write Byte */ | ||||
|  | ||||
| #endif /* _IPXE_SBI_H */ | ||||
							
								
								
									
										18
									
								
								src/arch/riscv/include/ipxe/sbi_reboot.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										18
									
								
								src/arch/riscv/include/ipxe/sbi_reboot.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,18 @@ | ||||
| #ifndef _IPXE_BIOS_REBOOT_H | ||||
| #define _IPXE_BIOS_REBOOT_H | ||||
|  | ||||
| /** @file | ||||
|  * | ||||
|  * Supervisor Binary Interface (SBI) reboot mechanism | ||||
|  * | ||||
|  */ | ||||
|  | ||||
| FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); | ||||
|  | ||||
| #ifdef REBOOT_SBI | ||||
| #define REBOOT_PREFIX_sbi | ||||
| #else | ||||
| #define REBOOT_PREFIX_sbi __sbi_ | ||||
| #endif | ||||
|  | ||||
| #endif /* _IPXE_BIOS_REBOOT_H */ | ||||
							
								
								
									
										101
									
								
								src/arch/riscv/interface/sbi/sbi_console.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										101
									
								
								src/arch/riscv/interface/sbi/sbi_console.c
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,101 @@ | ||||
| /* | ||||
|  * Copyright (C) 2024 Michael Brown <mbrown@fensystems.co.uk>. | ||||
|  * | ||||
|  * This program is free software; you can redistribute it and/or | ||||
|  * modify it under the terms of the GNU General Public License as | ||||
|  * published by the Free Software Foundation; either version 2 of the | ||||
|  * License, or any later version. | ||||
|  * | ||||
|  * This program 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 this program; if not, write to the Free Software | ||||
|  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA | ||||
|  * 02110-1301, USA. | ||||
|  * | ||||
|  * You can also choose to distribute this program under the terms of | ||||
|  * the Unmodified Binary Distribution Licence (as given in the file | ||||
|  * COPYING.UBDL), provided that you have satisfied its requirements. | ||||
|  */ | ||||
|  | ||||
| /** @file | ||||
|  * | ||||
|  * SBI debug console | ||||
|  * | ||||
|  */ | ||||
|  | ||||
| FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); | ||||
|  | ||||
| #include <ipxe/sbi.h> | ||||
| #include <ipxe/io.h> | ||||
| #include <ipxe/console.h> | ||||
| #include <config/console.h> | ||||
|  | ||||
| /* Set default console usage if applicable */ | ||||
| #if ! ( defined ( CONSOLE_SBI ) && CONSOLE_EXPLICIT ( CONSOLE_SBI ) ) | ||||
| #undef CONSOLE_SBI | ||||
| #define CONSOLE_SBI ( CONSOLE_USAGE_ALL & ~CONSOLE_USAGE_LOG ) | ||||
| #endif | ||||
|  | ||||
| /** Buffered input character (if any) */ | ||||
| static unsigned char sbi_console_input; | ||||
|  | ||||
| /** | ||||
|  * Print a character to SBI console | ||||
|  * | ||||
|  * @v character		Character to be printed | ||||
|  */ | ||||
| static void sbi_putchar ( int character ) { | ||||
|  | ||||
| 	/* Write byte to console */ | ||||
| 	sbi_ecall_1 ( SBI_DBCN, SBI_DBCN_WRITE_BYTE, character ); | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * Get character from SBI console | ||||
|  * | ||||
|  * @ret character	Character read from console, if any | ||||
|  */ | ||||
| static int sbi_getchar ( void ) { | ||||
| 	int character; | ||||
|  | ||||
| 	/* Consume and return buffered character, if any */ | ||||
| 	character = sbi_console_input; | ||||
| 	sbi_console_input = 0; | ||||
| 	return character; | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * Check for character ready to read from SBI console | ||||
|  * | ||||
|  * @ret True		Character available to read | ||||
|  * @ret False		No character available to read | ||||
|  */ | ||||
| static int sbi_iskey ( void ) { | ||||
| 	struct sbi_return ret; | ||||
|  | ||||
| 	/* Do nothing if we already have a buffered character */ | ||||
| 	if ( sbi_console_input ) | ||||
| 		return sbi_console_input; | ||||
|  | ||||
| 	/* Read and buffer byte from console, if any */ | ||||
| 	ret = sbi_ecall_3 ( SBI_DBCN, SBI_DBCN_READ, | ||||
| 			    sizeof ( sbi_console_input ), | ||||
| 			    virt_to_phys ( &sbi_console_input ), 0 ); | ||||
| 	if ( ret.error ) | ||||
| 		return 0; | ||||
|  | ||||
| 	/* Return number of characters read and buffered */ | ||||
| 	return ret.value; | ||||
| } | ||||
|  | ||||
| /** SBI console */ | ||||
| struct console_driver sbi_console_driver __console_driver = { | ||||
| 	.putchar = sbi_putchar, | ||||
| 	.getchar = sbi_getchar, | ||||
| 	.iskey = sbi_iskey, | ||||
| 	.usage = CONSOLE_SBI, | ||||
| }; | ||||
							
								
								
									
										76
									
								
								src/arch/riscv/interface/sbi/sbi_reboot.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										76
									
								
								src/arch/riscv/interface/sbi/sbi_reboot.c
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,76 @@ | ||||
| /* | ||||
|  * Copyright (C) 2024 Michael Brown <mbrown@fensystems.co.uk>. | ||||
|  * | ||||
|  * This program is free software; you can redistribute it and/or | ||||
|  * modify it under the terms of the GNU General Public License as | ||||
|  * published by the Free Software Foundation; either version 2 of the | ||||
|  * License, or any later version. | ||||
|  * | ||||
|  * This program 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 this program; if not, write to the Free Software | ||||
|  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA | ||||
|  * 02110-1301, USA. | ||||
|  * | ||||
|  * You can also choose to distribute this program under the terms of | ||||
|  * the Unmodified Binary Distribution Licence (as given in the file | ||||
|  * COPYING.UBDL), provided that you have satisfied its requirements. | ||||
|  */ | ||||
|  | ||||
| FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); | ||||
|  | ||||
| /** @file | ||||
|  * | ||||
|  * Supervisor Binary Interface (SBI) reboot mechanism | ||||
|  * | ||||
|  */ | ||||
|  | ||||
| #include <errno.h> | ||||
| #include <string.h> | ||||
| #include <ipxe/sbi.h> | ||||
| #include <ipxe/reboot.h> | ||||
|  | ||||
| /** | ||||
|  * Reboot system | ||||
|  * | ||||
|  * @v warm		Perform a warm reboot | ||||
|  */ | ||||
| static void sbi_reboot ( int warm ) { | ||||
| 	struct sbi_return ret; | ||||
| 	int rc; | ||||
|  | ||||
| 	/* Reboot system */ | ||||
| 	ret = sbi_ecall_2 ( SBI_SRST, SBI_SRST_SYSTEM_RESET, | ||||
| 			    ( warm ? SBI_RESET_WARM : SBI_RESET_COLD ), 0 ); | ||||
|  | ||||
| 	/* Any return is an error */ | ||||
| 	rc = -ESBI ( ret.error ); | ||||
| 	DBGC ( SBI_SRST, "SBI %s reset failed: %s\n", | ||||
| 	       ( warm ? "warm" : "cold" ), strerror ( rc ) ); | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * Power off system | ||||
|  * | ||||
|  * @ret rc		Return status code | ||||
|  */ | ||||
| static int sbi_poweroff ( void ) { | ||||
| 	struct sbi_return ret; | ||||
| 	int rc; | ||||
|  | ||||
| 	/* Shut down system */ | ||||
| 	ret = sbi_ecall_2 ( SBI_SRST, SBI_SRST_SYSTEM_RESET, | ||||
| 			    SBI_RESET_SHUTDOWN, 0 ); | ||||
|  | ||||
| 	/* Any return is an error */ | ||||
| 	rc = -ESBI ( ret.error ); | ||||
| 	DBGC ( SBI_SRST, "SBI shutdown failed: %s\n", strerror ( rc ) ); | ||||
| 	return rc; | ||||
| } | ||||
|  | ||||
| PROVIDE_REBOOT ( sbi, reboot, sbi_reboot ); | ||||
| PROVIDE_REBOOT ( sbi, poweroff, sbi_poweroff ); | ||||
| @ -78,6 +78,9 @@ REQUIRE_OBJECT ( vmconsole ); | ||||
| #ifdef CONSOLE_DEBUGCON | ||||
| REQUIRE_OBJECT ( debugcon ); | ||||
| #endif | ||||
| #ifdef CONSOLE_SBI | ||||
| REQUIRE_OBJECT ( sbi_console ); | ||||
| #endif | ||||
|  | ||||
| /* | ||||
|  * Drag in all requested network protocols | ||||
|  | ||||
| @ -41,6 +41,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); | ||||
| //#define	CONSOLE_VMWARE		/* VMware logfile console */ | ||||
| //#define	CONSOLE_DEBUGCON	/* Bochs/QEMU/KVM debug port console */ | ||||
| //#define	CONSOLE_INT13		/* INT13 disk log console */ | ||||
| //#define	CONSOLE_SBI		/* RISC-V SBI debug console */ | ||||
|  | ||||
| /* | ||||
|  * Very obscure console types | ||||
|  | ||||
| @ -305,6 +305,60 @@ void bigint_reduce_raw ( const bigint_element_t *minuend0, | ||||
| 	profile_stop ( &bigint_mod_profiler ); | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * Compute inverse of odd big integer modulo any power of two | ||||
|  * | ||||
|  * @v invertend0	Element 0 of odd big integer to be inverted | ||||
|  * @v inverse0		Element 0 of big integer to hold result | ||||
|  * @v size		Number of elements in invertend and result | ||||
|  * @v tmp		Temporary working space | ||||
|  */ | ||||
| void bigint_mod_invert_raw ( const bigint_element_t *invertend0, | ||||
| 			     bigint_element_t *inverse0, | ||||
| 			     unsigned int size, void *tmp ) { | ||||
| 	const bigint_t ( size ) __attribute__ (( may_alias )) | ||||
| 		*invertend = ( ( const void * ) invertend0 ); | ||||
| 	bigint_t ( size ) __attribute__ (( may_alias )) | ||||
| 		*inverse = ( ( void * ) inverse0 ); | ||||
| 	struct { | ||||
| 		bigint_t ( size ) residue; | ||||
| 	} *temp = tmp; | ||||
| 	const unsigned int width = ( 8 * sizeof ( bigint_element_t ) ); | ||||
| 	unsigned int i; | ||||
|  | ||||
| 	/* Sanity check */ | ||||
| 	assert ( invertend->element[0] & 1 ); | ||||
|  | ||||
| 	/* Initialise temporary working space and output value */ | ||||
| 	memset ( &temp->residue, 0xff, sizeof ( temp->residue ) ); | ||||
| 	memset ( inverse, 0, sizeof ( *inverse ) ); | ||||
|  | ||||
| 	/* Compute inverse modulo 2^(width) | ||||
| 	 * | ||||
| 	 * This method is a lightly modified version of the pseudocode | ||||
| 	 * presented in "A New Algorithm for Inversion mod p^k (Koç, | ||||
| 	 * 2017)". | ||||
| 	 * | ||||
| 	 * Each loop iteration calculates one bit of the inverse.  The | ||||
| 	 * residue value is the two's complement negation of the value | ||||
| 	 * "b" as used by Koç, to allow for division by two using a | ||||
| 	 * logical right shift (since we have no arithmetic right | ||||
| 	 * shift operation for big integers). | ||||
| 	 * | ||||
| 	 * Due to the suffix property of inverses mod 2^k, the result | ||||
| 	 * represents the least significant bits of the inverse modulo | ||||
| 	 * an arbitrarily large 2^k. | ||||
| 	 */ | ||||
| 	for ( i = 0 ; i < ( 8 * sizeof ( *inverse ) ) ; i++ ) { | ||||
| 		if ( temp->residue.element[0] & 1 ) { | ||||
| 			inverse->element[ i / width ] |= | ||||
| 				( 1UL << ( i % width ) ); | ||||
| 			bigint_add ( invertend, &temp->residue ); | ||||
| 		} | ||||
| 		bigint_shr ( &temp->residue ); | ||||
| 	} | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * Perform modular multiplication of big integers | ||||
|  * | ||||
|  | ||||
| @ -246,6 +246,31 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); | ||||
| 		bigint_t ( size ) temp_modulus;				\ | ||||
| 	} ); } ) | ||||
|  | ||||
| /** | ||||
|  * Compute inverse of odd big integer modulo its own size | ||||
|  * | ||||
|  * @v invertend		Odd big integer to be inverted | ||||
|  * @v inverse		Big integer to hold result | ||||
|  * @v tmp		Temporary working space | ||||
|  */ | ||||
| #define bigint_mod_invert( invertend, inverse, tmp ) do {		\ | ||||
| 	unsigned int size = bigint_size (invertend);			\ | ||||
| 	bigint_mod_invert_raw ( (invertend)->element,			\ | ||||
| 				(inverse)->element, size, tmp );	\ | ||||
| 	} while ( 0 ) | ||||
|  | ||||
| /** | ||||
|  * Calculate temporary working space required for modular inversion | ||||
|  * | ||||
|  * @v invertend		Odd big integer to be inverted | ||||
|  * @ret len		Length of temporary working space | ||||
|  */ | ||||
| #define bigint_mod_invert_tmp_len( invertend ) ( {			\ | ||||
| 	unsigned int size = bigint_size (invertend);			\ | ||||
| 	sizeof ( struct {						\ | ||||
| 		bigint_t ( size ) temp_residue;				\ | ||||
| 	} ); } ) | ||||
|  | ||||
| /** | ||||
|  * Perform modular multiplication of big integers | ||||
|  * | ||||
| @ -373,6 +398,9 @@ void bigint_reduce_raw ( const bigint_element_t *minuend0, | ||||
| 			 const bigint_element_t *modulus0, | ||||
| 			 unsigned int modulus_size, | ||||
| 			 bigint_element_t *result0, void *tmp ); | ||||
| void bigint_mod_invert_raw ( const bigint_element_t *invertend0, | ||||
| 			     bigint_element_t *inverse0, | ||||
| 			     unsigned int size, void *tmp ); | ||||
| void bigint_mod_multiply_raw ( const bigint_element_t *multiplicand0, | ||||
| 			       const bigint_element_t *multiplier0, | ||||
| 			       const bigint_element_t *modulus0, | ||||
|  | ||||
| @ -200,6 +200,17 @@ void bigint_reduce_sample ( const bigint_element_t *minuend0, | ||||
| 	bigint_reduce ( minuend, modulus, result, tmp ); | ||||
| } | ||||
|  | ||||
| void bigint_mod_invert_sample ( const bigint_element_t *invertend0, | ||||
| 				bigint_element_t *inverse0, | ||||
| 				unsigned int size, void *tmp ) { | ||||
| 	const bigint_t ( size ) __attribute__ (( may_alias )) | ||||
| 		*invertend = ( ( const void * ) invertend0 ); | ||||
| 	bigint_t ( size ) __attribute__ (( may_alias )) | ||||
| 		*inverse = ( ( void * ) inverse0 ); | ||||
|  | ||||
| 	bigint_mod_invert ( invertend, inverse, tmp ); | ||||
| } | ||||
|  | ||||
| void bigint_mod_multiply_sample ( const bigint_element_t *multiplicand0, | ||||
| 				  const bigint_element_t *multiplier0, | ||||
| 				  const bigint_element_t *modulus0, | ||||
| @ -573,6 +584,39 @@ void bigint_mod_exp_sample ( const bigint_element_t *base0, | ||||
| 		      sizeof ( result_raw ) ) == 0 );			\ | ||||
| 	} while ( 0 ) | ||||
|  | ||||
| /** | ||||
|  * Report result of big integer modular inversion test | ||||
|  * | ||||
|  * @v invertend		Big integer to be inverted | ||||
|  * @v expected		Big integer expected result | ||||
|  */ | ||||
| #define bigint_mod_invert_ok( invertend, expected ) do {		\ | ||||
| 	static const uint8_t invertend_raw[] = invertend;		\ | ||||
| 	static const uint8_t expected_raw[] = expected;			\ | ||||
| 	uint8_t inverse_raw[ sizeof ( expected_raw ) ];			\ | ||||
| 	unsigned int size =						\ | ||||
| 		bigint_required_size ( sizeof ( invertend_raw ) );	\ | ||||
| 	bigint_t ( size ) invertend_temp;				\ | ||||
| 	bigint_t ( size ) inverse_temp;					\ | ||||
| 	size_t tmp_len = bigint_mod_invert_tmp_len ( &invertend_temp );	\ | ||||
| 	uint8_t tmp[tmp_len];						\ | ||||
| 	{} /* Fix emacs alignment */					\ | ||||
| 									\ | ||||
| 	assert ( bigint_size ( &invertend_temp ) ==			\ | ||||
| 		 bigint_size ( &inverse_temp ) );			\ | ||||
| 	bigint_init ( &invertend_temp, invertend_raw,			\ | ||||
| 		      sizeof ( invertend_raw ) );			\ | ||||
| 	DBG ( "Modular invert:\n" );					\ | ||||
| 	DBG_HDA ( 0, &invertend_temp, sizeof ( invertend_temp ) );	\ | ||||
| 	bigint_mod_invert ( &invertend_temp, &inverse_temp, tmp );	\ | ||||
| 	DBG_HDA ( 0, &inverse_temp, sizeof ( inverse_temp ) );		\ | ||||
| 	bigint_done ( &inverse_temp, inverse_raw,			\ | ||||
| 		      sizeof ( inverse_raw ) );				\ | ||||
| 									\ | ||||
| 	ok ( memcmp ( inverse_raw, expected_raw,			\ | ||||
| 		      sizeof ( inverse_raw ) ) == 0 );			\ | ||||
| 	} while ( 0 ) | ||||
|  | ||||
| /** | ||||
|  * Report result of big integer modular multiplication test | ||||
|  * | ||||
| @ -1760,6 +1804,23 @@ static void bigint_test_exec ( void ) { | ||||
| 				    0xfb, 0x5d, 0x55 ), | ||||
| 			   BIGINT ( 0x27, 0x31, 0x49, 0xc3, 0xf5, 0x06, 0x1f, | ||||
| 				    0x3c, 0x7c, 0xd5 ) ); | ||||
| 	bigint_mod_invert_ok ( BIGINT ( 0x01 ), BIGINT ( 0x01 ) ); | ||||
| 	bigint_mod_invert_ok ( BIGINT ( 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, | ||||
| 					0xff, 0xff ), | ||||
| 			       BIGINT ( 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, | ||||
| 					0xff, 0xff ) ); | ||||
| 	bigint_mod_invert_ok ( BIGINT ( 0x95, 0x6a, 0xc5, 0xe7, 0x2e, 0x5b, | ||||
| 					0x44, 0xed, 0xbf, 0x7e, 0xfe, 0x8d, | ||||
| 					0xf4, 0x5a, 0x48, 0xc1 ), | ||||
| 			       BIGINT ( 0xad, 0xb8, 0x3d, 0x85, 0x10, 0xdf, | ||||
| 					0xea, 0x70, 0x71, 0x2c, 0x80, 0xf4, | ||||
| 					0x6e, 0x66, 0x47, 0x41 ) ); | ||||
| 	bigint_mod_invert_ok ( BIGINT ( 0x35, 0xe4, 0x80, 0x48, 0xdd, 0xa1, | ||||
| 					0x46, 0xc0, 0x84, 0x63, 0xc1, 0xe4, | ||||
| 					0xf7, 0xbf, 0xb3, 0x05 ), | ||||
| 			       BIGINT ( 0xf2, 0x9c, 0x63, 0x29, 0xfa, 0xe4, | ||||
| 					0xbf, 0x90, 0xa6, 0x9a, 0xec, 0xcf, | ||||
| 					0x5f, 0xe2, 0x21, 0xcd ) ); | ||||
| 	bigint_mod_multiply_ok ( BIGINT ( 0x37 ), | ||||
| 				 BIGINT ( 0x67 ), | ||||
| 				 BIGINT ( 0x3f ), | ||||
|  | ||||
		Reference in New Issue
	
	Block a user
	