Register writes to UART register in util_libs driver is not working on seL4

Hi Team,
I am working on bringing up on seL4 on one of the ARM based 64bit architecture.
Able to get serial up and running in elf-loader and kernel, in both cases initialization is used from u-boot and putchar is used for serial prints. Now i am creating new driver for uart in util_libs.
Below are the queries.

  1. There is no “ps_fdt_read_path” function in uart driver to read details from device tree. so hardcoded irq and address in chardev.c, is it fine ?
  2. clocks are not enabled yet. using “sel4test” for validating the serial from userspace. Disabled “LIB_SEL4_PLAT_SUPPORT_USE_SEL4_DEBUG_PUTCHAR” to redirect prints to userspace
    seL4 version: 13.0
    When reading any register, no issue. But when i am writing to any UART register getting below error.
    ctrl = base->lincr1;
    ctrl |= LINCR1_INIT;
    base->lincr1 = ctrl; /* Writing into this register,gave below error*/

halting…
Kernel entry via Syscall, number: 1, Call
Cap type: 31, Invocation tag: 1

What can be the reason for this error.

I think most just hard-code the IRQ and peripheral address. It may be possible to get a DTB passed to the rootserver and parsing that for info in user space, but you will need to put some effort into getting that to work.

How to enable clocks is hardware dependent and depends on the SoC. In my experience writing registers to a clock disabled domain just didn’t work, but it didn’t cause faults though.

The error message hints it is not the memory write causing the fault, but a syscall on an invalid cap (valid cap types can be found in build/kernel/generated/arch/object/structures_gen.h). But more likely the debug info is just wrong, and it is the write causing a fault.

Then you’re probably getting an SError, which is handled by halting in seL4. You can try enabling KernelAArch64SErrorIgnore in your platform cmake file and see if it makes a difference, then the write should just silently fail instead.

Reads of invalid peripheral addresses cause normal synchronous faults, but writes usually cause asynchronous faults which arrive as SErrors. If you don’t want a random write of peripheral space to halt the whole system, you need to set KernelAArch64SErrorIgnore (but because of a bug you can only set it in your platform’s config file and not as a user).

Hi Indan,
Thank you for the response.
clocks are taken from uboot until now, we need to re-initialize the clock.
when i disable KernelAArch64SErrorIgnore. error is ignored. But finally need to understand the reason for this error, this write is happening from “uart_init” function in serial.c

I guess the reason is either because you’re accidentally writing a read-only register, or your system gives SErrors for peripherals with clocks disabled.

The uart_init function probably can’t enable the clocks, as it’s SoC dependent how to do that, so the UART won’t know that, it’s just a UART driver, not a clock driver.

Hi Indan,

Thanks for the response, I am writing to control register(R/W).
coming to clocks. I have taken (./projects/util_libs/libplatsupport/src/plat/zynq7000/clock.c) as example.But unable to find from where clocks are intialized(clock_sys_init).

Are you trying to get the same UART working in user space, or a different one?

If a different one, in addition to enabling and configuring the peripheral clock (which is not the same as the UART clocking configuration!), you may also need to power on the UART.

If it is the same UART and it’s used by Uboot then it should be working already. If you just want to change the baud rate or some other configuration, just follow the UART’s datasheet information. It may want you to disable the UART first before reconfiguring it.

All this is basic board bring-up/embedded programming, nothing seL4 specific about this.

If you want to know what you need to do to get your UART working, read the SoC datasheet and perhaps look at the U-boot code. Looking at seL4 user space code may not be the best because they may assume the UART was used by U-boot, so it won’t need to do peripheral power and clock configurations.

Hi Indan,
Thanks for the response.
It is same as u-boot UART.
We are able to get prints from elf-loader and kernel. But in user space we want to re-initialize the UART. facing issue in the init code.

Then try disabling the UART before reconfiguring it. And double check you mapped the register memory uncached.

Hi Indan,

I have disabled UART re-initialization code, just putchar.

  1. uncached memory, used all register writes using volatile.
  2. converted from paddr to vaddr using below function.

void vaddr = chardev_map(defn, ops);
** if (vaddr == NULL) {
*
** return -1;**
** }**
Still observing the issue.
Error:
halting…
Kernel entry via Syscall, number: 1, Call
Cap type: 1, Invocation tag: 37

You can use seL4_ARM_Page_GetAddress on the page cap to check whether the physical address matches your UART’s.

Another thing you can do is reading the registers and see if the content is as expected. If not, you’re mapping the wrong address. Another advantage of doing reads is that any errors are synchronous.

Hi Indan,
Thanks for the input.
I am using seL4test for testing this driver.
When i use “LIB_SEL4_PLAT_SUPPORT_USE_SEL4_DEBUG_PUTCHAR”, it is using kernel driver and “ps_cdev_init” is bypassed.
When i disable “LIB_SEL4_PLAT_SUPPORT_USE_SEL4_DEBUG_PUTCHAR”, ps_cdev_init is called. but none of the logging mechanism is working, as it is redirected to userspace serial driver.
Is there anyway i can still get prints from serial.c when LIB_SEL4_PLAT_SUPPORT_USE_SEL4_DEBUG_PUTCHAR is disabled.

Is there anyway i can still get prints from serial.c when LIB_SEL4_PLAT_SUPPORT_USE_SEL4_DEBUG_PUTCHAR is disabled.

Enable debug prints in the kernel and use seL4_DebugPutChar.

Or send your debug text via Ethernet, I2C or anything else you can monitor.

Or try debugging your problem in QEMU first.

But I’d try keeping LIB_SEL4_PLAT_SUPPORT_USE_SEL4_DEBUG_PUTCHAR enabled first and debug the issue separately, if possible. I can’t remember if seL4 reserves the UART memory region for itself or whether you could share it with user space, but I think it can be shared when kernel printing is enabled.