Stovent
Posts: 2
Joined: Mon Nov 19, 2018 9:45 pm

Segmentation fault while controlling GPIO in assembly

Mon Nov 19, 2018 10:04 pm

Hi all

I'm trying to control the GPIO in assembly. After a quick look at the ARM peripherals documentation, I wrote this program :

Code: Select all

.globl _start

_start:
	LDR r0, =0x20200000
	
	MOV r1, #0x200000
	STR r1, [r0, #4]
	
	MOV r1, #0x20000
	STR r1, [r0, #0x1C]
	
loop:
	B loop
However, I have a segmentation fault when executing the first STR (STR r1, [r0, #4])

Could someone explain me what I'm doing wrong please ?

Thanks,
Stovent

rst
Posts: 366
Joined: Sat Apr 20, 2013 6:42 pm
Location: Germany

Re: Segmentation fault while controlling GPIO in assembly

Wed Nov 21, 2018 2:43 pm

I guess, your code is running on Linux, because you wouldn't get a segmentation fault otherwise. You have to map the GPIO address space into the address space of your process to be able to access it, first. There is a mmap system call, with which you can do this mapping. I have only done this using C so far, so I do not have an assembly code snippet by hand and this would belong into the C / C++ programming forum.

Stovent
Posts: 2
Joined: Mon Nov 19, 2018 9:45 pm

Re: Segmentation fault while controlling GPIO in assembly

Fri Nov 23, 2018 11:18 pm

Using mmap fixed the problem, thanks.

I ended doing it in C because I couldn't find any documentation on system calls parameters in ARM .

rst
Posts: 366
Joined: Sat Apr 20, 2013 6:42 pm
Location: Germany

Re: Segmentation fault while controlling GPIO in assembly

Sun Nov 25, 2018 9:48 am

Stovent wrote:
Fri Nov 23, 2018 11:18 pm
I ended doing it in C because I couldn't find any documentation on system calls parameters in ARM .
Because I was interested in how system calls are implemented in Linux on ARM, I figured this out now. Here is a simple assembly program, which shows how to get access to the GPIOs:

Code: Select all

	.text

	.globl	_start
_start:
	ldr	r0, =gpiomem
	ldr	r1, =0x101002	/* O_RDWR | O_SYNC */
	mov	r7, #5		/* open */
	svc	#0
	mov	r4, r0		/* file descriptor */

	mov	r0, #0		/* kernel chooses address */
	mov	r1, #4096	/* map size */
	mov	r2, #3		/* PROT_READ | PROT_WRITE */
	mov	r3, #1		/* MAP_SHARED */
	mov	r5, #0		/* offset */
	mov	r7, #192	/* mmap2 */
	svc	#0

	/* access GPIOs via r0 */
	ldr	r1, [r0, #0x34]	/* read GPLEV0 */
	/* ... */

	mov	r0, #0		/* return code */
	mov	r7, #248	/* exit */
	svc	#0

	.data

gpiomem: .asciz	"/dev/gpiomem"

jahboater
Posts: 4196
Joined: Wed Feb 04, 2015 6:38 pm

Re: Segmentation fault while controlling GPIO in assembly

Sun Nov 25, 2018 9:54 am

You can do inline system calls in C with:-

Code: Select all

/*
 *  Get the terminal (window) size.
 *  Return non-zero if not a terminal.
 */
static int
screen_size( const int fd, struct winsize * const buf )
{
  register int rc reg( "w0" ) = fd,
               w1 reg( "w1" ) = TIOCGWINSZ,
               nr reg( "w8" ) = SYS_ioctl;
  register struct winsize *x2 reg( "x2" ) = buf;
  asm( "svc 0" : "+r" (rc) : "r" (nr), "r" (w1), "r" (x2) : "memory" );
  return rc;
}
Its much easier on x86 because you have named registers in the constraints.

rst
Posts: 366
Joined: Sat Apr 20, 2013 6:42 pm
Location: Germany

Re: Segmentation fault while controlling GPIO in assembly

Sun Nov 25, 2018 10:24 am

jahboater wrote:
Sun Nov 25, 2018 9:54 am
You can do inline system calls in C with:-
...
Its much easier on x86 because you have named registers in the constraints.
Yes, but the intention here was to do it with bare assembly language. Normally one would probably do this from C by simply calling open() and mmap().

bkl
Posts: 1
Joined: Fri Feb 15, 2019 7:07 pm

Re: Segmentation fault while controlling GPIO in assembly

Fri Feb 15, 2019 7:10 pm

Hi rst,

your assembler snippet worked just fine for my GPIO accessing problem. But how does the code has to be changed if I want to access the ARMTimer of the Raspberry Pi, too? Would be awesome if you could help me out with this. I'm not able to figure it out.

Thanks!

rst
Posts: 366
Joined: Sat Apr 20, 2013 6:42 pm
Location: Germany

Re: Segmentation fault while controlling GPIO in assembly

Sat Feb 16, 2019 11:09 am

bkl wrote:
Fri Feb 15, 2019 7:10 pm
But how does the code has to be changed if I want to access the ARMTimer of the Raspberry Pi, too?
The code has to be changed as follows:

Code: Select all

	.text

	.globl	_start
_start:
	ldr	r0, =mem
	ldr	r1, =0x101002	/* O_RDWR | O_SYNC */
	mov	r7, #5		/* open */
	svc	#0
	mov	r4, r0		/* file descriptor */

	mov	r0, #0		/* kernel chooses address */
	mov	r1, #4096	/* map size */
	mov	r2, #3		/* protection */
	mov	r3, #1		/* shared */
	ldr	r5, =0x3F003	/* offset */
	mov	r7, #192	/* mmap2 */
	svc	#0

	/* access ARM timer via r0 */
	ldr	r1, [r0, #0x04]	/* read CLO */

	mov	r0, #0		/* return code */
	mov	r7, #248	/* exit */
	svc	#0

	.data

mem: .asciz	"/dev/mem"
The ARM timer cannot be accessed via /dev/gpiomem, so we have to use /dev/mem. This does only work with root privileges (sudo). The offset handed over to the mmap2 system call must be 0x3F003 on the RPi 2 and 3 (0x20003 on the RPi 1 and Zero). It is expressed in 0x1000 byte sized page units. The CLO timer register can be read at offset 0x04 of the mapped memory range then.

Return to “Bare metal, Assembly language”