rtic/book/ru/src/internals/access.md
2021-04-08 12:22:43 +03:00

5.9 KiB
Raw Blame History

Контроль доступа

Одна из основ RTIC - контроль доступа. Контроль того, какая часть программы может получить доступ к какой статической переменной - инструмент обеспечения безопасности памяти.

Статические переменные используются для разделения состояний между обработчиками прерываний, или между обработчиком прерывания и нижним контекстом выполнения, main. В обычном Rust коде трудно обеспечить гранулированный контроль за тем, какие функции могут получать доступ к статическим переменным, поскольку к статическим переменным можно получить доступ из любой функции, находящейся в той же области видимости, в которой они определены. Модули дают частичный контроль над доступом к статическим переменным, но они недостаточно гибкие.

Чтобы добиться полного контроля за тем, что задачи могут получить доступ только к статическим переменным (ресурсам), которые им были указаны в RTIC атрибуте, фреймворк RTIC производит трансформацию структуры кода. Эта трансформация состоит из размещения ресурсов (статических переменных), определенных пользователем внутри модуля, а пользовательского кода вне модуля. Это делает невозможным обращение пользовательского кода к статическим переменным.

Затем доступ к ресурсам предоставляется каждой задаче с помощью структуры Resources, чьи поля соответствуют ресурсам, к которым получает доступ задача. Есть лишь одна такая структура на задачу и структура Resources инициализируется либо уникальной ссылкой (&mut-) на статическую переменную, либо с помощью прокси-ресурса (см. раздел критические секции).

Код ниже - пример разных трансформаций структуры кода, происходящих за сценой:

#[rtic::app(device = ..)]
mod app {
    static mut X: u64: 0;
    static mut Y: bool: 0;

    #[init(resources = [Y])]
    fn init(c: init::Context) {
        // .. пользовательский код ..
    }

    #[interrupt(binds = UART0, resources = [X])]
    fn foo(c: foo::Context) {
        // .. пользовательский код ..
    }

    #[interrupt(binds = UART1, resources = [X, Y])]
    fn bar(c: bar::Context) {
        // .. пользовательский код ..
    }

    // ..
}

Фреймворк создает код, подобный этому:

fn init(c: init::Context) {
    // .. пользовательский код ..
}

fn foo(c: foo::Context) {
    // .. пользовательский код ..
}

fn bar(c: bar::Context) {
    // .. пользовательский код ..
}

// Публичное API
pub mod init {
    pub struct Context<'a> {
        pub resources: Resources<'a>,
        // ..
    }

    pub struct Resources<'a> {
        pub Y: &'a mut bool,
    }
}

pub mod foo {
    pub struct Context<'a> {
        pub resources: Resources<'a>,
        // ..
    }

    pub struct Resources<'a> {
        pub X: &'a mut u64,
    }
}

pub mod bar {
    pub struct Context<'a> {
        pub resources: Resources<'a>,
        // ..
    }

    pub struct Resources<'a> {
        pub X: &'a mut u64,
        pub Y: &'a mut bool,
    }
}

/// Детали реализации
mod app {
    // все, что внутри этого модуля спрятано от пользовательского кода

    static mut X: u64 = 0;
    static mut Y: bool = 0;

    // настоящая точка входа в программу
    unsafe fn main() -> ! {
        interrupt::disable();

        // ..

        // вызов пользовательского кода; передача ссылок на статические переменные
        init(init::Context {
            resources: init::Resources {
                X: &mut X,
            },
            // ..
        });

        // ..

        interrupt::enable();

        // ..
    }

    // обработчик прерывания,с которым связан `foo`
    #[no_mangle]
    unsafe fn UART0() {
        // вызов пользовательского кода; передача ссылок на статические переменные
        foo(foo::Context {
            resources: foo::Resources {
                X: &mut X,
            },
            // ..
        });
    }

    // обработчик прерывания,с которым связан `bar`
    #[no_mangle]
    unsafe fn UART1() {
        // вызов пользовательского кода; передача ссылок на статические переменные
        bar(bar::Context {
            resources: bar::Resources {
                X: &mut X,
                Y: &mut Y,
            },
            // ..
        });
    }
}