Хотя это и не похоже, но в большинстве операционных систем стандартные потоки ввода-вывода stdin
и stdout
, хотя и называются «потоками», имеют интерфейс файла. Мы также будем реализовывать их как файлы.
Однако не стоит беспокоиться, так как многие функции файлов не будут поддерживаться для stdin
и stdout
. Нам нужно только реализовать самый простой интерфейс чтения и записи для них.
Операционная система должна поддерживать список файлов, открытых процессом. Среди них обязательно есть stdin
, stdout
и stderr
. Для простоты мы реализуем только stdin
и stdout
, их значения файлового дескриптора равны 0 и 1 соответственно.
stdout
Поток вывода очень прост: каждый раз, когда встречается системный вызов, символы из буфера напрямую выводятся через SBI-вызов.
stdin
Ввод потока более сложен: каждый раз при встрече системного вызова он получает символы через прерывание или опрос: если есть, то продолжает получать; если нет, то ждёт. Возвращается только после получения строки согласованной длины.
Для пользовательской программы внешний ввод — это данные, которые активно считываются в любое время. На самом деле внешний ввод обычно краток и не ждёт, операционная система должна немедленно обработать его и буферизовать, а затем ждать, пока программа прочитает его. Поэтому каждая клавиша на клавиатуре является кратковременным прерыванием для операционной системы.
Во время предыдущего эксперимента операционная система не падала из-за одной клавиши, потому что OpenSBI по умолчанию отключает все внешние прерывания. Но теперь нам нужно включить их, чтобы принимать информацию о клавишах.
{% label %}os/src/interrupt/handler.rs{% endlabel %}
/// Инициализация обработки прерываний
///
/// Записывает `__interrupt` в `stvec`, и включает обработку прерываний
pub fn init() {
unsafe {
extern "C" {
/// Входной прерывающий вызов в `interrupt.asm`
fn __interrupt();
}
// Используем прямой режим, устанавливаем входное прерывание на `__interrupt`
stvec::write(__interrupt as usize, stvec::TrapMode::Direct);
// Включаем внешние прерывания
sie::set_sext();
// В OpenSBI включаем внешние прерывания
*PhysicalAddress(0x0c00_2080).deref_kernel() = 1 << 10;
// В OpenSBI включаем последовательный порт
*PhysicalAddress(0x1000_0004).deref_kernel() = 0x0bu8;
*PhysicalAddress(0x1000_0001).deref_kernel() = 0x01u8;
}
}
Здесь нам нужно настроить в соответствии с интерфейсом OpenSBI в указанном адресе. Хорошо, что эти адреса находятся в пространстве отображения файловой системы, поэтому нам не нужно создавать отдельное отображение памяти для них. После включения обработки прерываний любое нажатие клавиши приведёт программу к области unimplemented!
.
Потоку ввода требуется буфер, который мы можем реализовать с помощью alloc::collections::VecDeque
. При возникновении прерывания клавиатуры вызывается sbi_call
для получения символа и добавления его в буфер. Когда встречается системный вызов sys_read
, соответствующее количество символов извлекается из буфера.
Что делать, если встречается sys_read
, а в буфере нет данных для чтения? Как сделать так, чтобы поток ждал, не тратя ресурсы процессора?
Вы можете оставить комментарий после Вход в систему
Неприемлемый контент может быть отображен здесь и не будет показан на странице. Вы можете проверить и изменить его с помощью соответствующей функции редактирования.
Если вы подтверждаете, что содержание не содержит непристойной лексики/перенаправления на рекламу/насилия/вульгарной порнографии/нарушений/пиратства/ложного/незначительного или незаконного контента, связанного с национальными законами и предписаниями, вы можете нажать «Отправить» для подачи апелляции, и мы обработаем ее как можно скорее.
Опубликовать ( 0 )