Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

UART IRQ is not received #166

Closed
sevenautumns opened this issue Jul 4, 2024 · 1 comment
Closed

UART IRQ is not received #166

sevenautumns opened this issue Jul 4, 2024 · 1 comment

Comments

@sevenautumns
Copy link

Hello, I've been trying to do the microkit tutorial with rust-sel4 but I've run into a problem with the interrupts of the UART in part1.
The problem is that while the writing to the UART works perfectly fine, the notification function is never called when typing in characters into QEMU. When I replace the elf file of the RUST serial_server with the tutorial native C serial_server it receives the interrupts.

C-program for verification that the irq can be set

#include <stdint.h>
#include <microkit.h>
#include "printf.h"

// This variable will have the address of the UART device
uintptr_t uart_base_vaddr;

#define RHR_MASK 0b111111111
#define UARTDR 0x000
#define UARTFR 0x018
#define UARTIMSC 0x038
#define UARTICR 0x044
#define PL011_UARTFR_TXFF (1 << 5)
#define PL011_UARTFR_RXFE (1 << 4)

#define REG_PTR(base, offset) ((volatile uint32_t *)((base) + (offset)))

void uart_init() {
    *REG_PTR(uart_base_vaddr, UARTIMSC) = 0x50;
}

int uart_get_char() {
    int ch = 0;

    if ((*REG_PTR(uart_base_vaddr, UARTFR) & PL011_UARTFR_RXFE) == 0) {
        ch = *REG_PTR(uart_base_vaddr, UARTDR) & RHR_MASK;
    }

    return ch;
}

void uart_put_char(int ch) {
    while ((*REG_PTR(uart_base_vaddr, UARTFR) & PL011_UARTFR_TXFF) != 0);

    *REG_PTR(uart_base_vaddr, UARTDR) = ch;
    if (ch == '\r') {
        uart_put_char('\n');
    }
}

void uart_handle_irq() {
    *REG_PTR(uart_base_vaddr, UARTICR) = 0x7f0;
}

void uart_put_str(char *str) {
    while (*str) {
        uart_put_char(*str);
        str++;
    }
}

void init(void) {
    // First we initialise the UART device, which will write to the
    // device's hardware registers. Which means we need access to
    // the UART device.
    uart_init();
    // After initialising the UART, print a message to the terminal
    // saying that the serial server has started.
    uart_put_str("SERIAL SERVER: starting\n");
}

void notified(microkit_channel channel) {
    uart_put_str("Notification");
}

Rust program which does not receive the irq and never enters the notified function

#![no_std]
#![no_main]

use core::ops::BitAnd;

use sel4_externally_shared::{access::ReadWrite, ExternallySharedRef, ExternallySharedRefExt};
use sel4_microkit::{memory_region_symbol, protection_domain, Channel, Handler, IrqAckError};

pub struct SerialServer {
    uart: ExternallySharedRef<'static, [u32], ReadWrite>,
}

impl SerialServer {
    const RHR_MASK: u32 = 0b111111111;
    const UARTDR: usize = 0x000;
    const UARTFR: usize = 0x018;
    const UARTIMSC: usize = 0x038;
    const UARTICR: usize = 0x044;
    const PL011_UARTFR_TXFF: u32 = (1 << 5);
    const PL011_UARTFR_RXFE: u32 = (1 << 4);
    const UART_SIZE: usize = 0x1_000;

    pub fn new() -> Self {
        let uart = unsafe {
            ExternallySharedRef::new(
                memory_region_symbol!(uart_base_vaddr: *mut [u32], n = Self::UART_SIZE),
            )
        };
        let mut serial_server = Self { uart };
        serial_server.init();
        serial_server
    }

    fn init(&mut self) {
        self.set_reg(Self::UARTIMSC, 0x50);
    }

    fn get_reg(&self, reg: usize) -> u32 {
        self.uart.as_ptr().index(reg).read()
    }

    fn set_reg(&mut self, reg: usize, value: u32) {
        self.uart.as_mut_ptr().index(reg).write(value)
    }

    pub fn get_char(&self) -> char {
        if self.get_reg(Self::UARTFR).bitand(Self::PL011_UARTFR_RXFE) != 0 {
            return 0 as char;
        }
        let ch = self.get_reg(Self::UARTDR).bitand(Self::RHR_MASK);
        core::char::from_u32(ch).unwrap_or_default()
    }

    pub fn put_char(&mut self, ch: char) {
        while self.get_reg(Self::UARTFR).bitand(Self::PL011_UARTFR_TXFF) != 0 {}
        self.set_reg(Self::UARTDR, ch as u32);
        if ch == '\r' {
            self.put_char('\n');
        }
    }

    pub fn handle_irq(&mut self) {
        self.set_reg(Self::UARTICR, 0x7f0);
    }

    pub fn put_str(&mut self, str: &str) {
        for ch in str.chars() {
            self.put_char(ch);
        }
    }
}

impl Default for SerialServer {
    fn default() -> Self {
        Self::new()
    }
}

#[protection_domain]
fn init() -> impl Handler {
    let mut server = SerialServer::new();
    server.put_str("SERIAL SERVER starting\n");
    server
}

const INPUT_CHANNEL: Channel = Channel::new(0);

impl Handler for SerialServer {
    type Error = IrqAckError;

    fn notified(&mut self, channel: Channel) -> Result<(), Self::Error> {
        self.put_str("got notification\n");
        match channel {
            INPUT_CHANNEL => {
                let ch = self.get_char();
                self.put_char(ch);
                self.handle_irq();
                channel.irq_ack()?;
            }
            _ => {
                todo!()
            }
        }
        Ok(())
    }
}
@sevenautumns sevenautumns changed the title Microkit Tutorial UART IRQ is not received UART IRQ is not received Jul 4, 2024
@sevenautumns
Copy link
Author

it looks like I forgot do divide the addresses of the registers by 4. sorry to bother you.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant