Skip to content
Projects
Groups
Snippets
Help
Loading...
Sign in
Toggle navigation
W
White Rabbit Switch - Software
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
84
Issues
84
List
Board
Labels
Milestones
Merge Requests
4
Merge Requests
4
CI / CD
CI / CD
Pipelines
Schedules
Wiki
Wiki
image/svg+xml
Discourse
Discourse
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Commits
Issue Boards
Open sidebar
Projects
White Rabbit Switch - Software
Commits
0371a420
Commit
0371a420
authored
Sep 11, 2014
by
Alessandro Rubini
Browse files
Options
Browse Files
Download
Plain Diff
Merge branch 'lm32-elf-loader'
parents
9e31590c
1bb48fcb
Show whitespace changes
Inline
Side-by-side
Showing
11 changed files
with
372 additions
and
176 deletions
+372
-176
wrs-build.in
doc/wrs-build.in
+6
-3
nm
userspace/rootfs_override/usr/bin/nm
+0
-0
libbfd-2.21.1.so
userspace/rootfs_override/usr/lib/libbfd-2.21.1.so
+0
-0
Makefile
userspace/tools/Makefile
+1
-1
libtools.h
userspace/tools/libtools.h
+0
-1
lm32-loader.c
userspace/tools/lm32-loader.c
+0
-154
load-fpga.c
userspace/tools/load-fpga.c
+3
-2
load-lm32.c
userspace/tools/load-lm32.c
+352
-3
mapper.c
userspace/tools/mapper.c
+0
-1
rtu_stat.c
userspace/tools/rtu_stat.c
+10
-10
wmapper.c
userspace/tools/wmapper.c
+0
-1
No files found.
doc/wrs-build.in
View file @
0371a420
...
...
@@ -35,7 +35,7 @@
@setchapternewpage off
@set update-month
August
2014
@set update-month
September
2014
@c the release name below is substituted at build time
@set release __RELEASE_GIT_ID__
...
...
@@ -1346,8 +1346,11 @@ The most important tools in @file{userspace/tools} are the following:
@itemx load-lm32
They load into the FPGA the gateware and the LM32 application.
They are used by the init scripts of the Linux system.
They are used by the init scripts of the Linux system. The LM32
loader can also change variables in the loaded binary, and
read or write variables without stopping the running CPU.
This is limited to 32-bit integer variaables, though. See the
commit message for details.
@item mapper
@itemx wmapper
...
...
userspace/rootfs_override/usr/bin/nm
0 → 100755
View file @
0371a420
File added
userspace/rootfs_override/usr/lib/libbfd-2.21.1.so
0 → 100755
View file @
0371a420
File added
userspace/tools/Makefile
View file @
0371a420
...
...
@@ -59,7 +59,7 @@ spll_dbg_proxy: spll_dbg_proxy.o
load-virtex
:
load-virtex.o load-fpga.o
${
CC
}
-o
$@
$^
$(LDFLAGS)
load-lm32
:
load-lm32.o
lm32-loader.o
load-lm32
:
load-lm32.o
${
CC
}
-o
$@
$^
$(LDFLAGS)
wrsw_version.o
:
wrsw_version.c
...
...
userspace/tools/libtools.h
View file @
0371a420
extern
int
load_lm32_main
(
char
*
fname
);
extern
int
load_fpga_main
(
char
*
fname
);
userspace/tools/lm32-loader.c
deleted
100644 → 0
View file @
9e31590c
/*
* Copyright (c) 2011 Grzegorz Daniluk <g.daniluk@elproma.com.pl>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <sys/mman.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/wait.h>
#define BASE_FPGA 0x10000000
#define SIZE_FPGA 0x20000
#define LM32_RAM_BASE 0x0
#define GPIO_BASE 0x10300
#define GPIO_COR 0x0
#define GPIO_SOR 0x4
#define LM32_RESET_PIN 2
static
void
*
base_fpga
;
static
void
fpga_writel
(
uint32_t
data
,
uint32_t
addr
)
{
*
(
volatile
uint32_t
*
)(
base_fpga
+
addr
)
=
data
;
}
static
uint32_t
fpga_readl
(
uint32_t
addr
)
{
return
*
(
volatile
uint32_t
*
)(
base_fpga
+
addr
);
}
int
conv_endian
(
int
x
)
{
return
((
x
&
0xff000000
)
>>
24
)
+
((
x
&
0x00ff0000
)
>>
8
)
+
((
x
&
0x0000ff00
)
<<
8
)
+
((
x
&
0x000000ff
)
<<
24
);
}
void
rst_lm32
(
int
rst
)
{
fpga_writel
(
1
<<
LM32_RESET_PIN
,
GPIO_BASE
+
(
rst
?
GPIO_SOR
:
GPIO_COR
));
}
void
copy_lm32
(
uint32_t
*
buf
,
int
buf_nwords
,
uint32_t
base_addr
)
{
int
i
;
printf
(
"Writing memory: "
);
for
(
i
=
0
;
i
<
buf_nwords
;
i
++
)
{
fpga_writel
(
conv_endian
(
buf
[
i
]),
base_addr
+
i
*
4
);
if
(
!
(
i
&
0xfff
))
{
printf
(
"."
);
fflush
(
stdout
);
}
}
printf
(
"
\n
Verifing memory: "
);
for
(
i
=
0
;
i
<
buf_nwords
;
i
++
)
{
uint32_t
x
=
fpga_readl
(
base_addr
+
i
*
4
);
if
(
conv_endian
(
buf
[
i
])
!=
x
)
{
printf
(
"Verify failed (%x vs %x)
\n
"
,
conv_endian
(
buf
[
i
]),
x
);
return
;
}
if
(
!
(
i
&
0xfff
))
{
printf
(
"."
);
fflush
(
stdout
);
}
}
printf
(
"OK.
\n
"
);
}
int
load_lm32_child
(
char
*
fname
)
{
uint32_t
*
buf
;
FILE
*
f
;
int
fdmem
;
/* /dev/mem for mmap of both gpio and spi1 */
if
((
fdmem
=
open
(
"/dev/mem"
,
O_RDWR
|
O_SYNC
))
<
0
)
{
fprintf
(
stderr
,
"%s: /dev/mem: %s
\n
"
,
__func__
,
strerror
(
errno
));
exit
(
1
);
}
/* map a whole page (4kB, but we called getpagesize to know it) */
base_fpga
=
mmap
(
0
,
SIZE_FPGA
,
PROT_READ
|
PROT_WRITE
,
MAP_SHARED
,
fdmem
,
BASE_FPGA
);
if
(
base_fpga
==
MAP_FAILED
)
{
fprintf
(
stderr
,
"%s: mmap(/dev/mem): %s
\n
"
,
__func__
,
strerror
(
errno
));
exit
(
1
);
}
f
=
fopen
(
fname
,
"rb"
);
if
(
!
f
)
{
fprintf
(
stderr
,
"Input file not found.
\n
"
);
return
-
1
;
}
fseek
(
f
,
0
,
SEEK_END
);
int
size
=
ftell
(
f
);
rewind
(
f
);
buf
=
malloc
(
size
+
4
);
fread
(
buf
,
1
,
size
,
f
);
fclose
(
f
);
rst_lm32
(
1
);
copy_lm32
(
buf
,
(
size
+
3
)
/
4
,
0
);
rst_lm32
(
0
);
// mbn_stats(mb_handle);
return
0
;
}
int
load_lm32_main
(
char
*
fname
)
{
int
pid
=
fork
();
int
status
;
switch
(
pid
)
{
case
-
1
:
fprintf
(
stderr
,
"fork(): %s
\n
"
,
strerror
(
errno
));
return
-
1
;
case
0
:
/* child */
load_lm32_child
(
fname
);
exit
(
0
);
default:
/* parent */
waitpid
(
pid
,
&
status
,
0
);
if
(
!
WEXITSTATUS
(
status
))
return
0
;
return
-
1
;
}
}
userspace/tools/load-fpga.c
View file @
0371a420
...
...
@@ -313,7 +313,8 @@ int load_fpga_main(char *fname)
fprintf
(
stderr
,
"fork(): %s
\n
"
,
strerror
(
errno
));
return
-
1
;
case
0
:
/* child */
load_fpga_child
(
fname
);
if
(
load_fpga_child
(
fname
))
exit
(
1
);
exit
(
0
);
default:
/* parent */
waitpid
(
pid
,
&
status
,
0
);
...
...
userspace/tools/load-lm32.c
View file @
0371a420
/*
* Copyright (c) 2011 Grzegorz Daniluk <g.daniluk@elproma.com.pl>
* ELF support added by Alessandro Rubini for CERN, 2014
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#include <stdio.h>
#include "libtools.h"
#include <stdlib.h>
#include <stdint.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <elf.h>
#include <sys/mman.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include <arpa/inet.h>
/* htonl */
#define BASE_FPGA 0x10000000
#define SIZE_FPGA 0x20000
#define LM32_RAM_BASE 0x0
#define GPIO_BASE 0x10300
#define GPIO_COR 0x0
#define GPIO_SOR 0x4
#define LM32_RESET_PIN 2
static
void
*
base_fpga
;
static
char
*
prgname
;
static
void
fpga_writel
(
uint32_t
data
,
uint32_t
addr
)
{
*
(
volatile
uint32_t
*
)(
base_fpga
+
addr
)
=
data
;
}
static
uint32_t
fpga_readl
(
uint32_t
addr
)
{
return
*
(
volatile
uint32_t
*
)(
base_fpga
+
addr
);
}
/* The original "conv_endian" was bound to 32 bits. This is any-size */
#define BE(datum) \
({ __typeof__(datum) result; \
switch(sizeof(datum)) { \
case 1: result = (datum); break; \
case 2: result = htons((datum)); break; \
case 4: result = htonl((datum)); break; \
default: kill(getpid(), SIGUSR1); \
} \
result; \
})
static
void
rst_lm32
(
int
rst
)
{
fpga_writel
(
1
<<
LM32_RESET_PIN
,
GPIO_BASE
+
(
rst
?
GPIO_SOR
:
GPIO_COR
));
}
static
int
copy_lm32
(
void
*
data
,
int
noload
,
int
size
,
uint32_t
base_addr
)
{
int
i
;
uint32_t
*
buf
=
data
;
/* be 32-bit oriented in writing */
int
buf_nwords
=
(
size
+
3
)
/
4
;
/* Do not actually load anything. This is used to read/write variables */
if
(
noload
)
return
0
;
printf
(
"Writing memory (0x%04x bytes at 0x%04x): "
,
size
,
base_addr
);
for
(
i
=
0
;
i
<
buf_nwords
;
i
++
)
{
fpga_writel
(
BE
(
buf
[
i
]),
base_addr
+
i
*
4
);
if
(
!
(
i
&
0xfff
))
printf
(
"."
);
}
printf
(
"
\n
Verifing memory: "
);
for
(
i
=
0
;
i
<
buf_nwords
;
i
++
)
{
uint32_t
x
=
fpga_readl
(
base_addr
+
i
*
4
);
if
(
BE
(
buf
[
i
])
!=
x
)
{
printf
(
"Verify failed (%x vs %x)
\n
"
,
BE
(
buf
[
i
]),
x
);
return
-
1
;
}
if
(
!
(
i
&
0xfff
))
printf
(
"."
);
}
printf
(
" OK.
\n
"
);
return
0
;
}
static
char
*
global_strptr
;
static
Elf32_Shdr
*
global_sh
;
/* The elf loader relies on the binary loader above (and the global mmap) */
static
int
copy_lm32_elf
(
void
*
data
,
int
noload
,
int
size
)
{
int
i
,
flags
,
verbose
=
getenv
(
"LOAD_LM32_VERBOSE"
)
!=
NULL
;
Elf32_Ehdr
*
eh
;
Elf32_Phdr
*
ph
;
Elf32_Shdr
*
sh
;
char
*
strptr
;
eh
=
data
;
if
(
verbose
)
{
printf
(
"type: %8i
\n
"
,
BE
(
eh
->
e_type
));
printf
(
"machine: %8i
\n
"
,
BE
(
eh
->
e_machine
));
printf
(
"version: %8i
\n
"
,
BE
(
eh
->
e_version
));
printf
(
"entry: %08lx
\n
"
,
(
long
)
BE
(
eh
->
e_entry
));
printf
(
"phoff: %8i
\n
"
,
BE
(
eh
->
e_phoff
));
printf
(
"shoff: %8i
\n
"
,
BE
(
eh
->
e_shoff
));
printf
(
"ehsize: %8i
\n
"
,
BE
(
eh
->
e_ehsize
));
printf
(
"shstrndx:%8i
\n
"
,
BE
(
eh
->
e_shstrndx
));
}
ph
=
(
Elf32_Phdr
*
)((
char
*
)
eh
+
(
int
)(
BE
(
eh
->
e_phoff
)));
/* program headers. Irrelevant, actually... */
for
(
i
=
0
;
i
<
BE
(
eh
->
e_phnum
);
i
++
)
{
flags
=
BE
(
ph
->
p_flags
);
if
(
verbose
)
{
printf
(
"prg: %i 0x%08lx, 0x%08lx, 0x%08lx, %c%c%c "
"(%08x), %i, %i %i
\n
"
,
BE
(
ph
->
p_type
),
(
long
)(
BE
(
ph
->
p_offset
)),
(
long
)(
BE
(
ph
->
p_vaddr
)),
(
long
)(
BE
(
ph
->
p_paddr
)),
flags
&
PF_R
?
'r'
:
'-'
,
flags
&
PF_W
?
'w'
:
'-'
,
flags
&
PF_X
?
'x'
:
'-'
,
flags
,
BE
(
ph
->
p_filesz
),
BE
(
ph
->
p_memsz
),
BE
(
ph
->
p_align
));
}
}
/* first loop: look for strtab */
sh
=
(
Elf32_Shdr
*
)((
char
*
)
eh
+
(
int
)(
BE
(
eh
->
e_shoff
)));
for
(
i
=
0
;
i
<
BE
(
eh
->
e_shstrndx
);
i
++
)
sh
=
(
Elf32_Shdr
*
)((
char
*
)
sh
+
(
int
)
BE
(
eh
->
e_shentsize
));
strptr
=
(
char
*
)
eh
+
BE
(
sh
->
sh_offset
);
sh
=
(
Elf32_Shdr
*
)((
char
*
)
eh
+
(
int
)(
BE
(
eh
->
e_shoff
)));
/* Save them for later (setting vriables) */
global_strptr
=
strptr
;
global_sh
=
sh
;
/* Section headers: this is what we load */
for
(
i
=
0
;
i
<
BE
(
eh
->
e_shnum
);
i
++
)
{
unsigned
long
off
,
len
,
ram
;
if
(
i
)
/* next header */
sh
=
(
Elf32_Shdr
*
)((
char
*
)
sh
+
(
int
)
BE
(
eh
->
e_shentsize
));
if
(
verbose
)
{
printf
(
"sect: %3i %-25.25s %2i 0x%08lx, 0x%08lx, (%i) %i %i
\n
"
,
BE
(
sh
->
sh_name
),
strptr
+
BE
(
sh
->
sh_name
),
BE
(
sh
->
sh_type
),
(
long
)(
BE
(
sh
->
sh_offset
)),
(
long
)(
BE
(
sh
->
sh_addr
)),
BE
(
sh
->
sh_size
),
BE
(
sh
->
sh_addralign
),
BE
(
sh
->
sh_entsize
));
}
off
=
BE
(
sh
->
sh_offset
);
len
=
BE
(
sh
->
sh_size
);
ram
=
BE
(
sh
->
sh_addr
)
&
0x0fffffff
;
/* ignore unloadable sections */
if
(
BE
(
sh
->
sh_type
)
!=
SHT_PROGBITS
)
continue
;
if
(
!
(
BE
(
sh
->
sh_flags
)
&
SHF_ALLOC
))
continue
;
if
(
len
==
0
)
continue
;
/*
* First argument is base in file, third is offset
* in both fpga and file, so adjust file base (hack)
*/
if
(
copy_lm32
(
data
+
off
,
noload
,
len
,
ram
))
return
-
1
;
}
return
0
;
}
int
load_lm32
(
char
*
fname
,
int
noload
)
{
void
*
buf
;
FILE
*
f
;
int
iself
,
ret
;
f
=
fopen
(
fname
,
"rb"
);
if
(
!
f
)
{
fprintf
(
stderr
,
"%s: %s: %s
\n
"
,
prgname
,
fname
,
strerror
(
errno
));
return
-
1
;
}
fseek
(
f
,
0
,
SEEK_END
);
int
size
=
ftell
(
f
);
rewind
(
f
);
buf
=
malloc
(
size
+
4
);
ret
=
fread
(
buf
,
1
,
size
,
f
);
fclose
(
f
);
if
(
ret
!=
size
)
{
fprintf
(
stderr
,
"%s: %s: read error (
\n
"
,
prgname
,
fname
);
return
-
1
;
}
if
(
!
memcmp
(
buf
,
ELFMAG
,
SELFMAG
))
iself
=
1
;
else
if
(
!
memcmp
(
buf
,
"
\x98\0\0\0
"
,
4
))
iself
=
0
;
else
{
fprintf
(
stderr
,
"%s: %s: Unrecognized file type
\n
"
,
prgname
,
fname
);
return
-
1
;
}
/*
* If ELF, we need to call the function even if (noload)
* because the function parses ELF and sets global variables.
* To the same to the binary loader for symmetry.
*/
if
(
iself
)
ret
=
copy_lm32_elf
(
buf
,
noload
,
size
);
else
ret
=
copy_lm32
(
buf
,
noload
,
size
,
0
);
free
(
buf
);
return
ret
;
}
/* Set, or read, a variable. We already loaded to memory the file */
static
int
varaction_lm32
(
char
*
fname
,
char
*
action
)
{
char
vname
[
64
],
sname
[
64
];
char
stmp
[
256
];
int
i
,
write
,
vvalue
,
saddr
;
FILE
*
f
;
char
eq
;
if
(
!
global_strptr
)
{
fprintf
(
stderr
,
"%s: Can't execute
\"
%s
\"
on a non-elf file
\n
"
,
prgname
,
action
);
return
-
1
;
}
i
=
sscanf
(
action
,
"%[^=]%c%i"
,
vname
,
&
eq
,
&
vvalue
);
if
(
i
<
2
||
eq
!=
'='
)
{
fprintf
(
stderr
,
"%s: Can't parse action
\"
%s
\"\n
"
,
prgname
,
action
);
return
-
1
;
}
if
(
i
==
3
)
write
=
1
;
else
write
=
0
;
/* Open "nm" (lazy me)" to find the variable's address */
sprintf
(
stmp
,
"nm %s"
,
fname
);
f
=
popen
(
stmp
,
"r"
);
if
(
!
f
)
{
fprintf
(
stderr
,
"%s: Can't run
\"
%s
\"
(%s)
\n
"
,
prgname
,
stmp
,
strerror
(
errno
));
return
-
1
;
}
while
(
fgets
(
stmp
,
sizeof
(
stmp
),
f
))
{
if
(
sscanf
(
stmp
,
"%x %*c %s"
,
&
saddr
,
sname
)
!=
2
)
continue
;
if
(
!
strcmp
(
vname
,
sname
))
break
;
}
if
(
feof
(
f
))
{
fprintf
(
stderr
,
"%s: no symbol
\"
%s
\"
int
\"
%s
\"\n
"
,
prgname
,
sname
,
fname
);
pclose
(
f
);
return
-
1
;
}
pclose
(
f
);
/* NOTE: we must not convert endianness here: it's bitwise ok */
if
(
write
)
{
/* FIXME: check it is in a writable section */
fpga_writel
(
vvalue
,
saddr
);
}
else
{
vvalue
=
fpga_readl
(
saddr
);
printf
(
"%s = %i (0x%08x)
\n
"
,
vname
,
vvalue
,
vvalue
);
}
return
0
;
}
int
main
(
int
argc
,
char
**
argv
)
{
int
fdmem
,
ret
;
int
i
,
noload
=
0
;
prgname
=
argv
[
0
];
if
(
argc
>
1
&&
!
strcmp
(
argv
[
1
],
"-n"
))
{
noload
=
1
;
argv
++
;
argc
--
;
}
if
(
argc
<
2
)
{
fprintf
(
stderr
,
"Use:
\"
%s <filename>
\"\n
"
,
argv
[
0
]);
fprintf
(
stderr
,
"%s: Use:
\"
%s [-n] <filename> "
"[<var>=<value> ...]
\"\n
"
,
prgname
,
prgname
);
}
setbuffer
(
stdout
,
NULL
,
0
);
if
((
fdmem
=
open
(
"/dev/mem"
,
O_RDWR
|
O_SYNC
))
<
0
)
{
fprintf
(
stderr
,
"%s: /dev/mem: %s
\n
"
,
prgname
,
strerror
(
errno
));
exit
(
1
);
}
base_fpga
=
mmap
(
0
,
SIZE_FPGA
,
PROT_READ
|
PROT_WRITE
,
MAP_SHARED
,
fdmem
,
BASE_FPGA
);
close
(
fdmem
);
if
(
base_fpga
==
MAP_FAILED
)
{
fprintf
(
stderr
,
"%s: mmap(/dev/mem): %s
\n
"
,
prgname
,
strerror
(
errno
));
exit
(
1
);
}
return
load_lm32_main
(
argv
[
1
]);
if
(
!
noload
)
rst_lm32
(
1
);
ret
=
load_lm32
(
argv
[
1
],
noload
);
if
(
ret
)
exit
(
1
);
for
(
i
=
2
;
i
<
argc
;
i
++
)
if
(
varaction_lm32
(
argv
[
1
],
argv
[
i
]))
exit
(
1
);
if
(
!
noload
)
rst_lm32
(
0
);
return
0
;
}
userspace/tools/mapper.c
View file @
0371a420
...
...
@@ -64,4 +64,3 @@ int main(int argc, char **argv)
}
return
0
;
}
userspace/tools/rtu_stat.c
View file @
0371a420
userspace/tools/wmapper.c
View file @
0371a420
...
...
@@ -64,4 +64,3 @@ int main(int argc, char **argv)
}
return
0
;
}
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment