mirror of
https://gitlab.com/qemu-project/ipxe.git
synced 2025-10-30 07:56:50 +08:00
Compare commits
79 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 37850e0e85 | |||
| 9bbe77669c | |||
| 170bbfd487 | |||
| dcad73ca5a | |||
| da5188f3ea | |||
| ca483a196c | |||
| a15ce00182 | |||
| 390bce9516 | |||
| 1a84facf12 | |||
| 88c2a01e1a | |||
| 926816c58f | |||
| c11734eee0 | |||
| fa4bda617d | |||
| bac967d51a | |||
| 17882e76af | |||
| 1344e13a03 | |||
| a67f913d66 | |||
| 89bb926a04 | |||
| 1ab4d3079d | |||
| df2f23e333 | |||
| 226531ed36 | |||
| 06e229590c | |||
| 24a855f1fc | |||
| 62b6d36335 | |||
| cea22d76e4 | |||
| c4471e3408 | |||
| 636ccb4ca5 | |||
| b1c13cc43e | |||
| 8da22a59ee | |||
| 37edfea72b | |||
| eb720d2224 | |||
| 75c7904482 | |||
| 1b23d4de25 | |||
| 7cd73884e5 | |||
| 0eb8fbd0bf | |||
| da7b266289 | |||
| 182ee90931 | |||
| 43e385091a | |||
| 25ffcd79bf | |||
| 834f319f87 | |||
| ee6185dcf5 | |||
| e5f3ba0ca7 | |||
| 582132fe3f | |||
| 075292cc2d | |||
| 929f06a76d | |||
| 943d75b557 | |||
| 3e721e0c08 | |||
| e10dfe5dc7 | |||
| 88b291d647 | |||
| 94b39fbe92 | |||
| 0f5abd8b11 | |||
| a846c4ccfc | |||
| e7ae51b0d7 | |||
| af4583b214 | |||
| 36a27b22b1 | |||
| 0cc0f47443 | |||
| 65d69d33da | |||
| 963ec1c4f3 | |||
| 8f6a9399b3 | |||
| a881a26061 | |||
| b234226dbc | |||
| 8e2469c861 | |||
| 989dbe0bc4 | |||
| 6f70e8be83 | |||
| 17135c83fb | |||
| 27398f1360 | |||
| de8a0821c7 | |||
| 2eea04c02c | |||
| 908174ec7e | |||
| bac13ba1f6 | |||
| 13e390d54e | |||
| 26d3ef062b | |||
| 4b7d9a6af0 | |||
| 6d29415c89 | |||
| 6ca597eee9 | |||
| e66552eeed | |||
| 08fcb0e8fb | |||
| c6226f104e | |||
| 0abb3e85e5 |
14
.github/workflows/build.yml
vendored
14
.github/workflows/build.yml
vendored
@ -12,7 +12,7 @@ jobs:
|
||||
run: |
|
||||
sudo chown $(id -un) /var/cache/apt/archives
|
||||
- name: Cache packages
|
||||
uses: actions/cache@v3
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: /var/cache/apt/archives/*.deb
|
||||
key: apt-cache-${{ github.run_id }}-${{ github.run_attempt }}
|
||||
@ -32,14 +32,14 @@ jobs:
|
||||
needs: cache
|
||||
steps:
|
||||
- name: Check out code
|
||||
uses: actions/checkout@v3
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- name: Cache permissions
|
||||
run: |
|
||||
sudo chown $(id -un) /var/cache/apt/archives
|
||||
- name: Cache packages
|
||||
uses: actions/cache/restore@v3
|
||||
uses: actions/cache/restore@v4
|
||||
with:
|
||||
path: /var/cache/apt/archives/*.deb
|
||||
key: apt-cache-${{ github.run_id }}-${{ github.run_attempt }}
|
||||
@ -68,14 +68,14 @@ jobs:
|
||||
needs: cache
|
||||
steps:
|
||||
- name: Check out code
|
||||
uses: actions/checkout@v3
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- name: Cache permissions
|
||||
run: |
|
||||
sudo chown $(id -un) /var/cache/apt/archives
|
||||
- name: Cache packages
|
||||
uses: actions/cache/restore@v3
|
||||
uses: actions/cache/restore@v4
|
||||
with:
|
||||
path: /var/cache/apt/archives/*.deb
|
||||
key: apt-cache-${{ github.run_id }}-${{ github.run_attempt }}
|
||||
@ -97,14 +97,14 @@ jobs:
|
||||
needs: cache
|
||||
steps:
|
||||
- name: Check out code
|
||||
uses: actions/checkout@v3
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- name: Cache permissions
|
||||
run: |
|
||||
sudo chown $(id -un) /var/cache/apt/archives
|
||||
- name: Cache packages
|
||||
uses: actions/cache/restore@v3
|
||||
uses: actions/cache/restore@v4
|
||||
with:
|
||||
path: /var/cache/apt/archives/*.deb
|
||||
key: apt-cache-${{ github.run_id }}-${{ github.run_attempt }}
|
||||
|
||||
2
.github/workflows/coverity.yml
vendored
2
.github/workflows/coverity.yml
vendored
@ -11,7 +11,7 @@ jobs:
|
||||
runs-on: ubuntu-22.04
|
||||
steps:
|
||||
- name: Check out code
|
||||
uses: actions/checkout@v3
|
||||
uses: actions/checkout@v4
|
||||
- name: Download Coverity Scan
|
||||
run: |
|
||||
curl --form token=${{ secrets.COVERITY_SCAN_TOKEN }} \
|
||||
|
||||
@ -23,9 +23,9 @@ NON_AUTO_MEDIA += efidrv
|
||||
NON_AUTO_MEDIA += drv.efi
|
||||
NON_AUTO_MEDIA += efirom
|
||||
|
||||
# Include SNP driver in the all-drivers build
|
||||
# Include SNP and MNP drivers in the all-drivers build
|
||||
#
|
||||
DRIVERS_net += snp
|
||||
DRIVERS_net += snp mnp
|
||||
|
||||
# Rules for building EFI files
|
||||
#
|
||||
|
||||
12
src/arch/arm/include/bits/mp.h
Normal file
12
src/arch/arm/include/bits/mp.h
Normal file
@ -0,0 +1,12 @@
|
||||
#ifndef _BITS_MP_H
|
||||
#define _BITS_MP_H
|
||||
|
||||
/** @file
|
||||
*
|
||||
* ARM-specific multiprocessor API implementation
|
||||
*
|
||||
*/
|
||||
|
||||
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
|
||||
|
||||
#endif /* _BITS_MP_H */
|
||||
@ -46,8 +46,12 @@ static void efiarm_cpu_nap ( void ) {
|
||||
* The EFI shell doesn't seem to bother sleeping the CPU; it
|
||||
* just sits there idly burning power.
|
||||
*
|
||||
* If a shutdown is in progess, there may be nothing to
|
||||
* generate an interrupt since the timer is disabled in the
|
||||
* first step of ExitBootServices().
|
||||
*/
|
||||
__asm__ __volatile__ ( "wfi" );
|
||||
if ( ! efi_shutdown_in_progress )
|
||||
__asm__ __volatile__ ( "wfi" );
|
||||
}
|
||||
|
||||
PROVIDE_NAP ( efiarm, cpu_nap, efiarm_cpu_nap );
|
||||
|
||||
@ -36,19 +36,23 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
|
||||
* Multiply big integers
|
||||
*
|
||||
* @v multiplicand0 Element 0 of big integer to be multiplied
|
||||
* @v multiplicand_size Number of elements in multiplicand
|
||||
* @v multiplier0 Element 0 of big integer to be multiplied
|
||||
* @v multiplier_size Number of elements in multiplier
|
||||
* @v result0 Element 0 of big integer to hold result
|
||||
* @v size Number of elements
|
||||
*/
|
||||
void bigint_multiply_raw ( const uint32_t *multiplicand0,
|
||||
unsigned int multiplicand_size,
|
||||
const uint32_t *multiplier0,
|
||||
uint32_t *result0, unsigned int size ) {
|
||||
const bigint_t ( size ) __attribute__ (( may_alias )) *multiplicand =
|
||||
( ( const void * ) multiplicand0 );
|
||||
const bigint_t ( size ) __attribute__ (( may_alias )) *multiplier =
|
||||
( ( const void * ) multiplier0 );
|
||||
bigint_t ( size * 2 ) __attribute__ (( may_alias )) *result =
|
||||
( ( void * ) result0 );
|
||||
unsigned int multiplier_size,
|
||||
uint32_t *result0 ) {
|
||||
unsigned int result_size = ( multiplicand_size + multiplier_size );
|
||||
const bigint_t ( multiplicand_size ) __attribute__ (( may_alias ))
|
||||
*multiplicand = ( ( const void * ) multiplicand0 );
|
||||
const bigint_t ( multiplier_size ) __attribute__ (( may_alias ))
|
||||
*multiplier = ( ( const void * ) multiplier0 );
|
||||
bigint_t ( result_size ) __attribute__ (( may_alias ))
|
||||
*result = ( ( void * ) result0 );
|
||||
unsigned int i;
|
||||
unsigned int j;
|
||||
uint32_t multiplicand_element;
|
||||
@ -62,9 +66,9 @@ void bigint_multiply_raw ( const uint32_t *multiplicand0,
|
||||
memset ( result, 0, sizeof ( *result ) );
|
||||
|
||||
/* Multiply integers one element at a time */
|
||||
for ( i = 0 ; i < size ; i++ ) {
|
||||
for ( i = 0 ; i < multiplicand_size ; i++ ) {
|
||||
multiplicand_element = multiplicand->element[i];
|
||||
for ( j = 0 ; j < size ; j++ ) {
|
||||
for ( j = 0 ; j < multiplier_size ; j++ ) {
|
||||
multiplier_element = multiplier->element[j];
|
||||
result_elements = &result->element[ i + j ];
|
||||
/* Perform a single multiply, and add the
|
||||
@ -73,7 +77,7 @@ void bigint_multiply_raw ( const uint32_t *multiplicand0,
|
||||
* never overflow beyond the end of the
|
||||
* result, since:
|
||||
*
|
||||
* a < 2^{n}, b < 2^{n} => ab < 2^{2n}
|
||||
* a < 2^{n}, b < 2^{m} => ab < 2^{n+m}
|
||||
*/
|
||||
__asm__ __volatile__ ( "umull %1, %2, %5, %6\n\t"
|
||||
"ldr %3, [%0]\n\t"
|
||||
|
||||
@ -310,7 +310,9 @@ bigint_done_raw ( const uint32_t *value0, unsigned int size __unused,
|
||||
}
|
||||
|
||||
extern void bigint_multiply_raw ( const uint32_t *multiplicand0,
|
||||
unsigned int multiplicand_size,
|
||||
const uint32_t *multiplier0,
|
||||
uint32_t *value0, unsigned int size );
|
||||
unsigned int multiplier_size,
|
||||
uint32_t *value0 );
|
||||
|
||||
#endif /* _BITS_BIGINT_H */
|
||||
|
||||
@ -1,7 +1,6 @@
|
||||
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL )
|
||||
|
||||
.section ".note.GNU-stack", "", %progbits
|
||||
.text
|
||||
.thumb
|
||||
|
||||
/**
|
||||
|
||||
@ -1,7 +1,6 @@
|
||||
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL )
|
||||
|
||||
.section ".note.GNU-stack", "", %progbits
|
||||
.text
|
||||
.arm
|
||||
|
||||
/**
|
||||
|
||||
@ -36,19 +36,23 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
|
||||
* Multiply big integers
|
||||
*
|
||||
* @v multiplicand0 Element 0 of big integer to be multiplied
|
||||
* @v multiplicand_size Number of elements in multiplicand
|
||||
* @v multiplier0 Element 0 of big integer to be multiplied
|
||||
* @v multiplier_size Number of elements in multiplier
|
||||
* @v result0 Element 0 of big integer to hold result
|
||||
* @v size Number of elements
|
||||
*/
|
||||
void bigint_multiply_raw ( const uint64_t *multiplicand0,
|
||||
unsigned int multiplicand_size,
|
||||
const uint64_t *multiplier0,
|
||||
uint64_t *result0, unsigned int size ) {
|
||||
const bigint_t ( size ) __attribute__ (( may_alias )) *multiplicand =
|
||||
( ( const void * ) multiplicand0 );
|
||||
const bigint_t ( size ) __attribute__ (( may_alias )) *multiplier =
|
||||
( ( const void * ) multiplier0 );
|
||||
bigint_t ( size * 2 ) __attribute__ (( may_alias )) *result =
|
||||
( ( void * ) result0 );
|
||||
unsigned int multiplier_size,
|
||||
uint64_t *result0 ) {
|
||||
unsigned int result_size = ( multiplicand_size + multiplier_size );
|
||||
const bigint_t ( multiplicand_size ) __attribute__ (( may_alias ))
|
||||
*multiplicand = ( ( const void * ) multiplicand0 );
|
||||
const bigint_t ( multiplier_size ) __attribute__ (( may_alias ))
|
||||
*multiplier = ( ( const void * ) multiplier0 );
|
||||
bigint_t ( result_size ) __attribute__ (( may_alias ))
|
||||
*result = ( ( void * ) result0 );
|
||||
unsigned int i;
|
||||
unsigned int j;
|
||||
uint64_t multiplicand_element;
|
||||
@ -63,9 +67,9 @@ void bigint_multiply_raw ( const uint64_t *multiplicand0,
|
||||
memset ( result, 0, sizeof ( *result ) );
|
||||
|
||||
/* Multiply integers one element at a time */
|
||||
for ( i = 0 ; i < size ; i++ ) {
|
||||
for ( i = 0 ; i < multiplicand_size ; i++ ) {
|
||||
multiplicand_element = multiplicand->element[i];
|
||||
for ( j = 0 ; j < size ; j++ ) {
|
||||
for ( j = 0 ; j < multiplier_size ; j++ ) {
|
||||
multiplier_element = multiplier->element[j];
|
||||
result_elements = &result->element[ i + j ];
|
||||
/* Perform a single multiply, and add the
|
||||
@ -74,7 +78,7 @@ void bigint_multiply_raw ( const uint64_t *multiplicand0,
|
||||
* never overflow beyond the end of the
|
||||
* result, since:
|
||||
*
|
||||
* a < 2^{n}, b < 2^{n} => ab < 2^{2n}
|
||||
* a < 2^{n}, b < 2^{m} => ab < 2^{n+m}
|
||||
*/
|
||||
__asm__ __volatile__ ( "mul %1, %6, %7\n\t"
|
||||
"umulh %2, %6, %7\n\t"
|
||||
|
||||
@ -311,7 +311,9 @@ bigint_done_raw ( const uint64_t *value0, unsigned int size __unused,
|
||||
}
|
||||
|
||||
extern void bigint_multiply_raw ( const uint64_t *multiplicand0,
|
||||
unsigned int multiplicand_size,
|
||||
const uint64_t *multiplier0,
|
||||
uint64_t *value0, unsigned int size );
|
||||
unsigned int multiplier_size,
|
||||
uint64_t *value0 );
|
||||
|
||||
#endif /* _BITS_BIGINT_H */
|
||||
|
||||
@ -2,8 +2,8 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL )
|
||||
|
||||
.section ".note.GNU-stack", "", @progbits
|
||||
.text
|
||||
.arch i386
|
||||
.code32
|
||||
.arch i386
|
||||
|
||||
/* Must match jmp_buf structure layout */
|
||||
.struct 0
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
.section ".note.GNU-stack", "", @progbits
|
||||
.code32
|
||||
.arch i386
|
||||
|
||||
.section ".data", "aw", @progbits
|
||||
|
||||
@ -37,19 +37,23 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
|
||||
* Multiply big integers
|
||||
*
|
||||
* @v multiplicand0 Element 0 of big integer to be multiplied
|
||||
* @v multiplicand_size Number of elements in multiplicand
|
||||
* @v multiplier0 Element 0 of big integer to be multiplied
|
||||
* @v multiplier_size Number of elements in multiplier
|
||||
* @v result0 Element 0 of big integer to hold result
|
||||
* @v size Number of elements
|
||||
*/
|
||||
void bigint_multiply_raw ( const uint64_t *multiplicand0,
|
||||
unsigned int multiplicand_size,
|
||||
const uint64_t *multiplier0,
|
||||
uint64_t *result0, unsigned int size ) {
|
||||
const bigint_t ( size ) __attribute__ (( may_alias )) *multiplicand =
|
||||
( ( const void * ) multiplicand0 );
|
||||
const bigint_t ( size ) __attribute__ (( may_alias )) *multiplier =
|
||||
( ( const void * ) multiplier0 );
|
||||
bigint_t ( size * 2 ) __attribute__ (( may_alias )) *result =
|
||||
( ( void * ) result0 );
|
||||
unsigned int multiplier_size,
|
||||
uint64_t *result0 ) {
|
||||
unsigned int result_size = ( multiplicand_size + multiplier_size );
|
||||
const bigint_t ( multiplicand_size ) __attribute__ (( may_alias ))
|
||||
*multiplicand = ( ( const void * ) multiplicand0 );
|
||||
const bigint_t ( multiplier_size ) __attribute__ (( may_alias ))
|
||||
*multiplier = ( ( const void * ) multiplier0 );
|
||||
bigint_t ( result_size ) __attribute__ (( may_alias ))
|
||||
*result = ( ( void * ) result0 );
|
||||
unsigned int i;
|
||||
unsigned int j;
|
||||
uint64_t multiplicand_element;
|
||||
@ -64,9 +68,9 @@ void bigint_multiply_raw ( const uint64_t *multiplicand0,
|
||||
memset ( result, 0, sizeof ( *result ) );
|
||||
|
||||
/* Multiply integers one element at a time */
|
||||
for ( i = 0 ; i < size ; i++ ) {
|
||||
for ( i = 0 ; i < multiplicand_size ; i++ ) {
|
||||
multiplicand_element = multiplicand->element[i];
|
||||
for ( j = 0 ; j < size ; j++ ) {
|
||||
for ( j = 0 ; j < multiplier_size ; j++ ) {
|
||||
multiplier_element = multiplier->element[j];
|
||||
result_elements = &result->element[ i + j ];
|
||||
/* Perform a single multiply, and add the
|
||||
@ -75,7 +79,7 @@ void bigint_multiply_raw ( const uint64_t *multiplicand0,
|
||||
* never overflow beyond the end of the
|
||||
* result, since:
|
||||
*
|
||||
* a < 2^{n}, b < 2^{n} => ab < 2^{2n}
|
||||
* a < 2^{n}, b < 2^{m} => ab < 2^{n+m}
|
||||
*/
|
||||
__asm__ __volatile__ ( "mul.d %1, %6, %7\n\t"
|
||||
"mulh.du %2, %6, %7\n\t"
|
||||
|
||||
@ -53,34 +53,37 @@ bigint_add_raw ( const uint64_t *addend0, uint64_t *value0,
|
||||
uint64_t *discard_value;
|
||||
uint64_t discard_addend_i;
|
||||
uint64_t discard_value_i;
|
||||
uint64_t discard_carry;
|
||||
uint64_t discard_temp;
|
||||
unsigned int discard_size;
|
||||
__asm__ __volatile__ ( "move $t0, $zero\n"
|
||||
"1:\n\t"
|
||||
"ld.d %3, %0, 0\n\t"
|
||||
|
||||
__asm__ __volatile__ ( "\n1:\n\t"
|
||||
/* Load addend[i] and value[i] */
|
||||
"ld.d %3, %0, 0\n\t"
|
||||
"ld.d %4, %1, 0\n\t"
|
||||
/* Add carry flag and addend */
|
||||
"add.d %4, %4, %5\n\t"
|
||||
"sltu %6, %4, %5\n\t"
|
||||
"add.d %4, %4, %3\n\t"
|
||||
"sltu %5, %4, %3\n\t"
|
||||
"or %5, %5, %6\n\t"
|
||||
/* Store value[i] */
|
||||
"st.d %4, %1, 0\n\t"
|
||||
/* Loop */
|
||||
"addi.d %0, %0, 8\n\t"
|
||||
"ld.d %4, %1, 0\n\t"
|
||||
|
||||
"add.d %4, %4, $t0\n\t"
|
||||
"sltu $t0, %4, $t0\n\t"
|
||||
|
||||
"add.d %4, %4, %3\n\t"
|
||||
"sltu $t1, %4, %3\n\t"
|
||||
|
||||
"or $t0, $t0, $t1\n\t"
|
||||
"st.d %4, %1, 0\n\t"
|
||||
"addi.d %1, %1, 8\n\t"
|
||||
"addi.w %2, %2, -1\n\t"
|
||||
"bnez %2, 1b"
|
||||
"bnez %2, 1b\n\t"
|
||||
: "=r" ( discard_addend ),
|
||||
"=r" ( discard_value ),
|
||||
"=r" ( discard_size ),
|
||||
"=r" ( discard_addend_i ),
|
||||
"=r" ( discard_value_i ),
|
||||
"=r" ( discard_carry ),
|
||||
"=r" ( discard_temp ),
|
||||
"+m" ( *value )
|
||||
: "0" ( addend0 ),
|
||||
"1" ( value0 ),
|
||||
"2" ( size )
|
||||
: "t0", "t1" );
|
||||
: "0" ( addend0 ), "1" ( value0 ),
|
||||
"2" ( size ), "5" ( 0 ) );
|
||||
}
|
||||
|
||||
/**
|
||||
@ -93,35 +96,43 @@ bigint_add_raw ( const uint64_t *addend0, uint64_t *value0,
|
||||
static inline __attribute__ (( always_inline )) void
|
||||
bigint_subtract_raw ( const uint64_t *subtrahend0, uint64_t *value0,
|
||||
unsigned int size ) {
|
||||
bigint_t ( size ) __attribute__ (( may_alias )) *value =
|
||||
( ( void * ) value0 );
|
||||
uint64_t *discard_subtrahend;
|
||||
uint64_t *discard_value;
|
||||
uint64_t discard_subtrahend_i;
|
||||
uint64_t discard_value_i;
|
||||
uint64_t discard_carry;
|
||||
uint64_t discard_temp;
|
||||
unsigned int discard_size;
|
||||
unsigned int flag = 0;
|
||||
|
||||
discard_subtrahend = (uint64_t*) subtrahend0;
|
||||
discard_value = value0;
|
||||
discard_size = size;
|
||||
|
||||
do {
|
||||
discard_subtrahend_i = *discard_subtrahend;
|
||||
discard_subtrahend++;
|
||||
discard_value_i = *discard_value;
|
||||
|
||||
discard_value_i = discard_value_i - discard_subtrahend_i - flag;
|
||||
|
||||
if ( *discard_value < (discard_subtrahend_i + flag)) {
|
||||
flag = 1;
|
||||
} else {
|
||||
flag = 0;
|
||||
}
|
||||
|
||||
*discard_value = discard_value_i;
|
||||
|
||||
discard_value++;
|
||||
discard_size -= 1;
|
||||
} while (discard_size != 0);
|
||||
__asm__ __volatile__ ( "\n1:\n\t"
|
||||
/* Load subtrahend[i] and value[i] */
|
||||
"ld.d %3, %0, 0\n\t"
|
||||
"ld.d %4, %1, 0\n\t"
|
||||
/* Subtract carry flag and subtrahend */
|
||||
"sltu %6, %4, %5\n\t"
|
||||
"sub.d %4, %4, %5\n\t"
|
||||
"sltu %5, %4, %3\n\t"
|
||||
"sub.d %4, %4, %3\n\t"
|
||||
"or %5, %5, %6\n\t"
|
||||
/* Store value[i] */
|
||||
"st.d %4, %1, 0\n\t"
|
||||
/* Loop */
|
||||
"addi.d %0, %0, 8\n\t"
|
||||
"addi.d %1, %1, 8\n\t"
|
||||
"addi.w %2, %2, -1\n\t"
|
||||
"bnez %2, 1b\n\t"
|
||||
: "=r" ( discard_subtrahend ),
|
||||
"=r" ( discard_value ),
|
||||
"=r" ( discard_size ),
|
||||
"=r" ( discard_subtrahend_i ),
|
||||
"=r" ( discard_value_i ),
|
||||
"=r" ( discard_carry ),
|
||||
"=r" ( discard_temp ),
|
||||
"+m" ( *value )
|
||||
: "0" ( subtrahend0 ), "1" ( value0 ),
|
||||
"2" ( size ), "5" ( 0 ) );
|
||||
}
|
||||
|
||||
/**
|
||||
@ -132,30 +143,37 @@ bigint_subtract_raw ( const uint64_t *subtrahend0, uint64_t *value0,
|
||||
*/
|
||||
static inline __attribute__ (( always_inline )) void
|
||||
bigint_rol_raw ( uint64_t *value0, unsigned int size ) {
|
||||
bigint_t ( size ) __attribute__ (( may_alias )) *value =
|
||||
( ( void * ) value0 );
|
||||
uint64_t *discard_value;
|
||||
uint64_t discard_value_i;
|
||||
uint64_t discard_carry;
|
||||
uint64_t discard_temp;
|
||||
unsigned int discard_size;
|
||||
uint64_t current_value_i;
|
||||
unsigned int flag = 0;
|
||||
|
||||
discard_value = value0;
|
||||
discard_size = size;
|
||||
do {
|
||||
discard_value_i = *discard_value;
|
||||
current_value_i = discard_value_i;
|
||||
|
||||
discard_value_i += discard_value_i + flag;
|
||||
|
||||
if (discard_value_i < current_value_i) {
|
||||
flag = 1;
|
||||
} else {
|
||||
flag = 0;
|
||||
}
|
||||
|
||||
*discard_value = discard_value_i;
|
||||
discard_value++;
|
||||
discard_size -= 1;
|
||||
} while ( discard_size != 0 );
|
||||
__asm__ __volatile__ ( "\n1:\n\t"
|
||||
/* Load value[i] */
|
||||
"ld.d %2, %0, 0\n\t"
|
||||
/* Shift left */
|
||||
"rotri.d %2, %2, 63\n\t"
|
||||
"andi %4, %2, 1\n\t"
|
||||
"xor %2, %2, %4\n\t"
|
||||
"or %2, %2, %3\n\t"
|
||||
"move %3, %4\n\t"
|
||||
/* Store value[i] */
|
||||
"st.d %2, %0, 0\n\t"
|
||||
/* Loop */
|
||||
"addi.d %0, %0, 8\n\t"
|
||||
"addi.w %1, %1, -1\n\t"
|
||||
"bnez %1, 1b\n\t"
|
||||
: "=r" ( discard_value ),
|
||||
"=r" ( discard_size ),
|
||||
"=r" ( discard_value_i ),
|
||||
"=r" ( discard_carry ),
|
||||
"=r" ( discard_temp ),
|
||||
"+m" ( *value )
|
||||
: "0" ( value0 ), "1" ( size ), "3" ( 0 )
|
||||
: "cc" );
|
||||
}
|
||||
|
||||
/**
|
||||
@ -166,27 +184,37 @@ bigint_rol_raw ( uint64_t *value0, unsigned int size ) {
|
||||
*/
|
||||
static inline __attribute__ (( always_inline )) void
|
||||
bigint_ror_raw ( uint64_t *value0, unsigned int size ) {
|
||||
bigint_t ( size ) __attribute__ (( may_alias )) *value =
|
||||
( ( void * ) value0 );
|
||||
uint64_t *discard_value;
|
||||
uint64_t discard_value_i;
|
||||
uint64_t discard_value_j;
|
||||
uint64_t discard_carry;
|
||||
uint64_t discard_temp;
|
||||
unsigned int discard_size;
|
||||
|
||||
discard_value = value0;
|
||||
discard_size = size;
|
||||
|
||||
discard_value_j = 0;
|
||||
|
||||
do {
|
||||
discard_size -= 1;
|
||||
|
||||
discard_value_i = *(discard_value + discard_size);
|
||||
|
||||
discard_value_j = (discard_value_j << 63) | (discard_value_i >> 1);
|
||||
|
||||
*(discard_value + discard_size) = discard_value_j;
|
||||
|
||||
discard_value_j = discard_value_i;
|
||||
} while ( discard_size > 0 );
|
||||
__asm__ __volatile__ ( "\n1:\n\t"
|
||||
/* Load value[i] */
|
||||
"ld.d %2, %0, -8\n\t"
|
||||
/* Shift right */
|
||||
"andi %4, %2, 1\n\t"
|
||||
"xor %2, %2, %4\n\t"
|
||||
"or %2, %2, %3\n\t"
|
||||
"move %3, %4\n\t"
|
||||
"rotri.d %2, %2, 1\n\t"
|
||||
/* Store value[i] */
|
||||
"st.d %2, %0, -8\n\t"
|
||||
/* Loop */
|
||||
"addi.d %0, %0, -8\n\t"
|
||||
"addi.w %1, %1, -1\n\t"
|
||||
"bnez %1, 1b\n\t"
|
||||
: "=r" ( discard_value ),
|
||||
"=r" ( discard_size ),
|
||||
"=r" ( discard_value_i ),
|
||||
"=r" ( discard_carry ),
|
||||
"=r" ( discard_temp ),
|
||||
"+m" ( *value )
|
||||
: "0" ( value0 + size ), "1" ( size ), "3" ( 0 )
|
||||
: "cc" );
|
||||
}
|
||||
|
||||
/**
|
||||
@ -330,7 +358,9 @@ bigint_done_raw ( const uint64_t *value0, unsigned int size __unused,
|
||||
}
|
||||
|
||||
extern void bigint_multiply_raw ( const uint64_t *multiplicand0,
|
||||
unsigned int multiplicand_size,
|
||||
const uint64_t *multiplier0,
|
||||
uint64_t *value0, unsigned int size );
|
||||
unsigned int multiplier_size,
|
||||
uint64_t *value0 );
|
||||
|
||||
#endif /* _BITS_BIGINT_H */
|
||||
|
||||
12
src/arch/loong64/include/bits/mp.h
Normal file
12
src/arch/loong64/include/bits/mp.h
Normal file
@ -0,0 +1,12 @@
|
||||
#ifndef _BITS_MP_H
|
||||
#define _BITS_MP_H
|
||||
|
||||
/** @file
|
||||
*
|
||||
* LoongArch64-specific multiprocessor API implementation
|
||||
*
|
||||
*/
|
||||
|
||||
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
|
||||
|
||||
#endif /* _BITS_MP_H */
|
||||
@ -46,8 +46,12 @@ static void efiloong64_cpu_nap ( void ) {
|
||||
* The EFI shell doesn't seem to bother sleeping the CPU; it
|
||||
* just sits there idly burning power.
|
||||
*
|
||||
* If a shutdown is in progess, there may be nothing to
|
||||
* generate an interrupt since the timer is disabled in the
|
||||
* first step of ExitBootServices().
|
||||
*/
|
||||
__asm__ __volatile__ ( "idle 0" );
|
||||
if ( ! efi_shutdown_in_progress )
|
||||
__asm__ __volatile__ ( "idle 0" );
|
||||
}
|
||||
|
||||
PROVIDE_NAP ( efiloong64, cpu_nap, efiloong64_cpu_nap );
|
||||
|
||||
197
src/arch/x86/core/mpcall.S
Normal file
197
src/arch/x86/core/mpcall.S
Normal file
@ -0,0 +1,197 @@
|
||||
/*
|
||||
* 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
|
||||
*
|
||||
* Multiprocessor functions
|
||||
*
|
||||
*/
|
||||
|
||||
.section ".note.GNU-stack", "", @progbits
|
||||
.text
|
||||
|
||||
/* Selectively assemble code for 32-bit/64-bit builds */
|
||||
#if defined ( __x86_64__ ) && ! defined ( PLATFORM_pcbios )
|
||||
#define codemp code64
|
||||
#define DI rdi
|
||||
#define SP rsp
|
||||
#define if32 if 0
|
||||
#define if64 if 1
|
||||
#else
|
||||
#define codemp code32
|
||||
#define DI edi
|
||||
#define SP esp
|
||||
#define if32 if 1
|
||||
#define if64 if 0
|
||||
#endif
|
||||
|
||||
/* Standard features CPUID leaf */
|
||||
#define CPUID_FEATURES 0x00000001
|
||||
|
||||
/* x2APIC is supported */
|
||||
#define CPUID_FEATURES_ECX_X2APIC 0x00200000
|
||||
|
||||
/* Extended topology enumeration CPUID leaf */
|
||||
#define CPUID_XT_ENUM 0x0000000b
|
||||
|
||||
/*
|
||||
* Call multiprocessor function from C code
|
||||
*
|
||||
* Parameters:
|
||||
* 4(%esp)/%rdi Multiprocessor function
|
||||
* 8(%esp)/%rsi Opaque data pointer
|
||||
*/
|
||||
.section ".text.mp_call", "ax", @progbits
|
||||
.codemp
|
||||
.globl mp_call
|
||||
mp_call:
|
||||
.if64 /* Preserve registers, load incoming parameters into registers */
|
||||
pushq %rax
|
||||
pushq %rcx
|
||||
pushq %rdx
|
||||
pushq %rbx
|
||||
pushq %rsp
|
||||
pushq %rbp
|
||||
pushq %rsi
|
||||
pushq %rdi
|
||||
pushq %r8
|
||||
pushq %r9
|
||||
pushq %r10
|
||||
pushq %r11
|
||||
pushq %r12
|
||||
pushq %r13
|
||||
pushq %r14
|
||||
pushq %r15
|
||||
.else
|
||||
pushal
|
||||
movl 36(%esp), %eax
|
||||
movl 40(%esp), %edx
|
||||
.endif
|
||||
/* Call multiprocessor function */
|
||||
call mp_jump
|
||||
|
||||
.if64 /* Restore registers and return */
|
||||
popq %r15
|
||||
popq %r14
|
||||
popq %r13
|
||||
popq %r12
|
||||
popq %r11
|
||||
popq %r10
|
||||
popq %r9
|
||||
popq %r8
|
||||
popq %rdi
|
||||
popq %rsi
|
||||
popq %rbp
|
||||
leaq 8(%rsp), %rsp /* discard */
|
||||
popq %rbx
|
||||
popq %rdx
|
||||
popq %rcx
|
||||
popq %rax
|
||||
.else
|
||||
popal
|
||||
.endif
|
||||
ret
|
||||
.size mp_call, . - mp_call
|
||||
|
||||
/*
|
||||
* Jump to multiprocessor function
|
||||
*
|
||||
* Parameters:
|
||||
* %eax/%rdi Multiprocessor function
|
||||
* %edx/%rsi Opaque data pointer
|
||||
* %esp/%rsp Stack, or NULL to halt AP upon completion
|
||||
*
|
||||
* Obtain the CPU identifier (i.e. the APIC ID) and perform a tail
|
||||
* call into the specified multiprocessor function.
|
||||
*
|
||||
* This code may run with no stack on an application processor.
|
||||
*/
|
||||
.section ".text.mp_jump", "ax", @progbits
|
||||
.codemp
|
||||
.globl mp_jump
|
||||
mp_jump:
|
||||
.if32 /* Move function parameters to available registers */
|
||||
movl %eax, %edi
|
||||
movl %edx, %esi
|
||||
.endif
|
||||
|
||||
/* Get 8-bit APIC ID and x2APIC feature bit */
|
||||
movl $CPUID_FEATURES, %eax
|
||||
cpuid
|
||||
shrl $24, %ebx
|
||||
movl %ebx, %edx
|
||||
|
||||
/* Get 32-bit x2APIC ID if applicable */
|
||||
testl $CPUID_FEATURES_ECX_X2APIC, %ecx
|
||||
jz 1f
|
||||
movl $CPUID_XT_ENUM, %eax
|
||||
xorl %ecx, %ecx
|
||||
cpuid
|
||||
1:
|
||||
|
||||
.if64 /* Tail call to function */
|
||||
movq %rdi, %rax
|
||||
movq %rsi, %rdi
|
||||
movl %edx, %esi
|
||||
jmp *%rax
|
||||
.else
|
||||
movl %esi, %eax
|
||||
jmp *%edi
|
||||
.endif
|
||||
.size mp_jump, . - mp_jump
|
||||
|
||||
/*
|
||||
* Update maximum CPU identifier
|
||||
*
|
||||
* Parameters:
|
||||
* %eax/%rdi Pointer to shared maximum APIC ID
|
||||
* %edx/%rsi CPU identifier (APIC ID)
|
||||
* %esp/%rsp Stack, or NULL to halt AP upon completion
|
||||
*
|
||||
* This code may run with no stack on an application processor.
|
||||
*/
|
||||
.section ".text.mp_update_max_cpuid", "ax", @progbits
|
||||
.codemp
|
||||
.globl mp_update_max_cpuid
|
||||
mp_update_max_cpuid:
|
||||
.if32 /* Move function parameters to available registers */
|
||||
movl %eax, %edi
|
||||
movl %edx, %esi
|
||||
.endif
|
||||
/* Update maximum APIC ID (atomically) */
|
||||
movl (%DI), %eax
|
||||
1: cmpl %esi, %eax
|
||||
jae 2f
|
||||
lock cmpxchgl %esi, (%DI)
|
||||
jnz 1b
|
||||
2:
|
||||
/* Return to caller (if stack exists), or halt application processor */
|
||||
test %SP, %SP
|
||||
jz 3f
|
||||
ret
|
||||
3: cli
|
||||
hlt
|
||||
jmp 3b
|
||||
.size mp_update_max_cpuid, . - mp_update_max_cpuid
|
||||
@ -23,9 +23,8 @@
|
||||
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL )
|
||||
|
||||
.section ".note.GNU-stack", "", @progbits
|
||||
.text
|
||||
.arch i386
|
||||
.code16
|
||||
.arch i386
|
||||
|
||||
/****************************************************************************
|
||||
* Set/clear CF on the stack as appropriate, assumes stack is as it should
|
||||
|
||||
@ -1,7 +1,6 @@
|
||||
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL )
|
||||
|
||||
.section ".note.GNU-stack", "", @progbits
|
||||
.arch i386
|
||||
|
||||
#ifdef __x86_64__
|
||||
#define STACK_SIZE 8192
|
||||
|
||||
@ -1,7 +1,6 @@
|
||||
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL )
|
||||
|
||||
.section ".note.GNU-stack", "", @progbits
|
||||
.arch i386
|
||||
|
||||
/****************************************************************************
|
||||
* Internal stack
|
||||
|
||||
257
src/arch/x86/core/ucode_mp.S
Normal file
257
src/arch/x86/core/ucode_mp.S
Normal file
@ -0,0 +1,257 @@
|
||||
/*
|
||||
* 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
|
||||
*
|
||||
* Microcode updates
|
||||
*
|
||||
*/
|
||||
|
||||
.section ".note.GNU-stack", "", @progbits
|
||||
.text
|
||||
|
||||
/* Selectively assemble code for 32-bit/64-bit builds */
|
||||
#if defined ( __x86_64__ ) && ! defined ( PLATFORM_pcbios )
|
||||
#define codemp code64
|
||||
#define AX rax
|
||||
#define BX rbx
|
||||
#define CX rcx
|
||||
#define DX rdx
|
||||
#define SI rsi
|
||||
#define DI rdi
|
||||
#define BP rbp
|
||||
#define SP rsp
|
||||
#define if32 if 0
|
||||
#define if64 if 1
|
||||
#else
|
||||
#define codemp code32
|
||||
#define AX eax
|
||||
#define BX ebx
|
||||
#define CX ecx
|
||||
#define DX edx
|
||||
#define SI esi
|
||||
#define DI edi
|
||||
#define BP ebp
|
||||
#define SP esp
|
||||
#define if32 if 1
|
||||
#define if64 if 0
|
||||
#endif
|
||||
|
||||
/* Standard features CPUID leaf */
|
||||
#define CPUID_FEATURES 0x00000001
|
||||
|
||||
/* BIOS update signature MSR */
|
||||
#define MSR_BIOS_SIGN_ID 0x0000008b
|
||||
|
||||
/** Microcode update control layout
|
||||
*
|
||||
* This must match the layout of struct ucode_control.
|
||||
*/
|
||||
.struct 0
|
||||
CONTROL_DESC:
|
||||
.space 8
|
||||
CONTROL_STATUS:
|
||||
.space 8
|
||||
CONTROL_TRIGGER_MSR:
|
||||
.space 4
|
||||
CONTROL_APIC_MAX:
|
||||
.space 4
|
||||
CONTROL_APIC_UNEXPECTED:
|
||||
.space 4
|
||||
CONTROL_APIC_MASK:
|
||||
.space 4
|
||||
CONTROL_APIC_TEST:
|
||||
.space 4
|
||||
CONTROL_VER_CLEAR:
|
||||
.space 1
|
||||
CONTROL_VER_HIGH:
|
||||
.space 1
|
||||
CONTROL_LEN:
|
||||
|
||||
/* We use register %ebp/%rbp to hold the address of the update control */
|
||||
#define CONTROL BP
|
||||
|
||||
/* Microcode update descriptor layout
|
||||
*
|
||||
* This must match the layout of struct ucode_descriptor.
|
||||
*/
|
||||
.struct 0
|
||||
DESC_SIGNATURE:
|
||||
.space 4
|
||||
DESC_VERSION:
|
||||
.space 4
|
||||
DESC_ADDRESS:
|
||||
.space 8
|
||||
DESC_LEN:
|
||||
|
||||
/* We use register %esi/%rsi to hold the address of the descriptor */
|
||||
#define DESC SI
|
||||
|
||||
/** Microcode update status report layout
|
||||
*
|
||||
* This must match the layout of struct ucode_status.
|
||||
*/
|
||||
.struct 0
|
||||
STATUS_SIGNATURE:
|
||||
.space 4
|
||||
STATUS_ID:
|
||||
.space 4
|
||||
STATUS_BEFORE:
|
||||
.space 4
|
||||
STATUS_AFTER:
|
||||
.space 4
|
||||
STATUS_LEN:
|
||||
.equ LOG2_STATUS_LEN, 4
|
||||
.if ( 1 << LOG2_STATUS_LEN ) - STATUS_LEN
|
||||
.error "LOG2_STATUS_LEN value is incorrect"
|
||||
.endif
|
||||
|
||||
/* We use register %edi/%rdi to hold the address of the status report */
|
||||
#define STATUS DI
|
||||
|
||||
/*
|
||||
* Update microcode
|
||||
*
|
||||
* Parameters:
|
||||
* %eax/%rdi Microcode update structure
|
||||
* %edx/%rsi CPU identifier (APIC ID)
|
||||
* %esp/%rsp Stack, or NULL to halt AP upon completion
|
||||
*
|
||||
* This code may run with no stack on an application processor (AP).
|
||||
* All values must be held in registers, and no subroutine calls are
|
||||
* possible. No firmware routines may be called.
|
||||
*
|
||||
* Since cpuid/rdmsr/wrmsr require the use of %eax, %ebx, %ecx, and
|
||||
* %edx, we have essentially only three registers available for
|
||||
* long-term state.
|
||||
*/
|
||||
.text
|
||||
.globl ucode_update
|
||||
.codemp
|
||||
.section ".text.ucode_update", "ax", @progbits
|
||||
ucode_update:
|
||||
|
||||
.if64 /* Get input parameters */
|
||||
movq %rdi, %CONTROL
|
||||
movl %esi, %edx
|
||||
.else
|
||||
movl %eax, %CONTROL
|
||||
.endif
|
||||
/* Check against maximum expected APIC ID */
|
||||
cmpl CONTROL_APIC_MAX(%CONTROL), %edx
|
||||
jbe 1f
|
||||
movl %edx, CONTROL_APIC_UNEXPECTED(%CONTROL)
|
||||
jmp done
|
||||
1:
|
||||
/* Calculate per-CPU status report buffer address */
|
||||
mov %DX, %STATUS
|
||||
shl $LOG2_STATUS_LEN, %STATUS
|
||||
add CONTROL_STATUS(%CONTROL), %STATUS
|
||||
|
||||
/* Report APIC ID */
|
||||
movl %edx, STATUS_ID(%STATUS)
|
||||
|
||||
/* Get and report CPU signature */
|
||||
movl $CPUID_FEATURES, %eax
|
||||
cpuid
|
||||
movl %eax, STATUS_SIGNATURE(%STATUS)
|
||||
|
||||
/* Check APIC ID mask */
|
||||
movl STATUS_ID(%STATUS), %eax
|
||||
andl CONTROL_APIC_MASK(%CONTROL), %eax
|
||||
cmpl CONTROL_APIC_TEST(%CONTROL), %eax
|
||||
jne done
|
||||
|
||||
/* Clear BIOS_SIGN_ID MSR if applicable */
|
||||
movl $MSR_BIOS_SIGN_ID, %ecx
|
||||
xorl %eax, %eax
|
||||
xorl %edx, %edx
|
||||
testb $0xff, CONTROL_VER_CLEAR(%CONTROL)
|
||||
jz 1f
|
||||
wrmsr
|
||||
1:
|
||||
/* Get CPU signature to repopulate BIOS_SIGN_ID MSR (for Intel) */
|
||||
movl $CPUID_FEATURES, %eax
|
||||
cpuid
|
||||
|
||||
/* Get initial microcode version */
|
||||
movl $MSR_BIOS_SIGN_ID, %ecx
|
||||
rdmsr
|
||||
testb $0xff, CONTROL_VER_HIGH(%CONTROL)
|
||||
jz 1f
|
||||
movl %edx, %eax
|
||||
1: movl %eax, STATUS_BEFORE(%STATUS)
|
||||
|
||||
/* Get start of descriptor list */
|
||||
mov CONTROL_DESC(%CONTROL), %DESC
|
||||
sub $DESC_LEN, %DESC
|
||||
|
||||
1: /* Walk update descriptor list to find a matching CPU signature */
|
||||
add $DESC_LEN, %DESC
|
||||
movl DESC_SIGNATURE(%DESC), %eax
|
||||
testl %eax, %eax
|
||||
jz noload
|
||||
cmpl STATUS_SIGNATURE(%STATUS), %eax
|
||||
jne 1b
|
||||
|
||||
/* Compare (signed) microcode versions */
|
||||
movl STATUS_BEFORE(%STATUS), %eax
|
||||
cmpl DESC_VERSION(%DESC), %eax
|
||||
jge noload
|
||||
|
||||
/* Load microcode update */
|
||||
movl CONTROL_TRIGGER_MSR(%CONTROL), %ecx
|
||||
movl (DESC_ADDRESS + 0)(%DESC), %eax
|
||||
movl (DESC_ADDRESS + 4)(%DESC), %edx
|
||||
wrmsr
|
||||
|
||||
noload: /* Clear BIOS_SIGN_ID MSR if applicable */
|
||||
movl $MSR_BIOS_SIGN_ID, %ecx
|
||||
xorl %eax, %eax
|
||||
xorl %edx, %edx
|
||||
testb $0xff, CONTROL_VER_CLEAR(%CONTROL)
|
||||
jz 1f
|
||||
wrmsr
|
||||
1:
|
||||
/* Get CPU signature to repopulate BIOS_SIGN_ID MSR (for Intel) */
|
||||
movl $CPUID_FEATURES, %eax
|
||||
cpuid
|
||||
|
||||
/* Get and report final microcode version */
|
||||
movl $MSR_BIOS_SIGN_ID, %ecx
|
||||
rdmsr
|
||||
testb $0xff, CONTROL_VER_HIGH(%CONTROL)
|
||||
jz 1f
|
||||
movl %edx, %eax
|
||||
1: movl %eax, STATUS_AFTER(%STATUS)
|
||||
|
||||
done: /* Return to caller (if stack exists), or halt application processor */
|
||||
test %SP, %SP
|
||||
jz 1f
|
||||
ret
|
||||
1: cli
|
||||
hlt
|
||||
jmp 1b
|
||||
.size ucode_update, . - ucode_update
|
||||
@ -36,19 +36,23 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
|
||||
* Multiply big integers
|
||||
*
|
||||
* @v multiplicand0 Element 0 of big integer to be multiplied
|
||||
* @v multiplicand_size Number of elements in multiplicand
|
||||
* @v multiplier0 Element 0 of big integer to be multiplied
|
||||
* @v multiplier_size Number of elements in multiplier
|
||||
* @v result0 Element 0 of big integer to hold result
|
||||
* @v size Number of elements
|
||||
*/
|
||||
void bigint_multiply_raw ( const uint32_t *multiplicand0,
|
||||
unsigned int multiplicand_size,
|
||||
const uint32_t *multiplier0,
|
||||
uint32_t *result0, unsigned int size ) {
|
||||
const bigint_t ( size ) __attribute__ (( may_alias )) *multiplicand =
|
||||
( ( const void * ) multiplicand0 );
|
||||
const bigint_t ( size ) __attribute__ (( may_alias )) *multiplier =
|
||||
( ( const void * ) multiplier0 );
|
||||
bigint_t ( size * 2 ) __attribute__ (( may_alias )) *result =
|
||||
( ( void * ) result0 );
|
||||
unsigned int multiplier_size,
|
||||
uint32_t *result0 ) {
|
||||
unsigned int result_size = ( multiplicand_size + multiplier_size );
|
||||
const bigint_t ( multiplicand_size ) __attribute__ (( may_alias ))
|
||||
*multiplicand = ( ( const void * ) multiplicand0 );
|
||||
const bigint_t ( multiplier_size ) __attribute__ (( may_alias ))
|
||||
*multiplier = ( ( const void * ) multiplier0 );
|
||||
bigint_t ( result_size ) __attribute__ (( may_alias ))
|
||||
*result = ( ( void * ) result0 );
|
||||
unsigned int i;
|
||||
unsigned int j;
|
||||
uint32_t multiplicand_element;
|
||||
@ -62,9 +66,9 @@ void bigint_multiply_raw ( const uint32_t *multiplicand0,
|
||||
memset ( result, 0, sizeof ( *result ) );
|
||||
|
||||
/* Multiply integers one element at a time */
|
||||
for ( i = 0 ; i < size ; i++ ) {
|
||||
for ( i = 0 ; i < multiplicand_size ; i++ ) {
|
||||
multiplicand_element = multiplicand->element[i];
|
||||
for ( j = 0 ; j < size ; j++ ) {
|
||||
for ( j = 0 ; j < multiplier_size ; j++ ) {
|
||||
multiplier_element = multiplier->element[j];
|
||||
result_elements = &result->element[ i + j ];
|
||||
/* Perform a single multiply, and add the
|
||||
@ -73,7 +77,7 @@ void bigint_multiply_raw ( const uint32_t *multiplicand0,
|
||||
* never overflow beyond the end of the
|
||||
* result, since:
|
||||
*
|
||||
* a < 2^{n}, b < 2^{n} => ab < 2^{2n}
|
||||
* a < 2^{n}, b < 2^{m} => ab < 2^{n+m}
|
||||
*/
|
||||
__asm__ __volatile__ ( "mull %5\n\t"
|
||||
"addl %%eax, (%6,%2,4)\n\t"
|
||||
|
||||
@ -11,9 +11,8 @@ FILE_LICENCE ( GPL2_OR_LATER )
|
||||
#define PIC2_ICR 0xa0
|
||||
|
||||
.section ".note.GNU-stack", "", @progbits
|
||||
.text
|
||||
.arch i386
|
||||
.code16
|
||||
.arch i386
|
||||
|
||||
.section ".text16", "ax", @progbits
|
||||
.globl undiisr
|
||||
|
||||
798
src/arch/x86/image/ucode.c
Normal file
798
src/arch/x86/image/ucode.c
Normal file
@ -0,0 +1,798 @@
|
||||
/*
|
||||
* 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
|
||||
*
|
||||
* Microcode updates
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
#include <ipxe/uaccess.h>
|
||||
#include <ipxe/umalloc.h>
|
||||
#include <ipxe/image.h>
|
||||
#include <ipxe/cpuid.h>
|
||||
#include <ipxe/msr.h>
|
||||
#include <ipxe/mp.h>
|
||||
#include <ipxe/timer.h>
|
||||
#include <ipxe/ucode.h>
|
||||
|
||||
/**
|
||||
* Maximum number of hyperthread siblings
|
||||
*
|
||||
* Microcode updates must not be performed on hyperthread siblings at
|
||||
* the same time, since they share microcode storage.
|
||||
*
|
||||
* Hyperthread siblings are always the lowest level of the CPU
|
||||
* topology and correspond to the least significant bits of the APIC
|
||||
* ID. We may therefore avoid collisions by performing the microcode
|
||||
* updates in batches, with each batch targeting just one value for
|
||||
* the least significant N bits of the APIC ID.
|
||||
*
|
||||
* We assume that no CPUs exist with more than this number of
|
||||
* hyperthread siblings. (This must be a power of two.)
|
||||
*/
|
||||
#define UCODE_MAX_HT 8
|
||||
|
||||
/** Time to wait for a microcode update to complete */
|
||||
#define UCODE_WAIT_MS 10
|
||||
|
||||
/** A CPU vendor string */
|
||||
union ucode_vendor_id {
|
||||
/** CPUID registers */
|
||||
uint32_t dword[3];
|
||||
/** Human-readable string */
|
||||
uint8_t string[12];
|
||||
};
|
||||
|
||||
/** A CPU vendor */
|
||||
struct ucode_vendor {
|
||||
/** Vendor string */
|
||||
union ucode_vendor_id id;
|
||||
/** Microcode load trigger MSR */
|
||||
uint32_t trigger_msr;
|
||||
/** Microcode version requires manual clear */
|
||||
uint8_t ver_clear;
|
||||
/** Microcode version is reported via high dword */
|
||||
uint8_t ver_high;
|
||||
};
|
||||
|
||||
/** A microcode update */
|
||||
struct ucode_update {
|
||||
/** CPU vendor, if known */
|
||||
struct ucode_vendor *vendor;
|
||||
/** Boot processor CPU signature */
|
||||
uint32_t signature;
|
||||
/** Platform ID */
|
||||
uint32_t platform;
|
||||
/** Number of potentially relevant signatures found */
|
||||
unsigned int count;
|
||||
/** Update descriptors (if being populated) */
|
||||
struct ucode_descriptor *desc;
|
||||
};
|
||||
|
||||
/** A microcode update summary */
|
||||
struct ucode_summary {
|
||||
/** Number of CPUs processed */
|
||||
unsigned int count;
|
||||
/** Lowest observed microcode version */
|
||||
int32_t low;
|
||||
/** Highest observed microcode version */
|
||||
int32_t high;
|
||||
};
|
||||
|
||||
/** Intel CPU vendor */
|
||||
static struct ucode_vendor ucode_intel = {
|
||||
.id = { .string = "GenuineIntel" },
|
||||
.ver_clear = 1,
|
||||
.ver_high = 1,
|
||||
.trigger_msr = MSR_UCODE_TRIGGER_INTEL,
|
||||
};
|
||||
|
||||
/** AMD CPU vendor */
|
||||
static struct ucode_vendor ucode_amd = {
|
||||
.id = { .string = "AuthenticAMD" },
|
||||
.trigger_msr = MSR_UCODE_TRIGGER_AMD,
|
||||
};
|
||||
|
||||
/** List of known CPU vendors */
|
||||
static struct ucode_vendor *ucode_vendors[] = {
|
||||
&ucode_intel,
|
||||
&ucode_amd,
|
||||
};
|
||||
|
||||
/**
|
||||
* Get CPU vendor name (for debugging)
|
||||
*
|
||||
* @v vendor CPU vendor
|
||||
* @ret name Name
|
||||
*/
|
||||
static const char * ucode_vendor_name ( const union ucode_vendor_id *vendor ) {
|
||||
static union {
|
||||
union ucode_vendor_id vendor;
|
||||
char text[ sizeof ( *vendor ) + 1 /* NUL */ ];
|
||||
} u;
|
||||
|
||||
/* Construct name */
|
||||
memcpy ( &u.vendor, vendor, sizeof ( u.vendor ) );
|
||||
u.text[ sizeof ( u.text ) - 1 ] = '\0';
|
||||
return u.text;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check status report
|
||||
*
|
||||
* @v update Microcode update
|
||||
* @v control Microcode update control
|
||||
* @v summary Microcode update summary
|
||||
* @v id APIC ID
|
||||
* @v optional Status report is optional
|
||||
* @ret rc Return status code
|
||||
*/
|
||||
static int ucode_status ( struct ucode_update *update,
|
||||
struct ucode_control *control,
|
||||
struct ucode_summary *summary,
|
||||
unsigned int id, int optional ) {
|
||||
struct ucode_status status;
|
||||
struct ucode_descriptor *desc;
|
||||
|
||||
/* Sanity check */
|
||||
assert ( id <= control->apic_max );
|
||||
|
||||
/* Read status report */
|
||||
copy_from_user ( &status, phys_to_user ( control->status ),
|
||||
( id * sizeof ( status ) ), sizeof ( status ) );
|
||||
|
||||
/* Ignore empty optional status reports */
|
||||
if ( optional && ( ! status.signature ) )
|
||||
return 0;
|
||||
DBGC ( update, "UCODE %#08x signature %#08x ucode %#08x->%#08x\n",
|
||||
id, status.signature, status.before, status.after );
|
||||
|
||||
/* Check CPU signature */
|
||||
if ( ! status.signature ) {
|
||||
DBGC2 ( update, "UCODE %#08x has no signature\n", id );
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
/* Check APIC ID is correct */
|
||||
if ( status.id != id ) {
|
||||
DBGC ( update, "UCODE %#08x wrong APIC ID %#08x\n",
|
||||
id, status.id );
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* Check that maximum APIC ID was not exceeded */
|
||||
if ( control->apic_unexpected ) {
|
||||
DBGC ( update, "UCODE %#08x saw unexpected APIC ID %#08x\n",
|
||||
id, control->apic_unexpected );
|
||||
return -ERANGE;
|
||||
}
|
||||
|
||||
/* Check microcode was not downgraded */
|
||||
if ( status.after < status.before ) {
|
||||
DBGC ( update, "UCODE %#08x was downgraded %#08x->%#08x\n",
|
||||
id, status.before, status.after );
|
||||
return -ENOTTY;
|
||||
}
|
||||
|
||||
/* Check that expected updates (if any) were applied */
|
||||
for ( desc = update->desc ; desc->signature ; desc++ ) {
|
||||
if ( ( desc->signature == status.signature ) &&
|
||||
( status.after < desc->version ) ) {
|
||||
DBGC ( update, "UCODE %#08x failed update %#08x->%#08x "
|
||||
"(wanted %#08x)\n", id, status.before,
|
||||
status.after, desc->version );
|
||||
return -EIO;
|
||||
}
|
||||
}
|
||||
|
||||
/* Update summary */
|
||||
summary->count++;
|
||||
if ( status.before < summary->low )
|
||||
summary->low = status.before;
|
||||
if ( status.after > summary->high )
|
||||
summary->high = status.after;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update microcode on all CPUs
|
||||
*
|
||||
* @v image Microcode image
|
||||
* @v update Microcode update
|
||||
* @v summary Microcode update summary to fill in
|
||||
* @ret rc Return status code
|
||||
*/
|
||||
static int ucode_update_all ( struct image *image,
|
||||
struct ucode_update *update,
|
||||
struct ucode_summary *summary ) {
|
||||
struct ucode_control control;
|
||||
struct ucode_vendor *vendor;
|
||||
userptr_t status;
|
||||
unsigned int max;
|
||||
unsigned int i;
|
||||
size_t len;
|
||||
int rc;
|
||||
|
||||
/* Initialise summary */
|
||||
summary->count = 0;
|
||||
summary->low = UCODE_VERSION_MAX;
|
||||
summary->high = UCODE_VERSION_MIN;
|
||||
|
||||
/* Allocate status reports */
|
||||
max = mp_max_cpuid();
|
||||
len = ( ( max + 1 ) * sizeof ( struct ucode_status ) );
|
||||
status = umalloc ( len );
|
||||
if ( ! status ) {
|
||||
DBGC ( image, "UCODE %s could not allocate %d status reports\n",
|
||||
image->name, ( max + 1 ) );
|
||||
rc = -ENOMEM;
|
||||
goto err_alloc;
|
||||
}
|
||||
memset_user ( status, 0, 0, len );
|
||||
|
||||
/* Construct control structure */
|
||||
memset ( &control, 0, sizeof ( control ) );
|
||||
control.desc = virt_to_phys ( update->desc );
|
||||
control.status = user_to_phys ( status, 0 );
|
||||
vendor = update->vendor;
|
||||
if ( vendor ) {
|
||||
control.ver_clear = vendor->ver_clear;
|
||||
control.ver_high = vendor->ver_high;
|
||||
control.trigger_msr = vendor->trigger_msr;
|
||||
} else {
|
||||
assert ( update->count == 0 );
|
||||
}
|
||||
control.apic_max = max;
|
||||
|
||||
/* Update microcode on boot processor */
|
||||
mp_exec_boot ( ucode_update, &control );
|
||||
if ( ( rc = ucode_status ( update, &control, summary,
|
||||
mp_boot_cpuid(), 0 ) ) != 0 ) {
|
||||
DBGC ( image, "UCODE %s failed on boot processor: %s\n",
|
||||
image->name, strerror ( rc ) );
|
||||
goto err_boot;
|
||||
}
|
||||
|
||||
/* Update microcode on application processors, avoiding
|
||||
* simultaneous updates on hyperthread siblings.
|
||||
*/
|
||||
build_assert ( ( UCODE_MAX_HT & ( UCODE_MAX_HT - 1 ) ) == 0 );
|
||||
control.apic_mask = ( UCODE_MAX_HT - 1 );
|
||||
for ( ; control.apic_test <= control.apic_mask ; control.apic_test++ ) {
|
||||
mp_start_all ( ucode_update, &control );
|
||||
mdelay ( UCODE_WAIT_MS );
|
||||
}
|
||||
|
||||
/* Check status reports */
|
||||
summary->count = 0;
|
||||
for ( i = 0 ; i <= max ; i++ ) {
|
||||
if ( ( rc = ucode_status ( update, &control, summary,
|
||||
i, 1 ) ) != 0 ) {
|
||||
goto err_status;
|
||||
}
|
||||
}
|
||||
|
||||
/* Success */
|
||||
rc = 0;
|
||||
|
||||
err_status:
|
||||
err_boot:
|
||||
ufree ( status );
|
||||
err_alloc:
|
||||
return rc;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add descriptor to list (if applicable)
|
||||
*
|
||||
* @v image Microcode image
|
||||
* @v start Starting offset within image
|
||||
* @v vendor CPU vendor
|
||||
* @v desc Microcode descriptor
|
||||
* @v platforms Supported platforms, or 0 for all platforms
|
||||
* @v update Microcode update
|
||||
*/
|
||||
static void ucode_describe ( struct image *image, size_t start,
|
||||
const struct ucode_vendor *vendor,
|
||||
const struct ucode_descriptor *desc,
|
||||
uint32_t platforms, struct ucode_update *update ) {
|
||||
|
||||
/* Dump descriptor information */
|
||||
DBGC2 ( image, "UCODE %s+%#04zx %s %#08x", image->name, start,
|
||||
ucode_vendor_name ( &vendor->id ), desc->signature );
|
||||
if ( platforms )
|
||||
DBGC2 ( image, " (%#02x)", platforms );
|
||||
DBGC2 ( image, " version %#08x\n", desc->version );
|
||||
|
||||
/* Check applicability */
|
||||
if ( vendor != update->vendor )
|
||||
return;
|
||||
if ( ( desc->signature ^ update->signature ) & UCODE_SIGNATURE_MASK )
|
||||
return;
|
||||
if ( platforms && ( ! ( platforms & update->platform ) ) )
|
||||
return;
|
||||
|
||||
/* Add descriptor, if applicable */
|
||||
if ( update->desc ) {
|
||||
memcpy ( &update->desc[update->count], desc, sizeof ( *desc ) );
|
||||
DBGC ( image, "UCODE %s+%#04zx found %s %#08x version %#08x\n",
|
||||
image->name, start, ucode_vendor_name ( &vendor->id ),
|
||||
desc->signature, desc->version );
|
||||
}
|
||||
update->count++;
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify checksum
|
||||
*
|
||||
* @v image Microcode image
|
||||
* @v start Starting offset
|
||||
* @v len Length
|
||||
* @ret rc Return status code
|
||||
*/
|
||||
static int ucode_verify ( struct image *image, size_t start, size_t len ) {
|
||||
uint32_t checksum = 0;
|
||||
uint32_t dword;
|
||||
size_t offset;
|
||||
|
||||
/* Check length is a multiple of dwords */
|
||||
if ( ( len % sizeof ( dword ) ) != 0 ) {
|
||||
DBGC ( image, "UCODE %s+%#04zx invalid length %#zx\n",
|
||||
image->name, start, len );
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* Calculate checksum */
|
||||
for ( offset = start ; len ;
|
||||
offset += sizeof ( dword ), len -= sizeof ( dword ) ) {
|
||||
copy_from_user ( &dword, image->data, offset,
|
||||
sizeof ( dword ) );
|
||||
checksum += dword;
|
||||
}
|
||||
if ( checksum != 0 ) {
|
||||
DBGC ( image, "UCODE %s+%#04zx bad checksum %#08x\n",
|
||||
image->name, start, checksum );
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse Intel microcode image
|
||||
*
|
||||
* @v image Microcode image
|
||||
* @v start Starting offset within image
|
||||
* @v update Microcode update
|
||||
* @ret len Length consumed, or negative error
|
||||
*/
|
||||
static int ucode_parse_intel ( struct image *image, size_t start,
|
||||
struct ucode_update *update ) {
|
||||
struct intel_ucode_header hdr;
|
||||
struct intel_ucode_ext_header exthdr;
|
||||
struct intel_ucode_ext ext;
|
||||
struct ucode_descriptor desc;
|
||||
size_t remaining;
|
||||
size_t offset;
|
||||
size_t data_len;
|
||||
size_t len;
|
||||
unsigned int i;
|
||||
int rc;
|
||||
|
||||
/* Read header */
|
||||
remaining = ( image->len - start );
|
||||
if ( remaining < sizeof ( hdr ) ) {
|
||||
DBGC ( image, "UCODE %s+%#04zx too small for Intel header\n",
|
||||
image->name, start );
|
||||
return -ENOEXEC;
|
||||
}
|
||||
copy_from_user ( &hdr, image->data, start, sizeof ( hdr ) );
|
||||
|
||||
/* Determine lengths */
|
||||
data_len = hdr.data_len;
|
||||
if ( ! data_len )
|
||||
data_len = INTEL_UCODE_DATA_LEN;
|
||||
len = hdr.len;
|
||||
if ( ! len )
|
||||
len = ( sizeof ( hdr ) + data_len );
|
||||
|
||||
/* Verify a selection of fields */
|
||||
if ( ( hdr.hver != INTEL_UCODE_HVER ) ||
|
||||
( hdr.lver != INTEL_UCODE_LVER ) ||
|
||||
( len < sizeof ( hdr ) ) ||
|
||||
( len > remaining ) ||
|
||||
( data_len > ( len - sizeof ( hdr ) ) ) ||
|
||||
( ( data_len % sizeof ( uint32_t ) ) != 0 ) ||
|
||||
( ( len % INTEL_UCODE_ALIGN ) != 0 ) ) {
|
||||
DBGC2 ( image, "UCODE %s+%#04zx is not an Intel update\n",
|
||||
image->name, start );
|
||||
return -EINVAL;
|
||||
}
|
||||
DBGC2 ( image, "UCODE %s+%#04zx is an Intel update\n",
|
||||
image->name, start );
|
||||
|
||||
/* Verify checksum */
|
||||
if ( ( rc = ucode_verify ( image, start, len ) ) != 0 )
|
||||
return rc;
|
||||
|
||||
/* Populate descriptor */
|
||||
desc.signature = hdr.signature;
|
||||
desc.version = hdr.version;
|
||||
desc.address = user_to_phys ( image->data,
|
||||
( start + sizeof ( hdr ) ) );
|
||||
|
||||
/* Add non-extended descriptor, if applicable */
|
||||
ucode_describe ( image, start, &ucode_intel, &desc, hdr.platforms,
|
||||
update );
|
||||
|
||||
/* Construct extended descriptors, if applicable */
|
||||
offset = ( sizeof ( hdr ) + data_len );
|
||||
if ( offset <= ( len - sizeof ( exthdr ) ) ) {
|
||||
|
||||
/* Read extended header */
|
||||
copy_from_user ( &exthdr, image->data, ( start + offset ),
|
||||
sizeof ( exthdr ) );
|
||||
offset += sizeof ( exthdr );
|
||||
|
||||
/* Read extended signatures */
|
||||
for ( i = 0 ; i < exthdr.count ; i++ ) {
|
||||
|
||||
/* Read extended signature */
|
||||
if ( offset > ( len - sizeof ( ext ) ) ) {
|
||||
DBGC ( image, "UCODE %s+%#04zx extended "
|
||||
"signature overrun\n",
|
||||
image->name, start );
|
||||
return -EINVAL;
|
||||
}
|
||||
copy_from_user ( &ext, image->data, ( start + offset ),
|
||||
sizeof ( ext ) );
|
||||
offset += sizeof ( ext );
|
||||
|
||||
/* Avoid duplicating non-extended descriptor */
|
||||
if ( ( ext.signature == hdr.signature ) &&
|
||||
( ext.platforms == hdr.platforms ) ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Construct descriptor, if applicable */
|
||||
desc.signature = ext.signature;
|
||||
ucode_describe ( image, start, &ucode_intel, &desc,
|
||||
ext.platforms, update );
|
||||
}
|
||||
}
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse AMD microcode image
|
||||
*
|
||||
* @v image Microcode image
|
||||
* @v start Starting offset within image
|
||||
* @v update Microcode update
|
||||
* @ret len Length consumed, or negative error
|
||||
*/
|
||||
static int ucode_parse_amd ( struct image *image, size_t start,
|
||||
struct ucode_update *update ) {
|
||||
struct amd_ucode_header hdr;
|
||||
struct amd_ucode_equivalence equiv;
|
||||
struct amd_ucode_patch_header phdr;
|
||||
struct amd_ucode_patch patch;
|
||||
struct ucode_descriptor desc;
|
||||
size_t remaining;
|
||||
size_t offset;
|
||||
unsigned int count;
|
||||
unsigned int used;
|
||||
unsigned int i;
|
||||
|
||||
/* Read header */
|
||||
remaining = ( image->len - start );
|
||||
if ( remaining < sizeof ( hdr ) ) {
|
||||
DBGC ( image, "UCODE %s+%#04zx too small for AMD header\n",
|
||||
image->name, start );
|
||||
return -ENOEXEC;
|
||||
}
|
||||
copy_from_user ( &hdr, image->data, start, sizeof ( hdr ) );
|
||||
|
||||
/* Check header */
|
||||
if ( hdr.magic != AMD_UCODE_MAGIC ) {
|
||||
DBGC2 ( image, "UCODE %s+%#04zx is not an AMD update\n",
|
||||
image->name, start );
|
||||
return -ENOEXEC;
|
||||
}
|
||||
DBGC2 ( image, "UCODE %s+%#04zx is an AMD update\n",
|
||||
image->name, start );
|
||||
if ( hdr.type != AMD_UCODE_EQUIV_TYPE ) {
|
||||
DBGC ( image, "UCODE %s+%#04zx unsupported equivalence table "
|
||||
"type %d\n", image->name, start, hdr.type );
|
||||
return -ENOTSUP;
|
||||
}
|
||||
if ( hdr.len > ( remaining - sizeof ( hdr ) ) ) {
|
||||
DBGC ( image, "UCODE %s+%#04zx truncated equivalence table\n",
|
||||
image->name, start );
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* Count number of equivalence table entries */
|
||||
offset = sizeof ( hdr );
|
||||
for ( count = 0 ; offset < ( sizeof ( hdr ) + hdr.len ) ;
|
||||
count++, offset += sizeof ( equiv ) ) {
|
||||
copy_from_user ( &equiv, image->data, ( start + offset ),
|
||||
sizeof ( equiv ) );
|
||||
if ( ! equiv.signature )
|
||||
break;
|
||||
}
|
||||
DBGC2 ( image, "UCODE %s+%#04zx has %d equivalence table entries\n",
|
||||
image->name, start, count );
|
||||
|
||||
/* Parse available updates */
|
||||
offset = ( sizeof ( hdr ) + hdr.len );
|
||||
used = 0;
|
||||
while ( used < count ) {
|
||||
|
||||
/* Read patch header */
|
||||
if ( ( offset + sizeof ( phdr ) ) > remaining ) {
|
||||
DBGC ( image, "UCODE %s+%#04zx truncated patch "
|
||||
"header\n", image->name, start );
|
||||
return -EINVAL;
|
||||
}
|
||||
copy_from_user ( &phdr, image->data, ( start + offset ),
|
||||
sizeof ( phdr ) );
|
||||
offset += sizeof ( phdr );
|
||||
|
||||
/* Validate patch header */
|
||||
if ( phdr.type != AMD_UCODE_PATCH_TYPE ) {
|
||||
DBGC ( image, "UCODE %s+%#04zx unsupported patch type "
|
||||
"%d\n", image->name, start, phdr.type );
|
||||
return -ENOTSUP;
|
||||
}
|
||||
if ( phdr.len < sizeof ( patch ) ) {
|
||||
DBGC ( image, "UCODE %s+%#04zx underlength patch\n",
|
||||
image->name, start );
|
||||
return -EINVAL;
|
||||
}
|
||||
if ( phdr.len > ( remaining - offset ) ) {
|
||||
DBGC ( image, "UCODE %s+%#04zx truncated patch\n",
|
||||
image->name, start );
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* Read patch and construct descriptor */
|
||||
copy_from_user ( &patch, image->data, ( start + offset ),
|
||||
sizeof ( patch ) );
|
||||
desc.version = patch.version;
|
||||
desc.address = user_to_phys ( image->data, ( start + offset ) );
|
||||
offset += phdr.len;
|
||||
|
||||
/* Parse equivalence table to find matching signatures */
|
||||
for ( i = 0 ; i < count ; i++ ) {
|
||||
copy_from_user ( &equiv, image->data,
|
||||
( start + sizeof ( hdr ) +
|
||||
( i * ( sizeof ( equiv ) ) ) ),
|
||||
sizeof ( equiv ) );
|
||||
if ( patch.id == equiv.id ) {
|
||||
desc.signature = equiv.signature;
|
||||
ucode_describe ( image, start, &ucode_amd,
|
||||
&desc, 0, update );
|
||||
used++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return offset;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse microcode image
|
||||
*
|
||||
* @v image Microcode image
|
||||
* @v update Microcode update
|
||||
* @ret rc Return status code
|
||||
*/
|
||||
static int ucode_parse ( struct image *image, struct ucode_update *update ) {
|
||||
size_t start;
|
||||
int len;
|
||||
|
||||
/* Attempt to parse concatenated microcode updates */
|
||||
for ( start = 0 ; start < image->len ; start += len ) {
|
||||
|
||||
/* Attempt to parse as Intel microcode */
|
||||
len = ucode_parse_intel ( image, start, update );
|
||||
if ( len > 0 )
|
||||
continue;
|
||||
|
||||
/* Attempt to parse as AMD microcode */
|
||||
len = ucode_parse_amd ( image, start, update );
|
||||
if ( len > 0 )
|
||||
continue;
|
||||
|
||||
/* Not a recognised microcode format */
|
||||
DBGC ( image, "UCODE %s+%zx not recognised\n",
|
||||
image->name, start );
|
||||
return -ENOEXEC;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute microcode update
|
||||
*
|
||||
* @v image Microcode image
|
||||
* @ret rc Return status code
|
||||
*/
|
||||
static int ucode_exec ( struct image *image ) {
|
||||
struct ucode_update update;
|
||||
struct ucode_vendor *vendor;
|
||||
struct ucode_summary summary;
|
||||
union ucode_vendor_id id;
|
||||
uint64_t platform_id;
|
||||
uint32_t discard_a;
|
||||
uint32_t discard_b;
|
||||
uint32_t discard_c;
|
||||
uint32_t discard_d;
|
||||
unsigned int check;
|
||||
unsigned int i;
|
||||
size_t len;
|
||||
int rc;
|
||||
|
||||
/* Initialise update */
|
||||
memset ( &update, 0, sizeof ( update ) );
|
||||
cpuid ( CPUID_VENDOR_ID, 0, &discard_a, &id.dword[0], &id.dword[2],
|
||||
&id.dword[1] );
|
||||
cpuid ( CPUID_FEATURES, 0, &update.signature, &discard_b,
|
||||
&discard_c, &discard_d );
|
||||
|
||||
/* Identify CPU vendor, if recognised */
|
||||
for ( i = 0 ; i < ( sizeof ( ucode_vendors ) /
|
||||
sizeof ( ucode_vendors[0] ) ) ; i++ ) {
|
||||
vendor = ucode_vendors[i];
|
||||
if ( memcmp ( &id, &vendor->id, sizeof ( id ) ) == 0 )
|
||||
update.vendor = vendor;
|
||||
}
|
||||
|
||||
/* Identify platform, if applicable */
|
||||
if ( update.vendor == &ucode_intel ) {
|
||||
platform_id = rdmsr ( MSR_PLATFORM_ID );
|
||||
update.platform =
|
||||
( 1 << MSR_PLATFORM_ID_VALUE ( platform_id ) );
|
||||
}
|
||||
|
||||
/* Count number of matching update descriptors */
|
||||
DBGC ( image, "UCODE %s applying to %s %#08x",
|
||||
image->name, ucode_vendor_name ( &id ), update.signature );
|
||||
if ( update.platform )
|
||||
DBGC ( image, " (%#02x)", update.platform );
|
||||
DBGC ( image, "\n" );
|
||||
if ( ( rc = ucode_parse ( image, &update ) ) != 0 )
|
||||
goto err_count;
|
||||
DBGC ( image, "UCODE %s found %d matching update(s)\n",
|
||||
image->name, update.count );
|
||||
|
||||
/* Allocate descriptors */
|
||||
len = ( ( update.count + 1 /* terminator */ ) *
|
||||
sizeof ( update.desc[0] ) );
|
||||
update.desc = zalloc ( len );
|
||||
if ( ! update.desc ) {
|
||||
rc = -ENOMEM;
|
||||
goto err_alloc;
|
||||
}
|
||||
|
||||
/* Populate descriptors */
|
||||
check = update.count;
|
||||
update.count = 0;
|
||||
if ( ( rc = ucode_parse ( image, &update ) ) != 0 )
|
||||
goto err_parse;
|
||||
assert ( check == update.count );
|
||||
|
||||
/* Perform update */
|
||||
if ( ( rc = ucode_update_all ( image, &update, &summary ) ) != 0 )
|
||||
goto err_update;
|
||||
|
||||
/* Print summary if directed to do so */
|
||||
if ( image->cmdline && ( strstr ( image->cmdline, "-v" ) ) ) {
|
||||
printf ( "Microcode: " );
|
||||
if ( summary.low == summary.high ) {
|
||||
printf ( "already version %#x", summary.low );
|
||||
} else {
|
||||
printf ( "updated version %#x->%#x",
|
||||
summary.low, summary.high );
|
||||
}
|
||||
printf ( " (x%d)\n", summary.count );
|
||||
}
|
||||
|
||||
err_update:
|
||||
err_parse:
|
||||
free ( update.desc );
|
||||
err_alloc:
|
||||
err_count:
|
||||
return rc;
|
||||
}
|
||||
|
||||
/**
|
||||
* Probe microcode update image
|
||||
*
|
||||
* @v image Microcode image
|
||||
* @ret rc Return status code
|
||||
*/
|
||||
static int ucode_probe ( struct image *image ) {
|
||||
union {
|
||||
struct intel_ucode_header intel;
|
||||
struct amd_ucode_header amd;
|
||||
} header;
|
||||
|
||||
/* Sanity check */
|
||||
if ( image->len < sizeof ( header ) ) {
|
||||
DBGC ( image, "UCODE %s too short\n", image->name );
|
||||
return -ENOEXEC;
|
||||
}
|
||||
|
||||
/* Read first microcode image header */
|
||||
copy_from_user ( &header, image->data, 0, sizeof ( header ) );
|
||||
|
||||
/* Check for something that looks like an Intel update
|
||||
*
|
||||
* Intel updates unfortunately have no magic signatures or
|
||||
* other easily verifiable fields. We check a small selection
|
||||
* of header fields that can be easily verified.
|
||||
*
|
||||
* We do not attempt to fully parse the update, since we want
|
||||
* errors to be reported at the point of attempting to execute
|
||||
* the image, and do not want to have a microcode image
|
||||
* erroneously treated as a PXE boot executable.
|
||||
*/
|
||||
if ( ( header.intel.hver == INTEL_UCODE_HVER ) &&
|
||||
( header.intel.lver == INTEL_UCODE_LVER ) &&
|
||||
( ( header.intel.date.century == 0x19 ) ||
|
||||
( ( header.intel.date.century >= 0x20 ) &&
|
||||
( header.intel.date.century <= 0x29 ) ) ) ) {
|
||||
DBGC ( image, "UCODE %s+%#04zx looks like an Intel update\n",
|
||||
image->name, ( ( size_t ) 0 ) );
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Check for AMD update signature */
|
||||
if ( ( header.amd.magic == AMD_UCODE_MAGIC ) &&
|
||||
( header.amd.type == AMD_UCODE_EQUIV_TYPE ) ) {
|
||||
DBGC ( image, "UCODE %s+%#04zx looks like an AMD update\n",
|
||||
image->name, ( ( size_t ) 0 ) );
|
||||
return 0;
|
||||
}
|
||||
|
||||
return -ENOEXEC;
|
||||
}
|
||||
|
||||
/** Microcode update image type */
|
||||
struct image_type ucode_image_type __image_type ( PROBE_NORMAL ) = {
|
||||
.name = "ucode",
|
||||
.probe = ucode_probe,
|
||||
.exec = ucode_exec,
|
||||
};
|
||||
@ -323,7 +323,9 @@ bigint_done_raw ( const uint32_t *value0, unsigned int size __unused,
|
||||
}
|
||||
|
||||
extern void bigint_multiply_raw ( const uint32_t *multiplicand0,
|
||||
unsigned int multiplicand_size,
|
||||
const uint32_t *multiplier0,
|
||||
uint32_t *value0, unsigned int size );
|
||||
unsigned int multiplier_size,
|
||||
uint32_t *value0 );
|
||||
|
||||
#endif /* _BITS_BIGINT_H */
|
||||
|
||||
@ -44,6 +44,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
|
||||
#define ERRFILE_sdi ( ERRFILE_ARCH | ERRFILE_IMAGE | 0x000b0000 )
|
||||
#define ERRFILE_initrd ( ERRFILE_ARCH | ERRFILE_IMAGE | 0x000c0000 )
|
||||
#define ERRFILE_pxe_call ( ERRFILE_ARCH | ERRFILE_IMAGE | 0x000d0000 )
|
||||
#define ERRFILE_ucode ( ERRFILE_ARCH | ERRFILE_IMAGE | 0x000e0000 )
|
||||
|
||||
#define ERRFILE_undi ( ERRFILE_ARCH | ERRFILE_NET | 0x00000000 )
|
||||
#define ERRFILE_undiload ( ERRFILE_ARCH | ERRFILE_NET | 0x00010000 )
|
||||
|
||||
14
src/arch/x86/include/bits/mp.h
Normal file
14
src/arch/x86/include/bits/mp.h
Normal file
@ -0,0 +1,14 @@
|
||||
#ifndef _BITS_MP_H
|
||||
#define _BITS_MP_H
|
||||
|
||||
/** @file
|
||||
*
|
||||
* x86-specific multiprocessor API implementation
|
||||
*
|
||||
*/
|
||||
|
||||
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
|
||||
|
||||
#include <ipxe/bios_mp.h>
|
||||
|
||||
#endif /* _BITS_MP_H */
|
||||
32
src/arch/x86/include/ipxe/bios_mp.h
Normal file
32
src/arch/x86/include/ipxe/bios_mp.h
Normal file
@ -0,0 +1,32 @@
|
||||
#ifndef _IPXE_BIOS_MP_H
|
||||
#define _IPXE_BIOS_MP_H
|
||||
|
||||
/** @file
|
||||
*
|
||||
* BIOS multiprocessor API implementation
|
||||
*
|
||||
*/
|
||||
|
||||
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
|
||||
|
||||
#include <ipxe/io.h>
|
||||
|
||||
#ifdef MPAPI_PCBIOS
|
||||
#define MPAPI_PREFIX_pcbios
|
||||
#else
|
||||
#define MPAPI_PREFIX_pcbios __pcbios_
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Calculate address as seen by a multiprocessor function
|
||||
*
|
||||
* @v address Address in boot processor address space
|
||||
* @ret address Address in application processor address space
|
||||
*/
|
||||
static inline __attribute__ (( always_inline )) mp_addr_t
|
||||
MPAPI_INLINE ( pcbios, mp_address ) ( void *address ) {
|
||||
|
||||
return virt_to_phys ( address );
|
||||
}
|
||||
|
||||
#endif /* _IPXE_BIOS_MP_H */
|
||||
223
src/arch/x86/include/ipxe/ucode.h
Normal file
223
src/arch/x86/include/ipxe/ucode.h
Normal file
@ -0,0 +1,223 @@
|
||||
#ifndef _IPXE_UCODE_H
|
||||
#define _IPXE_UCODE_H
|
||||
|
||||
/** @file
|
||||
*
|
||||
* Microcode updates
|
||||
*
|
||||
*/
|
||||
|
||||
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
|
||||
|
||||
#include <stdint.h>
|
||||
#include <ipxe/mp.h>
|
||||
|
||||
/** Platform ID MSR */
|
||||
#define MSR_PLATFORM_ID 0x00000017UL
|
||||
|
||||
/** Extract platform ID from MSR value */
|
||||
#define MSR_PLATFORM_ID_VALUE( value ) ( ( (value) >> 50 ) & 0x7 )
|
||||
|
||||
/** Intel microcode load trigger MSR */
|
||||
#define MSR_UCODE_TRIGGER_INTEL 0x00000079UL
|
||||
|
||||
/** AMD microcode load trigger MSR */
|
||||
#define MSR_UCODE_TRIGGER_AMD 0xc0010020UL
|
||||
|
||||
/** CPUID signature applicability mask
|
||||
*
|
||||
* We assume that only steppings may vary between the boot CPU and any
|
||||
* application processors.
|
||||
*/
|
||||
#define UCODE_SIGNATURE_MASK 0xfffffff0UL
|
||||
|
||||
/** Minimum possible microcode version */
|
||||
#define UCODE_VERSION_MIN -0x80000000L
|
||||
|
||||
/** Maximum possible microcode version */
|
||||
#define UCODE_VERSION_MAX 0x7fffffffL
|
||||
|
||||
/** A microcode update control
|
||||
*
|
||||
* This must match the layout as used by the assembly code in
|
||||
* ucode_mp.S.
|
||||
*/
|
||||
struct ucode_control {
|
||||
/** Microcode descriptor list physical address */
|
||||
uint64_t desc;
|
||||
/** Microcode status array physical address */
|
||||
uint64_t status;
|
||||
/** Microcode load trigger MSR */
|
||||
uint32_t trigger_msr;
|
||||
/** Maximum expected APIC ID */
|
||||
uint32_t apic_max;
|
||||
/** Unexpected APIC ID
|
||||
*
|
||||
* Any application processor may set this to indicate that its
|
||||
* APIC ID was higher than the maximum expected APIC ID.
|
||||
*/
|
||||
uint32_t apic_unexpected;
|
||||
/** APIC ID eligibility mask bits */
|
||||
uint32_t apic_mask;
|
||||
/** APIC ID eligibility test bits */
|
||||
uint32_t apic_test;
|
||||
/** Microcode version requires manual clear */
|
||||
uint8_t ver_clear;
|
||||
/** Microcode version is reported via high dword */
|
||||
uint8_t ver_high;
|
||||
} __attribute__ (( packed ));
|
||||
|
||||
/** A microcode update descriptor
|
||||
*
|
||||
* This must match the layout as used by the assembly code in
|
||||
* ucode_mp.S.
|
||||
*/
|
||||
struct ucode_descriptor {
|
||||
/** CPUID signature (or 0 to terminate list) */
|
||||
uint32_t signature;
|
||||
/** Microcode version */
|
||||
int32_t version;
|
||||
/** Microcode physical address */
|
||||
uint64_t address;
|
||||
} __attribute__ (( packed ));
|
||||
|
||||
/** A microcode update status report
|
||||
*
|
||||
* This must match the layout as used by the assembly code in
|
||||
* ucode_mp.S.
|
||||
*/
|
||||
struct ucode_status {
|
||||
/** CPU signature */
|
||||
uint32_t signature;
|
||||
/** APIC ID (for sanity checking) */
|
||||
uint32_t id;
|
||||
/** Initial microcode version */
|
||||
int32_t before;
|
||||
/** Final microcode version */
|
||||
int32_t after;
|
||||
} __attribute__ (( packed ));
|
||||
|
||||
/** A microcode date */
|
||||
struct ucode_date {
|
||||
/** Year (BCD) */
|
||||
uint8_t year;
|
||||
/** Century (BCD) */
|
||||
uint8_t century;
|
||||
/** Day (BCD) */
|
||||
uint8_t day;
|
||||
/** Month (BCD) */
|
||||
uint8_t month;
|
||||
} __attribute__ (( packed ));
|
||||
|
||||
/** An Intel microcode update file header */
|
||||
struct intel_ucode_header {
|
||||
/** Header version number */
|
||||
uint32_t hver;
|
||||
/** Microcode version */
|
||||
int32_t version;
|
||||
/** Date */
|
||||
struct ucode_date date;
|
||||
/** CPUID signature */
|
||||
uint32_t signature;
|
||||
/** Checksum */
|
||||
uint32_t checksum;
|
||||
/** Loader version */
|
||||
uint32_t lver;
|
||||
/** Supported platforms */
|
||||
uint32_t platforms;
|
||||
/** Microcode data size (or 0 to indicate 2000 bytes) */
|
||||
uint32_t data_len;
|
||||
/** Total size (or 0 to indicate 2048 bytes) */
|
||||
uint32_t len;
|
||||
/** Reserved */
|
||||
uint8_t reserved[12];
|
||||
} __attribute__ (( packed ));
|
||||
|
||||
/** Intel microcode header version number */
|
||||
#define INTEL_UCODE_HVER 0x00000001UL
|
||||
|
||||
/** Intel microcode loader version number */
|
||||
#define INTEL_UCODE_LVER 0x00000001UL
|
||||
|
||||
/** Intel microcode default data length */
|
||||
#define INTEL_UCODE_DATA_LEN 2000
|
||||
|
||||
/** Intel microcode file alignment */
|
||||
#define INTEL_UCODE_ALIGN 1024
|
||||
|
||||
/** An Intel microcode update file extended header */
|
||||
struct intel_ucode_ext_header {
|
||||
/** Extended signature count */
|
||||
uint32_t count;
|
||||
/** Extended checksum */
|
||||
uint32_t checksum;
|
||||
/** Reserved */
|
||||
uint8_t reserved[12];
|
||||
} __attribute__ (( packed ));
|
||||
|
||||
/** An Intel microcode extended signature */
|
||||
struct intel_ucode_ext {
|
||||
/** CPUID signature */
|
||||
uint32_t signature;
|
||||
/** Supported platforms */
|
||||
uint32_t platforms;
|
||||
/** Checksum */
|
||||
uint32_t checksum;
|
||||
} __attribute__ (( packed ));
|
||||
|
||||
/** An AMD microcode update file header */
|
||||
struct amd_ucode_header {
|
||||
/** Magic signature */
|
||||
uint32_t magic;
|
||||
/** Equivalence table type */
|
||||
uint32_t type;
|
||||
/** Equivalence table length */
|
||||
uint32_t len;
|
||||
} __attribute__ (( packed ));
|
||||
|
||||
/** AMD microcode magic signature */
|
||||
#define AMD_UCODE_MAGIC ( ( 'A' << 16 ) | ( 'M' << 8 ) | ( 'D' << 0 ) )
|
||||
|
||||
/** AMD microcode equivalence table type */
|
||||
#define AMD_UCODE_EQUIV_TYPE 0x00000000UL
|
||||
|
||||
/** An AMD microcode equivalence table entry */
|
||||
struct amd_ucode_equivalence {
|
||||
/** CPU signature */
|
||||
uint32_t signature;
|
||||
/** Reserved */
|
||||
uint8_t reserved_a[8];
|
||||
/** Equivalence ID */
|
||||
uint16_t id;
|
||||
/** Reserved */
|
||||
uint8_t reserved_b[2];
|
||||
} __attribute__ (( packed ));
|
||||
|
||||
/** An AMD microcode patch header */
|
||||
struct amd_ucode_patch_header {
|
||||
/** Patch type */
|
||||
uint32_t type;
|
||||
/** Patch length */
|
||||
uint32_t len;
|
||||
} __attribute__ (( packed ));
|
||||
|
||||
/** An AMD microcode patch */
|
||||
struct amd_ucode_patch {
|
||||
/** Date */
|
||||
struct ucode_date date;
|
||||
/** Microcode version */
|
||||
int32_t version;
|
||||
/** Reserved */
|
||||
uint8_t reserved_a[16];
|
||||
/** Equivalence ID */
|
||||
uint16_t id;
|
||||
/** Reserved */
|
||||
uint8_t reserved_b[14];
|
||||
} __attribute__ (( packed ));
|
||||
|
||||
/** AMD patch type */
|
||||
#define AMD_UCODE_PATCH_TYPE 0x00000001UL
|
||||
|
||||
extern mp_func_t ucode_update;
|
||||
|
||||
#endif /* _IPXE_UCODE_H */
|
||||
@ -474,6 +474,26 @@ extern struct page_table io_pages;
|
||||
*/
|
||||
#define IO_BASE ( ( void * ) 0x100000000ULL )
|
||||
|
||||
/** Startup IPI real-mode handler */
|
||||
extern char __text16_array ( sipi, [] );
|
||||
#define sipi __use_text16 ( sipi )
|
||||
|
||||
/** Length of startup IPI real-mode handler */
|
||||
extern char sipi_len[];
|
||||
|
||||
/** Startup IPI real-mode handler copy of real-mode data segment */
|
||||
extern uint16_t __text16 ( sipi_ds );
|
||||
#define sipi_ds __use_text16 ( sipi_ds )
|
||||
|
||||
/** Startup IPI protected-mode handler (physical address) */
|
||||
extern uint32_t sipi_handler;
|
||||
|
||||
/** Startup IPI register state */
|
||||
extern struct i386_regs sipi_regs;
|
||||
|
||||
extern void setup_sipi ( unsigned int vector, uint32_t handler,
|
||||
struct i386_regs *regs );
|
||||
|
||||
#endif /* ASSEMBLY */
|
||||
|
||||
#endif /* LIBRM_H */
|
||||
|
||||
@ -46,8 +46,12 @@ static void efix86_cpu_nap ( void ) {
|
||||
* The EFI shell doesn't seem to bother sleeping the CPU; it
|
||||
* just sits there idly burning power.
|
||||
*
|
||||
* If a shutdown is in progess, there may be nothing to
|
||||
* generate an interrupt since the timer is disabled in the
|
||||
* first step of ExitBootServices().
|
||||
*/
|
||||
__asm__ __volatile__ ( "hlt" );
|
||||
if ( ! efi_shutdown_in_progress )
|
||||
__asm__ __volatile__ ( "hlt" );
|
||||
}
|
||||
|
||||
PROVIDE_NAP ( efix86, cpu_nap, efix86_cpu_nap );
|
||||
|
||||
173
src/arch/x86/interface/pcbios/bios_mp.c
Normal file
173
src/arch/x86/interface/pcbios/bios_mp.c
Normal file
@ -0,0 +1,173 @@
|
||||
/*
|
||||
* 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
|
||||
*
|
||||
* BIOS multiprocessor API implementation
|
||||
*
|
||||
*/
|
||||
|
||||
#include <registers.h>
|
||||
#include <ipxe/uaccess.h>
|
||||
#include <ipxe/timer.h>
|
||||
#include <ipxe/msr.h>
|
||||
#include <ipxe/mp.h>
|
||||
|
||||
/** Local APIC base address MSR */
|
||||
#define MSR_APIC_BASE 0x0000001b
|
||||
|
||||
/** Local APIC is in x2APIC mode */
|
||||
#define MSR_APIC_BASE_X2APIC 0x400
|
||||
|
||||
/** Local APIC base address mask */
|
||||
#define MSR_APIC_BASE_MASK ( ~0xfffULL )
|
||||
|
||||
/** Interrupt command register */
|
||||
#define APIC_ICR 0x0300
|
||||
|
||||
/** Interrupt command register (x2APIC) */
|
||||
#define MSR_X2APIC_ICR 0x830
|
||||
|
||||
/** Interrupt command register: send to all excluding self */
|
||||
#define APIC_ICR_ALL_NOT_SELF 0x000c0000
|
||||
|
||||
/** Interrupt command register: level mode */
|
||||
#define APIC_ICR_LEVEL 0x00008000
|
||||
|
||||
/** Interrupt command register: level asserted */
|
||||
#define APIC_ICR_LEVEL_ASSERT 0x00004000
|
||||
|
||||
/** Interrupt command register: INIT */
|
||||
#define APIC_ICR_INIT 0x00000500
|
||||
|
||||
/** Interrupt command register: SIPI */
|
||||
#define APIC_ICR_SIPI( vector ) ( 0x00000600 | (vector) )
|
||||
|
||||
/** Time to wait for an IPI to complete */
|
||||
#define IPI_WAIT_MS 10
|
||||
|
||||
/**
|
||||
* Startup IPI vector
|
||||
*
|
||||
* The real-mode startup IPI code must be copied to a page boundary in
|
||||
* base memory. We fairly arbitrarily choose to place this at 0x8000.
|
||||
*/
|
||||
#define SIPI_VECTOR 0x08
|
||||
|
||||
/** Protected-mode startup IPI handler */
|
||||
extern void __asmcall mp_jump ( mp_addr_t func, mp_addr_t opaque );
|
||||
|
||||
/**
|
||||
* Execute a multiprocessor function on the boot processor
|
||||
*
|
||||
* @v func Multiprocessor function
|
||||
* @v opaque Opaque data pointer
|
||||
*/
|
||||
static void bios_mp_exec_boot ( mp_func_t func, void *opaque ) {
|
||||
|
||||
/* Call multiprocessor function with physical addressing */
|
||||
__asm__ __volatile__ ( PHYS_CODE ( "pushl %k2\n\t"
|
||||
"pushl %k1\n\t"
|
||||
"call *%k0\n\t"
|
||||
"addl $8, %%esp\n\t" )
|
||||
: : "r" ( mp_address ( mp_call ) ),
|
||||
"r" ( mp_address ( func ) ),
|
||||
"r" ( mp_address ( opaque ) ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Send an interprocessor interrupt
|
||||
*
|
||||
* @v apic APIC base address
|
||||
* @v x2apic x2APIC mode enabled
|
||||
* @v icr Interrupt control register value
|
||||
*/
|
||||
static void bios_mp_ipi ( void *apic, int x2apic, uint32_t icr ) {
|
||||
|
||||
/* Write ICR according to APIC/x2APIC mode */
|
||||
DBGC ( MSR_APIC_BASE, "BIOSMP sending IPI %#08x\n", icr );
|
||||
if ( x2apic ) {
|
||||
wrmsr ( MSR_X2APIC_ICR, icr );
|
||||
} else {
|
||||
writel ( icr, ( apic + APIC_ICR ) );
|
||||
}
|
||||
|
||||
/* Allow plenty of time for delivery to complete */
|
||||
mdelay ( IPI_WAIT_MS );
|
||||
}
|
||||
|
||||
/**
|
||||
* Start a multiprocessor function on all application processors
|
||||
*
|
||||
* @v func Multiprocessor function
|
||||
* @v opaque Opaque data pointer
|
||||
*/
|
||||
static void bios_mp_start_all ( mp_func_t func, void *opaque ) {
|
||||
struct i386_regs regs;
|
||||
uint64_t base;
|
||||
uint32_t ipi;
|
||||
void *apic;
|
||||
int x2apic;
|
||||
|
||||
/* Prepare SIPI handler */
|
||||
regs.eax = mp_address ( func );
|
||||
regs.edx = mp_address ( opaque );
|
||||
setup_sipi ( SIPI_VECTOR, virt_to_phys ( mp_jump ), ®s );
|
||||
|
||||
/* Get local APIC base address and mode */
|
||||
base = rdmsr ( MSR_APIC_BASE );
|
||||
x2apic = ( base & MSR_APIC_BASE_X2APIC );
|
||||
DBGC ( MSR_APIC_BASE, "BIOSMP local %sAPIC base %#llx\n",
|
||||
( x2apic ? "x2" : "" ), ( ( unsigned long long ) base ) );
|
||||
|
||||
/* Map local APIC */
|
||||
apic = ioremap ( ( base & MSR_APIC_BASE_MASK ), PAGE_SIZE );
|
||||
if ( ! apic )
|
||||
goto err_ioremap;
|
||||
|
||||
/* Assert INIT IPI */
|
||||
ipi = ( APIC_ICR_ALL_NOT_SELF | APIC_ICR_LEVEL |
|
||||
APIC_ICR_LEVEL_ASSERT | APIC_ICR_INIT );
|
||||
bios_mp_ipi ( apic, x2apic, ipi );
|
||||
|
||||
/* Clear INIT IPI */
|
||||
ipi &= ~APIC_ICR_LEVEL_ASSERT;
|
||||
bios_mp_ipi ( apic, x2apic, ipi );
|
||||
|
||||
/* Send SIPI */
|
||||
ipi = ( APIC_ICR_ALL_NOT_SELF | APIC_ICR_SIPI ( SIPI_VECTOR ) );
|
||||
bios_mp_ipi ( apic, x2apic, ipi );
|
||||
|
||||
iounmap ( apic );
|
||||
err_ioremap:
|
||||
/* No way to handle errors: caller must check that
|
||||
* multiprocessor function executed as expected.
|
||||
*/
|
||||
return;
|
||||
}
|
||||
|
||||
PROVIDE_MPAPI_INLINE ( pcbios, mp_address );
|
||||
PROVIDE_MPAPI ( pcbios, mp_exec_boot, bios_mp_exec_boot );
|
||||
PROVIDE_MPAPI ( pcbios, mp_start_all, bios_mp_start_all );
|
||||
@ -24,9 +24,8 @@
|
||||
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL )
|
||||
|
||||
.section ".note.GNU-stack", "", @progbits
|
||||
.text
|
||||
.arch i386
|
||||
.code16
|
||||
.arch i386
|
||||
|
||||
#define SMAP 0x534d4150
|
||||
|
||||
|
||||
@ -183,8 +183,8 @@ static int int13_parse_eltorito ( struct san_device *sandev, void *scratch ) {
|
||||
/* Read boot record volume descriptor */
|
||||
if ( ( rc = sandev_read ( sandev, ELTORITO_LBA, 1,
|
||||
virt_to_user ( boot ) ) ) != 0 ) {
|
||||
DBGC ( sandev, "INT13 drive %02x could not read El Torito boot "
|
||||
"record volume descriptor: %s\n",
|
||||
DBGC ( sandev->drive, "INT13 drive %02x could not read El "
|
||||
"Torito boot record volume descriptor: %s\n",
|
||||
sandev->drive, strerror ( rc ) );
|
||||
return rc;
|
||||
}
|
||||
@ -192,10 +192,11 @@ static int int13_parse_eltorito ( struct san_device *sandev, void *scratch ) {
|
||||
/* Check for an El Torito boot catalog */
|
||||
if ( memcmp ( boot, &boot_check, sizeof ( boot_check ) ) == 0 ) {
|
||||
int13->boot_catalog = boot->sector;
|
||||
DBGC ( sandev, "INT13 drive %02x has an El Torito boot catalog "
|
||||
"at LBA %08x\n", sandev->drive, int13->boot_catalog );
|
||||
DBGC ( sandev->drive, "INT13 drive %02x has an El Torito boot "
|
||||
"catalog at LBA %08x\n", sandev->drive,
|
||||
int13->boot_catalog );
|
||||
} else {
|
||||
DBGC ( sandev, "INT13 drive %02x has no El Torito boot "
|
||||
DBGC ( sandev->drive, "INT13 drive %02x has no El Torito boot "
|
||||
"catalog\n", sandev->drive );
|
||||
}
|
||||
|
||||
@ -228,14 +229,14 @@ static int int13_guess_geometry_hdd ( struct san_device *sandev, void *scratch,
|
||||
|
||||
/* Read partition table */
|
||||
if ( ( rc = sandev_read ( sandev, 0, 1, virt_to_user ( mbr ) ) ) != 0 ) {
|
||||
DBGC ( sandev, "INT13 drive %02x could not read "
|
||||
DBGC ( sandev->drive, "INT13 drive %02x could not read "
|
||||
"partition table to guess geometry: %s\n",
|
||||
sandev->drive, strerror ( rc ) );
|
||||
return rc;
|
||||
}
|
||||
DBGC2 ( sandev, "INT13 drive %02x has MBR:\n", sandev->drive );
|
||||
DBGC2_HDA ( sandev, 0, mbr, sizeof ( *mbr ) );
|
||||
DBGC ( sandev, "INT13 drive %02x has signature %08x\n",
|
||||
DBGC2 ( sandev->drive, "INT13 drive %02x has MBR:\n", sandev->drive );
|
||||
DBGC2_HDA ( sandev->drive, 0, mbr, sizeof ( *mbr ) );
|
||||
DBGC ( sandev->drive, "INT13 drive %02x has signature %08x\n",
|
||||
sandev->drive, mbr->signature );
|
||||
|
||||
/* Scan through partition table and modify guesses for
|
||||
@ -260,8 +261,8 @@ static int int13_guess_geometry_hdd ( struct san_device *sandev, void *scratch,
|
||||
if ( ( start_cylinder == 0 ) && ( start_head != 0 ) ) {
|
||||
*sectors = ( ( partition->start + 1 - start_sector ) /
|
||||
start_head );
|
||||
DBGC ( sandev, "INT13 drive %02x guessing C/H/S "
|
||||
"xx/xx/%d based on partition %d\n",
|
||||
DBGC ( sandev->drive, "INT13 drive %02x guessing "
|
||||
"C/H/S xx/xx/%d based on partition %d\n",
|
||||
sandev->drive, *sectors, ( i + 1 ) );
|
||||
}
|
||||
|
||||
@ -272,14 +273,14 @@ static int int13_guess_geometry_hdd ( struct san_device *sandev, void *scratch,
|
||||
end_sector = PART_SECTOR ( partition->chs_end );
|
||||
if ( ( end_head + 1 ) > *heads ) {
|
||||
*heads = ( end_head + 1 );
|
||||
DBGC ( sandev, "INT13 drive %02x guessing C/H/S "
|
||||
"xx/%d/xx based on partition %d\n",
|
||||
DBGC ( sandev->drive, "INT13 drive %02x guessing "
|
||||
"C/H/S xx/%d/xx based on partition %d\n",
|
||||
sandev->drive, *heads, ( i + 1 ) );
|
||||
}
|
||||
if ( end_sector > *sectors ) {
|
||||
*sectors = end_sector;
|
||||
DBGC ( sandev, "INT13 drive %02x guessing C/H/S "
|
||||
"xx/xx/%d based on partition %d\n",
|
||||
DBGC ( sandev->drive, "INT13 drive %02x guessing "
|
||||
"C/H/S xx/xx/%d based on partition %d\n",
|
||||
sandev->drive, *sectors, ( i + 1 ) );
|
||||
}
|
||||
}
|
||||
@ -343,9 +344,10 @@ static int int13_guess_geometry_fdd ( struct san_device *sandev,
|
||||
*heads = INT13_FDD_HEADS ( geometry );
|
||||
*sectors = INT13_FDD_SECTORS ( geometry );
|
||||
if ( ( cylinders * (*heads) * (*sectors) ) == blocks ) {
|
||||
DBGC ( sandev, "INT13 drive %02x guessing C/H/S "
|
||||
"%d/%d/%d based on size %dK\n", sandev->drive,
|
||||
cylinders, *heads, *sectors, ( blocks / 2 ) );
|
||||
DBGC ( sandev->drive, "INT13 drive %02x guessing "
|
||||
"C/H/S %d/%d/%d based on size %dK\n",
|
||||
sandev->drive, cylinders, *heads, *sectors,
|
||||
( blocks / 2 ) );
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
@ -355,8 +357,9 @@ static int int13_guess_geometry_fdd ( struct san_device *sandev,
|
||||
*/
|
||||
*heads = 2;
|
||||
*sectors = 18;
|
||||
DBGC ( sandev, "INT13 drive %02x guessing C/H/S xx/%d/%d based on size "
|
||||
"%dK\n", sandev->drive, *heads, *sectors, ( blocks / 2 ) );
|
||||
DBGC ( sandev->drive, "INT13 drive %02x guessing C/H/S xx/%d/%d "
|
||||
"based on size %dK\n", sandev->drive, *heads, *sectors,
|
||||
( blocks / 2 ) );
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -431,8 +434,8 @@ static void int13_sync_num_drives ( void ) {
|
||||
required = ( ( max_drive & 0x7f ) + 1 );
|
||||
if ( *counter < required ) {
|
||||
*counter = required;
|
||||
DBGC ( sandev, "INT13 drive %02x added to drive count: "
|
||||
"%d HDDs, %d FDDs\n",
|
||||
DBGC ( sandev->drive, "INT13 drive %02x added to "
|
||||
"drive count: %d HDDs, %d FDDs\n",
|
||||
sandev->drive, num_drives, num_fdds );
|
||||
}
|
||||
}
|
||||
@ -472,7 +475,7 @@ static int int13_reset ( struct san_device *sandev,
|
||||
struct i386_all_regs *ix86 __unused ) {
|
||||
int rc;
|
||||
|
||||
DBGC2 ( sandev, "Reset drive\n" );
|
||||
DBGC2 ( sandev->drive, "Reset drive\n" );
|
||||
|
||||
/* Reset SAN device */
|
||||
if ( ( rc = sandev_reset ( sandev ) ) != 0 )
|
||||
@ -491,7 +494,7 @@ static int int13_get_last_status ( struct san_device *sandev,
|
||||
struct i386_all_regs *ix86 __unused ) {
|
||||
struct int13_data *int13 = sandev->priv;
|
||||
|
||||
DBGC2 ( sandev, "Get status of last operation\n" );
|
||||
DBGC2 ( sandev->drive, "Get status of last operation\n" );
|
||||
return int13->last_status;
|
||||
}
|
||||
|
||||
@ -524,8 +527,8 @@ static int int13_rw_sectors ( struct san_device *sandev,
|
||||
|
||||
/* Validate blocksize */
|
||||
if ( sandev_blksize ( sandev ) != INT13_BLKSIZE ) {
|
||||
DBGC ( sandev, "\nINT 13 drive %02x invalid blocksize (%zd) "
|
||||
"for non-extended read/write\n",
|
||||
DBGC ( sandev->drive, "\nINT 13 drive %02x invalid blocksize "
|
||||
"(%zd) for non-extended read/write\n",
|
||||
sandev->drive, sandev_blksize ( sandev ) );
|
||||
return -INT13_STATUS_INVALID;
|
||||
}
|
||||
@ -537,9 +540,10 @@ static int int13_rw_sectors ( struct san_device *sandev,
|
||||
if ( ( cylinder >= int13->cylinders ) ||
|
||||
( head >= int13->heads ) ||
|
||||
( sector < 1 ) || ( sector > int13->sectors_per_track ) ) {
|
||||
DBGC ( sandev, "C/H/S %d/%d/%d out of range for geometry "
|
||||
"%d/%d/%d\n", cylinder, head, sector, int13->cylinders,
|
||||
int13->heads, int13->sectors_per_track );
|
||||
DBGC ( sandev->drive, "C/H/S %d/%d/%d out of range for "
|
||||
"geometry %d/%d/%d\n", cylinder, head, sector,
|
||||
int13->cylinders, int13->heads,
|
||||
int13->sectors_per_track );
|
||||
return -INT13_STATUS_INVALID;
|
||||
}
|
||||
lba = ( ( ( ( cylinder * int13->heads ) + head )
|
||||
@ -547,13 +551,13 @@ static int int13_rw_sectors ( struct san_device *sandev,
|
||||
count = ix86->regs.al;
|
||||
buffer = real_to_user ( ix86->segs.es, ix86->regs.bx );
|
||||
|
||||
DBGC2 ( sandev, "C/H/S %d/%d/%d = LBA %08lx <-> %04x:%04x (count %d)\n",
|
||||
cylinder, head, sector, lba, ix86->segs.es, ix86->regs.bx,
|
||||
count );
|
||||
DBGC2 ( sandev->drive, "C/H/S %d/%d/%d = LBA %08lx <-> %04x:%04x "
|
||||
"(count %d)\n", cylinder, head, sector, lba, ix86->segs.es,
|
||||
ix86->regs.bx, count );
|
||||
|
||||
/* Read from / write to block device */
|
||||
if ( ( rc = sandev_rw ( sandev, lba, count, buffer ) ) != 0 ){
|
||||
DBGC ( sandev, "INT13 drive %02x I/O failed: %s\n",
|
||||
DBGC ( sandev->drive, "INT13 drive %02x I/O failed: %s\n",
|
||||
sandev->drive, strerror ( rc ) );
|
||||
return -INT13_STATUS_READ_ERROR;
|
||||
}
|
||||
@ -577,7 +581,7 @@ static int int13_rw_sectors ( struct san_device *sandev,
|
||||
static int int13_read_sectors ( struct san_device *sandev,
|
||||
struct i386_all_regs *ix86 ) {
|
||||
|
||||
DBGC2 ( sandev, "Read: " );
|
||||
DBGC2 ( sandev->drive, "Read: " );
|
||||
return int13_rw_sectors ( sandev, ix86, sandev_read );
|
||||
}
|
||||
|
||||
@ -597,7 +601,7 @@ static int int13_read_sectors ( struct san_device *sandev,
|
||||
static int int13_write_sectors ( struct san_device *sandev,
|
||||
struct i386_all_regs *ix86 ) {
|
||||
|
||||
DBGC2 ( sandev, "Write: " );
|
||||
DBGC2 ( sandev->drive, "Write: " );
|
||||
return int13_rw_sectors ( sandev, ix86, sandev_write );
|
||||
}
|
||||
|
||||
@ -619,12 +623,12 @@ static int int13_get_parameters ( struct san_device *sandev,
|
||||
unsigned int max_head = int13->heads - 1;
|
||||
unsigned int max_sector = int13->sectors_per_track; /* sic */
|
||||
|
||||
DBGC2 ( sandev, "Get drive parameters\n" );
|
||||
DBGC2 ( sandev->drive, "Get drive parameters\n" );
|
||||
|
||||
/* Validate blocksize */
|
||||
if ( sandev_blksize ( sandev ) != INT13_BLKSIZE ) {
|
||||
DBGC ( sandev, "\nINT 13 drive %02x invalid blocksize (%zd) "
|
||||
"for non-extended parameters\n",
|
||||
DBGC ( sandev->drive, "\nINT 13 drive %02x invalid blocksize "
|
||||
"(%zd) for non-extended parameters\n",
|
||||
sandev->drive, sandev_blksize ( sandev ) );
|
||||
return -INT13_STATUS_INVALID;
|
||||
}
|
||||
@ -657,7 +661,7 @@ static int int13_get_disk_type ( struct san_device *sandev,
|
||||
struct i386_all_regs *ix86 ) {
|
||||
uint32_t blocks;
|
||||
|
||||
DBGC2 ( sandev, "Get disk type\n" );
|
||||
DBGC2 ( sandev->drive, "Get disk type\n" );
|
||||
|
||||
if ( int13_is_fdd ( sandev ) ) {
|
||||
return INT13_DISK_TYPE_FDD;
|
||||
@ -682,7 +686,7 @@ static int int13_extension_check ( struct san_device *sandev,
|
||||
struct i386_all_regs *ix86 ) {
|
||||
|
||||
if ( ( ix86->regs.bx == 0x55aa ) && ! int13_is_fdd ( sandev ) ) {
|
||||
DBGC2 ( sandev, "INT13 extensions installation check\n" );
|
||||
DBGC2 ( sandev->drive, "INT13 extensions check\n" );
|
||||
ix86->regs.bx = 0xaa55;
|
||||
ix86->regs.cx = ( INT13_EXTENSION_LINEAR |
|
||||
INT13_EXTENSION_EDD |
|
||||
@ -725,7 +729,8 @@ static int int13_extended_rw ( struct san_device *sandev,
|
||||
get_real ( bufsize, ix86->segs.ds,
|
||||
( ix86->regs.si + offsetof ( typeof ( addr ), bufsize ) ) );
|
||||
if ( bufsize < offsetof ( typeof ( addr ), buffer_phys ) ) {
|
||||
DBGC2 ( sandev, "<invalid buffer size %#02x\n>\n", bufsize );
|
||||
DBGC2 ( sandev->drive, "<invalid buffer size %#02x\n>\n",
|
||||
bufsize );
|
||||
return -INT13_STATUS_INVALID;
|
||||
}
|
||||
|
||||
@ -733,17 +738,18 @@ static int int13_extended_rw ( struct san_device *sandev,
|
||||
memset ( &addr, 0, sizeof ( addr ) );
|
||||
copy_from_real ( &addr, ix86->segs.ds, ix86->regs.si, bufsize );
|
||||
lba = addr.lba;
|
||||
DBGC2 ( sandev, "LBA %08llx <-> ", ( ( unsigned long long ) lba ) );
|
||||
DBGC2 ( sandev->drive, "LBA %08llx <-> ",
|
||||
( ( unsigned long long ) lba ) );
|
||||
if ( ( addr.count == 0xff ) ||
|
||||
( ( addr.buffer.segment == 0xffff ) &&
|
||||
( addr.buffer.offset == 0xffff ) ) ) {
|
||||
buffer = phys_to_user ( addr.buffer_phys );
|
||||
DBGC2 ( sandev, "%08llx",
|
||||
DBGC2 ( sandev->drive, "%08llx",
|
||||
( ( unsigned long long ) addr.buffer_phys ) );
|
||||
} else {
|
||||
buffer = real_to_user ( addr.buffer.segment,
|
||||
addr.buffer.offset );
|
||||
DBGC2 ( sandev, "%04x:%04x", addr.buffer.segment,
|
||||
DBGC2 ( sandev->drive, "%04x:%04x", addr.buffer.segment,
|
||||
addr.buffer.offset );
|
||||
}
|
||||
if ( addr.count <= 0x7f ) {
|
||||
@ -751,15 +757,15 @@ static int int13_extended_rw ( struct san_device *sandev,
|
||||
} else if ( addr.count == 0xff ) {
|
||||
count = addr.long_count;
|
||||
} else {
|
||||
DBGC2 ( sandev, " <invalid count %#02x>\n", addr.count );
|
||||
DBGC2 ( sandev->drive, " <invalid count %#02x>\n", addr.count );
|
||||
return -INT13_STATUS_INVALID;
|
||||
}
|
||||
DBGC2 ( sandev, " (count %ld)\n", count );
|
||||
DBGC2 ( sandev->drive, " (count %ld)\n", count );
|
||||
|
||||
/* Read from / write to block device */
|
||||
if ( ( rc = sandev_rw ( sandev, lba, count, buffer ) ) != 0 ) {
|
||||
DBGC ( sandev, "INT13 drive %02x extended I/O failed: %s\n",
|
||||
sandev->drive, strerror ( rc ) );
|
||||
DBGC ( sandev->drive, "INT13 drive %02x extended I/O failed: "
|
||||
"%s\n", sandev->drive, strerror ( rc ) );
|
||||
/* Record that no blocks were transferred successfully */
|
||||
addr.count = 0;
|
||||
put_real ( addr.count, ix86->segs.ds,
|
||||
@ -781,7 +787,7 @@ static int int13_extended_rw ( struct san_device *sandev,
|
||||
static int int13_extended_read ( struct san_device *sandev,
|
||||
struct i386_all_regs *ix86 ) {
|
||||
|
||||
DBGC2 ( sandev, "Extended read: " );
|
||||
DBGC2 ( sandev->drive, "Extended read: " );
|
||||
return int13_extended_rw ( sandev, ix86, sandev_read );
|
||||
}
|
||||
|
||||
@ -795,7 +801,7 @@ static int int13_extended_read ( struct san_device *sandev,
|
||||
static int int13_extended_write ( struct san_device *sandev,
|
||||
struct i386_all_regs *ix86 ) {
|
||||
|
||||
DBGC2 ( sandev, "Extended write: " );
|
||||
DBGC2 ( sandev->drive, "Extended write: " );
|
||||
return int13_extended_rw ( sandev, ix86, sandev_write );
|
||||
}
|
||||
|
||||
@ -818,7 +824,7 @@ static int int13_extended_verify ( struct san_device *sandev,
|
||||
sizeof ( addr ));
|
||||
lba = addr.lba;
|
||||
count = addr.count;
|
||||
DBGC2 ( sandev, "Verify: LBA %08llx (count %ld)\n",
|
||||
DBGC2 ( sandev->drive, "Verify: LBA %08llx (count %ld)\n",
|
||||
( ( unsigned long long ) lba ), count );
|
||||
}
|
||||
|
||||
@ -845,7 +851,7 @@ static int int13_extended_seek ( struct san_device *sandev,
|
||||
sizeof ( addr ));
|
||||
lba = addr.lba;
|
||||
count = addr.count;
|
||||
DBGC2 ( sandev, "Seek: LBA %08llx (count %ld)\n",
|
||||
DBGC2 ( sandev->drive, "Seek: LBA %08llx (count %ld)\n",
|
||||
( ( unsigned long long ) lba ), count );
|
||||
}
|
||||
|
||||
@ -879,8 +885,8 @@ static int int13_device_path_info ( struct san_device *sandev,
|
||||
/* Get underlying hardware device */
|
||||
device = identify_device ( &sanpath->block );
|
||||
if ( ! device ) {
|
||||
DBGC ( sandev, "INT13 drive %02x cannot identify hardware "
|
||||
"device\n", sandev->drive );
|
||||
DBGC ( sandev->drive, "INT13 drive %02x cannot identify "
|
||||
"hardware device\n", sandev->drive );
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
@ -895,16 +901,16 @@ static int int13_device_path_info ( struct san_device *sandev,
|
||||
dpi->interface_path.pci.channel = 0xff; /* unused */
|
||||
break;
|
||||
default:
|
||||
DBGC ( sandev, "INT13 drive %02x unrecognised bus type %d\n",
|
||||
sandev->drive, desc->bus_type );
|
||||
DBGC ( sandev->drive, "INT13 drive %02x unrecognised bus "
|
||||
"type %d\n", sandev->drive, desc->bus_type );
|
||||
return -ENOTSUP;
|
||||
}
|
||||
|
||||
/* Get EDD block device description */
|
||||
if ( ( rc = edd_describe ( &sanpath->block, &dpi->interface_type,
|
||||
&dpi->device_path ) ) != 0 ) {
|
||||
DBGC ( sandev, "INT13 drive %02x cannot identify block device: "
|
||||
"%s\n", sandev->drive, strerror ( rc ) );
|
||||
DBGC ( sandev->drive, "INT13 drive %02x cannot identify "
|
||||
"block device: %s\n", sandev->drive, strerror ( rc ) );
|
||||
return rc;
|
||||
}
|
||||
|
||||
@ -938,8 +944,8 @@ static int int13_get_extended_parameters ( struct san_device *sandev,
|
||||
get_real ( bufsize, ix86->segs.ds,
|
||||
( ix86->regs.si + offsetof ( typeof ( params ), bufsize )));
|
||||
|
||||
DBGC2 ( sandev, "Get extended drive parameters to %04x:%04x+%02x\n",
|
||||
ix86->segs.ds, ix86->regs.si, bufsize );
|
||||
DBGC2 ( sandev->drive, "Get extended drive parameters to "
|
||||
"%04x:%04x+%02x\n", ix86->segs.ds, ix86->regs.si, bufsize );
|
||||
|
||||
/* Build drive parameters */
|
||||
memset ( ¶ms, 0, sizeof ( params ) );
|
||||
@ -955,8 +961,8 @@ static int int13_get_extended_parameters ( struct san_device *sandev,
|
||||
params.sector_size = sandev_blksize ( sandev );
|
||||
memset ( ¶ms.dpte, 0xff, sizeof ( params.dpte ) );
|
||||
if ( ( rc = int13_device_path_info ( sandev, ¶ms.dpi ) ) != 0 ) {
|
||||
DBGC ( sandev, "INT13 drive %02x could not provide device "
|
||||
"path information: %s\n",
|
||||
DBGC ( sandev->drive, "INT13 drive %02x could not provide "
|
||||
"device path information: %s\n",
|
||||
sandev->drive, strerror ( rc ) );
|
||||
len = offsetof ( typeof ( params ), dpi );
|
||||
}
|
||||
@ -973,11 +979,11 @@ static int int13_get_extended_parameters ( struct san_device *sandev,
|
||||
params.bufsize = offsetof ( typeof ( params ), dpi );
|
||||
}
|
||||
|
||||
DBGC ( sandev, "INT 13 drive %02x described using extended "
|
||||
DBGC ( sandev->drive, "INT 13 drive %02x described using extended "
|
||||
"parameters:\n", sandev->drive );
|
||||
address.segment = ix86->segs.ds;
|
||||
address.offset = ix86->regs.si;
|
||||
DBGC_HDA ( sandev, address, ¶ms, len );
|
||||
DBGC_HDA ( sandev->drive, address, ¶ms, len );
|
||||
|
||||
/* Return drive parameters */
|
||||
if ( len > bufsize )
|
||||
@ -998,13 +1004,13 @@ static int int13_cdrom_status_terminate ( struct san_device *sandev,
|
||||
struct i386_all_regs *ix86 ) {
|
||||
struct int13_cdrom_specification specification;
|
||||
|
||||
DBGC2 ( sandev, "Get CD-ROM emulation status to %04x:%04x%s\n",
|
||||
DBGC2 ( sandev->drive, "Get CD-ROM emulation status to %04x:%04x%s\n",
|
||||
ix86->segs.ds, ix86->regs.si,
|
||||
( ix86->regs.al ? "" : " and terminate" ) );
|
||||
|
||||
/* Fail if we are not a CD-ROM */
|
||||
if ( ! sandev->is_cdrom ) {
|
||||
DBGC ( sandev, "INT13 drive %02x is not a CD-ROM\n",
|
||||
DBGC ( sandev->drive, "INT13 drive %02x is not a CD-ROM\n",
|
||||
sandev->drive );
|
||||
return -INT13_STATUS_INVALID;
|
||||
}
|
||||
@ -1039,11 +1045,12 @@ static int int13_cdrom_read_boot_catalog ( struct san_device *sandev,
|
||||
/* Read parameters from command packet */
|
||||
copy_from_real ( &command, ix86->segs.ds, ix86->regs.si,
|
||||
sizeof ( command ) );
|
||||
DBGC2 ( sandev, "Read CD-ROM boot catalog to %08x\n", command.buffer );
|
||||
DBGC2 ( sandev->drive, "Read CD-ROM boot catalog to %08x\n",
|
||||
command.buffer );
|
||||
|
||||
/* Fail if we have no boot catalog */
|
||||
if ( ! int13->boot_catalog ) {
|
||||
DBGC ( sandev, "INT13 drive %02x has no boot catalog\n",
|
||||
DBGC ( sandev->drive, "INT13 drive %02x has no boot catalog\n",
|
||||
sandev->drive );
|
||||
return -INT13_STATUS_INVALID;
|
||||
}
|
||||
@ -1052,8 +1059,8 @@ static int int13_cdrom_read_boot_catalog ( struct san_device *sandev,
|
||||
/* Read from boot catalog */
|
||||
if ( ( rc = sandev_read ( sandev, start, command.count,
|
||||
phys_to_user ( command.buffer ) ) ) != 0 ) {
|
||||
DBGC ( sandev, "INT13 drive %02x could not read boot catalog: "
|
||||
"%s\n", sandev->drive, strerror ( rc ) );
|
||||
DBGC ( sandev->drive, "INT13 drive %02x could not read boot "
|
||||
"catalog: %s\n", sandev->drive, strerror ( rc ) );
|
||||
return -INT13_STATUS_READ_ERROR;
|
||||
}
|
||||
|
||||
@ -1080,8 +1087,8 @@ static __asmcall __used void int13 ( struct i386_all_regs *ix86 ) {
|
||||
if ( bios_drive != sandev->drive ) {
|
||||
/* Remap any accesses to this drive's natural number */
|
||||
if ( bios_drive == int13->natural_drive ) {
|
||||
DBGC2 ( sandev, "INT13,%02x (%02x) remapped to "
|
||||
"(%02x)\n", ix86->regs.ah,
|
||||
DBGC2 ( sandev->drive, "INT13,%02x (%02x) "
|
||||
"remapped to (%02x)\n", ix86->regs.ah,
|
||||
bios_drive, sandev->drive );
|
||||
ix86->regs.dl = sandev->drive;
|
||||
return;
|
||||
@ -1094,7 +1101,7 @@ static __asmcall __used void int13 ( struct i386_all_regs *ix86 ) {
|
||||
}
|
||||
}
|
||||
|
||||
DBGC2 ( sandev, "INT13,%02x (%02x): ",
|
||||
DBGC2 ( sandev->drive, "INT13,%02x (%02x): ",
|
||||
ix86->regs.ah, bios_drive );
|
||||
|
||||
switch ( command ) {
|
||||
@ -1141,7 +1148,7 @@ static __asmcall __used void int13 ( struct i386_all_regs *ix86 ) {
|
||||
status = int13_cdrom_read_boot_catalog ( sandev, ix86 );
|
||||
break;
|
||||
default:
|
||||
DBGC2 ( sandev, "*** Unrecognised INT13 ***\n" );
|
||||
DBGC2 ( sandev->drive, "*** Unrecognised INT13 ***\n" );
|
||||
status = -INT13_STATUS_INVALID;
|
||||
break;
|
||||
}
|
||||
@ -1152,8 +1159,9 @@ static __asmcall __used void int13 ( struct i386_all_regs *ix86 ) {
|
||||
/* Negative status indicates an error */
|
||||
if ( status < 0 ) {
|
||||
status = -status;
|
||||
DBGC ( sandev, "INT13,%02x (%02x) failed with status "
|
||||
"%02x\n", ix86->regs.ah, sandev->drive, status );
|
||||
DBGC ( sandev->drive, "INT13,%02x (%02x) failed with "
|
||||
"status %02x\n", ix86->regs.ah, sandev->drive,
|
||||
status );
|
||||
} else {
|
||||
ix86->flags &= ~CF;
|
||||
}
|
||||
@ -1269,7 +1277,7 @@ static int int13_hook ( unsigned int drive, struct uri **uris,
|
||||
|
||||
/* Register SAN device */
|
||||
if ( ( rc = register_sandev ( sandev, drive, flags ) ) != 0 ) {
|
||||
DBGC ( sandev, "INT13 drive %02x could not register: %s\n",
|
||||
DBGC ( drive, "INT13 drive %02x could not register: %s\n",
|
||||
drive, strerror ( rc ) );
|
||||
goto err_register;
|
||||
}
|
||||
@ -1289,10 +1297,9 @@ static int int13_hook ( unsigned int drive, struct uri **uris,
|
||||
( ( rc = int13_guess_geometry ( sandev, scratch ) ) != 0 ) )
|
||||
goto err_guess_geometry;
|
||||
|
||||
DBGC ( sandev, "INT13 drive %02x (naturally %02x) registered with "
|
||||
"C/H/S geometry %d/%d/%d\n",
|
||||
sandev->drive, int13->natural_drive, int13->cylinders,
|
||||
int13->heads, int13->sectors_per_track );
|
||||
DBGC ( drive, "INT13 drive %02x (naturally %02x) registered with "
|
||||
"C/H/S geometry %d/%d/%d\n", drive, int13->natural_drive,
|
||||
int13->cylinders, int13->heads, int13->sectors_per_track );
|
||||
|
||||
/* Hook INT 13 vector if not already hooked */
|
||||
if ( need_hook ) {
|
||||
@ -1332,7 +1339,7 @@ static void int13_unhook ( unsigned int drive ) {
|
||||
/* Find drive */
|
||||
sandev = sandev_find ( drive );
|
||||
if ( ! sandev ) {
|
||||
DBG ( "INT13 cannot find drive %02x\n", drive );
|
||||
DBGC ( drive, "INT13 drive %02x is not a SAN drive\n", drive );
|
||||
return;
|
||||
}
|
||||
|
||||
@ -1343,7 +1350,7 @@ static void int13_unhook ( unsigned int drive ) {
|
||||
* to do so reliably.
|
||||
*/
|
||||
|
||||
DBGC ( sandev, "INT13 drive %02x unregistered\n", sandev->drive );
|
||||
DBGC ( drive, "INT13 drive %02x unregistered\n", drive );
|
||||
|
||||
/* Unhook INT 13 vector if no more drives */
|
||||
if ( ! have_sandevs() ) {
|
||||
@ -1387,8 +1394,8 @@ static int int13_load_mbr ( unsigned int drive, struct segoff *address ) {
|
||||
: "a" ( 0x0201 ), "b" ( *address ),
|
||||
"c" ( 1 ), "d" ( drive ) );
|
||||
if ( status ) {
|
||||
DBG ( "INT13 drive %02x could not read MBR (status %04x)\n",
|
||||
drive, status );
|
||||
DBGC ( drive, "INT13 drive %02x could not read MBR (status "
|
||||
"%04x)\n", drive, status );
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
@ -1397,8 +1404,8 @@ static int int13_load_mbr ( unsigned int drive, struct segoff *address ) {
|
||||
( address->offset +
|
||||
offsetof ( struct master_boot_record, magic ) ) );
|
||||
if ( magic != INT13_MBR_MAGIC ) {
|
||||
DBG ( "INT13 drive %02x does not contain a valid MBR\n",
|
||||
drive );
|
||||
DBGC ( drive, "INT13 drive %02x does not contain a valid MBR\n",
|
||||
drive );
|
||||
return -ENOEXEC;
|
||||
}
|
||||
|
||||
@ -1444,8 +1451,8 @@ static int int13_load_eltorito ( unsigned int drive, struct segoff *address ) {
|
||||
: "a" ( 0x4d00 ), "d" ( drive ),
|
||||
"S" ( __from_data16 ( &eltorito_cmd ) ) );
|
||||
if ( status ) {
|
||||
DBG ( "INT13 drive %02x could not read El Torito boot catalog "
|
||||
"(status %04x)\n", drive, status );
|
||||
DBGC ( drive, "INT13 drive %02x could not read El Torito boot "
|
||||
"catalog (status %04x)\n", drive, status );
|
||||
return -EIO;
|
||||
}
|
||||
copy_from_user ( &catalog, phys_to_user ( eltorito_cmd.buffer ), 0,
|
||||
@ -1453,26 +1460,27 @@ static int int13_load_eltorito ( unsigned int drive, struct segoff *address ) {
|
||||
|
||||
/* Sanity checks */
|
||||
if ( catalog.valid.platform_id != ELTORITO_PLATFORM_X86 ) {
|
||||
DBG ( "INT13 drive %02x El Torito specifies unknown platform "
|
||||
"%02x\n", drive, catalog.valid.platform_id );
|
||||
DBGC ( drive, "INT13 drive %02x El Torito specifies unknown "
|
||||
"platform %02x\n", drive, catalog.valid.platform_id );
|
||||
return -ENOEXEC;
|
||||
}
|
||||
if ( catalog.boot.indicator != ELTORITO_BOOTABLE ) {
|
||||
DBG ( "INT13 drive %02x El Torito is not bootable\n", drive );
|
||||
DBGC ( drive, "INT13 drive %02x El Torito is not bootable\n",
|
||||
drive );
|
||||
return -ENOEXEC;
|
||||
}
|
||||
if ( catalog.boot.media_type != ELTORITO_NO_EMULATION ) {
|
||||
DBG ( "INT13 drive %02x El Torito requires emulation "
|
||||
DBGC ( drive, "INT13 drive %02x El Torito requires emulation "
|
||||
"type %02x\n", drive, catalog.boot.media_type );
|
||||
return -ENOTSUP;
|
||||
}
|
||||
DBG ( "INT13 drive %02x El Torito boot image at LBA %08x (count %d)\n",
|
||||
drive, catalog.boot.start, catalog.boot.length );
|
||||
DBGC ( drive, "INT13 drive %02x El Torito boot image at LBA %08x "
|
||||
"(count %d)\n", drive, catalog.boot.start, catalog.boot.length );
|
||||
address->segment = ( catalog.boot.load_segment ?
|
||||
catalog.boot.load_segment : 0x7c0 );
|
||||
address->offset = 0;
|
||||
DBG ( "INT13 drive %02x El Torito boot image loads at %04x:%04x\n",
|
||||
drive, address->segment, address->offset );
|
||||
DBGC ( drive, "INT13 drive %02x El Torito boot image loads at "
|
||||
"%04x:%04x\n", drive, address->segment, address->offset );
|
||||
|
||||
/* Use INT 13, 42 to read the boot image */
|
||||
eltorito_address.bufsize =
|
||||
@ -1491,8 +1499,8 @@ static int int13_load_eltorito ( unsigned int drive, struct segoff *address ) {
|
||||
: "a" ( 0x4200 ), "d" ( drive ),
|
||||
"S" ( __from_data16 ( &eltorito_address ) ) );
|
||||
if ( status ) {
|
||||
DBG ( "INT13 drive %02x could not read El Torito boot image "
|
||||
"(status %04x)\n", drive, status );
|
||||
DBGC ( drive, "INT13 drive %02x could not read El Torito boot "
|
||||
"image (status %04x)\n", drive, status );
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
@ -1503,7 +1511,7 @@ static int int13_load_eltorito ( unsigned int drive, struct segoff *address ) {
|
||||
* Attempt to boot from an INT 13 drive
|
||||
*
|
||||
* @v drive Drive number
|
||||
* @v filename Filename (or NULL to use default)
|
||||
* @v config Boot configuration parameters
|
||||
* @ret rc Return status code
|
||||
*
|
||||
* This boots from the specified INT 13 drive by loading the Master
|
||||
@ -1513,7 +1521,8 @@ static int int13_load_eltorito ( unsigned int drive, struct segoff *address ) {
|
||||
*
|
||||
* Note that this function can never return success, by definition.
|
||||
*/
|
||||
static int int13_boot ( unsigned int drive, const char *filename __unused ) {
|
||||
static int int13_boot ( unsigned int drive,
|
||||
struct san_boot_config *config __unused ) {
|
||||
struct memory_map memmap;
|
||||
struct segoff address;
|
||||
int rc;
|
||||
@ -1533,8 +1542,8 @@ static int int13_boot ( unsigned int drive, const char *filename __unused ) {
|
||||
/* Jump to boot sector */
|
||||
if ( ( rc = call_bootsector ( address.segment, address.offset,
|
||||
drive ) ) != 0 ) {
|
||||
DBG ( "INT13 drive %02x boot returned: %s\n",
|
||||
drive, strerror ( rc ) );
|
||||
DBGC ( drive, "INT13 drive %02x boot returned: %s\n",
|
||||
drive, strerror ( rc ) );
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
@ -27,6 +27,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL )
|
||||
#include <librm.h>
|
||||
|
||||
.section ".note.GNU-stack", "", @progbits
|
||||
.code16
|
||||
.arch i386
|
||||
|
||||
/****************************************************************************
|
||||
|
||||
@ -6,10 +6,9 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL )
|
||||
#define STACK_SIZE 0x2000
|
||||
|
||||
.section ".note.GNU-stack", "", @progbits
|
||||
.text
|
||||
.code16
|
||||
.arch i386
|
||||
.section ".prefix", "awx", @progbits
|
||||
.code16
|
||||
|
||||
/*
|
||||
* Find active partition
|
||||
|
||||
@ -26,10 +26,9 @@ FILE_LICENCE ( GPL2_ONLY )
|
||||
|
||||
.section ".note.GNU-stack", "", @progbits
|
||||
.org 0
|
||||
.arch i386
|
||||
.text
|
||||
.section ".prefix", "ax", @progbits
|
||||
.code16
|
||||
.arch i386
|
||||
.section ".prefix", "ax", @progbits
|
||||
.globl _dsk_start
|
||||
_dsk_start:
|
||||
|
||||
|
||||
@ -37,10 +37,9 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL )
|
||||
#define PSP_CMDLINE_START 0x81
|
||||
|
||||
.section ".note.GNU-stack", "", @progbits
|
||||
.text
|
||||
.code16
|
||||
.arch i386
|
||||
.org 0
|
||||
.code16
|
||||
.section ".prefix", "awx", @progbits
|
||||
|
||||
signature:
|
||||
|
||||
@ -3,10 +3,9 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL )
|
||||
#include <librm.h>
|
||||
|
||||
.section ".note.GNU-stack", "", @progbits
|
||||
.text
|
||||
.code16
|
||||
.arch i386
|
||||
.section ".prefix", "awx", @progbits
|
||||
.code16
|
||||
.org 0
|
||||
.globl _hd_start
|
||||
_hd_start:
|
||||
|
||||
@ -27,6 +27,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL )
|
||||
#include <librm.h>
|
||||
|
||||
.section ".note.GNU-stack", "", @progbits
|
||||
.code16
|
||||
.arch i386
|
||||
|
||||
/* Image compression enabled */
|
||||
|
||||
@ -5,9 +5,8 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL )
|
||||
#define BZI_LOAD_HIGH_ADDR 0x100000
|
||||
|
||||
.section ".note.GNU-stack", "", @progbits
|
||||
.text
|
||||
.arch i386
|
||||
.code16
|
||||
.arch i386
|
||||
.section ".prefix", "ax", @progbits
|
||||
.globl _lkrn_start
|
||||
_lkrn_start:
|
||||
|
||||
@ -1,10 +1,9 @@
|
||||
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL )
|
||||
|
||||
.section ".note.GNU-stack", "", @progbits
|
||||
.text
|
||||
.code16
|
||||
.arch i386
|
||||
.section ".prefix", "awx", @progbits
|
||||
.code16
|
||||
.org 0
|
||||
|
||||
.globl mbr
|
||||
|
||||
@ -42,9 +42,8 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL )
|
||||
#include "pciromprefix.S"
|
||||
|
||||
.section ".note.GNU-stack", "", @progbits
|
||||
.text
|
||||
.arch i386
|
||||
.code16
|
||||
.arch i386
|
||||
|
||||
/* Obtain access to payload by exposing the expansion ROM BAR at the
|
||||
* address currently used by a suitably large memory BAR on the same
|
||||
|
||||
@ -3,9 +3,8 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL )
|
||||
#include <librm.h>
|
||||
|
||||
.section ".note.GNU-stack", "", @progbits
|
||||
.text
|
||||
.arch i386
|
||||
.code16
|
||||
.arch i386
|
||||
.section ".prefix", "ax", @progbits
|
||||
.org 0
|
||||
|
||||
|
||||
@ -2,11 +2,10 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL )
|
||||
|
||||
.section ".note.GNU-stack", "", @progbits
|
||||
.org 0
|
||||
.text
|
||||
.code16
|
||||
.arch i386
|
||||
|
||||
.section ".prefix", "ax", @progbits
|
||||
.code16
|
||||
_prefix:
|
||||
|
||||
.section ".text16", "ax", @progbits
|
||||
|
||||
@ -12,10 +12,9 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL )
|
||||
#define PXE_HACK_EB54 0x0001
|
||||
|
||||
.section ".note.GNU-stack", "", @progbits
|
||||
.text
|
||||
.code16
|
||||
.arch i386
|
||||
.org 0
|
||||
.code16
|
||||
|
||||
#include <librm.h>
|
||||
#include <undi.h>
|
||||
|
||||
@ -9,10 +9,9 @@
|
||||
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL )
|
||||
|
||||
.section ".note.GNU-stack", "", @progbits
|
||||
.text
|
||||
.code16
|
||||
.arch i386
|
||||
.org 0
|
||||
.code16
|
||||
|
||||
#include <librm.h>
|
||||
|
||||
|
||||
@ -55,7 +55,6 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL )
|
||||
#endif
|
||||
|
||||
.section ".note.GNU-stack", "", @progbits
|
||||
.text
|
||||
.code16
|
||||
.arch i386
|
||||
.section ".prefix", "ax", @progbits
|
||||
|
||||
@ -3,7 +3,6 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL )
|
||||
#include <librm.h>
|
||||
|
||||
.section ".note.GNU-stack", "", @progbits
|
||||
.text
|
||||
.code16
|
||||
.arch i386
|
||||
.section ".prefix", "ax", @progbits
|
||||
|
||||
@ -44,7 +44,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
|
||||
*/
|
||||
|
||||
.section ".note.GNU-stack", "", @progbits
|
||||
.text
|
||||
.code32
|
||||
.arch i486
|
||||
.section ".prefix.lib", "ax", @progbits
|
||||
|
||||
|
||||
@ -3,10 +3,9 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL )
|
||||
#include <config/console.h>
|
||||
|
||||
.section ".note.GNU-stack", "", @progbits
|
||||
.text
|
||||
.code16
|
||||
.arch i386
|
||||
.section ".prefix", "awx", @progbits
|
||||
.code16
|
||||
.org 0
|
||||
|
||||
#include "mbr.S"
|
||||
|
||||
@ -25,6 +25,7 @@
|
||||
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL )
|
||||
|
||||
.section ".note.GNU-stack", "", @progbits
|
||||
.code16
|
||||
.arch i386
|
||||
|
||||
/****************************************************************************
|
||||
|
||||
@ -32,10 +32,9 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL )
|
||||
#define BOCHSBP xchgw %bx, %bx
|
||||
|
||||
.section ".note.GNU-stack", "", @progbits
|
||||
.text
|
||||
.code16
|
||||
.arch i386
|
||||
.section ".text16", "awx", @progbits
|
||||
.code16
|
||||
|
||||
/****************************************************************************
|
||||
* init_libkir (real-mode or 16:xx protected-mode far call)
|
||||
|
||||
@ -1632,3 +1632,70 @@ init_pages:
|
||||
|
||||
/* Return */
|
||||
ret
|
||||
|
||||
/****************************************************************************
|
||||
* sipi (real-mode jump)
|
||||
*
|
||||
* Handle Startup IPI
|
||||
*
|
||||
* This code must be copied to a page-aligned boundary in base memory.
|
||||
* It will be entered with %cs:0000 pointing to the start of the code.
|
||||
* The stack pointer is undefined and so no stack space can be used.
|
||||
*
|
||||
****************************************************************************
|
||||
*/
|
||||
.section ".text16.sipi", "ax", @progbits
|
||||
.code16
|
||||
.globl sipi
|
||||
sipi:
|
||||
/* Retrieve rm_ds from copy */
|
||||
movw %cs:( sipi_ds - sipi ), %ax
|
||||
movw %ax, %ds
|
||||
|
||||
/* Load GDT and switch to protected mode */
|
||||
data32 lgdt gdtr
|
||||
movl %cr0, %eax
|
||||
orb $CR0_PE, %al
|
||||
movl %eax, %cr0
|
||||
data32 ljmp $VIRTUAL_CS, $VIRTUAL(1f)
|
||||
|
||||
/* Copy of rm_ds required to access GDT */
|
||||
.globl sipi_ds
|
||||
sipi_ds:
|
||||
.word 0
|
||||
|
||||
/* Length of real-mode SIPI handler to be copied */
|
||||
.globl sipi_len
|
||||
.equ sipi_len, . - sipi
|
||||
|
||||
.section ".text.sipi", "ax", @progbits
|
||||
.code32
|
||||
1: /* Set up protected-mode segment registers (with no stack) */
|
||||
movw $VIRTUAL_DS, %ax
|
||||
movw %ax, %ds
|
||||
movw %ax, %ss
|
||||
movw $PHYSICAL_DS, %ax
|
||||
movw %ax, %es
|
||||
movw %ax, %fs
|
||||
movw %ax, %gs
|
||||
|
||||
/* Load register state and clear stack pointer */
|
||||
movl $VIRTUAL(sipi_regs), %esp
|
||||
popal
|
||||
|
||||
/* Switch to flat physical addressing */
|
||||
movw $PHYSICAL_DS, %sp
|
||||
movw %sp, %ds
|
||||
movw %sp, %ss
|
||||
|
||||
/* Clear stack pointer */
|
||||
xorl %esp, %esp
|
||||
|
||||
/* Jump to protected-mode SIPI handler */
|
||||
ljmp %cs:*VIRTUAL(sipi_handler)
|
||||
|
||||
/* Protected-mode SIPI handler vector */
|
||||
.section ".data.sipi_handler", "aw", @progbits
|
||||
.globl sipi_handler
|
||||
sipi_handler:
|
||||
.long 0, PHYSICAL_CS
|
||||
|
||||
@ -45,6 +45,9 @@ struct idtr64 idtr64 = {
|
||||
.limit = ( sizeof ( idt64 ) - 1 ),
|
||||
};
|
||||
|
||||
/** Startup IPI register state */
|
||||
struct i386_regs sipi_regs;
|
||||
|
||||
/** Length of stack dump */
|
||||
#define STACK_DUMP_LEN 128
|
||||
|
||||
@ -402,6 +405,29 @@ __asmcall void check_fxsr ( struct i386_all_regs *regs ) {
|
||||
( ( regs->flags & CF ) ? " not" : "" ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Set up startup IPI handler
|
||||
*
|
||||
* @v vector Startup IPI vector
|
||||
* @v handler Protected-mode startup IPI handler physical address
|
||||
* @v regs Initial register state
|
||||
*/
|
||||
void setup_sipi ( unsigned int vector, uint32_t handler,
|
||||
struct i386_regs *regs ) {
|
||||
|
||||
/* Record protected-mode handler */
|
||||
sipi_handler = handler;
|
||||
|
||||
/* Update copy of rm_ds */
|
||||
sipi_ds = rm_ds;
|
||||
|
||||
/* Save register state */
|
||||
memcpy ( &sipi_regs, regs, sizeof ( sipi_regs ) );
|
||||
|
||||
/* Copy real-mode handler */
|
||||
copy_to_real ( ( vector << 8 ), 0, sipi, ( ( size_t ) sipi_len ) );
|
||||
}
|
||||
|
||||
PROVIDE_UACCESS_INLINE ( librm, phys_to_user );
|
||||
PROVIDE_UACCESS_INLINE ( librm, user_to_phys );
|
||||
PROVIDE_UACCESS_INLINE ( librm, virt_to_user );
|
||||
|
||||
@ -188,6 +188,9 @@ REQUIRE_OBJECT ( zlib );
|
||||
#ifdef IMAGE_GZIP
|
||||
REQUIRE_OBJECT ( gzip );
|
||||
#endif
|
||||
#ifdef IMAGE_UCODE
|
||||
REQUIRE_OBJECT ( ucode );
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Drag in all requested commands
|
||||
|
||||
@ -83,6 +83,11 @@ REQUIRE_OBJECT ( oid_sha512_224 );
|
||||
REQUIRE_OBJECT ( oid_sha512_256 );
|
||||
#endif
|
||||
|
||||
/* X25519 */
|
||||
#if defined ( CRYPTO_CURVE_X25519 )
|
||||
REQUIRE_OBJECT ( oid_x25519 );
|
||||
#endif
|
||||
|
||||
/* RSA and MD5 */
|
||||
#if defined ( CRYPTO_PUBKEY_RSA ) && defined ( CRYPTO_DIGEST_MD5 )
|
||||
REQUIRE_OBJECT ( rsa_md5 );
|
||||
@ -114,25 +119,79 @@ REQUIRE_OBJECT ( rsa_sha512 );
|
||||
#endif
|
||||
|
||||
/* RSA, AES-CBC, and SHA-1 */
|
||||
#if defined ( CRYPTO_PUBKEY_RSA ) && defined ( CRYPTO_CIPHER_AES_CBC ) && \
|
||||
defined ( CRYPTO_DIGEST_SHA1 )
|
||||
#if defined ( CRYPTO_EXCHANGE_PUBKEY ) && defined ( CRYPTO_PUBKEY_RSA ) && \
|
||||
defined ( CRYPTO_CIPHER_AES_CBC ) && defined ( CRYPTO_DIGEST_SHA1 )
|
||||
REQUIRE_OBJECT ( rsa_aes_cbc_sha1 );
|
||||
#endif
|
||||
|
||||
/* RSA, AES-CBC, and SHA-256 */
|
||||
#if defined ( CRYPTO_PUBKEY_RSA ) && defined ( CRYPTO_CIPHER_AES_CBC ) && \
|
||||
defined ( CRYPTO_DIGEST_SHA256 )
|
||||
#if defined ( CRYPTO_EXCHANGE_PUBKEY ) && defined ( CRYPTO_PUBKEY_RSA ) && \
|
||||
defined ( CRYPTO_CIPHER_AES_CBC ) && defined ( CRYPTO_DIGEST_SHA256 )
|
||||
REQUIRE_OBJECT ( rsa_aes_cbc_sha256 );
|
||||
#endif
|
||||
|
||||
/* RSA, AES-GCM, and SHA-256 */
|
||||
#if defined ( CRYPTO_PUBKEY_RSA ) && defined ( CRYPTO_CIPHER_AES_GCM ) && \
|
||||
defined ( CRYPTO_DIGEST_SHA256 )
|
||||
#if defined ( CRYPTO_EXCHANGE_PUBKEY ) && defined ( CRYPTO_PUBKEY_RSA ) && \
|
||||
defined ( CRYPTO_CIPHER_AES_GCM ) && defined ( CRYPTO_DIGEST_SHA256 )
|
||||
REQUIRE_OBJECT ( rsa_aes_gcm_sha256 );
|
||||
#endif
|
||||
|
||||
/* RSA, AES-GCM, and SHA-384 */
|
||||
#if defined ( CRYPTO_PUBKEY_RSA ) && defined ( CRYPTO_CIPHER_AES_GCM ) && \
|
||||
defined ( CRYPTO_DIGEST_SHA384 )
|
||||
#if defined ( CRYPTO_EXCHANGE_PUBKEY ) && defined ( CRYPTO_PUBKEY_RSA ) && \
|
||||
defined ( CRYPTO_CIPHER_AES_GCM ) && defined ( CRYPTO_DIGEST_SHA384 )
|
||||
REQUIRE_OBJECT ( rsa_aes_gcm_sha384 );
|
||||
#endif
|
||||
|
||||
/* DHE, RSA, AES-CBC, and SHA-1 */
|
||||
#if defined ( CRYPTO_EXCHANGE_DHE ) && defined ( CRYPTO_PUBKEY_RSA ) && \
|
||||
defined ( CRYPTO_CIPHER_AES_CBC ) && defined ( CRYPTO_DIGEST_SHA1 )
|
||||
REQUIRE_OBJECT ( dhe_rsa_aes_cbc_sha1 );
|
||||
#endif
|
||||
|
||||
/* DHE, RSA, AES-CBC, and SHA-256 */
|
||||
#if defined ( CRYPTO_EXCHANGE_DHE ) && defined ( CRYPTO_PUBKEY_RSA ) && \
|
||||
defined ( CRYPTO_CIPHER_AES_CBC ) && defined ( CRYPTO_DIGEST_SHA256 )
|
||||
REQUIRE_OBJECT ( dhe_rsa_aes_cbc_sha256 );
|
||||
#endif
|
||||
|
||||
/* DHE, RSA, AES-GCM, and SHA-256 */
|
||||
#if defined ( CRYPTO_EXCHANGE_DHE ) && defined ( CRYPTO_PUBKEY_RSA ) && \
|
||||
defined ( CRYPTO_CIPHER_AES_GCM ) && defined ( CRYPTO_DIGEST_SHA256 )
|
||||
REQUIRE_OBJECT ( dhe_rsa_aes_gcm_sha256 );
|
||||
#endif
|
||||
|
||||
/* DHE, RSA, AES-GCM, and SHA-384 */
|
||||
#if defined ( CRYPTO_EXCHANGE_DHE ) && defined ( CRYPTO_PUBKEY_RSA ) && \
|
||||
defined ( CRYPTO_CIPHER_AES_GCM ) && defined ( CRYPTO_DIGEST_SHA384 )
|
||||
REQUIRE_OBJECT ( dhe_rsa_aes_gcm_sha384 );
|
||||
#endif
|
||||
|
||||
/* ECDHE, RSA, AES-CBC, and SHA-1 */
|
||||
#if defined ( CRYPTO_EXCHANGE_ECDHE ) && defined ( CRYPTO_PUBKEY_RSA ) && \
|
||||
defined ( CRYPTO_CIPHER_AES_CBC ) && defined ( CRYPTO_DIGEST_SHA1 )
|
||||
REQUIRE_OBJECT ( ecdhe_rsa_aes_cbc_sha1 );
|
||||
#endif
|
||||
|
||||
/* ECDHE, RSA, AES-CBC, and SHA-256 */
|
||||
#if defined ( CRYPTO_EXCHANGE_ECDHE ) && defined ( CRYPTO_PUBKEY_RSA ) && \
|
||||
defined ( CRYPTO_CIPHER_AES_CBC ) && defined ( CRYPTO_DIGEST_SHA256 )
|
||||
REQUIRE_OBJECT ( ecdhe_rsa_aes_cbc_sha256 );
|
||||
#endif
|
||||
|
||||
/* ECDHE, RSA, AES-CBC, and SHA-384 */
|
||||
#if defined ( CRYPTO_EXCHANGE_ECDHE ) && defined ( CRYPTO_PUBKEY_RSA ) && \
|
||||
defined ( CRYPTO_CIPHER_AES_CBC ) && defined ( CRYPTO_DIGEST_SHA384 )
|
||||
REQUIRE_OBJECT ( ecdhe_rsa_aes_cbc_sha384 );
|
||||
#endif
|
||||
|
||||
/* ECDHE, RSA, AES-GCM, and SHA-256 */
|
||||
#if defined ( CRYPTO_EXCHANGE_ECDHE ) && defined ( CRYPTO_PUBKEY_RSA ) && \
|
||||
defined ( CRYPTO_CIPHER_AES_GCM ) && defined ( CRYPTO_DIGEST_SHA256 )
|
||||
REQUIRE_OBJECT ( ecdhe_rsa_aes_gcm_sha256 );
|
||||
#endif
|
||||
|
||||
/* ECDHE, RSA, AES-GCM, and SHA-384 */
|
||||
#if defined ( CRYPTO_EXCHANGE_ECDHE ) && defined ( CRYPTO_PUBKEY_RSA ) && \
|
||||
defined ( CRYPTO_CIPHER_AES_GCM ) && defined ( CRYPTO_DIGEST_SHA384 )
|
||||
REQUIRE_OBJECT ( ecdhe_rsa_aes_gcm_sha384 );
|
||||
#endif
|
||||
|
||||
42
src/config/config_eap.c
Normal file
42
src/config/config_eap.c
Normal file
@ -0,0 +1,42 @@
|
||||
/*
|
||||
* 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 (at your option) 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 );
|
||||
|
||||
#include <config/general.h>
|
||||
|
||||
/** @file
|
||||
*
|
||||
* EAP configuration options
|
||||
*
|
||||
*/
|
||||
|
||||
PROVIDE_REQUIRING_SYMBOL();
|
||||
|
||||
/*
|
||||
* Drag in EAP authentication methods
|
||||
*/
|
||||
#ifdef EAP_METHOD_MD5
|
||||
REQUIRE_OBJECT ( eap_md5 );
|
||||
#endif
|
||||
#ifdef EAP_METHOD_MSCHAPV2
|
||||
REQUIRE_OBJECT ( eap_mschapv2 );
|
||||
#endif
|
||||
@ -12,6 +12,15 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
|
||||
/** Minimum TLS version */
|
||||
#define TLS_VERSION_MIN TLS_VERSION_TLS_1_1
|
||||
|
||||
/** Public-key exchange algorithm */
|
||||
#define CRYPTO_EXCHANGE_PUBKEY
|
||||
|
||||
/** DHE key exchange algorithm */
|
||||
#define CRYPTO_EXCHANGE_DHE
|
||||
|
||||
/** ECDHE key exchange algorithm */
|
||||
#define CRYPTO_EXCHANGE_ECDHE
|
||||
|
||||
/** RSA public-key algorithm */
|
||||
#define CRYPTO_PUBKEY_RSA
|
||||
|
||||
@ -48,6 +57,9 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
|
||||
/** SHA-512/256 digest algorithm */
|
||||
//#define CRYPTO_DIGEST_SHA512_256
|
||||
|
||||
/** X25519 elliptic curve */
|
||||
#define CRYPTO_CURVE_X25519
|
||||
|
||||
/** Margin of error (in seconds) allowed in signed timestamps
|
||||
*
|
||||
* We default to allowing a reasonable margin of error: 12 hours to
|
||||
|
||||
@ -25,6 +25,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
|
||||
#define REBOOT_EFI
|
||||
#define ACPI_EFI
|
||||
#define FDT_EFI
|
||||
#define MPAPI_EFI
|
||||
|
||||
#define NET_PROTO_IPV6 /* IPv6 protocol */
|
||||
#define NET_PROTO_LLDP /* Link Layer Discovery protocol */
|
||||
|
||||
@ -22,6 +22,7 @@ FILE_LICENCE ( GPL2_OR_LATER );
|
||||
#define PCIAPI_LINUX
|
||||
#define DMAAPI_FLAT
|
||||
#define ACPI_LINUX
|
||||
#define MPAPI_NULL
|
||||
|
||||
#define DRIVERS_LINUX
|
||||
|
||||
|
||||
@ -24,6 +24,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
|
||||
#define TIME_RTC
|
||||
#define REBOOT_PCBIOS
|
||||
#define ACPI_RSDP
|
||||
#define MPAPI_PCBIOS
|
||||
|
||||
#ifdef __x86_64__
|
||||
#define IOMAP_PAGES
|
||||
|
||||
@ -91,6 +91,13 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
|
||||
#define CRYPTO_80211_WPA /* WPA Personal, authenticating with passphrase */
|
||||
#define CRYPTO_80211_WPA2 /* Add support for stronger WPA cryptography */
|
||||
|
||||
/*
|
||||
* 802.1x EAP authentication methods
|
||||
*
|
||||
*/
|
||||
#define EAP_METHOD_MD5 /* MD5-Challenge port authentication */
|
||||
//#define EAP_METHOD_MSCHAPV2 /* MS-CHAPv2 port authentication */
|
||||
|
||||
/*
|
||||
* Name resolution modules
|
||||
*
|
||||
@ -120,6 +127,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
|
||||
#define IMAGE_PEM /* PEM image support */
|
||||
//#define IMAGE_ZLIB /* ZLIB image support */
|
||||
//#define IMAGE_GZIP /* GZIP image support */
|
||||
//#define IMAGE_UCODE /* Microcode update image support */
|
||||
|
||||
/*
|
||||
* Command-line commands to include
|
||||
|
||||
@ -78,12 +78,23 @@ int hex_decode ( char separator, const char *encoded, void *data, size_t len ) {
|
||||
unsigned int count = 0;
|
||||
unsigned int sixteens;
|
||||
unsigned int units;
|
||||
int optional;
|
||||
|
||||
/* Strip out optionality flag from separator character */
|
||||
optional = ( separator & HEX_DECODE_OPTIONAL );
|
||||
separator &= ~HEX_DECODE_OPTIONAL;
|
||||
|
||||
/* Decode string */
|
||||
while ( *encoded ) {
|
||||
|
||||
/* Check separator, if applicable */
|
||||
if ( count && separator && ( ( *(encoded++) != separator ) ) )
|
||||
return -EINVAL;
|
||||
if ( count && separator ) {
|
||||
if ( *encoded == separator ) {
|
||||
encoded++;
|
||||
} else if ( ! optional ) {
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
/* Extract digits. Note that either digit may be NUL,
|
||||
* which would be interpreted as an invalid value by
|
||||
|
||||
@ -55,7 +55,7 @@ static int dummy_san_hook ( unsigned int drive, struct uri **uris,
|
||||
|
||||
/* Register SAN device */
|
||||
if ( ( rc = register_sandev ( sandev, drive, flags ) ) != 0 ) {
|
||||
DBGC ( sandev, "SAN %#02x could not register: %s\n",
|
||||
DBGC ( sandev->drive, "SAN %#02x could not register: %s\n",
|
||||
sandev->drive, strerror ( rc ) );
|
||||
goto err_register;
|
||||
}
|
||||
@ -80,7 +80,7 @@ static void dummy_san_unhook ( unsigned int drive ) {
|
||||
/* Find drive */
|
||||
sandev = sandev_find ( drive );
|
||||
if ( ! sandev ) {
|
||||
DBG ( "SAN %#02x does not exist\n", drive );
|
||||
DBGC ( drive, "SAN %#02x does not exist\n", drive );
|
||||
return;
|
||||
}
|
||||
|
||||
@ -95,11 +95,11 @@ static void dummy_san_unhook ( unsigned int drive ) {
|
||||
* Boot from dummy SAN device
|
||||
*
|
||||
* @v drive Drive number
|
||||
* @v filename Filename (or NULL to use default)
|
||||
* @v config Boot configuration parameters
|
||||
* @ret rc Return status code
|
||||
*/
|
||||
static int dummy_san_boot ( unsigned int drive __unused,
|
||||
const char *filename __unused ) {
|
||||
struct san_boot_config *config __unused ) {
|
||||
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
67
src/core/mp.c
Normal file
67
src/core/mp.c
Normal file
@ -0,0 +1,67 @@
|
||||
/*
|
||||
* 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
|
||||
*
|
||||
* Multiprocessor functions
|
||||
*
|
||||
*/
|
||||
|
||||
#include <ipxe/timer.h>
|
||||
#include <ipxe/mp.h>
|
||||
|
||||
/** Time to wait for application processors */
|
||||
#define MP_MAX_CPUID_WAIT_MS 10
|
||||
|
||||
/**
|
||||
* Get boot CPU identifier
|
||||
*
|
||||
* @ret id Boot CPU identifier
|
||||
*/
|
||||
unsigned int mp_boot_cpuid ( void ) {
|
||||
unsigned int max = 0;
|
||||
|
||||
/* Update maximum to accommodate boot processor */
|
||||
mp_exec_boot ( mp_update_max_cpuid, &max );
|
||||
DBGC ( &mp_call, "MP boot processor ID is %#x\n", max );
|
||||
|
||||
return max;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get maximum CPU identifier
|
||||
*
|
||||
* @ret max Maximum CPU identifier
|
||||
*/
|
||||
unsigned int mp_max_cpuid ( void ) {
|
||||
unsigned int max = mp_boot_cpuid();
|
||||
|
||||
/* Update maximum to accommodate application processors */
|
||||
mp_start_all ( mp_update_max_cpuid, &max );
|
||||
mdelay ( MP_MAX_CPUID_WAIT_MS );
|
||||
DBGC ( &mp_call, "MP observed maximum CPU ID is %#x\n", max );
|
||||
|
||||
return max;
|
||||
}
|
||||
37
src/core/null_mp.c
Normal file
37
src/core/null_mp.c
Normal file
@ -0,0 +1,37 @@
|
||||
/*
|
||||
* 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
|
||||
*
|
||||
* Null multiprocessor API
|
||||
*
|
||||
*/
|
||||
|
||||
#include <ipxe/mp.h>
|
||||
|
||||
PROVIDE_MPAPI_INLINE ( null, mp_address );
|
||||
PROVIDE_MPAPI_INLINE ( null, mp_exec_boot );
|
||||
PROVIDE_MPAPI_INLINE ( null, mp_start_all );
|
||||
@ -38,7 +38,7 @@ static void null_san_unhook ( unsigned int drive __unused ) {
|
||||
}
|
||||
|
||||
static int null_san_boot ( unsigned int drive __unused,
|
||||
const char *filename __unused ) {
|
||||
struct san_boot_config *config __unused ) {
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
|
||||
@ -31,6 +31,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
|
||||
#include <ctype.h>
|
||||
#include <errno.h>
|
||||
#include <getopt.h>
|
||||
#include <ipxe/uuid.h>
|
||||
#include <ipxe/netdevice.h>
|
||||
#include <ipxe/menu.h>
|
||||
#include <ipxe/settings.h>
|
||||
@ -124,6 +125,29 @@ int parse_timeout ( char *text, unsigned long *value ) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse UUID
|
||||
*
|
||||
* @v text Text
|
||||
* @ret uuid UUID value
|
||||
* @ret rc Return status code
|
||||
*/
|
||||
int parse_uuid ( char *text, struct uuid_option *uuid ) {
|
||||
int rc;
|
||||
|
||||
/* Sanity check */
|
||||
assert ( text != NULL );
|
||||
|
||||
/* Parse UUID */
|
||||
if ( ( rc = uuid_aton ( text, &uuid->buf ) ) != 0 ) {
|
||||
printf ( "\"%s\": invalid UUID\n", text );
|
||||
return rc;
|
||||
}
|
||||
uuid->value = &uuid->buf;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse network device name
|
||||
*
|
||||
|
||||
@ -44,16 +44,6 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
|
||||
#include <ipxe/quiesce.h>
|
||||
#include <ipxe/sanboot.h>
|
||||
|
||||
/**
|
||||
* Default SAN drive number
|
||||
*
|
||||
* The drive number is a meaningful concept only in a BIOS
|
||||
* environment, where it represents the INT13 drive number (0x80 for
|
||||
* the first hard disk). We retain it in other environments to allow
|
||||
* for a simple way for iPXE commands to refer to SAN drives.
|
||||
*/
|
||||
#define SAN_DEFAULT_DRIVE 0x80
|
||||
|
||||
/**
|
||||
* Timeout for block device commands (in ticks)
|
||||
*
|
||||
@ -107,6 +97,22 @@ struct san_device * sandev_find ( unsigned int drive ) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Find next SAN device by drive number
|
||||
*
|
||||
* @v drive Minimum drive number
|
||||
* @ret sandev SAN device, or NULL
|
||||
*/
|
||||
struct san_device * sandev_next ( unsigned int drive ) {
|
||||
struct san_device *sandev;
|
||||
|
||||
list_for_each_entry ( sandev, &san_devices, list ) {
|
||||
if ( sandev->drive >= drive )
|
||||
return sandev;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Free SAN device
|
||||
*
|
||||
@ -197,7 +203,7 @@ static int sanpath_open ( struct san_path *sanpath ) {
|
||||
|
||||
/* Open interface */
|
||||
if ( ( rc = xfer_open_uri ( &sanpath->block, sanpath->uri ) ) != 0 ) {
|
||||
DBGC ( sandev, "SAN %#02x.%d could not (re)open URI: "
|
||||
DBGC ( sandev->drive, "SAN %#02x.%d could not (re)open URI: "
|
||||
"%s\n", sandev->drive, sanpath->index, strerror ( rc ) );
|
||||
return rc;
|
||||
}
|
||||
@ -265,7 +271,7 @@ static void sanpath_block_close ( struct san_path *sanpath, int rc ) {
|
||||
/* Any closure is an error from our point of view */
|
||||
if ( rc == 0 )
|
||||
rc = -ENOTCONN;
|
||||
DBGC ( sandev, "SAN %#02x.%d closed: %s\n",
|
||||
DBGC ( sandev->drive, "SAN %#02x.%d closed: %s\n",
|
||||
sandev->drive, sanpath->index, strerror ( rc ) );
|
||||
|
||||
/* Close path */
|
||||
@ -307,11 +313,11 @@ static void sanpath_step ( struct san_path *sanpath ) {
|
||||
|
||||
/* Mark as active path or close as applicable */
|
||||
if ( ! sandev->active ) {
|
||||
DBGC ( sandev, "SAN %#02x.%d is active\n",
|
||||
DBGC ( sandev->drive, "SAN %#02x.%d is active\n",
|
||||
sandev->drive, sanpath->index );
|
||||
sandev->active = sanpath;
|
||||
} else {
|
||||
DBGC ( sandev, "SAN %#02x.%d is available\n",
|
||||
DBGC ( sandev->drive, "SAN %#02x.%d is available\n",
|
||||
sandev->drive, sanpath->index );
|
||||
sanpath_close ( sanpath, 0 );
|
||||
}
|
||||
@ -398,8 +404,9 @@ int sandev_reopen ( struct san_device *sandev ) {
|
||||
rc = sanpath->path_rc;
|
||||
break;
|
||||
}
|
||||
DBGC ( sandev, "SAN %#02x never became available: %s\n",
|
||||
sandev->drive, strerror ( rc ) );
|
||||
DBGC ( sandev->drive, "SAN %#02x never became "
|
||||
"available: %s\n", sandev->drive,
|
||||
strerror ( rc ) );
|
||||
goto err_none;
|
||||
}
|
||||
}
|
||||
@ -453,8 +460,9 @@ static int sandev_command_rw ( struct san_device *sandev,
|
||||
if ( ( rc = params->rw.block_rw ( &sanpath->block, &sandev->command,
|
||||
params->rw.lba, params->rw.count,
|
||||
params->rw.buffer, len ) ) != 0 ) {
|
||||
DBGC ( sandev, "SAN %#02x.%d could not initiate read/write: "
|
||||
"%s\n", sandev->drive, sanpath->index, strerror ( rc ) );
|
||||
DBGC ( sandev->drive, "SAN %#02x.%d could not initiate "
|
||||
"read/write: %s\n", sandev->drive, sanpath->index,
|
||||
strerror ( rc ) );
|
||||
return rc;
|
||||
}
|
||||
|
||||
@ -480,8 +488,9 @@ sandev_command_read_capacity ( struct san_device *sandev,
|
||||
/* Initiate read capacity command */
|
||||
if ( ( rc = block_read_capacity ( &sanpath->block,
|
||||
&sandev->command ) ) != 0 ) {
|
||||
DBGC ( sandev, "SAN %#02x.%d could not initiate read capacity: "
|
||||
"%s\n", sandev->drive, sanpath->index, strerror ( rc ) );
|
||||
DBGC ( sandev->drive, "SAN %#02x.%d could not initiate read "
|
||||
"capacity: %s\n", sandev->drive, sanpath->index,
|
||||
strerror ( rc ) );
|
||||
return rc;
|
||||
}
|
||||
|
||||
@ -565,7 +574,7 @@ sandev_command ( struct san_device *sandev,
|
||||
int sandev_reset ( struct san_device *sandev ) {
|
||||
int rc;
|
||||
|
||||
DBGC ( sandev, "SAN %#02x reset\n", sandev->drive );
|
||||
DBGC ( sandev->drive, "SAN %#02x reset\n", sandev->drive );
|
||||
|
||||
/* Close and reopen underlying block device */
|
||||
if ( ( rc = sandev_reopen ( sandev ) ) != 0 )
|
||||
@ -698,8 +707,8 @@ static int sandev_describe ( struct san_device *sandev ) {
|
||||
if ( ! desc )
|
||||
continue;
|
||||
if ( ( rc = desc->model->complete ( desc ) ) != 0 ) {
|
||||
DBGC ( sandev, "SAN %#02x.%d could not be "
|
||||
"described: %s\n", sandev->drive,
|
||||
DBGC ( sandev->drive, "SAN %#02x.%d could not "
|
||||
"be described: %s\n", sandev->drive,
|
||||
sanpath->index, strerror ( rc ) );
|
||||
return rc;
|
||||
}
|
||||
@ -792,8 +801,8 @@ static int sandev_parse_iso9660 ( struct san_device *sandev ) {
|
||||
/* Read primary volume descriptor */
|
||||
if ( ( rc = sandev_read ( sandev, lba, count,
|
||||
virt_to_user ( scratch ) ) ) != 0 ) {
|
||||
DBGC ( sandev, "SAN %#02x could not read ISO9660 primary"
|
||||
"volume descriptor: %s\n",
|
||||
DBGC ( sandev->drive, "SAN %#02x could not read ISO9660 "
|
||||
"primary volume descriptor: %s\n",
|
||||
sandev->drive, strerror ( rc ) );
|
||||
goto err_rw;
|
||||
}
|
||||
@ -801,8 +810,8 @@ static int sandev_parse_iso9660 ( struct san_device *sandev ) {
|
||||
/* Configure as CD-ROM if applicable */
|
||||
if ( memcmp ( &scratch->primary.fixed, &primary_check,
|
||||
sizeof ( primary_check ) ) == 0 ) {
|
||||
DBGC ( sandev, "SAN %#02x contains an ISO9660 filesystem; "
|
||||
"treating as CD-ROM\n", sandev->drive );
|
||||
DBGC ( sandev->drive, "SAN %#02x contains an ISO9660 "
|
||||
"filesystem; treating as CD-ROM\n", sandev->drive );
|
||||
sandev->blksize_shift = blksize_shift;
|
||||
sandev->is_cdrom = 1;
|
||||
}
|
||||
@ -867,11 +876,12 @@ struct san_device * alloc_sandev ( struct uri **uris, unsigned int count,
|
||||
*/
|
||||
int register_sandev ( struct san_device *sandev, unsigned int drive,
|
||||
unsigned int flags ) {
|
||||
struct san_device *before;
|
||||
int rc;
|
||||
|
||||
/* Check that drive number is not in use */
|
||||
if ( sandev_find ( drive ) != NULL ) {
|
||||
DBGC ( sandev, "SAN %#02x is already in use\n", drive );
|
||||
DBGC ( sandev->drive, "SAN %#02x is already in use\n", drive );
|
||||
rc = -EADDRINUSE;
|
||||
goto err_in_use;
|
||||
}
|
||||
@ -900,9 +910,13 @@ int register_sandev ( struct san_device *sandev, unsigned int drive,
|
||||
if ( ( rc = sandev_parse_iso9660 ( sandev ) ) != 0 )
|
||||
goto err_iso9660;
|
||||
|
||||
/* Add to list of SAN devices */
|
||||
list_add_tail ( &sandev->list, &san_devices );
|
||||
DBGC ( sandev, "SAN %#02x registered\n", sandev->drive );
|
||||
/* Add to list of SAN devices, in drive order */
|
||||
for_each_sandev ( before ) {
|
||||
if ( before->drive > sandev->drive )
|
||||
break;
|
||||
}
|
||||
list_add_tail ( &sandev->list, &before->list );
|
||||
DBGC ( sandev->drive, "SAN %#02x registered\n", sandev->drive );
|
||||
|
||||
return 0;
|
||||
|
||||
@ -936,7 +950,7 @@ void unregister_sandev ( struct san_device *sandev ) {
|
||||
/* Remove ACPI descriptors */
|
||||
sandev_undescribe ( sandev );
|
||||
|
||||
DBGC ( sandev, "SAN %#02x unregistered\n", sandev->drive );
|
||||
DBGC ( sandev->drive, "SAN %#02x unregistered\n", sandev->drive );
|
||||
}
|
||||
|
||||
/** The "san-drive" setting */
|
||||
|
||||
@ -2194,6 +2194,37 @@ const struct setting_type setting_type_base64 __setting_type = {
|
||||
.format = format_base64_setting,
|
||||
};
|
||||
|
||||
/**
|
||||
* Parse UUID/GUID setting value
|
||||
*
|
||||
* @v type Setting type
|
||||
* @v value Formatted setting value
|
||||
* @v buf Buffer to contain raw value
|
||||
* @v len Length of buffer
|
||||
* @v size Integer size, in bytes
|
||||
* @ret len Length of raw value, or negative error
|
||||
*/
|
||||
static int parse_uuid_setting ( const struct setting_type *type,
|
||||
const char *value, void *buf, size_t len ) {
|
||||
union uuid uuid;
|
||||
int rc;
|
||||
|
||||
/* Parse UUID */
|
||||
if ( ( rc = uuid_aton ( value, &uuid ) ) != 0 )
|
||||
return rc;
|
||||
|
||||
/* Mangle GUID byte ordering */
|
||||
if ( type == &setting_type_guid )
|
||||
uuid_mangle ( &uuid );
|
||||
|
||||
/* Copy value */
|
||||
if ( len > sizeof ( uuid ) )
|
||||
len = sizeof ( uuid );
|
||||
memcpy ( buf, uuid.raw, len );
|
||||
|
||||
return ( sizeof ( uuid ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Format UUID/GUID setting value
|
||||
*
|
||||
@ -2227,12 +2258,14 @@ static int format_uuid_setting ( const struct setting_type *type,
|
||||
/** UUID setting type */
|
||||
const struct setting_type setting_type_uuid __setting_type = {
|
||||
.name = "uuid",
|
||||
.parse = parse_uuid_setting,
|
||||
.format = format_uuid_setting,
|
||||
};
|
||||
|
||||
/** GUID setting type */
|
||||
const struct setting_type setting_type_guid __setting_type = {
|
||||
.name = "guid",
|
||||
.parse = parse_uuid_setting,
|
||||
.format = format_uuid_setting,
|
||||
};
|
||||
|
||||
@ -2617,6 +2650,113 @@ struct builtin_setting unixtime_builtin_setting __builtin_setting = {
|
||||
.fetch = unixtime_fetch,
|
||||
};
|
||||
|
||||
/**
|
||||
* Fetch current working URI-related setting
|
||||
*
|
||||
* @v data Buffer to fill with setting data
|
||||
* @v len Length of buffer
|
||||
* @v rel Relative URI string
|
||||
* @ret len Length of setting data, or negative error
|
||||
*/
|
||||
static int cwuri_fetch_uri ( void *data, size_t len, const char *rel ) {
|
||||
struct uri *reluri;
|
||||
struct uri *uri;
|
||||
char *uristring;
|
||||
int ret;
|
||||
|
||||
/* Check that current working URI is set */
|
||||
if ( ! cwuri ) {
|
||||
ret = -ENOENT;
|
||||
goto err_unset;
|
||||
}
|
||||
|
||||
/* Construct relative URI */
|
||||
reluri = parse_uri ( rel );
|
||||
if ( ! reluri ) {
|
||||
ret = -ENOMEM;
|
||||
goto err_parse;
|
||||
}
|
||||
|
||||
/* Construct resolved URI */
|
||||
uri = resolve_uri ( cwuri, reluri );
|
||||
if ( ! uri ) {
|
||||
ret = -ENOMEM;
|
||||
goto err_resolve;
|
||||
}
|
||||
|
||||
/* Format URI string into allocated buffer (with NUL) */
|
||||
uristring = format_uri_alloc ( uri );
|
||||
if ( ! uristring ) {
|
||||
ret = -ENOMEM;
|
||||
goto err_format;
|
||||
}
|
||||
|
||||
/* Copy URI string to buffer */
|
||||
strncpy ( data, uristring, len );
|
||||
ret = strlen ( uristring );
|
||||
|
||||
free ( uristring );
|
||||
err_format:
|
||||
uri_put ( uri );
|
||||
err_resolve:
|
||||
uri_put ( reluri );
|
||||
err_parse:
|
||||
err_unset:
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch current working URI setting
|
||||
*
|
||||
* @v data Buffer to fill with setting data
|
||||
* @v len Length of buffer
|
||||
* @ret len Length of setting data, or negative error
|
||||
*/
|
||||
static int cwuri_fetch ( void *data, size_t len ) {
|
||||
|
||||
return cwuri_fetch_uri ( data, len, "" );
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch current working directory URI setting
|
||||
*
|
||||
* @v data Buffer to fill with setting data
|
||||
* @v len Length of buffer
|
||||
* @ret len Length of setting data, or negative error
|
||||
*/
|
||||
static int cwduri_fetch ( void *data, size_t len ) {
|
||||
|
||||
return cwuri_fetch_uri ( data, len, "." );
|
||||
}
|
||||
|
||||
/** Current working URI setting */
|
||||
const struct setting cwuri_setting __setting ( SETTING_MISC, cwuri ) = {
|
||||
.name = "cwuri",
|
||||
.description = "Current working URI",
|
||||
.type = &setting_type_string,
|
||||
.scope = &builtin_scope,
|
||||
};
|
||||
|
||||
/** Current working directory URI setting */
|
||||
const struct setting cwduri_setting __setting ( SETTING_MISC, cwduri ) = {
|
||||
.name = "cwduri",
|
||||
.description = "Current working directory URI",
|
||||
.type = &setting_type_string,
|
||||
.scope = &builtin_scope,
|
||||
};
|
||||
|
||||
/** Current working URI built-in setting */
|
||||
struct builtin_setting cwuri_builtin_setting __builtin_setting = {
|
||||
.setting = &cwuri_setting,
|
||||
.fetch = cwuri_fetch,
|
||||
};
|
||||
|
||||
/** Current working directory URI built-in setting */
|
||||
struct builtin_setting cwduri_builtin_setting __builtin_setting = {
|
||||
.setting = &cwduri_setting,
|
||||
.fetch = cwduri_fetch,
|
||||
};
|
||||
|
||||
/**
|
||||
* Fetch built-in setting
|
||||
*
|
||||
|
||||
@ -25,7 +25,9 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
#include <byteswap.h>
|
||||
#include <ipxe/base16.h>
|
||||
#include <ipxe/uuid.h>
|
||||
|
||||
/** @file
|
||||
@ -53,3 +55,29 @@ const char * uuid_ntoa ( const union uuid *uuid ) {
|
||||
uuid->canonical.e[4], uuid->canonical.e[5] );
|
||||
return buf;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse UUID
|
||||
*
|
||||
* @v string UUID string
|
||||
* @v uuid UUID to fill in
|
||||
* @ret rc Return status code
|
||||
*/
|
||||
int uuid_aton ( const char *string, union uuid *uuid ) {
|
||||
int len;
|
||||
int rc;
|
||||
|
||||
/* Decode as hex string with optional '-' separator */
|
||||
len = hex_decode ( ( '-' | HEX_DECODE_OPTIONAL ), string, uuid->raw,
|
||||
sizeof ( *uuid ) );
|
||||
if ( len < 0 ) {
|
||||
rc = len;
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* Check length */
|
||||
if ( len != sizeof ( *uuid ) )
|
||||
return -EINVAL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -50,6 +50,31 @@ static struct profiler bigint_mod_multiply_rescale_profiler __profiler =
|
||||
static struct profiler bigint_mod_multiply_subtract_profiler __profiler =
|
||||
{ .name = "bigint_mod_multiply.subtract" };
|
||||
|
||||
/**
|
||||
* Conditionally swap big integers (in constant time)
|
||||
*
|
||||
* @v first0 Element 0 of big integer to be conditionally swapped
|
||||
* @v second0 Element 0 of big integer to be conditionally swapped
|
||||
* @v size Number of elements in big integers
|
||||
* @v swap Swap first and second big integers
|
||||
*/
|
||||
void bigint_swap_raw ( bigint_element_t *first0, bigint_element_t *second0,
|
||||
unsigned int size, int swap ) {
|
||||
bigint_element_t mask;
|
||||
bigint_element_t xor;
|
||||
unsigned int i;
|
||||
|
||||
/* Construct mask */
|
||||
mask = ( ( bigint_element_t ) ( ! swap ) - 1 );
|
||||
|
||||
/* Conditionally swap elements */
|
||||
for ( i = 0 ; i < size ; i++ ) {
|
||||
xor = ( mask & ( first0[i] ^ second0[i] ) );
|
||||
first0[i] ^= xor;
|
||||
second0[i] ^= xor;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform modular multiplication of big integers
|
||||
*
|
||||
|
||||
695
src/crypto/des.c
Normal file
695
src/crypto/des.c
Normal file
@ -0,0 +1,695 @@
|
||||
/*
|
||||
* 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
|
||||
*
|
||||
* DES algorithm
|
||||
*
|
||||
* DES was not designed to be implemented in software, and therefore
|
||||
* contains a large number of bit permutation operations that are
|
||||
* essentially free in hardware (requiring only wires, no gates) but
|
||||
* expensive in software.
|
||||
*
|
||||
* Since DES is no longer used as a practical block cipher for large
|
||||
* volumes of data, we optimise for code size, and do not attempt to
|
||||
* obtain fast throughput.
|
||||
*
|
||||
* The algorithm is specified in NIST SP 800-67, downloadable from
|
||||
* https://nvlpubs.nist.gov/nistpubs/SpecialPublications/NIST.SP.800-67r2.pdf
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <byteswap.h>
|
||||
#include <ipxe/rotate.h>
|
||||
#include <ipxe/crypto.h>
|
||||
#include <ipxe/ecb.h>
|
||||
#include <ipxe/cbc.h>
|
||||
#include <ipxe/init.h>
|
||||
#include <ipxe/des.h>
|
||||
|
||||
/**
|
||||
* DES shift schedule
|
||||
*
|
||||
* The DES shift schedule (ordered from round 16 down to round 1) is
|
||||
* {1,2,2,2,2,2,2,1,2,2,2,2,2,2,1,1}. In binary, this may be
|
||||
* represented as {1,10,10,10,10,10,10,1,10,10,10,10,10,10,1,1} and
|
||||
* concatenated (without padding) to produce a single binary integer
|
||||
* 1101010101010110101010101011 (equal to 0x0d556aab in hexadecimal).
|
||||
*
|
||||
* This integer may then be consumed LSB-first, where a 1 bit
|
||||
* indicates a shift and the generation of a round key, and a 0 bit
|
||||
* indicates a shift without the generation of a round key.
|
||||
*/
|
||||
#define DES_SCHEDULE 0x0d556aab
|
||||
|
||||
/**
|
||||
* Define an element pair in a DES S-box
|
||||
*
|
||||
* @v x Upper element of element pair
|
||||
* @v y Lower element of element pair
|
||||
*
|
||||
* DES S-box elements are 4-bit values. We encode two values per
|
||||
* byte, ordering the elements so that the six-bit input value may be
|
||||
* used directly as a lookup index.
|
||||
*
|
||||
* Specifically, if the input value is {r1,c3,c2,c1,c0,r0}, where
|
||||
* {r1,r0} is the table row index and {c3,c2,c1,c0} is the table
|
||||
* column index (as used in the DES specification), then:
|
||||
*
|
||||
* - {r1,c3,c2,c1,c0} is the byte index into the table
|
||||
*
|
||||
* - (4*r0) is the required bit shift to extract the 4-bit value
|
||||
*/
|
||||
#define SBYTE( x, y ) ( ( (y) << 4 ) | (x) )
|
||||
|
||||
/**
|
||||
* Define a row pair in a DES S-box
|
||||
*
|
||||
* @v x0..xf Upper row of row pair
|
||||
* @v y0..yf Lower row of row pair
|
||||
*/
|
||||
#define SBOX( x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, xa, xb, xc, xd, xe, xf, \
|
||||
y0, y1, y2, y3, y4, y5, y6, y7, y8, y9, ya, yb, yc, yd, ye, yf ) \
|
||||
SBYTE ( x0, y0 ), SBYTE ( x1, y1 ), SBYTE ( x2, y2 ), SBYTE ( x3, y3 ),\
|
||||
SBYTE ( x4, y4 ), SBYTE ( x5, y5 ), SBYTE ( x6, y6 ), SBYTE ( x7, y7 ),\
|
||||
SBYTE ( x8, y8 ), SBYTE ( x9, y9 ), SBYTE ( xa, ya ), SBYTE ( xb, yb ),\
|
||||
SBYTE ( xc, yc ), SBYTE ( xd, yd ), SBYTE ( xe, ye ), SBYTE ( xf, yf )
|
||||
|
||||
/** DES S-boxes S1..S8 */
|
||||
static const uint8_t des_s[8][32] = { {
|
||||
/* S1 */
|
||||
SBOX ( 14, 4, 13, 1, 2, 15, 11, 8, 3, 10, 6, 12, 5, 9, 0, 7,
|
||||
0, 15, 7, 4, 14, 2, 13, 1, 10, 6, 12, 11, 9, 5, 3, 8 ),
|
||||
SBOX ( 4, 1, 14, 8, 13, 6, 2, 11, 15, 12, 9, 7, 3, 10, 5, 0,
|
||||
15, 12, 8, 2, 4, 9, 1, 7, 5, 11, 3, 14, 10, 0, 6, 13 )
|
||||
}, {
|
||||
/* S2 */
|
||||
SBOX ( 15, 1, 8, 14, 6, 11, 3, 4, 9, 7, 2, 13, 12, 0, 5, 10,
|
||||
3, 13, 4, 7, 15, 2, 8, 14, 12, 0, 1, 10, 6, 9, 11, 5 ),
|
||||
SBOX ( 0, 14, 7, 11, 10, 4, 13, 1, 5, 8, 12, 6, 9, 3, 2, 15,
|
||||
13, 8, 10, 1, 3, 15, 4, 2, 11, 6, 7, 12, 0, 5, 14, 9 )
|
||||
}, {
|
||||
/* S3 */
|
||||
SBOX ( 10, 0, 9, 14, 6, 3, 15, 5, 1, 13, 12, 7, 11, 4, 2, 8,
|
||||
13, 7, 0, 9, 3, 4, 6, 10, 2, 8, 5, 14, 12, 11, 15, 1 ),
|
||||
SBOX ( 13, 6, 4, 9, 8, 15, 3, 0, 11, 1, 2, 12, 5, 10, 14, 7,
|
||||
1, 10, 13, 0, 6, 9, 8, 7, 4, 15, 14, 3, 11, 5, 2, 12 )
|
||||
}, {
|
||||
/* S4 */
|
||||
SBOX ( 7, 13, 14, 3, 0, 6, 9, 10, 1, 2, 8, 5, 11, 12, 4, 15,
|
||||
13, 8, 11, 5, 6, 15, 0, 3, 4, 7, 2, 12, 1, 10, 14, 9 ),
|
||||
SBOX ( 10, 6, 9, 0, 12, 11, 7, 13, 15, 1, 3, 14, 5, 2, 8, 4,
|
||||
3, 15, 0, 6, 10, 1, 13, 8, 9, 4, 5, 11, 12, 7, 2, 14 )
|
||||
}, {
|
||||
/* S5 */
|
||||
SBOX ( 2, 12, 4, 1, 7, 10, 11, 6, 8, 5, 3, 15, 13, 0, 14, 9,
|
||||
14, 11, 2, 12, 4, 7, 13, 1, 5, 0, 15, 10, 3, 9, 8, 6 ),
|
||||
SBOX ( 4, 2, 1, 11, 10, 13, 7, 8, 15, 9, 12, 5, 6, 3, 0, 14,
|
||||
11, 8, 12, 7, 1, 14, 2, 13, 6, 15, 0, 9, 10, 4, 5, 3 )
|
||||
}, {
|
||||
/* S6 */
|
||||
SBOX ( 12, 1, 10, 15, 9, 2, 6, 8, 0, 13, 3, 4, 14, 7, 5, 11,
|
||||
10, 15, 4, 2, 7, 12, 9, 5, 6, 1, 13, 14, 0, 11, 3, 8 ),
|
||||
SBOX ( 9, 14, 15, 5, 2, 8, 12, 3, 7, 0, 4, 10, 1, 13, 11, 6,
|
||||
4, 3, 2, 12, 9, 5, 15, 10, 11, 14, 1, 7, 6, 0, 8, 13 )
|
||||
}, {
|
||||
/* S7 */
|
||||
SBOX ( 4, 11, 2, 14, 15, 0, 8, 13, 3, 12, 9, 7, 5, 10, 6, 1,
|
||||
13, 0, 11, 7, 4, 9, 1, 10, 14, 3, 5, 12, 2, 15, 8, 6 ),
|
||||
SBOX ( 1, 4, 11, 13, 12, 3, 7, 14, 10, 15, 6, 8, 0, 5, 9, 2,
|
||||
6, 11, 13, 8, 1, 4, 10, 7, 9, 5, 0, 15, 14, 2, 3, 12 )
|
||||
}, {
|
||||
/* S8 */
|
||||
SBOX ( 13, 2, 8, 4, 6, 15, 11, 1, 10, 9, 3, 14, 5, 0, 12, 7,
|
||||
1, 15, 13, 8, 10, 3, 7, 4, 12, 5, 6, 11, 0, 14, 9, 2 ),
|
||||
SBOX ( 7, 11, 4, 1, 9, 12, 14, 2, 0, 6, 10, 13, 15, 3, 5, 8,
|
||||
2, 1, 14, 7, 4, 10, 8, 13, 15, 12, 9, 0, 3, 5, 6, 11 )
|
||||
} };
|
||||
|
||||
/**
|
||||
* Define a bit index within permuted choice 2 (PC2)
|
||||
*
|
||||
* @v bit Bit index
|
||||
*
|
||||
* Permuted choice 2 (PC2) is used to select bits from a concatenated
|
||||
* pair of 28-bit registers ("C" and "D") as part of the key schedule.
|
||||
* We store these as 32-bit registers and so must add 4 to indexes
|
||||
* above 28.
|
||||
*/
|
||||
#define DES_PC2( x ) ( (x) + ( ( (x) > 28 ) ? 4 : 0 ) )
|
||||
|
||||
/**
|
||||
* Define six bits of permuted choice 2 (PC2)
|
||||
*
|
||||
* @v r1:r0 Bits corresponding to S-box row index
|
||||
* @v c3:c0 Bits corresponding to S-box column index
|
||||
*
|
||||
* There are 8 steps within a DES round (one step per S-box). Each
|
||||
* step requires six bits of the round key, corresponding to the S-box
|
||||
* input value {r1,c3,c2,c1,c0,r0}, where {r1,r0} is the table row
|
||||
* index and {c3,c2,c1,c0} is the table column index.
|
||||
*
|
||||
* As an optimisation, we store the least significant of the 6 bits in
|
||||
* the sign bit of a signed 8-bit value, and the remaining 5 bits in
|
||||
* the least significant 5 bits of the 8-bit value. See the comments
|
||||
* in des_sbox() for further details.
|
||||
*/
|
||||
#define DES_PC2R( r1, c3, c2, c1, c0, r0 ) \
|
||||
DES_PC2 ( r0 ), /* LSB stored in sign bit */ \
|
||||
DES_PC2 ( r0 ), /* Unused bit */ \
|
||||
DES_PC2 ( r0 ), /* Unused bit */ \
|
||||
DES_PC2 ( r1 ), /* Remaining 5 bits */ \
|
||||
DES_PC2 ( c3 ), /* ... */ \
|
||||
DES_PC2 ( c2 ), /* ... */ \
|
||||
DES_PC2 ( c1 ), /* ... */ \
|
||||
DES_PC2 ( c0 ) /* ... */
|
||||
|
||||
/**
|
||||
* A DES systematic permutation generator
|
||||
*
|
||||
* Many of the permutations used in DES comprise systematic bit
|
||||
* patterns. We generate these permutations at runtime to save on
|
||||
* code size.
|
||||
*/
|
||||
struct des_generator {
|
||||
/** Permutation */
|
||||
uint8_t *permutation;
|
||||
/** Seed value */
|
||||
uint32_t seed;
|
||||
};
|
||||
|
||||
/**
|
||||
* Define a DES permutation generator
|
||||
*
|
||||
* @v PERMUTATION Permutation
|
||||
* @v OFFSET Fixed input bit offset (0 or 1)
|
||||
* @v INV<n> Input bit index bit <n> should be inverted
|
||||
* @v BIT<n> Source bit for input bit index bit <n>
|
||||
* @ret generator Permutation generator
|
||||
*/
|
||||
#define DES_GENERATOR( PERMUTATION, OFFSET, INV5, BIT5, INV4, BIT4, \
|
||||
INV3, BIT3, INV2, BIT2, INV1, BIT1, INV0, BIT0 ) \
|
||||
{ \
|
||||
.permutation = (PERMUTATION), \
|
||||
.seed = ( ( (INV0) << 31 ) | ( (BIT0) << 28 ) | \
|
||||
( (INV1) << 27 ) | ( (BIT1) << 24 ) | \
|
||||
( (INV2) << 23 ) | ( (BIT2) << 20 ) | \
|
||||
( (INV3) << 19 ) | ( (BIT3) << 16 ) | \
|
||||
( (INV4) << 15 ) | ( (BIT4) << 12 ) | \
|
||||
( (INV5) << 11 ) | ( (BIT5) << 8 ) | \
|
||||
( ( uint32_t ) sizeof (PERMUTATION) - 1 ) | \
|
||||
(OFFSET) ), \
|
||||
}
|
||||
|
||||
/** DES permuted choice 1 (PC1) "C" register */
|
||||
static uint8_t des_pc1c[29];
|
||||
|
||||
/** DES permuted choice 1 (PC1) "D" register */
|
||||
static uint8_t des_pc1d[33];
|
||||
|
||||
/** DES permuted choice 2 (PC2) */
|
||||
static const uint8_t des_pc2[65] = {
|
||||
DES_PC2R ( 14, 17, 11, 24, 1, 5 ),
|
||||
DES_PC2R ( 3, 28, 15, 6, 21, 10 ),
|
||||
DES_PC2R ( 23, 19, 12, 4, 26, 8 ),
|
||||
DES_PC2R ( 16, 7, 27, 20, 13, 2 ),
|
||||
DES_PC2R ( 41, 52, 31, 37, 47, 55 ),
|
||||
DES_PC2R ( 30, 40, 51, 45, 33, 48 ),
|
||||
DES_PC2R ( 44, 49, 39, 56, 34, 53 ),
|
||||
DES_PC2R ( 46, 42, 50, 36, 29, 32 ),
|
||||
0 /* terminator */
|
||||
};
|
||||
|
||||
/** DES initial permutation (IP) */
|
||||
static uint8_t des_ip[65];
|
||||
|
||||
/** DES data permutation (P) */
|
||||
static const uint8_t des_p[33] = {
|
||||
16, 7, 20, 21, 29, 12, 28, 17, 1, 15, 23, 26, 5, 18, 31, 10,
|
||||
2, 8, 24, 14, 32, 27, 3, 9, 19, 13, 30, 6, 22, 11, 4, 25,
|
||||
0 /* terminator */
|
||||
};
|
||||
|
||||
/** DES final / inverse initial permutation (FP / IP^-1) */
|
||||
static uint8_t des_fp[65];
|
||||
|
||||
/** DES permutation generators */
|
||||
static struct des_generator des_generators[] = {
|
||||
|
||||
/* The DES initial permutation transforms the bit index
|
||||
* {x5,x4,x3,x2,x1,x0}+1 into {~x2,~x1,~x0,x4,x3,~x5}+1
|
||||
*/
|
||||
DES_GENERATOR ( des_ip, 1, 1, 2, 1, 1, 1, 0, 0, 4, 0, 3, 1, 5 ),
|
||||
|
||||
/* The DES final permutation transforms the bit index
|
||||
* {x5,x4,x3,x2,x1,x0}+1 into {~x0,x2,x1,~x5,~x4,~x3}+1
|
||||
*
|
||||
* There is an asymmetry in the DES block diagram for the last
|
||||
* of the 16 rounds, which is functionally equivalent to
|
||||
* performing 16 identical rounds and then swapping the left
|
||||
* and right halves before applying the final permutation. We
|
||||
* may therefore account for this asymmetry by inverting the
|
||||
* MSB in each bit index, to point to the corresponding bit in
|
||||
* the other half.
|
||||
*
|
||||
* This is equivalent to using a permutation that transforms
|
||||
* {x5,x4,x3,x2,x1,x0}+1 into {x0,x2,x1,~x5,~x4,~x3}+1
|
||||
*/
|
||||
DES_GENERATOR ( des_fp, 1, 0, 0, 0, 2, 0, 1, 1, 5, 1, 4, 1, 3 ),
|
||||
|
||||
/* The "C" half of DES permuted choice 1 (PC1) transforms the
|
||||
* bit index {x5,x4,x3,x2,x1,x0}+1 into {~x2,~x1,~x0,x5,x4,x3}+1
|
||||
*/
|
||||
DES_GENERATOR ( des_pc1c, 1, 1, 2, 1, 1, 1, 0, 0, 5, 0, 4, 0, 3 ),
|
||||
|
||||
/* The "D" half of DES permuted choice 1 (PC1) transforms the
|
||||
* bit index {x5,x4,x3,x2,x1,x0}+1 into {~x2,~x1,~x0,~x5,~x4,~x3}+0
|
||||
*
|
||||
* Due to the idosyncratic design choice of using 28-bit
|
||||
* registers in the DES key expansion schedule, the final four
|
||||
* permutation values appear at indices [28:31] instead of
|
||||
* [24:27]. This is adjusted for in @c des_setkey().
|
||||
*/
|
||||
DES_GENERATOR ( des_pc1d, 0, 1, 2, 1, 1, 1, 0, 1, 5, 1, 4, 1, 3 ),
|
||||
};
|
||||
|
||||
/**
|
||||
* Generate DES permutation
|
||||
*
|
||||
* @v generator Generator
|
||||
*/
|
||||
static __attribute__ (( noinline )) void
|
||||
des_generate ( struct des_generator *generator ) {
|
||||
uint8_t *permutation = generator->permutation;
|
||||
uint32_t seed = generator->seed;
|
||||
unsigned int index = 0;
|
||||
uint8_t accum;
|
||||
uint8_t bit;
|
||||
|
||||
/* Generate permutations
|
||||
*
|
||||
* This loop is optimised for code size on a
|
||||
* register-constrained architecture such as i386.
|
||||
*/
|
||||
do {
|
||||
/* Rotate seed to access MSB's bit descriptor */
|
||||
seed = ror32 ( seed, 8 );
|
||||
|
||||
/* Initialise accumulator with six flag bits */
|
||||
accum = 0xfc;
|
||||
|
||||
/* Accumulate bits until all six flag bits are cleared */
|
||||
do {
|
||||
/* Extract specified bit from index. Use a
|
||||
* rotation instead of a shift, since this
|
||||
* will allow the mask to be elided.
|
||||
*/
|
||||
bit = ror8 ( index, ( seed & 0x07 ) );
|
||||
seed = ror32 ( seed, 3 );
|
||||
|
||||
/* Toggle bit if applicable */
|
||||
bit ^= seed;
|
||||
seed = ror32 ( seed, 1 );
|
||||
|
||||
/* Add bit to accumulator and clear one flag bit */
|
||||
accum <<= 1;
|
||||
accum |= ( bit & 0x01 );
|
||||
|
||||
} while ( accum & 0x80 );
|
||||
|
||||
/* Add constant offset if applicable */
|
||||
accum += ( seed & 0x01 );
|
||||
|
||||
/* Store permutation */
|
||||
permutation[index] = accum;
|
||||
|
||||
/* Loop until reaching length (which is always even) */
|
||||
} while ( ++index < ( seed & 0xfe ) );
|
||||
DBGC2 ( permutation, "DES generated permutation %p:\n", permutation );
|
||||
DBGC2_HDA ( permutation, 0, permutation,
|
||||
( ( seed & 0xfe ) + 1 /* zero terminator */ ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialise permutations
|
||||
*/
|
||||
static void des_init ( void ) {
|
||||
unsigned int i;
|
||||
|
||||
/* Generate all generated permutations */
|
||||
for ( i = 0 ; i < ( sizeof ( des_generators ) /
|
||||
sizeof ( des_generators[0] ) ) ; i++ ) {
|
||||
des_generate ( &des_generators[i] );
|
||||
}
|
||||
}
|
||||
|
||||
/** Initialisation function */
|
||||
struct init_fn des_init_fn __init_fn ( INIT_NORMAL ) = {
|
||||
.initialise = des_init,
|
||||
};
|
||||
|
||||
/**
|
||||
* Perform bit permutation
|
||||
*
|
||||
* @v permutation Bit permutation (zero-terminated)
|
||||
* @v in Input value
|
||||
* @v out Output value
|
||||
*/
|
||||
static void des_permute ( const uint8_t *permutation, const uint8_t *in,
|
||||
uint8_t *out ) {
|
||||
uint8_t mask = 0x80;
|
||||
uint8_t accum = 0;
|
||||
unsigned int bit;
|
||||
|
||||
/* Extract individual input bits to construct output value */
|
||||
while ( ( bit = *(permutation++) ) ) {
|
||||
bit--;
|
||||
if ( in[ bit / 8 ] & ( 0x80 >> ( bit % 8 ) ) )
|
||||
accum |= mask;
|
||||
*out = accum;
|
||||
mask = ror8 ( mask, 1 );
|
||||
if ( mask == 0x80 ) {
|
||||
out++;
|
||||
accum = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform DES S-box substitution
|
||||
*
|
||||
* @v in 32-bit input value (native endian)
|
||||
* @v rkey 48-bit round key
|
||||
* @ret out 32-bit output value (native endian)
|
||||
*/
|
||||
static uint32_t des_sbox ( uint32_t in, const union des_round_key *rkey ) {
|
||||
uint32_t out = 0;
|
||||
uint32_t lookup;
|
||||
int32_t key;
|
||||
uint8_t sub;
|
||||
unsigned int i;
|
||||
|
||||
/* Perform input expansion, key addition, and S-box substitution */
|
||||
for ( i = 0 ; i < 8 ; i++ ) {
|
||||
|
||||
/* Rotate input and output */
|
||||
out = rol32 ( out, 4 );
|
||||
in = rol32 ( in, 4 );
|
||||
|
||||
/* Extract step key from relevant 6 bits of round key
|
||||
*
|
||||
* The least significant of the 6 bits (corresponding
|
||||
* to bit r0 in the S-box lookup index) is stored in
|
||||
* the sign bit of the step key byte. It will
|
||||
* therefore be propagated via sign extension to the
|
||||
* MSB of the 32-bit step key.
|
||||
*
|
||||
* The remaining 5 of the 6 bits (corresponding to
|
||||
* bits {r1,c3,c2,c1,c0} in the S-box lookup index)
|
||||
* are stored in the least significant 5 bits of the
|
||||
* step key byte and will end up in the least
|
||||
* significant 5 bits of the 32-bit step key.
|
||||
*/
|
||||
key = rkey->step[i];
|
||||
|
||||
/* Add step key to input to produce S-box lookup index
|
||||
*
|
||||
* We do not ever perform an explicit expansion of the
|
||||
* input value from 32 to 48 bits. Instead, we rotate
|
||||
* the 32-bit input value by 4 bits on each step, and
|
||||
* extract the relevant 6 bits.
|
||||
*
|
||||
* The least significant of the 6 bits (corresponding
|
||||
* to bit r0 in the S-box lookup index) is currently
|
||||
* in the MSB of the 32-bit (rotated) input value.
|
||||
*
|
||||
* The remaining 5 of the 6 bits (corresponding to
|
||||
* bits {r1,c3,c2,c1,c0} in the S-box lookup index)
|
||||
* are currently in the least significant 5 bits of
|
||||
* the 32-bit (rotated) input value.
|
||||
*
|
||||
* This aligns with the placement of the bits in the
|
||||
* step key (see above), and we can therefore perform
|
||||
* a single XOR to add the 6-bit step key to the
|
||||
* relevant 6 bits of the input value.
|
||||
*/
|
||||
lookup = ( in ^ key );
|
||||
|
||||
/* Look up S[i][in ^ key] from S-box
|
||||
*
|
||||
* We have bits {r1,c3,c2,c1,c0} in the least
|
||||
* significant 5 bits of the lookup index, and so can
|
||||
* use the masked lookup index directly as a byte
|
||||
* index into the relevant S-box to extract the byte
|
||||
* containing both {r1,c3,c2,c1,c0,'0'} and
|
||||
* {r1,c3,c2,c1,c0,'1'}.
|
||||
*
|
||||
* We then use the MSB of the 32-bit lookup index to
|
||||
* extract the relevant nibble for the full lookup
|
||||
* index {r1,c3,c2,c1,c0,r0}.
|
||||
*/
|
||||
sub = des_s[i][ lookup & 0x1f ];
|
||||
sub >>= ( ( lookup >> 29 ) & 4 );
|
||||
sub &= 0x0f;
|
||||
|
||||
/* Substitute S[i][input ^ key] into output */
|
||||
out |= sub;
|
||||
}
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform a single DES round
|
||||
*
|
||||
* @v block DES block
|
||||
* @v rkey 48-bit round key
|
||||
*/
|
||||
static void des_round ( union des_block *block,
|
||||
const union des_round_key *rkey ) {
|
||||
union des_dword sbox;
|
||||
uint32_t left;
|
||||
uint32_t right;
|
||||
|
||||
/* Extract left and right halves L[n-1] and R[n-1] */
|
||||
left = block->left.dword;
|
||||
right = block->right.dword;
|
||||
DBGC2 ( block, "DES L=%08x R=%08x K=%08x%08x", be32_to_cpu ( left ),
|
||||
be32_to_cpu ( right ), be32_to_cpu ( rkey->dword[0] ),
|
||||
be32_to_cpu ( rkey->dword[1] ) );
|
||||
|
||||
/* L[n] = R[n-1] */
|
||||
block->left.dword = right;
|
||||
|
||||
/* Calculate Feistel function f(R[n-1], K[n]) */
|
||||
sbox.dword = cpu_to_be32 ( des_sbox ( be32_to_cpu ( right ), rkey ) );
|
||||
des_permute ( des_p, sbox.byte, block->right.byte );
|
||||
|
||||
/* R[n] = L[n-1] + f(R[n-1], K[n]) */
|
||||
block->right.dword ^= left;
|
||||
DBGC2 ( block, " => L=%08x R=%08x\n",
|
||||
be32_to_cpu ( block->left.dword ),
|
||||
be32_to_cpu ( block->right.dword ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform all DES rounds
|
||||
*
|
||||
* @v in Input DES block
|
||||
* @v out Output DES block
|
||||
* @v rkey Starting 48-bit round key
|
||||
* @v offset Byte offset between round keys
|
||||
*/
|
||||
static void des_rounds ( const union des_block *in, union des_block *out,
|
||||
const union des_round_key *rkey,
|
||||
ssize_t offset ) {
|
||||
union des_block tmp;
|
||||
unsigned int i;
|
||||
|
||||
/* Apply initial permutation */
|
||||
des_permute ( des_ip, in->byte, tmp.byte );
|
||||
|
||||
/* Perform all DES rounds, consuming keys in the specified order */
|
||||
for ( i = 0 ; i < DES_ROUNDS ; i++ ) {
|
||||
des_round ( &tmp, rkey );
|
||||
rkey = ( ( ( void * ) rkey ) + offset );
|
||||
}
|
||||
|
||||
/* Apply final permutation */
|
||||
DBGC ( &tmp, "DES %scrypted %08x%08x => ",
|
||||
( ( offset > 0 ) ? "en" : "de" ), be32_to_cpu ( in->dword[0] ),
|
||||
be32_to_cpu ( in->dword[1] ) );
|
||||
des_permute ( des_fp, tmp.byte, out->byte );
|
||||
DBGC ( &tmp, "%08x%08x\n", be32_to_cpu ( out->dword[0] ),
|
||||
be32_to_cpu ( out->dword[1] ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Rotate 28-bit word
|
||||
*
|
||||
* @v dword 28-bit dword value
|
||||
* @ret dword Rotated 28-bit dword value
|
||||
*/
|
||||
static uint32_t des_rol28 ( uint32_t dword ) {
|
||||
int32_t sdword;
|
||||
|
||||
/* Convert to native-endian */
|
||||
sdword = be32_to_cpu ( dword );
|
||||
|
||||
/* Signed shift right by 4 places to copy bit 31 to bits 27:31 */
|
||||
sdword >>= 4;
|
||||
|
||||
/* Rotate left */
|
||||
sdword = rol32 ( sdword, 1 );
|
||||
|
||||
/* Shift left by 4 places to restore bit positions */
|
||||
sdword <<= 4;
|
||||
|
||||
/* Convert back to big-endian */
|
||||
dword = cpu_to_be32 ( sdword );
|
||||
|
||||
return dword;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set key
|
||||
*
|
||||
* @v ctx Context
|
||||
* @v key Key
|
||||
* @v keylen Key length
|
||||
* @ret rc Return status code
|
||||
*/
|
||||
static int des_setkey ( void *ctx, const void *key, size_t keylen ) {
|
||||
struct des_context *des = ctx;
|
||||
union des_round_key *rkey = des->rkey;
|
||||
union des_block reg;
|
||||
uint32_t schedule;
|
||||
|
||||
/* Validate key length */
|
||||
if ( keylen != DES_BLOCKSIZE )
|
||||
return -EINVAL;
|
||||
DBGC ( des, "DES %p new key:\n", des );
|
||||
DBGC_HDA ( des, 0, key, keylen );
|
||||
|
||||
/* Apply permuted choice 1 */
|
||||
des_permute ( des_pc1c, key, reg.c.byte );
|
||||
des_permute ( des_pc1d, key, reg.d.byte );
|
||||
reg.d.byte[3] <<= 4; /* see comment for @c des_pc1d */
|
||||
DBGC2 ( des, "DES %p C[ 0]=%07x D[ 0]=%07x\n",
|
||||
des, ( be32_to_cpu ( reg.c.dword ) >> 4 ),
|
||||
( be32_to_cpu ( reg.d.dword ) >> 4 ) );
|
||||
|
||||
/* Generate round keys */
|
||||
for ( schedule = DES_SCHEDULE ; schedule ; schedule >>= 1 ) {
|
||||
|
||||
/* Shift 28-bit words */
|
||||
reg.c.dword = des_rol28 ( reg.c.dword );
|
||||
reg.d.dword = des_rol28 ( reg.d.dword );
|
||||
|
||||
/* Skip rounds according to shift schedule */
|
||||
if ( ! ( schedule & 1 ) )
|
||||
continue;
|
||||
|
||||
/* Apply permuted choice 2 */
|
||||
des_permute ( des_pc2, reg.byte, rkey->byte );
|
||||
DBGC2 ( des, "DES %p C[%2zd]=%07x D[%2zd]=%07x K[%2zd]="
|
||||
"%08x%08x\n", des, ( ( rkey - des->rkey ) + 1 ),
|
||||
( be32_to_cpu ( reg.c.dword ) >> 4 ),
|
||||
( ( rkey - des->rkey ) + 1 ),
|
||||
( be32_to_cpu ( reg.d.dword ) >> 4 ),
|
||||
( ( rkey - des->rkey ) + 1 ),
|
||||
be32_to_cpu ( rkey->dword[0] ),
|
||||
be32_to_cpu ( rkey->dword[1] ) );
|
||||
|
||||
/* Move to next key */
|
||||
rkey++;
|
||||
}
|
||||
|
||||
/* Sanity check */
|
||||
assert ( rkey == &des->rkey[DES_ROUNDS] );
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Encrypt data
|
||||
*
|
||||
* @v ctx Context
|
||||
* @v src Data to encrypt
|
||||
* @v dst Buffer for encrypted data
|
||||
* @v len Length of data
|
||||
*/
|
||||
static void des_encrypt ( void *ctx, const void *src, void *dst, size_t len ) {
|
||||
struct des_context *des = ctx;
|
||||
|
||||
/* Sanity check */
|
||||
assert ( len == DES_BLOCKSIZE );
|
||||
|
||||
/* Cipher using keys in forward direction */
|
||||
des_rounds ( src, dst, &des->rkey[0], sizeof ( des->rkey[0] ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Decrypt data
|
||||
*
|
||||
* @v ctx Context
|
||||
* @v src Data to decrypt
|
||||
* @v dst Buffer for decrypted data
|
||||
* @v len Length of data
|
||||
*/
|
||||
static void des_decrypt ( void *ctx, const void *src, void *dst, size_t len ) {
|
||||
struct des_context *des = ctx;
|
||||
|
||||
/* Sanity check */
|
||||
assert ( len == DES_BLOCKSIZE );
|
||||
|
||||
/* Cipher using keys in reverse direction */
|
||||
des_rounds ( src, dst, &des->rkey[ DES_ROUNDS - 1 ],
|
||||
-sizeof ( des->rkey[0] ) );
|
||||
}
|
||||
|
||||
/** Basic DES algorithm */
|
||||
struct cipher_algorithm des_algorithm = {
|
||||
.name = "des",
|
||||
.ctxsize = sizeof ( struct des_context ),
|
||||
.blocksize = DES_BLOCKSIZE,
|
||||
.alignsize = 0,
|
||||
.authsize = 0,
|
||||
.setkey = des_setkey,
|
||||
.setiv = cipher_null_setiv,
|
||||
.encrypt = des_encrypt,
|
||||
.decrypt = des_decrypt,
|
||||
.auth = cipher_null_auth,
|
||||
};
|
||||
|
||||
/* DES in Electronic Codebook mode */
|
||||
ECB_CIPHER ( des_ecb, des_ecb_algorithm,
|
||||
des_algorithm, struct des_context, DES_BLOCKSIZE );
|
||||
|
||||
/* DES in Cipher Block Chaining mode */
|
||||
CBC_CIPHER ( des_cbc, des_cbc_algorithm,
|
||||
des_algorithm, struct des_context, DES_BLOCKSIZE );
|
||||
@ -109,6 +109,9 @@ static union gcm_block gcm_cached_mult[256];
|
||||
*/
|
||||
static uint16_t gcm_cached_reduce[256];
|
||||
|
||||
/** Offset of a field within GCM context */
|
||||
#define gcm_offset( field ) offsetof ( struct gcm_context, field )
|
||||
|
||||
/**
|
||||
* Reverse bits in a byte
|
||||
*
|
||||
@ -469,16 +472,14 @@ int gcm_setkey ( struct gcm_context *context, const void *key, size_t keylen,
|
||||
* @v ivlen Initialisation vector length
|
||||
*/
|
||||
void gcm_setiv ( struct gcm_context *context, const void *iv, size_t ivlen ) {
|
||||
union gcm_block *check = ( ( void * ) context );
|
||||
|
||||
/* Sanity checks */
|
||||
linker_assert ( &context->hash == check, gcm_bad_layout );
|
||||
linker_assert ( &context->len == check + 1, gcm_bad_layout );
|
||||
linker_assert ( &context->ctr == check + 2, gcm_bad_layout );
|
||||
linker_assert ( &context->key == check + 3, gcm_bad_layout );
|
||||
|
||||
/* Reset non-key state */
|
||||
memset ( context, 0, offsetof ( typeof ( *context ), key ) );
|
||||
memset ( context, 0, gcm_offset ( key ) );
|
||||
build_assert ( gcm_offset ( key ) > gcm_offset ( hash ) );
|
||||
build_assert ( gcm_offset ( key ) > gcm_offset ( len ) );
|
||||
build_assert ( gcm_offset ( key ) > gcm_offset ( ctr ) );
|
||||
build_assert ( gcm_offset ( key ) < gcm_offset ( raw_cipher ) );
|
||||
build_assert ( gcm_offset ( key ) < gcm_offset ( raw_ctx ) );
|
||||
|
||||
/* Reset counter */
|
||||
context->ctr.ctr.value = cpu_to_be32 ( 1 );
|
||||
@ -497,7 +498,12 @@ void gcm_setiv ( struct gcm_context *context, const void *iv, size_t ivlen ) {
|
||||
assert ( context->len.len.add == 0 );
|
||||
|
||||
/* Reset non-key, non-counter state */
|
||||
memset ( context, 0, offsetof ( typeof ( *context ), ctr ) );
|
||||
memset ( context, 0, gcm_offset ( ctr ) );
|
||||
build_assert ( gcm_offset ( ctr ) > gcm_offset ( hash ) );
|
||||
build_assert ( gcm_offset ( ctr ) > gcm_offset ( len ) );
|
||||
build_assert ( gcm_offset ( ctr ) < gcm_offset ( key ) );
|
||||
build_assert ( gcm_offset ( ctr ) < gcm_offset ( raw_cipher ) );
|
||||
build_assert ( gcm_offset ( ctr ) < gcm_offset ( raw_ctx ) );
|
||||
}
|
||||
|
||||
DBGC2 ( context, "GCM %p Y[0]:\n", context );
|
||||
|
||||
@ -155,11 +155,11 @@ static void md4_digest ( struct md4_context *context ) {
|
||||
|
||||
/* Sanity checks */
|
||||
assert ( ( context->len % sizeof ( context->ddd.dd.data ) ) == 0 );
|
||||
linker_assert ( &u.ddd.dd.digest.h[0] == a, md4_bad_layout );
|
||||
linker_assert ( &u.ddd.dd.digest.h[1] == b, md4_bad_layout );
|
||||
linker_assert ( &u.ddd.dd.digest.h[2] == c, md4_bad_layout );
|
||||
linker_assert ( &u.ddd.dd.digest.h[3] == d, md4_bad_layout );
|
||||
linker_assert ( &u.ddd.dd.data.dword[0] == w, md4_bad_layout );
|
||||
build_assert ( &u.ddd.dd.digest.h[0] == a );
|
||||
build_assert ( &u.ddd.dd.digest.h[1] == b );
|
||||
build_assert ( &u.ddd.dd.digest.h[2] == c );
|
||||
build_assert ( &u.ddd.dd.digest.h[3] == d );
|
||||
build_assert ( &u.ddd.dd.data.dword[0] == w );
|
||||
|
||||
DBGC ( context, "MD4 digesting:\n" );
|
||||
DBGC_HDA ( context, 0, &context->ddd.dd.digest,
|
||||
|
||||
@ -178,11 +178,11 @@ static void md5_digest ( struct md5_context *context ) {
|
||||
|
||||
/* Sanity checks */
|
||||
assert ( ( context->len % sizeof ( context->ddd.dd.data ) ) == 0 );
|
||||
linker_assert ( &u.ddd.dd.digest.h[0] == a, md5_bad_layout );
|
||||
linker_assert ( &u.ddd.dd.digest.h[1] == b, md5_bad_layout );
|
||||
linker_assert ( &u.ddd.dd.digest.h[2] == c, md5_bad_layout );
|
||||
linker_assert ( &u.ddd.dd.digest.h[3] == d, md5_bad_layout );
|
||||
linker_assert ( &u.ddd.dd.data.dword[0] == w, md5_bad_layout );
|
||||
build_assert ( &u.ddd.dd.digest.h[0] == a );
|
||||
build_assert ( &u.ddd.dd.digest.h[1] == b );
|
||||
build_assert ( &u.ddd.dd.digest.h[2] == c );
|
||||
build_assert ( &u.ddd.dd.digest.h[3] == d );
|
||||
build_assert ( &u.ddd.dd.data.dword[0] == w );
|
||||
|
||||
DBGC ( context, "MD5 digesting:\n" );
|
||||
DBGC_HDA ( context, 0, &context->ddd.dd.digest,
|
||||
|
||||
61
src/crypto/mishmash/dhe_rsa_aes_cbc_sha1.c
Normal file
61
src/crypto/mishmash/dhe_rsa_aes_cbc_sha1.c
Normal file
@ -0,0 +1,61 @@
|
||||
/*
|
||||
* Copyright (C) 2015 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 (at your option) 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 );
|
||||
|
||||
#include <byteswap.h>
|
||||
#include <ipxe/rsa.h>
|
||||
#include <ipxe/aes.h>
|
||||
#include <ipxe/sha1.h>
|
||||
#include <ipxe/sha256.h>
|
||||
#include <ipxe/tls.h>
|
||||
|
||||
/** TLS_DHE_RSA_WITH_AES_128_CBC_SHA cipher suite */
|
||||
struct tls_cipher_suite
|
||||
tls_dhe_rsa_with_aes_128_cbc_sha __tls_cipher_suite ( 15 ) = {
|
||||
.code = htons ( TLS_DHE_RSA_WITH_AES_128_CBC_SHA ),
|
||||
.key_len = ( 128 / 8 ),
|
||||
.fixed_iv_len = 0,
|
||||
.record_iv_len = AES_BLOCKSIZE,
|
||||
.mac_len = SHA1_DIGEST_SIZE,
|
||||
.exchange = &tls_dhe_exchange_algorithm,
|
||||
.pubkey = &rsa_algorithm,
|
||||
.cipher = &aes_cbc_algorithm,
|
||||
.digest = &sha1_algorithm,
|
||||
.handshake = &sha256_algorithm,
|
||||
};
|
||||
|
||||
/** TLS_DHE_RSA_WITH_AES_256_CBC_SHA cipher suite */
|
||||
struct tls_cipher_suite
|
||||
tls_dhe_rsa_with_aes_256_cbc_sha __tls_cipher_suite ( 16 ) = {
|
||||
.code = htons ( TLS_DHE_RSA_WITH_AES_256_CBC_SHA ),
|
||||
.key_len = ( 256 / 8 ),
|
||||
.fixed_iv_len = 0,
|
||||
.record_iv_len = AES_BLOCKSIZE,
|
||||
.mac_len = SHA1_DIGEST_SIZE,
|
||||
.exchange = &tls_dhe_exchange_algorithm,
|
||||
.pubkey = &rsa_algorithm,
|
||||
.cipher = &aes_cbc_algorithm,
|
||||
.digest = &sha1_algorithm,
|
||||
.handshake = &sha256_algorithm,
|
||||
};
|
||||
60
src/crypto/mishmash/dhe_rsa_aes_cbc_sha256.c
Normal file
60
src/crypto/mishmash/dhe_rsa_aes_cbc_sha256.c
Normal file
@ -0,0 +1,60 @@
|
||||
/*
|
||||
* Copyright (C) 2015 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 (at your option) 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 );
|
||||
|
||||
#include <byteswap.h>
|
||||
#include <ipxe/rsa.h>
|
||||
#include <ipxe/aes.h>
|
||||
#include <ipxe/sha256.h>
|
||||
#include <ipxe/tls.h>
|
||||
|
||||
/** TLS_DHE_RSA_WITH_AES_128_CBC_SHA256 cipher suite */
|
||||
struct tls_cipher_suite
|
||||
tls_dhe_rsa_with_aes_128_cbc_sha256 __tls_cipher_suite ( 13 ) = {
|
||||
.code = htons ( TLS_DHE_RSA_WITH_AES_128_CBC_SHA256 ),
|
||||
.key_len = ( 128 / 8 ),
|
||||
.fixed_iv_len = 0,
|
||||
.record_iv_len = AES_BLOCKSIZE,
|
||||
.mac_len = SHA256_DIGEST_SIZE,
|
||||
.exchange = &tls_dhe_exchange_algorithm,
|
||||
.pubkey = &rsa_algorithm,
|
||||
.cipher = &aes_cbc_algorithm,
|
||||
.digest = &sha256_algorithm,
|
||||
.handshake = &sha256_algorithm,
|
||||
};
|
||||
|
||||
/** TLS_DHE_RSA_WITH_AES_256_CBC_SHA256 cipher suite */
|
||||
struct tls_cipher_suite
|
||||
tls_dhe_rsa_with_aes_256_cbc_sha256 __tls_cipher_suite ( 14 ) = {
|
||||
.code = htons ( TLS_DHE_RSA_WITH_AES_256_CBC_SHA256 ),
|
||||
.key_len = ( 256 / 8 ),
|
||||
.fixed_iv_len = 0,
|
||||
.record_iv_len = AES_BLOCKSIZE,
|
||||
.mac_len = SHA256_DIGEST_SIZE,
|
||||
.exchange = &tls_dhe_exchange_algorithm,
|
||||
.pubkey = &rsa_algorithm,
|
||||
.cipher = &aes_cbc_algorithm,
|
||||
.digest = &sha256_algorithm,
|
||||
.handshake = &sha256_algorithm,
|
||||
};
|
||||
45
src/crypto/mishmash/dhe_rsa_aes_gcm_sha256.c
Normal file
45
src/crypto/mishmash/dhe_rsa_aes_gcm_sha256.c
Normal file
@ -0,0 +1,45 @@
|
||||
/*
|
||||
* Copyright (C) 2022 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 (at your option) 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 );
|
||||
|
||||
#include <byteswap.h>
|
||||
#include <ipxe/rsa.h>
|
||||
#include <ipxe/aes.h>
|
||||
#include <ipxe/sha256.h>
|
||||
#include <ipxe/tls.h>
|
||||
|
||||
/** TLS_DHE_RSA_WITH_AES_128_GCM_SHA256 cipher suite */
|
||||
struct tls_cipher_suite
|
||||
tls_dhe_rsa_with_aes_128_gcm_sha256 __tls_cipher_suite ( 11 ) = {
|
||||
.code = htons ( TLS_DHE_RSA_WITH_AES_128_GCM_SHA256 ),
|
||||
.key_len = ( 128 / 8 ),
|
||||
.fixed_iv_len = 4,
|
||||
.record_iv_len = 8,
|
||||
.mac_len = 0,
|
||||
.exchange = &tls_dhe_exchange_algorithm,
|
||||
.pubkey = &rsa_algorithm,
|
||||
.cipher = &aes_gcm_algorithm,
|
||||
.digest = &sha256_algorithm,
|
||||
.handshake = &sha256_algorithm,
|
||||
};
|
||||
45
src/crypto/mishmash/dhe_rsa_aes_gcm_sha384.c
Normal file
45
src/crypto/mishmash/dhe_rsa_aes_gcm_sha384.c
Normal file
@ -0,0 +1,45 @@
|
||||
/*
|
||||
* Copyright (C) 2022 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 (at your option) 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 );
|
||||
|
||||
#include <byteswap.h>
|
||||
#include <ipxe/rsa.h>
|
||||
#include <ipxe/aes.h>
|
||||
#include <ipxe/sha512.h>
|
||||
#include <ipxe/tls.h>
|
||||
|
||||
/** TLS_DHE_RSA_WITH_AES_256_GCM_SHA384 cipher suite */
|
||||
struct tls_cipher_suite
|
||||
tls_dhe_rsa_with_aes_256_gcm_sha384 __tls_cipher_suite ( 12 ) = {
|
||||
.code = htons ( TLS_DHE_RSA_WITH_AES_256_GCM_SHA384 ),
|
||||
.key_len = ( 256 / 8 ),
|
||||
.fixed_iv_len = 4,
|
||||
.record_iv_len = 8,
|
||||
.mac_len = 0,
|
||||
.exchange = &tls_dhe_exchange_algorithm,
|
||||
.pubkey = &rsa_algorithm,
|
||||
.cipher = &aes_gcm_algorithm,
|
||||
.digest = &sha384_algorithm,
|
||||
.handshake = &sha384_algorithm,
|
||||
};
|
||||
61
src/crypto/mishmash/ecdhe_rsa_aes_cbc_sha1.c
Normal file
61
src/crypto/mishmash/ecdhe_rsa_aes_cbc_sha1.c
Normal file
@ -0,0 +1,61 @@
|
||||
/*
|
||||
* 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 (at your option) 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 );
|
||||
|
||||
#include <byteswap.h>
|
||||
#include <ipxe/rsa.h>
|
||||
#include <ipxe/aes.h>
|
||||
#include <ipxe/sha1.h>
|
||||
#include <ipxe/sha256.h>
|
||||
#include <ipxe/tls.h>
|
||||
|
||||
/** TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA cipher suite */
|
||||
struct tls_cipher_suite
|
||||
tls_ecdhe_rsa_with_aes_128_cbc_sha __tls_cipher_suite ( 05 ) = {
|
||||
.code = htons ( TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA ),
|
||||
.key_len = ( 128 / 8 ),
|
||||
.fixed_iv_len = 0,
|
||||
.record_iv_len = AES_BLOCKSIZE,
|
||||
.mac_len = SHA1_DIGEST_SIZE,
|
||||
.exchange = &tls_ecdhe_exchange_algorithm,
|
||||
.pubkey = &rsa_algorithm,
|
||||
.cipher = &aes_cbc_algorithm,
|
||||
.digest = &sha1_algorithm,
|
||||
.handshake = &sha256_algorithm,
|
||||
};
|
||||
|
||||
/** TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA cipher suite */
|
||||
struct tls_cipher_suite
|
||||
tls_ecdhe_rsa_with_aes_256_cbc_sha __tls_cipher_suite ( 06 ) = {
|
||||
.code = htons ( TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA ),
|
||||
.key_len = ( 256 / 8 ),
|
||||
.fixed_iv_len = 0,
|
||||
.record_iv_len = AES_BLOCKSIZE,
|
||||
.mac_len = SHA1_DIGEST_SIZE,
|
||||
.exchange = &tls_ecdhe_exchange_algorithm,
|
||||
.pubkey = &rsa_algorithm,
|
||||
.cipher = &aes_cbc_algorithm,
|
||||
.digest = &sha1_algorithm,
|
||||
.handshake = &sha256_algorithm,
|
||||
};
|
||||
45
src/crypto/mishmash/ecdhe_rsa_aes_cbc_sha256.c
Normal file
45
src/crypto/mishmash/ecdhe_rsa_aes_cbc_sha256.c
Normal file
@ -0,0 +1,45 @@
|
||||
/*
|
||||
* 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 (at your option) 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 );
|
||||
|
||||
#include <byteswap.h>
|
||||
#include <ipxe/rsa.h>
|
||||
#include <ipxe/aes.h>
|
||||
#include <ipxe/sha256.h>
|
||||
#include <ipxe/tls.h>
|
||||
|
||||
/** TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256 cipher suite */
|
||||
struct tls_cipher_suite
|
||||
tls_ecdhe_rsa_with_aes_128_cbc_sha256 __tls_cipher_suite ( 03 ) = {
|
||||
.code = htons ( TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256 ),
|
||||
.key_len = ( 128 / 8 ),
|
||||
.fixed_iv_len = 0,
|
||||
.record_iv_len = AES_BLOCKSIZE,
|
||||
.mac_len = SHA256_DIGEST_SIZE,
|
||||
.exchange = &tls_ecdhe_exchange_algorithm,
|
||||
.pubkey = &rsa_algorithm,
|
||||
.cipher = &aes_cbc_algorithm,
|
||||
.digest = &sha256_algorithm,
|
||||
.handshake = &sha256_algorithm,
|
||||
};
|
||||
45
src/crypto/mishmash/ecdhe_rsa_aes_cbc_sha384.c
Normal file
45
src/crypto/mishmash/ecdhe_rsa_aes_cbc_sha384.c
Normal file
@ -0,0 +1,45 @@
|
||||
/*
|
||||
* 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 (at your option) 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 );
|
||||
|
||||
#include <byteswap.h>
|
||||
#include <ipxe/rsa.h>
|
||||
#include <ipxe/aes.h>
|
||||
#include <ipxe/sha512.h>
|
||||
#include <ipxe/tls.h>
|
||||
|
||||
/** TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384 cipher suite */
|
||||
struct tls_cipher_suite
|
||||
tls_ecdhe_rsa_with_aes_256_cbc_sha384 __tls_cipher_suite ( 04 ) = {
|
||||
.code = htons ( TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384 ),
|
||||
.key_len = ( 256 / 8 ),
|
||||
.fixed_iv_len = 0,
|
||||
.record_iv_len = AES_BLOCKSIZE,
|
||||
.mac_len = SHA384_DIGEST_SIZE,
|
||||
.exchange = &tls_ecdhe_exchange_algorithm,
|
||||
.pubkey = &rsa_algorithm,
|
||||
.cipher = &aes_cbc_algorithm,
|
||||
.digest = &sha384_algorithm,
|
||||
.handshake = &sha384_algorithm,
|
||||
};
|
||||
45
src/crypto/mishmash/ecdhe_rsa_aes_gcm_sha256.c
Normal file
45
src/crypto/mishmash/ecdhe_rsa_aes_gcm_sha256.c
Normal file
@ -0,0 +1,45 @@
|
||||
/*
|
||||
* 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 (at your option) 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 );
|
||||
|
||||
#include <byteswap.h>
|
||||
#include <ipxe/rsa.h>
|
||||
#include <ipxe/aes.h>
|
||||
#include <ipxe/sha256.h>
|
||||
#include <ipxe/tls.h>
|
||||
|
||||
/** TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 cipher suite */
|
||||
struct tls_cipher_suite
|
||||
tls_ecdhe_rsa_with_aes_128_gcm_sha256 __tls_cipher_suite ( 01 ) = {
|
||||
.code = htons ( TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 ),
|
||||
.key_len = ( 128 / 8 ),
|
||||
.fixed_iv_len = 4,
|
||||
.record_iv_len = 8,
|
||||
.mac_len = 0,
|
||||
.exchange = &tls_ecdhe_exchange_algorithm,
|
||||
.pubkey = &rsa_algorithm,
|
||||
.cipher = &aes_gcm_algorithm,
|
||||
.digest = &sha256_algorithm,
|
||||
.handshake = &sha256_algorithm,
|
||||
};
|
||||
45
src/crypto/mishmash/ecdhe_rsa_aes_gcm_sha384.c
Normal file
45
src/crypto/mishmash/ecdhe_rsa_aes_gcm_sha384.c
Normal file
@ -0,0 +1,45 @@
|
||||
/*
|
||||
* 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 (at your option) 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 );
|
||||
|
||||
#include <byteswap.h>
|
||||
#include <ipxe/rsa.h>
|
||||
#include <ipxe/aes.h>
|
||||
#include <ipxe/sha512.h>
|
||||
#include <ipxe/tls.h>
|
||||
|
||||
/** TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 cipher suite */
|
||||
struct tls_cipher_suite
|
||||
tls_ecdhe_rsa_with_aes_256_gcm_sha384 __tls_cipher_suite ( 02 ) = {
|
||||
.code = htons ( TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 ),
|
||||
.key_len = ( 256 / 8 ),
|
||||
.fixed_iv_len = 4,
|
||||
.record_iv_len = 8,
|
||||
.mac_len = 0,
|
||||
.exchange = &tls_ecdhe_exchange_algorithm,
|
||||
.pubkey = &rsa_algorithm,
|
||||
.cipher = &aes_gcm_algorithm,
|
||||
.digest = &sha384_algorithm,
|
||||
.handshake = &sha384_algorithm,
|
||||
};
|
||||
45
src/crypto/mishmash/oid_x25519.c
Normal file
45
src/crypto/mishmash/oid_x25519.c
Normal file
@ -0,0 +1,45 @@
|
||||
/*
|
||||
* 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 (at your option) 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 );
|
||||
|
||||
#include <byteswap.h>
|
||||
#include <ipxe/x25519.h>
|
||||
#include <ipxe/asn1.h>
|
||||
#include <ipxe/tls.h>
|
||||
|
||||
/** "x25519" object identifier */
|
||||
static uint8_t oid_x25519[] = { ASN1_OID_X25519 };
|
||||
|
||||
/** "x25519" OID-identified algorithm */
|
||||
struct asn1_algorithm x25519_algorithm __asn1_algorithm = {
|
||||
.name = "x25519",
|
||||
.curve = &x25519_curve,
|
||||
.oid = ASN1_CURSOR ( oid_x25519 ),
|
||||
};
|
||||
|
||||
/** X25519 named curve */
|
||||
struct tls_named_curve tls_x25519_named_curve __tls_named_curve ( 01 ) = {
|
||||
.curve = &x25519_curve,
|
||||
.code = htons ( TLS_NAMED_CURVE_X25519 ),
|
||||
};
|
||||
@ -30,39 +30,9 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
|
||||
#include <ipxe/sha256.h>
|
||||
#include <ipxe/tls.h>
|
||||
|
||||
/** TLS_DHE_RSA_WITH_AES_128_CBC_SHA cipher suite */
|
||||
struct tls_cipher_suite
|
||||
tls_dhe_rsa_with_aes_128_cbc_sha __tls_cipher_suite ( 05 ) = {
|
||||
.code = htons ( TLS_DHE_RSA_WITH_AES_128_CBC_SHA ),
|
||||
.key_len = ( 128 / 8 ),
|
||||
.fixed_iv_len = 0,
|
||||
.record_iv_len = AES_BLOCKSIZE,
|
||||
.mac_len = SHA1_DIGEST_SIZE,
|
||||
.exchange = &tls_dhe_exchange_algorithm,
|
||||
.pubkey = &rsa_algorithm,
|
||||
.cipher = &aes_cbc_algorithm,
|
||||
.digest = &sha1_algorithm,
|
||||
.handshake = &sha256_algorithm,
|
||||
};
|
||||
|
||||
/** TLS_DHE_RSA_WITH_AES_256_CBC_SHA cipher suite */
|
||||
struct tls_cipher_suite
|
||||
tls_dhe_rsa_with_aes_256_cbc_sha __tls_cipher_suite ( 06 ) = {
|
||||
.code = htons ( TLS_DHE_RSA_WITH_AES_256_CBC_SHA ),
|
||||
.key_len = ( 256 / 8 ),
|
||||
.fixed_iv_len = 0,
|
||||
.record_iv_len = AES_BLOCKSIZE,
|
||||
.mac_len = SHA1_DIGEST_SIZE,
|
||||
.exchange = &tls_dhe_exchange_algorithm,
|
||||
.pubkey = &rsa_algorithm,
|
||||
.cipher = &aes_cbc_algorithm,
|
||||
.digest = &sha1_algorithm,
|
||||
.handshake = &sha256_algorithm,
|
||||
};
|
||||
|
||||
/** TLS_RSA_WITH_AES_128_CBC_SHA cipher suite */
|
||||
struct tls_cipher_suite
|
||||
tls_rsa_with_aes_128_cbc_sha __tls_cipher_suite ( 15 ) = {
|
||||
tls_rsa_with_aes_128_cbc_sha __tls_cipher_suite ( 25 ) = {
|
||||
.code = htons ( TLS_RSA_WITH_AES_128_CBC_SHA ),
|
||||
.key_len = ( 128 / 8 ),
|
||||
.fixed_iv_len = 0,
|
||||
@ -77,7 +47,7 @@ tls_rsa_with_aes_128_cbc_sha __tls_cipher_suite ( 15 ) = {
|
||||
|
||||
/** TLS_RSA_WITH_AES_256_CBC_SHA cipher suite */
|
||||
struct tls_cipher_suite
|
||||
tls_rsa_with_aes_256_cbc_sha __tls_cipher_suite ( 16 ) = {
|
||||
tls_rsa_with_aes_256_cbc_sha __tls_cipher_suite ( 26 ) = {
|
||||
.code = htons ( TLS_RSA_WITH_AES_256_CBC_SHA ),
|
||||
.key_len = ( 256 / 8 ),
|
||||
.fixed_iv_len = 0,
|
||||
|
||||
@ -29,39 +29,9 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
|
||||
#include <ipxe/sha256.h>
|
||||
#include <ipxe/tls.h>
|
||||
|
||||
/** TLS_DHE_RSA_WITH_AES_128_CBC_SHA256 cipher suite */
|
||||
struct tls_cipher_suite
|
||||
tls_dhe_rsa_with_aes_128_cbc_sha256 __tls_cipher_suite ( 03 ) = {
|
||||
.code = htons ( TLS_DHE_RSA_WITH_AES_128_CBC_SHA256 ),
|
||||
.key_len = ( 128 / 8 ),
|
||||
.fixed_iv_len = 0,
|
||||
.record_iv_len = AES_BLOCKSIZE,
|
||||
.mac_len = SHA256_DIGEST_SIZE,
|
||||
.exchange = &tls_dhe_exchange_algorithm,
|
||||
.pubkey = &rsa_algorithm,
|
||||
.cipher = &aes_cbc_algorithm,
|
||||
.digest = &sha256_algorithm,
|
||||
.handshake = &sha256_algorithm,
|
||||
};
|
||||
|
||||
/** TLS_DHE_RSA_WITH_AES_256_CBC_SHA256 cipher suite */
|
||||
struct tls_cipher_suite
|
||||
tls_dhe_rsa_with_aes_256_cbc_sha256 __tls_cipher_suite ( 04 ) = {
|
||||
.code = htons ( TLS_DHE_RSA_WITH_AES_256_CBC_SHA256 ),
|
||||
.key_len = ( 256 / 8 ),
|
||||
.fixed_iv_len = 0,
|
||||
.record_iv_len = AES_BLOCKSIZE,
|
||||
.mac_len = SHA256_DIGEST_SIZE,
|
||||
.exchange = &tls_dhe_exchange_algorithm,
|
||||
.pubkey = &rsa_algorithm,
|
||||
.cipher = &aes_cbc_algorithm,
|
||||
.digest = &sha256_algorithm,
|
||||
.handshake = &sha256_algorithm,
|
||||
};
|
||||
|
||||
/** TLS_RSA_WITH_AES_128_CBC_SHA256 cipher suite */
|
||||
struct tls_cipher_suite
|
||||
tls_rsa_with_aes_128_cbc_sha256 __tls_cipher_suite ( 13 ) = {
|
||||
tls_rsa_with_aes_128_cbc_sha256 __tls_cipher_suite ( 23 ) = {
|
||||
.code = htons ( TLS_RSA_WITH_AES_128_CBC_SHA256 ),
|
||||
.key_len = ( 128 / 8 ),
|
||||
.fixed_iv_len = 0,
|
||||
@ -76,7 +46,7 @@ tls_rsa_with_aes_128_cbc_sha256 __tls_cipher_suite ( 13 ) = {
|
||||
|
||||
/** TLS_RSA_WITH_AES_256_CBC_SHA256 cipher suite */
|
||||
struct tls_cipher_suite
|
||||
tls_rsa_with_aes_256_cbc_sha256 __tls_cipher_suite ( 14 ) = {
|
||||
tls_rsa_with_aes_256_cbc_sha256 __tls_cipher_suite ( 24 ) = {
|
||||
.code = htons ( TLS_RSA_WITH_AES_256_CBC_SHA256 ),
|
||||
.key_len = ( 256 / 8 ),
|
||||
.fixed_iv_len = 0,
|
||||
|
||||
@ -29,24 +29,9 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
|
||||
#include <ipxe/sha256.h>
|
||||
#include <ipxe/tls.h>
|
||||
|
||||
/** TLS_DHE_RSA_WITH_AES_128_GCM_SHA256 cipher suite */
|
||||
struct tls_cipher_suite
|
||||
tls_dhe_rsa_with_aes_128_gcm_sha256 __tls_cipher_suite ( 01 ) = {
|
||||
.code = htons ( TLS_DHE_RSA_WITH_AES_128_GCM_SHA256 ),
|
||||
.key_len = ( 128 / 8 ),
|
||||
.fixed_iv_len = 4,
|
||||
.record_iv_len = 8,
|
||||
.mac_len = 0,
|
||||
.exchange = &tls_dhe_exchange_algorithm,
|
||||
.pubkey = &rsa_algorithm,
|
||||
.cipher = &aes_gcm_algorithm,
|
||||
.digest = &sha256_algorithm,
|
||||
.handshake = &sha256_algorithm,
|
||||
};
|
||||
|
||||
/** TLS_RSA_WITH_AES_128_GCM_SHA256 cipher suite */
|
||||
struct tls_cipher_suite
|
||||
tls_rsa_with_aes_128_gcm_sha256 __tls_cipher_suite ( 11 ) = {
|
||||
tls_rsa_with_aes_128_gcm_sha256 __tls_cipher_suite ( 21 ) = {
|
||||
.code = htons ( TLS_RSA_WITH_AES_128_GCM_SHA256 ),
|
||||
.key_len = ( 128 / 8 ),
|
||||
.fixed_iv_len = 4,
|
||||
|
||||
@ -29,24 +29,9 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
|
||||
#include <ipxe/sha512.h>
|
||||
#include <ipxe/tls.h>
|
||||
|
||||
/** TLS_DHE_RSA_WITH_AES_256_GCM_SHA384 cipher suite */
|
||||
struct tls_cipher_suite
|
||||
tls_dhe_rsa_with_aes_256_gcm_sha384 __tls_cipher_suite ( 02 ) = {
|
||||
.code = htons ( TLS_DHE_RSA_WITH_AES_256_GCM_SHA384 ),
|
||||
.key_len = ( 256 / 8 ),
|
||||
.fixed_iv_len = 4,
|
||||
.record_iv_len = 8,
|
||||
.mac_len = 0,
|
||||
.exchange = &tls_dhe_exchange_algorithm,
|
||||
.pubkey = &rsa_algorithm,
|
||||
.cipher = &aes_gcm_algorithm,
|
||||
.digest = &sha384_algorithm,
|
||||
.handshake = &sha384_algorithm,
|
||||
};
|
||||
|
||||
/** TLS_RSA_WITH_AES_256_GCM_SHA384 cipher suite */
|
||||
struct tls_cipher_suite
|
||||
tls_rsa_with_aes_256_gcm_sha384 __tls_cipher_suite ( 12 ) = {
|
||||
tls_rsa_with_aes_256_gcm_sha384 __tls_cipher_suite ( 22 ) = {
|
||||
.code = htons ( TLS_RSA_WITH_AES_256_GCM_SHA384 ),
|
||||
.key_len = ( 256 / 8 ),
|
||||
.fixed_iv_len = 4,
|
||||
|
||||
363
src/crypto/mschapv2.c
Normal file
363
src/crypto/mschapv2.c
Normal file
@ -0,0 +1,363 @@
|
||||
/*
|
||||
* 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
|
||||
*
|
||||
* MS-CHAPv2 authentication
|
||||
*
|
||||
* The algorithms used for MS-CHAPv2 authentication are defined in
|
||||
* RFC 2759 section 8.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <byteswap.h>
|
||||
#include <ipxe/md4.h>
|
||||
#include <ipxe/sha1.h>
|
||||
#include <ipxe/des.h>
|
||||
#include <ipxe/mschapv2.h>
|
||||
|
||||
/**
|
||||
* MS-CHAPv2 context block
|
||||
*
|
||||
* For no particularly discernible reason, MS-CHAPv2 uses two
|
||||
* different digest algorithms and one block cipher. The uses do not
|
||||
* overlap, so share the context storage between these to reduce stack
|
||||
* usage.
|
||||
*/
|
||||
union mschapv2_context {
|
||||
/** SHA-1 digest context */
|
||||
uint8_t sha1[SHA1_CTX_SIZE];
|
||||
/** MD4 digest context */
|
||||
uint8_t md4[MD4_CTX_SIZE];
|
||||
/** DES cipher context */
|
||||
uint8_t des[DES_CTX_SIZE];
|
||||
};
|
||||
|
||||
/**
|
||||
* MS-CHAPv2 challenge hash
|
||||
*
|
||||
* MS-CHAPv2 calculates the SHA-1 digest of the peer challenge, the
|
||||
* authenticator challenge, and the username, and then uses only the
|
||||
* first 8 bytes of the result (as a DES plaintext block).
|
||||
*/
|
||||
union mschapv2_challenge_hash {
|
||||
/** SHA-1 digest */
|
||||
uint8_t sha1[SHA1_DIGEST_SIZE];
|
||||
/** DES plaintext block */
|
||||
uint8_t des[DES_BLOCKSIZE];
|
||||
};
|
||||
|
||||
/**
|
||||
* MS-CHAPv2 password hash
|
||||
*
|
||||
* MS-CHAPv2 calculates the MD4 digest of an unspecified two-byte
|
||||
* little-endian Unicode encoding (presumably either UCS-2LE or
|
||||
* UTF-16LE) of the password.
|
||||
*
|
||||
* For constructing the challenge response, the MD4 digest is then
|
||||
* zero-padded to 21 bytes and used as three separate 56-bit DES keys.
|
||||
*
|
||||
* For constructing the authenticator response, the MD4 digest is then
|
||||
* used as an input to a SHA-1 digest along with the NT response and a
|
||||
* magic constant.
|
||||
*/
|
||||
union mschapv2_password_hash {
|
||||
/** MD4 digest */
|
||||
uint8_t md4[MD4_DIGEST_SIZE];
|
||||
/** SHA-1 digest */
|
||||
uint8_t sha1[SHA1_DIGEST_SIZE];
|
||||
/** DES keys */
|
||||
uint8_t des[3][DES_BLOCKSIZE];
|
||||
/** DES key expansion */
|
||||
uint8_t expand[ 3 * DES_BLOCKSIZE ];
|
||||
};
|
||||
|
||||
/** MS-CHAPv2 magic constant 1 */
|
||||
static const char mschapv2_magic1[39] =
|
||||
"Magic server to client signing constant";
|
||||
|
||||
/** MS-CHAPv2 magic constant 2 */
|
||||
static const char mschapv2_magic2[41] =
|
||||
"Pad to make it do more than one iteration";
|
||||
|
||||
/**
|
||||
* Calculate MS-CHAPv2 challenge hash
|
||||
*
|
||||
* @v ctx Context block
|
||||
* @v challenge Authenticator challenge
|
||||
* @v peer Peer challenge
|
||||
* @v username User name (or NULL to use empty string)
|
||||
* @v chash Challenge hash to fill in
|
||||
*
|
||||
* This is the ChallengeHash() function as documented in RFC 2759
|
||||
* section 8.2.
|
||||
*/
|
||||
static void
|
||||
mschapv2_challenge_hash ( union mschapv2_context *ctx,
|
||||
const struct mschapv2_challenge *challenge,
|
||||
const struct mschapv2_challenge *peer,
|
||||
const char *username,
|
||||
union mschapv2_challenge_hash *chash ) {
|
||||
struct digest_algorithm *sha1 = &sha1_algorithm;
|
||||
|
||||
/* Calculate SHA-1 hash of challenges and username */
|
||||
digest_init ( sha1, ctx->sha1 );
|
||||
digest_update ( sha1, ctx->sha1, peer, sizeof ( *peer ) );
|
||||
digest_update ( sha1, ctx->sha1, challenge, sizeof ( *challenge ) );
|
||||
if ( username ) {
|
||||
digest_update ( sha1, ctx->sha1, username,
|
||||
strlen ( username ) );
|
||||
}
|
||||
digest_final ( sha1, ctx->sha1, chash->sha1 );
|
||||
DBGC ( ctx, "MSCHAPv2 authenticator challenge:\n" );
|
||||
DBGC_HDA ( ctx, 0, challenge, sizeof ( *challenge ) );
|
||||
DBGC ( ctx, "MSCHAPv2 peer challenge:\n" );
|
||||
DBGC_HDA ( ctx, 0, peer, sizeof ( *peer ) );
|
||||
DBGC ( ctx, "MSCHAPv2 challenge hash:\n" );
|
||||
DBGC_HDA ( ctx, 0, chash->des, sizeof ( chash->des ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate MS-CHAPv2 password hash
|
||||
*
|
||||
* @v ctx Context block
|
||||
* @v password Password (or NULL to use empty string)
|
||||
* @v phash Password hash to fill in
|
||||
*
|
||||
* This is the NtPasswordHash() function as documented in RFC 2759
|
||||
* section 8.3.
|
||||
*/
|
||||
static void mschapv2_password_hash ( union mschapv2_context *ctx,
|
||||
const char *password,
|
||||
union mschapv2_password_hash *phash ) {
|
||||
struct digest_algorithm *md4 = &md4_algorithm;
|
||||
uint16_t wc;
|
||||
uint8_t c;
|
||||
|
||||
/* Construct zero-padded MD4 hash of encoded password */
|
||||
memset ( phash, 0, sizeof ( *phash ) );
|
||||
digest_init ( md4, ctx->md4 );
|
||||
if ( password ) {
|
||||
while ( ( c = *(password++) ) ) {
|
||||
wc = cpu_to_le16 ( c );
|
||||
digest_update ( md4, ctx->md4, &wc, sizeof ( wc ) );
|
||||
}
|
||||
}
|
||||
digest_final ( md4, ctx->md4, phash->md4 );
|
||||
DBGC ( ctx, "MSCHAPv2 password hash:\n" );
|
||||
DBGC_HDA ( ctx, 0, phash->md4, sizeof ( phash->md4 ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Hash the MS-CHAPv2 password hash
|
||||
*
|
||||
* @v ctx Context block
|
||||
* @v phash Password hash to be rehashed
|
||||
*
|
||||
* This is the HashNtPasswordHash() function as documented in RFC 2759
|
||||
* section 8.4.
|
||||
*/
|
||||
static void mschapv2_hash_hash ( union mschapv2_context *ctx,
|
||||
union mschapv2_password_hash *phash ) {
|
||||
struct digest_algorithm *md4 = &md4_algorithm;
|
||||
|
||||
/* Calculate MD4 hash of existing MD4 hash */
|
||||
digest_init ( md4, ctx->md4 );
|
||||
digest_update ( md4, ctx->md4, phash->md4, sizeof ( phash->md4 ) );
|
||||
digest_final ( md4, ctx->md4, phash->md4 );
|
||||
DBGC ( ctx, "MSCHAPv2 password hash hash:\n" );
|
||||
DBGC_HDA ( ctx, 0, phash->md4, sizeof ( phash->md4 ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Expand MS-CHAPv2 password hash by inserting DES dummy parity bits
|
||||
*
|
||||
* @v ctx Context block
|
||||
* @v phash Password hash to expand
|
||||
*
|
||||
* This is part of the DesEncrypt() function as documented in RFC 2759
|
||||
* section 8.6.
|
||||
*/
|
||||
static void mschapv2_expand_hash ( union mschapv2_context *ctx,
|
||||
union mschapv2_password_hash *phash ) {
|
||||
uint8_t *dst;
|
||||
uint8_t *src;
|
||||
unsigned int i;
|
||||
|
||||
/* Expand password hash by inserting (unused) DES parity bits */
|
||||
for ( i = ( sizeof ( phash->expand ) - 1 ) ; i > 0 ; i-- ) {
|
||||
dst = &phash->expand[i];
|
||||
src = ( dst - ( i / 8 ) );
|
||||
*dst = ( ( ( src[-1] << 8 ) | src[0] ) >> ( i % 8 ) );
|
||||
}
|
||||
DBGC ( ctx, "MSCHAPv2 expanded password hash:\n" );
|
||||
DBGC_HDA ( ctx, 0, phash->expand, sizeof ( phash->expand ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate MS-CHAPv2 challenge response
|
||||
*
|
||||
* @v ctx Context block
|
||||
* @v chash Challenge hash
|
||||
* @v phash Password hash (after expansion)
|
||||
* @v nt NT response to fill in
|
||||
*
|
||||
* This is the ChallengeResponse() function as documented in RFC 2759
|
||||
* section 8.5.
|
||||
*/
|
||||
static void
|
||||
mschapv2_challenge_response ( union mschapv2_context *ctx,
|
||||
const union mschapv2_challenge_hash *chash,
|
||||
const union mschapv2_password_hash *phash,
|
||||
struct mschapv2_nt_response *nt ) {
|
||||
struct cipher_algorithm *des = &des_algorithm;
|
||||
unsigned int i;
|
||||
int rc;
|
||||
|
||||
/* Construct response. The design of the algorithm here is
|
||||
* interesting, suggesting that an intern at Microsoft had
|
||||
* heard the phrase "Triple DES" and hazarded a blind guess at
|
||||
* what it might mean.
|
||||
*/
|
||||
for ( i = 0 ; i < ( sizeof ( phash->des ) /
|
||||
sizeof ( phash->des[0] ) ) ; i++ ) {
|
||||
rc = cipher_setkey ( des, ctx->des, phash->des[i],
|
||||
sizeof ( phash->des[i] ) );
|
||||
assert ( rc == 0 ); /* no failure mode exists */
|
||||
cipher_encrypt ( des, ctx->des, chash->des, nt->block[i],
|
||||
sizeof ( chash->des ) );
|
||||
}
|
||||
DBGC ( ctx, "MSCHAPv2 NT response:\n" );
|
||||
DBGC_HDA ( ctx, 0, nt, sizeof ( *nt ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate MS-CHAPv2 challenge response
|
||||
*
|
||||
* @v username User name (or NULL to use empty string)
|
||||
* @v password Password (or NULL to use empty string)
|
||||
* @v challenge Authenticator challenge
|
||||
* @v peer Peer challenge
|
||||
* @v response Challenge response to fill in
|
||||
*
|
||||
* This is essentially the GenerateNTResponse() function as documented
|
||||
* in RFC 2759 section 8.1.
|
||||
*/
|
||||
void mschapv2_response ( const char *username, const char *password,
|
||||
const struct mschapv2_challenge *challenge,
|
||||
const struct mschapv2_challenge *peer,
|
||||
struct mschapv2_response *response ) {
|
||||
union mschapv2_context ctx;
|
||||
union mschapv2_challenge_hash chash;
|
||||
union mschapv2_password_hash phash;
|
||||
|
||||
/* Zero reserved fields */
|
||||
memset ( response, 0, sizeof ( *response ) );
|
||||
|
||||
/* Copy peer challenge to response */
|
||||
memcpy ( &response->peer, peer, sizeof ( response->peer ) );
|
||||
|
||||
/* Construct challenge hash */
|
||||
mschapv2_challenge_hash ( &ctx, challenge, peer, username, &chash );
|
||||
|
||||
/* Construct expanded password hash */
|
||||
mschapv2_password_hash ( &ctx, password, &phash );
|
||||
mschapv2_expand_hash ( &ctx, &phash );
|
||||
|
||||
/* Construct NT response */
|
||||
mschapv2_challenge_response ( &ctx, &chash, &phash, &response->nt );
|
||||
DBGC ( &ctx, "MSCHAPv2 challenge response:\n" );
|
||||
DBGC_HDA ( &ctx, 0, response, sizeof ( *response ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate MS-CHAPv2 authenticator response
|
||||
*
|
||||
* @v username User name (or NULL to use empty string)
|
||||
* @v password Password (or NULL to use empty string)
|
||||
* @v challenge Authenticator challenge
|
||||
* @v response Challenge response
|
||||
* @v auth Authenticator response to fill in
|
||||
*
|
||||
* This is essentially the GenerateAuthenticatorResponse() function as
|
||||
* documented in RFC 2759 section 8.7.
|
||||
*/
|
||||
void mschapv2_auth ( const char *username, const char *password,
|
||||
const struct mschapv2_challenge *challenge,
|
||||
const struct mschapv2_response *response,
|
||||
struct mschapv2_auth *auth ) {
|
||||
struct digest_algorithm *sha1 = &sha1_algorithm;
|
||||
union mschapv2_context ctx;
|
||||
union mschapv2_challenge_hash chash;
|
||||
union mschapv2_password_hash phash;
|
||||
char tmp[3];
|
||||
char *wtf;
|
||||
unsigned int i;
|
||||
|
||||
/* Construct hash of password hash */
|
||||
mschapv2_password_hash ( &ctx, password, &phash );
|
||||
mschapv2_hash_hash ( &ctx, &phash );
|
||||
|
||||
/* Construct unnamed intermediate hash */
|
||||
digest_init ( sha1, ctx.sha1 );
|
||||
digest_update ( sha1, ctx.sha1, phash.md4, sizeof ( phash.md4 ) );
|
||||
digest_update ( sha1, ctx.sha1, &response->nt,
|
||||
sizeof ( response->nt ) );
|
||||
digest_update ( sha1, ctx.sha1, mschapv2_magic1,
|
||||
sizeof ( mschapv2_magic1 ) );
|
||||
digest_final ( sha1, ctx.sha1, phash.sha1 );
|
||||
DBGC ( &ctx, "MSCHAPv2 NT response:\n" );
|
||||
DBGC_HDA ( &ctx, 0, &response->nt, sizeof ( response->nt ) );
|
||||
DBGC ( &ctx, "MSCHAPv2 unnamed intermediate hash:\n" );
|
||||
DBGC_HDA ( &ctx, 0, phash.sha1, sizeof ( phash.sha1 ) );
|
||||
|
||||
/* Construct challenge hash */
|
||||
mschapv2_challenge_hash ( &ctx, challenge, &response->peer,
|
||||
username, &chash );
|
||||
|
||||
/* Construct authenticator response hash */
|
||||
digest_init ( sha1, ctx.sha1 );
|
||||
digest_update ( sha1, ctx.sha1, phash.sha1, sizeof ( phash.sha1 ) );
|
||||
digest_update ( sha1, ctx.sha1, chash.des, sizeof ( chash.des ) );
|
||||
digest_update ( sha1, ctx.sha1, mschapv2_magic2,
|
||||
sizeof ( mschapv2_magic2 ) );
|
||||
digest_final ( sha1, ctx.sha1, phash.sha1 );
|
||||
DBGC ( &ctx, "MSCHAPv2 authenticator response hash:\n" );
|
||||
DBGC_HDA ( &ctx, 0, phash.sha1, sizeof ( phash.sha1 ) );
|
||||
|
||||
/* Encode authenticator response hash */
|
||||
wtf = auth->wtf;
|
||||
*(wtf++) = 'S';
|
||||
*(wtf++) = '=';
|
||||
DBGC ( &ctx, "MSCHAPv2 authenticator response: S=" );
|
||||
for ( i = 0 ; i < sizeof ( phash.sha1 ) ; i++ ) {
|
||||
snprintf ( tmp, sizeof ( tmp ), "%02X", phash.sha1[i] );
|
||||
*(wtf++) = tmp[0];
|
||||
*(wtf++) = tmp[1];
|
||||
DBGC ( &ctx, "%s", tmp );
|
||||
}
|
||||
DBGC ( &ctx, "\n" );
|
||||
}
|
||||
@ -145,12 +145,12 @@ static void sha1_digest ( struct sha1_context *context ) {
|
||||
|
||||
/* Sanity checks */
|
||||
assert ( ( context->len % sizeof ( context->ddd.dd.data ) ) == 0 );
|
||||
linker_assert ( &u.ddd.dd.digest.h[0] == a, sha1_bad_layout );
|
||||
linker_assert ( &u.ddd.dd.digest.h[1] == b, sha1_bad_layout );
|
||||
linker_assert ( &u.ddd.dd.digest.h[2] == c, sha1_bad_layout );
|
||||
linker_assert ( &u.ddd.dd.digest.h[3] == d, sha1_bad_layout );
|
||||
linker_assert ( &u.ddd.dd.digest.h[4] == e, sha1_bad_layout );
|
||||
linker_assert ( &u.ddd.dd.data.dword[0] == w, sha1_bad_layout );
|
||||
build_assert ( &u.ddd.dd.digest.h[0] == a );
|
||||
build_assert ( &u.ddd.dd.digest.h[1] == b );
|
||||
build_assert ( &u.ddd.dd.digest.h[2] == c );
|
||||
build_assert ( &u.ddd.dd.digest.h[3] == d );
|
||||
build_assert ( &u.ddd.dd.digest.h[4] == e );
|
||||
build_assert ( &u.ddd.dd.data.dword[0] == w );
|
||||
|
||||
DBGC ( context, "SHA1 digesting:\n" );
|
||||
DBGC_HDA ( context, 0, &context->ddd.dd.digest,
|
||||
|
||||
@ -140,15 +140,15 @@ static void sha256_digest ( struct sha256_context *context ) {
|
||||
|
||||
/* Sanity checks */
|
||||
assert ( ( context->len % sizeof ( context->ddd.dd.data ) ) == 0 );
|
||||
linker_assert ( &u.ddd.dd.digest.h[0] == a, sha256_bad_layout );
|
||||
linker_assert ( &u.ddd.dd.digest.h[1] == b, sha256_bad_layout );
|
||||
linker_assert ( &u.ddd.dd.digest.h[2] == c, sha256_bad_layout );
|
||||
linker_assert ( &u.ddd.dd.digest.h[3] == d, sha256_bad_layout );
|
||||
linker_assert ( &u.ddd.dd.digest.h[4] == e, sha256_bad_layout );
|
||||
linker_assert ( &u.ddd.dd.digest.h[5] == f, sha256_bad_layout );
|
||||
linker_assert ( &u.ddd.dd.digest.h[6] == g, sha256_bad_layout );
|
||||
linker_assert ( &u.ddd.dd.digest.h[7] == h, sha256_bad_layout );
|
||||
linker_assert ( &u.ddd.dd.data.dword[0] == w, sha256_bad_layout );
|
||||
build_assert ( &u.ddd.dd.digest.h[0] == a );
|
||||
build_assert ( &u.ddd.dd.digest.h[1] == b );
|
||||
build_assert ( &u.ddd.dd.digest.h[2] == c );
|
||||
build_assert ( &u.ddd.dd.digest.h[3] == d );
|
||||
build_assert ( &u.ddd.dd.digest.h[4] == e );
|
||||
build_assert ( &u.ddd.dd.digest.h[5] == f );
|
||||
build_assert ( &u.ddd.dd.digest.h[6] == g );
|
||||
build_assert ( &u.ddd.dd.digest.h[7] == h );
|
||||
build_assert ( &u.ddd.dd.data.dword[0] == w );
|
||||
|
||||
DBGC ( context, "SHA256 digesting:\n" );
|
||||
DBGC_HDA ( context, 0, &context->ddd.dd.digest,
|
||||
|
||||
@ -156,15 +156,15 @@ static void sha512_digest ( struct sha512_context *context ) {
|
||||
|
||||
/* Sanity checks */
|
||||
assert ( ( context->len % sizeof ( context->ddq.dd.data ) ) == 0 );
|
||||
linker_assert ( &u.ddq.dd.digest.h[0] == a, sha512_bad_layout );
|
||||
linker_assert ( &u.ddq.dd.digest.h[1] == b, sha512_bad_layout );
|
||||
linker_assert ( &u.ddq.dd.digest.h[2] == c, sha512_bad_layout );
|
||||
linker_assert ( &u.ddq.dd.digest.h[3] == d, sha512_bad_layout );
|
||||
linker_assert ( &u.ddq.dd.digest.h[4] == e, sha512_bad_layout );
|
||||
linker_assert ( &u.ddq.dd.digest.h[5] == f, sha512_bad_layout );
|
||||
linker_assert ( &u.ddq.dd.digest.h[6] == g, sha512_bad_layout );
|
||||
linker_assert ( &u.ddq.dd.digest.h[7] == h, sha512_bad_layout );
|
||||
linker_assert ( &u.ddq.dd.data.qword[0] == w, sha512_bad_layout );
|
||||
build_assert ( &u.ddq.dd.digest.h[0] == a );
|
||||
build_assert ( &u.ddq.dd.digest.h[1] == b );
|
||||
build_assert ( &u.ddq.dd.digest.h[2] == c );
|
||||
build_assert ( &u.ddq.dd.digest.h[3] == d );
|
||||
build_assert ( &u.ddq.dd.digest.h[4] == e );
|
||||
build_assert ( &u.ddq.dd.digest.h[5] == f );
|
||||
build_assert ( &u.ddq.dd.digest.h[6] == g );
|
||||
build_assert ( &u.ddq.dd.digest.h[7] == h );
|
||||
build_assert ( &u.ddq.dd.data.qword[0] == w );
|
||||
|
||||
DBGC ( context, "SHA512 digesting:\n" );
|
||||
DBGC_HDA ( context, 0, &context->ddq.dd.digest,
|
||||
|
||||
844
src/crypto/x25519.c
Normal file
844
src/crypto/x25519.c
Normal file
@ -0,0 +1,844 @@
|
||||
/*
|
||||
* 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
|
||||
*
|
||||
* X25519 key exchange
|
||||
*
|
||||
* This implementation is inspired by and partially based upon the
|
||||
* paper "Implementing Curve25519/X25519: A Tutorial on Elliptic Curve
|
||||
* Cryptography" by Martin Kleppmann, available for download from
|
||||
* https://www.cl.cam.ac.uk/teaching/2122/Crypto/curve25519.pdf
|
||||
*
|
||||
* The underlying modular addition, subtraction, and multiplication
|
||||
* operations are completely redesigned for substantially improved
|
||||
* efficiency compared to the TweetNaCl implementation studied in that
|
||||
* paper.
|
||||
*
|
||||
* TweetNaCl iPXE
|
||||
* --------- ----
|
||||
*
|
||||
* Storage size of each big integer 128 40
|
||||
* (in bytes)
|
||||
*
|
||||
* Stack usage for key exchange 1144 360
|
||||
* (in bytes, large objects only)
|
||||
*
|
||||
* Cost of big integer addition 16 5
|
||||
* (in number of 64-bit additions)
|
||||
*
|
||||
* Cost of big integer multiplication 273 31
|
||||
* (in number of 64-bit multiplications)
|
||||
*
|
||||
* The implementation is constant-time (provided that the underlying
|
||||
* big integer operations are also constant-time).
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
#include <ipxe/init.h>
|
||||
#include <ipxe/crypto.h>
|
||||
#include <ipxe/x25519.h>
|
||||
|
||||
/** X25519 reduction constant
|
||||
*
|
||||
* The X25519 field prime is p=2^255-19. This gives us:
|
||||
*
|
||||
* p = 2^255 - 19
|
||||
* 2^255 = p + 19
|
||||
* 2^255 = 19 (mod p)
|
||||
* k * 2^255 = k * 19 (mod p)
|
||||
*
|
||||
* We can therefore reduce a value modulo p by taking the high-order
|
||||
* bits of the value from bit 255 and above, multiplying by 19, and
|
||||
* adding this to the low-order 255 bits of the value.
|
||||
*
|
||||
* This would be cumbersome to do in practice since it would require
|
||||
* partitioning the value at a 255-bit boundary (and hence would
|
||||
* require some shifting and masking operations). However, we can
|
||||
* note that:
|
||||
*
|
||||
* k * 2^255 = k * 19 (mod p)
|
||||
* k * 2 * 2^255 = k * 2 * 19 (mod p)
|
||||
* k * 2^256 = k * 38 (mod p)
|
||||
*
|
||||
* We can therefore simplify the reduction to taking the high order
|
||||
* bits of the value from bit 256 and above, multiplying by 38, and
|
||||
* adding this to the low-order 256 bits of the value.
|
||||
*
|
||||
* Since 256 will inevitably be a multiple of the big integer element
|
||||
* size (typically 32 or 64 bits), this avoids the need to perform any
|
||||
* shifting or masking operations.
|
||||
*/
|
||||
#define X25519_REDUCE_256 38
|
||||
|
||||
/** X25519 multiplication step 1 result
|
||||
*
|
||||
* Step 1 of X25519 multiplication is to compute the product of two
|
||||
* X25519 unsigned 258-bit integers.
|
||||
*
|
||||
* Both multiplication inputs are limited to 258 bits, and so the
|
||||
* product will have at most 516 bits.
|
||||
*/
|
||||
union x25519_multiply_step1 {
|
||||
/** Raw product
|
||||
*
|
||||
* Big integer multiplication produces a result with a number
|
||||
* of elements equal to the sum of the number of elements in
|
||||
* each input.
|
||||
*/
|
||||
bigint_t ( X25519_SIZE + X25519_SIZE ) product;
|
||||
/** Partition into low-order and high-order bits
|
||||
*
|
||||
* Reduction modulo p requires separating the low-order 256
|
||||
* bits from the remaining high-order bits.
|
||||
*
|
||||
* Since the value will never exceed 516 bits (see above),
|
||||
* there will be at most 260 high-order bits.
|
||||
*/
|
||||
struct {
|
||||
/** Low-order 256 bits */
|
||||
bigint_t ( bigint_required_size ( ( 256 /* bits */ + 7 ) / 8 ) )
|
||||
low_256bit;
|
||||
/** High-order 260 bits */
|
||||
bigint_t ( bigint_required_size ( ( 260 /* bits */ + 7 ) / 8 ) )
|
||||
high_260bit;
|
||||
} __attribute__ (( packed )) parts;
|
||||
};
|
||||
|
||||
/** X25519 multiplication step 2 result
|
||||
*
|
||||
* Step 2 of X25519 multiplication is to multiply the high-order 260
|
||||
* bits from step 1 with the 6-bit reduction constant 38, and to add
|
||||
* this to the low-order 256 bits from step 1.
|
||||
*
|
||||
* The multiplication inputs are limited to 260 and 6 bits
|
||||
* respectively, and so the product will have at most 266 bits. After
|
||||
* adding the low-order 256 bits from step 1, the result will have at
|
||||
* most 267 bits.
|
||||
*/
|
||||
union x25519_multiply_step2 {
|
||||
/** Raw product
|
||||
*
|
||||
* Big integer multiplication produces a result with a number
|
||||
* of elements equal to the sum of the number of elements in
|
||||
* each input.
|
||||
*/
|
||||
bigint_t ( bigint_required_size ( ( 260 /* bits */ + 7 ) / 8 ) +
|
||||
bigint_required_size ( ( 6 /* bits */ + 7 ) / 8 ) ) product;
|
||||
/** Big integer value
|
||||
*
|
||||
* The value will never exceed 267 bits (see above), and so
|
||||
* may be consumed as a normal X25519 big integer.
|
||||
*/
|
||||
x25519_t value;
|
||||
/** Partition into low-order and high-order bits
|
||||
*
|
||||
* Reduction modulo p requires separating the low-order 256
|
||||
* bits from the remaining high-order bits.
|
||||
*
|
||||
* Since the value will never exceed 267 bits (see above),
|
||||
* there will be at most 11 high-order bits.
|
||||
*/
|
||||
struct {
|
||||
/** Low-order 256 bits */
|
||||
bigint_t ( bigint_required_size ( ( 256 /* bits */ + 7 ) / 8 ) )
|
||||
low_256bit;
|
||||
/** High-order 11 bits */
|
||||
bigint_t ( bigint_required_size ( ( 11 /* bits */ + 7 ) / 8 ) )
|
||||
high_11bit;
|
||||
} __attribute__ (( packed )) parts;
|
||||
};
|
||||
|
||||
/** X25519 multiplication step 3 result
|
||||
*
|
||||
* Step 3 of X25519 multiplication is to multiply the high-order 11
|
||||
* bits from step 2 with the 6-bit reduction constant 38, and to add
|
||||
* this to the low-order 256 bits from step 2.
|
||||
*
|
||||
* The multiplication inputs are limited to 11 and 6 bits
|
||||
* respectively, and so the product will have at most 17 bits. After
|
||||
* adding the low-order 256 bits from step 2, the result will have at
|
||||
* most 257 bits.
|
||||
*/
|
||||
union x25519_multiply_step3 {
|
||||
/** Raw product
|
||||
*
|
||||
* Big integer multiplication produces a result with a number
|
||||
* of elements equal to the sum of the number of elements in
|
||||
* each input.
|
||||
*/
|
||||
bigint_t ( bigint_required_size ( ( 11 /* bits */ + 7 ) / 8 ) +
|
||||
bigint_required_size ( ( 6 /* bits */ + 7 ) / 8 ) ) product;
|
||||
/** Big integer value
|
||||
*
|
||||
* The value will never exceed 267 bits (see above), and so
|
||||
* may be consumed as a normal X25519 big integer.
|
||||
*/
|
||||
x25519_t value;
|
||||
};
|
||||
|
||||
/** X25519 multiplication temporary working space
|
||||
*
|
||||
* We overlap the buffers used by each step of the multiplication
|
||||
* calculation to reduce the total stack space required:
|
||||
*
|
||||
* |--------------------------------------------------------|
|
||||
* | <- pad -> | <------------ step 1 result -------------> |
|
||||
* | | <- low 256 bits -> | <-- high 260 bits --> |
|
||||
* | <------- step 2 result ------> | <-- step 3 result --> |
|
||||
* |--------------------------------------------------------|
|
||||
*/
|
||||
union x25519_multiply_workspace {
|
||||
/** Step 1 result */
|
||||
struct {
|
||||
/** Padding to avoid collision between steps 1 and 2
|
||||
*
|
||||
* The step 2 multiplication consumes the high 260
|
||||
* bits of step 1, and so the step 2 multiplication
|
||||
* result must not overlap this portion of the step 1
|
||||
* result.
|
||||
*/
|
||||
uint8_t pad[ sizeof ( union x25519_multiply_step2 ) -
|
||||
offsetof ( union x25519_multiply_step1,
|
||||
parts.high_260bit ) ];
|
||||
/** Step 1 result */
|
||||
union x25519_multiply_step1 step1;
|
||||
} __attribute__ (( packed ));
|
||||
/** Steps 2 and 3 results */
|
||||
struct {
|
||||
/** Step 2 result */
|
||||
union x25519_multiply_step2 step2;
|
||||
/** Step 3 result */
|
||||
union x25519_multiply_step3 step3;
|
||||
} __attribute__ (( packed ));
|
||||
};
|
||||
|
||||
/** An X25519 elliptic curve point in projective coordinates
|
||||
*
|
||||
* A point (x,y) on the Montgomery curve used in X25519 is represented
|
||||
* using projective coordinates (X/Z,Y/Z) so that intermediate
|
||||
* calculations may be performed on both numerator and denominator
|
||||
* separately, with the division step performed only once at the end
|
||||
* of the calculation.
|
||||
*
|
||||
* The group operation calculation is performed using a Montgomery
|
||||
* ladder as:
|
||||
*
|
||||
* X[2i] = ( X[i]^2 - Z[i]^2 )^2
|
||||
* X[2i+1] = ( X[i] * X[i+1] - Z[i] * Z[i+1] )^2
|
||||
* Z[2i] = 4 * X[i] * Z[i] * ( X[i]^2 + A * X[i] * Z[i] + Z[i]^2 )
|
||||
* Z[2i+1] = X[0] * ( X[i] * Z[i+1] - X[i+1] * Z[i] ) ^ 2
|
||||
*
|
||||
* It is therefore not necessary to store (or use) the value of Y.
|
||||
*/
|
||||
struct x25519_projective {
|
||||
/** X coordinate */
|
||||
union x25519_quad257 X;
|
||||
/** Z coordinate */
|
||||
union x25519_quad257 Z;
|
||||
};
|
||||
|
||||
/** An X25519 Montgomery ladder step */
|
||||
struct x25519_step {
|
||||
/** X[n]/Z[n] */
|
||||
struct x25519_projective x_n;
|
||||
/** X[n+1]/Z[n+1] */
|
||||
struct x25519_projective x_n1;
|
||||
};
|
||||
|
||||
/** Constant p=2^255-19 (the finite field prime) */
|
||||
static const uint8_t x25519_p_raw[] = {
|
||||
0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xed
|
||||
};
|
||||
|
||||
/** Constant p=2^255-19 (the finite field prime) */
|
||||
static x25519_t x25519_p;
|
||||
|
||||
/** Constant 2p=2^256-38 */
|
||||
static x25519_t x25519_2p;
|
||||
|
||||
/** Constant 4p=2^257-76 */
|
||||
static x25519_t x25519_4p;
|
||||
|
||||
/** Reduction constant (used during multiplication) */
|
||||
static const uint8_t x25519_reduce_256_raw[] = { X25519_REDUCE_256 };
|
||||
|
||||
/** Reduction constant (used during multiplication) */
|
||||
static bigint_t ( bigint_required_size ( sizeof ( x25519_reduce_256_raw ) ) )
|
||||
x25519_reduce_256;
|
||||
|
||||
/** Constant 121665 (used in the Montgomery ladder) */
|
||||
static const uint8_t x25519_121665_raw[] = { 0x01, 0xdb, 0x41 };
|
||||
|
||||
/** Constant 121665 (used in the Montgomery ladder) */
|
||||
static union x25519_oct258 x25519_121665;
|
||||
|
||||
/** Constant g=9 (the group generator) */
|
||||
static struct x25519_value x25519_generator = {
|
||||
.raw = { 9, }
|
||||
};
|
||||
|
||||
/**
|
||||
* Initialise constants
|
||||
*
|
||||
*/
|
||||
static void x25519_init_constants ( void ) {
|
||||
|
||||
/* Construct constant p */
|
||||
bigint_init ( &x25519_p, x25519_p_raw, sizeof ( x25519_p_raw ) );
|
||||
|
||||
/* Construct constant 2p */
|
||||
bigint_copy ( &x25519_p, &x25519_2p );
|
||||
bigint_add ( &x25519_p, &x25519_2p );
|
||||
|
||||
/* Construct constant 4p */
|
||||
bigint_copy ( &x25519_2p, &x25519_4p );
|
||||
bigint_add ( &x25519_2p, &x25519_4p );
|
||||
|
||||
/* Construct reduction constant */
|
||||
bigint_init ( &x25519_reduce_256, x25519_reduce_256_raw,
|
||||
sizeof ( x25519_reduce_256_raw ) );
|
||||
|
||||
/* Construct constant 121665 */
|
||||
bigint_init ( &x25519_121665.value, x25519_121665_raw,
|
||||
sizeof ( x25519_121665_raw ) );
|
||||
}
|
||||
|
||||
/** Initialisation function */
|
||||
struct init_fn x25519_init_fn __init_fn ( INIT_NORMAL ) = {
|
||||
.initialise = x25519_init_constants,
|
||||
};
|
||||
|
||||
/**
|
||||
* Add big integers modulo field prime
|
||||
*
|
||||
* @v augend Big integer to add
|
||||
* @v addend Big integer to add
|
||||
* @v result Big integer to hold result (may overlap augend)
|
||||
*/
|
||||
static inline __attribute__ (( always_inline )) void
|
||||
x25519_add ( const union x25519_quad257 *augend,
|
||||
const union x25519_quad257 *addend,
|
||||
union x25519_oct258 *result ) {
|
||||
int copy;
|
||||
|
||||
/* Copy augend if necessary */
|
||||
copy = ( result != &augend->oct258 );
|
||||
build_assert ( __builtin_constant_p ( copy ) );
|
||||
if ( copy ) {
|
||||
build_assert ( result != &addend->oct258 );
|
||||
bigint_copy ( &augend->oct258.value, &result->value );
|
||||
}
|
||||
|
||||
/* Perform addition
|
||||
*
|
||||
* Both inputs are in the range [0,4p-1] and the resulting
|
||||
* sum is therefore in the range [0,8p-2].
|
||||
*
|
||||
* This range lies within the range [0,8p-1] and the result is
|
||||
* therefore a valid X25519 unsigned 258-bit integer, as
|
||||
* required.
|
||||
*/
|
||||
bigint_add ( &addend->value, &result->value );
|
||||
}
|
||||
|
||||
/**
|
||||
* Subtract big integers modulo field prime
|
||||
*
|
||||
* @v minuend Big integer from which to subtract
|
||||
* @v subtrahend Big integer to subtract
|
||||
* @v result Big integer to hold result (may overlap minuend)
|
||||
*/
|
||||
static inline __attribute__ (( always_inline )) void
|
||||
x25519_subtract ( const union x25519_quad257 *minuend,
|
||||
const union x25519_quad257 *subtrahend,
|
||||
union x25519_oct258 *result ) {
|
||||
int copy;
|
||||
|
||||
/* Copy minuend if necessary */
|
||||
copy = ( result != &minuend->oct258 );
|
||||
build_assert ( __builtin_constant_p ( copy ) );
|
||||
if ( copy ) {
|
||||
build_assert ( result != &subtrahend->oct258 );
|
||||
bigint_copy ( &minuend->oct258.value, &result->value );
|
||||
}
|
||||
|
||||
/* Perform subtraction
|
||||
*
|
||||
* Both inputs are in the range [0,4p-1] and the resulting
|
||||
* difference is therefore in the range [1-4p,4p-1].
|
||||
*
|
||||
* This range lies partially outside the range [0,8p-1] and
|
||||
* the result is therefore not yet a valid X25519 unsigned
|
||||
* 258-bit integer.
|
||||
*/
|
||||
bigint_subtract ( &subtrahend->value, &result->value );
|
||||
|
||||
/* Add constant multiple of field prime p
|
||||
*
|
||||
* Add the constant 4p to the result. This brings the result
|
||||
* within the range [1,8p-1] (without changing the value
|
||||
* modulo p).
|
||||
*
|
||||
* This range lies within the range [0,8p-1] and the result is
|
||||
* therefore now a valid X25519 unsigned 258-bit integer, as
|
||||
* required.
|
||||
*/
|
||||
bigint_add ( &x25519_4p, &result->value );
|
||||
}
|
||||
|
||||
/**
|
||||
* Multiply big integers modulo field prime
|
||||
*
|
||||
* @v multiplicand Big integer to be multiplied
|
||||
* @v multiplier Big integer to be multiplied
|
||||
* @v result Big integer to hold result (may overlap either input)
|
||||
*/
|
||||
void x25519_multiply ( const union x25519_oct258 *multiplicand,
|
||||
const union x25519_oct258 *multiplier,
|
||||
union x25519_quad257 *result ) {
|
||||
union x25519_multiply_workspace tmp;
|
||||
union x25519_multiply_step1 *step1 = &tmp.step1;
|
||||
union x25519_multiply_step2 *step2 = &tmp.step2;
|
||||
union x25519_multiply_step3 *step3 = &tmp.step3;
|
||||
|
||||
/* Step 1: perform raw multiplication
|
||||
*
|
||||
* step1 = multiplicand * multiplier
|
||||
*
|
||||
* Both inputs are 258-bit numbers and the step 1 result is
|
||||
* therefore 258+258=516 bits.
|
||||
*/
|
||||
static_assert ( sizeof ( step1->product ) >= sizeof ( step1->parts ) );
|
||||
bigint_multiply ( &multiplicand->value, &multiplier->value,
|
||||
&step1->product );
|
||||
|
||||
/* Step 2: reduce high-order 516-256=260 bits of step 1 result
|
||||
*
|
||||
* Use the identity 2^256=38 (mod p) to reduce the high-order
|
||||
* bits of the step 1 result. We split the 516-bit result
|
||||
* from step 1 into its low-order 256 bits and high-order 260
|
||||
* bits:
|
||||
*
|
||||
* step1 = step1(low 256 bits) + step1(high 260 bits) * 2^256
|
||||
*
|
||||
* and then perform the calculation:
|
||||
*
|
||||
* step2 = step1 (mod p)
|
||||
* = step1(low 256 bits) + step1(high 260 bits) * 2^256 (mod p)
|
||||
* = step1(low 256 bits) + step1(high 260 bits) * 38 (mod p)
|
||||
*
|
||||
* There are 6 bits in the constant value 38. The step 2
|
||||
* multiplication product will therefore have 260+6=266 bits,
|
||||
* and the step 2 result (after the addition) will therefore
|
||||
* have 267 bits.
|
||||
*/
|
||||
static_assert ( sizeof ( step2->product ) >= sizeof ( step2->value ) );
|
||||
static_assert ( sizeof ( step2->product ) >= sizeof ( step2->parts ) );
|
||||
bigint_grow ( &step1->parts.low_256bit, &result->value );
|
||||
bigint_multiply ( &step1->parts.high_260bit, &x25519_reduce_256,
|
||||
&step2->product );
|
||||
bigint_add ( &result->value, &step2->value );
|
||||
|
||||
/* Step 3: reduce high-order 267-256=11 bits of step 2 result
|
||||
*
|
||||
* Use the identity 2^256=38 (mod p) again to reduce the
|
||||
* high-order bits of the step 2 result. As before, we split
|
||||
* the 267-bit result from step 2 into its low-order 256 bits
|
||||
* and high-order 11 bits:
|
||||
*
|
||||
* step2 = step2(low 256 bits) + step2(high 11 bits) * 2^256
|
||||
*
|
||||
* and then perform the calculation:
|
||||
*
|
||||
* step3 = step2 (mod p)
|
||||
* = step2(low 256 bits) + step2(high 11 bits) * 2^256 (mod p)
|
||||
* = step2(low 256 bits) + step2(high 11 bits) * 38 (mod p)
|
||||
*
|
||||
* There are 6 bits in the constant value 38. The step 3
|
||||
* multiplication product will therefore have 11+6=19 bits,
|
||||
* and the step 3 result (after the addition) will therefore
|
||||
* have 257 bits.
|
||||
*
|
||||
* A loose upper bound for the step 3 result (after the
|
||||
* addition) is given by:
|
||||
*
|
||||
* step3 < ( 2^256 - 1 ) + ( 2^19 - 1 )
|
||||
* < ( 2^257 - 2^256 - 1 ) + ( 2^19 - 1 )
|
||||
* < ( 2^257 - 76 ) - 2^256 + 2^19 + 74
|
||||
* < 4 * ( 2^255 - 19 ) - 2^256 + 2^19 + 74
|
||||
* < 4p - 2^256 + 2^19 + 74
|
||||
*
|
||||
* and so the step 3 result is strictly less than 4p, and
|
||||
* therefore lies within the range [0,4p-1].
|
||||
*/
|
||||
memset ( &step3->value, 0, sizeof ( step3->value ) );
|
||||
bigint_grow ( &step2->parts.low_256bit, &result->value );
|
||||
bigint_multiply ( &step2->parts.high_11bit, &x25519_reduce_256,
|
||||
&step3->product );
|
||||
bigint_add ( &step3->value, &result->value );
|
||||
|
||||
/* Step 1 calculates the product of the input operands, and
|
||||
* each subsequent step reduces the number of bits in the
|
||||
* result while preserving this value (modulo p). The final
|
||||
* result is therefore equal to the product of the input
|
||||
* operands (modulo p), as required.
|
||||
*
|
||||
* The step 3 result lies within the range [0,4p-1] and the
|
||||
* final result is therefore a valid X25519 unsigned 257-bit
|
||||
* integer, as required.
|
||||
*/
|
||||
}
|
||||
|
||||
/**
|
||||
* Compute multiplicative inverse
|
||||
*
|
||||
* @v invertend Big integer to be inverted
|
||||
* @v result Big integer to hold result (may not overlap input)
|
||||
*/
|
||||
void x25519_invert ( const union x25519_oct258 *invertend,
|
||||
union x25519_quad257 *result ) {
|
||||
int i;
|
||||
|
||||
/* Sanity check */
|
||||
assert ( invertend != &result->oct258 );
|
||||
|
||||
/* Calculate inverse as x^(-1)=x^(p-2) where p is the field prime
|
||||
*
|
||||
* The field prime is p=2^255-19 and so:
|
||||
*
|
||||
* p - 2 = 2^255 - 21
|
||||
* = (2^255 - 1) - 2^4 - 2^2
|
||||
*
|
||||
* i.e. p-2 is a 254-bit number in which all bits are set
|
||||
* apart from bit 2 and bit 4.
|
||||
*
|
||||
* We use the square-and-multiply method to compute x^(p-2).
|
||||
*/
|
||||
bigint_copy ( &invertend->value, &result->value );
|
||||
for ( i = 253 ; i >= 0 ; i-- ) {
|
||||
|
||||
/* Square running total */
|
||||
x25519_multiply ( &result->oct258, &result->oct258, result );
|
||||
|
||||
/* For each set bit in the exponent, multiply by invertend */
|
||||
if ( ( i != 2 ) && ( i != 4 ) ) {
|
||||
x25519_multiply ( invertend, &result->oct258, result );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Reduce big integer via conditional subtraction
|
||||
*
|
||||
* @v subtrahend Big integer to subtract
|
||||
* @v value Big integer to be subtracted from, if possible
|
||||
*/
|
||||
static void x25519_reduce_by ( const x25519_t *subtrahend, x25519_t *value ) {
|
||||
unsigned int max_bit = ( ( 8 * sizeof ( *value ) ) - 1 );
|
||||
x25519_t tmp;
|
||||
|
||||
/* Conditionally subtract subtrahend
|
||||
*
|
||||
* Subtract the subtrahend, discarding the result (in constant
|
||||
* time) if the subtraction underflows.
|
||||
*/
|
||||
bigint_copy ( value, &tmp );
|
||||
bigint_subtract ( subtrahend, value );
|
||||
bigint_swap ( value, &tmp, bigint_bit_is_set ( value, max_bit ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Reduce big integer to canonical range
|
||||
*
|
||||
* @v value Big integer to be reduced
|
||||
*/
|
||||
void x25519_reduce ( union x25519_quad257 *value ) {
|
||||
|
||||
/* Conditionally subtract 2p
|
||||
*
|
||||
* Subtract twice the field prime, discarding the result (in
|
||||
* constant time) if the subtraction underflows.
|
||||
*
|
||||
* The input value is in the range [0,4p-1]. After this
|
||||
* conditional subtraction, the value is in the range
|
||||
* [0,2p-1].
|
||||
*/
|
||||
x25519_reduce_by ( &x25519_2p, &value->value );
|
||||
|
||||
/* Conditionally subtract p
|
||||
*
|
||||
* Subtract the field prime, discarding the result (in
|
||||
* constant time) if the subtraction underflows.
|
||||
*
|
||||
* The value is already in the range [0,2p-1]. After this
|
||||
* conditional subtraction, the value is in the range [0,p-1]
|
||||
* and is therefore the canonical representation.
|
||||
*/
|
||||
x25519_reduce_by ( &x25519_p, &value->value );
|
||||
}
|
||||
|
||||
/**
|
||||
* Compute next step of the Montgomery ladder
|
||||
*
|
||||
* @v base Base point
|
||||
* @v bit Bit value
|
||||
* @v step Ladder step
|
||||
*/
|
||||
static void x25519_step ( const union x25519_quad257 *base, int bit,
|
||||
struct x25519_step *step ) {
|
||||
union x25519_quad257 *a = &step->x_n.X;
|
||||
union x25519_quad257 *b = &step->x_n1.X;
|
||||
union x25519_quad257 *c = &step->x_n.Z;
|
||||
union x25519_quad257 *d = &step->x_n1.Z;
|
||||
union x25519_oct258 e;
|
||||
union x25519_quad257 f;
|
||||
union x25519_oct258 *v1_e;
|
||||
union x25519_oct258 *v2_a;
|
||||
union x25519_oct258 *v3_c;
|
||||
union x25519_oct258 *v4_b;
|
||||
union x25519_quad257 *v5_d;
|
||||
union x25519_quad257 *v6_f;
|
||||
union x25519_quad257 *v7_a;
|
||||
union x25519_quad257 *v8_c;
|
||||
union x25519_oct258 *v9_e;
|
||||
union x25519_oct258 *v10_a;
|
||||
union x25519_quad257 *v11_b;
|
||||
union x25519_oct258 *v12_c;
|
||||
union x25519_quad257 *v13_a;
|
||||
union x25519_oct258 *v14_a;
|
||||
union x25519_quad257 *v15_c;
|
||||
union x25519_quad257 *v16_a;
|
||||
union x25519_quad257 *v17_d;
|
||||
union x25519_quad257 *v18_b;
|
||||
|
||||
/* See the referenced paper "Implementing Curve25519/X25519: A
|
||||
* Tutorial on Elliptic Curve Cryptography" for the reasoning
|
||||
* behind this calculation.
|
||||
*/
|
||||
|
||||
/* Reuse storage locations for intermediate results where possible */
|
||||
v1_e = &e;
|
||||
v2_a = container_of ( &a->value, union x25519_oct258, value );
|
||||
v3_c = container_of ( &c->value, union x25519_oct258, value );
|
||||
v4_b = container_of ( &b->value, union x25519_oct258, value );
|
||||
v5_d = d;
|
||||
v6_f = &f;
|
||||
v7_a = a;
|
||||
v8_c = c;
|
||||
v9_e = &e;
|
||||
v10_a = container_of ( &a->value, union x25519_oct258, value );
|
||||
v11_b = b;
|
||||
v12_c = container_of ( &c->value, union x25519_oct258, value );
|
||||
v13_a = a;
|
||||
v14_a = container_of ( &a->value, union x25519_oct258, value );
|
||||
v15_c = c;
|
||||
v16_a = a;
|
||||
v17_d = d;
|
||||
v18_b = b;
|
||||
|
||||
/* Select inputs */
|
||||
bigint_swap ( &a->value, &b->value, bit );
|
||||
bigint_swap ( &c->value, &d->value, bit );
|
||||
|
||||
/* v1 = a + c */
|
||||
x25519_add ( a, c, v1_e );
|
||||
|
||||
/* v2 = a - c */
|
||||
x25519_subtract ( a, c, v2_a );
|
||||
|
||||
/* v3 = b + d */
|
||||
x25519_add ( b, d, v3_c );
|
||||
|
||||
/* v4 = b - d */
|
||||
x25519_subtract ( b, d, v4_b );
|
||||
|
||||
/* v5 = v1^2 = (a + c)^2 = a^2 + 2ac + c^2 */
|
||||
x25519_multiply ( v1_e, v1_e, v5_d );
|
||||
|
||||
/* v6 = v2^2 = (a - c)^2 = a^2 - 2ac + c^2 */
|
||||
x25519_multiply ( v2_a, v2_a, v6_f );
|
||||
|
||||
/* v7 = v3 * v2 = (b + d) * (a - c) = ab - bc + ad - cd */
|
||||
x25519_multiply ( v3_c, v2_a, v7_a );
|
||||
|
||||
/* v8 = v4 * v1 = (b - d) * (a + c) = ab + bc - ad - cd */
|
||||
x25519_multiply ( v4_b, v1_e, v8_c );
|
||||
|
||||
/* v9 = v7 + v8 = 2 * (ab - cd) */
|
||||
x25519_add ( v7_a, v8_c, v9_e );
|
||||
|
||||
/* v10 = v7 - v8 = 2 * (ad - bc) */
|
||||
x25519_subtract ( v7_a, v8_c, v10_a );
|
||||
|
||||
/* v11 = v10^2 = 4 * (ad - bc)^2 */
|
||||
x25519_multiply ( v10_a, v10_a, v11_b );
|
||||
|
||||
/* v12 = v5 - v6 = (a + c)^2 - (a - c)^2 = 4ac */
|
||||
x25519_subtract ( v5_d, v6_f, v12_c );
|
||||
|
||||
/* v13 = v12 * 121665 = 486660ac = (A-2) * ac */
|
||||
x25519_multiply ( v12_c, &x25519_121665, v13_a );
|
||||
|
||||
/* v14 = v13 + v5 = (A-2) * ac + a^2 + 2ac + c^2 = a^2 + A * ac + c^2 */
|
||||
x25519_add ( v13_a, v5_d, v14_a );
|
||||
|
||||
/* v15 = v12 * v14 = 4ac * (a^2 + A * ac + c^2) */
|
||||
x25519_multiply ( v12_c, v14_a, v15_c );
|
||||
|
||||
/* v16 = v5 * v6 = (a + c)^2 * (a - c)^2 = (a^2 - c^2)^2 */
|
||||
x25519_multiply ( &v5_d->oct258, &v6_f->oct258, v16_a );
|
||||
|
||||
/* v17 = v11 * base = 4 * base * (ad - bc)^2 */
|
||||
x25519_multiply ( &v11_b->oct258, &base->oct258, v17_d );
|
||||
|
||||
/* v18 = v9^2 = 4 * (ab - cd)^2 */
|
||||
x25519_multiply ( v9_e, v9_e, v18_b );
|
||||
|
||||
/* Select outputs */
|
||||
bigint_swap ( &a->value, &b->value, bit );
|
||||
bigint_swap ( &c->value, &d->value, bit );
|
||||
}
|
||||
|
||||
/**
|
||||
* Multiply X25519 elliptic curve point
|
||||
*
|
||||
* @v base Base point
|
||||
* @v scalar Scalar multiple
|
||||
* @v result Point to hold result (may overlap base point)
|
||||
*/
|
||||
static void x25519_ladder ( const union x25519_quad257 *base,
|
||||
struct x25519_value *scalar,
|
||||
union x25519_quad257 *result ) {
|
||||
static const uint8_t zero[] = { 0 };
|
||||
static const uint8_t one[] = { 1 };
|
||||
struct x25519_step step;
|
||||
union x25519_quad257 *tmp;
|
||||
int bit;
|
||||
int i;
|
||||
|
||||
/* Initialise ladder */
|
||||
bigint_init ( &step.x_n.X.value, one, sizeof ( one ) );
|
||||
bigint_init ( &step.x_n.Z.value, zero, sizeof ( zero ) );
|
||||
bigint_copy ( &base->value, &step.x_n1.X.value );
|
||||
bigint_init ( &step.x_n1.Z.value, one, sizeof ( one ) );
|
||||
|
||||
/* Use ladder */
|
||||
for ( i = 254 ; i >= 0 ; i-- ) {
|
||||
bit = ( ( scalar->raw[ i / 8 ] >> ( i % 8 ) ) & 1 );
|
||||
x25519_step ( base, bit, &step );
|
||||
}
|
||||
|
||||
/* Convert back to affine coordinate */
|
||||
tmp = &step.x_n1.X;
|
||||
x25519_invert ( &step.x_n.Z.oct258, tmp );
|
||||
x25519_multiply ( &step.x_n.X.oct258, &tmp->oct258, result );
|
||||
x25519_reduce ( result );
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse X25519 value endianness
|
||||
*
|
||||
* @v value Value to reverse
|
||||
*/
|
||||
static void x25519_reverse ( struct x25519_value *value ) {
|
||||
uint8_t *low = value->raw;
|
||||
uint8_t *high = &value->raw[ sizeof ( value->raw ) - 1 ];
|
||||
uint8_t tmp;
|
||||
|
||||
/* Reverse bytes */
|
||||
do {
|
||||
tmp = *low;
|
||||
*low = *high;
|
||||
*high = tmp;
|
||||
} while ( ++low < --high );
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate X25519 key
|
||||
*
|
||||
* @v base Base point
|
||||
* @v scalar Scalar multiple
|
||||
* @v result Point to hold result (may overlap base point)
|
||||
* @ret rc Return status code
|
||||
*/
|
||||
int x25519_key ( const struct x25519_value *base,
|
||||
const struct x25519_value *scalar,
|
||||
struct x25519_value *result ) {
|
||||
struct x25519_value *tmp = result;
|
||||
union x25519_quad257 point;
|
||||
|
||||
/* Reverse base point and clear high bit as required by RFC7748 */
|
||||
memcpy ( tmp, base, sizeof ( *tmp ) );
|
||||
x25519_reverse ( tmp );
|
||||
tmp->raw[0] &= 0x7f;
|
||||
bigint_init ( &point.value, tmp->raw, sizeof ( tmp->raw ) );
|
||||
|
||||
/* Clamp scalar as required by RFC7748 */
|
||||
memcpy ( tmp, scalar, sizeof ( *tmp ) );
|
||||
tmp->raw[0] &= 0xf8;
|
||||
tmp->raw[31] |= 0x40;
|
||||
|
||||
/* Multiply elliptic curve point */
|
||||
x25519_ladder ( &point, tmp, &point );
|
||||
|
||||
/* Reverse result */
|
||||
bigint_done ( &point.value, result->raw, sizeof ( result->raw ) );
|
||||
x25519_reverse ( result );
|
||||
|
||||
/* Fail if result was all zeros (as required by RFC8422) */
|
||||
return ( bigint_is_zero ( &point.value ) ? -EPERM : 0 );
|
||||
}
|
||||
|
||||
/**
|
||||
* Multiply scalar by curve point
|
||||
*
|
||||
* @v base Base point (or NULL to use generator)
|
||||
* @v scalar Scalar multiple
|
||||
* @v result Result point to fill in
|
||||
* @ret rc Return status code
|
||||
*/
|
||||
static int x25519_curve_multiply ( const void *base, const void *scalar,
|
||||
void *result ) {
|
||||
|
||||
/* Use base point if applicable */
|
||||
if ( ! base )
|
||||
base = &x25519_generator;
|
||||
|
||||
return x25519_key ( base, scalar, result );
|
||||
}
|
||||
|
||||
/** X25519 elliptic curve */
|
||||
struct elliptic_curve x25519_curve = {
|
||||
.name = "x25519",
|
||||
.keysize = sizeof ( struct x25519_value ),
|
||||
.multiply = x25519_curve_multiply,
|
||||
};
|
||||
@ -1603,19 +1603,12 @@ int x509_check_name ( struct x509_certificate *cert, const char *name ) {
|
||||
static void x509_free_chain ( struct refcnt *refcnt ) {
|
||||
struct x509_chain *chain =
|
||||
container_of ( refcnt, struct x509_chain, refcnt );
|
||||
struct x509_link *link;
|
||||
struct x509_link *tmp;
|
||||
|
||||
DBGC2 ( chain, "X509 chain %p freed\n", chain );
|
||||
|
||||
/* Free each link in the chain */
|
||||
list_for_each_entry_safe ( link, tmp, &chain->links, list ) {
|
||||
x509_put ( link->cert );
|
||||
list_del ( &link->list );
|
||||
free ( link );
|
||||
}
|
||||
|
||||
/* Free chain */
|
||||
x509_truncate ( chain, NULL );
|
||||
assert ( list_empty ( &chain->links ) );
|
||||
free ( chain );
|
||||
}
|
||||
|
||||
@ -1696,6 +1689,27 @@ int x509_append_raw ( struct x509_chain *chain, const void *data,
|
||||
return rc;
|
||||
}
|
||||
|
||||
/**
|
||||
* Truncate X.509 certificate chain
|
||||
*
|
||||
* @v chain X.509 certificate chain
|
||||
* @v link Link after which to truncate chain, or NULL
|
||||
*/
|
||||
void x509_truncate ( struct x509_chain *chain, struct x509_link *link ) {
|
||||
struct x509_link *tmp;
|
||||
|
||||
/* Truncate entire chain if no link is specified */
|
||||
if ( ! link )
|
||||
link = list_entry ( &chain->links, struct x509_link, list );
|
||||
|
||||
/* Free each link in the chain */
|
||||
list_for_each_entry_safe_continue ( link, tmp, &chain->links, list ) {
|
||||
x509_put ( link->cert );
|
||||
list_del ( &link->list );
|
||||
free ( link );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Identify X.509 certificate by subject
|
||||
*
|
||||
|
||||
@ -545,8 +545,8 @@ static int arbel_mad ( struct ib_device *ibdev, union ib_mad *mad ) {
|
||||
union arbelprm_mad mad_ifc;
|
||||
int rc;
|
||||
|
||||
linker_assert ( sizeof ( *mad ) == sizeof ( mad_ifc.mad ),
|
||||
mad_size_mismatch );
|
||||
/* Sanity check */
|
||||
static_assert ( sizeof ( *mad ) == sizeof ( mad_ifc.mad ) );
|
||||
|
||||
/* Copy in request packet */
|
||||
memcpy ( &mad_ifc.mad, mad, sizeof ( mad_ifc.mad ) );
|
||||
@ -3139,8 +3139,8 @@ static void arbel_remove ( struct pci_device *pci ) {
|
||||
}
|
||||
|
||||
static struct pci_device_id arbel_nics[] = {
|
||||
PCI_ROM ( 0x15b3, 0x6282, "mt25218", "MT25218 HCA driver", 0 ),
|
||||
PCI_ROM ( 0x15b3, 0x6274, "mt25204", "MT25204 HCA driver", 0 ),
|
||||
PCI_ROM ( 0x15b3, 0x6282, "mt25218", "MT25218 HCA driver", 0 ),
|
||||
};
|
||||
|
||||
struct pci_driver arbel_driver __pci_driver = {
|
||||
|
||||
@ -2502,7 +2502,7 @@ static mlx_status shomron_fill_eth_send_wqe ( struct ib_device *ibdev,
|
||||
}
|
||||
|
||||
#define SHOMRON_GENERATE_CQE 0x3
|
||||
#define SHOMRON_INLINE_HEADERS_SIZE 18
|
||||
#define SHOMRON_INLINE_HEADERS_SIZE ETH_HLEN
|
||||
#define SHOMRON_INLINE_HEADERS_OFFSET 32
|
||||
MLX_FILL_2 ( ð_wqe->ctrl, 0, opcode, FLEXBOOT_NODNIC_OPCODE_SEND,
|
||||
wqe_index, wqe_index & 0xFFFF);
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user