2014-02-05 17:48:26 +04:00
# include "defs.h"
2015-02-20 00:16:45 +03:00
# include "xlat/kexec_load_flags.h"
2014-04-26 03:30:54 +04:00
# include "xlat/kexec_arch_values.h"
2015-02-20 00:16:45 +03:00
# ifndef KEXEC_ARCH_MASK
# define KEXEC_ARCH_MASK 0xffff0000
# endif
# ifndef KEXEC_SEGMENT_MAX
# define KEXEC_SEGMENT_MAX 16
# endif
2014-02-05 17:48:26 +04:00
static void
2015-07-20 04:20:44 +03:00
print_seg ( const long seg_buf , const unsigned long seg_bufsz ,
const long seg_mem , const unsigned long seg_memsz )
{
tprints ( " { " ) ;
printaddr ( seg_buf ) ;
tprintf ( " , %lu, " , seg_bufsz ) ;
printaddr ( seg_mem ) ;
tprintf ( " , %lu} " , seg_memsz ) ;
}
static void
print_kexec_segments ( struct tcb * tcp , const unsigned long addr ,
const unsigned long len )
2014-02-05 17:48:26 +04:00
{
# if SUPPORTED_PERSONALITIES > 1
union {
struct { u_int32_t buf , bufsz , mem , memsz ; } seg32 ;
struct { u_int64_t buf , bufsz , mem , memsz ; } seg64 ;
} seg ;
# define sizeof_seg \
( current_wordsize = = 4 ? sizeof ( seg . seg32 ) : sizeof ( seg . seg64 ) )
# define seg_buf \
( current_wordsize = = 4 ? ( uint64_t ) seg . seg32 . buf : seg . seg64 . buf )
# define seg_bufsz \
( current_wordsize = = 4 ? ( uint64_t ) seg . seg32 . bufsz : seg . seg64 . bufsz )
# define seg_mem \
( current_wordsize = = 4 ? ( uint64_t ) seg . seg32 . mem : seg . seg64 . mem )
# define seg_memsz \
( current_wordsize = = 4 ? ( uint64_t ) seg . seg32 . memsz : seg . seg64 . memsz )
# else
2015-02-20 00:16:45 +03:00
struct {
void * buf ;
size_t bufsz ;
void * mem ;
size_t memsz ;
} seg ;
2014-02-05 17:48:26 +04:00
# define sizeof_seg sizeof(seg)
2014-02-07 01:13:36 +04:00
# define seg_buf seg.buf
# define seg_bufsz seg.bufsz
# define seg_mem seg.mem
# define seg_memsz seg.memsz
2014-02-05 17:48:26 +04:00
# endif
2015-07-20 04:20:44 +03:00
unsigned int i ;
2014-02-05 17:48:26 +04:00
if ( ! len ) {
tprints ( " [] " ) ;
return ;
}
if ( len > KEXEC_SEGMENT_MAX ) {
2015-07-20 04:20:44 +03:00
printaddr ( addr ) ;
2014-02-05 17:48:26 +04:00
return ;
}
2015-07-20 04:20:44 +03:00
if ( umoven_or_printaddr ( tcp , addr , sizeof_seg , & seg ) )
return ;
2014-02-05 17:48:26 +04:00
tprints ( " [ " ) ;
2015-07-20 04:20:44 +03:00
print_seg ( ( unsigned long ) seg_buf , seg_bufsz ,
( unsigned long ) seg_mem , seg_memsz ) ;
for ( i = 1 ; i < len ; + + i ) {
tprints ( " , " ) ;
if ( umoven_or_printaddr ( tcp , addr + i * sizeof_seg ,
sizeof_seg , & seg ) )
2014-02-05 17:48:26 +04:00
break ;
2015-07-20 04:20:44 +03:00
print_seg ( ( unsigned long ) seg_buf , seg_bufsz ,
( unsigned long ) seg_mem , seg_memsz ) ;
2014-02-05 17:48:26 +04:00
}
2015-07-20 04:20:44 +03:00
2014-02-05 17:48:26 +04:00
tprints ( " ] " ) ;
}
2015-04-07 04:36:50 +03:00
SYS_FUNC ( kexec_load )
2014-02-05 17:48:26 +04:00
{
unsigned long n ;
/* entry, nr_segments */
2015-07-20 04:20:44 +03:00
printaddr ( tcp - > u_arg [ 0 ] ) ;
tprintf ( " , %lu, " , tcp - > u_arg [ 1 ] ) ;
2014-02-05 17:48:26 +04:00
/* segments */
print_kexec_segments ( tcp , tcp - > u_arg [ 2 ] , tcp - > u_arg [ 1 ] ) ;
tprints ( " , " ) ;
/* flags */
n = tcp - > u_arg [ 3 ] ;
printxval ( kexec_arch_values , n & KEXEC_ARCH_MASK , " KEXEC_ARCH_??? " ) ;
n & = ~ KEXEC_ARCH_MASK ;
if ( n ) {
tprints ( " | " ) ;
2015-02-20 00:16:45 +03:00
printflags ( kexec_load_flags , n , " KEXEC_??? " ) ;
2014-02-05 17:48:26 +04:00
}
2015-07-20 04:20:44 +03:00
return RVAL_DECODED ;
2014-02-05 17:48:26 +04:00
}