From: Andreas Ă–man Date: Thu, 26 Nov 2009 20:32:58 +0000 (+0000) Subject: * Autodetect CPU capabilities and choose best mode for CSA descrambler. X-Git-Tag: 2.12~400 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=d8829bf604200da0c93abf57fdb324166c90e75e;p=thirdparty%2Ftvheadend.git * Autodetect CPU capabilities and choose best mode for CSA descrambler. Ticket #122 --- diff --git a/Makefile b/Makefile index 99265fb24..061e3252c 100644 --- a/Makefile +++ b/Makefile @@ -93,13 +93,16 @@ SRCS += src/dvb/dvb.c \ SRCS += src/cwc.c \ src/capmt.c \ src/krypt.c \ - src/ffdecsa/FFdecsa.c + src/ffdecsa/ffdecsa_interface.c \ + src/ffdecsa/ffdecsa_int.c \ + src/ffdecsa/ffdecsa_mmx.c \ + src/ffdecsa/ffdecsa_sse2.c \ -ifneq ($(ARCH), ppc) -${BUILDDIR}/src/ffdecsa/FFdecsa.o : CFLAGS = -mmmx -endif LDFLAGS += -lcrypt +${BUILDDIR}/src/ffdecsa/ffdecsa_mmx.o : CFLAGS = -mmmx +${BUILDDIR}/src/ffdecsa/ffdecsa_sse2.o : CFLAGS = -msse2 + # # Primary web interface # @@ -135,7 +138,7 @@ OBJDIRS+= $(sort $(dir $(BUNDLE_OBJS))) # Common CFLAGS for all files CFLAGS_com = -g -funsigned-char -O2 CFLAGS_com += -D_LARGEFILE_SOURCE -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 -CFLAGS_com += -I${BUILDDIR} -I${CURDIR}/src -I${CURDIR} $(CFLAGS_ffdecsa) +CFLAGS_com += -I${BUILDDIR} -I${CURDIR}/src -I${CURDIR} all: ${PROG} diff --git a/configure b/configure index c66e2f70f..193314bf8 100755 --- a/configure +++ b/configure @@ -19,11 +19,6 @@ CPU=generic ARCH=`uname -m` OSENV="posix" PREFIX=/usr/local -if [ "$ARCH" = "ppc" ] ; then - PARALLEL_MODE=PARALLEL_32_INT -else - PARALLEL_MODE=PARALLEL_64_MMX -fi show_help(){ echo "Usage: configure [options]" @@ -35,9 +30,6 @@ show_help(){ echo " --arch=arch Build for this architecture [$ARCH]" echo " --cpu=cpu Build and optimize for specific CPU" echo " --cc=CC Build using the given compiler" - echo " --ffdecsa-mode=MODE Select Mode for ffdecsa" - echo " PARALLEL_64_MMX (default)" - echo " PARALLEL_128_SSE2" echo " --release Stage for release" exit 1 } @@ -59,8 +51,6 @@ for opt do ;; --cc=*) CC="$optval" ;; - --ffdecsa-mode=*) PARALLEL_MODE="$optval" - ;; --enable-?*|--disable-?*) eval $(echo "$opt" | sed 's/--/action=/;s/-/ option=/;s/-/_/g') $action $option @@ -117,11 +107,6 @@ if enabled avahi; then fi fi -# -# ffdecsa mode -# -echo >>${CONFIG_MAK} "CFLAGS_ffdecsa = -DPARALLEL_MODE=${PARALLEL_MODE}" - # # configure ffmpeg # diff --git a/debian/changelog b/debian/changelog index b725af2b1..27a5b6c66 100644 --- a/debian/changelog +++ b/debian/changelog @@ -25,6 +25,9 @@ hts-tvheadend (2.6) hts; urgency=low * Add support for configuring a per-channel pre/post extra time for scheduled recordings. Ticket #104 + * Autodetect CPU capabilities and choose best mode for CSA descrambler. + Ticket #122 + hts-tvheadend (2.5) hts; urgency=low * If a previosly detected DVB adapter was not present during startup, diff --git a/src/ffdecsa/FFdecsa.c b/src/ffdecsa/FFdecsa.c index 3be9855e9..74eb13734 100644 --- a/src/ffdecsa/FFdecsa.c +++ b/src/ffdecsa/FFdecsa.c @@ -23,8 +23,6 @@ #include #include -#include "FFdecsa.h" - #ifndef NULL #define NULL 0 #endif @@ -54,12 +52,6 @@ #define PARALLEL_128_SSE 1285 #define PARALLEL_128_SSE2 1286 -//////// our choice //////////////// our choice //////////////// our choice //////////////// our choice //////// -#ifndef PARALLEL_MODE -#define PARALLEL_MODE PARALLEL_64_MMX -#endif -//////// our choice //////////////// our choice //////////////// our choice //////////////// our choice //////// - #include "parallel_generic.h" //// conditionals #if PARALLEL_MODE==PARALLEL_32_4CHAR @@ -68,6 +60,7 @@ #include "parallel_032_4charA.h" #elif PARALLEL_MODE==PARALLEL_32_INT #include "parallel_032_int.h" +#define FUNC(x) (x ## _32int) #elif PARALLEL_MODE==PARALLEL_64_8CHAR #include "parallel_064_8char.h" #elif PARALLEL_MODE==PARALLEL_64_8CHARA @@ -78,6 +71,7 @@ #include "parallel_064_long.h" #elif PARALLEL_MODE==PARALLEL_64_MMX #include "parallel_064_mmx.h" +#define FUNC(x) (x ## _64mmx) #elif PARALLEL_MODE==PARALLEL_128_16CHAR #include "parallel_128_16char.h" #elif PARALLEL_MODE==PARALLEL_128_16CHARA @@ -92,10 +86,12 @@ #include "parallel_128_sse.h" #elif PARALLEL_MODE==PARALLEL_128_SSE2 #include "parallel_128_sse2.h" +#define FUNC(x) (x ## _128sse2) #else #error "unknown/undefined parallel mode" #endif + // stuff depending on conditionals #define BYTES_PER_GROUP (GROUP_PARALLELISM/8) @@ -333,7 +329,7 @@ static inline __attribute__((always_inline)) void trasp_8_N (unsigned char *in,u //-----block main function // block group -static void block_decypher_group( +static void block_decypher_group ( batch *kkmulti, // [In] kkmulti[0]-kkmulti[55] 56 batches | Key schedule (each batch has repeated equal bytes). unsigned char *ib, // [In] (ib0,ib1,...ib7)...x32 32*8 bytes | Initialization vector. unsigned char *bd, // [Out] (bd0,bd1,...bd7)...x32 32*8 bytes | Block decipher. @@ -463,35 +459,6 @@ static void block_decypher_group( //-----------------------------------EXTERNAL INTERFACE -//-----get internal parallelism - -int get_internal_parallelism(void){ - return GROUP_PARALLELISM; -} - -//-----get suggested cluster size - -int get_suggested_cluster_size(void){ - int r; - r=GROUP_PARALLELISM+GROUP_PARALLELISM/10; - if(reven,ev); schedule_key(&((struct csa_keys_t *)keys)->odd,od); } -void set_even_control_word(void *keys, const unsigned char *pk){ +extern void FUNC(set_even_control_word)(void *keys, const unsigned char *pk); + +void FUNC(set_even_control_word)(void *keys, const unsigned char *pk) +{ schedule_key(&((struct csa_keys_t *)keys)->even,pk); } -void set_odd_control_word(void *keys, const unsigned char *pk){ +extern void FUNC(set_odd_control_word)(void *keys, const unsigned char *pk); + +void FUNC(set_odd_control_word)(void *keys, const unsigned char *pk){ schedule_key(&((struct csa_keys_t *)keys)->odd,pk); } +//-----get internal parallelism + +extern int FUNC(get_internal_parallelism)(void); + +int FUNC(get_internal_parallelism)(void) +{ + return GROUP_PARALLELISM; +} + +//-----get suggested cluster size + +extern int FUNC(get_suggested_cluster_size)(void); + +int FUNC(get_suggested_cluster_size)(void) +{ + int r; + r=GROUP_PARALLELISM+GROUP_PARALLELISM/10; + if(r. + */ + +#include "tvhead.h" +#include "FFdecsa.h" + + + +typedef struct { + int (*get_internal_parallelism)(void); + int (*get_suggested_cluster_size)(void); + void *(*get_key_struct)(void); + void (*free_key_struct)(void *keys); + void (*set_control_words)(void *keys, const unsigned char *even, const unsigned char *odd); + + void (*set_even_control_word)(void *keys, const unsigned char *even); + void (*set_odd_control_word)(void *keys, const unsigned char *odd); + int (*decrypt_packets)(void *keys, unsigned char **cluster); + +} csafuncs_t; + + +#define MAKEFUNCS(x) \ +extern int get_internal_parallelism_##x(void);\ +extern int get_suggested_cluster_size_##x(void);\ +extern void *get_key_struct_##x(void);\ +extern void free_key_struct_##x(void *keys);\ +extern void set_control_words_##x(void *keys, const unsigned char *even, const unsigned char *odd);\ +extern void set_even_control_word_##x(void *keys, const unsigned char *even);\ +extern void set_odd_control_word_##x(void *keys, const unsigned char *odd);\ +extern int decrypt_packets_##x(void *keys, unsigned char **cluster);\ +static csafuncs_t funcs_##x = { \ + &get_internal_parallelism_##x,\ + &get_suggested_cluster_size_##x,\ + &get_key_struct_##x,\ + &free_key_struct_##x,\ + &set_control_words_##x,\ + &set_even_control_word_##x,\ + &set_odd_control_word_##x,\ + &decrypt_packets_##x\ +}; + +MAKEFUNCS(32int); +#if defined(__i386__) || defined(__x86_64__) +MAKEFUNCS(64mmx); +MAKEFUNCS(128sse2); +#endif + +static csafuncs_t current; + + + + +#if defined(__x86_64__) +# define REG_a "rax" +# define REG_b "rbx" +# define REG_c "rcx" +# define REG_d "rdx" +# define REG_D "rdi" +# define REG_S "rsi" +# define PTR_SIZE "8" +typedef int64_t x86_reg; + +# define REG_SP "rsp" +# define REG_BP "rbp" +# define REGBP rbp +# define REGa rax +# define REGb rbx +# define REGc rcx +# define REGd rdx +# define REGSP rsp + +#elif defined(__i386__) + +# define REG_a "eax" +# define REG_b "ebx" +# define REG_c "ecx" +# define REG_d "edx" +# define REG_D "edi" +# define REG_S "esi" +# define PTR_SIZE "4" +typedef int32_t x86_reg; + +# define REG_SP "esp" +# define REG_BP "ebp" +# define REGBP ebp +# define REGa eax +# define REGb ebx +# define REGc ecx +# define REGd edx +# define REGSP esp +#else +typedef int x86_reg; +#endif + + + +/* ebx saving is necessary for PIC. gcc seems unable to see it alone */ +#define cpuid(index,eax,ebx,ecx,edx)\ + __asm__ volatile\ + ("mov %%"REG_b", %%"REG_S"\n\t"\ + "cpuid\n\t"\ + "xchg %%"REG_b", %%"REG_S\ + : "=a" (eax), "=S" (ebx),\ + "=c" (ecx), "=d" (edx)\ + : "0" (index)); + + + +void +ffdecsa_init(void) +{ + current = funcs_32int; + + +#if defined(__i386__) || defined(__x86_64__) + + int eax, ebx, ecx, edx; + int max_std_level, std_caps=0; + +#if defined(__i386__) + + x86_reg a, c; + __asm__ volatile ( + /* See if CPUID instruction is supported ... */ + /* ... Get copies of EFLAGS into eax and ecx */ + "pushfl\n\t" + "pop %0\n\t" + "mov %0, %1\n\t" + + /* ... Toggle the ID bit in one copy and store */ + /* to the EFLAGS reg */ + "xor $0x200000, %0\n\t" + "push %0\n\t" + "popfl\n\t" + + /* ... Get the (hopefully modified) EFLAGS */ + "pushfl\n\t" + "pop %0\n\t" + : "=a" (a), "=c" (c) + : + : "cc" + ); + + if (a != c) { +#endif + cpuid(0, max_std_level, ebx, ecx, edx); + + if(max_std_level >= 1){ + cpuid(1, eax, ebx, ecx, std_caps); + + if (std_caps & (1<<26)) { + current = funcs_128sse2; + tvhlog(LOG_INFO, "CSA", "Using SSE2 128bit parallel descrambling"); + return; + } + + if (std_caps & (1<<23)) { + current = funcs_64mmx; + tvhlog(LOG_INFO, "CSA", "Using MMX 64bit parallel descrambling"); + return; + } + } +#if defined(__i386__) + } +#endif +#endif + + tvhlog(LOG_INFO, "CSA", "Using 32bit parallel descrambling"); +} + + +int +get_internal_parallelism(void) +{ + return current.get_internal_parallelism(); +} +int +get_suggested_cluster_size(void) +{ + return current.get_suggested_cluster_size(); +} + +void * +get_key_struct(void) +{ + return current.get_key_struct(); +} +void +free_key_struct(void *keys) +{ + current.free_key_struct(keys); +} + +void +set_even_control_word(void *keys, const unsigned char *even) +{ + current.set_even_control_word(keys, even); +} + +void +set_odd_control_word(void *keys, const unsigned char *odd) +{ + current.set_odd_control_word(keys, odd); +} + +int +decrypt_packets(void *keys, unsigned char **cluster) +{ + return current.decrypt_packets(keys, cluster); +} diff --git a/src/ffdecsa/ffdecsa_mmx.c b/src/ffdecsa/ffdecsa_mmx.c new file mode 100644 index 000000000..71cdcc93b --- /dev/null +++ b/src/ffdecsa/ffdecsa_mmx.c @@ -0,0 +1,4 @@ +#if defined(__i386__) || defined(__x86_64__) +#define PARALLEL_MODE PARALLEL_64_MMX +#include "FFdecsa.c" +#endif diff --git a/src/ffdecsa/ffdecsa_sse2.c b/src/ffdecsa/ffdecsa_sse2.c new file mode 100644 index 000000000..af5868a3d --- /dev/null +++ b/src/ffdecsa/ffdecsa_sse2.c @@ -0,0 +1,4 @@ +#if defined(__i386__) || defined(__x86_64__) +#define PARALLEL_MODE PARALLEL_128_SSE2 +#include "FFdecsa.c" +#endif diff --git a/src/main.c b/src/main.c index a380431fe..9c471bcc7 100644 --- a/src/main.c +++ b/src/main.c @@ -58,6 +58,7 @@ #include "v4l.h" #include "parachute.h" #include "settings.h" +#include "ffdecsa/FFdecsa.h" int running; extern const char *htsversion; @@ -386,6 +387,8 @@ main(int argc, char **argv) dvr_init(); htsp_init(); + + ffdecsa_init(); if(rawts_input != NULL) rawts_init(rawts_input);