mirror of
				https://gitlab.com/qemu-project/ipxe.git
				synced 2025-11-03 07:59:06 +08:00 
			
		
		
		
	Compare commits
	
		
			26 Commits
		
	
	
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 587ef78ad0 | |||
| 96bb6ba441 | |||
| 33cb56cf1b | |||
| 60531ff6e2 | |||
| 04e60a278a | |||
| 471599dc77 | |||
| 7d71cf318a | |||
| 6625e49cea | |||
| 9f17d1116d | |||
| 2733c4763a | |||
| cff857461b | |||
| 6a004be0cc | |||
| cf9ad00afc | |||
| 76a286530a | |||
| 3c83843e11 | |||
| be8ecaf805 | |||
| 62a1d5c0f5 | |||
| 84cb774390 | |||
| bfa5262f0e | |||
| ef0a6f4792 | |||
| c6901792f0 | |||
| a2bed43939 | |||
| 7cc305f7b4 | |||
| dc16de3204 | |||
| 6c0335adf6 | |||
| 8450fa4a7b | 
							
								
								
									
										55
									
								
								.github/workflows/build.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										55
									
								
								.github/workflows/build.yml
									
									
									
									
										vendored
									
									
								
							@ -4,14 +4,45 @@ on: push
 | 
			
		||||
 | 
			
		||||
jobs:
 | 
			
		||||
 | 
			
		||||
  cache:
 | 
			
		||||
    name: Cache
 | 
			
		||||
    runs-on: ubuntu-22.04
 | 
			
		||||
    steps:
 | 
			
		||||
      - name: Cache permissions
 | 
			
		||||
        run: |
 | 
			
		||||
          sudo chown $(id -un) /var/cache/apt/archives
 | 
			
		||||
      - name: Cache packages
 | 
			
		||||
        uses: actions/cache@v3
 | 
			
		||||
        with:
 | 
			
		||||
          path: /var/cache/apt/archives/*.deb
 | 
			
		||||
          key: apt-cache-${{ github.run_id }}-${{ github.run_attempt }}
 | 
			
		||||
          restore-keys: |
 | 
			
		||||
            apt-cache-
 | 
			
		||||
      - name: Download packages
 | 
			
		||||
        run: |
 | 
			
		||||
          sudo apt update
 | 
			
		||||
          sudo apt install -y -d -o Acquire::Retries=50 \
 | 
			
		||||
                           mtools syslinux isolinux \
 | 
			
		||||
                           libc6-dev-i386 valgrind \
 | 
			
		||||
                           gcc-arm-none-eabi gcc-aarch64-linux-gnu
 | 
			
		||||
 | 
			
		||||
  x86:
 | 
			
		||||
    name: x86
 | 
			
		||||
    runs-on: ubuntu-20.04
 | 
			
		||||
    runs-on: ubuntu-22.04
 | 
			
		||||
    needs: cache
 | 
			
		||||
    steps:
 | 
			
		||||
      - name: Check out code
 | 
			
		||||
        uses: actions/checkout@v3
 | 
			
		||||
        with:
 | 
			
		||||
          fetch-depth: 0
 | 
			
		||||
      - name: Cache permissions
 | 
			
		||||
        run: |
 | 
			
		||||
          sudo chown $(id -un) /var/cache/apt/archives
 | 
			
		||||
      - name: Cache packages
 | 
			
		||||
        uses: actions/cache/restore@v3
 | 
			
		||||
        with:
 | 
			
		||||
          path: /var/cache/apt/archives/*.deb
 | 
			
		||||
          key: apt-cache-${{ github.run_id }}-${{ github.run_attempt }}
 | 
			
		||||
      - name: Install packages
 | 
			
		||||
        run: |
 | 
			
		||||
          sudo dpkg --add-architecture i386
 | 
			
		||||
@ -32,12 +63,21 @@ jobs:
 | 
			
		||||
 | 
			
		||||
  arm32:
 | 
			
		||||
    name: ARM32
 | 
			
		||||
    runs-on: ubuntu-20.04
 | 
			
		||||
    runs-on: ubuntu-22.04
 | 
			
		||||
    needs: cache
 | 
			
		||||
    steps:
 | 
			
		||||
      - name: Check out code
 | 
			
		||||
        uses: actions/checkout@v3
 | 
			
		||||
        with:
 | 
			
		||||
          fetch-depth: 0
 | 
			
		||||
      - name: Cache permissions
 | 
			
		||||
        run: |
 | 
			
		||||
          sudo chown $(id -un) /var/cache/apt/archives
 | 
			
		||||
      - name: Cache packages
 | 
			
		||||
        uses: actions/cache/restore@v3
 | 
			
		||||
        with:
 | 
			
		||||
          path: /var/cache/apt/archives/*.deb
 | 
			
		||||
          key: apt-cache-${{ github.run_id }}-${{ github.run_attempt }}
 | 
			
		||||
      - name: Install packages
 | 
			
		||||
        run: |
 | 
			
		||||
          sudo apt update
 | 
			
		||||
@ -52,12 +92,21 @@ jobs:
 | 
			
		||||
 | 
			
		||||
  arm64:
 | 
			
		||||
    name: ARM64
 | 
			
		||||
    runs-on: ubuntu-20.04
 | 
			
		||||
    runs-on: ubuntu-22.04
 | 
			
		||||
    needs: cache
 | 
			
		||||
    steps:
 | 
			
		||||
      - name: Check out code
 | 
			
		||||
        uses: actions/checkout@v3
 | 
			
		||||
        with:
 | 
			
		||||
          fetch-depth: 0
 | 
			
		||||
      - name: Cache permissions
 | 
			
		||||
        run: |
 | 
			
		||||
          sudo chown $(id -un) /var/cache/apt/archives
 | 
			
		||||
      - name: Cache packages
 | 
			
		||||
        uses: actions/cache/restore@v3
 | 
			
		||||
        with:
 | 
			
		||||
          path: /var/cache/apt/archives/*.deb
 | 
			
		||||
          key: apt-cache-${{ github.run_id }}-${{ github.run_attempt }}
 | 
			
		||||
      - name: Install packages
 | 
			
		||||
        run: |
 | 
			
		||||
          sudo apt update
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										2
									
								
								.github/workflows/coverity.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								.github/workflows/coverity.yml
									
									
									
									
										vendored
									
									
								
							@ -8,7 +8,7 @@ on:
 | 
			
		||||
jobs:
 | 
			
		||||
  submit:
 | 
			
		||||
    name: Submit
 | 
			
		||||
    runs-on: ubuntu-20.04
 | 
			
		||||
    runs-on: ubuntu-22.04
 | 
			
		||||
    steps:
 | 
			
		||||
      - name: Check out code
 | 
			
		||||
        uses: actions/checkout@v3
 | 
			
		||||
 | 
			
		||||
@ -1,12 +0,0 @@
 | 
			
		||||
#ifndef _BITS_ENTROPY_H
 | 
			
		||||
#define _BITS_ENTROPY_H
 | 
			
		||||
 | 
			
		||||
/** @file
 | 
			
		||||
 *
 | 
			
		||||
 * ARM-specific entropy API implementations
 | 
			
		||||
 *
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
 | 
			
		||||
 | 
			
		||||
#endif /* _BITS_ENTROPY_H */
 | 
			
		||||
@ -9,6 +9,9 @@
 | 
			
		||||
 | 
			
		||||
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
 | 
			
		||||
 | 
			
		||||
/** Page shift */
 | 
			
		||||
#define PAGE_SHIFT 12
 | 
			
		||||
 | 
			
		||||
#include <ipxe/arm_io.h>
 | 
			
		||||
 | 
			
		||||
#endif /* _BITS_IO_H */
 | 
			
		||||
 | 
			
		||||
@ -20,9 +20,6 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
 | 
			
		||||
 *
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
/** Page shift */
 | 
			
		||||
#define PAGE_SHIFT 12
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Physical<->Bus address mappings
 | 
			
		||||
 *
 | 
			
		||||
 | 
			
		||||
@ -8,6 +8,9 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
 | 
			
		||||
 | 
			
		||||
#ifndef ASSEMBLY
 | 
			
		||||
 | 
			
		||||
/** Unprefixed constant operand modifier */
 | 
			
		||||
#define ASM_NO_PREFIX "c"
 | 
			
		||||
 | 
			
		||||
#define __asmcall
 | 
			
		||||
#define __libgcc
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -8,6 +8,9 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
 | 
			
		||||
 | 
			
		||||
#ifndef ASSEMBLY
 | 
			
		||||
 | 
			
		||||
/** Unprefixed constant operand modifier */
 | 
			
		||||
#define ASM_NO_PREFIX "c"
 | 
			
		||||
 | 
			
		||||
#define __asmcall
 | 
			
		||||
#define __libgcc
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -8,6 +8,9 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
 | 
			
		||||
 | 
			
		||||
#ifndef ASSEMBLY
 | 
			
		||||
 | 
			
		||||
/** Unprefixed constant operand modifier */
 | 
			
		||||
#define ASM_NO_PREFIX "c"
 | 
			
		||||
 | 
			
		||||
/** Declare a function with standard calling conventions */
 | 
			
		||||
#define __asmcall __attribute__ (( cdecl, regparm(0) ))
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										26
									
								
								src/arch/loong64/Makefile
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										26
									
								
								src/arch/loong64/Makefile
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,26 @@
 | 
			
		||||
# Assembler section type character
 | 
			
		||||
#
 | 
			
		||||
ASM_TCHAR	:= @
 | 
			
		||||
ASM_TCHAR_OPS	:= @
 | 
			
		||||
 | 
			
		||||
# LoongArch64-specific flags
 | 
			
		||||
#
 | 
			
		||||
CFLAGS		+= -fstrength-reduce -fomit-frame-pointer
 | 
			
		||||
CFLAGS		+= -falign-jumps=1 -falign-loops=1 -falign-functions=1
 | 
			
		||||
 | 
			
		||||
# Check if -mno-explicit-relocs is valid
 | 
			
		||||
ifeq ($(CCTYPE),gcc)
 | 
			
		||||
MNER_TEST = $(CC) -mno-explicit-relocs -x c -c /dev/null -o /dev/null >/dev/null 2>&1
 | 
			
		||||
MNER_FLAGS := $(shell $(MNER_TEST) && $(ECHO) '-mno-explicit-relocs')
 | 
			
		||||
WORKAROUND_CFLAGS += $(MNER_FLAGS)
 | 
			
		||||
endif
 | 
			
		||||
 | 
			
		||||
# EFI requires -fshort-wchar, and nothing else currently uses wchar_t
 | 
			
		||||
CFLAGS		+= -fshort-wchar
 | 
			
		||||
 | 
			
		||||
# LoongArch64-specific directories containing source files
 | 
			
		||||
SRCDIRS		+= arch/loong64/core
 | 
			
		||||
 | 
			
		||||
# Include platform-specific Makefile
 | 
			
		||||
MAKEDEPS	+= arch/loong64/Makefile.$(PLATFORM)
 | 
			
		||||
include arch/loong64/Makefile.$(PLATFORM)
 | 
			
		||||
							
								
								
									
										10
									
								
								src/arch/loong64/Makefile.linux
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								src/arch/loong64/Makefile.linux
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,10 @@
 | 
			
		||||
# -*- makefile -*- : Force emacs to use Makefile mode
 | 
			
		||||
 | 
			
		||||
# Starting virtual address
 | 
			
		||||
#
 | 
			
		||||
LDFLAGS += -Ttext=0x120000000
 | 
			
		||||
 | 
			
		||||
# Include generic Linux Makefile
 | 
			
		||||
#
 | 
			
		||||
MAKEDEPS += Makefile.linux
 | 
			
		||||
include Makefile.linux
 | 
			
		||||
							
								
								
									
										120
									
								
								src/arch/loong64/core/loong64_bigint.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										120
									
								
								src/arch/loong64/core/loong64_bigint.c
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,120 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (C) 2012 Michael Brown <mbrown@fensystems.co.uk>.
 | 
			
		||||
 * Copyright (c) 2023, Xiaotian Wu <wuxiaotian@loongson.cn>
 | 
			
		||||
 *
 | 
			
		||||
 * 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 );
 | 
			
		||||
 | 
			
		||||
#include <stdint.h>
 | 
			
		||||
#include <string.h>
 | 
			
		||||
#include <ipxe/bigint.h>
 | 
			
		||||
 | 
			
		||||
/** @file
 | 
			
		||||
 *
 | 
			
		||||
 * Big integer support
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Multiply big integers
 | 
			
		||||
 *
 | 
			
		||||
 * @v multiplicand0	Element 0 of big integer to be multiplied
 | 
			
		||||
 * @v multiplier0	Element 0 of big integer to be multiplied
 | 
			
		||||
 * @v result0		Element 0 of big integer to hold result
 | 
			
		||||
 * @v size		Number of elements
 | 
			
		||||
 */
 | 
			
		||||
void bigint_multiply_raw ( const uint64_t *multiplicand0,
 | 
			
		||||
			   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 i;
 | 
			
		||||
	unsigned int j;
 | 
			
		||||
	uint64_t multiplicand_element;
 | 
			
		||||
	uint64_t multiplier_element;
 | 
			
		||||
	uint64_t *result_elements;
 | 
			
		||||
	uint64_t discard_low;
 | 
			
		||||
	uint64_t discard_high;
 | 
			
		||||
	uint64_t discard_temp_low;
 | 
			
		||||
	uint64_t discard_temp_high;
 | 
			
		||||
 | 
			
		||||
	/* Zero result */
 | 
			
		||||
	memset ( result, 0, sizeof ( *result ) );
 | 
			
		||||
 | 
			
		||||
	/* Multiply integers one element at a time */
 | 
			
		||||
	for ( i = 0 ; i < size ; i++ ) {
 | 
			
		||||
		multiplicand_element = multiplicand->element[i];
 | 
			
		||||
		for ( j = 0 ; j < size ; j++ ) {
 | 
			
		||||
			multiplier_element = multiplier->element[j];
 | 
			
		||||
			result_elements = &result->element[ i + j ];
 | 
			
		||||
			/* Perform a single multiply, and add the
 | 
			
		||||
			 * resulting double-element into the result,
 | 
			
		||||
			 * carrying as necessary.  The carry can
 | 
			
		||||
			 * never overflow beyond the end of the
 | 
			
		||||
			 * result, since:
 | 
			
		||||
			 *
 | 
			
		||||
			 *     a < 2^{n}, b < 2^{n} => ab < 2^{2n}
 | 
			
		||||
			 */
 | 
			
		||||
			__asm__ __volatile__ ( "mul.d   %1, %6, %7\n\t"
 | 
			
		||||
					       "mulh.du %2, %6, %7\n\t"
 | 
			
		||||
 | 
			
		||||
					       "ld.d    %3, %0, 0\n\t"
 | 
			
		||||
					       "ld.d    %4, %0, 8\n\t"
 | 
			
		||||
 | 
			
		||||
					       "add.d   %3, %3, %1\n\t"
 | 
			
		||||
					       "sltu    $t0, %3, %1\n\t"
 | 
			
		||||
 | 
			
		||||
					       "add.d   %4, %4, %2\n\t"
 | 
			
		||||
					       "sltu    $t1, %4, %2\n\t"
 | 
			
		||||
 | 
			
		||||
					       "add.d   %4, %4, $t0\n\t"
 | 
			
		||||
					       "sltu    $t0, %4, $t0\n\t"
 | 
			
		||||
					       "or      $t0, $t0, $t1\n\t"
 | 
			
		||||
 | 
			
		||||
					       "st.d    %3,  %0, 0\n\t"
 | 
			
		||||
					       "st.d    %4,  %0, 8\n\t"
 | 
			
		||||
 | 
			
		||||
					       "addi.d  %0,  %0, 16\n\t"
 | 
			
		||||
					       "beqz    $t0, 2f\n"
 | 
			
		||||
					       "1:\n\t"
 | 
			
		||||
					       "ld.d    %3,  %0, 0\n\t"
 | 
			
		||||
					       "add.d   %3,  %3, $t0\n\t"
 | 
			
		||||
					       "sltu    $t0, %3, $t0\n\t"
 | 
			
		||||
					       "st.d    %3,  %0, 0\n\t"
 | 
			
		||||
					       "addi.d  %0, %0, 8\n\t"
 | 
			
		||||
					       "bnez    $t0, 1b\n"
 | 
			
		||||
					       "2:"
 | 
			
		||||
					       : "+r" ( result_elements ),
 | 
			
		||||
						 "=&r" ( discard_low ),
 | 
			
		||||
						 "=&r" ( discard_high ),
 | 
			
		||||
						 "=r" ( discard_temp_low ),
 | 
			
		||||
						 "=r" ( discard_temp_high ),
 | 
			
		||||
						 "+m" ( *result )
 | 
			
		||||
					       : "r" ( multiplicand_element ),
 | 
			
		||||
						 "r" ( multiplier_element )
 | 
			
		||||
					       : "t0", "t1" );
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										266
									
								
								src/arch/loong64/core/loong64_string.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										266
									
								
								src/arch/loong64/core/loong64_string.c
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,266 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (C) 2016 Michael Brown <mbrown@fensystems.co.uk>.
 | 
			
		||||
 * Copyright (c) 2023, Xiaotian Wu <wuxiaotian@loongson.cn>
 | 
			
		||||
 *
 | 
			
		||||
 * 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
 | 
			
		||||
 *
 | 
			
		||||
 * Optimised string operations
 | 
			
		||||
 *
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
 | 
			
		||||
 | 
			
		||||
#include <string.h>
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Copy memory area
 | 
			
		||||
 *
 | 
			
		||||
 * @v dest		Destination address
 | 
			
		||||
 * @v src		Source address
 | 
			
		||||
 * @v len		Length
 | 
			
		||||
 * @ret dest		Destination address
 | 
			
		||||
 */
 | 
			
		||||
void loong64_memcpy ( void *dest, const void *src, size_t len ) {
 | 
			
		||||
	void *discard_dest;
 | 
			
		||||
	void *discard_end;
 | 
			
		||||
	const void *discard_src;
 | 
			
		||||
	size_t discard_offset;
 | 
			
		||||
	unsigned long discard_data;
 | 
			
		||||
	unsigned long discard_low;
 | 
			
		||||
	unsigned long discard_high;
 | 
			
		||||
 | 
			
		||||
	/* If length is too short, then just copy individual bytes.
 | 
			
		||||
	 */
 | 
			
		||||
	if ( len < 16 ) {
 | 
			
		||||
		__asm__ __volatile__ ( "beqz %0, 2f\n\t"
 | 
			
		||||
				       "\n1:\n\t"
 | 
			
		||||
				       "addi.d %0, %0, -1\n\t"
 | 
			
		||||
				       "ldx.b %1, %3, %0\n\t"
 | 
			
		||||
				       "stx.b %1, %2, %0\n\t"
 | 
			
		||||
				       "bnez %0, 1b\n\t"
 | 
			
		||||
				       "\n2:\n\t"
 | 
			
		||||
				       : "=&r" ( discard_offset ),
 | 
			
		||||
					 "=&r" ( discard_data )
 | 
			
		||||
				       : "r" ( dest ), "r" ( src ), "0" ( len )
 | 
			
		||||
				       : "memory", "t0" );
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* Copy 16 bytes at a time: one initial
 | 
			
		||||
	 * potentially unaligned access, multiple destination-aligned
 | 
			
		||||
	 * accesses, one final potentially unaligned access.
 | 
			
		||||
	 */
 | 
			
		||||
	__asm__ __volatile__ ( "ld.d %3, %1, 0\n\t"
 | 
			
		||||
			       "ld.d %4, %1, 8\n\t"
 | 
			
		||||
			       "addi.d %1, %1, 16\n\t"
 | 
			
		||||
			       "st.d %3, %0, 0\n\t"
 | 
			
		||||
			       "st.d %4, %0, 8\n\t"
 | 
			
		||||
			       "addi.d %0, %0, 16\n\t"
 | 
			
		||||
			       "andi %3, %0, 15\n\t"
 | 
			
		||||
			       "sub.d %0, %0, %3\n\t"
 | 
			
		||||
			       "sub.d %1, %1, %3\n\t"
 | 
			
		||||
			       "addi.d $t0, $zero, 0xf\n\t"
 | 
			
		||||
			       "andn %2, %5, $t0\n\t"
 | 
			
		||||
			       "b 2f\n\t"
 | 
			
		||||
			       "\n1:\n\t"
 | 
			
		||||
			       "ld.d %3, %1, 0\n\t"
 | 
			
		||||
			       "ld.d %4, %1, 8\n\t"
 | 
			
		||||
			       "addi.d %1, %1, 16\n\t"
 | 
			
		||||
			       "st.d %3, %0, 0\n\t"
 | 
			
		||||
			       "st.d %4, %0, 8\n\t"
 | 
			
		||||
			       "addi.d %0, %0, 16\n\t"
 | 
			
		||||
			       "\n2:\n\t"
 | 
			
		||||
			       "bne %0, %2, 1b\n\t"
 | 
			
		||||
			       "ld.d %3, %6, -16\n\t"
 | 
			
		||||
			       "ld.d %4, %6, -8\n\t"
 | 
			
		||||
			       "st.d %3, %5, -16\n\t"
 | 
			
		||||
			       "st.d %4, %5, -8\n\t"
 | 
			
		||||
			       : "=&r" ( discard_dest ),
 | 
			
		||||
				 "=&r" ( discard_src ),
 | 
			
		||||
				 "=&r" ( discard_end ),
 | 
			
		||||
				 "=&r" ( discard_low ),
 | 
			
		||||
				 "=&r" ( discard_high )
 | 
			
		||||
			       : "r" ( dest + len ), "r" ( src + len ),
 | 
			
		||||
				 "0" ( dest ), "1" ( src )
 | 
			
		||||
			       : "memory", "t0" );
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Zero memory region
 | 
			
		||||
 *
 | 
			
		||||
 * @v dest		Destination region
 | 
			
		||||
 * @v len		Length
 | 
			
		||||
 */
 | 
			
		||||
void loong64_bzero ( void *dest, size_t len ) {
 | 
			
		||||
	size_t discard_offset;
 | 
			
		||||
	void *discard_dest;
 | 
			
		||||
	void *discard_end;
 | 
			
		||||
 | 
			
		||||
	/* If length is too short, then just zero individual bytes.
 | 
			
		||||
	 */
 | 
			
		||||
	if ( len < 16 ) {
 | 
			
		||||
		__asm__ __volatile__ ( "beqz %0, 2f\n\t"
 | 
			
		||||
				       "\n1:\n\t"
 | 
			
		||||
				       "addi.d %0, %0, -1\n\t"
 | 
			
		||||
				       "stx.b $zero, %1, %0\n\t"
 | 
			
		||||
				       "bnez %0, 1b\n\t"
 | 
			
		||||
				       "\n2:\n\t"
 | 
			
		||||
				       : "=&r" ( discard_offset )
 | 
			
		||||
				       : "r" ( dest ), "0" ( len )
 | 
			
		||||
				       : "memory" );
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* To zero 16 bytes at a time: one initial
 | 
			
		||||
	 * potentially unaligned access, multiple aligned accesses,
 | 
			
		||||
	 * one final potentially unaligned access.
 | 
			
		||||
	 */
 | 
			
		||||
 | 
			
		||||
	__asm__ __volatile__ ( "st.d $zero, %0, 0\n\t"
 | 
			
		||||
			       "st.d $zero, %0, 8\n\t"
 | 
			
		||||
			       "addi.d %0, %0, 16\n\t"
 | 
			
		||||
			       "addi.w $t0, $zero, 15\n\t"
 | 
			
		||||
			       "andn %0, %0, $t0\n\t"
 | 
			
		||||
			       "addi.w $t0, $zero, 15\n\t"
 | 
			
		||||
			       "andn %1, %2, $t0\n\t"
 | 
			
		||||
			       "b 2f\n\t"
 | 
			
		||||
			       "\n1:\n\t"
 | 
			
		||||
			       "st.d $zero, %0, 0\n\t"
 | 
			
		||||
			       "st.d $zero, %0, 8\n\t"
 | 
			
		||||
			       "addi.d %0, %0, 16\n\t"
 | 
			
		||||
			       "\n2:\n\t"
 | 
			
		||||
			       "bne %0, %1, 1b\n\t"
 | 
			
		||||
			       "st.d $zero, %2, -16\n\t"
 | 
			
		||||
			       "st.d $zero, %2, -8\n\t"
 | 
			
		||||
			       : "=&r" ( discard_dest ),
 | 
			
		||||
				 "=&r" ( discard_end )
 | 
			
		||||
			       : "r" ( dest + len ), "0" ( dest )
 | 
			
		||||
			       : "memory", "t0" );
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Fill memory region
 | 
			
		||||
 *
 | 
			
		||||
 * @v dest		Destination region
 | 
			
		||||
 * @v len		Length
 | 
			
		||||
 * @v character		Fill character
 | 
			
		||||
 *
 | 
			
		||||
 * The unusual parameter order is to allow for more efficient
 | 
			
		||||
 * tail-calling to loong64_memset() when zeroing a region.
 | 
			
		||||
 */
 | 
			
		||||
void loong64_memset ( void *dest, size_t len, int character ) {
 | 
			
		||||
	size_t discard_offset;
 | 
			
		||||
 | 
			
		||||
	/* Use optimised zeroing code if applicable */
 | 
			
		||||
	if ( character == 0 ) {
 | 
			
		||||
		loong64_bzero ( dest, len );
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* Fill one byte at a time.  Calling memset() with a non-zero
 | 
			
		||||
	 * value is relatively rare and unlikely to be
 | 
			
		||||
	 * performance-critical.
 | 
			
		||||
	 */
 | 
			
		||||
	__asm__ __volatile__ ( "beqz %0, 2f\n\t"
 | 
			
		||||
			       "\n1:\n\t"
 | 
			
		||||
			       "addi.d %0, %0, -1\n\t"
 | 
			
		||||
			       "stx.b %2, %1, %0\n\t"
 | 
			
		||||
			       "bnez %0, 1b\n\t"
 | 
			
		||||
			       "\n2:\n\t"
 | 
			
		||||
			       : "=&r" ( discard_offset )
 | 
			
		||||
			       : "r" ( dest ), "r" ( character ), "0" ( len )
 | 
			
		||||
			       : "memory" );
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Copy (possibly overlapping) memory region forwards
 | 
			
		||||
 *
 | 
			
		||||
 * @v dest		Destination region
 | 
			
		||||
 * @v src		Source region
 | 
			
		||||
 * @v len		Length
 | 
			
		||||
 */
 | 
			
		||||
void loong64_memmove_forwards ( void *dest, const void *src, size_t len ) {
 | 
			
		||||
	void *discard_dest;
 | 
			
		||||
	const void *discard_src;
 | 
			
		||||
	unsigned long discard_data;
 | 
			
		||||
 | 
			
		||||
	/* Assume memmove() is not performance-critical, and perform a
 | 
			
		||||
	 * bytewise copy for simplicity.
 | 
			
		||||
	 */
 | 
			
		||||
	__asm__ __volatile__ ( "b 2f\n\t"
 | 
			
		||||
			       "\n1:\n\t"
 | 
			
		||||
			       "ld.b %2, %1, 0\n\t"
 | 
			
		||||
			       "addi.d %1, %1, 1\n\t"
 | 
			
		||||
			       "st.b %2, %0, 0\n\t"
 | 
			
		||||
			       "addi.d %0, %0, 1\n\t"
 | 
			
		||||
			       "\n2:\n\t"
 | 
			
		||||
			       "bne %0, %3, 1b\n\t"
 | 
			
		||||
			       : "=&r" ( discard_dest ),
 | 
			
		||||
				 "=&r" ( discard_src ),
 | 
			
		||||
				 "=&r" ( discard_data )
 | 
			
		||||
			       : "r" ( dest + len ), "0" ( dest ), "1" ( src )
 | 
			
		||||
			       : "memory" );
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Copy (possibly overlapping) memory region backwards
 | 
			
		||||
 *
 | 
			
		||||
 * @v dest		Destination region
 | 
			
		||||
 * @v src		Source region
 | 
			
		||||
 * @v len		Length
 | 
			
		||||
 */
 | 
			
		||||
void loong64_memmove_backwards ( void *dest, const void *src, size_t len ) {
 | 
			
		||||
	size_t discard_offset;
 | 
			
		||||
	unsigned long discard_data;
 | 
			
		||||
 | 
			
		||||
	/* Assume memmove() is not performance-critical, and perform a
 | 
			
		||||
	 * bytewise copy for simplicity.
 | 
			
		||||
	 */
 | 
			
		||||
	__asm__ __volatile__ ( "beqz %0, 2f\n\t"
 | 
			
		||||
			       "\n1:\n\t"
 | 
			
		||||
			       "addi.d %0, %0, -1\n\t"
 | 
			
		||||
			       "ldx.b %1, %3, %0\n\t"
 | 
			
		||||
			       "stx.b %1, %2, %0\n\t"
 | 
			
		||||
			       "bnez %0, 1b\n\t"
 | 
			
		||||
			       "\n2:\n\t"
 | 
			
		||||
			       : "=&r" ( discard_offset ),
 | 
			
		||||
				 "=&r" ( discard_data )
 | 
			
		||||
			       : "r" ( dest ), "r" ( src ), "0" ( len )
 | 
			
		||||
			       : "memory" );
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Copy (possibly overlapping) memory region
 | 
			
		||||
 *
 | 
			
		||||
 * @v dest		Destination region
 | 
			
		||||
 * @v src		Source region
 | 
			
		||||
 * @v len		Length
 | 
			
		||||
 */
 | 
			
		||||
void loong64_memmove ( void *dest, const void *src, size_t len ) {
 | 
			
		||||
 | 
			
		||||
	if ( dest <= src ) {
 | 
			
		||||
		loong64_memmove_forwards ( dest, src, len );
 | 
			
		||||
	} else {
 | 
			
		||||
		loong64_memmove_backwards ( dest, src, len );
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										53
									
								
								src/arch/loong64/core/setjmp.S
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										53
									
								
								src/arch/loong64/core/setjmp.S
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,53 @@
 | 
			
		||||
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL )
 | 
			
		||||
 | 
			
		||||
	.section ".note.GNU-stack", "", %progbits
 | 
			
		||||
	.text
 | 
			
		||||
/*
 | 
			
		||||
   int setjmp(jmp_buf env);
 | 
			
		||||
*/
 | 
			
		||||
	.globl	setjmp
 | 
			
		||||
	.type	setjmp, %function
 | 
			
		||||
setjmp:
 | 
			
		||||
	/* Store registers */
 | 
			
		||||
	st.d	$s0, $a0, 0x0
 | 
			
		||||
	st.d	$s1, $a0, 0x8
 | 
			
		||||
	st.d	$s2, $a0, 0x10
 | 
			
		||||
	st.d	$s3, $a0, 0x18
 | 
			
		||||
	st.d	$s4, $a0, 0x20
 | 
			
		||||
	st.d	$s5, $a0, 0x28
 | 
			
		||||
	st.d	$s6, $a0, 0x30
 | 
			
		||||
	st.d	$s7, $a0, 0x38
 | 
			
		||||
	st.d	$s8, $a0, 0x40
 | 
			
		||||
	st.d	$fp, $a0, 0x48
 | 
			
		||||
	st.d	$sp, $a0, 0x50
 | 
			
		||||
	st.d	$ra, $a0, 0x58
 | 
			
		||||
 | 
			
		||||
	move	$a0, $zero
 | 
			
		||||
	jirl	$zero, $ra, 0
 | 
			
		||||
	.size	setjmp, . - setjmp
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
   void longjmp(jmp_buf env, int val);
 | 
			
		||||
*/
 | 
			
		||||
	.globl	longjmp
 | 
			
		||||
	.type	longjmp, %function
 | 
			
		||||
longjmp:
 | 
			
		||||
	/* Restore registers */
 | 
			
		||||
	ld.d	$s0, $a0, 0x0
 | 
			
		||||
	ld.d	$s1, $a0, 0x8
 | 
			
		||||
	ld.d	$s2, $a0, 0x10
 | 
			
		||||
	ld.d	$s3, $a0, 0x18
 | 
			
		||||
	ld.d	$s4, $a0, 0x20
 | 
			
		||||
	ld.d	$s5, $a0, 0x28
 | 
			
		||||
	ld.d	$s6, $a0, 0x30
 | 
			
		||||
	ld.d	$s7, $a0, 0x38
 | 
			
		||||
	ld.d	$s8, $a0, 0x40
 | 
			
		||||
	ld.d	$fp, $a0, 0x48
 | 
			
		||||
	ld.d	$sp, $a0, 0x50
 | 
			
		||||
	ld.d	$ra, $a0, 0x58
 | 
			
		||||
	addi.d	$a0, $zero, 1    # a0 = 1
 | 
			
		||||
	beqz	$a1, .exit       # if (a1 == 0); goto L0
 | 
			
		||||
	move	$a0, $a1         # a0 = a1
 | 
			
		||||
.exit:
 | 
			
		||||
	jirl	$zero, $ra, 0
 | 
			
		||||
	.size	longjmp, . - longjmp
 | 
			
		||||
							
								
								
									
										12
									
								
								src/arch/loong64/include/bits/acpi.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								src/arch/loong64/include/bits/acpi.h
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,12 @@
 | 
			
		||||
#ifndef _BITS_ACPI_H
 | 
			
		||||
#define _BITS_ACPI_H
 | 
			
		||||
 | 
			
		||||
/** @file
 | 
			
		||||
 *
 | 
			
		||||
 * LoongArch64-specific ACPI API implementations
 | 
			
		||||
 *
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
 | 
			
		||||
 | 
			
		||||
#endif /* _BITS_ACPI_H */
 | 
			
		||||
							
								
								
									
										336
									
								
								src/arch/loong64/include/bits/bigint.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										336
									
								
								src/arch/loong64/include/bits/bigint.h
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,336 @@
 | 
			
		||||
#ifndef _BITS_BIGINT_H
 | 
			
		||||
#define _BITS_BIGINT_H
 | 
			
		||||
 | 
			
		||||
/** @file
 | 
			
		||||
 *
 | 
			
		||||
 * Big integer support
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
 | 
			
		||||
 | 
			
		||||
#include <stdint.h>
 | 
			
		||||
#include <string.h>
 | 
			
		||||
#include <strings.h>
 | 
			
		||||
 | 
			
		||||
/** Element of a big integer */
 | 
			
		||||
typedef uint64_t bigint_element_t;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Initialise big integer
 | 
			
		||||
 *
 | 
			
		||||
 * @v value0	Element 0 of big integer to initialise
 | 
			
		||||
 * @v size		Number of elements
 | 
			
		||||
 * @v data		Raw data
 | 
			
		||||
 * @v len		Length of raw data
 | 
			
		||||
 */
 | 
			
		||||
static inline __attribute__ (( always_inline )) void
 | 
			
		||||
bigint_init_raw ( uint64_t *value0, unsigned int size,
 | 
			
		||||
		  const void *data, size_t len ) {
 | 
			
		||||
	size_t pad_len = ( sizeof ( bigint_t ( size ) ) - len );
 | 
			
		||||
	uint8_t *value_byte = ( ( void * ) value0 );
 | 
			
		||||
	const uint8_t *data_byte = ( data + len );
 | 
			
		||||
 | 
			
		||||
	/* Copy raw data in reverse order, padding with zeros */
 | 
			
		||||
	while ( len-- )
 | 
			
		||||
		*(value_byte++) = *(--data_byte);
 | 
			
		||||
	while ( pad_len-- )
 | 
			
		||||
		*(value_byte++) = 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Add big integers
 | 
			
		||||
 *
 | 
			
		||||
 * @v addend0		Element 0 of big integer to add
 | 
			
		||||
 * @v value0		Element 0 of big integer to be added to
 | 
			
		||||
 * @v size		Number of elements
 | 
			
		||||
 */
 | 
			
		||||
static inline __attribute__ (( always_inline )) void
 | 
			
		||||
bigint_add_raw ( const uint64_t *addend0, uint64_t *value0,
 | 
			
		||||
		 unsigned int size ) {
 | 
			
		||||
	bigint_t ( size ) __attribute__ (( may_alias )) *value =
 | 
			
		||||
		( ( void * ) value0 );
 | 
			
		||||
	uint64_t *discard_addend;
 | 
			
		||||
	uint64_t *discard_value;
 | 
			
		||||
	uint64_t discard_addend_i;
 | 
			
		||||
	uint64_t discard_value_i;
 | 
			
		||||
	unsigned int discard_size;
 | 
			
		||||
	__asm__ __volatile__ ( "move   $t0, $zero\n"
 | 
			
		||||
			       "1:\n\t"
 | 
			
		||||
			       "ld.d   %3, %0, 0\n\t"
 | 
			
		||||
			       "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"
 | 
			
		||||
			       : "=r" ( discard_addend ),
 | 
			
		||||
				 "=r" ( discard_value ),
 | 
			
		||||
				 "=r" ( discard_size ),
 | 
			
		||||
				 "=r" ( discard_addend_i ),
 | 
			
		||||
				 "=r" ( discard_value_i ),
 | 
			
		||||
				 "+m" ( *value )
 | 
			
		||||
			       : "0" ( addend0 ),
 | 
			
		||||
				 "1" ( value0 ),
 | 
			
		||||
				 "2" ( size )
 | 
			
		||||
			       : "t0", "t1" );
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Subtract big integers
 | 
			
		||||
 *
 | 
			
		||||
 * @v subtrahend0	Element 0 of big integer to subtract
 | 
			
		||||
 * @v value0		Element 0 of big integer to be subtracted from
 | 
			
		||||
 * @v size		Number of elements
 | 
			
		||||
 */
 | 
			
		||||
static inline __attribute__ (( always_inline )) void
 | 
			
		||||
bigint_subtract_raw ( const uint64_t *subtrahend0, uint64_t *value0,
 | 
			
		||||
		      unsigned int size ) {
 | 
			
		||||
	uint64_t *discard_subtrahend;
 | 
			
		||||
	uint64_t *discard_value;
 | 
			
		||||
	uint64_t discard_subtrahend_i;
 | 
			
		||||
	uint64_t discard_value_i;
 | 
			
		||||
	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);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Rotate big integer left
 | 
			
		||||
 *
 | 
			
		||||
 * @v value0		Element 0 of big integer
 | 
			
		||||
 * @v size		Number of elements
 | 
			
		||||
 */
 | 
			
		||||
static inline __attribute__ (( always_inline )) void
 | 
			
		||||
bigint_rol_raw ( uint64_t *value0, unsigned int size ) {
 | 
			
		||||
	uint64_t *discard_value;
 | 
			
		||||
	uint64_t discard_value_i;
 | 
			
		||||
	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 );
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Rotate big integer right
 | 
			
		||||
 *
 | 
			
		||||
 * @v value0		Element 0 of big integer
 | 
			
		||||
 * @v size		Number of elements
 | 
			
		||||
 */
 | 
			
		||||
static inline __attribute__ (( always_inline )) void
 | 
			
		||||
bigint_ror_raw ( uint64_t *value0, unsigned int size ) {
 | 
			
		||||
	uint64_t *discard_value;
 | 
			
		||||
	uint64_t discard_value_i;
 | 
			
		||||
	uint64_t discard_value_j;
 | 
			
		||||
	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 );
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Test if big integer is equal to zero
 | 
			
		||||
 *
 | 
			
		||||
 * @v value0		Element 0 of big integer
 | 
			
		||||
 * @v size		Number of elements
 | 
			
		||||
 * @ret is_zero		Big integer is equal to zero
 | 
			
		||||
 */
 | 
			
		||||
static inline __attribute__ (( always_inline, pure )) int
 | 
			
		||||
bigint_is_zero_raw ( const uint64_t *value0, unsigned int size ) {
 | 
			
		||||
	const uint64_t *value = value0;
 | 
			
		||||
	uint64_t value_i;
 | 
			
		||||
 | 
			
		||||
	do {
 | 
			
		||||
		value_i = *(value++);
 | 
			
		||||
		if ( value_i )
 | 
			
		||||
			break;
 | 
			
		||||
	} while ( --size );
 | 
			
		||||
 | 
			
		||||
	return ( value_i == 0 );
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Compare big integers
 | 
			
		||||
 *
 | 
			
		||||
 * @v value0		Element 0 of big integer
 | 
			
		||||
 * @v reference0	Element 0 of reference big integer
 | 
			
		||||
 * @v size		Number of elements
 | 
			
		||||
 * @ret geq		Big integer is greater than or equal to the reference
 | 
			
		||||
 */
 | 
			
		||||
static inline __attribute__ (( always_inline, pure )) int
 | 
			
		||||
bigint_is_geq_raw ( const uint64_t *value0, const uint64_t *reference0,
 | 
			
		||||
		    unsigned int size ) {
 | 
			
		||||
	const uint64_t *value = ( value0 + size );
 | 
			
		||||
	const uint64_t *reference = ( reference0 + size );
 | 
			
		||||
	uint64_t value_i;
 | 
			
		||||
	uint64_t reference_i;
 | 
			
		||||
 | 
			
		||||
	do {
 | 
			
		||||
		value_i = *(--value);
 | 
			
		||||
		reference_i = *(--reference);
 | 
			
		||||
		if ( value_i != reference_i )
 | 
			
		||||
			break;
 | 
			
		||||
	} while ( --size );
 | 
			
		||||
 | 
			
		||||
	return ( value_i >= reference_i );
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Test if bit is set in big integer
 | 
			
		||||
 *
 | 
			
		||||
 * @v value0		Element 0 of big integer
 | 
			
		||||
 * @v size		Number of elements
 | 
			
		||||
 * @v bit		Bit to test
 | 
			
		||||
 * @ret is_set		Bit is set
 | 
			
		||||
 */
 | 
			
		||||
static inline __attribute__ (( always_inline )) int
 | 
			
		||||
bigint_bit_is_set_raw ( const uint64_t *value0, unsigned int size,
 | 
			
		||||
			unsigned int bit ) {
 | 
			
		||||
	const bigint_t ( size ) __attribute__ (( may_alias )) *value =
 | 
			
		||||
		( ( const void * ) value0 );
 | 
			
		||||
	unsigned int index = ( bit / ( 8 * sizeof ( value->element[0] ) ) );
 | 
			
		||||
	unsigned int subindex = ( bit % ( 8 * sizeof ( value->element[0] ) ) );
 | 
			
		||||
 | 
			
		||||
	return ( !! ( value->element[index] & ( 1UL << subindex ) ) );
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Find highest bit set in big integer
 | 
			
		||||
 *
 | 
			
		||||
 * @v value0		Element 0 of big integer
 | 
			
		||||
 * @v size		Number of elements
 | 
			
		||||
 * @ret max_bit		Highest bit set + 1 (or 0 if no bits set)
 | 
			
		||||
 */
 | 
			
		||||
static inline __attribute__ (( always_inline )) int
 | 
			
		||||
bigint_max_set_bit_raw ( const uint64_t *value0, unsigned int size ) {
 | 
			
		||||
	const uint64_t *value = ( value0 + size );
 | 
			
		||||
	int max_bit = ( 8 * sizeof ( bigint_t ( size ) ) );
 | 
			
		||||
	uint64_t value_i;
 | 
			
		||||
 | 
			
		||||
	do {
 | 
			
		||||
		value_i = *(--value);
 | 
			
		||||
		max_bit -= ( 64 - fls ( value_i ) );
 | 
			
		||||
		if ( value_i )
 | 
			
		||||
			break;
 | 
			
		||||
	} while ( --size );
 | 
			
		||||
 | 
			
		||||
	return max_bit;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Grow big integer
 | 
			
		||||
 *
 | 
			
		||||
 * @v source0		Element 0 of source big integer
 | 
			
		||||
 * @v source_size	Number of elements in source big integer
 | 
			
		||||
 * @v dest0		Element 0 of destination big integer
 | 
			
		||||
 * @v dest_size		Number of elements in destination big integer
 | 
			
		||||
 */
 | 
			
		||||
static inline __attribute__ (( always_inline )) void
 | 
			
		||||
bigint_grow_raw ( const uint64_t *source0, unsigned int source_size,
 | 
			
		||||
		  uint64_t *dest0, unsigned int dest_size ) {
 | 
			
		||||
	unsigned int pad_size = ( dest_size - source_size );
 | 
			
		||||
 | 
			
		||||
	memcpy ( dest0, source0, sizeof ( bigint_t ( source_size ) ) );
 | 
			
		||||
	memset ( ( dest0 + source_size ), 0, sizeof ( bigint_t ( pad_size ) ) );
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Shrink big integer
 | 
			
		||||
 *
 | 
			
		||||
 * @v source0		Element 0 of source big integer
 | 
			
		||||
 * @v source_size	Number of elements in source big integer
 | 
			
		||||
 * @v dest0		Element 0 of destination big integer
 | 
			
		||||
 * @v dest_size		Number of elements in destination big integer
 | 
			
		||||
 */
 | 
			
		||||
static inline __attribute__ (( always_inline )) void
 | 
			
		||||
bigint_shrink_raw ( const uint64_t *source0, unsigned int source_size __unused,
 | 
			
		||||
		    uint64_t *dest0, unsigned int dest_size ) {
 | 
			
		||||
 | 
			
		||||
	memcpy ( dest0, source0, sizeof ( bigint_t ( dest_size ) ) );
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Finalise big integer
 | 
			
		||||
 *
 | 
			
		||||
 * @v value0		Element 0 of big integer to finalise
 | 
			
		||||
 * @v size		Number of elements
 | 
			
		||||
 * @v out		Output buffer
 | 
			
		||||
 * @v len		Length of output buffer
 | 
			
		||||
 */
 | 
			
		||||
static inline __attribute__ (( always_inline )) void
 | 
			
		||||
bigint_done_raw ( const uint64_t *value0, unsigned int size __unused,
 | 
			
		||||
		  void *out, size_t len ) {
 | 
			
		||||
	const uint8_t *value_byte = ( ( const void * ) value0 );
 | 
			
		||||
	uint8_t *out_byte = ( out + len );
 | 
			
		||||
 | 
			
		||||
	/* Copy raw data in reverse order */
 | 
			
		||||
	while ( len-- )
 | 
			
		||||
		*(--out_byte) = *(value_byte++);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
extern void bigint_multiply_raw ( const uint64_t *multiplicand0,
 | 
			
		||||
				  const uint64_t *multiplier0,
 | 
			
		||||
				  uint64_t *value0, unsigned int size );
 | 
			
		||||
 | 
			
		||||
#endif /* _BITS_BIGINT_H */
 | 
			
		||||
							
								
								
									
										102
									
								
								src/arch/loong64/include/bits/bitops.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										102
									
								
								src/arch/loong64/include/bits/bitops.h
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,102 @@
 | 
			
		||||
#ifndef _BITS_BITOPS_H
 | 
			
		||||
#define _BITS_BITOPS_H
 | 
			
		||||
 | 
			
		||||
/** @file
 | 
			
		||||
 *
 | 
			
		||||
 * loongArch bit operations
 | 
			
		||||
 *
 | 
			
		||||
 * We perform atomic bit set and bit clear operations using "ll"
 | 
			
		||||
 * and "sc".  We use the output constraint to inform the
 | 
			
		||||
 * compiler that any memory from the start of the bit field up to and
 | 
			
		||||
 * including the byte containing the bit may be modified.  (This is
 | 
			
		||||
 * overkill but shouldn't matter in practice since we're unlikely to
 | 
			
		||||
 * subsequently read other bits from the same bit field.)
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
 | 
			
		||||
 | 
			
		||||
#include <stdint.h>
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Test and set bit atomically
 | 
			
		||||
 *
 | 
			
		||||
 * @v bit		Bit to set
 | 
			
		||||
 * @v bits		Bit field
 | 
			
		||||
 * @ret old		Old value of bit (zero or non-zero)
 | 
			
		||||
 */
 | 
			
		||||
static inline __attribute__ (( always_inline )) int
 | 
			
		||||
test_and_set_bit ( unsigned int bit, volatile void *bits ) {
 | 
			
		||||
	unsigned int index = ( bit / 64 );
 | 
			
		||||
	unsigned int offset = ( bit % 64 );
 | 
			
		||||
	volatile uint64_t *qword = ( ( ( volatile uint64_t * ) bits ) + index );
 | 
			
		||||
	uint64_t mask = ( 1UL << offset );
 | 
			
		||||
	uint64_t old;
 | 
			
		||||
	uint64_t new;
 | 
			
		||||
 | 
			
		||||
	__asm__ __volatile__ ( "1:				\n\t"
 | 
			
		||||
			       "ll.d %[old], %[qword]		\n\t"
 | 
			
		||||
			       "or   %[new], %[old], %[mask]	\n\t"
 | 
			
		||||
			       "sc.d %[new], %[qword]		\n\t"
 | 
			
		||||
			       "beqz %[new], 1b			\n\t"
 | 
			
		||||
			       : [old] "=&r" ( old ),
 | 
			
		||||
				 [new] "=&r" ( new ),
 | 
			
		||||
				 [qword] "+m" ( *qword )
 | 
			
		||||
			       : [mask] "r" ( mask )
 | 
			
		||||
			       : "cc", "memory");
 | 
			
		||||
	return ( !! ( old & mask ) );
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Test and clear bit atomically
 | 
			
		||||
 *
 | 
			
		||||
 * @v bit		Bit to set
 | 
			
		||||
 * @v bits		Bit field
 | 
			
		||||
 * @ret old		Old value of bit (zero or non-zero)
 | 
			
		||||
 */
 | 
			
		||||
static inline __attribute__ (( always_inline )) int
 | 
			
		||||
test_and_clear_bit ( unsigned int bit, volatile void *bits ) {
 | 
			
		||||
	unsigned int index = ( bit / 64 );
 | 
			
		||||
	unsigned int offset = ( bit % 64 );
 | 
			
		||||
	volatile uint64_t *qword = ( ( ( volatile uint64_t * ) bits ) + index );
 | 
			
		||||
	uint64_t mask = ( 1UL << offset );
 | 
			
		||||
	uint64_t old;
 | 
			
		||||
	uint64_t new;
 | 
			
		||||
 | 
			
		||||
	__asm__ __volatile__ ( "1:				\n\t"
 | 
			
		||||
			       "ll.d %[old], %[qword]		\n\t"
 | 
			
		||||
			       "andn %[new], %[old], %[mask]	\n\t"
 | 
			
		||||
			       "sc.d %[new], %[qword]		\n\t"
 | 
			
		||||
			       "beqz %[new], 1b			\n\t"
 | 
			
		||||
			       : [old] "=&r" ( old ),
 | 
			
		||||
				 [new] "=&r" ( new ),
 | 
			
		||||
				 [qword] "+m" ( *qword )
 | 
			
		||||
			       : [mask] "r" ( mask )
 | 
			
		||||
			       : "cc", "memory");
 | 
			
		||||
	return ( !! ( old & mask ) );
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Set bit atomically
 | 
			
		||||
 *
 | 
			
		||||
 * @v bit		Bit to set
 | 
			
		||||
 * @v bits		Bit field
 | 
			
		||||
 */
 | 
			
		||||
static inline __attribute__ (( always_inline )) void
 | 
			
		||||
set_bit ( unsigned int bit, volatile void *bits ) {
 | 
			
		||||
 | 
			
		||||
	test_and_set_bit ( bit, bits );
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Clear bit atomically
 | 
			
		||||
 *
 | 
			
		||||
 * @v bit		Bit to set
 | 
			
		||||
 * @v bits		Bit field
 | 
			
		||||
 */
 | 
			
		||||
static inline __attribute__ (( always_inline )) void
 | 
			
		||||
clear_bit ( unsigned int bit, volatile void *bits ) {
 | 
			
		||||
 | 
			
		||||
	test_and_clear_bit ( bit, bits );
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#endif /* _BITS_BITOPS_H */
 | 
			
		||||
							
								
								
									
										47
									
								
								src/arch/loong64/include/bits/byteswap.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										47
									
								
								src/arch/loong64/include/bits/byteswap.h
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,47 @@
 | 
			
		||||
#ifndef _BITS_BYTESWAP_H
 | 
			
		||||
#define _BITS_BYTESWAP_H
 | 
			
		||||
 | 
			
		||||
/** @file
 | 
			
		||||
 *
 | 
			
		||||
 * Byte-order swapping functions
 | 
			
		||||
 *
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include <stdint.h>
 | 
			
		||||
 | 
			
		||||
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
 | 
			
		||||
 | 
			
		||||
static inline __attribute__ (( always_inline, const )) uint16_t
 | 
			
		||||
__bswap_variable_16 ( uint16_t x ) {
 | 
			
		||||
	__asm__ ( "revb.2h %0, %1" : "=r" ( x ) : "r" ( x ) );
 | 
			
		||||
	return x;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline __attribute__ (( always_inline )) void
 | 
			
		||||
__bswap_16s ( uint16_t *x ) {
 | 
			
		||||
	*x = __bswap_variable_16 ( *x );
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline __attribute__ (( always_inline, const )) uint32_t
 | 
			
		||||
__bswap_variable_32 ( uint32_t x ) {
 | 
			
		||||
	__asm__ ( "revb.2w %0, %1" : "=r" ( x ) : "r" ( x ) );
 | 
			
		||||
	return x;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline __attribute__ (( always_inline )) void
 | 
			
		||||
__bswap_32s ( uint32_t *x ) {
 | 
			
		||||
	*x = __bswap_variable_32 ( *x );
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline __attribute__ (( always_inline, const )) uint64_t
 | 
			
		||||
__bswap_variable_64 ( uint64_t x ) {
 | 
			
		||||
	__asm__ ( "revb.d %0, %1" : "=r" ( x ) : "r" ( x ) );
 | 
			
		||||
	return x;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline __attribute__ (( always_inline )) void
 | 
			
		||||
__bswap_64s ( uint64_t *x ) {
 | 
			
		||||
	*x = __bswap_variable_64 ( *x );
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
							
								
								
									
										19
									
								
								src/arch/loong64/include/bits/compiler.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										19
									
								
								src/arch/loong64/include/bits/compiler.h
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,19 @@
 | 
			
		||||
#ifndef _BITS_COMPILER_H
 | 
			
		||||
#define _BITS_COMPILER_H
 | 
			
		||||
 | 
			
		||||
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
 | 
			
		||||
 | 
			
		||||
/** Dummy relocation type */
 | 
			
		||||
#define RELOC_TYPE_NONE R_LARCH_NONE
 | 
			
		||||
 | 
			
		||||
#ifndef ASSEMBLY
 | 
			
		||||
 | 
			
		||||
/** Unprefixed constant operand modifier */
 | 
			
		||||
#define ASM_NO_PREFIX "a"
 | 
			
		||||
 | 
			
		||||
#define __asmcall
 | 
			
		||||
#define __libgcc
 | 
			
		||||
 | 
			
		||||
#endif /* ASSEMBLY */
 | 
			
		||||
 | 
			
		||||
#endif /*_BITS_COMPILER_H */
 | 
			
		||||
							
								
								
									
										8
									
								
								src/arch/loong64/include/bits/endian.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										8
									
								
								src/arch/loong64/include/bits/endian.h
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,8 @@
 | 
			
		||||
#ifndef _BITS_ENDIAN_H
 | 
			
		||||
#define _BITS_ENDIAN_H
 | 
			
		||||
 | 
			
		||||
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
 | 
			
		||||
 | 
			
		||||
#define __BYTE_ORDER __LITTLE_ENDIAN
 | 
			
		||||
 | 
			
		||||
#endif /* _BITS_ENDIAN_H */
 | 
			
		||||
							
								
								
									
										19
									
								
								src/arch/loong64/include/bits/errfile.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										19
									
								
								src/arch/loong64/include/bits/errfile.h
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,19 @@
 | 
			
		||||
#ifndef _BITS_ERRFILE_H
 | 
			
		||||
#define _BITS_ERRFILE_H
 | 
			
		||||
 | 
			
		||||
/** @file
 | 
			
		||||
 *
 | 
			
		||||
 * LoongArch64-specific error file identifiers
 | 
			
		||||
 *
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @addtogroup errfile Error file identifiers
 | 
			
		||||
 * @{
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
/** @} */
 | 
			
		||||
 | 
			
		||||
#endif /* _BITS_ERRFILE_H */
 | 
			
		||||
							
								
								
									
										12
									
								
								src/arch/loong64/include/bits/hyperv.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								src/arch/loong64/include/bits/hyperv.h
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,12 @@
 | 
			
		||||
#ifndef _BITS_HYPERV_H
 | 
			
		||||
#define _BITS_HYPERV_H
 | 
			
		||||
 | 
			
		||||
/** @file
 | 
			
		||||
 *
 | 
			
		||||
 * Hyper-V interface
 | 
			
		||||
 *
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
 | 
			
		||||
 | 
			
		||||
#endif /* _BITS_HYPERV_H */
 | 
			
		||||
							
								
								
									
										15
									
								
								src/arch/loong64/include/bits/io.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										15
									
								
								src/arch/loong64/include/bits/io.h
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,15 @@
 | 
			
		||||
#ifndef _BITS_IO_H
 | 
			
		||||
#define _BITS_IO_H
 | 
			
		||||
 | 
			
		||||
/** @file
 | 
			
		||||
 *
 | 
			
		||||
 * LoongArch64-specific I/O API implementations
 | 
			
		||||
 *
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
 | 
			
		||||
 | 
			
		||||
/** Page shift */
 | 
			
		||||
#define PAGE_SHIFT 12
 | 
			
		||||
 | 
			
		||||
#endif /* _BITS_IO_H */
 | 
			
		||||
							
								
								
									
										12
									
								
								src/arch/loong64/include/bits/iomap.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								src/arch/loong64/include/bits/iomap.h
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,12 @@
 | 
			
		||||
#ifndef _BITS_IOMAP_H
 | 
			
		||||
#define _BITS_IOMAP_H
 | 
			
		||||
 | 
			
		||||
/** @file
 | 
			
		||||
 *
 | 
			
		||||
 * LoongArch64-specific I/O mapping API implementations
 | 
			
		||||
 *
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
 | 
			
		||||
 | 
			
		||||
#endif /* _BITS_IOMAP_H */
 | 
			
		||||
							
								
								
									
										12
									
								
								src/arch/loong64/include/bits/nap.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								src/arch/loong64/include/bits/nap.h
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,12 @@
 | 
			
		||||
#ifndef _BITS_NAP_H
 | 
			
		||||
#define _BITS_NAP_H
 | 
			
		||||
 | 
			
		||||
/** @file
 | 
			
		||||
 *
 | 
			
		||||
 * LoongArch64-specific CPU sleeping API implementations
 | 
			
		||||
 *
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
 | 
			
		||||
 | 
			
		||||
#endif /* _BITS_MAP_H */
 | 
			
		||||
							
								
								
									
										12
									
								
								src/arch/loong64/include/bits/pci_io.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								src/arch/loong64/include/bits/pci_io.h
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,12 @@
 | 
			
		||||
#ifndef _BITS_PCI_IO_H
 | 
			
		||||
#define _BITS_PCI_IO_H
 | 
			
		||||
 | 
			
		||||
/** @file
 | 
			
		||||
 *
 | 
			
		||||
 * LoongArch64-specific PCI I/O API implementations
 | 
			
		||||
 *
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
 | 
			
		||||
 | 
			
		||||
#endif /* _BITS_PCI_IO_H */
 | 
			
		||||
							
								
								
									
										28
									
								
								src/arch/loong64/include/bits/profile.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										28
									
								
								src/arch/loong64/include/bits/profile.h
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,28 @@
 | 
			
		||||
#ifndef _BITS_PROFILE_H
 | 
			
		||||
#define _BITS_PROFILE_H
 | 
			
		||||
 | 
			
		||||
/** @file
 | 
			
		||||
 *
 | 
			
		||||
 * Profiling
 | 
			
		||||
 *
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
 | 
			
		||||
 | 
			
		||||
#include <stdint.h>
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Get profiling timestamp
 | 
			
		||||
 *
 | 
			
		||||
 * @ret timestamp	Timestamp
 | 
			
		||||
 */
 | 
			
		||||
static inline __attribute__ (( always_inline )) uint64_t
 | 
			
		||||
profile_timestamp ( void ) {
 | 
			
		||||
	uint64_t cycles;
 | 
			
		||||
 | 
			
		||||
	/* Read cycle counter */
 | 
			
		||||
	__asm__ __volatile__ ( "rdtime.d %0, $zero\n\t" : "=r" ( cycles ) );
 | 
			
		||||
	return cycles;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#endif /* _BITS_PROFILE_H */
 | 
			
		||||
							
								
								
									
										12
									
								
								src/arch/loong64/include/bits/reboot.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								src/arch/loong64/include/bits/reboot.h
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,12 @@
 | 
			
		||||
#ifndef _BITS_REBOOT_H
 | 
			
		||||
#define _BITS_REBOOT_H
 | 
			
		||||
 | 
			
		||||
/** @file
 | 
			
		||||
 *
 | 
			
		||||
 * LoongArch64-specific reboot API implementations
 | 
			
		||||
 *
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
 | 
			
		||||
 | 
			
		||||
#endif /* _BITS_REBOOT_H */
 | 
			
		||||
							
								
								
									
										12
									
								
								src/arch/loong64/include/bits/sanboot.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								src/arch/loong64/include/bits/sanboot.h
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,12 @@
 | 
			
		||||
#ifndef _BITS_SANBOOT_H
 | 
			
		||||
#define _BITS_SANBOOT_H
 | 
			
		||||
 | 
			
		||||
/** @file
 | 
			
		||||
 *
 | 
			
		||||
 * LoongArch64-specific sanboot API implementations
 | 
			
		||||
 *
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
 | 
			
		||||
 | 
			
		||||
#endif /* _BITS_SANBOOT_H */
 | 
			
		||||
							
								
								
									
										12
									
								
								src/arch/loong64/include/bits/smbios.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								src/arch/loong64/include/bits/smbios.h
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,12 @@
 | 
			
		||||
#ifndef _BITS_SMBIOS_H
 | 
			
		||||
#define _BITS_SMBIOS_H
 | 
			
		||||
 | 
			
		||||
/** @file
 | 
			
		||||
 *
 | 
			
		||||
 * LoongArch64-specific SMBIOS API implementations
 | 
			
		||||
 *
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
 | 
			
		||||
 | 
			
		||||
#endif /* _BITS_SMBIOS_H */
 | 
			
		||||
							
								
								
									
										23
									
								
								src/arch/loong64/include/bits/stdint.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										23
									
								
								src/arch/loong64/include/bits/stdint.h
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,23 @@
 | 
			
		||||
#ifndef _BITS_STDINT_H
 | 
			
		||||
#define _BITS_STDINT_H
 | 
			
		||||
 | 
			
		||||
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
 | 
			
		||||
 | 
			
		||||
typedef __SIZE_TYPE__		size_t;
 | 
			
		||||
typedef signed long		ssize_t;
 | 
			
		||||
typedef signed long		off_t;
 | 
			
		||||
 | 
			
		||||
typedef unsigned char		uint8_t;
 | 
			
		||||
typedef unsigned short		uint16_t;
 | 
			
		||||
typedef unsigned int		uint32_t;
 | 
			
		||||
typedef unsigned long long	uint64_t;
 | 
			
		||||
 | 
			
		||||
typedef signed char		int8_t;
 | 
			
		||||
typedef signed short		int16_t;
 | 
			
		||||
typedef signed int		int32_t;
 | 
			
		||||
typedef signed long long	int64_t;
 | 
			
		||||
 | 
			
		||||
typedef unsigned long		physaddr_t;
 | 
			
		||||
typedef unsigned long		intptr_t;
 | 
			
		||||
 | 
			
		||||
#endif /* _BITS_STDINT_H */
 | 
			
		||||
							
								
								
									
										61
									
								
								src/arch/loong64/include/bits/string.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										61
									
								
								src/arch/loong64/include/bits/string.h
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,61 @@
 | 
			
		||||
#ifndef _BITS_STRING_H
 | 
			
		||||
#define _BITS_STRING_H
 | 
			
		||||
 | 
			
		||||
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
 | 
			
		||||
 | 
			
		||||
/** @file
 | 
			
		||||
 *
 | 
			
		||||
 * String functions
 | 
			
		||||
 *
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
extern void loong64_bzero ( void *dest, size_t len );
 | 
			
		||||
extern void loong64_memset ( void *dest, size_t len, int character );
 | 
			
		||||
extern void loong64_memcpy ( void *dest, const void *src, size_t len );
 | 
			
		||||
extern void loong64_memmove_forwards ( void *dest, const void *src, size_t len );
 | 
			
		||||
extern void loong64_memmove_backwards ( void *dest, const void *src, size_t len );
 | 
			
		||||
extern void loong64_memmove ( void *dest, const void *src, size_t len );
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Fill memory region
 | 
			
		||||
 *
 | 
			
		||||
 * @v dest		Destination region
 | 
			
		||||
 * @v character		Fill character
 | 
			
		||||
 * @v len		Length
 | 
			
		||||
 * @ret dest		Destination region
 | 
			
		||||
 */
 | 
			
		||||
static inline __attribute__ (( always_inline )) void *
 | 
			
		||||
memset ( void *dest, int character, size_t len ) {
 | 
			
		||||
	loong64_memset ( dest, len, character );
 | 
			
		||||
	return dest;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Copy memory region
 | 
			
		||||
 *
 | 
			
		||||
 * @v dest		Destination region
 | 
			
		||||
 * @v src		Source region
 | 
			
		||||
 * @v len		Length
 | 
			
		||||
 * @ret dest		Destination region
 | 
			
		||||
 */
 | 
			
		||||
static inline __attribute__ (( always_inline )) void *
 | 
			
		||||
memcpy ( void *dest, const void *src, size_t len ) {
 | 
			
		||||
	loong64_memcpy ( dest, src, len );
 | 
			
		||||
	return dest;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Copy (possibly overlapping) memory region
 | 
			
		||||
 *
 | 
			
		||||
 * @v dest		Destination region
 | 
			
		||||
 * @v src		Source region
 | 
			
		||||
 * @v len		Length
 | 
			
		||||
 * @ret dest		Destination region
 | 
			
		||||
 */
 | 
			
		||||
static inline __attribute__ (( always_inline )) void *
 | 
			
		||||
memmove ( void *dest, const void *src, size_t len ) {
 | 
			
		||||
	loong64_memmove ( dest, src, len );
 | 
			
		||||
	return dest;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#endif /* _BITS_STRING_H */
 | 
			
		||||
							
								
								
									
										69
									
								
								src/arch/loong64/include/bits/strings.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										69
									
								
								src/arch/loong64/include/bits/strings.h
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,69 @@
 | 
			
		||||
#ifndef _BITS_STRINGS_H
 | 
			
		||||
#define _BITS_STRINGS_H
 | 
			
		||||
 | 
			
		||||
/** @file
 | 
			
		||||
 *
 | 
			
		||||
 * String functions
 | 
			
		||||
 *
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Find first (i.e. least significant) set bit
 | 
			
		||||
 *
 | 
			
		||||
 * @v value		Value
 | 
			
		||||
 * @ret lsb		Least significant bit set in value (LSB=1), or zero
 | 
			
		||||
 */
 | 
			
		||||
static inline __attribute__ (( always_inline )) int __ffsll ( long long value ){
 | 
			
		||||
	unsigned long long bits = value;
 | 
			
		||||
	unsigned long long lsb;
 | 
			
		||||
	unsigned int lz;
 | 
			
		||||
 | 
			
		||||
	/* Extract least significant set bit */
 | 
			
		||||
	lsb = ( bits & -bits );
 | 
			
		||||
 | 
			
		||||
	/* Count number of leading zeroes before LSB */
 | 
			
		||||
	__asm__ ( "clz.d %0, %1" : "=r" ( lz ) : "r" ( lsb ) );
 | 
			
		||||
 | 
			
		||||
	return ( 64 - lz );
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Find first (i.e. least significant) set bit
 | 
			
		||||
 *
 | 
			
		||||
 * @v value		Value
 | 
			
		||||
 * @ret lsb		Least significant bit set in value (LSB=1), or zero
 | 
			
		||||
 */
 | 
			
		||||
static inline __attribute__ (( always_inline )) int __ffsl ( long value ) {
 | 
			
		||||
 | 
			
		||||
	return __ffsll ( value );
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Find last (i.e. most significant) set bit
 | 
			
		||||
 *
 | 
			
		||||
 * @v value		Value
 | 
			
		||||
 * @ret msb		Most significant bit set in value (LSB=1), or zero
 | 
			
		||||
 */
 | 
			
		||||
static inline __attribute__ (( always_inline )) int __flsll ( long long value ){
 | 
			
		||||
	unsigned int lz;
 | 
			
		||||
 | 
			
		||||
	/* Count number of leading zeroes */
 | 
			
		||||
	__asm__ ( "clz.d %0, %1" : "=r" ( lz ) : "r" ( value ) );
 | 
			
		||||
 | 
			
		||||
	return ( 64 - lz );
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Find last (i.e. most significant) set bit
 | 
			
		||||
 *
 | 
			
		||||
 * @v value		Value
 | 
			
		||||
 * @ret msb		Most significant bit set in value (LSB=1), or zero
 | 
			
		||||
 */
 | 
			
		||||
static inline __attribute__ (( always_inline )) int __flsl ( long value ) {
 | 
			
		||||
 | 
			
		||||
	return __flsll ( value );
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#endif /* _BITS_STRINGS_H */
 | 
			
		||||
							
								
								
									
										19
									
								
								src/arch/loong64/include/bits/tcpip.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										19
									
								
								src/arch/loong64/include/bits/tcpip.h
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,19 @@
 | 
			
		||||
#ifndef _BITS_TCPIP_H
 | 
			
		||||
#define _BITS_TCPIP_H
 | 
			
		||||
 | 
			
		||||
/** @file
 | 
			
		||||
 *
 | 
			
		||||
 * Transport-network layer interface
 | 
			
		||||
 *
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
 | 
			
		||||
 | 
			
		||||
static inline __attribute__ (( always_inline )) uint16_t
 | 
			
		||||
tcpip_continue_chksum ( uint16_t partial, const void *data, size_t len ) {
 | 
			
		||||
 | 
			
		||||
	/* Not yet optimised */
 | 
			
		||||
	return generic_tcpip_continue_chksum ( partial, data, len );
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#endif /* _BITS_TCPIP_H */
 | 
			
		||||
							
								
								
									
										12
									
								
								src/arch/loong64/include/bits/time.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								src/arch/loong64/include/bits/time.h
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,12 @@
 | 
			
		||||
#ifndef _BITS_TIME_H
 | 
			
		||||
#define _BITS_TIME_H
 | 
			
		||||
 | 
			
		||||
/** @file
 | 
			
		||||
 *
 | 
			
		||||
 * LoongArch64-specific time API implementations
 | 
			
		||||
 *
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
 | 
			
		||||
 | 
			
		||||
#endif /* _BITS_TIME_H */
 | 
			
		||||
							
								
								
									
										12
									
								
								src/arch/loong64/include/bits/uaccess.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								src/arch/loong64/include/bits/uaccess.h
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,12 @@
 | 
			
		||||
#ifndef _BITS_UACCESS_H
 | 
			
		||||
#define _BITS_UACCESS_H
 | 
			
		||||
 | 
			
		||||
/** @file
 | 
			
		||||
 *
 | 
			
		||||
 * LoongArch64-specific user access API implementations
 | 
			
		||||
 *
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
 | 
			
		||||
 | 
			
		||||
#endif /* _BITS_UACCESS_H */
 | 
			
		||||
							
								
								
									
										12
									
								
								src/arch/loong64/include/bits/uart.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								src/arch/loong64/include/bits/uart.h
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,12 @@
 | 
			
		||||
#ifndef _BITS_UART_H
 | 
			
		||||
#define _BITS_UART_H
 | 
			
		||||
 | 
			
		||||
/** @file
 | 
			
		||||
 *
 | 
			
		||||
 * 16550-compatible UART
 | 
			
		||||
 *
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
 | 
			
		||||
 | 
			
		||||
#endif /* _BITS_UART_H */
 | 
			
		||||
							
								
								
									
										12
									
								
								src/arch/loong64/include/bits/umalloc.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								src/arch/loong64/include/bits/umalloc.h
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,12 @@
 | 
			
		||||
#ifndef _BITS_UMALLOC_H
 | 
			
		||||
#define _BITS_UMALLOC_H
 | 
			
		||||
 | 
			
		||||
/** @file
 | 
			
		||||
 *
 | 
			
		||||
 * LoongArch64-specific user memory allocation API implementations
 | 
			
		||||
 *
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
 | 
			
		||||
 | 
			
		||||
#endif /* _BITS_UMALLOC_H */
 | 
			
		||||
							
								
								
									
										13
									
								
								src/arch/loong64/include/bits/xen.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										13
									
								
								src/arch/loong64/include/bits/xen.h
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,13 @@
 | 
			
		||||
#ifndef _BITS_XEN_H
 | 
			
		||||
#define _BITS_XEN_H
 | 
			
		||||
 | 
			
		||||
/** @file
 | 
			
		||||
 *
 | 
			
		||||
 * Xen interface
 | 
			
		||||
 *
 | 
			
		||||
 */
 | 
			
		||||
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
 | 
			
		||||
 | 
			
		||||
#include <ipxe/nonxen.h>
 | 
			
		||||
 | 
			
		||||
#endif /* _BITS_XEN_H */
 | 
			
		||||
							
								
								
									
										45
									
								
								src/arch/loong64/include/gdbmach.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										45
									
								
								src/arch/loong64/include/gdbmach.h
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,45 @@
 | 
			
		||||
#ifndef GDBMACH_H
 | 
			
		||||
#define GDBMACH_H
 | 
			
		||||
 | 
			
		||||
/** @file
 | 
			
		||||
 *
 | 
			
		||||
 * GDB architecture specifics
 | 
			
		||||
 *
 | 
			
		||||
 * This file declares functions for manipulating the machine state and
 | 
			
		||||
 * debugging context.
 | 
			
		||||
 *
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include <stdint.h>
 | 
			
		||||
 | 
			
		||||
typedef unsigned long gdbreg_t;
 | 
			
		||||
 | 
			
		||||
/* Register snapshot */
 | 
			
		||||
enum {
 | 
			
		||||
	/* Not yet implemented */
 | 
			
		||||
	GDBMACH_NREGS,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#define GDBMACH_SIZEOF_REGS ( GDBMACH_NREGS * sizeof ( gdbreg_t ) )
 | 
			
		||||
 | 
			
		||||
static inline void gdbmach_set_pc ( gdbreg_t *regs, gdbreg_t pc ) {
 | 
			
		||||
	/* Not yet implemented */
 | 
			
		||||
	( void ) regs;
 | 
			
		||||
	( void ) pc;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline void gdbmach_set_single_step ( gdbreg_t *regs, int step ) {
 | 
			
		||||
	/* Not yet implemented */
 | 
			
		||||
	( void ) regs;
 | 
			
		||||
	( void ) step;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline void gdbmach_breakpoint ( void ) {
 | 
			
		||||
	/* Not yet implemented */
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
extern int gdbmach_set_breakpoint ( int type, unsigned long addr, size_t len,
 | 
			
		||||
				    int enable );
 | 
			
		||||
extern void gdbmach_init ( void );
 | 
			
		||||
 | 
			
		||||
#endif /* GDBMACH_H */
 | 
			
		||||
							
								
								
									
										20
									
								
								src/arch/loong64/include/ipxe/efi/dhcparch.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										20
									
								
								src/arch/loong64/include/ipxe/efi/dhcparch.h
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,20 @@
 | 
			
		||||
#ifndef _IPXE_EFI_DHCPARCH_H
 | 
			
		||||
#define _IPXE_EFI_DHCPARCH_H
 | 
			
		||||
 | 
			
		||||
/** @file
 | 
			
		||||
 *
 | 
			
		||||
 * DHCP client architecture definitions
 | 
			
		||||
 *
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
 | 
			
		||||
 | 
			
		||||
#include <ipxe/dhcp.h>
 | 
			
		||||
 | 
			
		||||
/** DHCP client architecture */
 | 
			
		||||
#define DHCP_ARCH_CLIENT_ARCHITECTURE DHCP_CLIENT_ARCHITECTURE_LOONG64
 | 
			
		||||
 | 
			
		||||
/** DHCP client network device interface */
 | 
			
		||||
#define DHCP_ARCH_CLIENT_NDI 1 /* UNDI */ , 3, 10 /* v3.10 */
 | 
			
		||||
 | 
			
		||||
#endif /* _IPXE_EFI_DHCPARCH_H */
 | 
			
		||||
							
								
								
									
										53
									
								
								src/arch/loong64/include/limits.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										53
									
								
								src/arch/loong64/include/limits.h
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,53 @@
 | 
			
		||||
#ifndef LIMITS_H
 | 
			
		||||
#define LIMITS_H	1
 | 
			
		||||
 | 
			
		||||
/* Number of bits in a `char' */
 | 
			
		||||
#define CHAR_BIT	8
 | 
			
		||||
 | 
			
		||||
/* Minimum and maximum values a `signed char' can hold */
 | 
			
		||||
#define SCHAR_MIN	(-128)
 | 
			
		||||
#define SCHAR_MAX	127
 | 
			
		||||
 | 
			
		||||
/* Maximum value an `unsigned char' can hold. (Minimum is 0.) */
 | 
			
		||||
#define UCHAR_MAX	255
 | 
			
		||||
 | 
			
		||||
/* Minimum and maximum values a `char' can hold */
 | 
			
		||||
#define CHAR_MIN	SCHAR_MIN
 | 
			
		||||
#define CHAR_MAX	SCHAR_MAX
 | 
			
		||||
 | 
			
		||||
/* Minimum and maximum values a `signed short int' can hold */
 | 
			
		||||
#define SHRT_MIN	(-32768)
 | 
			
		||||
#define SHRT_MAX	32767
 | 
			
		||||
 | 
			
		||||
/* Maximum value an `unsigned short' can hold. (Minimum is 0.) */
 | 
			
		||||
#define USHRT_MAX	65535
 | 
			
		||||
 | 
			
		||||
/* Minimum and maximum values a `signed int' can hold */
 | 
			
		||||
#define INT_MIN		(-INT_MAX - 1)
 | 
			
		||||
#define INT_MAX		2147483647
 | 
			
		||||
 | 
			
		||||
/* Maximum value an `unsigned int' can hold. (Minimum is 0.) */
 | 
			
		||||
#define UINT_MAX	4294967295U
 | 
			
		||||
 | 
			
		||||
/* Minimum and maximum values a `signed int' can hold */
 | 
			
		||||
#define INT_MAX		2147483647
 | 
			
		||||
#define INT_MIN		(-INT_MAX - 1)
 | 
			
		||||
 | 
			
		||||
/* Maximum value an `unsigned int' can hold. (Minimum is 0.) */
 | 
			
		||||
#define UINT_MAX	4294967295U
 | 
			
		||||
 | 
			
		||||
/* Minimum and maximum values a `signed long' can hold */
 | 
			
		||||
#define LONG_MAX	9223372036854775807L
 | 
			
		||||
#define LONG_MIN	(-LONG_MAX - 1L)
 | 
			
		||||
 | 
			
		||||
/* Maximum value an `unsigned long' can hold. (Minimum is 0.) */
 | 
			
		||||
#define ULONG_MAX	18446744073709551615UL
 | 
			
		||||
 | 
			
		||||
/* Minimum and maximum values a `signed long long' can hold */
 | 
			
		||||
#define LLONG_MAX	9223372036854775807LL
 | 
			
		||||
#define LLONG_MIN	(-LONG_MAX - 1LL)
 | 
			
		||||
 | 
			
		||||
/* Maximum value an `unsigned long long' can hold. (Minimum is 0.) */
 | 
			
		||||
#define ULLONG_MAX	18446744073709551615ULL
 | 
			
		||||
 | 
			
		||||
#endif /* LIMITS_H */
 | 
			
		||||
							
								
								
									
										31
									
								
								src/arch/loong64/include/setjmp.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										31
									
								
								src/arch/loong64/include/setjmp.h
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,31 @@
 | 
			
		||||
#ifndef _SETJMP_H
 | 
			
		||||
#define _SETJMP_H
 | 
			
		||||
 | 
			
		||||
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
 | 
			
		||||
 | 
			
		||||
#include <stdint.h>
 | 
			
		||||
 | 
			
		||||
/** jump buffer env*/
 | 
			
		||||
typedef struct {
 | 
			
		||||
	uint64_t s0;
 | 
			
		||||
	uint64_t s1;
 | 
			
		||||
	uint64_t s2;
 | 
			
		||||
	uint64_t s3;
 | 
			
		||||
	uint64_t s4;
 | 
			
		||||
	uint64_t s5;
 | 
			
		||||
	uint64_t s6;
 | 
			
		||||
	uint64_t s7;
 | 
			
		||||
	uint64_t s8;
 | 
			
		||||
 | 
			
		||||
	uint64_t fp;
 | 
			
		||||
	uint64_t sp;
 | 
			
		||||
	uint64_t ra;
 | 
			
		||||
} jmp_buf[1];
 | 
			
		||||
 | 
			
		||||
extern int __asmcall __attribute__ (( returns_twice ))
 | 
			
		||||
setjmp ( jmp_buf env );
 | 
			
		||||
 | 
			
		||||
extern void __asmcall __attribute__ (( noreturn ))
 | 
			
		||||
longjmp ( jmp_buf env, int val );
 | 
			
		||||
 | 
			
		||||
#endif /* _SETJMP_H */
 | 
			
		||||
							
								
								
									
										103
									
								
								src/arch/x86/core/rdrand.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										103
									
								
								src/arch/x86/core/rdrand.c
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,103 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (C) 2023 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
 | 
			
		||||
 *
 | 
			
		||||
 * Hardware random number generator
 | 
			
		||||
 *
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include <errno.h>
 | 
			
		||||
#include <ipxe/cpuid.h>
 | 
			
		||||
#include <ipxe/entropy.h>
 | 
			
		||||
#include <ipxe/drbg.h>
 | 
			
		||||
 | 
			
		||||
struct entropy_source rdrand_entropy __entropy_source ( ENTROPY_PREFERRED );
 | 
			
		||||
 | 
			
		||||
/** Number of times to retry RDRAND instruction */
 | 
			
		||||
#define RDRAND_RETRY_COUNT 16
 | 
			
		||||
 | 
			
		||||
/** Colour for debug messages */
 | 
			
		||||
#define colour &rdrand_entropy
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Enable entropy gathering
 | 
			
		||||
 *
 | 
			
		||||
 * @ret rc		Return status code
 | 
			
		||||
 */
 | 
			
		||||
static int rdrand_entropy_enable ( void ) {
 | 
			
		||||
	struct x86_features features;
 | 
			
		||||
 | 
			
		||||
	/* Check that RDRAND is supported */
 | 
			
		||||
	x86_features ( &features );
 | 
			
		||||
	if ( ! ( features.intel.ecx & CPUID_FEATURES_INTEL_ECX_RDRAND ) ) {
 | 
			
		||||
		DBGC ( colour, "RDRAND not supported\n" );
 | 
			
		||||
		return -ENOTSUP;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* Data returned by RDRAND is theoretically full entropy, up
 | 
			
		||||
	 * to a security strength of 128 bits, so assume that each
 | 
			
		||||
	 * sample contains exactly 8 bits of entropy.
 | 
			
		||||
	 */
 | 
			
		||||
	if ( DRBG_SECURITY_STRENGTH > 128 )
 | 
			
		||||
		return -ENOTSUP;
 | 
			
		||||
	entropy_init ( &rdrand_entropy, MIN_ENTROPY ( 8.0 ) );
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Get noise sample
 | 
			
		||||
 *
 | 
			
		||||
 * @ret noise		Noise sample
 | 
			
		||||
 * @ret rc		Return status code
 | 
			
		||||
 */
 | 
			
		||||
static int rdrand_get_noise ( noise_sample_t *noise ) {
 | 
			
		||||
	unsigned int result;
 | 
			
		||||
	unsigned int discard_c;
 | 
			
		||||
	unsigned int ok;
 | 
			
		||||
 | 
			
		||||
	/* Issue RDRAND, retrying until CF is set */
 | 
			
		||||
	__asm__ ( "\n1:\n\t"
 | 
			
		||||
		  "rdrand %0\n\t"
 | 
			
		||||
		  "sbb %1, %1\n\t"
 | 
			
		||||
		  "loopz 1b\n\t"
 | 
			
		||||
		  : "=r" ( result ), "=r" ( ok ), "=c" ( discard_c )
 | 
			
		||||
		  : "2" ( RDRAND_RETRY_COUNT ) );
 | 
			
		||||
	if ( ! ok ) {
 | 
			
		||||
		DBGC ( colour, "RDRAND failed to become ready\n" );
 | 
			
		||||
		return -EBUSY;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	*noise = result;
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/** Hardware random number generator entropy source */
 | 
			
		||||
struct entropy_source rdrand_entropy __entropy_source ( ENTROPY_PREFERRED ) = {
 | 
			
		||||
	.name = "rdrand",
 | 
			
		||||
	.enable = rdrand_entropy_enable,
 | 
			
		||||
	.get_noise = rdrand_get_noise,
 | 
			
		||||
};
 | 
			
		||||
@ -247,19 +247,17 @@ static void bzimage_update_header ( struct image *image,
 | 
			
		||||
 *
 | 
			
		||||
 * @v image		bzImage file
 | 
			
		||||
 * @v bzimg		bzImage context
 | 
			
		||||
 * @v cmdline		Kernel command line
 | 
			
		||||
 * @ret rc		Return status code
 | 
			
		||||
 */
 | 
			
		||||
static int bzimage_parse_cmdline ( struct image *image,
 | 
			
		||||
				   struct bzimage_context *bzimg,
 | 
			
		||||
				   char *cmdline ) {
 | 
			
		||||
				   struct bzimage_context *bzimg ) {
 | 
			
		||||
	const char *vga;
 | 
			
		||||
	const char *mem;
 | 
			
		||||
	char *sep;
 | 
			
		||||
	char *vga;
 | 
			
		||||
	char *mem;
 | 
			
		||||
	char *end;
 | 
			
		||||
 | 
			
		||||
	/* Look for "vga=" */
 | 
			
		||||
	if ( ( vga = strstr ( cmdline, "vga=" ) ) ) {
 | 
			
		||||
		vga += 4;
 | 
			
		||||
	if ( ( vga = image_argument ( image, "vga=" ) ) ) {
 | 
			
		||||
		sep = strchr ( vga, ' ' );
 | 
			
		||||
		if ( sep )
 | 
			
		||||
			*sep = '\0';
 | 
			
		||||
@ -270,10 +268,10 @@ static int bzimage_parse_cmdline ( struct image *image,
 | 
			
		||||
		} else if ( strcmp ( vga, "ask" ) == 0 ) {
 | 
			
		||||
			bzimg->vid_mode = BZI_VID_MODE_ASK;
 | 
			
		||||
		} else {
 | 
			
		||||
			bzimg->vid_mode = strtoul ( vga, &vga, 0 );
 | 
			
		||||
			if ( *vga ) {
 | 
			
		||||
			bzimg->vid_mode = strtoul ( vga, &end, 0 );
 | 
			
		||||
			if ( *end ) {
 | 
			
		||||
				DBGC ( image, "bzImage %p strange \"vga=\" "
 | 
			
		||||
				       "terminator '%c'\n", image, *vga );
 | 
			
		||||
				       "terminator '%c'\n", image, *end );
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		if ( sep )
 | 
			
		||||
@ -281,10 +279,9 @@ static int bzimage_parse_cmdline ( struct image *image,
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* Look for "mem=" */
 | 
			
		||||
	if ( ( mem = strstr ( cmdline, "mem=" ) ) ) {
 | 
			
		||||
		mem += 4;
 | 
			
		||||
		bzimg->mem_limit = strtoul ( mem, &mem, 0 );
 | 
			
		||||
		switch ( *mem ) {
 | 
			
		||||
	if ( ( mem = image_argument ( image, "mem=" ) ) ) {
 | 
			
		||||
		bzimg->mem_limit = strtoul ( mem, &end, 0 );
 | 
			
		||||
		switch ( *end ) {
 | 
			
		||||
		case 'G':
 | 
			
		||||
		case 'g':
 | 
			
		||||
			bzimg->mem_limit <<= 10;
 | 
			
		||||
@ -302,7 +299,7 @@ static int bzimage_parse_cmdline ( struct image *image,
 | 
			
		||||
			break;
 | 
			
		||||
		default:
 | 
			
		||||
			DBGC ( image, "bzImage %p strange \"mem=\" "
 | 
			
		||||
			       "terminator '%c'\n", image, *mem );
 | 
			
		||||
			       "terminator '%c'\n", image, *end );
 | 
			
		||||
			break;
 | 
			
		||||
		}
 | 
			
		||||
		bzimg->mem_limit -= 1;
 | 
			
		||||
@ -316,11 +313,10 @@ static int bzimage_parse_cmdline ( struct image *image,
 | 
			
		||||
 *
 | 
			
		||||
 * @v image		bzImage image
 | 
			
		||||
 * @v bzimg		bzImage context
 | 
			
		||||
 * @v cmdline		Kernel command line
 | 
			
		||||
 */
 | 
			
		||||
static void bzimage_set_cmdline ( struct image *image,
 | 
			
		||||
				  struct bzimage_context *bzimg,
 | 
			
		||||
				  const char *cmdline ) {
 | 
			
		||||
				  struct bzimage_context *bzimg ) {
 | 
			
		||||
	const char *cmdline = ( image->cmdline ? image->cmdline : "" );
 | 
			
		||||
	size_t cmdline_len;
 | 
			
		||||
 | 
			
		||||
	/* Copy command line down to real-mode portion */
 | 
			
		||||
@ -528,7 +524,6 @@ static void bzimage_load_initrds ( struct image *image,
 | 
			
		||||
 */
 | 
			
		||||
static int bzimage_exec ( struct image *image ) {
 | 
			
		||||
	struct bzimage_context bzimg;
 | 
			
		||||
	char *cmdline = ( image->cmdline ? image->cmdline : "" );
 | 
			
		||||
	int rc;
 | 
			
		||||
 | 
			
		||||
	/* Read and parse header from image */
 | 
			
		||||
@ -551,7 +546,7 @@ static int bzimage_exec ( struct image *image ) {
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* Parse command line for bootloader parameters */
 | 
			
		||||
	if ( ( rc = bzimage_parse_cmdline ( image, &bzimg, cmdline ) ) != 0)
 | 
			
		||||
	if ( ( rc = bzimage_parse_cmdline ( image, &bzimg ) ) != 0)
 | 
			
		||||
		return rc;
 | 
			
		||||
 | 
			
		||||
	/* Check that initrds can be loaded */
 | 
			
		||||
@ -568,7 +563,7 @@ static int bzimage_exec ( struct image *image ) {
 | 
			
		||||
		      bzimg.rm_filesz, bzimg.pm_sz );
 | 
			
		||||
 | 
			
		||||
	/* Store command line */
 | 
			
		||||
	bzimage_set_cmdline ( image, &bzimg, cmdline );
 | 
			
		||||
	bzimage_set_cmdline ( image, &bzimg );
 | 
			
		||||
 | 
			
		||||
	/* Prepare for exiting.  Must do this before loading initrds,
 | 
			
		||||
	 * since loading the initrds will corrupt the external heap.
 | 
			
		||||
 | 
			
		||||
@ -1,14 +0,0 @@
 | 
			
		||||
#ifndef _BITS_ENTROPY_H
 | 
			
		||||
#define _BITS_ENTROPY_H
 | 
			
		||||
 | 
			
		||||
/** @file
 | 
			
		||||
 *
 | 
			
		||||
 * x86-specific entropy API implementations
 | 
			
		||||
 *
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
 | 
			
		||||
 | 
			
		||||
#include <ipxe/rtc_entropy.h>
 | 
			
		||||
 | 
			
		||||
#endif /* _BITS_ENTROPY_H */
 | 
			
		||||
@ -28,6 +28,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
 | 
			
		||||
#define ERRFILE_cpuid		( ERRFILE_ARCH | ERRFILE_CORE | 0x00110000 )
 | 
			
		||||
#define ERRFILE_rdtsc_timer	( ERRFILE_ARCH | ERRFILE_CORE | 0x00120000 )
 | 
			
		||||
#define ERRFILE_acpi_timer	( ERRFILE_ARCH | ERRFILE_CORE | 0x00130000 )
 | 
			
		||||
#define ERRFILE_rdrand		( ERRFILE_ARCH | ERRFILE_CORE | 0x00140000 )
 | 
			
		||||
 | 
			
		||||
#define ERRFILE_bootsector     ( ERRFILE_ARCH | ERRFILE_IMAGE | 0x00000000 )
 | 
			
		||||
#define ERRFILE_bzimage	       ( ERRFILE_ARCH | ERRFILE_IMAGE | 0x00010000 )
 | 
			
		||||
 | 
			
		||||
@ -9,6 +9,9 @@
 | 
			
		||||
 | 
			
		||||
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
 | 
			
		||||
 | 
			
		||||
/** Page shift */
 | 
			
		||||
#define PAGE_SHIFT 12
 | 
			
		||||
 | 
			
		||||
#include <ipxe/x86_io.h>
 | 
			
		||||
 | 
			
		||||
#endif /* _BITS_IO_H */
 | 
			
		||||
 | 
			
		||||
@ -39,6 +39,9 @@ struct x86_features {
 | 
			
		||||
/** Get standard features */
 | 
			
		||||
#define CPUID_FEATURES 0x00000001UL
 | 
			
		||||
 | 
			
		||||
/** RDRAND instruction is supported */
 | 
			
		||||
#define CPUID_FEATURES_INTEL_ECX_RDRAND 0x40000000UL
 | 
			
		||||
 | 
			
		||||
/** Hypervisor is present */
 | 
			
		||||
#define CPUID_FEATURES_INTEL_ECX_HYPERVISOR 0x80000000UL
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -1,62 +0,0 @@
 | 
			
		||||
#ifndef _IPXE_RTC_ENTROPY_H
 | 
			
		||||
#define _IPXE_RTC_ENTROPY_H
 | 
			
		||||
 | 
			
		||||
/** @file
 | 
			
		||||
 *
 | 
			
		||||
 * RTC-based entropy source
 | 
			
		||||
 *
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
 | 
			
		||||
 | 
			
		||||
#include <stdint.h>
 | 
			
		||||
 | 
			
		||||
#ifdef ENTROPY_RTC
 | 
			
		||||
#define ENTROPY_PREFIX_rtc
 | 
			
		||||
#else
 | 
			
		||||
#define ENTROPY_PREFIX_rtc __rtc_
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * min-entropy per sample
 | 
			
		||||
 *
 | 
			
		||||
 * @ret min_entropy	min-entropy of each sample
 | 
			
		||||
 */
 | 
			
		||||
static inline __always_inline min_entropy_t
 | 
			
		||||
ENTROPY_INLINE ( rtc, min_entropy_per_sample ) ( void ) {
 | 
			
		||||
 | 
			
		||||
	/* The min-entropy has been measured on several platforms
 | 
			
		||||
	 * using the entropy_sample test code.  Modelling the samples
 | 
			
		||||
	 * as independent, and using a confidence level of 99.99%, the
 | 
			
		||||
	 * measurements were as follows:
 | 
			
		||||
	 *
 | 
			
		||||
	 *    qemu-kvm		: 7.38 bits
 | 
			
		||||
	 *    VMware		: 7.46 bits
 | 
			
		||||
	 *    Physical hardware	: 2.67 bits
 | 
			
		||||
	 *
 | 
			
		||||
	 * We choose the lowest of these (2.67 bits) and apply a 50%
 | 
			
		||||
	 * safety margin to allow for some potential non-independence
 | 
			
		||||
	 * of samples.
 | 
			
		||||
	 */
 | 
			
		||||
	return MIN_ENTROPY ( 1.3 );
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
extern uint8_t rtc_sample ( void );
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Get noise sample
 | 
			
		||||
 *
 | 
			
		||||
 * @ret noise		Noise sample
 | 
			
		||||
 * @ret rc		Return status code
 | 
			
		||||
 */
 | 
			
		||||
static inline __always_inline int
 | 
			
		||||
ENTROPY_INLINE ( rtc, get_noise ) ( noise_sample_t *noise ) {
 | 
			
		||||
 | 
			
		||||
	/* Get sample */
 | 
			
		||||
	*noise = rtc_sample();
 | 
			
		||||
 | 
			
		||||
	/* Always successful */
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#endif /* _IPXE_RTC_ENTROPY_H */
 | 
			
		||||
@ -28,9 +28,6 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
 | 
			
		||||
 *
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
/** Page shift */
 | 
			
		||||
#define PAGE_SHIFT 12
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Physical<->Bus address mappings
 | 
			
		||||
 *
 | 
			
		||||
 | 
			
		||||
@ -39,9 +39,14 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
 | 
			
		||||
#include <ipxe/cpuid.h>
 | 
			
		||||
#include <ipxe/entropy.h>
 | 
			
		||||
 | 
			
		||||
struct entropy_source rtc_entropy __entropy_source ( ENTROPY_NORMAL );
 | 
			
		||||
 | 
			
		||||
/** Maximum time to wait for an RTC interrupt, in milliseconds */
 | 
			
		||||
#define RTC_MAX_WAIT_MS 100
 | 
			
		||||
 | 
			
		||||
/** Number of RTC interrupts to check for */
 | 
			
		||||
#define RTC_CHECK_COUNT 3
 | 
			
		||||
 | 
			
		||||
/** RTC interrupt handler */
 | 
			
		||||
extern void rtc_isr ( void );
 | 
			
		||||
 | 
			
		||||
@ -145,6 +150,7 @@ static void rtc_disable_int ( void ) {
 | 
			
		||||
 * @ret rc		Return status code
 | 
			
		||||
 */
 | 
			
		||||
static int rtc_entropy_check ( void ) {
 | 
			
		||||
	unsigned int count = 0;
 | 
			
		||||
	unsigned int i;
 | 
			
		||||
 | 
			
		||||
	/* Check that RTC interrupts are working */
 | 
			
		||||
@ -158,14 +164,18 @@ static int rtc_entropy_check ( void ) {
 | 
			
		||||
				       "cli\n\t" );
 | 
			
		||||
 | 
			
		||||
		/* Check for RTC interrupt flag */
 | 
			
		||||
		if ( rtc_flag )
 | 
			
		||||
			return 0;
 | 
			
		||||
		if ( rtc_flag ) {
 | 
			
		||||
			rtc_flag = 0;
 | 
			
		||||
			if ( ++count >= RTC_CHECK_COUNT )
 | 
			
		||||
				return 0;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		/* Delay */
 | 
			
		||||
		mdelay ( 1 );
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	DBGC ( &rtc_flag, "RTC timed out waiting for interrupt\n" );
 | 
			
		||||
	DBGC ( &rtc_flag, "RTC timed out waiting for interrupt %d/%d\n",
 | 
			
		||||
	       ( count + 1 ), RTC_CHECK_COUNT );
 | 
			
		||||
	return -ETIMEDOUT;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -195,6 +205,21 @@ static int rtc_entropy_enable ( void ) {
 | 
			
		||||
	if ( ( rc = rtc_entropy_check() ) != 0 )
 | 
			
		||||
		goto err_check;
 | 
			
		||||
 | 
			
		||||
	/* The min-entropy has been measured on several platforms
 | 
			
		||||
	 * using the entropy_sample test code.  Modelling the samples
 | 
			
		||||
	 * as independent, and using a confidence level of 99.99%, the
 | 
			
		||||
	 * measurements were as follows:
 | 
			
		||||
	 *
 | 
			
		||||
	 *    qemu-kvm		: 7.38 bits
 | 
			
		||||
	 *    VMware		: 7.46 bits
 | 
			
		||||
	 *    Physical hardware	: 2.67 bits
 | 
			
		||||
	 *
 | 
			
		||||
	 * We choose the lowest of these (2.67 bits) and apply a 50%
 | 
			
		||||
	 * safety margin to allow for some potential non-independence
 | 
			
		||||
	 * of samples.
 | 
			
		||||
	 */
 | 
			
		||||
	entropy_init ( &rtc_entropy, MIN_ENTROPY ( 1.3 ) );
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
 | 
			
		||||
 err_check:
 | 
			
		||||
@ -218,11 +243,12 @@ static void rtc_entropy_disable ( void ) {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Measure a single RTC tick
 | 
			
		||||
 * Get noise sample
 | 
			
		||||
 *
 | 
			
		||||
 * @ret delta		Length of RTC tick (in TSC units)
 | 
			
		||||
 * @ret noise		Noise sample
 | 
			
		||||
 * @ret rc		Return status code
 | 
			
		||||
 */
 | 
			
		||||
uint8_t rtc_sample ( void ) {
 | 
			
		||||
static int rtc_get_noise ( noise_sample_t *noise ) {
 | 
			
		||||
	uint32_t before;
 | 
			
		||||
	uint32_t after;
 | 
			
		||||
	uint32_t temp;
 | 
			
		||||
@ -257,10 +283,14 @@ uint8_t rtc_sample ( void ) {
 | 
			
		||||
		: "=a" ( after ), "=d" ( before ), "=Q" ( temp )
 | 
			
		||||
		: "2" ( 0 ) );
 | 
			
		||||
 | 
			
		||||
	return ( after - before );
 | 
			
		||||
	*noise = ( after - before );
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
PROVIDE_ENTROPY_INLINE ( rtc, min_entropy_per_sample );
 | 
			
		||||
PROVIDE_ENTROPY ( rtc, entropy_enable, rtc_entropy_enable );
 | 
			
		||||
PROVIDE_ENTROPY ( rtc, entropy_disable, rtc_entropy_disable );
 | 
			
		||||
PROVIDE_ENTROPY_INLINE ( rtc, get_noise );
 | 
			
		||||
/** RTC entropy source */
 | 
			
		||||
struct entropy_source rtc_entropy __entropy_source ( ENTROPY_NORMAL ) = {
 | 
			
		||||
	.name = "rtc",
 | 
			
		||||
	.enable = rtc_entropy_enable,
 | 
			
		||||
	.disable = rtc_entropy_disable,
 | 
			
		||||
	.get_noise = rtc_get_noise,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
@ -8,6 +8,9 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
 | 
			
		||||
 | 
			
		||||
#ifndef ASSEMBLY
 | 
			
		||||
 | 
			
		||||
/** Unprefixed constant operand modifier */
 | 
			
		||||
#define ASM_NO_PREFIX "c"
 | 
			
		||||
 | 
			
		||||
/** Declare a function with standard calling conventions */
 | 
			
		||||
#define __asmcall __attribute__ (( regparm(0) ))
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -352,6 +352,9 @@ REQUIRE_OBJECT ( vram_settings );
 | 
			
		||||
#ifdef ACPI_SETTINGS
 | 
			
		||||
REQUIRE_OBJECT ( acpi_settings );
 | 
			
		||||
#endif
 | 
			
		||||
#ifdef EFI_SETTINGS
 | 
			
		||||
REQUIRE_OBJECT ( efi_settings );
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Drag in selected keyboard map
 | 
			
		||||
 | 
			
		||||
@ -1,10 +1,8 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (C) 2012 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.
 | 
			
		||||
 * 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
 | 
			
		||||
@ -23,18 +21,31 @@
 | 
			
		||||
 | 
			
		||||
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
 | 
			
		||||
 | 
			
		||||
#include <config/entropy.h>
 | 
			
		||||
 | 
			
		||||
/** @file
 | 
			
		||||
 *
 | 
			
		||||
 * Nonexistent entropy source
 | 
			
		||||
 * Entropy configuration options
 | 
			
		||||
 *
 | 
			
		||||
 *
 | 
			
		||||
 * This source provides no entropy and must NOT be used in a
 | 
			
		||||
 * security-sensitive environment.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include <ipxe/entropy.h>
 | 
			
		||||
PROVIDE_REQUIRING_SYMBOL();
 | 
			
		||||
 | 
			
		||||
PROVIDE_ENTROPY_INLINE ( null, min_entropy_per_sample );
 | 
			
		||||
PROVIDE_ENTROPY_INLINE ( null, entropy_enable );
 | 
			
		||||
PROVIDE_ENTROPY_INLINE ( null, entropy_disable );
 | 
			
		||||
PROVIDE_ENTROPY_INLINE ( null, get_noise );
 | 
			
		||||
/*
 | 
			
		||||
 * Drag in entropy sources
 | 
			
		||||
 */
 | 
			
		||||
#ifdef ENTROPY_RTC
 | 
			
		||||
REQUIRE_OBJECT ( rtc_entropy );
 | 
			
		||||
#endif
 | 
			
		||||
#ifdef ENTROPY_EFITICK
 | 
			
		||||
REQUIRE_OBJECT ( efi_entropy );
 | 
			
		||||
#endif
 | 
			
		||||
#ifdef ENTROPY_EFIRNG
 | 
			
		||||
REQUIRE_OBJECT ( efi_rng );
 | 
			
		||||
#endif
 | 
			
		||||
#ifdef ENTROPY_LINUX
 | 
			
		||||
REQUIRE_OBJECT ( linux_entropy );
 | 
			
		||||
#endif
 | 
			
		||||
#ifdef ENTROPY_RDRAND
 | 
			
		||||
REQUIRE_OBJECT ( rdrand );
 | 
			
		||||
#endif
 | 
			
		||||
@ -49,3 +49,6 @@ REQUIRE_OBJECT ( eth_slow );
 | 
			
		||||
#ifdef NET_PROTO_EAPOL
 | 
			
		||||
REQUIRE_OBJECT ( eapol );
 | 
			
		||||
#endif
 | 
			
		||||
#ifdef NET_PROTO_LLDP
 | 
			
		||||
REQUIRE_OBJECT ( lldp );
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
@ -19,13 +19,15 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
 | 
			
		||||
#define SMBIOS_EFI
 | 
			
		||||
#define SANBOOT_EFI
 | 
			
		||||
#define BOFM_EFI
 | 
			
		||||
#define ENTROPY_EFI
 | 
			
		||||
#define ENTROPY_EFITICK
 | 
			
		||||
#define ENTROPY_EFIRNG
 | 
			
		||||
#define TIME_EFI
 | 
			
		||||
#define REBOOT_EFI
 | 
			
		||||
#define ACPI_EFI
 | 
			
		||||
#define FDT_EFI
 | 
			
		||||
 | 
			
		||||
#define	NET_PROTO_IPV6		/* IPv6 protocol */
 | 
			
		||||
#define	NET_PROTO_LLDP		/* Link Layer Discovery protocol */
 | 
			
		||||
 | 
			
		||||
#define DOWNLOAD_PROTO_FILE	/* Local filesystem access */
 | 
			
		||||
 | 
			
		||||
@ -46,9 +48,12 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
 | 
			
		||||
 | 
			
		||||
#define	REBOOT_CMD		/* Reboot command */
 | 
			
		||||
 | 
			
		||||
#define EFI_SETTINGS		/* EFI variable settings */
 | 
			
		||||
 | 
			
		||||
#if defined ( __i386__ ) || defined ( __x86_64__ )
 | 
			
		||||
#define IOAPI_X86
 | 
			
		||||
#define NAP_EFIX86
 | 
			
		||||
#define ENTROPY_RDRAND
 | 
			
		||||
#define	CPUID_CMD		/* x86 CPU feature detection command */
 | 
			
		||||
#define	UNSAFE_STD		/* Avoid setting direction flag */
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
@ -33,4 +33,8 @@ FILE_LICENCE ( GPL2_OR_LATER );
 | 
			
		||||
#define SANBOOT_PROTO_FCP
 | 
			
		||||
#define SANBOOT_PROTO_HTTP
 | 
			
		||||
 | 
			
		||||
#if defined ( __i386__ ) || defined ( __x86_64__ )
 | 
			
		||||
#define ENTROPY_RDRAND
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#endif /* CONFIG_DEFAULTS_LINUX_H */
 | 
			
		||||
 | 
			
		||||
@ -20,6 +20,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
 | 
			
		||||
#define SMBIOS_PCBIOS
 | 
			
		||||
#define SANBOOT_PCBIOS
 | 
			
		||||
#define ENTROPY_RTC
 | 
			
		||||
#define ENTROPY_RDRAND
 | 
			
		||||
#define TIME_RTC
 | 
			
		||||
#define REBOOT_PCBIOS
 | 
			
		||||
#define ACPI_RSDP
 | 
			
		||||
 | 
			
		||||
@ -40,6 +40,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
 | 
			
		||||
#define	NET_PROTO_STP		/* Spanning Tree protocol */
 | 
			
		||||
#define	NET_PROTO_LACP		/* Link Aggregation control protocol */
 | 
			
		||||
#define	NET_PROTO_EAPOL		/* EAP over LAN protocol */
 | 
			
		||||
//#define NET_PROTO_LLDP	/* Link Layer Discovery protocol */
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * PXE support
 | 
			
		||||
@ -149,7 +150,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
 | 
			
		||||
//#define POWEROFF_CMD		/* Power off command */
 | 
			
		||||
//#define IMAGE_TRUST_CMD	/* Image trust management commands */
 | 
			
		||||
//#define PCI_CMD		/* PCI commands */
 | 
			
		||||
//#define PARAM_CMD		/* Form parameter commands */
 | 
			
		||||
//#define PARAM_CMD		/* Request parameter commands */
 | 
			
		||||
//#define NEIGHBOUR_CMD		/* Neighbour management commands */
 | 
			
		||||
//#define PING_CMD		/* Ping command */
 | 
			
		||||
//#define CONSOLE_CMD		/* Console command */
 | 
			
		||||
 | 
			
		||||
@ -9,6 +9,8 @@
 | 
			
		||||
 | 
			
		||||
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
 | 
			
		||||
 | 
			
		||||
#include <config/defaults.h>
 | 
			
		||||
 | 
			
		||||
#define	PCI_SETTINGS	/* PCI device settings */
 | 
			
		||||
//#define	CPUID_SETTINGS	/* CPUID settings */
 | 
			
		||||
//#define	MEMMAP_SETTINGS	/* Memory map settings */
 | 
			
		||||
 | 
			
		||||
@ -77,17 +77,12 @@ size_t cpio_name_len ( struct image *image ) {
 | 
			
		||||
 */
 | 
			
		||||
static void cpio_parse_cmdline ( struct image *image,
 | 
			
		||||
				 struct cpio_header *cpio ) {
 | 
			
		||||
	const char *cmdline;
 | 
			
		||||
	char *arg;
 | 
			
		||||
	const char *arg;
 | 
			
		||||
	char *end;
 | 
			
		||||
	unsigned int mode;
 | 
			
		||||
 | 
			
		||||
	/* Skip image filename */
 | 
			
		||||
	cmdline = ( cpio_name ( image ) + cpio_name_len ( image ) );
 | 
			
		||||
 | 
			
		||||
	/* Look for "mode=" */
 | 
			
		||||
	if ( ( arg = strstr ( cmdline, "mode=" ) ) ) {
 | 
			
		||||
		arg += 5;
 | 
			
		||||
	if ( ( arg = image_argument ( image, "mode=" ) ) ) {
 | 
			
		||||
		mode = strtoul ( arg, &end, 8 /* Octal for file mode */ );
 | 
			
		||||
		if ( *end && ( *end != ' ' ) ) {
 | 
			
		||||
			DBGC ( image, "CPIO %p strange \"mode=\" "
 | 
			
		||||
 | 
			
		||||
@ -27,6 +27,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
 | 
			
		||||
#include <string.h>
 | 
			
		||||
#include <stdlib.h>
 | 
			
		||||
#include <stdio.h>
 | 
			
		||||
#include <ctype.h>
 | 
			
		||||
#include <errno.h>
 | 
			
		||||
#include <assert.h>
 | 
			
		||||
#include <libgen.h>
 | 
			
		||||
@ -569,3 +570,33 @@ struct image * image_memory ( const char *name, userptr_t data, size_t len ) {
 | 
			
		||||
 err_alloc_image:
 | 
			
		||||
	return NULL;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Find argument within image command line
 | 
			
		||||
 *
 | 
			
		||||
 * @v image		Image
 | 
			
		||||
 * @v key		Argument search key (including trailing delimiter)
 | 
			
		||||
 * @ret value		Argument value, or NULL if not found
 | 
			
		||||
 */
 | 
			
		||||
const char * image_argument ( struct image *image, const char *key ) {
 | 
			
		||||
	const char *cmdline = image->cmdline;
 | 
			
		||||
	const char *search;
 | 
			
		||||
	const char *match;
 | 
			
		||||
	const char *next;
 | 
			
		||||
 | 
			
		||||
	/* Find argument */
 | 
			
		||||
	for ( search = cmdline ; search ; search = next ) {
 | 
			
		||||
 | 
			
		||||
		/* Find next occurrence, if any */
 | 
			
		||||
		match = strstr ( search, key );
 | 
			
		||||
		if ( ! match )
 | 
			
		||||
			break;
 | 
			
		||||
		next = ( match + strlen ( key ) );
 | 
			
		||||
 | 
			
		||||
		/* Check preceding delimiter, if any */
 | 
			
		||||
		if ( ( match == cmdline ) || isspace ( match[-1] ) )
 | 
			
		||||
			return next;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return NULL;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -25,7 +25,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
 | 
			
		||||
 | 
			
		||||
/** @file
 | 
			
		||||
 *
 | 
			
		||||
 * Form parameters
 | 
			
		||||
 * Request parameters
 | 
			
		||||
 *
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
@ -37,7 +37,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
 | 
			
		||||
static LIST_HEAD ( parameters );
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Free form parameter list
 | 
			
		||||
 * Free request parameter list
 | 
			
		||||
 *
 | 
			
		||||
 * @v refcnt		Reference count
 | 
			
		||||
 */
 | 
			
		||||
@ -60,7 +60,7 @@ static void free_parameters ( struct refcnt *refcnt ) {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Find form parameter list by name
 | 
			
		||||
 * Find request parameter list by name
 | 
			
		||||
 *
 | 
			
		||||
 * @v name		Parameter list name (may be NULL)
 | 
			
		||||
 * @ret params		Parameter list, or NULL if not found
 | 
			
		||||
@ -78,7 +78,7 @@ struct parameters * find_parameters ( const char *name ) {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Create form parameter list
 | 
			
		||||
 * Create request parameter list
 | 
			
		||||
 *
 | 
			
		||||
 * @v name		Parameter list name (may be NULL)
 | 
			
		||||
 * @ret params		Parameter list, or NULL on failure
 | 
			
		||||
@ -118,15 +118,17 @@ struct parameters * create_parameters ( const char *name ) {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Add form parameter
 | 
			
		||||
 * Add request parameter
 | 
			
		||||
 *
 | 
			
		||||
 * @v params		Parameter list
 | 
			
		||||
 * @v key		Parameter key
 | 
			
		||||
 * @v value		Parameter value
 | 
			
		||||
 * @v flags		Parameter flags
 | 
			
		||||
 * @ret param		Parameter, or NULL on failure
 | 
			
		||||
 */
 | 
			
		||||
struct parameter * add_parameter ( struct parameters *params,
 | 
			
		||||
				   const char *key, const char *value ) {
 | 
			
		||||
				   const char *key, const char *value,
 | 
			
		||||
				   unsigned int flags ) {
 | 
			
		||||
	struct parameter *param;
 | 
			
		||||
	size_t key_len;
 | 
			
		||||
	size_t value_len;
 | 
			
		||||
@ -147,11 +149,14 @@ struct parameter * add_parameter ( struct parameters *params,
 | 
			
		||||
	param->key = key_copy;
 | 
			
		||||
	strcpy ( value_copy, value );
 | 
			
		||||
	param->value = value_copy;
 | 
			
		||||
	param->flags = flags;
 | 
			
		||||
 | 
			
		||||
	/* Add to list of parameters */
 | 
			
		||||
	list_add_tail ( ¶m->list, ¶ms->entries );
 | 
			
		||||
 | 
			
		||||
	DBGC ( params, "PARAMS \"%s\" added \"%s\"=\"%s\"\n",
 | 
			
		||||
	       params->name, param->key, param->value );
 | 
			
		||||
	DBGC ( params, "PARAMS \"%s\" added \"%s\"=\"%s\"%s%s\n",
 | 
			
		||||
	       params->name, param->key, param->value,
 | 
			
		||||
	       ( ( param->flags & PARAMETER_FORM ) ? " (form)" : "" ),
 | 
			
		||||
	       ( ( param->flags & PARAMETER_HEADER ) ? " (header)" : "" ) );
 | 
			
		||||
	return param;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -302,7 +302,7 @@ int parse_autovivified_setting ( char *text, struct named_setting *setting ) {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Parse form parameter list name
 | 
			
		||||
 * Parse request parameter list name
 | 
			
		||||
 *
 | 
			
		||||
 * @v text		Text
 | 
			
		||||
 * @ret params		Parameter list
 | 
			
		||||
 | 
			
		||||
@ -51,59 +51,33 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
 | 
			
		||||
	__einfo_uniqify ( EINFO_EPIPE, 0x02, "Adaptive proportion test failed" )
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Calculate cutoff value for the repetition count test
 | 
			
		||||
 * Initialise repetition count test
 | 
			
		||||
 *
 | 
			
		||||
 * @ret cutoff		Cutoff value
 | 
			
		||||
 *
 | 
			
		||||
 * This is the cutoff value for the Repetition Count Test defined in
 | 
			
		||||
 * ANS X9.82 Part 2 (October 2011 Draft) Section 8.5.2.1.2.
 | 
			
		||||
 * @v source		Entropy source
 | 
			
		||||
 */
 | 
			
		||||
static inline __attribute__ (( always_inline )) unsigned int
 | 
			
		||||
repetition_count_cutoff ( void ) {
 | 
			
		||||
	double max_repetitions;
 | 
			
		||||
	unsigned int cutoff;
 | 
			
		||||
static void repetition_count_test_init ( struct entropy_source *source ) {
 | 
			
		||||
	struct entropy_repetition_count_test *test =
 | 
			
		||||
		&source->repetition_count_test;
 | 
			
		||||
 | 
			
		||||
	/* The cutoff formula for the repetition test is:
 | 
			
		||||
	 *
 | 
			
		||||
	 *   C = ( 1 + ( -log2(W) / H_min ) )
 | 
			
		||||
	 *
 | 
			
		||||
	 * where W is set at 2^(-30) (in ANS X9.82 Part 2 (October
 | 
			
		||||
	 * 2011 Draft) Section 8.5.2.1.3.1).
 | 
			
		||||
	 */
 | 
			
		||||
	max_repetitions = ( 1 + ( MIN_ENTROPY ( 30 ) /
 | 
			
		||||
				  min_entropy_per_sample() ) );
 | 
			
		||||
 | 
			
		||||
	/* Round up to a whole number of repetitions.  We don't have
 | 
			
		||||
	 * the ceil() function available, so do the rounding by hand.
 | 
			
		||||
	 */
 | 
			
		||||
	cutoff = max_repetitions;
 | 
			
		||||
	if ( cutoff < max_repetitions )
 | 
			
		||||
		cutoff++;
 | 
			
		||||
	linker_assert ( ( cutoff >= max_repetitions ), rounding_error );
 | 
			
		||||
 | 
			
		||||
	/* Floating-point operations are not allowed in iPXE since we
 | 
			
		||||
	 * never set up a suitable environment.  Abort the build
 | 
			
		||||
	 * unless the calculated number of repetitions is a
 | 
			
		||||
	 * compile-time constant.
 | 
			
		||||
	 */
 | 
			
		||||
	linker_assert ( __builtin_constant_p ( cutoff ),
 | 
			
		||||
			repetition_count_cutoff_not_constant );
 | 
			
		||||
 | 
			
		||||
	return cutoff;
 | 
			
		||||
	/* Sanity checks */
 | 
			
		||||
	assert ( test->repetition_count == 0 );
 | 
			
		||||
	assert ( test->cutoff > 0 );
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Perform repetition count test
 | 
			
		||||
 *
 | 
			
		||||
 * @v source		Entropy source
 | 
			
		||||
 * @v sample		Noise sample
 | 
			
		||||
 * @ret rc		Return status code
 | 
			
		||||
 *
 | 
			
		||||
 * This is the Repetition Count Test defined in ANS X9.82 Part 2
 | 
			
		||||
 * (October 2011 Draft) Section 8.5.2.1.2.
 | 
			
		||||
 */
 | 
			
		||||
static int repetition_count_test ( noise_sample_t sample ) {
 | 
			
		||||
	static noise_sample_t most_recent_sample;
 | 
			
		||||
	static unsigned int repetition_count = 0;
 | 
			
		||||
static int repetition_count_test ( struct entropy_source *source,
 | 
			
		||||
				   noise_sample_t sample ) {
 | 
			
		||||
	struct entropy_repetition_count_test *test =
 | 
			
		||||
		&source->repetition_count_test;
 | 
			
		||||
 | 
			
		||||
	/* A = the most recently seen sample value
 | 
			
		||||
	 * B = the number of times that value A has been seen in a row
 | 
			
		||||
@ -116,158 +90,71 @@ static int repetition_count_test ( noise_sample_t sample ) {
 | 
			
		||||
	 * the initial value of most_recent_sample is treated as being
 | 
			
		||||
	 * undefined.)
 | 
			
		||||
	 */
 | 
			
		||||
	if ( ( sample == most_recent_sample ) && ( repetition_count > 0 ) ) {
 | 
			
		||||
	if ( ( sample == test->most_recent_sample ) &&
 | 
			
		||||
	     ( test->repetition_count > 0 ) ) {
 | 
			
		||||
 | 
			
		||||
		/* a) If the new sample = A, then B is incremented by one. */
 | 
			
		||||
		repetition_count++;
 | 
			
		||||
		test->repetition_count++;
 | 
			
		||||
 | 
			
		||||
		/*    i.  If B >= C, then an error condition is raised
 | 
			
		||||
		 *        due to a failure of the test
 | 
			
		||||
		 */
 | 
			
		||||
		if ( repetition_count >= repetition_count_cutoff() )
 | 
			
		||||
		if ( test->repetition_count >= test->cutoff ) {
 | 
			
		||||
			DBGC ( source, "ENTROPY %s excessively repeated "
 | 
			
		||||
			       "value %d (%d/%d)\n", source->name, sample,
 | 
			
		||||
			       test->repetition_count, test->cutoff );
 | 
			
		||||
			return -EPIPE_REPETITION_COUNT_TEST;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
	} else {
 | 
			
		||||
 | 
			
		||||
		/* b) Else:
 | 
			
		||||
		 *    i.  A = new sample
 | 
			
		||||
		 */
 | 
			
		||||
		most_recent_sample = sample;
 | 
			
		||||
		test->most_recent_sample = sample;
 | 
			
		||||
 | 
			
		||||
		/*    ii. B = 1 */
 | 
			
		||||
		repetition_count = 1;
 | 
			
		||||
		test->repetition_count = 1;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Window size for the adaptive proportion test
 | 
			
		||||
 * Initialise adaptive proportion test
 | 
			
		||||
 *
 | 
			
		||||
 * ANS X9.82 Part 2 (October 2011 Draft) Section 8.5.2.1.3.1.1 allows
 | 
			
		||||
 * five possible window sizes: 16, 64, 256, 4096 and 65536.
 | 
			
		||||
 *
 | 
			
		||||
 * We expect to generate relatively few (<256) entropy samples during
 | 
			
		||||
 * a typical iPXE run; the use of a large window size would mean that
 | 
			
		||||
 * the test would never complete a single cycle.  We use a window size
 | 
			
		||||
 * of 64, which is the smallest window size that permits values of
 | 
			
		||||
 * H_min down to one bit per sample.
 | 
			
		||||
 * @v source		Entropy source
 | 
			
		||||
 */
 | 
			
		||||
#define ADAPTIVE_PROPORTION_WINDOW_SIZE 64
 | 
			
		||||
static void adaptive_proportion_test_init ( struct entropy_source *source ) {
 | 
			
		||||
	struct entropy_adaptive_proportion_test *test =
 | 
			
		||||
		&source->adaptive_proportion_test;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Combine adaptive proportion test window size and min-entropy
 | 
			
		||||
 *
 | 
			
		||||
 * @v n			N (window size)
 | 
			
		||||
 * @v h			H (min-entropy)
 | 
			
		||||
 * @ret n_h		(N,H) combined value
 | 
			
		||||
 */
 | 
			
		||||
#define APC_N_H( n, h ) ( ( (n) << 8 ) | (h) )
 | 
			
		||||
	/* Sanity checks */
 | 
			
		||||
	assert ( test->sample_count == 0 );
 | 
			
		||||
	assert ( test->repetition_count == 0 );
 | 
			
		||||
	assert ( test->cutoff > 0 );
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Define a row of the adaptive proportion cutoff table
 | 
			
		||||
 *
 | 
			
		||||
 * @v h			H (min-entropy)
 | 
			
		||||
 * @v c16		Cutoff for N=16
 | 
			
		||||
 * @v c64		Cutoff for N=64
 | 
			
		||||
 * @v c256		Cutoff for N=256
 | 
			
		||||
 * @v c4096		Cutoff for N=4096
 | 
			
		||||
 * @v c65536		Cutoff for N=65536
 | 
			
		||||
 */
 | 
			
		||||
#define APC_TABLE_ROW( h, c16, c64, c256, c4096, c65536)	   \
 | 
			
		||||
	case APC_N_H ( 16, h ) :	return c16;		   \
 | 
			
		||||
	case APC_N_H ( 64, h ) :	return c64;   		   \
 | 
			
		||||
	case APC_N_H ( 256, h ) :	return c256;		   \
 | 
			
		||||
	case APC_N_H ( 4096, h ) :	return c4096;		   \
 | 
			
		||||
	case APC_N_H ( 65536, h ) :	return c65536;
 | 
			
		||||
 | 
			
		||||
/** Value used to represent "N/A" in adaptive proportion cutoff table */
 | 
			
		||||
#define APC_NA 0
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Look up value in adaptive proportion test cutoff table
 | 
			
		||||
 *
 | 
			
		||||
 * @v n			N (window size)
 | 
			
		||||
 * @v h			H (min-entropy)
 | 
			
		||||
 * @ret cutoff		Cutoff
 | 
			
		||||
 *
 | 
			
		||||
 * This is the table of cutoff values defined in ANS X9.82 Part 2
 | 
			
		||||
 * (October 2011 Draft) Section 8.5.2.1.3.1.2.
 | 
			
		||||
 */
 | 
			
		||||
static inline __attribute__ (( always_inline )) unsigned int
 | 
			
		||||
adaptive_proportion_cutoff_lookup ( unsigned int n, unsigned int h ) {
 | 
			
		||||
	switch ( APC_N_H ( n, h ) ) {
 | 
			
		||||
		APC_TABLE_ROW (  1, APC_NA,     51,    168,   2240,  33537 );
 | 
			
		||||
		APC_TABLE_ROW (  2, APC_NA,     35,    100,   1193,  17053 );
 | 
			
		||||
		APC_TABLE_ROW (  3,     10,     24,     61,    643,   8705 );
 | 
			
		||||
		APC_TABLE_ROW (  4,      8,     16,     38,    354,   4473 );
 | 
			
		||||
		APC_TABLE_ROW (  5,      6,     12,     25,    200,   2321 );
 | 
			
		||||
		APC_TABLE_ROW (  6,      5,      9,     17,    117,   1220 );
 | 
			
		||||
		APC_TABLE_ROW (  7,      4,      7,     15,     71,    653 );
 | 
			
		||||
		APC_TABLE_ROW (  8,      4,      5,      9,     45,    358 );
 | 
			
		||||
		APC_TABLE_ROW (  9,      3,      4,      7,     30,    202 );
 | 
			
		||||
		APC_TABLE_ROW ( 10,      3,      4,      5,     21,    118 );
 | 
			
		||||
		APC_TABLE_ROW ( 11,      2,      3,      4,     15,     71 );
 | 
			
		||||
		APC_TABLE_ROW ( 12,      2,      3,      4,     11,     45 );
 | 
			
		||||
		APC_TABLE_ROW ( 13,      2,      2,      3,      9,     30 );
 | 
			
		||||
		APC_TABLE_ROW ( 14,      2,      2,      3,      7,     21 );
 | 
			
		||||
		APC_TABLE_ROW ( 15,      1,      2,      2,      6,     15 );
 | 
			
		||||
		APC_TABLE_ROW ( 16,      1,      2,      2,      5,     11 );
 | 
			
		||||
		APC_TABLE_ROW ( 17,      1,      1,      2,      4,      9 );
 | 
			
		||||
		APC_TABLE_ROW ( 18,      1,      1,      2,      4,      7 );
 | 
			
		||||
		APC_TABLE_ROW ( 19,      1,      1,      1,      3,      6 );
 | 
			
		||||
		APC_TABLE_ROW ( 20,      1,      1,      1,      3,      5 );
 | 
			
		||||
	default:
 | 
			
		||||
		return APC_NA;
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Calculate cutoff value for the adaptive proportion test
 | 
			
		||||
 *
 | 
			
		||||
 * @ret cutoff		Cutoff value
 | 
			
		||||
 *
 | 
			
		||||
 * This is the cutoff value for the Adaptive Proportion Test defined
 | 
			
		||||
 * in ANS X9.82 Part 2 (October 2011 Draft) Section 8.5.2.1.3.1.2.
 | 
			
		||||
 */
 | 
			
		||||
static inline __attribute__ (( always_inline )) unsigned int
 | 
			
		||||
adaptive_proportion_cutoff ( void ) {
 | 
			
		||||
	unsigned int h;
 | 
			
		||||
	unsigned int n;
 | 
			
		||||
	unsigned int cutoff;
 | 
			
		||||
 | 
			
		||||
	/* Look up cutoff value in cutoff table */
 | 
			
		||||
	n = ADAPTIVE_PROPORTION_WINDOW_SIZE;
 | 
			
		||||
	h = ( min_entropy_per_sample() / MIN_ENTROPY_SCALE );
 | 
			
		||||
	cutoff = adaptive_proportion_cutoff_lookup ( n, h );
 | 
			
		||||
 | 
			
		||||
	/* Fail unless cutoff value is a build-time constant */
 | 
			
		||||
	linker_assert ( __builtin_constant_p ( cutoff ),
 | 
			
		||||
			adaptive_proportion_cutoff_not_constant );
 | 
			
		||||
 | 
			
		||||
	/* Fail if cutoff value is N/A */
 | 
			
		||||
	linker_assert ( ( cutoff != APC_NA ),
 | 
			
		||||
			adaptive_proportion_cutoff_not_applicable );
 | 
			
		||||
 | 
			
		||||
	return cutoff;
 | 
			
		||||
	/* Ensure that a new test run starts immediately */
 | 
			
		||||
	test->sample_count = ADAPTIVE_PROPORTION_WINDOW_SIZE;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Perform adaptive proportion test
 | 
			
		||||
 *
 | 
			
		||||
 * @v source		Entropy source
 | 
			
		||||
 * @v sample		Noise sample
 | 
			
		||||
 * @ret rc		Return status code
 | 
			
		||||
 *
 | 
			
		||||
 * This is the Adaptive Proportion Test for the Most Common Value
 | 
			
		||||
 * defined in ANS X9.82 Part 2 (October 2011 Draft) Section 8.5.2.1.3.
 | 
			
		||||
 */
 | 
			
		||||
static int adaptive_proportion_test ( noise_sample_t sample ) {
 | 
			
		||||
	static noise_sample_t current_counted_sample;
 | 
			
		||||
	static unsigned int sample_count = ADAPTIVE_PROPORTION_WINDOW_SIZE;
 | 
			
		||||
	static unsigned int repetition_count;
 | 
			
		||||
static int adaptive_proportion_test ( struct entropy_source *source,
 | 
			
		||||
				      noise_sample_t sample ) {
 | 
			
		||||
	struct entropy_adaptive_proportion_test *test =
 | 
			
		||||
		&source->adaptive_proportion_test;
 | 
			
		||||
 | 
			
		||||
	/* A = the sample value currently being counted
 | 
			
		||||
	 * B = the number of samples examined in this run of the test so far
 | 
			
		||||
	 * S = the number of samples examined in this run of the test so far
 | 
			
		||||
	 * N = the total number of samples that must be observed in
 | 
			
		||||
	 *     one run of the test, also known as the "window size" of
 | 
			
		||||
	 *     the test
 | 
			
		||||
@ -284,37 +171,41 @@ static int adaptive_proportion_test ( noise_sample_t sample ) {
 | 
			
		||||
	 */
 | 
			
		||||
 | 
			
		||||
	/* 2.  If S = N, then a new run of the test begins: */
 | 
			
		||||
	if ( sample_count == ADAPTIVE_PROPORTION_WINDOW_SIZE ) {
 | 
			
		||||
	if ( test->sample_count == ADAPTIVE_PROPORTION_WINDOW_SIZE ) {
 | 
			
		||||
 | 
			
		||||
		/* a.  A = the current sample */
 | 
			
		||||
		current_counted_sample = sample;
 | 
			
		||||
		test->current_counted_sample = sample;
 | 
			
		||||
 | 
			
		||||
		/* b.  S = 0 */
 | 
			
		||||
		sample_count = 0;
 | 
			
		||||
		test->sample_count = 0;
 | 
			
		||||
 | 
			
		||||
		/* c. B = 0 */
 | 
			
		||||
		repetition_count = 0;
 | 
			
		||||
		test->repetition_count = 0;
 | 
			
		||||
 | 
			
		||||
	} else {
 | 
			
		||||
 | 
			
		||||
		/* Else: (the test is already running)
 | 
			
		||||
		 * a.  S = S + 1
 | 
			
		||||
		 */
 | 
			
		||||
		sample_count++;
 | 
			
		||||
		test->sample_count++;
 | 
			
		||||
 | 
			
		||||
		/* b.  If A = the current sample, then: */
 | 
			
		||||
		if ( sample == current_counted_sample ) {
 | 
			
		||||
		if ( sample == test->current_counted_sample ) {
 | 
			
		||||
 | 
			
		||||
			/* i.   B = B + 1 */
 | 
			
		||||
			repetition_count++;
 | 
			
		||||
			test->repetition_count++;
 | 
			
		||||
 | 
			
		||||
			/* ii.  If S (sic) > C then raise an error
 | 
			
		||||
			 *      condition, because the test has
 | 
			
		||||
			 *      detected a failure
 | 
			
		||||
			 */
 | 
			
		||||
			if ( repetition_count > adaptive_proportion_cutoff() )
 | 
			
		||||
			if ( test->repetition_count > test->cutoff ) {
 | 
			
		||||
				DBGC ( source, "ENTROPY %s excessively "
 | 
			
		||||
				       "repeated value %d (%d/%d)\n",
 | 
			
		||||
				       source->name, sample,
 | 
			
		||||
				       test->repetition_count, test->cutoff );
 | 
			
		||||
				return -EPIPE_ADAPTIVE_PROPORTION_TEST;
 | 
			
		||||
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
@ -324,62 +215,180 @@ static int adaptive_proportion_test ( noise_sample_t sample ) {
 | 
			
		||||
/**
 | 
			
		||||
 * Get entropy sample
 | 
			
		||||
 *
 | 
			
		||||
 * @v source		Entropy source
 | 
			
		||||
 * @ret entropy		Entropy sample
 | 
			
		||||
 * @ret rc		Return status code
 | 
			
		||||
 *
 | 
			
		||||
 * This is the GetEntropy function defined in ANS X9.82 Part 2
 | 
			
		||||
 * (October 2011 Draft) Section 6.5.1.
 | 
			
		||||
 */
 | 
			
		||||
static int get_entropy ( entropy_sample_t *entropy ) {
 | 
			
		||||
	static int rc = 0;
 | 
			
		||||
static int get_entropy ( struct entropy_source *source,
 | 
			
		||||
			 entropy_sample_t *entropy ) {
 | 
			
		||||
	noise_sample_t noise;
 | 
			
		||||
	int rc;
 | 
			
		||||
 | 
			
		||||
	/* Any failure is permanent */
 | 
			
		||||
	if ( rc != 0 )
 | 
			
		||||
		return rc;
 | 
			
		||||
	if ( ( rc = source->rc ) != 0 )
 | 
			
		||||
		goto err_broken;
 | 
			
		||||
 | 
			
		||||
	/* Get noise sample */
 | 
			
		||||
	if ( ( rc = get_noise ( &noise ) ) != 0 )
 | 
			
		||||
		return rc;
 | 
			
		||||
	if ( ( rc = get_noise ( source, &noise ) ) != 0 )
 | 
			
		||||
		goto err_get_noise;
 | 
			
		||||
 | 
			
		||||
	/* Perform Repetition Count Test and Adaptive Proportion Test
 | 
			
		||||
	 * as mandated by ANS X9.82 Part 2 (October 2011 Draft)
 | 
			
		||||
	 * Section 8.5.2.1.1.
 | 
			
		||||
	 */
 | 
			
		||||
	if ( ( rc = repetition_count_test ( noise ) ) != 0 )
 | 
			
		||||
		return rc;
 | 
			
		||||
	if ( ( rc = adaptive_proportion_test ( noise ) ) != 0 )
 | 
			
		||||
		return rc;
 | 
			
		||||
	if ( ( rc = repetition_count_test ( source, noise ) ) != 0 )
 | 
			
		||||
		goto err_repetition_count_test;
 | 
			
		||||
	if ( ( rc = adaptive_proportion_test ( source, noise ) ) != 0 )
 | 
			
		||||
		goto err_adaptive_proportion_test;
 | 
			
		||||
 | 
			
		||||
	/* We do not use any optional conditioning component */
 | 
			
		||||
	*entropy = noise;
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
 | 
			
		||||
 err_adaptive_proportion_test:
 | 
			
		||||
 err_repetition_count_test:
 | 
			
		||||
 err_get_noise:
 | 
			
		||||
	source->rc = rc;
 | 
			
		||||
 err_broken:
 | 
			
		||||
	return rc;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Calculate number of samples required for startup tests
 | 
			
		||||
 * Initialise startup test
 | 
			
		||||
 *
 | 
			
		||||
 * @ret num_samples	Number of samples required
 | 
			
		||||
 *
 | 
			
		||||
 * ANS X9.82 Part 2 (October 2011 Draft) Section 8.5.2.1.5 requires
 | 
			
		||||
 * that at least one full cycle of the continuous tests must be
 | 
			
		||||
 * performed at start-up.
 | 
			
		||||
 * @v source		Entropy source
 | 
			
		||||
 */
 | 
			
		||||
static inline __attribute__ (( always_inline )) unsigned int
 | 
			
		||||
startup_test_count ( void ) {
 | 
			
		||||
	unsigned int num_samples;
 | 
			
		||||
static void startup_test_init ( struct entropy_source *source ) {
 | 
			
		||||
	struct entropy_startup_test *test = &source->startup_test;
 | 
			
		||||
 | 
			
		||||
	/* At least max(N,C) samples shall be generated by the noise
 | 
			
		||||
	 * source for start-up testing.
 | 
			
		||||
	 */
 | 
			
		||||
	num_samples = repetition_count_cutoff();
 | 
			
		||||
	if ( num_samples < adaptive_proportion_cutoff() )
 | 
			
		||||
		num_samples = adaptive_proportion_cutoff();
 | 
			
		||||
	linker_assert ( __builtin_constant_p ( num_samples ),
 | 
			
		||||
			startup_test_count_not_constant );
 | 
			
		||||
	/* Sanity check */
 | 
			
		||||
	assert ( test->tested == 0 );
 | 
			
		||||
	assert ( test->count > 0 );
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
	return num_samples;
 | 
			
		||||
/**
 | 
			
		||||
 * Perform startup test
 | 
			
		||||
 *
 | 
			
		||||
 * @v source		Entropy source
 | 
			
		||||
 * @ret rc		Return status code
 | 
			
		||||
 */
 | 
			
		||||
static int startup_test ( struct entropy_source *source ) {
 | 
			
		||||
	struct entropy_startup_test *test = &source->startup_test;
 | 
			
		||||
	entropy_sample_t sample;
 | 
			
		||||
	int rc;
 | 
			
		||||
 | 
			
		||||
	/* Perform mandatory number of startup tests */
 | 
			
		||||
	for ( ; test->tested < test->count ; test->tested++ ) {
 | 
			
		||||
		if ( ( rc = get_entropy ( source, &sample ) ) != 0 ) {
 | 
			
		||||
			DBGC ( source, "ENTROPY %s failed: %s\n",
 | 
			
		||||
			       source->name, strerror ( rc ) );
 | 
			
		||||
			return rc;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Enable entropy gathering
 | 
			
		||||
 *
 | 
			
		||||
 * @v source		Entropy source
 | 
			
		||||
 * @ret rc		Return status code
 | 
			
		||||
 */
 | 
			
		||||
int entropy_enable ( struct entropy_source *source ) {
 | 
			
		||||
	int rc;
 | 
			
		||||
 | 
			
		||||
	/* Refuse to enable a previously failed source */
 | 
			
		||||
	if ( ( rc = source->rc ) != 0 )
 | 
			
		||||
		return rc;
 | 
			
		||||
 | 
			
		||||
	/* Enable entropy source */
 | 
			
		||||
	if ( ( rc = source->enable() ) != 0 ) {
 | 
			
		||||
		DBGC ( source, "ENTROPY %s could not enable: %s\n",
 | 
			
		||||
		       source->name, strerror ( rc ) );
 | 
			
		||||
		source->rc = rc;
 | 
			
		||||
		return rc;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* Sanity check */
 | 
			
		||||
	assert ( source->min_entropy_per_sample > 0 );
 | 
			
		||||
 | 
			
		||||
	/* Initialise test state if this source has not previously been used */
 | 
			
		||||
	if ( source->startup_test.tested == 0 ) {
 | 
			
		||||
		repetition_count_test_init ( source );
 | 
			
		||||
		adaptive_proportion_test_init ( source );
 | 
			
		||||
		startup_test_init ( source );
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	DBGC ( source, "ENTROPY %s enabled\n", source->name );
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Enable and test entropy source
 | 
			
		||||
 *
 | 
			
		||||
 * @v source		Entropy source
 | 
			
		||||
 * @ret rc		Return status code
 | 
			
		||||
 */
 | 
			
		||||
static int entropy_enable_and_test ( struct entropy_source *source ) {
 | 
			
		||||
	int rc;
 | 
			
		||||
 | 
			
		||||
	/* Enable source */
 | 
			
		||||
	if ( ( rc = entropy_enable ( source ) ) != 0 )
 | 
			
		||||
		goto err_enable;
 | 
			
		||||
 | 
			
		||||
	/* Test source */
 | 
			
		||||
	if ( ( rc = startup_test ( source ) ) != 0 )
 | 
			
		||||
		goto err_test;
 | 
			
		||||
 | 
			
		||||
	DBGC ( source, "ENTROPY %s passed %d startup tests\n",
 | 
			
		||||
	       source->name, source->startup_test.count );
 | 
			
		||||
	return 0;
 | 
			
		||||
 | 
			
		||||
 err_test:
 | 
			
		||||
	entropy_disable ( source );
 | 
			
		||||
 err_enable:
 | 
			
		||||
	assert ( source->rc == rc );
 | 
			
		||||
	return rc;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Enable first working entropy source
 | 
			
		||||
 *
 | 
			
		||||
 * @v source		Entropy source to fill in
 | 
			
		||||
 * @ret rc		Return status code
 | 
			
		||||
 */
 | 
			
		||||
static int entropy_enable_working ( struct entropy_source **source ) {
 | 
			
		||||
	int rc;
 | 
			
		||||
 | 
			
		||||
	/* Find the first working source */
 | 
			
		||||
	rc = -ENOENT;
 | 
			
		||||
	for_each_table_entry ( *source, ENTROPY_SOURCES ) {
 | 
			
		||||
		if ( ( rc = entropy_enable_and_test ( *source ) ) == 0 )
 | 
			
		||||
			return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	DBGC ( *source, "ENTROPY has no working sources: %s\n",
 | 
			
		||||
	       strerror ( rc ) );
 | 
			
		||||
	return rc;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Disable entropy gathering
 | 
			
		||||
 *
 | 
			
		||||
 * @v source		Entropy source
 | 
			
		||||
 */
 | 
			
		||||
void entropy_disable ( struct entropy_source *source ) {
 | 
			
		||||
 | 
			
		||||
	/* Disable entropy gathering, if applicable */
 | 
			
		||||
	if ( source->disable )
 | 
			
		||||
		source->disable();
 | 
			
		||||
 | 
			
		||||
	DBGC ( source, "ENTROPY %s disabled\n", source->name );
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
@ -402,7 +411,7 @@ static uint32_t make_next_nonce ( void ) {
 | 
			
		||||
/**
 | 
			
		||||
 * Obtain entropy input temporary buffer
 | 
			
		||||
 *
 | 
			
		||||
 * @v num_samples	Number of entropy samples
 | 
			
		||||
 * @v min_entropy	Min-entropy required
 | 
			
		||||
 * @v tmp		Temporary buffer
 | 
			
		||||
 * @v tmp_len		Length of temporary buffer
 | 
			
		||||
 * @ret rc		Return status code
 | 
			
		||||
@ -412,47 +421,41 @@ static uint32_t make_next_nonce ( void ) {
 | 
			
		||||
 * and condensing each entropy source output after each GetEntropy
 | 
			
		||||
 * call) as defined in ANS X9.82 Part 4 (April 2011 Draft) Section
 | 
			
		||||
 * 13.3.4.2.
 | 
			
		||||
 *
 | 
			
		||||
 * To minimise code size, the number of samples required is calculated
 | 
			
		||||
 * at compilation time.
 | 
			
		||||
 */
 | 
			
		||||
int get_entropy_input_tmp ( unsigned int num_samples, uint8_t *tmp,
 | 
			
		||||
int get_entropy_input_tmp ( min_entropy_t min_entropy, uint8_t *tmp,
 | 
			
		||||
			    size_t tmp_len ) {
 | 
			
		||||
	static unsigned int startup_tested = 0;
 | 
			
		||||
	struct entropy_source *source;
 | 
			
		||||
	struct {
 | 
			
		||||
		uint32_t nonce;
 | 
			
		||||
		entropy_sample_t sample;
 | 
			
		||||
	} __attribute__ (( packed )) data;;
 | 
			
		||||
	uint8_t df_buf[tmp_len];
 | 
			
		||||
	min_entropy_t entropy_total;
 | 
			
		||||
	unsigned int num_samples;
 | 
			
		||||
	unsigned int i;
 | 
			
		||||
	int rc;
 | 
			
		||||
 | 
			
		||||
	/* Enable entropy gathering */
 | 
			
		||||
	if ( ( rc = entropy_enable() ) != 0 )
 | 
			
		||||
		return rc;
 | 
			
		||||
	if ( ( rc = entropy_enable_working ( &source ) ) != 0 )
 | 
			
		||||
		goto err_enable_working;
 | 
			
		||||
 | 
			
		||||
	/* Perform mandatory startup tests, if not yet performed */
 | 
			
		||||
	for ( ; startup_tested < startup_test_count() ; startup_tested++ ) {
 | 
			
		||||
		if ( ( rc = get_entropy ( &data.sample ) ) != 0 )
 | 
			
		||||
			goto err_get_entropy;
 | 
			
		||||
	}
 | 
			
		||||
	/* Sanity checks */
 | 
			
		||||
	assert ( source->startup_test.count > 0 );
 | 
			
		||||
	assert ( source->startup_test.tested >= source->startup_test.count );
 | 
			
		||||
 | 
			
		||||
	/* 3.  entropy_total = 0
 | 
			
		||||
	 *
 | 
			
		||||
	 * (Nothing to do; the number of entropy samples required has
 | 
			
		||||
	 * already been precalculated.)
 | 
			
		||||
	 */
 | 
			
		||||
	/* 3.  entropy_total = 0 */
 | 
			
		||||
	entropy_total = MIN_ENTROPY ( 0 );
 | 
			
		||||
 | 
			
		||||
	/* 4.  tmp = a fixed n-bit value, such as 0^n */
 | 
			
		||||
	memset ( tmp, 0, tmp_len );
 | 
			
		||||
 | 
			
		||||
	/* 5.  While ( entropy_total < min_entropy ) */
 | 
			
		||||
	while ( num_samples-- ) {
 | 
			
		||||
	for ( num_samples = 0 ; entropy_total < min_entropy ; num_samples++ ) {
 | 
			
		||||
		/* 5.1.  ( status, entropy_bitstring, assessed_entropy )
 | 
			
		||||
		 *       = GetEntropy()
 | 
			
		||||
		 * 5.2.  If status indicates an error, return ( status, Null )
 | 
			
		||||
		 */
 | 
			
		||||
		if ( ( rc = get_entropy ( &data.sample ) ) != 0 )
 | 
			
		||||
		if ( ( rc = get_entropy ( source, &data.sample ) ) != 0 )
 | 
			
		||||
			goto err_get_entropy;
 | 
			
		||||
 | 
			
		||||
		/* 5.3.  nonce = MakeNextNonce() */
 | 
			
		||||
@ -466,19 +469,26 @@ int get_entropy_input_tmp ( unsigned int num_samples, uint8_t *tmp,
 | 
			
		||||
		for ( i = 0 ; i < tmp_len ; i++ )
 | 
			
		||||
			tmp[i] ^= df_buf[i];
 | 
			
		||||
 | 
			
		||||
		/* 5.5.  entropy_total = entropy_total + assessed_entropy
 | 
			
		||||
		 *
 | 
			
		||||
		 * (Nothing to do; the number of entropy samples
 | 
			
		||||
		 * required has already been precalculated.)
 | 
			
		||||
		 */
 | 
			
		||||
		/* 5.5.  entropy_total = entropy_total + assessed_entropy */
 | 
			
		||||
		entropy_total += source->min_entropy_per_sample;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* Disable entropy gathering */
 | 
			
		||||
	entropy_disable();
 | 
			
		||||
	entropy_disable ( source );
 | 
			
		||||
 | 
			
		||||
	DBGC ( source, "ENTROPY %s gathered %d bits in %d samples\n",
 | 
			
		||||
	       source->name, ( min_entropy / MIN_ENTROPY_SCALE ), num_samples );
 | 
			
		||||
	return 0;
 | 
			
		||||
 | 
			
		||||
 err_get_entropy:
 | 
			
		||||
	entropy_disable();
 | 
			
		||||
	entropy_disable ( source );
 | 
			
		||||
	assert ( source->rc == rc );
 | 
			
		||||
 err_enable_working:
 | 
			
		||||
	return rc;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Drag in objects via entropy_enable */
 | 
			
		||||
REQUIRING_SYMBOL ( entropy_enable );
 | 
			
		||||
 | 
			
		||||
/* Drag in entropy configuration */
 | 
			
		||||
REQUIRE_OBJECT ( config_entropy );
 | 
			
		||||
 | 
			
		||||
@ -609,6 +609,7 @@ static void scsicmd_read_capacity_cmd ( struct scsi_command *scsicmd,
 | 
			
		||||
 */
 | 
			
		||||
static void scsicmd_read_capacity_done ( struct scsi_command *scsicmd,
 | 
			
		||||
					 int rc ) {
 | 
			
		||||
	struct scsi_device *scsidev = scsicmd->scsidev;
 | 
			
		||||
	struct scsi_read_capacity_private *priv = scsicmd_priv ( scsicmd );
 | 
			
		||||
	struct scsi_capacity_16 *capacity16 = &priv->capacity.capacity16;
 | 
			
		||||
	struct scsi_capacity_10 *capacity10 = &priv->capacity.capacity10;
 | 
			
		||||
@ -645,6 +646,9 @@ static void scsicmd_read_capacity_done ( struct scsi_command *scsicmd,
 | 
			
		||||
	}
 | 
			
		||||
	capacity.max_count = -1U;
 | 
			
		||||
 | 
			
		||||
	/* Allow transport layer to update capacity */
 | 
			
		||||
	block_capacity ( &scsidev->scsi, &capacity );
 | 
			
		||||
 | 
			
		||||
	/* Return capacity to caller */
 | 
			
		||||
	block_capacity ( &scsicmd->block, &capacity );
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -98,8 +98,16 @@ static void eisa_remove ( struct eisa_device *eisa ) {
 | 
			
		||||
static int eisabus_probe ( struct root_device *rootdev ) {
 | 
			
		||||
	struct eisa_device *eisa = NULL;
 | 
			
		||||
	unsigned int slot;
 | 
			
		||||
	uint8_t system;
 | 
			
		||||
	int rc;
 | 
			
		||||
 | 
			
		||||
	/* Check for EISA system board */
 | 
			
		||||
	system = inb ( EISA_VENDOR_ID );
 | 
			
		||||
	if ( system & 0x80 ) {
 | 
			
		||||
		DBG ( "No EISA system board (read %02x)\n", system );
 | 
			
		||||
		return -ENODEV;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	for ( slot = EISA_MIN_SLOT ; slot <= EISA_MAX_SLOT ; slot++ ) {
 | 
			
		||||
		/* Allocate struct eisa_device */
 | 
			
		||||
		if ( ! eisa )
 | 
			
		||||
 | 
			
		||||
@ -25,7 +25,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
 | 
			
		||||
 | 
			
		||||
/** @file
 | 
			
		||||
 *
 | 
			
		||||
 * Form parameter commands
 | 
			
		||||
 * Request parameter commands
 | 
			
		||||
 *
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
@ -90,12 +90,16 @@ static int params_exec ( int argc, char **argv ) {
 | 
			
		||||
struct param_options {
 | 
			
		||||
	/** Parameter list name */
 | 
			
		||||
	char *params;
 | 
			
		||||
	/** Parameter is a header */
 | 
			
		||||
	int header;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/** "param" option list */
 | 
			
		||||
static struct option_descriptor param_opts[] = {
 | 
			
		||||
	OPTION_DESC ( "params", 'p', required_argument,
 | 
			
		||||
		      struct param_options, params, parse_string ),
 | 
			
		||||
	OPTION_DESC ( "header", 'H', no_argument,
 | 
			
		||||
		      struct param_options, header, parse_flag ),
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/** "param" command descriptor */
 | 
			
		||||
@ -114,6 +118,7 @@ static int param_exec ( int argc, char **argv ) {
 | 
			
		||||
	struct param_options opts;
 | 
			
		||||
	char *key;
 | 
			
		||||
	char *value;
 | 
			
		||||
	unsigned int flags;
 | 
			
		||||
	struct parameters *params;
 | 
			
		||||
	struct parameter *param;
 | 
			
		||||
	int rc;
 | 
			
		||||
@ -132,12 +137,15 @@ static int param_exec ( int argc, char **argv ) {
 | 
			
		||||
		goto err_parse_value;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* Construct flags */
 | 
			
		||||
	flags = ( opts.header ? PARAMETER_HEADER : PARAMETER_FORM );
 | 
			
		||||
 | 
			
		||||
	/* Identify parameter list */
 | 
			
		||||
	if ( ( rc = parse_parameters ( opts.params, ¶ms ) ) != 0 )
 | 
			
		||||
		goto err_parse_parameters;
 | 
			
		||||
 | 
			
		||||
	/* Add parameter */
 | 
			
		||||
	param = add_parameter ( params, key, value );
 | 
			
		||||
	param = add_parameter ( params, key, value, flags );
 | 
			
		||||
	if ( ! param ) {
 | 
			
		||||
		rc = -ENOMEM;
 | 
			
		||||
		goto err_add_parameter;
 | 
			
		||||
@ -154,7 +162,7 @@ static int param_exec ( int argc, char **argv ) {
 | 
			
		||||
	return rc;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/** Form parameter commands */
 | 
			
		||||
/** Request parameter commands */
 | 
			
		||||
struct command param_commands[] __command = {
 | 
			
		||||
	{
 | 
			
		||||
		.name = "params",
 | 
			
		||||
 | 
			
		||||
@ -262,10 +262,10 @@ static inline void eplatform_discard ( int dummy __unused, ... ) {}
 | 
			
		||||
		  ".balign 8\n\t"					\
 | 
			
		||||
		  "\n1:\n\t"						\
 | 
			
		||||
		  ".long ( 4f - 1b )\n\t"				\
 | 
			
		||||
		  ".long %c0\n\t"					\
 | 
			
		||||
		  ".long %" ASM_NO_PREFIX "0\n\t"			\
 | 
			
		||||
		  ".long ( 2f - 1b )\n\t"				\
 | 
			
		||||
		  ".long ( 3f - 1b )\n\t"				\
 | 
			
		||||
		  ".long %c1\n\t"					\
 | 
			
		||||
		  ".long %" ASM_NO_PREFIX "1\n\t"			\
 | 
			
		||||
		  "\n2:\t.asciz \"" __einfo_desc ( einfo ) "\"\n\t"	\
 | 
			
		||||
		  "\n3:\t.asciz \"" __FILE__ "\"\n\t"			\
 | 
			
		||||
		  ".balign 8\n\t"					\
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										188
									
								
								src/include/ipxe/efi/Guid/GlobalVariable.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										188
									
								
								src/include/ipxe/efi/Guid/GlobalVariable.h
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,188 @@
 | 
			
		||||
/** @file
 | 
			
		||||
  GUID for EFI (NVRAM) Variables.
 | 
			
		||||
 | 
			
		||||
  Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
 | 
			
		||||
  SPDX-License-Identifier: BSD-2-Clause-Patent
 | 
			
		||||
 | 
			
		||||
  @par Revision Reference:
 | 
			
		||||
  GUID defined in UEFI 2.1
 | 
			
		||||
**/
 | 
			
		||||
 | 
			
		||||
#ifndef __GLOBAL_VARIABLE_GUID_H__
 | 
			
		||||
#define __GLOBAL_VARIABLE_GUID_H__
 | 
			
		||||
 | 
			
		||||
FILE_LICENCE ( BSD2_PATENT );
 | 
			
		||||
 | 
			
		||||
#define EFI_GLOBAL_VARIABLE \
 | 
			
		||||
  { \
 | 
			
		||||
    0x8BE4DF61, 0x93CA, 0x11d2, {0xAA, 0x0D, 0x00, 0xE0, 0x98, 0x03, 0x2B, 0x8C } \
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
extern EFI_GUID  gEfiGlobalVariableGuid;
 | 
			
		||||
 | 
			
		||||
//
 | 
			
		||||
// Follow UEFI 2.4 spec:
 | 
			
		||||
// To prevent name collisions with possible future globally defined variables,
 | 
			
		||||
// other internal firmware data variables that are not defined here must be
 | 
			
		||||
// saved with a unique VendorGuid other than EFI_GLOBAL_VARIABLE or
 | 
			
		||||
// any other GUID defined by the UEFI Specification. Implementations must
 | 
			
		||||
// only permit the creation of variables with a UEFI Specification-defined
 | 
			
		||||
// VendorGuid when these variables are documented in the UEFI Specification.
 | 
			
		||||
//
 | 
			
		||||
// Note: except the globally defined variables defined below, the spec also defines
 | 
			
		||||
// L"Boot####"      - A boot load option.
 | 
			
		||||
// L"Driver####"    - A driver load option.
 | 
			
		||||
// L"SysPrep####"   - A System Prep application load option.
 | 
			
		||||
// L"Key####"       - Describes hot key relationship with a Boot#### load option.
 | 
			
		||||
// The attribute for them is NV+BS+RT, #### is a printed hex value, and no 0x or h
 | 
			
		||||
// is included in the hex value. They can not be expressed as a #define like other globally
 | 
			
		||||
// defined variables, it is because we can not list the Boot0000, Boot0001, etc one by one.
 | 
			
		||||
//
 | 
			
		||||
 | 
			
		||||
///
 | 
			
		||||
/// The language codes that the firmware supports. This value is deprecated.
 | 
			
		||||
/// Its attribute is BS+RT.
 | 
			
		||||
///
 | 
			
		||||
#define EFI_LANG_CODES_VARIABLE_NAME  L"LangCodes"
 | 
			
		||||
///
 | 
			
		||||
/// The language code that the system is configured for. This value is deprecated.
 | 
			
		||||
/// Its attribute is NV+BS+RT.
 | 
			
		||||
///
 | 
			
		||||
#define EFI_LANG_VARIABLE_NAME  L"Lang"
 | 
			
		||||
///
 | 
			
		||||
/// The firmware's boot managers timeout, in seconds, before initiating the default boot selection.
 | 
			
		||||
/// Its attribute is NV+BS+RT.
 | 
			
		||||
///
 | 
			
		||||
#define EFI_TIME_OUT_VARIABLE_NAME  L"Timeout"
 | 
			
		||||
///
 | 
			
		||||
/// The language codes that the firmware supports.
 | 
			
		||||
/// Its attribute is BS+RT.
 | 
			
		||||
///
 | 
			
		||||
#define EFI_PLATFORM_LANG_CODES_VARIABLE_NAME  L"PlatformLangCodes"
 | 
			
		||||
///
 | 
			
		||||
/// The language code that the system is configured for.
 | 
			
		||||
/// Its attribute is NV+BS+RT.
 | 
			
		||||
///
 | 
			
		||||
#define EFI_PLATFORM_LANG_VARIABLE_NAME  L"PlatformLang"
 | 
			
		||||
///
 | 
			
		||||
/// The device path of the default input/output/error output console.
 | 
			
		||||
/// Its attribute is NV+BS+RT.
 | 
			
		||||
///
 | 
			
		||||
#define EFI_CON_IN_VARIABLE_NAME   L"ConIn"
 | 
			
		||||
#define EFI_CON_OUT_VARIABLE_NAME  L"ConOut"
 | 
			
		||||
#define EFI_ERR_OUT_VARIABLE_NAME  L"ErrOut"
 | 
			
		||||
///
 | 
			
		||||
/// The device path of all possible input/output/error output devices.
 | 
			
		||||
/// Its attribute is BS+RT.
 | 
			
		||||
///
 | 
			
		||||
#define EFI_CON_IN_DEV_VARIABLE_NAME   L"ConInDev"
 | 
			
		||||
#define EFI_CON_OUT_DEV_VARIABLE_NAME  L"ConOutDev"
 | 
			
		||||
#define EFI_ERR_OUT_DEV_VARIABLE_NAME  L"ErrOutDev"
 | 
			
		||||
///
 | 
			
		||||
/// The ordered boot option load list.
 | 
			
		||||
/// Its attribute is NV+BS+RT.
 | 
			
		||||
///
 | 
			
		||||
#define EFI_BOOT_ORDER_VARIABLE_NAME  L"BootOrder"
 | 
			
		||||
///
 | 
			
		||||
/// The boot option for the next boot only.
 | 
			
		||||
/// Its attribute is NV+BS+RT.
 | 
			
		||||
///
 | 
			
		||||
#define EFI_BOOT_NEXT_VARIABLE_NAME  L"BootNext"
 | 
			
		||||
///
 | 
			
		||||
/// The boot option that was selected for the current boot.
 | 
			
		||||
/// Its attribute is BS+RT.
 | 
			
		||||
///
 | 
			
		||||
#define EFI_BOOT_CURRENT_VARIABLE_NAME  L"BootCurrent"
 | 
			
		||||
///
 | 
			
		||||
/// The types of boot options supported by the boot manager. Should be treated as read-only.
 | 
			
		||||
/// Its attribute is BS+RT.
 | 
			
		||||
///
 | 
			
		||||
#define EFI_BOOT_OPTION_SUPPORT_VARIABLE_NAME  L"BootOptionSupport"
 | 
			
		||||
///
 | 
			
		||||
/// The ordered driver load option list.
 | 
			
		||||
/// Its attribute is NV+BS+RT.
 | 
			
		||||
///
 | 
			
		||||
#define EFI_DRIVER_ORDER_VARIABLE_NAME  L"DriverOrder"
 | 
			
		||||
///
 | 
			
		||||
/// The ordered System Prep Application load option list.
 | 
			
		||||
/// Its attribute is NV+BS+RT.
 | 
			
		||||
///
 | 
			
		||||
#define EFI_SYS_PREP_ORDER_VARIABLE_NAME  L"SysPrepOrder"
 | 
			
		||||
///
 | 
			
		||||
/// Identifies the level of hardware error record persistence
 | 
			
		||||
/// support implemented by the platform. This variable is
 | 
			
		||||
/// only modified by firmware and is read-only to the OS.
 | 
			
		||||
/// Its attribute is NV+BS+RT.
 | 
			
		||||
///
 | 
			
		||||
#define EFI_HW_ERR_REC_SUPPORT_VARIABLE_NAME  L"HwErrRecSupport"
 | 
			
		||||
///
 | 
			
		||||
/// Whether the system is operating in setup mode (1) or not (0).
 | 
			
		||||
/// All other values are reserved. Should be treated as read-only.
 | 
			
		||||
/// Its attribute is BS+RT.
 | 
			
		||||
///
 | 
			
		||||
#define EFI_SETUP_MODE_NAME  L"SetupMode"
 | 
			
		||||
///
 | 
			
		||||
/// The Key Exchange Key Signature Database.
 | 
			
		||||
/// Its attribute is NV+BS+RT+AT.
 | 
			
		||||
///
 | 
			
		||||
#define EFI_KEY_EXCHANGE_KEY_NAME  L"KEK"
 | 
			
		||||
///
 | 
			
		||||
/// The public Platform Key.
 | 
			
		||||
/// Its attribute is NV+BS+RT+AT.
 | 
			
		||||
///
 | 
			
		||||
#define EFI_PLATFORM_KEY_NAME  L"PK"
 | 
			
		||||
///
 | 
			
		||||
/// Array of GUIDs representing the type of signatures supported
 | 
			
		||||
/// by the platform firmware. Should be treated as read-only.
 | 
			
		||||
/// Its attribute is BS+RT.
 | 
			
		||||
///
 | 
			
		||||
#define EFI_SIGNATURE_SUPPORT_NAME  L"SignatureSupport"
 | 
			
		||||
///
 | 
			
		||||
/// Whether the platform firmware is operating in Secure boot mode (1) or not (0).
 | 
			
		||||
/// All other values are reserved. Should be treated as read-only.
 | 
			
		||||
/// Its attribute is BS+RT.
 | 
			
		||||
///
 | 
			
		||||
#define EFI_SECURE_BOOT_MODE_NAME  L"SecureBoot"
 | 
			
		||||
///
 | 
			
		||||
/// The OEM's default Key Exchange Key Signature Database. Should be treated as read-only.
 | 
			
		||||
/// Its attribute is BS+RT.
 | 
			
		||||
///
 | 
			
		||||
#define EFI_KEK_DEFAULT_VARIABLE_NAME  L"KEKDefault"
 | 
			
		||||
///
 | 
			
		||||
/// The OEM's default public Platform Key. Should be treated as read-only.
 | 
			
		||||
/// Its attribute is BS+RT.
 | 
			
		||||
///
 | 
			
		||||
#define EFI_PK_DEFAULT_VARIABLE_NAME  L"PKDefault"
 | 
			
		||||
///
 | 
			
		||||
/// The OEM's default secure boot signature store. Should be treated as read-only.
 | 
			
		||||
/// Its attribute is BS+RT.
 | 
			
		||||
///
 | 
			
		||||
#define EFI_DB_DEFAULT_VARIABLE_NAME  L"dbDefault"
 | 
			
		||||
///
 | 
			
		||||
/// The OEM's default secure boot blacklist signature store. Should be treated as read-only.
 | 
			
		||||
/// Its attribute is BS+RT.
 | 
			
		||||
///
 | 
			
		||||
#define EFI_DBX_DEFAULT_VARIABLE_NAME  L"dbxDefault"
 | 
			
		||||
///
 | 
			
		||||
/// The OEM's default secure boot timestamp signature store. Should be treated as read-only.
 | 
			
		||||
/// Its attribute is BS+RT.
 | 
			
		||||
///
 | 
			
		||||
#define EFI_DBT_DEFAULT_VARIABLE_NAME  L"dbtDefault"
 | 
			
		||||
///
 | 
			
		||||
/// Allows the firmware to indicate supported features and actions to the OS.
 | 
			
		||||
/// Its attribute is BS+RT.
 | 
			
		||||
///
 | 
			
		||||
#define EFI_OS_INDICATIONS_SUPPORT_VARIABLE_NAME  L"OsIndicationsSupported"
 | 
			
		||||
///
 | 
			
		||||
/// Allows the OS to request the firmware to enable certain features and to take certain actions.
 | 
			
		||||
/// Its attribute is NV+BS+RT.
 | 
			
		||||
///
 | 
			
		||||
#define EFI_OS_INDICATIONS_VARIABLE_NAME  L"OsIndications"
 | 
			
		||||
///
 | 
			
		||||
/// Whether the system is configured to use only vendor provided
 | 
			
		||||
/// keys or not. Should be treated as read-only.
 | 
			
		||||
/// Its attribute is BS+RT.
 | 
			
		||||
///
 | 
			
		||||
#define EFI_VENDOR_KEYS_VARIABLE_NAME  L"VendorKeys"
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
@ -1,35 +0,0 @@
 | 
			
		||||
#ifndef _IPXE_EFI_ENTROPY_H
 | 
			
		||||
#define _IPXE_EFI_ENTROPY_H
 | 
			
		||||
 | 
			
		||||
/** @file
 | 
			
		||||
 *
 | 
			
		||||
 * EFI entropy source
 | 
			
		||||
 *
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
 | 
			
		||||
 | 
			
		||||
#include <stdint.h>
 | 
			
		||||
 | 
			
		||||
#ifdef ENTROPY_EFI
 | 
			
		||||
#define ENTROPY_PREFIX_efi
 | 
			
		||||
#else
 | 
			
		||||
#define ENTROPY_PREFIX_efi __efi_
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * min-entropy per sample
 | 
			
		||||
 *
 | 
			
		||||
 * @ret min_entropy	min-entropy of each sample
 | 
			
		||||
 */
 | 
			
		||||
static inline __always_inline min_entropy_t
 | 
			
		||||
ENTROPY_INLINE ( efi, min_entropy_per_sample ) ( void ) {
 | 
			
		||||
 | 
			
		||||
	/* We use essentially the same mechanism as for the BIOS
 | 
			
		||||
	 * RTC-based entropy source, and so assume the same
 | 
			
		||||
	 * min-entropy per sample.
 | 
			
		||||
	 */
 | 
			
		||||
	return MIN_ENTROPY ( 1.3 );
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#endif /* _IPXE_EFI_ENTROPY_H */
 | 
			
		||||
@ -12,40 +12,11 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
 | 
			
		||||
#include <stdint.h>
 | 
			
		||||
#include <string.h>
 | 
			
		||||
#include <assert.h>
 | 
			
		||||
#include <ipxe/api.h>
 | 
			
		||||
#include <ipxe/hash_df.h>
 | 
			
		||||
#include <ipxe/sha256.h>
 | 
			
		||||
#include <ipxe/tables.h>
 | 
			
		||||
#include <config/entropy.h>
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Calculate static inline entropy API function name
 | 
			
		||||
 *
 | 
			
		||||
 * @v _prefix		Subsystem prefix
 | 
			
		||||
 * @v _api_func		API function
 | 
			
		||||
 * @ret _subsys_func	Subsystem API function
 | 
			
		||||
 */
 | 
			
		||||
#define ENTROPY_INLINE( _subsys, _api_func ) \
 | 
			
		||||
	SINGLE_API_INLINE ( ENTROPY_PREFIX_ ## _subsys, _api_func )
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Provide a entropy API implementation
 | 
			
		||||
 *
 | 
			
		||||
 * @v _prefix		Subsystem prefix
 | 
			
		||||
 * @v _api_func		API function
 | 
			
		||||
 * @v _func		Implementing function
 | 
			
		||||
 */
 | 
			
		||||
#define PROVIDE_ENTROPY( _subsys, _api_func, _func ) \
 | 
			
		||||
	PROVIDE_SINGLE_API ( ENTROPY_PREFIX_ ## _subsys, _api_func, _func )
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Provide a static inline entropy API implementation
 | 
			
		||||
 *
 | 
			
		||||
 * @v _prefix		Subsystem prefix
 | 
			
		||||
 * @v _api_func		API function
 | 
			
		||||
 */
 | 
			
		||||
#define PROVIDE_ENTROPY_INLINE( _subsys, _api_func ) \
 | 
			
		||||
	PROVIDE_SINGLE_API_INLINE ( ENTROPY_PREFIX_ ## _subsys, _api_func )
 | 
			
		||||
 | 
			
		||||
/** A noise sample */
 | 
			
		||||
typedef uint8_t noise_sample_t;
 | 
			
		||||
 | 
			
		||||
@ -71,56 +42,148 @@ typedef unsigned int min_entropy_t;
 | 
			
		||||
#define MIN_ENTROPY( bits ) \
 | 
			
		||||
	( ( min_entropy_t ) ( (bits) * MIN_ENTROPY_SCALE ) )
 | 
			
		||||
 | 
			
		||||
/* Include all architecture-independent entropy API headers */
 | 
			
		||||
#include <ipxe/null_entropy.h>
 | 
			
		||||
#include <ipxe/efi/efi_entropy.h>
 | 
			
		||||
#include <ipxe/linux/linux_entropy.h>
 | 
			
		||||
 | 
			
		||||
/* Include all architecture-dependent entropy API headers */
 | 
			
		||||
#include <bits/entropy.h>
 | 
			
		||||
/**
 | 
			
		||||
 * Repetition count test state
 | 
			
		||||
 *
 | 
			
		||||
 * This is the state for the repetition Count Test defined in ANS
 | 
			
		||||
 * X9.82 Part 2 (October 2011 Draft) Section 8.5.2.1.2.
 | 
			
		||||
 */
 | 
			
		||||
struct entropy_repetition_count_test {
 | 
			
		||||
	/**
 | 
			
		||||
	 * A = the most recently seen sample value
 | 
			
		||||
	 */
 | 
			
		||||
	noise_sample_t most_recent_sample;
 | 
			
		||||
	/**
 | 
			
		||||
	 * B = the number of times that value A has been seen in a row
 | 
			
		||||
	 */
 | 
			
		||||
	unsigned int repetition_count;
 | 
			
		||||
	/**
 | 
			
		||||
	 * C = the cutoff value above which the repetition test should fail
 | 
			
		||||
	 *
 | 
			
		||||
	 * Filled in by entropy_init().
 | 
			
		||||
	 */
 | 
			
		||||
	unsigned int cutoff;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Enable entropy gathering
 | 
			
		||||
 * Adaptive proportion test state
 | 
			
		||||
 *
 | 
			
		||||
 * @ret rc		Return status code
 | 
			
		||||
 * This is the state for the Adaptive Proportion Test for the Most
 | 
			
		||||
 * Common Value defined in ANS X9.82 Part 2 (October 2011 Draft)
 | 
			
		||||
 * Section 8.5.2.1.3.
 | 
			
		||||
 */
 | 
			
		||||
int entropy_enable ( void );
 | 
			
		||||
struct entropy_adaptive_proportion_test {
 | 
			
		||||
	/**
 | 
			
		||||
	 * A = the sample value currently being counted
 | 
			
		||||
	 */
 | 
			
		||||
	noise_sample_t current_counted_sample;
 | 
			
		||||
	/**
 | 
			
		||||
	 * S = the number of samples examined in this run of the test so far
 | 
			
		||||
	 */
 | 
			
		||||
	unsigned int sample_count;
 | 
			
		||||
	/**
 | 
			
		||||
	 * B = the current number of times that S (sic) has been seen
 | 
			
		||||
	 *     in the W (sic) samples examined so far
 | 
			
		||||
	 */
 | 
			
		||||
	unsigned int repetition_count;
 | 
			
		||||
	/**
 | 
			
		||||
	 * C = the cutoff value above which the repetition test should fail
 | 
			
		||||
	 *
 | 
			
		||||
	 * Filled in by entropy_init().
 | 
			
		||||
	 */
 | 
			
		||||
	unsigned int cutoff;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Disable entropy gathering
 | 
			
		||||
 * Startup test state
 | 
			
		||||
 *
 | 
			
		||||
 * ANS X9.82 Part 2 (October 2011 Draft) Section 8.5.2.1.5 requires
 | 
			
		||||
 * that at least one full cycle of the continuous tests must be
 | 
			
		||||
 * performed at start-up.
 | 
			
		||||
 */
 | 
			
		||||
void entropy_disable ( void );
 | 
			
		||||
struct entropy_startup_test {
 | 
			
		||||
	/** Number of startup tests performed */
 | 
			
		||||
	unsigned int tested;
 | 
			
		||||
	/**
 | 
			
		||||
	 * Number of startup tests required for one full cycle
 | 
			
		||||
	 *
 | 
			
		||||
	 * Filled in by entropy_init().
 | 
			
		||||
	 */
 | 
			
		||||
	unsigned int count;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * min-entropy per sample
 | 
			
		||||
/** An entropy source */
 | 
			
		||||
struct entropy_source {
 | 
			
		||||
	/** Name */
 | 
			
		||||
	const char *name;
 | 
			
		||||
	/**
 | 
			
		||||
	 * min-entropy per sample
 | 
			
		||||
	 *
 | 
			
		||||
	 * min-entropy is defined in ANS X9.82 Part 1-2006 Section 8.3 and in
 | 
			
		||||
	 * NIST SP 800-90 Appendix C.3 as
 | 
			
		||||
	 *
 | 
			
		||||
	 *    H_min = -log2 ( p_max )
 | 
			
		||||
	 *
 | 
			
		||||
	 * where p_max is the probability of the most likely sample value.
 | 
			
		||||
	 *
 | 
			
		||||
	 * Filled in by entropy_init().
 | 
			
		||||
	 */
 | 
			
		||||
	min_entropy_t min_entropy_per_sample;
 | 
			
		||||
	/** Repetition count test state */
 | 
			
		||||
	struct entropy_repetition_count_test repetition_count_test;
 | 
			
		||||
	/** Adaptive proportion test state */
 | 
			
		||||
	struct entropy_adaptive_proportion_test adaptive_proportion_test;
 | 
			
		||||
	/** Startup test state */
 | 
			
		||||
	struct entropy_startup_test startup_test;
 | 
			
		||||
	/**
 | 
			
		||||
	 * Failure status (if any)
 | 
			
		||||
	 *
 | 
			
		||||
	 * Any failure of an entropy source is regarded as permanent.
 | 
			
		||||
	 */
 | 
			
		||||
	int rc;
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * Enable entropy gathering
 | 
			
		||||
	 *
 | 
			
		||||
	 * @ret rc		Return status code
 | 
			
		||||
	 */
 | 
			
		||||
	int ( * enable ) ( void );
 | 
			
		||||
	/**
 | 
			
		||||
	 * Disable entropy gathering
 | 
			
		||||
	 *
 | 
			
		||||
	 */
 | 
			
		||||
	void ( * disable ) ( void );
 | 
			
		||||
	/**
 | 
			
		||||
	 * Get noise sample
 | 
			
		||||
	 *
 | 
			
		||||
	 * @ret noise		Noise sample
 | 
			
		||||
	 * @ret rc		Return status code
 | 
			
		||||
	 *
 | 
			
		||||
	 * This is the GetNoise function defined in ANS X9.82 Part 2
 | 
			
		||||
	 * (October 2011 Draft) Section 6.5.2.
 | 
			
		||||
	 */
 | 
			
		||||
	int ( * get_noise ) ( noise_sample_t *noise );
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/** Entropy source table */
 | 
			
		||||
#define ENTROPY_SOURCES __table ( struct entropy_source, "entropy_sources" )
 | 
			
		||||
 | 
			
		||||
/** Declare an entropy source */
 | 
			
		||||
#define __entropy_source( order ) __table_entry ( ENTROPY_SOURCES, order )
 | 
			
		||||
 | 
			
		||||
/** @defgroup entropy_source_order Entropy source order
 | 
			
		||||
 *
 | 
			
		||||
 * @ret min_entropy	min-entropy of each sample
 | 
			
		||||
 *
 | 
			
		||||
 * min-entropy is defined in ANS X9.82 Part 1-2006 Section 8.3 and in
 | 
			
		||||
 * NIST SP 800-90 Appendix C.3 as
 | 
			
		||||
 *
 | 
			
		||||
 *    H_min = -log2 ( p_max )
 | 
			
		||||
 *
 | 
			
		||||
 * where p_max is the probability of the most likely sample value.
 | 
			
		||||
 *
 | 
			
		||||
 * This must be a compile-time constant.
 | 
			
		||||
 * @{
 | 
			
		||||
 */
 | 
			
		||||
min_entropy_t min_entropy_per_sample ( void );
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Get noise sample
 | 
			
		||||
 *
 | 
			
		||||
 * @ret noise		Noise sample
 | 
			
		||||
 * @ret rc		Return status code
 | 
			
		||||
 *
 | 
			
		||||
 * This is the GetNoise function defined in ANS X9.82 Part 2
 | 
			
		||||
 * (October 2011 Draft) Section 6.5.2.
 | 
			
		||||
 */
 | 
			
		||||
int get_noise ( noise_sample_t *noise );
 | 
			
		||||
#define ENTROPY_PREFERRED	01	/**< Preferred entropy source */
 | 
			
		||||
#define ENTROPY_NORMAL		02	/**< Normal entropy source */
 | 
			
		||||
#define ENTROPY_FALLBACK	03	/**< Fallback entropy source */
 | 
			
		||||
 | 
			
		||||
extern int get_entropy_input_tmp ( unsigned int num_samples,
 | 
			
		||||
				   uint8_t *tmp, size_t tmp_len );
 | 
			
		||||
/** @} */
 | 
			
		||||
 | 
			
		||||
extern int get_entropy_input_tmp ( min_entropy_t min_entropy, uint8_t *tmp,
 | 
			
		||||
				   size_t tmp_len );
 | 
			
		||||
 | 
			
		||||
/** Use SHA-256 as the underlying hash algorithm for Hash_df
 | 
			
		||||
 *
 | 
			
		||||
@ -131,6 +194,22 @@ extern int get_entropy_input_tmp ( unsigned int num_samples,
 | 
			
		||||
/** Underlying hash algorithm output length (in bytes) */
 | 
			
		||||
#define ENTROPY_HASH_DF_OUTLEN_BYTES SHA256_DIGEST_SIZE
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Get noise sample
 | 
			
		||||
 *
 | 
			
		||||
 * @v source		Entropy source
 | 
			
		||||
 * @ret noise		Noise sample
 | 
			
		||||
 * @ret rc		Return status code
 | 
			
		||||
 *
 | 
			
		||||
 * This is the GetNoise function defined in ANS X9.82 Part 2
 | 
			
		||||
 * (October 2011 Draft) Section 6.5.2.
 | 
			
		||||
 */
 | 
			
		||||
static inline __attribute__ (( always_inline )) int
 | 
			
		||||
get_noise ( struct entropy_source *source, noise_sample_t *noise ) {
 | 
			
		||||
 | 
			
		||||
	return source->get_noise ( noise );
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Obtain entropy input
 | 
			
		||||
 *
 | 
			
		||||
@ -145,8 +224,8 @@ extern int get_entropy_input_tmp ( unsigned int num_samples,
 | 
			
		||||
 * each entropy source output after each GetEntropy call) as defined
 | 
			
		||||
 * in ANS X9.82 Part 4 (April 2011 Draft) Section 13.3.4.2.
 | 
			
		||||
 *
 | 
			
		||||
 * To minimise code size, the number of samples required is calculated
 | 
			
		||||
 * at compilation time.
 | 
			
		||||
 * This function is inlined since the entropy amount and length inputs
 | 
			
		||||
 * are always compile-time constants.
 | 
			
		||||
 */
 | 
			
		||||
static inline __attribute__ (( always_inline )) int
 | 
			
		||||
get_entropy_input ( unsigned int min_entropy_bits, void *data, size_t min_len,
 | 
			
		||||
@ -154,41 +233,16 @@ get_entropy_input ( unsigned int min_entropy_bits, void *data, size_t min_len,
 | 
			
		||||
	size_t tmp_len = ( ( ( min_entropy_bits * 2 ) + 7 ) / 8 );
 | 
			
		||||
	uint8_t tmp_buf[ tmp_len ];
 | 
			
		||||
	uint8_t *tmp = ( ( tmp_len > max_len ) ? tmp_buf : data );
 | 
			
		||||
	double min_samples;
 | 
			
		||||
	unsigned int num_samples;
 | 
			
		||||
	unsigned int n;
 | 
			
		||||
	int rc;
 | 
			
		||||
 | 
			
		||||
	/* Sanity checks */
 | 
			
		||||
	linker_assert ( ( min_entropy_per_sample() <=
 | 
			
		||||
			  MIN_ENTROPY ( 8 * sizeof ( noise_sample_t ) ) ),
 | 
			
		||||
			min_entropy_per_sample_is_impossibly_high );
 | 
			
		||||
	/* Sanity check */
 | 
			
		||||
	linker_assert ( ( min_entropy_bits <= ( 8 * max_len ) ),
 | 
			
		||||
			entropy_buffer_too_small );
 | 
			
		||||
 | 
			
		||||
	/* Round up minimum entropy to an integral number of bytes */
 | 
			
		||||
	min_entropy_bits = ( ( min_entropy_bits + 7 ) & ~7 );
 | 
			
		||||
 | 
			
		||||
	/* Calculate number of samples required to contain sufficient entropy */
 | 
			
		||||
	min_samples = ( MIN_ENTROPY ( min_entropy_bits ) /
 | 
			
		||||
			min_entropy_per_sample() );
 | 
			
		||||
 | 
			
		||||
	/* Round up to a whole number of samples.  We don't have the
 | 
			
		||||
	 * ceil() function available, so do the rounding by hand.
 | 
			
		||||
	 */
 | 
			
		||||
	num_samples = min_samples;
 | 
			
		||||
	if ( num_samples < min_samples )
 | 
			
		||||
		num_samples++;
 | 
			
		||||
	linker_assert ( ( num_samples >= min_samples ), rounding_error );
 | 
			
		||||
 | 
			
		||||
	/* Floating-point operations are not allowed in iPXE since we
 | 
			
		||||
	 * never set up a suitable environment.  Abort the build
 | 
			
		||||
	 * unless the calculated number of samples is a compile-time
 | 
			
		||||
	 * constant.
 | 
			
		||||
	 */
 | 
			
		||||
	linker_assert ( __builtin_constant_p ( num_samples ),
 | 
			
		||||
			num_samples_not_constant );
 | 
			
		||||
 | 
			
		||||
	/* (Unnumbered).  The output length of the hash function shall
 | 
			
		||||
	 * meet or exceed the security strength indicated by the
 | 
			
		||||
	 * min_entropy parameter.
 | 
			
		||||
@ -218,8 +272,10 @@ get_entropy_input ( unsigned int min_entropy_bits, void *data, size_t min_len,
 | 
			
		||||
	linker_assert ( __builtin_constant_p ( tmp_len ),
 | 
			
		||||
			tmp_len_not_constant );
 | 
			
		||||
	linker_assert ( ( n == ( 8 * tmp_len ) ), tmp_len_mismatch );
 | 
			
		||||
	if ( ( rc = get_entropy_input_tmp ( num_samples, tmp, tmp_len ) ) != 0 )
 | 
			
		||||
	if ( ( rc = get_entropy_input_tmp ( MIN_ENTROPY ( min_entropy_bits ),
 | 
			
		||||
					    tmp, tmp_len ) ) != 0 ) {
 | 
			
		||||
		return rc;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* 6.  If ( n < min_length ), then tmp = tmp || 0^(min_length-n)
 | 
			
		||||
	 * 7.  If ( n > max_length ), then tmp = df ( tmp, max_length )
 | 
			
		||||
@ -242,4 +298,231 @@ get_entropy_input ( unsigned int min_entropy_bits, void *data, size_t min_len,
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Calculate cutoff value for the repetition count test
 | 
			
		||||
 *
 | 
			
		||||
 * @v min_entropy_per_sample	Min-entropy per sample
 | 
			
		||||
 * @ret cutoff			Cutoff value
 | 
			
		||||
 *
 | 
			
		||||
 * This is the cutoff value for the Repetition Count Test defined in
 | 
			
		||||
 * ANS X9.82 Part 2 (October 2011 Draft) Section 8.5.2.1.2.
 | 
			
		||||
 */
 | 
			
		||||
static inline __attribute__ (( always_inline )) unsigned int
 | 
			
		||||
entropy_repetition_count_cutoff ( min_entropy_t min_entropy_per_sample ) {
 | 
			
		||||
	double max_repetitions;
 | 
			
		||||
	unsigned int cutoff;
 | 
			
		||||
 | 
			
		||||
	/* The cutoff formula for the repetition test is:
 | 
			
		||||
	 *
 | 
			
		||||
	 *   C = ( 1 + ( -log2(W) / H_min ) )
 | 
			
		||||
	 *
 | 
			
		||||
	 * where W is set at 2^(-30) (in ANS X9.82 Part 2 (October
 | 
			
		||||
	 * 2011 Draft) Section 8.5.2.1.3.1).
 | 
			
		||||
	 */
 | 
			
		||||
	max_repetitions = ( 1 + ( MIN_ENTROPY ( 30 ) /
 | 
			
		||||
				  min_entropy_per_sample ) );
 | 
			
		||||
 | 
			
		||||
	/* Round up to a whole number of repetitions.  We don't have
 | 
			
		||||
	 * the ceil() function available, so do the rounding by hand.
 | 
			
		||||
	 */
 | 
			
		||||
	cutoff = max_repetitions;
 | 
			
		||||
	if ( cutoff < max_repetitions )
 | 
			
		||||
		cutoff++;
 | 
			
		||||
	linker_assert ( ( cutoff >= max_repetitions ), rounding_error );
 | 
			
		||||
 | 
			
		||||
	/* Floating-point operations are not allowed in iPXE since we
 | 
			
		||||
	 * never set up a suitable environment.  Abort the build
 | 
			
		||||
	 * unless the calculated number of repetitions is a
 | 
			
		||||
	 * compile-time constant.
 | 
			
		||||
	 */
 | 
			
		||||
	linker_assert ( __builtin_constant_p ( cutoff ),
 | 
			
		||||
			repetition_count_cutoff_not_constant );
 | 
			
		||||
 | 
			
		||||
	return cutoff;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Window size for the adaptive proportion test
 | 
			
		||||
 *
 | 
			
		||||
 * ANS X9.82 Part 2 (October 2011 Draft) Section 8.5.2.1.3.1.1 allows
 | 
			
		||||
 * five possible window sizes: 16, 64, 256, 4096 and 65536.
 | 
			
		||||
 *
 | 
			
		||||
 * We expect to generate relatively few (<256) entropy samples during
 | 
			
		||||
 * a typical iPXE run; the use of a large window size would mean that
 | 
			
		||||
 * the test would never complete a single cycle.  We use a window size
 | 
			
		||||
 * of 64, which is the smallest window size that permits values of
 | 
			
		||||
 * H_min down to one bit per sample.
 | 
			
		||||
 */
 | 
			
		||||
#define ADAPTIVE_PROPORTION_WINDOW_SIZE 64
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Combine adaptive proportion test window size and min-entropy
 | 
			
		||||
 *
 | 
			
		||||
 * @v n			N (window size)
 | 
			
		||||
 * @v h			H (min-entropy)
 | 
			
		||||
 * @ret n_h		(N,H) combined value
 | 
			
		||||
 */
 | 
			
		||||
#define APC_N_H( n, h ) ( ( (n) << 8 ) | (h) )
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Define a row of the adaptive proportion cutoff table
 | 
			
		||||
 *
 | 
			
		||||
 * @v h			H (min-entropy)
 | 
			
		||||
 * @v c16		Cutoff for N=16
 | 
			
		||||
 * @v c64		Cutoff for N=64
 | 
			
		||||
 * @v c256		Cutoff for N=256
 | 
			
		||||
 * @v c4096		Cutoff for N=4096
 | 
			
		||||
 * @v c65536		Cutoff for N=65536
 | 
			
		||||
 */
 | 
			
		||||
#define APC_TABLE_ROW( h, c16, c64, c256, c4096, c65536)	   \
 | 
			
		||||
	case APC_N_H ( 16, h ) :	return c16;		   \
 | 
			
		||||
	case APC_N_H ( 64, h ) :	return c64;   		   \
 | 
			
		||||
	case APC_N_H ( 256, h ) :	return c256;		   \
 | 
			
		||||
	case APC_N_H ( 4096, h ) :	return c4096;		   \
 | 
			
		||||
	case APC_N_H ( 65536, h ) :	return c65536;
 | 
			
		||||
 | 
			
		||||
/** Value used to represent "N/A" in adaptive proportion cutoff table */
 | 
			
		||||
#define APC_NA 0
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Look up value in adaptive proportion test cutoff table
 | 
			
		||||
 *
 | 
			
		||||
 * @v n			N (window size)
 | 
			
		||||
 * @v h			H (min-entropy)
 | 
			
		||||
 * @ret cutoff		Cutoff
 | 
			
		||||
 *
 | 
			
		||||
 * This is the table of cutoff values defined in ANS X9.82 Part 2
 | 
			
		||||
 * (October 2011 Draft) Section 8.5.2.1.3.1.2.
 | 
			
		||||
 */
 | 
			
		||||
static inline __attribute__ (( always_inline )) unsigned int
 | 
			
		||||
entropy_adaptive_proportion_cutoff_lookup ( unsigned int n, unsigned int h ) {
 | 
			
		||||
	switch ( APC_N_H ( n, h ) ) {
 | 
			
		||||
		APC_TABLE_ROW (  1, APC_NA,     51,    168,   2240,  33537 );
 | 
			
		||||
		APC_TABLE_ROW (  2, APC_NA,     35,    100,   1193,  17053 );
 | 
			
		||||
		APC_TABLE_ROW (  3,     10,     24,     61,    643,   8705 );
 | 
			
		||||
		APC_TABLE_ROW (  4,      8,     16,     38,    354,   4473 );
 | 
			
		||||
		APC_TABLE_ROW (  5,      6,     12,     25,    200,   2321 );
 | 
			
		||||
		APC_TABLE_ROW (  6,      5,      9,     17,    117,   1220 );
 | 
			
		||||
		APC_TABLE_ROW (  7,      4,      7,     15,     71,    653 );
 | 
			
		||||
		APC_TABLE_ROW (  8,      4,      5,      9,     45,    358 );
 | 
			
		||||
		APC_TABLE_ROW (  9,      3,      4,      7,     30,    202 );
 | 
			
		||||
		APC_TABLE_ROW ( 10,      3,      4,      5,     21,    118 );
 | 
			
		||||
		APC_TABLE_ROW ( 11,      2,      3,      4,     15,     71 );
 | 
			
		||||
		APC_TABLE_ROW ( 12,      2,      3,      4,     11,     45 );
 | 
			
		||||
		APC_TABLE_ROW ( 13,      2,      2,      3,      9,     30 );
 | 
			
		||||
		APC_TABLE_ROW ( 14,      2,      2,      3,      7,     21 );
 | 
			
		||||
		APC_TABLE_ROW ( 15,      1,      2,      2,      6,     15 );
 | 
			
		||||
		APC_TABLE_ROW ( 16,      1,      2,      2,      5,     11 );
 | 
			
		||||
		APC_TABLE_ROW ( 17,      1,      1,      2,      4,      9 );
 | 
			
		||||
		APC_TABLE_ROW ( 18,      1,      1,      2,      4,      7 );
 | 
			
		||||
		APC_TABLE_ROW ( 19,      1,      1,      1,      3,      6 );
 | 
			
		||||
		APC_TABLE_ROW ( 20,      1,      1,      1,      3,      5 );
 | 
			
		||||
	default:
 | 
			
		||||
		return APC_NA;
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Calculate cutoff value for the adaptive proportion test
 | 
			
		||||
 *
 | 
			
		||||
 * @v min_entropy_per_sample	Min-entropy per sample
 | 
			
		||||
 * @ret cutoff			Cutoff value
 | 
			
		||||
 *
 | 
			
		||||
 * This is the cutoff value for the Adaptive Proportion Test defined
 | 
			
		||||
 * in ANS X9.82 Part 2 (October 2011 Draft) Section 8.5.2.1.3.1.2.
 | 
			
		||||
 */
 | 
			
		||||
static inline __attribute__ (( always_inline )) unsigned int
 | 
			
		||||
entropy_adaptive_proportion_cutoff ( min_entropy_t min_entropy_per_sample ) {
 | 
			
		||||
	unsigned int h;
 | 
			
		||||
	unsigned int n;
 | 
			
		||||
	unsigned int cutoff;
 | 
			
		||||
 | 
			
		||||
	/* Look up cutoff value in cutoff table */
 | 
			
		||||
	n = ADAPTIVE_PROPORTION_WINDOW_SIZE;
 | 
			
		||||
	h = ( min_entropy_per_sample / MIN_ENTROPY_SCALE );
 | 
			
		||||
	cutoff = entropy_adaptive_proportion_cutoff_lookup ( n, h );
 | 
			
		||||
 | 
			
		||||
	/* Fail unless cutoff value is a compile-time constant */
 | 
			
		||||
	linker_assert ( __builtin_constant_p ( cutoff ),
 | 
			
		||||
			adaptive_proportion_cutoff_not_constant );
 | 
			
		||||
 | 
			
		||||
	/* Fail if cutoff value is N/A */
 | 
			
		||||
	linker_assert ( ( cutoff != APC_NA ),
 | 
			
		||||
			adaptive_proportion_cutoff_not_applicable );
 | 
			
		||||
 | 
			
		||||
	return cutoff;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Calculate number of samples required for startup tests
 | 
			
		||||
 *
 | 
			
		||||
 * @v repetition_count_cutoff	Repetition count test cutoff value
 | 
			
		||||
 * @v adaptive_proportion_cutoff Adaptive proportion test cutoff value
 | 
			
		||||
 * @ret num_samples		Number of samples required
 | 
			
		||||
 *
 | 
			
		||||
 * ANS X9.82 Part 2 (October 2011 Draft) Section 8.5.2.1.5 requires
 | 
			
		||||
 * that at least one full cycle of the continuous tests must be
 | 
			
		||||
 * performed at start-up.
 | 
			
		||||
 */
 | 
			
		||||
static inline __attribute__ (( always_inline )) unsigned int
 | 
			
		||||
entropy_startup_test_count ( unsigned int repetition_count_cutoff,
 | 
			
		||||
			     unsigned int adaptive_proportion_cutoff ) {
 | 
			
		||||
	unsigned int num_samples;
 | 
			
		||||
 | 
			
		||||
	/* At least max(N,C) samples shall be generated by the noise
 | 
			
		||||
	 * source for start-up testing.
 | 
			
		||||
	 */
 | 
			
		||||
	num_samples = repetition_count_cutoff;
 | 
			
		||||
	if ( num_samples < adaptive_proportion_cutoff )
 | 
			
		||||
		num_samples = adaptive_proportion_cutoff;
 | 
			
		||||
	linker_assert ( __builtin_constant_p ( num_samples ),
 | 
			
		||||
			startup_test_count_not_constant );
 | 
			
		||||
 | 
			
		||||
	return num_samples;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Initialise entropy source
 | 
			
		||||
 *
 | 
			
		||||
 * @v source			Entropy source
 | 
			
		||||
 * @v min_entropy_per_sample	Min-entropy per sample
 | 
			
		||||
 *
 | 
			
		||||
 * The cutoff value calculations for the repetition count test and the
 | 
			
		||||
 * adaptive proportion test are provided as static inline functions
 | 
			
		||||
 * since the results will always be compile-time constants.
 | 
			
		||||
 */
 | 
			
		||||
static inline __attribute__ (( always_inline )) void
 | 
			
		||||
entropy_init ( struct entropy_source *source,
 | 
			
		||||
	       min_entropy_t min_entropy_per_sample ) {
 | 
			
		||||
	unsigned int repetition_count_cutoff;
 | 
			
		||||
	unsigned int adaptive_proportion_cutoff;
 | 
			
		||||
	unsigned int startup_test_count;
 | 
			
		||||
 | 
			
		||||
	/* Sanity check */
 | 
			
		||||
	linker_assert ( min_entropy_per_sample > MIN_ENTROPY ( 0 ),
 | 
			
		||||
			min_entropy_per_sample_is_zero );
 | 
			
		||||
	linker_assert ( ( min_entropy_per_sample <=
 | 
			
		||||
			  MIN_ENTROPY ( 8 * sizeof ( noise_sample_t ) ) ),
 | 
			
		||||
			min_entropy_per_sample_is_impossibly_high );
 | 
			
		||||
 | 
			
		||||
	/* Calculate test cutoff values */
 | 
			
		||||
	repetition_count_cutoff =
 | 
			
		||||
		entropy_repetition_count_cutoff ( min_entropy_per_sample );
 | 
			
		||||
	adaptive_proportion_cutoff =
 | 
			
		||||
		entropy_adaptive_proportion_cutoff ( min_entropy_per_sample );
 | 
			
		||||
	startup_test_count =
 | 
			
		||||
		entropy_startup_test_count ( repetition_count_cutoff,
 | 
			
		||||
					     adaptive_proportion_cutoff );
 | 
			
		||||
 | 
			
		||||
	/* Record min-entropy per sample and test cutoff values */
 | 
			
		||||
	source->min_entropy_per_sample = min_entropy_per_sample;
 | 
			
		||||
	source->repetition_count_test.cutoff = repetition_count_cutoff;
 | 
			
		||||
	source->adaptive_proportion_test.cutoff = adaptive_proportion_cutoff;
 | 
			
		||||
	source->startup_test.count = startup_test_count;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
extern int entropy_enable ( struct entropy_source *source );
 | 
			
		||||
extern void entropy_disable ( struct entropy_source *source );
 | 
			
		||||
extern int get_noise ( struct entropy_source *source, noise_sample_t *noise );
 | 
			
		||||
 | 
			
		||||
#endif /* _IPXE_ENTROPY_H */
 | 
			
		||||
 | 
			
		||||
@ -295,6 +295,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
 | 
			
		||||
#define ERRFILE_ntp			( ERRFILE_NET | 0x00490000 )
 | 
			
		||||
#define ERRFILE_httpntlm		( ERRFILE_NET | 0x004a0000 )
 | 
			
		||||
#define ERRFILE_eap			( ERRFILE_NET | 0x004b0000 )
 | 
			
		||||
#define ERRFILE_lldp			( ERRFILE_NET | 0x004c0000 )
 | 
			
		||||
 | 
			
		||||
#define ERRFILE_image		      ( ERRFILE_IMAGE | 0x00000000 )
 | 
			
		||||
#define ERRFILE_elf		      ( ERRFILE_IMAGE | 0x00010000 )
 | 
			
		||||
@ -402,6 +403,8 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
 | 
			
		||||
#define ERRFILE_pci_cmd		      ( ERRFILE_OTHER | 0x00590000 )
 | 
			
		||||
#define ERRFILE_dhe		      ( ERRFILE_OTHER | 0x005a0000 )
 | 
			
		||||
#define ERRFILE_efi_cmdline	      ( ERRFILE_OTHER | 0x005b0000 )
 | 
			
		||||
#define ERRFILE_efi_rng		      ( ERRFILE_OTHER | 0x005c0000 )
 | 
			
		||||
#define ERRFILE_efi_settings	      ( ERRFILE_OTHER | 0x005d0000 )
 | 
			
		||||
 | 
			
		||||
/** @} */
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -23,6 +23,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
 | 
			
		||||
#define ETH_P_SLOW	0x8809	/* Ethernet slow protocols */
 | 
			
		||||
#define ETH_P_EAPOL	0x888E	/* 802.1X EAP over LANs */
 | 
			
		||||
#define ETH_P_AOE	0x88A2	/* ATA over Ethernet */
 | 
			
		||||
#define ETH_P_LLDP	0x88CC	/* Link Layer Discovery Protocol */
 | 
			
		||||
#define ETH_P_FCOE	0x8906	/* Fibre Channel over Ethernet */
 | 
			
		||||
#define ETH_P_FIP	0x8914	/* FCoE Initialization Protocol */
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -195,6 +195,7 @@ extern struct image * image_find_selected ( void );
 | 
			
		||||
extern int image_set_trust ( int require_trusted, int permanent );
 | 
			
		||||
extern struct image * image_memory ( const char *name, userptr_t data,
 | 
			
		||||
				     size_t len );
 | 
			
		||||
extern const char * image_argument ( struct image *image, const char *key );
 | 
			
		||||
extern int image_pixbuf ( struct image *image, struct pixel_buffer **pixbuf );
 | 
			
		||||
extern int image_asn1 ( struct image *image, size_t offset,
 | 
			
		||||
			struct asn1_cursor **cursor );
 | 
			
		||||
 | 
			
		||||
@ -22,6 +22,15 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
 | 
			
		||||
/** Default iSCSI port */
 | 
			
		||||
#define ISCSI_PORT 3260
 | 
			
		||||
 | 
			
		||||
/** Default iSCSI first burst length */
 | 
			
		||||
#define ISCSI_FIRST_BURST_LEN 65536
 | 
			
		||||
 | 
			
		||||
/** Default iSCSI maximum burst length */
 | 
			
		||||
#define ISCSI_MAX_BURST_LEN 262144
 | 
			
		||||
 | 
			
		||||
/** Default iSCSI maximum receive data segment length */
 | 
			
		||||
#define ISCSI_MAX_RECV_DATA_SEG_LEN 8192
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * iSCSI segment lengths
 | 
			
		||||
 *
 | 
			
		||||
@ -577,6 +586,9 @@ struct iscsi_session {
 | 
			
		||||
	/** CHAP response (used for both initiator and target auth) */
 | 
			
		||||
	struct chap_response chap;
 | 
			
		||||
 | 
			
		||||
	/** Maximum burst length */
 | 
			
		||||
	size_t max_burst_len;
 | 
			
		||||
 | 
			
		||||
	/** Initiator session ID (IANA format) qualifier
 | 
			
		||||
	 *
 | 
			
		||||
	 * This is part of the ISID.  It is generated randomly
 | 
			
		||||
 | 
			
		||||
@ -1,34 +0,0 @@
 | 
			
		||||
#ifndef _IPXE_LINUX_ENTROPY_H
 | 
			
		||||
#define _IPXE_LINUX_ENTROPY_H
 | 
			
		||||
 | 
			
		||||
/** @file
 | 
			
		||||
 *
 | 
			
		||||
 * /dev/random-based entropy source
 | 
			
		||||
 *
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
 | 
			
		||||
 | 
			
		||||
#ifdef ENTROPY_LINUX
 | 
			
		||||
#define ENTROPY_PREFIX_linux
 | 
			
		||||
#else
 | 
			
		||||
#define ENTROPY_PREFIX_linux __linux_
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * min-entropy per sample
 | 
			
		||||
 *
 | 
			
		||||
 * @ret min_entropy	min-entropy of each sample
 | 
			
		||||
 */
 | 
			
		||||
static inline __always_inline min_entropy_t
 | 
			
		||||
ENTROPY_INLINE ( linux, min_entropy_per_sample ) ( void ) {
 | 
			
		||||
 | 
			
		||||
	/* linux_get_noise() reads a single byte from /dev/random,
 | 
			
		||||
	 * which is supposed to block until a sufficient amount of
 | 
			
		||||
	 * entropy is available.  We therefore assume that each sample
 | 
			
		||||
	 * contains exactly 8 bits of entropy.
 | 
			
		||||
	 */
 | 
			
		||||
	return MIN_ENTROPY ( 8.0 );
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#endif /* _IPXE_LINUX_ENTROPY_H */
 | 
			
		||||
							
								
								
									
										97
									
								
								src/include/ipxe/lldp.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										97
									
								
								src/include/ipxe/lldp.h
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,97 @@
 | 
			
		||||
#ifndef _IPXE_LLDP_H
 | 
			
		||||
#define _IPXE_LLDP_H
 | 
			
		||||
 | 
			
		||||
/** @file
 | 
			
		||||
 *
 | 
			
		||||
 * Link Layer Discovery Protocol
 | 
			
		||||
 *
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
 | 
			
		||||
 | 
			
		||||
#include <stdint.h>
 | 
			
		||||
 | 
			
		||||
/** An LLDP TLV header */
 | 
			
		||||
struct lldp_tlv {
 | 
			
		||||
	/** Type and length */
 | 
			
		||||
	uint16_t type_len;
 | 
			
		||||
	/** Data */
 | 
			
		||||
	uint8_t data[0];
 | 
			
		||||
} __attribute__ (( packed ));
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Extract LLDP TLV type
 | 
			
		||||
 *
 | 
			
		||||
 * @v type_len		Type and length
 | 
			
		||||
 * @ret type		Type
 | 
			
		||||
 */
 | 
			
		||||
#define LLDP_TLV_TYPE( type_len ) ( (type_len) >> 9 )
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Extract LLDP TLV length
 | 
			
		||||
 *
 | 
			
		||||
 * @v type_len		Type and length
 | 
			
		||||
 * @ret len		Length
 | 
			
		||||
 */
 | 
			
		||||
#define LLDP_TLV_LEN( type_len ) ( (type_len) & 0x01ff )
 | 
			
		||||
 | 
			
		||||
/** End of LLDP data unit */
 | 
			
		||||
#define LLDP_TYPE_END 0x00
 | 
			
		||||
 | 
			
		||||
/** LLDP settings block name */
 | 
			
		||||
#define LLDP_SETTINGS_NAME "lldp"
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Construct LLDP setting tag
 | 
			
		||||
 *
 | 
			
		||||
 * LLDP settings are encoded as
 | 
			
		||||
 *
 | 
			
		||||
 *   ${netX.lldp/<prefix>.<type>.<index>.<offset>.<length>}
 | 
			
		||||
 *
 | 
			
		||||
 * where
 | 
			
		||||
 *
 | 
			
		||||
 *   <type> is the TLV type
 | 
			
		||||
 *
 | 
			
		||||
 *   <offset> is the starting offset within the TLV value
 | 
			
		||||
 *
 | 
			
		||||
 *   <length> is the length (or zero to read the from <offset> to the end)
 | 
			
		||||
 *
 | 
			
		||||
 *   <prefix>, if it has a non-zero value, is the subtype byte string
 | 
			
		||||
 *   of length <offset> to match at the start of the TLV value, up to
 | 
			
		||||
 *   a maximum matched length of 4 bytes
 | 
			
		||||
 *
 | 
			
		||||
 *   <index> is the index of the entry matching <type> and <prefix> to
 | 
			
		||||
 *   be accessed, with zero indicating the first matching entry
 | 
			
		||||
 *
 | 
			
		||||
 * The <prefix> is designed to accommodate both matching of the OUI
 | 
			
		||||
 * within an organization-specific TLV (e.g. 0x0080c2 for IEEE 802.1
 | 
			
		||||
 * TLVs) and of a subtype byte as found within many TLVs.
 | 
			
		||||
 *
 | 
			
		||||
 * This encoding allows most LLDP values to be extracted easily.  For
 | 
			
		||||
 * example
 | 
			
		||||
 *
 | 
			
		||||
 *   System name: ${netX.lldp/5.0.0.0:string}
 | 
			
		||||
 *
 | 
			
		||||
 *   System description: ${netX.lldp/6.0.0.0:string}
 | 
			
		||||
 *
 | 
			
		||||
 *   Port description: ${netX.lldp/4.0.0.0:string}
 | 
			
		||||
 *
 | 
			
		||||
 *   Port interface name: ${netX.lldp/5.2.0.1.0:string}
 | 
			
		||||
 *
 | 
			
		||||
 *   Chassis MAC address: ${netX.lldp/4.1.0.1.0:hex}
 | 
			
		||||
 *
 | 
			
		||||
 *   Management IPv4 address: ${netX.lldp/5.1.8.0.2.4:ipv4}
 | 
			
		||||
 *
 | 
			
		||||
 *   Port VLAN ID: ${netX.lldp/0x0080c2.1.127.0.4.2:int16}
 | 
			
		||||
 *
 | 
			
		||||
 *   Port VLAN name: ${netX.lldp/0x0080c2.3.127.0.7.0:string}
 | 
			
		||||
 *
 | 
			
		||||
 *   Maximum frame size: ${netX.lldp/0x00120f.4.127.0.4.2:uint16}
 | 
			
		||||
 *
 | 
			
		||||
 */
 | 
			
		||||
#define LLDP_TAG( prefix, type, index, offset, length )			\
 | 
			
		||||
	( ( ( ( uint64_t ) (prefix) ) << 32 ) |				\
 | 
			
		||||
	  ( (type) << 24 ) | ( (index) << 16 ) |			\
 | 
			
		||||
	  ( (offset) << 8 ) | ( (length) << 0 ) )
 | 
			
		||||
 | 
			
		||||
#endif /* _IPXE_LLDP_H */
 | 
			
		||||
							
								
								
									
										76
									
								
								src/include/ipxe/nonxen.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										76
									
								
								src/include/ipxe/nonxen.h
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,76 @@
 | 
			
		||||
#ifndef _IPXE_NONXEN_H
 | 
			
		||||
#define _IPXE_NONXEN_H
 | 
			
		||||
 | 
			
		||||
/** @file
 | 
			
		||||
 *
 | 
			
		||||
 * Stub Xen definitions for platforms with no Xen support
 | 
			
		||||
 *
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
 | 
			
		||||
 | 
			
		||||
#define __XEN_GUEST_HANDLE(name)        __guest_handle_ ## name
 | 
			
		||||
 | 
			
		||||
#define XEN_GUEST_HANDLE(name)          __XEN_GUEST_HANDLE(name)
 | 
			
		||||
 | 
			
		||||
#define ___DEFINE_XEN_GUEST_HANDLE(name, type)	\
 | 
			
		||||
	typedef type * __XEN_GUEST_HANDLE(name)
 | 
			
		||||
 | 
			
		||||
#define __DEFINE_XEN_GUEST_HANDLE(name, type)			\
 | 
			
		||||
	___DEFINE_XEN_GUEST_HANDLE(name, type);			\
 | 
			
		||||
	___DEFINE_XEN_GUEST_HANDLE(const_##name, const type)
 | 
			
		||||
 | 
			
		||||
#define DEFINE_XEN_GUEST_HANDLE(name)   __DEFINE_XEN_GUEST_HANDLE(name, name)
 | 
			
		||||
 | 
			
		||||
typedef unsigned long xen_pfn_t;
 | 
			
		||||
 | 
			
		||||
typedef unsigned long xen_ulong_t;
 | 
			
		||||
 | 
			
		||||
struct arch_vcpu_info {};
 | 
			
		||||
 | 
			
		||||
struct arch_shared_info {};
 | 
			
		||||
 | 
			
		||||
#define XEN_LEGACY_MAX_VCPUS 0
 | 
			
		||||
 | 
			
		||||
struct xen_hypervisor;
 | 
			
		||||
 | 
			
		||||
static inline __attribute__ (( always_inline )) unsigned long
 | 
			
		||||
xen_hypercall_1 ( struct xen_hypervisor *xen __unused,
 | 
			
		||||
		  unsigned int hypercall __unused,
 | 
			
		||||
		  unsigned long arg1 __unused ) {
 | 
			
		||||
	return 1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline __attribute__ (( always_inline )) unsigned long
 | 
			
		||||
xen_hypercall_2 ( struct xen_hypervisor *xen __unused,
 | 
			
		||||
		  unsigned int hypercall __unused,
 | 
			
		||||
		  unsigned long arg1 __unused, unsigned long arg2 __unused ) {
 | 
			
		||||
	return 1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline __attribute__ (( always_inline )) unsigned long
 | 
			
		||||
xen_hypercall_3 ( struct xen_hypervisor *xen __unused,
 | 
			
		||||
		  unsigned int hypercall __unused,
 | 
			
		||||
		  unsigned long arg1 __unused, unsigned long arg2 __unused,
 | 
			
		||||
		  unsigned long arg3 __unused ) {
 | 
			
		||||
	return 1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline __attribute__ (( always_inline )) unsigned long
 | 
			
		||||
xen_hypercall_4 ( struct xen_hypervisor *xen __unused,
 | 
			
		||||
		  unsigned int hypercall __unused,
 | 
			
		||||
		  unsigned long arg1 __unused, unsigned long arg2 __unused,
 | 
			
		||||
		  unsigned long arg3 __unused, unsigned long arg4 __unused ) {
 | 
			
		||||
	return 1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline __attribute__ (( always_inline )) unsigned long
 | 
			
		||||
xen_hypercall_5 ( struct xen_hypervisor *xen __unused,
 | 
			
		||||
		  unsigned int hypercall __unused,
 | 
			
		||||
		  unsigned long arg1 __unused, unsigned long arg2 __unused,
 | 
			
		||||
		  unsigned long arg3 __unused, unsigned long arg4 __unused,
 | 
			
		||||
		  unsigned long arg5 __unused ) {
 | 
			
		||||
	return 1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#endif /* _IPXE_NONXEN_H */
 | 
			
		||||
@ -1,52 +0,0 @@
 | 
			
		||||
#ifndef _IPXE_NULL_ENTROPY_H
 | 
			
		||||
#define _IPXE_NULL_ENTROPY_H
 | 
			
		||||
 | 
			
		||||
/** @file
 | 
			
		||||
 *
 | 
			
		||||
 * Nonexistent entropy source
 | 
			
		||||
 *
 | 
			
		||||
 * This source provides no entropy and must NOT be used in a
 | 
			
		||||
 * security-sensitive environment.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
 | 
			
		||||
 | 
			
		||||
#include <stdint.h>
 | 
			
		||||
 | 
			
		||||
#ifdef ENTROPY_NULL
 | 
			
		||||
#define ENTROPY_PREFIX_null
 | 
			
		||||
#else
 | 
			
		||||
#define ENTROPY_PREFIX_null __null_
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
static inline __always_inline int
 | 
			
		||||
ENTROPY_INLINE ( null, entropy_enable ) ( void ) {
 | 
			
		||||
	/* Do nothing */
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline __always_inline void
 | 
			
		||||
ENTROPY_INLINE ( null, entropy_disable ) ( void ) {
 | 
			
		||||
	/* Do nothing */
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline __always_inline min_entropy_t
 | 
			
		||||
ENTROPY_INLINE ( null, min_entropy_per_sample ) ( void ) {
 | 
			
		||||
	/* Actual amount of min-entropy is zero.  To avoid
 | 
			
		||||
	 * division-by-zero errors and to allow compilation of
 | 
			
		||||
	 * entropy-consuming code, pretend to have 1 bit of entropy in
 | 
			
		||||
	 * each sample.
 | 
			
		||||
	 */
 | 
			
		||||
	return MIN_ENTROPY ( 1.0 );
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline __always_inline int
 | 
			
		||||
ENTROPY_INLINE ( null, get_noise ) ( noise_sample_t *noise ) {
 | 
			
		||||
 | 
			
		||||
	/* All sample values are constant */
 | 
			
		||||
	*noise = 0x01;
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#endif /* _IPXE_NULL_ENTROPY_H */
 | 
			
		||||
@ -3,7 +3,7 @@
 | 
			
		||||
 | 
			
		||||
/** @file
 | 
			
		||||
 *
 | 
			
		||||
 * Form parameters
 | 
			
		||||
 * Request parameters
 | 
			
		||||
 *
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
@ -12,7 +12,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
 | 
			
		||||
#include <ipxe/list.h>
 | 
			
		||||
#include <ipxe/refcnt.h>
 | 
			
		||||
 | 
			
		||||
/** A form parameter list */
 | 
			
		||||
/** A request parameter list */
 | 
			
		||||
struct parameters {
 | 
			
		||||
	/** Reference count */
 | 
			
		||||
	struct refcnt refcnt;
 | 
			
		||||
@ -24,18 +24,26 @@ struct parameters {
 | 
			
		||||
	struct list_head entries;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/** A form parameter */
 | 
			
		||||
/** A request parameter */
 | 
			
		||||
struct parameter {
 | 
			
		||||
	/** List of form parameters */
 | 
			
		||||
	/** List of request parameters */
 | 
			
		||||
	struct list_head list;
 | 
			
		||||
	/** Key */
 | 
			
		||||
	const char *key;
 | 
			
		||||
	/** Value */
 | 
			
		||||
	const char *value;
 | 
			
		||||
	/** Flags */
 | 
			
		||||
	unsigned int flags;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/** Request parameter is a form parameter */
 | 
			
		||||
#define PARAMETER_FORM 0x0001
 | 
			
		||||
 | 
			
		||||
/** Request parameter is a header parameter */
 | 
			
		||||
#define PARAMETER_HEADER 0x0002
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Increment form parameter list reference count
 | 
			
		||||
 * Increment request parameter list reference count
 | 
			
		||||
 *
 | 
			
		||||
 * @v params		Parameter list, or NULL
 | 
			
		||||
 * @ret params		Parameter list as passed in
 | 
			
		||||
@ -47,7 +55,7 @@ params_get ( struct parameters *params ) {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Decrement form parameter list reference count
 | 
			
		||||
 * Decrement request parameter list reference count
 | 
			
		||||
 *
 | 
			
		||||
 * @v params		Parameter list, or NULL
 | 
			
		||||
 */
 | 
			
		||||
@ -57,7 +65,7 @@ params_put ( struct parameters *params ) {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Claim ownership of form parameter list
 | 
			
		||||
 * Claim ownership of request parameter list
 | 
			
		||||
 *
 | 
			
		||||
 * @v params		Parameter list
 | 
			
		||||
 * @ret params		Parameter list
 | 
			
		||||
@ -71,13 +79,14 @@ claim_parameters ( struct parameters *params ) {
 | 
			
		||||
	return params;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/** Iterate over all form parameters in a list */
 | 
			
		||||
/** Iterate over all request parameters in a list */
 | 
			
		||||
#define for_each_param( param, params )				\
 | 
			
		||||
	list_for_each_entry ( (param), &(params)->entries, list )
 | 
			
		||||
 | 
			
		||||
extern struct parameters * find_parameters ( const char *name );
 | 
			
		||||
extern struct parameters * create_parameters ( const char *name );
 | 
			
		||||
extern struct parameter * add_parameter ( struct parameters *params,
 | 
			
		||||
					  const char *key, const char *value );
 | 
			
		||||
					  const char *key, const char *value,
 | 
			
		||||
					  unsigned int flags );
 | 
			
		||||
 | 
			
		||||
#endif /* _IPXE_PARAMS_H */
 | 
			
		||||
 | 
			
		||||
@ -383,9 +383,9 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
 | 
			
		||||
 *
 | 
			
		||||
 */
 | 
			
		||||
#define for_each_table_entry( pointer, table )				\
 | 
			
		||||
	for ( pointer = table_start ( table ) ;				\
 | 
			
		||||
	      pointer < table_end ( table ) ;				\
 | 
			
		||||
	      pointer++ )
 | 
			
		||||
	for ( (pointer) = table_start ( table ) ;			\
 | 
			
		||||
	      (pointer) < table_end ( table ) ;				\
 | 
			
		||||
	      (pointer)++ )
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Iterate through all remaining entries within a linker table
 | 
			
		||||
@ -412,9 +412,9 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
 | 
			
		||||
 *
 | 
			
		||||
 */
 | 
			
		||||
#define for_each_table_entry_continue( pointer, table )			\
 | 
			
		||||
	for ( pointer++ ;						\
 | 
			
		||||
	      pointer < table_end ( table ) ;				\
 | 
			
		||||
	      pointer++ )
 | 
			
		||||
	for ( (pointer)++ ;						\
 | 
			
		||||
	      (pointer) < table_end ( table ) ;				\
 | 
			
		||||
	      (pointer)++ )
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Iterate through all entries within a linker table in reverse order
 | 
			
		||||
@ -438,9 +438,9 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
 | 
			
		||||
 *
 | 
			
		||||
 */
 | 
			
		||||
#define for_each_table_entry_reverse( pointer, table )			\
 | 
			
		||||
	for ( pointer = ( table_end ( table ) - 1 ) ;			\
 | 
			
		||||
	      pointer >= table_start ( table ) ;			\
 | 
			
		||||
	      pointer-- )
 | 
			
		||||
	for ( (pointer) = ( table_end ( table ) - 1 ) ;			\
 | 
			
		||||
	      (pointer) >= table_start ( table ) ;			\
 | 
			
		||||
	      (pointer)-- )
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Iterate through all remaining entries within a linker table in reverse order
 | 
			
		||||
@ -467,8 +467,8 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
 | 
			
		||||
 *
 | 
			
		||||
 */
 | 
			
		||||
#define for_each_table_entry_continue_reverse( pointer, table )		\
 | 
			
		||||
	for ( pointer-- ;						\
 | 
			
		||||
	      pointer >= table_start ( table ) ;			\
 | 
			
		||||
	      pointer-- )
 | 
			
		||||
	for ( (pointer)-- ;						\
 | 
			
		||||
	      (pointer) >= table_start ( table ) ;			\
 | 
			
		||||
	      (pointer)-- )
 | 
			
		||||
 | 
			
		||||
#endif /* _IPXE_TABLES_H */
 | 
			
		||||
 | 
			
		||||
@ -84,7 +84,7 @@ struct uri {
 | 
			
		||||
	const char *equery;
 | 
			
		||||
	/** Fragment (with original URI encoding) */
 | 
			
		||||
	const char *efragment;
 | 
			
		||||
	/** Form parameters */
 | 
			
		||||
	/** Request parameters */
 | 
			
		||||
	struct parameters *params;
 | 
			
		||||
} __attribute__ (( packed ));
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -59,6 +59,10 @@ sub try_import_file {
 | 
			
		||||
    if ( /^\#include\s+[<\"](\S+)[>\"]/ ) {
 | 
			
		||||
      push @dependencies, catfile ( $subdir, $1 );
 | 
			
		||||
    }
 | 
			
		||||
    # Patch "Unsupported architecture" line
 | 
			
		||||
    if ( /^\#error\s+"Unsupported\sarchitecture"/ ) {
 | 
			
		||||
      $_ = "#include <bits/xen.h>"
 | 
			
		||||
    }
 | 
			
		||||
    # Write out line
 | 
			
		||||
    print $outfh "$_\n";
 | 
			
		||||
    # Apply FILE_LICENCE() immediately after include guard
 | 
			
		||||
 | 
			
		||||
@ -19,7 +19,7 @@ FILE_LICENCE ( MIT );
 | 
			
		||||
#elif defined(__arm__) || defined (__aarch64__)
 | 
			
		||||
#include "arch-arm.h"
 | 
			
		||||
#else
 | 
			
		||||
#error "Unsupported architecture"
 | 
			
		||||
#include <bits/xen.h>
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#ifndef __ASSEMBLY__
 | 
			
		||||
 | 
			
		||||
@ -25,10 +25,8 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
 | 
			
		||||
 | 
			
		||||
#include <errno.h>
 | 
			
		||||
#include <ipxe/entropy.h>
 | 
			
		||||
#include <ipxe/crc32.h>
 | 
			
		||||
#include <ipxe/profile.h>
 | 
			
		||||
#include <ipxe/efi/efi.h>
 | 
			
		||||
#include <ipxe/efi/Protocol/Rng.h>
 | 
			
		||||
 | 
			
		||||
/** @file
 | 
			
		||||
 *
 | 
			
		||||
@ -36,22 +34,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
 | 
			
		||||
 *
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
/** Random number generator protocol */
 | 
			
		||||
static EFI_RNG_PROTOCOL *efirng;
 | 
			
		||||
EFI_REQUEST_PROTOCOL ( EFI_RNG_PROTOCOL, &efirng );
 | 
			
		||||
 | 
			
		||||
/** Minimum number of bytes to request from RNG
 | 
			
		||||
 *
 | 
			
		||||
 * The UEFI spec states (for no apparently good reason) that "When a
 | 
			
		||||
 * Deterministic Random Bit Generator (DRBG) is used on the output of
 | 
			
		||||
 * a (raw) entropy source, its security level must be at least 256
 | 
			
		||||
 * bits."  The EDK2 codebase (mis)interprets this to mean that the
 | 
			
		||||
 * call to GetRNG() should fail if given a buffer less than 32 bytes.
 | 
			
		||||
 *
 | 
			
		||||
 * Incidentally, nothing in the EFI RNG protocol provides any way to
 | 
			
		||||
 * report the actual amount of entropy returned by GetRNG().
 | 
			
		||||
 */
 | 
			
		||||
#define EFI_ENTROPY_RNG_LEN 32
 | 
			
		||||
struct entropy_source efitick_entropy __entropy_source ( ENTROPY_FALLBACK );
 | 
			
		||||
 | 
			
		||||
/** Time (in 100ns units) to delay waiting for timer tick
 | 
			
		||||
 *
 | 
			
		||||
@ -76,9 +59,6 @@ static int efi_entropy_enable ( void ) {
 | 
			
		||||
	EFI_STATUS efirc;
 | 
			
		||||
	int rc;
 | 
			
		||||
 | 
			
		||||
	DBGC ( &tick, "ENTROPY %s RNG protocol\n",
 | 
			
		||||
	       ( efirng ? "has" : "has no" ) );
 | 
			
		||||
 | 
			
		||||
	/* Drop to external TPL to allow timer tick event to take place */
 | 
			
		||||
	bs->RestoreTPL ( efi_external_tpl );
 | 
			
		||||
 | 
			
		||||
@ -91,6 +71,12 @@ static int efi_entropy_enable ( void ) {
 | 
			
		||||
		return rc;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* We use essentially the same mechanism as for the BIOS
 | 
			
		||||
	 * RTC-based entropy source, and so assume the same
 | 
			
		||||
	 * min-entropy per sample.
 | 
			
		||||
	 */
 | 
			
		||||
	entropy_init ( &efitick_entropy, MIN_ENTROPY ( 1.3 ) );
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -147,7 +133,7 @@ static int efi_entropy_tick ( void ) {
 | 
			
		||||
 * @ret noise		Noise sample
 | 
			
		||||
 * @ret rc		Return status code
 | 
			
		||||
 */
 | 
			
		||||
static int efi_get_noise_ticks ( noise_sample_t *noise ) {
 | 
			
		||||
static int efi_get_noise ( noise_sample_t *noise ) {
 | 
			
		||||
	int before;
 | 
			
		||||
	int after;
 | 
			
		||||
	int rc;
 | 
			
		||||
@ -172,70 +158,10 @@ static int efi_get_noise_ticks ( noise_sample_t *noise ) {
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Get noise sample from RNG protocol
 | 
			
		||||
 *
 | 
			
		||||
 * @ret noise		Noise sample
 | 
			
		||||
 * @ret rc		Return status code
 | 
			
		||||
 */
 | 
			
		||||
static int efi_get_noise_rng ( noise_sample_t *noise ) {
 | 
			
		||||
	static uint8_t prev[EFI_ENTROPY_RNG_LEN];
 | 
			
		||||
	uint8_t buf[EFI_ENTROPY_RNG_LEN];
 | 
			
		||||
	EFI_STATUS efirc;
 | 
			
		||||
	int rc;
 | 
			
		||||
 | 
			
		||||
	/* Fail if we have no EFI RNG protocol */
 | 
			
		||||
	if ( ! efirng )
 | 
			
		||||
		return -ENOTSUP;
 | 
			
		||||
 | 
			
		||||
	/* Get the minimum allowed number of random bytes */
 | 
			
		||||
	if ( ( efirc = efirng->GetRNG ( efirng, NULL, EFI_ENTROPY_RNG_LEN,
 | 
			
		||||
					buf ) ) != 0 ) {
 | 
			
		||||
		rc = -EEFI ( efirc );
 | 
			
		||||
		DBGC ( &tick, "ENTROPY could not read from RNG: %s\n",
 | 
			
		||||
		       strerror ( rc ) );
 | 
			
		||||
		return rc;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* Fail (and permanently disable the EFI RNG) if we get
 | 
			
		||||
	 * consecutive identical results.
 | 
			
		||||
	 */
 | 
			
		||||
	if ( memcmp ( buf, prev, sizeof ( buf ) ) == 0 ) {
 | 
			
		||||
		DBGC ( &tick, "ENTROPY detected broken EFI RNG:\n" );
 | 
			
		||||
		DBGC_HDA ( &tick, 0, buf, sizeof ( buf ) );
 | 
			
		||||
		efirng = NULL;
 | 
			
		||||
		return -EIO;
 | 
			
		||||
	}
 | 
			
		||||
	memcpy ( prev, buf, sizeof ( prev ) );
 | 
			
		||||
 | 
			
		||||
	/* Reduce random bytes to a single noise sample.  This seems
 | 
			
		||||
	 * like overkill, but we have no way of knowing how much
 | 
			
		||||
	 * entropy is actually present in the bytes returned by the
 | 
			
		||||
	 * RNG protocol.
 | 
			
		||||
	 */
 | 
			
		||||
	*noise = crc32_le ( 0, buf, sizeof ( buf ) );
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Get noise sample
 | 
			
		||||
 *
 | 
			
		||||
 * @ret noise		Noise sample
 | 
			
		||||
 * @ret rc		Return status code
 | 
			
		||||
 */
 | 
			
		||||
static int efi_get_noise ( noise_sample_t *noise ) {
 | 
			
		||||
	int rc;
 | 
			
		||||
 | 
			
		||||
	/* Try RNG first, falling back to timer ticks */
 | 
			
		||||
	if ( ( ( rc = efi_get_noise_rng ( noise ) ) != 0 ) &&
 | 
			
		||||
	     ( ( rc = efi_get_noise_ticks ( noise ) ) != 0 ) )
 | 
			
		||||
		return rc;
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
PROVIDE_ENTROPY_INLINE ( efi, min_entropy_per_sample );
 | 
			
		||||
PROVIDE_ENTROPY ( efi, entropy_enable, efi_entropy_enable );
 | 
			
		||||
PROVIDE_ENTROPY ( efi, entropy_disable, efi_entropy_disable );
 | 
			
		||||
PROVIDE_ENTROPY ( efi, get_noise, efi_get_noise );
 | 
			
		||||
/** EFI entropy source */
 | 
			
		||||
struct entropy_source efitick_entropy __entropy_source ( ENTROPY_FALLBACK ) = {
 | 
			
		||||
	.name = "efitick",
 | 
			
		||||
	.enable = efi_entropy_enable,
 | 
			
		||||
	.disable = efi_entropy_disable,
 | 
			
		||||
	.get_noise = efi_get_noise,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
@ -43,14 +43,21 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
 | 
			
		||||
#include <ipxe/efi/Protocol/SimpleFileSystem.h>
 | 
			
		||||
#include <ipxe/efi/Protocol/BlockIo.h>
 | 
			
		||||
#include <ipxe/efi/Protocol/DiskIo.h>
 | 
			
		||||
#include <ipxe/efi/Protocol/LoadFile2.h>
 | 
			
		||||
#include <ipxe/efi/Guid/FileInfo.h>
 | 
			
		||||
#include <ipxe/efi/Guid/FileSystemInfo.h>
 | 
			
		||||
#include <ipxe/efi/efi_strings.h>
 | 
			
		||||
#include <ipxe/efi/efi_path.h>
 | 
			
		||||
#include <ipxe/efi/efi_file.h>
 | 
			
		||||
 | 
			
		||||
/** EFI media ID */
 | 
			
		||||
#define EFI_MEDIA_ID_MAGIC 0x69505845
 | 
			
		||||
 | 
			
		||||
/** Linux initrd fixed device path vendor GUID */
 | 
			
		||||
#define LINUX_INITRD_VENDOR_GUID					\
 | 
			
		||||
	{ 0x5568e427, 0x68fc, 0x4f3d,					\
 | 
			
		||||
	  { 0xac, 0x74, 0xca, 0x55, 0x52, 0x31, 0xcc, 0x68 } }
 | 
			
		||||
 | 
			
		||||
/** An EFI virtual file reader */
 | 
			
		||||
struct efi_file_reader {
 | 
			
		||||
	/** EFI file */
 | 
			
		||||
@ -69,6 +76,8 @@ struct efi_file {
 | 
			
		||||
	struct refcnt refcnt;
 | 
			
		||||
	/** EFI file protocol */
 | 
			
		||||
	EFI_FILE_PROTOCOL file;
 | 
			
		||||
	/** EFI load file protocol */
 | 
			
		||||
	EFI_LOAD_FILE2_PROTOCOL load;
 | 
			
		||||
	/** Image (if any) */
 | 
			
		||||
	struct image *image;
 | 
			
		||||
	/** Filename */
 | 
			
		||||
@ -370,6 +379,8 @@ efi_file_open ( EFI_FILE_PROTOCOL *this, EFI_FILE_PROTOCOL **new,
 | 
			
		||||
	ref_init ( &file->refcnt, efi_file_free );
 | 
			
		||||
	memcpy ( &new_file->file, &efi_file_root.file,
 | 
			
		||||
		 sizeof ( new_file->file ) );
 | 
			
		||||
	memcpy ( &new_file->load, &efi_file_root.load,
 | 
			
		||||
		 sizeof ( new_file->load ) );
 | 
			
		||||
	efi_file_image ( new_file, image_get ( image ) );
 | 
			
		||||
	*new = &new_file->file;
 | 
			
		||||
	DBGC ( new_file, "EFIFILE %s opened\n", efi_file_name ( new_file ) );
 | 
			
		||||
@ -528,7 +539,7 @@ static EFI_STATUS EFIAPI efi_file_read ( EFI_FILE_PROTOCOL *this,
 | 
			
		||||
 | 
			
		||||
	/* Read from the file */
 | 
			
		||||
	DBGC ( file, "EFIFILE %s read [%#08zx,%#08zx)\n",
 | 
			
		||||
	       efi_file_name ( file ), pos, file->pos );
 | 
			
		||||
	       efi_file_name ( file ), pos, ( ( size_t ) ( pos + *len ) ) );
 | 
			
		||||
	*len = file->read ( &reader );
 | 
			
		||||
	assert ( ( pos + *len ) == file->pos );
 | 
			
		||||
 | 
			
		||||
@ -684,6 +695,44 @@ static EFI_STATUS EFIAPI efi_file_flush ( EFI_FILE_PROTOCOL *this ) {
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Load file
 | 
			
		||||
 *
 | 
			
		||||
 * @v this		EFI file loader
 | 
			
		||||
 * @v path		File path
 | 
			
		||||
 * @v boot		Boot policy
 | 
			
		||||
 * @v len		Buffer size
 | 
			
		||||
 * @v data		Buffer, or NULL
 | 
			
		||||
 * @ret efirc		EFI status code
 | 
			
		||||
 */
 | 
			
		||||
static EFI_STATUS EFIAPI efi_file_load ( EFI_LOAD_FILE2_PROTOCOL *this,
 | 
			
		||||
					 EFI_DEVICE_PATH_PROTOCOL *path __unused,
 | 
			
		||||
					 BOOLEAN boot __unused, UINTN *len,
 | 
			
		||||
					 VOID *data ) {
 | 
			
		||||
	struct efi_file *file = container_of ( this, struct efi_file, load );
 | 
			
		||||
	size_t max_len;
 | 
			
		||||
	size_t file_len;
 | 
			
		||||
	EFI_STATUS efirc;
 | 
			
		||||
 | 
			
		||||
	/* Calculate maximum length */
 | 
			
		||||
	max_len = ( data ? *len : 0 );
 | 
			
		||||
	DBGC ( file, "EFIFILE %s load at %p+%#zx\n",
 | 
			
		||||
	       efi_file_name ( file ), data, max_len );
 | 
			
		||||
 | 
			
		||||
	/* Check buffer size */
 | 
			
		||||
	file_len = efi_file_len ( file );
 | 
			
		||||
	if ( file_len > max_len ) {
 | 
			
		||||
		*len = file_len;
 | 
			
		||||
		return EFI_BUFFER_TOO_SMALL;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* Read from file */
 | 
			
		||||
	if ( ( efirc = efi_file_read ( &file->file, len, data ) ) != 0 )
 | 
			
		||||
		return efirc;
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/** Root directory */
 | 
			
		||||
static struct efi_file efi_file_root = {
 | 
			
		||||
	.refcnt = REF_INIT ( ref_no_free ),
 | 
			
		||||
@ -700,6 +749,9 @@ static struct efi_file efi_file_root = {
 | 
			
		||||
		.SetInfo = efi_file_set_info,
 | 
			
		||||
		.Flush = efi_file_flush,
 | 
			
		||||
	},
 | 
			
		||||
	.load = {
 | 
			
		||||
		.LoadFile = efi_file_load,
 | 
			
		||||
	},
 | 
			
		||||
	.image = NULL,
 | 
			
		||||
	.name = "",
 | 
			
		||||
};
 | 
			
		||||
@ -720,11 +772,34 @@ static struct efi_file efi_file_initrd = {
 | 
			
		||||
		.SetInfo = efi_file_set_info,
 | 
			
		||||
		.Flush = efi_file_flush,
 | 
			
		||||
	},
 | 
			
		||||
	.load = {
 | 
			
		||||
		.LoadFile = efi_file_load,
 | 
			
		||||
	},
 | 
			
		||||
	.image = NULL,
 | 
			
		||||
	.name = "initrd.magic",
 | 
			
		||||
	.read = efi_file_read_initrd,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/** Linux initrd fixed device path */
 | 
			
		||||
static struct {
 | 
			
		||||
	VENDOR_DEVICE_PATH vendor;
 | 
			
		||||
	EFI_DEVICE_PATH_PROTOCOL end;
 | 
			
		||||
} __attribute__ (( packed )) efi_file_initrd_path = {
 | 
			
		||||
	.vendor = {
 | 
			
		||||
		.Header = {
 | 
			
		||||
			.Type = MEDIA_DEVICE_PATH,
 | 
			
		||||
			.SubType = MEDIA_VENDOR_DP,
 | 
			
		||||
			.Length[0] = sizeof ( efi_file_initrd_path.vendor ),
 | 
			
		||||
		},
 | 
			
		||||
		.Guid = LINUX_INITRD_VENDOR_GUID,
 | 
			
		||||
	},
 | 
			
		||||
	.end = {
 | 
			
		||||
		.Type = END_DEVICE_PATH_TYPE,
 | 
			
		||||
		.SubType = END_ENTIRE_DEVICE_PATH_SUBTYPE,
 | 
			
		||||
		.Length[0] = sizeof ( efi_file_initrd_path.end ),
 | 
			
		||||
	},
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Open root directory
 | 
			
		||||
 *
 | 
			
		||||
@ -833,6 +908,110 @@ static EFI_DISK_IO_PROTOCOL efi_disk_io_protocol = {
 | 
			
		||||
	.WriteDisk = efi_disk_io_write_disk,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * (Re)install fixed device path file
 | 
			
		||||
 *
 | 
			
		||||
 * @v path		Device path
 | 
			
		||||
 * @v load		Load file protocol, or NULL to uninstall protocol
 | 
			
		||||
 * @ret rc		Return status code
 | 
			
		||||
 *
 | 
			
		||||
 * Linux 5.7 added the ability to autodetect an initrd by searching
 | 
			
		||||
 * for a handle via a fixed vendor-specific "Linux initrd device path"
 | 
			
		||||
 * and then locating and using the EFI_LOAD_FILE2_PROTOCOL instance on
 | 
			
		||||
 * that handle.
 | 
			
		||||
 *
 | 
			
		||||
 * The design choice in Linux of using a single fixed device path
 | 
			
		||||
 * makes this unfortunately messy to support, since device paths must
 | 
			
		||||
 * be unique within a system.  When multiple bootloaders are used
 | 
			
		||||
 * (e.g. GRUB loading iPXE loading Linux) then only one bootloader can
 | 
			
		||||
 * ever install the device path onto a handle.  Subsequent bootloaders
 | 
			
		||||
 * must locate the existing handle and replace the load file protocol
 | 
			
		||||
 * instance with their own.
 | 
			
		||||
 */
 | 
			
		||||
static int efi_file_path_install ( EFI_DEVICE_PATH_PROTOCOL *path,
 | 
			
		||||
				   EFI_LOAD_FILE2_PROTOCOL *load ) {
 | 
			
		||||
	EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
 | 
			
		||||
	EFI_DEVICE_PATH_PROTOCOL *end;
 | 
			
		||||
	EFI_HANDLE handle;
 | 
			
		||||
	VOID *path_copy;
 | 
			
		||||
	VOID *old;
 | 
			
		||||
	size_t path_len;
 | 
			
		||||
	EFI_STATUS efirc;
 | 
			
		||||
	int rc;
 | 
			
		||||
 | 
			
		||||
	/* Locate or install the handle with this device path */
 | 
			
		||||
	end = path;
 | 
			
		||||
	if ( ( ( efirc = bs->LocateDevicePath ( &efi_device_path_protocol_guid,
 | 
			
		||||
						&end, &handle ) ) == 0 ) &&
 | 
			
		||||
	     ( end->Type == END_DEVICE_PATH_TYPE ) ) {
 | 
			
		||||
 | 
			
		||||
		/* Exact match: reuse (or uninstall from) this handle */
 | 
			
		||||
		if ( load ) {
 | 
			
		||||
			DBGC ( path, "EFIFILE %s reusing existing handle\n",
 | 
			
		||||
			       efi_devpath_text ( path ) );
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
	} else {
 | 
			
		||||
 | 
			
		||||
		/* Allocate a permanent copy of the device path, since
 | 
			
		||||
		 * this handle will survive after this binary is
 | 
			
		||||
		 * unloaded.
 | 
			
		||||
		 */
 | 
			
		||||
		path_len = ( efi_path_len ( path ) + sizeof ( *end ) );
 | 
			
		||||
		if ( ( efirc = bs->AllocatePool ( EfiBootServicesData, path_len,
 | 
			
		||||
						  &path_copy ) ) != 0 ) {
 | 
			
		||||
			rc = -EEFI ( efirc );
 | 
			
		||||
			DBGC ( path, "EFIFILE %s could not allocate device path: "
 | 
			
		||||
			       "%s\n", efi_devpath_text ( path ), strerror ( rc ) );
 | 
			
		||||
			return rc;
 | 
			
		||||
		}
 | 
			
		||||
		memcpy ( path_copy, path, path_len );
 | 
			
		||||
 | 
			
		||||
		/* Create a new handle with this device path */
 | 
			
		||||
		handle = NULL;
 | 
			
		||||
		if ( ( efirc = bs->InstallMultipleProtocolInterfaces (
 | 
			
		||||
				&handle,
 | 
			
		||||
				&efi_device_path_protocol_guid, path_copy,
 | 
			
		||||
				NULL ) ) != 0 ) {
 | 
			
		||||
			rc = -EEFI ( efirc );
 | 
			
		||||
			DBGC ( path, "EFIFILE %s could not create handle: %s\n",
 | 
			
		||||
			       efi_devpath_text ( path ), strerror ( rc ) );
 | 
			
		||||
			return rc;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* Uninstall existing load file protocol instance, if any */
 | 
			
		||||
	if ( ( ( efirc = bs->HandleProtocol ( handle, &efi_load_file2_protocol_guid,
 | 
			
		||||
					      &old ) ) == 0 ) &&
 | 
			
		||||
	     ( ( efirc = bs->UninstallMultipleProtocolInterfaces (
 | 
			
		||||
				handle,
 | 
			
		||||
				&efi_load_file2_protocol_guid, old,
 | 
			
		||||
				NULL ) ) != 0 ) ) {
 | 
			
		||||
		rc = -EEFI ( efirc );
 | 
			
		||||
		DBGC ( path, "EFIFILE %s could not uninstall %s: %s\n",
 | 
			
		||||
		       efi_devpath_text ( path ),
 | 
			
		||||
		       efi_guid_ntoa ( &efi_load_file2_protocol_guid ),
 | 
			
		||||
		       strerror ( rc ) );
 | 
			
		||||
		return rc;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* Install new load file protocol instance, if applicable */
 | 
			
		||||
	if ( ( load != NULL ) &&
 | 
			
		||||
	     ( ( efirc = bs->InstallMultipleProtocolInterfaces (
 | 
			
		||||
				&handle,
 | 
			
		||||
				&efi_load_file2_protocol_guid, load,
 | 
			
		||||
				NULL ) ) != 0 ) ) {
 | 
			
		||||
		rc = -EEFI ( efirc );
 | 
			
		||||
		DBGC ( path, "EFIFILE %s could not install %s: %s\n",
 | 
			
		||||
		       efi_devpath_text ( path ),
 | 
			
		||||
		       efi_guid_ntoa ( &efi_load_file2_protocol_guid ),
 | 
			
		||||
		       strerror ( rc ) );
 | 
			
		||||
		return rc;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Install EFI simple file system protocol
 | 
			
		||||
 *
 | 
			
		||||
@ -841,6 +1020,7 @@ static EFI_DISK_IO_PROTOCOL efi_disk_io_protocol = {
 | 
			
		||||
 */
 | 
			
		||||
int efi_file_install ( EFI_HANDLE handle ) {
 | 
			
		||||
	EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
 | 
			
		||||
	EFI_LOAD_FILE2_PROTOCOL *load;
 | 
			
		||||
	union {
 | 
			
		||||
		EFI_DISK_IO_PROTOCOL *diskio;
 | 
			
		||||
		void *interface;
 | 
			
		||||
@ -903,8 +1083,24 @@ int efi_file_install ( EFI_HANDLE handle ) {
 | 
			
		||||
	}
 | 
			
		||||
	assert ( diskio.diskio == &efi_disk_io_protocol );
 | 
			
		||||
 | 
			
		||||
	/* Install Linux initrd fixed device path file
 | 
			
		||||
	 *
 | 
			
		||||
	 * Install the device path handle unconditionally, since we
 | 
			
		||||
	 * are definitively the bootloader providing the initrd, if
 | 
			
		||||
	 * any, to the booted image.  Install the load file protocol
 | 
			
		||||
	 * instance only if the initrd is non-empty, since Linux does
 | 
			
		||||
	 * not gracefully handle a zero-length initrd.
 | 
			
		||||
	 */
 | 
			
		||||
	load = ( list_is_singular ( &images ) ? NULL : &efi_file_initrd.load );
 | 
			
		||||
	if ( ( rc = efi_file_path_install ( &efi_file_initrd_path.vendor.Header,
 | 
			
		||||
					    load ) ) != 0 ) {
 | 
			
		||||
		goto err_initrd;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
 | 
			
		||||
	efi_file_path_install ( &efi_file_initrd_path.vendor.Header, NULL );
 | 
			
		||||
 err_initrd:
 | 
			
		||||
	bs->CloseProtocol ( handle, &efi_disk_io_protocol_guid,
 | 
			
		||||
			    efi_image_handle, handle );
 | 
			
		||||
 err_open:
 | 
			
		||||
@ -930,6 +1126,9 @@ void efi_file_uninstall ( EFI_HANDLE handle ) {
 | 
			
		||||
	EFI_STATUS efirc;
 | 
			
		||||
	int rc;
 | 
			
		||||
 | 
			
		||||
	/* Uninstall Linux initrd fixed device path file */
 | 
			
		||||
	efi_file_path_install ( &efi_file_initrd_path.vendor.Header, NULL );
 | 
			
		||||
 | 
			
		||||
	/* Close our own disk I/O protocol */
 | 
			
		||||
	bs->CloseProtocol ( handle, &efi_disk_io_protocol_guid,
 | 
			
		||||
			    efi_image_handle, handle );
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										118
									
								
								src/interface/efi/efi_rng.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										118
									
								
								src/interface/efi/efi_rng.c
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,118 @@
 | 
			
		||||
/*
 | 
			
		||||
 * 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 <errno.h>
 | 
			
		||||
#include <ipxe/entropy.h>
 | 
			
		||||
#include <ipxe/crc32.h>
 | 
			
		||||
#include <ipxe/efi/efi.h>
 | 
			
		||||
#include <ipxe/efi/Protocol/Rng.h>
 | 
			
		||||
 | 
			
		||||
/** @file
 | 
			
		||||
 *
 | 
			
		||||
 * EFI random number generator protocol entropy source
 | 
			
		||||
 *
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
struct entropy_source efirng_entropy __entropy_source ( ENTROPY_NORMAL );
 | 
			
		||||
 | 
			
		||||
/** Random number generator protocol */
 | 
			
		||||
static EFI_RNG_PROTOCOL *efirng;
 | 
			
		||||
EFI_REQUEST_PROTOCOL ( EFI_RNG_PROTOCOL, &efirng );
 | 
			
		||||
 | 
			
		||||
/** Minimum number of bytes to request from RNG
 | 
			
		||||
 *
 | 
			
		||||
 * The UEFI spec states (for no apparently good reason) that "When a
 | 
			
		||||
 * Deterministic Random Bit Generator (DRBG) is used on the output of
 | 
			
		||||
 * a (raw) entropy source, its security level must be at least 256
 | 
			
		||||
 * bits."  The EDK2 codebase (mis)interprets this to mean that the
 | 
			
		||||
 * call to GetRNG() should fail if given a buffer less than 32 bytes.
 | 
			
		||||
 *
 | 
			
		||||
 * Incidentally, nothing in the EFI RNG protocol provides any way to
 | 
			
		||||
 * report the actual amount of entropy returned by GetRNG().
 | 
			
		||||
 */
 | 
			
		||||
#define EFIRNG_LEN 32
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Enable entropy gathering
 | 
			
		||||
 *
 | 
			
		||||
 * @ret rc		Return status code
 | 
			
		||||
 */
 | 
			
		||||
static int efirng_enable ( void ) {
 | 
			
		||||
 | 
			
		||||
	/* Check for RNG protocol support */
 | 
			
		||||
	if ( ! efirng ) {
 | 
			
		||||
		DBGC ( &efirng, "EFIRNG has no RNG protocol\n" );
 | 
			
		||||
		return -ENOTSUP;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* Nothing in the EFI specification provides any clue as to
 | 
			
		||||
	 * how much entropy will be returned by GetRNG().  Make a
 | 
			
		||||
	 * totally uninformed (and conservative guess) that each
 | 
			
		||||
	 * sample will contain at least one bit of entropy.
 | 
			
		||||
	 */
 | 
			
		||||
	entropy_init ( &efirng_entropy, MIN_ENTROPY ( 1.0 ) );
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Get noise sample from RNG protocol
 | 
			
		||||
 *
 | 
			
		||||
 * @ret noise		Noise sample
 | 
			
		||||
 * @ret rc		Return status code
 | 
			
		||||
 */
 | 
			
		||||
static int efirng_get_noise ( noise_sample_t *noise ) {
 | 
			
		||||
	uint8_t buf[EFIRNG_LEN];
 | 
			
		||||
	EFI_STATUS efirc;
 | 
			
		||||
	int rc;
 | 
			
		||||
 | 
			
		||||
	/* Sanity check */
 | 
			
		||||
	assert ( efirng != NULL );
 | 
			
		||||
 | 
			
		||||
	/* Get the minimum allowed number of random bytes */
 | 
			
		||||
	if ( ( efirc = efirng->GetRNG ( efirng, NULL, sizeof ( buf ),
 | 
			
		||||
					buf ) ) != 0 ) {
 | 
			
		||||
		rc = -EEFI ( efirc );
 | 
			
		||||
		DBGC ( &efirng, "ENTROPY could not read from RNG: %s\n",
 | 
			
		||||
		       strerror ( rc ) );
 | 
			
		||||
		return rc;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* Reduce random bytes to a single noise sample.  This seems
 | 
			
		||||
	 * like overkill, but we have no way of knowing how much
 | 
			
		||||
	 * entropy is actually present in the bytes returned by the
 | 
			
		||||
	 * RNG protocol.
 | 
			
		||||
	 */
 | 
			
		||||
	*noise = crc32_le ( 0, buf, sizeof ( buf ) );
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/** EFI random number generator protocol entropy source */
 | 
			
		||||
struct entropy_source efirng_entropy __entropy_source ( ENTROPY_NORMAL ) = {
 | 
			
		||||
	.name = "efirng",
 | 
			
		||||
	.enable = efirng_enable,
 | 
			
		||||
	.get_noise = efirng_get_noise,
 | 
			
		||||
};
 | 
			
		||||
							
								
								
									
										189
									
								
								src/interface/efi/efi_settings.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										189
									
								
								src/interface/efi/efi_settings.c
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,189 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (C) 2023 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
 | 
			
		||||
 *
 | 
			
		||||
 * EFI variable settings
 | 
			
		||||
 *
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include <stdlib.h>
 | 
			
		||||
#include <string.h>
 | 
			
		||||
#include <errno.h>
 | 
			
		||||
#include <ipxe/settings.h>
 | 
			
		||||
#include <ipxe/init.h>
 | 
			
		||||
#include <ipxe/efi/efi.h>
 | 
			
		||||
#include <ipxe/efi/Guid/GlobalVariable.h>
 | 
			
		||||
 | 
			
		||||
/** An EFI variable settings block */
 | 
			
		||||
struct efivar_settings {
 | 
			
		||||
	/** Settings block */
 | 
			
		||||
	struct settings settings;
 | 
			
		||||
	/** Vendor GUID */
 | 
			
		||||
	EFI_GUID guid;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/** EFI settings scope */
 | 
			
		||||
static const struct settings_scope efivar_scope;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Check applicability of EFI variable setting
 | 
			
		||||
 *
 | 
			
		||||
 * @v settings		Settings block
 | 
			
		||||
 * @v setting		Setting
 | 
			
		||||
 * @ret applies		Setting applies within this settings block
 | 
			
		||||
 */
 | 
			
		||||
static int efivar_applies ( struct settings *settings __unused,
 | 
			
		||||
			    const struct setting *setting ) {
 | 
			
		||||
 | 
			
		||||
	return ( setting->scope == &efivar_scope );
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Fetch value of EFI variable setting
 | 
			
		||||
 *
 | 
			
		||||
 * @v settings		Settings block
 | 
			
		||||
 * @v setting		Setting to fetch
 | 
			
		||||
 * @v data		Buffer to fill with setting data
 | 
			
		||||
 * @v len		Length of buffer
 | 
			
		||||
 * @ret len		Length of setting data, or negative error
 | 
			
		||||
 */
 | 
			
		||||
static int efivar_fetch ( struct settings *settings, struct setting *setting,
 | 
			
		||||
			  void *data, size_t len ) {
 | 
			
		||||
	EFI_RUNTIME_SERVICES *rs = efi_systab->RuntimeServices;
 | 
			
		||||
	struct efivar_settings *efivars =
 | 
			
		||||
		container_of ( settings, struct efivar_settings, settings );
 | 
			
		||||
	size_t name_len = strlen ( setting->name );
 | 
			
		||||
	CHAR16 wname[ name_len + 1 /* wNUL */ ];
 | 
			
		||||
	UINT32 attrs;
 | 
			
		||||
	UINTN size;
 | 
			
		||||
	void *buf;
 | 
			
		||||
	unsigned int i;
 | 
			
		||||
	EFI_STATUS efirc;
 | 
			
		||||
	int rc;
 | 
			
		||||
 | 
			
		||||
	/* Convert name to UCS-2 */
 | 
			
		||||
	for ( i = 0 ; i <= name_len ; i++ )
 | 
			
		||||
		wname[i] = setting->name[i];
 | 
			
		||||
 | 
			
		||||
	/* Get variable length */
 | 
			
		||||
	size = 0;
 | 
			
		||||
	efirc = rs->GetVariable ( wname, &efivars->guid, &attrs, &size, NULL );
 | 
			
		||||
	if ( ( efirc != 0 ) && ( efirc != EFI_BUFFER_TOO_SMALL ) ) {
 | 
			
		||||
		rc = -EEFI ( efirc );
 | 
			
		||||
		DBGC ( efivars, "EFIVAR %s:%s not present: %s\n",
 | 
			
		||||
		       efi_guid_ntoa ( &efivars->guid ), setting->name,
 | 
			
		||||
		       strerror ( rc ) );
 | 
			
		||||
		goto err_len;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* Allocate temporary buffer, since GetVariable() is not
 | 
			
		||||
	 * guaranteed to return partial data for an underlength
 | 
			
		||||
	 * buffer.
 | 
			
		||||
	 */
 | 
			
		||||
	buf = malloc ( size );
 | 
			
		||||
	if ( ! buf ) {
 | 
			
		||||
		rc = -ENOMEM;
 | 
			
		||||
		goto err_alloc;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* Get variable value */
 | 
			
		||||
	if ( ( efirc = rs->GetVariable ( wname, &efivars->guid, &attrs, &size,
 | 
			
		||||
					 buf ) ) != 0 ) {
 | 
			
		||||
		rc = -EEFI ( efirc );
 | 
			
		||||
		DBGC ( efivars, "EFIVAR %s:%s could not get %zd bytes: %s\n",
 | 
			
		||||
		       efi_guid_ntoa ( &efivars->guid ), setting->name,
 | 
			
		||||
		       ( ( size_t ) size ), strerror ( rc ) );
 | 
			
		||||
		goto err_get;
 | 
			
		||||
	}
 | 
			
		||||
	DBGC ( efivars, "EFIVAR %s:%s:\n", efi_guid_ntoa ( &efivars->guid ),
 | 
			
		||||
	       setting->name );
 | 
			
		||||
	DBGC_HDA ( efivars, 0, buf, size );
 | 
			
		||||
 | 
			
		||||
	/* Return setting value */
 | 
			
		||||
	if ( len > size )
 | 
			
		||||
		len = size;
 | 
			
		||||
	memcpy ( data, buf, len );
 | 
			
		||||
	if ( ! setting->type )
 | 
			
		||||
		setting->type = &setting_type_hex;
 | 
			
		||||
 | 
			
		||||
	/* Free temporary buffer */
 | 
			
		||||
	free ( buf );
 | 
			
		||||
 | 
			
		||||
	return size;
 | 
			
		||||
 | 
			
		||||
 err_get:
 | 
			
		||||
	free ( buf );
 | 
			
		||||
 err_alloc:
 | 
			
		||||
 err_len:
 | 
			
		||||
	return rc;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/** EFI variable settings operations */
 | 
			
		||||
static struct settings_operations efivar_operations = {
 | 
			
		||||
	.applies = efivar_applies,
 | 
			
		||||
	.fetch = efivar_fetch,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/** Well-known EFI variable settings blocks */
 | 
			
		||||
static struct efivar_settings efivar_settings[] = {
 | 
			
		||||
	{ .settings = { .name = "efi" }, .guid = EFI_GLOBAL_VARIABLE },
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Initialise EFI variable settings
 | 
			
		||||
 *
 | 
			
		||||
 */
 | 
			
		||||
static void efivar_init ( void ) {
 | 
			
		||||
	struct efivar_settings *efivars;
 | 
			
		||||
	const char *name;
 | 
			
		||||
	unsigned int i;
 | 
			
		||||
	int rc;
 | 
			
		||||
 | 
			
		||||
	/* Register all settings blocks */
 | 
			
		||||
	for ( i = 0 ; i < ( sizeof ( efivar_settings ) /
 | 
			
		||||
			    sizeof ( efivar_settings[0] ) ) ; i++ ) {
 | 
			
		||||
 | 
			
		||||
		/* Initialise settings block */
 | 
			
		||||
		efivars = &efivar_settings[i];
 | 
			
		||||
		settings_init ( &efivars->settings, &efivar_operations, NULL,
 | 
			
		||||
				&efivar_scope );
 | 
			
		||||
 | 
			
		||||
		/* Register settings block */
 | 
			
		||||
		name = efivars->settings.name;
 | 
			
		||||
		if ( ( rc = register_settings ( &efivars->settings, NULL,
 | 
			
		||||
						name ) ) != 0 ) {
 | 
			
		||||
			DBGC ( &efivar_settings, "EFIVAR could not register "
 | 
			
		||||
			       "%s: %s\n", name, strerror ( rc ) );
 | 
			
		||||
			/* Continue trying to register remaining blocks */
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/** EFI variable settings initialiser */
 | 
			
		||||
struct init_fn efivar_init_fn __init_fn ( INIT_NORMAL ) = {
 | 
			
		||||
	.initialise = efivar_init,
 | 
			
		||||
};
 | 
			
		||||
@ -34,6 +34,8 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
 | 
			
		||||
#include <ipxe/linux_api.h>
 | 
			
		||||
#include <ipxe/entropy.h>
 | 
			
		||||
 | 
			
		||||
struct entropy_source linux_entropy __entropy_source ( ENTROPY_NORMAL );
 | 
			
		||||
 | 
			
		||||
/** Entropy source filename */
 | 
			
		||||
static const char entropy_filename[] = "/dev/random";
 | 
			
		||||
 | 
			
		||||
@ -55,6 +57,13 @@ static int linux_entropy_enable ( void ) {
 | 
			
		||||
		return entropy_fd;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* linux_get_noise() reads a single byte from /dev/random,
 | 
			
		||||
	 * which is supposed to block until a sufficient amount of
 | 
			
		||||
	 * entropy is available.  We therefore assume that each sample
 | 
			
		||||
	 * contains exactly 8 bits of entropy.
 | 
			
		||||
	 */
 | 
			
		||||
	entropy_init ( &linux_entropy, MIN_ENTROPY ( 8.0 ) );
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -95,7 +104,10 @@ static int linux_get_noise ( noise_sample_t *noise ) {
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
PROVIDE_ENTROPY_INLINE ( linux, min_entropy_per_sample );
 | 
			
		||||
PROVIDE_ENTROPY ( linux, entropy_enable, linux_entropy_enable );
 | 
			
		||||
PROVIDE_ENTROPY ( linux, entropy_disable, linux_entropy_disable );
 | 
			
		||||
PROVIDE_ENTROPY ( linux, get_noise, linux_get_noise );
 | 
			
		||||
/** Linux entropy source */
 | 
			
		||||
struct entropy_source linux_entropy __entropy_source ( ENTROPY_NORMAL ) = {
 | 
			
		||||
	.name = "linux",
 | 
			
		||||
	.enable = linux_entropy_enable,
 | 
			
		||||
	.disable = linux_entropy_disable,
 | 
			
		||||
	.get_noise = linux_get_noise,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										340
									
								
								src/net/lldp.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										340
									
								
								src/net/lldp.c
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,340 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (C) 2023 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
 | 
			
		||||
 *
 | 
			
		||||
 * Link Layer Discovery Protocol
 | 
			
		||||
 *
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include <stdlib.h>
 | 
			
		||||
#include <errno.h>
 | 
			
		||||
#include <byteswap.h>
 | 
			
		||||
#include <ipxe/iobuf.h>
 | 
			
		||||
#include <ipxe/netdevice.h>
 | 
			
		||||
#include <ipxe/if_ether.h>
 | 
			
		||||
#include <ipxe/settings.h>
 | 
			
		||||
#include <ipxe/lldp.h>
 | 
			
		||||
 | 
			
		||||
/** An LLDP settings block */
 | 
			
		||||
struct lldp_settings {
 | 
			
		||||
	/** Reference counter */
 | 
			
		||||
	struct refcnt refcnt;
 | 
			
		||||
	/** Settings interface */
 | 
			
		||||
	struct settings settings;
 | 
			
		||||
	/** List of LLDP settings blocks */
 | 
			
		||||
	struct list_head list;
 | 
			
		||||
	/** Name */
 | 
			
		||||
	const char *name;
 | 
			
		||||
	/** LLDP data */
 | 
			
		||||
	void *data;
 | 
			
		||||
	/** Length of LLDP data */
 | 
			
		||||
	size_t len;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/** LLDP settings scope */
 | 
			
		||||
static const struct settings_scope lldp_settings_scope;
 | 
			
		||||
 | 
			
		||||
/** List of LLDP settings blocks */
 | 
			
		||||
static LIST_HEAD ( lldp_settings );
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Free LLDP settings block
 | 
			
		||||
 *
 | 
			
		||||
 * @v refcnt		Reference counter
 | 
			
		||||
 */
 | 
			
		||||
static void lldp_free ( struct refcnt *refcnt ) {
 | 
			
		||||
	struct lldp_settings *lldpset =
 | 
			
		||||
		container_of ( refcnt, struct lldp_settings, refcnt );
 | 
			
		||||
 | 
			
		||||
	DBGC ( lldpset, "LLDP %s freed\n", lldpset->name );
 | 
			
		||||
	list_del ( &lldpset->list );
 | 
			
		||||
	free ( lldpset->data );
 | 
			
		||||
	free ( lldpset );
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Find LLDP settings block
 | 
			
		||||
 *
 | 
			
		||||
 * @v netdev		Network device
 | 
			
		||||
 * @ret lldpset		LLDP settings block
 | 
			
		||||
 */
 | 
			
		||||
static struct lldp_settings * lldp_find ( struct net_device *netdev ) {
 | 
			
		||||
	struct lldp_settings *lldpset;
 | 
			
		||||
 | 
			
		||||
	/* Find matching LLDP settings block */
 | 
			
		||||
	list_for_each_entry ( lldpset, &lldp_settings, list ) {
 | 
			
		||||
		if ( netdev_settings ( netdev ) == lldpset->settings.parent )
 | 
			
		||||
			return lldpset;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return NULL;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Check applicability of LLDP setting
 | 
			
		||||
 *
 | 
			
		||||
 * @v settings		Settings block
 | 
			
		||||
 * @v setting		Setting to fetch
 | 
			
		||||
 * @ret applies		Setting applies within this settings block
 | 
			
		||||
 */
 | 
			
		||||
static int lldp_applies ( struct settings *settings __unused,
 | 
			
		||||
			  const struct setting *setting ) {
 | 
			
		||||
 | 
			
		||||
	return ( setting->scope == &lldp_settings_scope );
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Fetch value of LLDP setting
 | 
			
		||||
 *
 | 
			
		||||
 * @v settings		Settings block
 | 
			
		||||
 * @v setting		Setting to fetch
 | 
			
		||||
 * @v buf		Buffer to fill with setting data
 | 
			
		||||
 * @v len		Length of buffer
 | 
			
		||||
 * @ret len		Length of setting data, or negative error
 | 
			
		||||
 */
 | 
			
		||||
static int lldp_fetch ( struct settings *settings,
 | 
			
		||||
			struct setting *setting,
 | 
			
		||||
			void *buf, size_t len ) {
 | 
			
		||||
	struct lldp_settings *lldpset =
 | 
			
		||||
		container_of ( settings, struct lldp_settings, settings );
 | 
			
		||||
	union {
 | 
			
		||||
		uint32_t high;
 | 
			
		||||
		uint8_t raw[4];
 | 
			
		||||
	} tag_prefix;
 | 
			
		||||
	uint32_t tag_low;
 | 
			
		||||
	uint8_t tag_type;
 | 
			
		||||
	uint8_t tag_index;
 | 
			
		||||
	uint8_t tag_offset;
 | 
			
		||||
	uint8_t tag_length;
 | 
			
		||||
	const void *match;
 | 
			
		||||
	const void *data;
 | 
			
		||||
	size_t match_len;
 | 
			
		||||
	size_t remaining;
 | 
			
		||||
	const struct lldp_tlv *tlv;
 | 
			
		||||
	unsigned int tlv_type_len;
 | 
			
		||||
	unsigned int tlv_type;
 | 
			
		||||
	unsigned int tlv_len;
 | 
			
		||||
 | 
			
		||||
	/* Parse setting tag */
 | 
			
		||||
	tag_prefix.high = htonl ( setting->tag >> 32 );
 | 
			
		||||
	tag_low = setting->tag;
 | 
			
		||||
	tag_type = ( tag_low >> 24 );
 | 
			
		||||
	tag_index = ( tag_low >> 16 );
 | 
			
		||||
	tag_offset = ( tag_low >> 8 );
 | 
			
		||||
	tag_length = ( tag_low >> 0 );
 | 
			
		||||
 | 
			
		||||
	/* Identify match prefix */
 | 
			
		||||
	match_len = tag_offset;
 | 
			
		||||
	if ( match_len > sizeof ( tag_prefix ) )
 | 
			
		||||
		match_len = sizeof ( tag_prefix );
 | 
			
		||||
	if ( ! tag_prefix.high )
 | 
			
		||||
		match_len = 0;
 | 
			
		||||
	match = &tag_prefix.raw[ sizeof ( tag_prefix ) - match_len ];
 | 
			
		||||
 | 
			
		||||
	/* Locate matching TLV */
 | 
			
		||||
	for ( data = lldpset->data, remaining = lldpset->len ; remaining ;
 | 
			
		||||
	      data += tlv_len, remaining -= tlv_len ) {
 | 
			
		||||
 | 
			
		||||
		/* Parse TLV header */
 | 
			
		||||
		if ( remaining < sizeof ( *tlv ) ) {
 | 
			
		||||
			DBGC ( lldpset, "LLDP %s underlength TLV header\n",
 | 
			
		||||
			       lldpset->name );
 | 
			
		||||
			DBGC_HDA ( lldpset, 0, data, remaining );
 | 
			
		||||
			break;
 | 
			
		||||
		}
 | 
			
		||||
		tlv = data;
 | 
			
		||||
		data += sizeof ( *tlv );
 | 
			
		||||
		remaining -= sizeof ( *tlv );
 | 
			
		||||
		tlv_type_len = ntohs ( tlv->type_len );
 | 
			
		||||
		tlv_type = LLDP_TLV_TYPE ( tlv_type_len );
 | 
			
		||||
		if ( tlv_type == LLDP_TYPE_END )
 | 
			
		||||
			break;
 | 
			
		||||
		tlv_len = LLDP_TLV_LEN ( tlv_type_len );
 | 
			
		||||
		if ( remaining < tlv_len ) {
 | 
			
		||||
			DBGC ( lldpset, "LLDP %s underlength TLV value\n",
 | 
			
		||||
			       lldpset->name );
 | 
			
		||||
			DBGC_HDA ( lldpset, 0, data, remaining );
 | 
			
		||||
			break;
 | 
			
		||||
		}
 | 
			
		||||
		DBGC2 ( lldpset, "LLDP %s found type %d:\n",
 | 
			
		||||
			lldpset->name, tlv_type );
 | 
			
		||||
		DBGC2_HDA ( lldpset, 0, data, tlv_len );
 | 
			
		||||
 | 
			
		||||
		/* Check for matching tag type */
 | 
			
		||||
		if ( tlv_type != tag_type )
 | 
			
		||||
			continue;
 | 
			
		||||
 | 
			
		||||
		/* Check for matching prefix */
 | 
			
		||||
		if ( tlv_len < match_len )
 | 
			
		||||
			continue;
 | 
			
		||||
		if ( memcmp ( data, match, match_len ) != 0 )
 | 
			
		||||
			continue;
 | 
			
		||||
 | 
			
		||||
		/* Check for matching index */
 | 
			
		||||
		if ( tag_index-- )
 | 
			
		||||
			continue;
 | 
			
		||||
 | 
			
		||||
		/* Skip offset */
 | 
			
		||||
		if ( tlv_len < tag_offset )
 | 
			
		||||
			return 0;
 | 
			
		||||
		data += tag_offset;
 | 
			
		||||
		tlv_len -= tag_offset;
 | 
			
		||||
 | 
			
		||||
		/* Set type if not already specified */
 | 
			
		||||
		if ( ! setting->type ) {
 | 
			
		||||
			setting->type = ( tag_length ? &setting_type_hex :
 | 
			
		||||
					  &setting_type_string );
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		/* Extract value */
 | 
			
		||||
		if ( tag_length && ( tlv_len > tag_length ) )
 | 
			
		||||
			tlv_len = tag_length;
 | 
			
		||||
		if ( len > tlv_len )
 | 
			
		||||
			len = tlv_len;
 | 
			
		||||
		memcpy ( buf, data, len );
 | 
			
		||||
		return tlv_len;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return -ENOENT;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/** LLDP settings operations */
 | 
			
		||||
static struct settings_operations lldp_settings_operations = {
 | 
			
		||||
	.applies = lldp_applies,
 | 
			
		||||
	.fetch = lldp_fetch,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Process LLDP packet
 | 
			
		||||
 *
 | 
			
		||||
 * @v iobuf		I/O buffer
 | 
			
		||||
 * @v netdev		Network device
 | 
			
		||||
 * @v ll_dest		Link-layer destination address
 | 
			
		||||
 * @v ll_source		Link-layer source address
 | 
			
		||||
 * @v flags		Packet flags
 | 
			
		||||
 * @ret rc		Return status code
 | 
			
		||||
 */
 | 
			
		||||
static int lldp_rx ( struct io_buffer *iobuf, struct net_device *netdev,
 | 
			
		||||
		     const void *ll_dest, const void *ll_source,
 | 
			
		||||
		     unsigned int flags __unused ) {
 | 
			
		||||
	struct lldp_settings *lldpset;
 | 
			
		||||
	size_t len;
 | 
			
		||||
	void *data;
 | 
			
		||||
	int rc;
 | 
			
		||||
 | 
			
		||||
	/* Find matching LLDP settings block */
 | 
			
		||||
	lldpset = lldp_find ( netdev );
 | 
			
		||||
	if ( ! lldpset ) {
 | 
			
		||||
		DBGC ( netdev, "LLDP %s has no \"%s\" settings block\n",
 | 
			
		||||
		       netdev->name, LLDP_SETTINGS_NAME );
 | 
			
		||||
		rc = -ENOENT;
 | 
			
		||||
		goto err_find;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* Create trimmed copy of received LLDP data */
 | 
			
		||||
	len = iob_len ( iobuf );
 | 
			
		||||
	data = malloc ( len );
 | 
			
		||||
	if ( ! data ) {
 | 
			
		||||
		rc = -ENOMEM;
 | 
			
		||||
		goto err_alloc;
 | 
			
		||||
	}
 | 
			
		||||
	memcpy ( data, iobuf->data, len );
 | 
			
		||||
 | 
			
		||||
	/* Free any existing LLDP data */
 | 
			
		||||
	free ( lldpset->data );
 | 
			
		||||
 | 
			
		||||
	/* Transfer data to LLDP settings block */
 | 
			
		||||
	lldpset->data = data;
 | 
			
		||||
	lldpset->len = len;
 | 
			
		||||
	data = NULL;
 | 
			
		||||
	DBGC2 ( lldpset, "LLDP %s src %s ",
 | 
			
		||||
		lldpset->name, netdev->ll_protocol->ntoa ( ll_source ) );
 | 
			
		||||
	DBGC2 ( lldpset, "dst %s\n", netdev->ll_protocol->ntoa ( ll_dest ) );
 | 
			
		||||
	DBGC2_HDA ( lldpset, 0, lldpset->data, lldpset->len );
 | 
			
		||||
 | 
			
		||||
	/* Success */
 | 
			
		||||
	rc = 0;
 | 
			
		||||
 | 
			
		||||
	free ( data );
 | 
			
		||||
 err_alloc:
 | 
			
		||||
 err_find:
 | 
			
		||||
	free_iob ( iobuf );
 | 
			
		||||
	return rc;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/** LLDP protocol */
 | 
			
		||||
struct net_protocol lldp_protocol __net_protocol = {
 | 
			
		||||
	.name = "LLDP",
 | 
			
		||||
	.net_proto = htons ( ETH_P_LLDP ),
 | 
			
		||||
	.rx = lldp_rx,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Create LLDP settings block
 | 
			
		||||
 *
 | 
			
		||||
 * @v netdev		Network device
 | 
			
		||||
 * @ret rc		Return status code
 | 
			
		||||
 */
 | 
			
		||||
static int lldp_probe ( struct net_device *netdev ) {
 | 
			
		||||
	struct lldp_settings *lldpset;
 | 
			
		||||
	int rc;
 | 
			
		||||
 | 
			
		||||
	/* Allocate LLDP settings block */
 | 
			
		||||
	lldpset = zalloc ( sizeof ( *lldpset ) );
 | 
			
		||||
	if ( ! lldpset ) {
 | 
			
		||||
		rc = -ENOMEM;
 | 
			
		||||
		goto err_alloc;
 | 
			
		||||
	}
 | 
			
		||||
	ref_init ( &lldpset->refcnt, lldp_free );
 | 
			
		||||
	settings_init ( &lldpset->settings, &lldp_settings_operations,
 | 
			
		||||
			&lldpset->refcnt, &lldp_settings_scope );
 | 
			
		||||
	list_add_tail ( &lldpset->list, &lldp_settings );
 | 
			
		||||
	lldpset->name = netdev->name;
 | 
			
		||||
 | 
			
		||||
	/* Register settings */
 | 
			
		||||
	if ( ( rc = register_settings ( &lldpset->settings, netdev_settings ( netdev ),
 | 
			
		||||
					LLDP_SETTINGS_NAME ) ) != 0 ) {
 | 
			
		||||
		DBGC ( lldpset, "LLDP %s could not register settings: %s\n",
 | 
			
		||||
		       lldpset->name, strerror ( rc ) );
 | 
			
		||||
		goto err_register;
 | 
			
		||||
	}
 | 
			
		||||
	DBGC ( lldpset, "LLDP %s registered\n", lldpset->name );
 | 
			
		||||
 | 
			
		||||
	ref_put ( &lldpset->refcnt );
 | 
			
		||||
	return 0;
 | 
			
		||||
 | 
			
		||||
	unregister_settings ( &lldpset->settings );
 | 
			
		||||
 err_register:
 | 
			
		||||
	ref_put ( &lldpset->refcnt );
 | 
			
		||||
 err_alloc:
 | 
			
		||||
	return rc;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/** LLDP driver */
 | 
			
		||||
struct net_driver lldp_driver __net_driver = {
 | 
			
		||||
	.name = "LLDP",
 | 
			
		||||
	.probe = lldp_probe,
 | 
			
		||||
};
 | 
			
		||||
@ -830,7 +830,9 @@ static int http_transfer_complete ( struct http_transaction *http ) {
 | 
			
		||||
 */
 | 
			
		||||
static int http_format_headers ( struct http_transaction *http, char *buf,
 | 
			
		||||
				 size_t len ) {
 | 
			
		||||
	struct parameters *params = http->uri->params;
 | 
			
		||||
	struct http_request_header *header;
 | 
			
		||||
	struct parameter *param;
 | 
			
		||||
	size_t used;
 | 
			
		||||
	size_t remaining;
 | 
			
		||||
	char *line;
 | 
			
		||||
@ -844,7 +846,7 @@ static int http_format_headers ( struct http_transaction *http, char *buf,
 | 
			
		||||
		DBGC2 ( http, "HTTP %p TX %s\n", http, buf );
 | 
			
		||||
	used += ssnprintf ( ( buf + used ), ( len - used ), "\r\n" );
 | 
			
		||||
 | 
			
		||||
	/* Construct all headers */
 | 
			
		||||
	/* Construct all fixed headers */
 | 
			
		||||
	for_each_table_entry ( header, HTTP_REQUEST_HEADERS ) {
 | 
			
		||||
 | 
			
		||||
		/* Determine header value length */
 | 
			
		||||
@ -869,6 +871,23 @@ static int http_format_headers ( struct http_transaction *http, char *buf,
 | 
			
		||||
		used += ssnprintf ( ( buf + used ), ( len - used ), "\r\n" );
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* Construct parameter headers, if any */
 | 
			
		||||
	if ( params ) {
 | 
			
		||||
 | 
			
		||||
		/* Construct all parameter headers */
 | 
			
		||||
		for_each_param ( param, params ) {
 | 
			
		||||
 | 
			
		||||
			/* Skip non-header parameters */
 | 
			
		||||
			if ( ! ( param->flags & PARAMETER_HEADER ) )
 | 
			
		||||
				continue;
 | 
			
		||||
 | 
			
		||||
			/* Add parameter */
 | 
			
		||||
			used += ssnprintf ( ( buf + used ), ( len - used ),
 | 
			
		||||
					    "%s: %s\r\n", param->key,
 | 
			
		||||
					    param->value );
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* Construct terminating newline */
 | 
			
		||||
	used += ssnprintf ( ( buf + used ), ( len - used ), "\r\n" );
 | 
			
		||||
 | 
			
		||||
@ -1851,14 +1870,15 @@ static struct http_state http_trailers = {
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Construct HTTP parameter list
 | 
			
		||||
 * Construct HTTP form parameter list
 | 
			
		||||
 *
 | 
			
		||||
 * @v params		Parameter list
 | 
			
		||||
 * @v buf		Buffer to contain HTTP POST parameters
 | 
			
		||||
 * @v len		Length of buffer
 | 
			
		||||
 * @ret len		Length of parameter list (excluding terminating NUL)
 | 
			
		||||
 */
 | 
			
		||||
static size_t http_params ( struct parameters *params, char *buf, size_t len ) {
 | 
			
		||||
static size_t http_form_params ( struct parameters *params, char *buf,
 | 
			
		||||
				 size_t len ) {
 | 
			
		||||
	struct parameter *param;
 | 
			
		||||
	ssize_t remaining = len;
 | 
			
		||||
	size_t frag_len;
 | 
			
		||||
@ -1867,6 +1887,10 @@ static size_t http_params ( struct parameters *params, char *buf, size_t len ) {
 | 
			
		||||
	len = 0;
 | 
			
		||||
	for_each_param ( param, params ) {
 | 
			
		||||
 | 
			
		||||
		/* Skip non-form parameters */
 | 
			
		||||
		if ( ! ( param->flags & PARAMETER_FORM ) )
 | 
			
		||||
			continue;
 | 
			
		||||
 | 
			
		||||
		/* Add the "&", if applicable */
 | 
			
		||||
		if ( len ) {
 | 
			
		||||
			if ( remaining > 0 )
 | 
			
		||||
@ -1904,53 +1928,59 @@ static size_t http_params ( struct parameters *params, char *buf, size_t len ) {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Open HTTP transaction for simple GET URI
 | 
			
		||||
 * Open HTTP transaction for simple URI
 | 
			
		||||
 *
 | 
			
		||||
 * @v xfer		Data transfer interface
 | 
			
		||||
 * @v uri		Request URI
 | 
			
		||||
 * @ret rc		Return status code
 | 
			
		||||
 */
 | 
			
		||||
static int http_open_get_uri ( struct interface *xfer, struct uri *uri ) {
 | 
			
		||||
 | 
			
		||||
	return http_open ( xfer, &http_get, uri, NULL, NULL );
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Open HTTP transaction for simple POST URI
 | 
			
		||||
 *
 | 
			
		||||
 * @v xfer		Data transfer interface
 | 
			
		||||
 * @v uri		Request URI
 | 
			
		||||
 * @ret rc		Return status code
 | 
			
		||||
 */
 | 
			
		||||
static int http_open_post_uri ( struct interface *xfer, struct uri *uri ) {
 | 
			
		||||
int http_open_uri ( struct interface *xfer, struct uri *uri ) {
 | 
			
		||||
	struct parameters *params = uri->params;
 | 
			
		||||
	struct http_request_content content;
 | 
			
		||||
	struct http_method *method;
 | 
			
		||||
	const char *type;
 | 
			
		||||
	void *data;
 | 
			
		||||
	size_t len;
 | 
			
		||||
	size_t check_len;
 | 
			
		||||
	int rc;
 | 
			
		||||
 | 
			
		||||
	/* Calculate length of parameter list */
 | 
			
		||||
	len = http_params ( params, NULL, 0 );
 | 
			
		||||
	/* Calculate length of form parameter list, if any */
 | 
			
		||||
	len = ( params ? http_form_params ( params, NULL, 0 ) : 0 );
 | 
			
		||||
 | 
			
		||||
	/* Allocate temporary parameter list */
 | 
			
		||||
	data = zalloc ( len + 1 /* NUL */ );
 | 
			
		||||
	if ( ! data ) {
 | 
			
		||||
		rc = -ENOMEM;
 | 
			
		||||
		goto err_alloc;
 | 
			
		||||
	/* Use POST if and only if there are form parameters */
 | 
			
		||||
	if ( len ) {
 | 
			
		||||
 | 
			
		||||
		/* Use POST */
 | 
			
		||||
		method = &http_post;
 | 
			
		||||
		type = "application/x-www-form-urlencoded";
 | 
			
		||||
 | 
			
		||||
		/* Allocate temporary form parameter list */
 | 
			
		||||
		data = zalloc ( len + 1 /* NUL */ );
 | 
			
		||||
		if ( ! data ) {
 | 
			
		||||
			rc = -ENOMEM;
 | 
			
		||||
			goto err_alloc;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		/* Construct temporary form parameter list */
 | 
			
		||||
		check_len = http_form_params ( params, data,
 | 
			
		||||
					       ( len + 1 /* NUL */ ) );
 | 
			
		||||
		assert ( check_len == len );
 | 
			
		||||
 | 
			
		||||
	} else {
 | 
			
		||||
 | 
			
		||||
		/* Use GET */
 | 
			
		||||
		method = &http_get;
 | 
			
		||||
		type = NULL;
 | 
			
		||||
		data = NULL;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* Construct temporary parameter list */
 | 
			
		||||
	check_len = http_params ( params, data, ( len + 1 /* NUL */ ) );
 | 
			
		||||
	assert ( check_len == len );
 | 
			
		||||
 | 
			
		||||
	/* Construct request content */
 | 
			
		||||
	content.type = "application/x-www-form-urlencoded";
 | 
			
		||||
	content.type = type;
 | 
			
		||||
	content.data = data;
 | 
			
		||||
	content.len = len;
 | 
			
		||||
 | 
			
		||||
	/* Open HTTP transaction */
 | 
			
		||||
	if ( ( rc = http_open ( xfer, &http_post, uri, NULL, &content ) ) != 0 )
 | 
			
		||||
	if ( ( rc = http_open ( xfer, method, uri, NULL, &content ) ) != 0 )
 | 
			
		||||
		goto err_open;
 | 
			
		||||
 | 
			
		||||
 err_open:
 | 
			
		||||
@ -1959,23 +1989,6 @@ static int http_open_post_uri ( struct interface *xfer, struct uri *uri ) {
 | 
			
		||||
	return rc;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Open HTTP transaction for simple URI
 | 
			
		||||
 *
 | 
			
		||||
 * @v xfer		Data transfer interface
 | 
			
		||||
 * @v uri		Request URI
 | 
			
		||||
 * @ret rc		Return status code
 | 
			
		||||
 */
 | 
			
		||||
int http_open_uri ( struct interface *xfer, struct uri *uri ) {
 | 
			
		||||
 | 
			
		||||
	/* Open GET/POST URI as applicable */
 | 
			
		||||
	if ( uri->params ) {
 | 
			
		||||
		return http_open_post_uri ( xfer, uri );
 | 
			
		||||
	} else {
 | 
			
		||||
		return http_open_get_uri ( xfer, uri );
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Drag in HTTP extensions */
 | 
			
		||||
REQUIRING_SYMBOL ( http_open );
 | 
			
		||||
REQUIRE_OBJECT ( config_http );
 | 
			
		||||
 | 
			
		||||
@ -46,6 +46,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
 | 
			
		||||
#include <ipxe/base16.h>
 | 
			
		||||
#include <ipxe/base64.h>
 | 
			
		||||
#include <ipxe/ibft.h>
 | 
			
		||||
#include <ipxe/blockdev.h>
 | 
			
		||||
#include <ipxe/efi/efi_path.h>
 | 
			
		||||
#include <ipxe/iscsi.h>
 | 
			
		||||
 | 
			
		||||
@ -86,6 +87,10 @@ FEATURE ( FEATURE_PROTOCOL, "iSCSI", DHCP_EB_FEATURE_ISCSI, 1 );
 | 
			
		||||
	__einfo_error ( EINFO_EINVAL_NO_INITIATOR_IQN )
 | 
			
		||||
#define EINFO_EINVAL_NO_INITIATOR_IQN \
 | 
			
		||||
	__einfo_uniqify ( EINFO_EINVAL, 0x05, "No initiator IQN" )
 | 
			
		||||
#define EINVAL_MAXBURSTLENGTH				\
 | 
			
		||||
	__einfo_error ( EINFO_EINVAL_MAXBURSTLENGTH )
 | 
			
		||||
#define EINFO_EINVAL_MAXBURSTLENGTH \
 | 
			
		||||
	__einfo_uniqify ( EINFO_EINVAL, 0x06, "Invalid MaxBurstLength" )
 | 
			
		||||
#define EIO_TARGET_UNAVAILABLE \
 | 
			
		||||
	__einfo_error ( EINFO_EIO_TARGET_UNAVAILABLE )
 | 
			
		||||
#define EINFO_EIO_TARGET_UNAVAILABLE \
 | 
			
		||||
@ -281,6 +286,9 @@ static int iscsi_open_connection ( struct iscsi_session *iscsi ) {
 | 
			
		||||
	/* Assign fresh initiator task tag */
 | 
			
		||||
	iscsi_new_itt ( iscsi );
 | 
			
		||||
 | 
			
		||||
	/* Set default operational parameters */
 | 
			
		||||
	iscsi->max_burst_len = ISCSI_MAX_BURST_LEN;
 | 
			
		||||
 | 
			
		||||
	/* Initiate login */
 | 
			
		||||
	iscsi_start_login ( iscsi );
 | 
			
		||||
 | 
			
		||||
@ -736,16 +744,20 @@ static int iscsi_build_login_request_strings ( struct iscsi_session *iscsi,
 | 
			
		||||
				    "MaxConnections=1%c"
 | 
			
		||||
				    "InitialR2T=Yes%c"
 | 
			
		||||
				    "ImmediateData=No%c"
 | 
			
		||||
				    "MaxRecvDataSegmentLength=8192%c"
 | 
			
		||||
				    "MaxBurstLength=262144%c"
 | 
			
		||||
				    "FirstBurstLength=65536%c"
 | 
			
		||||
				    "MaxRecvDataSegmentLength=%d%c"
 | 
			
		||||
				    "MaxBurstLength=%d%c"
 | 
			
		||||
				    "FirstBurstLength=%d%c"
 | 
			
		||||
				    "DefaultTime2Wait=0%c"
 | 
			
		||||
				    "DefaultTime2Retain=0%c"
 | 
			
		||||
				    "MaxOutstandingR2T=1%c"
 | 
			
		||||
				    "DataPDUInOrder=Yes%c"
 | 
			
		||||
				    "DataSequenceInOrder=Yes%c"
 | 
			
		||||
				    "ErrorRecoveryLevel=0%c",
 | 
			
		||||
				    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 );
 | 
			
		||||
				    0, 0, 0, 0, 0,
 | 
			
		||||
				    ISCSI_MAX_RECV_DATA_SEG_LEN, 0,
 | 
			
		||||
				    ISCSI_MAX_BURST_LEN, 0,
 | 
			
		||||
				    ISCSI_FIRST_BURST_LEN, 0,
 | 
			
		||||
				    0, 0, 0, 0, 0, 0 );
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return used;
 | 
			
		||||
@ -908,6 +920,31 @@ static int iscsi_handle_authmethod_value ( struct iscsi_session *iscsi,
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Handle iSCSI MaxBurstLength text value
 | 
			
		||||
 *
 | 
			
		||||
 * @v iscsi		iSCSI session
 | 
			
		||||
 * @v value		MaxBurstLength value
 | 
			
		||||
 * @ret rc		Return status code
 | 
			
		||||
 */
 | 
			
		||||
static int iscsi_handle_maxburstlength_value ( struct iscsi_session *iscsi,
 | 
			
		||||
					       const char *value ) {
 | 
			
		||||
	unsigned long max_burst_len;
 | 
			
		||||
	char *end;
 | 
			
		||||
 | 
			
		||||
	/* Update maximum burst length */
 | 
			
		||||
	max_burst_len = strtoul ( value, &end, 0 );
 | 
			
		||||
	if ( *end ) {
 | 
			
		||||
		DBGC ( iscsi, "iSCSI %p invalid MaxBurstLength \"%s\"\n",
 | 
			
		||||
		       iscsi, value );
 | 
			
		||||
		return -EINVAL_MAXBURSTLENGTH;
 | 
			
		||||
	}
 | 
			
		||||
	if ( max_burst_len < iscsi->max_burst_len )
 | 
			
		||||
		iscsi->max_burst_len = max_burst_len;
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Handle iSCSI CHAP_A text value
 | 
			
		||||
 *
 | 
			
		||||
@ -1148,6 +1185,7 @@ struct iscsi_string_type {
 | 
			
		||||
/** iSCSI text strings that we want to handle */
 | 
			
		||||
static struct iscsi_string_type iscsi_string_types[] = {
 | 
			
		||||
	{ "TargetAddress", iscsi_handle_targetaddress_value },
 | 
			
		||||
	{ "MaxBurstLength", iscsi_handle_maxburstlength_value },
 | 
			
		||||
	{ "AuthMethod", iscsi_handle_authmethod_value },
 | 
			
		||||
	{ "CHAP_A", iscsi_handle_chap_a_value },
 | 
			
		||||
	{ "CHAP_I", iscsi_handle_chap_i_value },
 | 
			
		||||
@ -1847,6 +1885,24 @@ static int iscsi_scsi_command ( struct iscsi_session *iscsi,
 | 
			
		||||
	return iscsi->itt;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Update SCSI block device capacity
 | 
			
		||||
 *
 | 
			
		||||
 * @v iscsi		iSCSI session
 | 
			
		||||
 * @v capacity		Block device capacity
 | 
			
		||||
 */
 | 
			
		||||
static void iscsi_scsi_capacity ( struct iscsi_session *iscsi,
 | 
			
		||||
				  struct block_device_capacity *capacity ) {
 | 
			
		||||
	unsigned int max_count;
 | 
			
		||||
 | 
			
		||||
	/* Limit maximum number of blocks per transfer to fit MaxBurstLength */
 | 
			
		||||
	if ( capacity->blksize ) {
 | 
			
		||||
		max_count = ( iscsi->max_burst_len / capacity->blksize );
 | 
			
		||||
		if ( max_count < capacity->max_count )
 | 
			
		||||
			capacity->max_count = max_count;
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Get iSCSI ACPI descriptor
 | 
			
		||||
 *
 | 
			
		||||
@ -1862,6 +1918,7 @@ static struct acpi_descriptor * iscsi_describe ( struct iscsi_session *iscsi ) {
 | 
			
		||||
static struct interface_operation iscsi_control_op[] = {
 | 
			
		||||
	INTF_OP ( scsi_command, struct iscsi_session *, iscsi_scsi_command ),
 | 
			
		||||
	INTF_OP ( xfer_window, struct iscsi_session *, iscsi_scsi_window ),
 | 
			
		||||
	INTF_OP ( block_capacity, struct iscsi_session *, iscsi_scsi_capacity ),
 | 
			
		||||
	INTF_OP ( intf_close, struct iscsi_session *, iscsi_close ),
 | 
			
		||||
	INTF_OP ( acpi_describe, struct iscsi_session *, iscsi_describe ),
 | 
			
		||||
	EFI_INTF_OP ( efi_describe, struct iscsi_session *, efi_iscsi_path ),
 | 
			
		||||
 | 
			
		||||
@ -571,6 +571,10 @@ static void dhcp_request_rx ( struct dhcp_session *dhcp,
 | 
			
		||||
	if ( peer->sin_port != htons ( BOOTPS_PORT ) )
 | 
			
		||||
		return;
 | 
			
		||||
 | 
			
		||||
	/* Filter out non-selected servers */
 | 
			
		||||
	if ( server_id.s_addr != dhcp->server.s_addr )
 | 
			
		||||
		return;
 | 
			
		||||
 | 
			
		||||
	/* Handle DHCPNAK */
 | 
			
		||||
	if ( msgtype == DHCPNAK ) {
 | 
			
		||||
		dhcp_defer ( dhcp );
 | 
			
		||||
@ -580,8 +584,6 @@ static void dhcp_request_rx ( struct dhcp_session *dhcp,
 | 
			
		||||
	/* Filter out unacceptable responses */
 | 
			
		||||
	if ( msgtype /* BOOTP */ && ( msgtype != DHCPACK ) )
 | 
			
		||||
		return;
 | 
			
		||||
	if ( server_id.s_addr != dhcp->server.s_addr )
 | 
			
		||||
		return;
 | 
			
		||||
	if ( ip.s_addr != dhcp->offer.s_addr )
 | 
			
		||||
		return;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -42,8 +42,9 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
 | 
			
		||||
/**
 | 
			
		||||
 * Generate entropy samples for external testing
 | 
			
		||||
 *
 | 
			
		||||
 * @v source		Entropy source
 | 
			
		||||
 */
 | 
			
		||||
static void entropy_sample_test_exec ( void ) {
 | 
			
		||||
static void entropy_sample ( struct entropy_source *source ) {
 | 
			
		||||
	static noise_sample_t samples[SAMPLE_BLOCKSIZE];
 | 
			
		||||
	unsigned int i;
 | 
			
		||||
	unsigned int j;
 | 
			
		||||
@ -53,22 +54,35 @@ static void entropy_sample_test_exec ( void ) {
 | 
			
		||||
	for ( i = 0 ; i < ( SAMPLE_COUNT / SAMPLE_BLOCKSIZE ) ; i++ ) {
 | 
			
		||||
 | 
			
		||||
		/* Collect one block of samples */
 | 
			
		||||
		rc = entropy_enable();
 | 
			
		||||
		rc = entropy_enable ( source );
 | 
			
		||||
		ok ( rc == 0 );
 | 
			
		||||
		for ( j = 0 ; j < SAMPLE_BLOCKSIZE ; j++ ) {
 | 
			
		||||
			rc = get_noise ( &samples[j] );
 | 
			
		||||
			rc = get_noise ( source, &samples[j] );
 | 
			
		||||
			ok ( rc == 0 );
 | 
			
		||||
		}
 | 
			
		||||
		entropy_disable();
 | 
			
		||||
		entropy_disable ( source );
 | 
			
		||||
 | 
			
		||||
		/* Print out sample values */
 | 
			
		||||
		for ( j = 0 ; j < SAMPLE_BLOCKSIZE ; j++ ) {
 | 
			
		||||
			printf ( "SAMPLE %d %d\n", ( i * SAMPLE_BLOCKSIZE + j ),
 | 
			
		||||
				 samples[j] );
 | 
			
		||||
			printf ( "SAMPLE %s %d %d\n", source->name,
 | 
			
		||||
				 ( i * SAMPLE_BLOCKSIZE + j ), samples[j] );
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Generate entropy samples for external testing
 | 
			
		||||
 *
 | 
			
		||||
 */
 | 
			
		||||
static void entropy_sample_test_exec ( void ) {
 | 
			
		||||
	struct entropy_source *source;
 | 
			
		||||
 | 
			
		||||
	/* Test each entropy source */
 | 
			
		||||
	for_each_table_entry ( source, ENTROPY_SOURCES ) {
 | 
			
		||||
		entropy_sample ( source );
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/** Entropy sampling self-test */
 | 
			
		||||
struct self_test entropy_sample_test __self_test = {
 | 
			
		||||
	.name = "entropy_sample",
 | 
			
		||||
 | 
			
		||||
@ -119,7 +119,7 @@ static int run_all_tests ( void ) {
 | 
			
		||||
	unsigned int total = 0;
 | 
			
		||||
 | 
			
		||||
	/* Run all compiled-in self-tests */
 | 
			
		||||
	printf ( "Starting self-tests\n" );
 | 
			
		||||
	printf ( "Starting %s self-tests\n", _S2 ( ARCH ) );
 | 
			
		||||
	for_each_table_entry ( tests, SELF_TESTS )
 | 
			
		||||
		run_tests ( tests );
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -92,15 +92,17 @@ struct uri_churi_test {
 | 
			
		||||
	const char *expected;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/** A form parameter URI test list */
 | 
			
		||||
/** A request parameter URI test list */
 | 
			
		||||
struct uri_params_test_list {
 | 
			
		||||
	/** Key */
 | 
			
		||||
	const char *key;
 | 
			
		||||
	/** Value */
 | 
			
		||||
	const char *value;
 | 
			
		||||
	/** Flags */
 | 
			
		||||
	unsigned int flags;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/** A form parameter URI test */
 | 
			
		||||
/** A request parameter URI test */
 | 
			
		||||
struct uri_params_test {
 | 
			
		||||
	/** URI string */
 | 
			
		||||
	const char *string;
 | 
			
		||||
@ -403,9 +405,9 @@ static void uri_churi_okx ( struct uri_churi_test *test, const char *file,
 | 
			
		||||
#define uri_churi_ok( test ) uri_churi_okx ( test, __FILE__, __LINE__ )
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Report form parameter URI test list result
 | 
			
		||||
 * Report request parameter URI test list result
 | 
			
		||||
 *
 | 
			
		||||
 * @v test		Form parameter URI test
 | 
			
		||||
 * @v test		Request parameter URI test
 | 
			
		||||
 * @v uri		URI
 | 
			
		||||
 * @v file		Test code file
 | 
			
		||||
 * @v line		Test code line
 | 
			
		||||
@ -428,6 +430,7 @@ static void uri_params_list_okx ( struct uri_params_test *test,
 | 
			
		||||
			      file, line );
 | 
			
		||||
			okx ( strcmp ( param->value, list->value ) == 0,
 | 
			
		||||
			      file, line );
 | 
			
		||||
			okx ( param->flags == list->flags, file, line );
 | 
			
		||||
			list++;
 | 
			
		||||
		}
 | 
			
		||||
		okx ( list->key == NULL, file, line );
 | 
			
		||||
@ -437,9 +440,9 @@ static void uri_params_list_okx ( struct uri_params_test *test,
 | 
			
		||||
	uri_params_list_okx ( test, __FILE__, __LINE__ )
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Report form parameter URI test result
 | 
			
		||||
 * Report request parameter URI test result
 | 
			
		||||
 *
 | 
			
		||||
 * @v test		Form parameter URI test
 | 
			
		||||
 * @v test		Request parameter URI test
 | 
			
		||||
 * @v file		Test code file
 | 
			
		||||
 * @v line		Test code line
 | 
			
		||||
 */
 | 
			
		||||
@ -456,7 +459,8 @@ static void uri_params_okx ( struct uri_params_test *test, const char *file,
 | 
			
		||||
	okx ( params != NULL, file, line );
 | 
			
		||||
	if ( params ) {
 | 
			
		||||
		for ( list = test->list ; list->key ; list++ ) {
 | 
			
		||||
			param = add_parameter ( params, list->key, list->value);
 | 
			
		||||
			param = add_parameter ( params, list->key, list->value,
 | 
			
		||||
						list->flags );
 | 
			
		||||
			okx ( param != NULL, file, line );
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
@ -879,27 +883,31 @@ static struct uri_churi_test uri_churi[] = {
 | 
			
		||||
	}
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/** Form parameter URI test list */
 | 
			
		||||
/** Request parameter URI test list */
 | 
			
		||||
static struct uri_params_test_list uri_params_list[] = {
 | 
			
		||||
	{
 | 
			
		||||
		"vendor",
 | 
			
		||||
		"10ec",
 | 
			
		||||
		PARAMETER_FORM,
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		"device",
 | 
			
		||||
		"8139",
 | 
			
		||||
		PARAMETER_FORM,
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		"uuid",
 | 
			
		||||
		"f59fac00-758f-498f-9fe5-87d790045d94",
 | 
			
		||||
		PARAMETER_HEADER,
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		NULL,
 | 
			
		||||
		NULL,
 | 
			
		||||
		0,
 | 
			
		||||
	}
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/** Form parameter URI test */
 | 
			
		||||
/** Request parameter URI test */
 | 
			
		||||
static struct uri_params_test uri_params = {
 | 
			
		||||
	"http://boot.ipxe.org/demo/boot.php##params",
 | 
			
		||||
	{
 | 
			
		||||
@ -912,23 +920,26 @@ static struct uri_params_test uri_params = {
 | 
			
		||||
	uri_params_list,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/** Named form parameter URI test list */
 | 
			
		||||
/** Named request parameter URI test list */
 | 
			
		||||
static struct uri_params_test_list uri_named_params_list[] = {
 | 
			
		||||
	{
 | 
			
		||||
		"mac",
 | 
			
		||||
		"00:1e:65:80:d3:b6",
 | 
			
		||||
		PARAMETER_FORM,
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		"serial",
 | 
			
		||||
		"LXTQ20Z1139322762F2000",
 | 
			
		||||
		PARAMETER_FORM,
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		NULL,
 | 
			
		||||
		NULL,
 | 
			
		||||
		0,
 | 
			
		||||
	}
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/** Named form parameter URI test */
 | 
			
		||||
/** Named request parameter URI test */
 | 
			
		||||
static struct uri_params_test uri_named_params = {
 | 
			
		||||
	"http://192.168.100.4:3001/register##params=foo",
 | 
			
		||||
	{
 | 
			
		||||
@ -996,7 +1007,7 @@ static void uri_test_exec ( void ) {
 | 
			
		||||
	/* Current working URI tests */
 | 
			
		||||
	uri_churi_ok ( uri_churi );
 | 
			
		||||
 | 
			
		||||
	/* Form parameter URI tests */
 | 
			
		||||
	/* Request parameter URI tests */
 | 
			
		||||
	uri_params_ok ( &uri_params );
 | 
			
		||||
	uri_params_ok ( &uri_named_params );
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
		Reference in New Issue
	
	Block a user