1 В избранное 0 Ответвления 0

OSCHINA-MIRROR/rcore-os-rCore-Tutorial

Присоединиться к Gitlife
Откройте для себя и примите участие в публичных проектах с открытым исходным кодом с участием более 10 миллионов разработчиков. Приватные репозитории также полностью бесплатны :)
Присоединиться бесплатно
Клонировать/Скачать
part-2.md 9.2 КБ
Копировать Редактировать Web IDE Исходные данные Просмотреть построчно История
gitlife-traslator Отправлено 29.11.2024 21:14 7f8a4fd

Физические принципы работы памяти

Мы знаем, что обычно физический адрес обращается к блоку DRAM. Мы можем рассматривать его как большой массив байтов, в котором можно найти соответствующую позицию для чтения и записи с помощью физического адреса. Однако физический адрес не только обращается к DRAM, но также может использоваться для доступа к другим периферийным устройствам. Поэтому мы можем считать DRAM разновидностью периферийного устройства, а физический адрес — это абстракция среды хранения данных.

Если для доступа к другому периферийному устройству необходимо использовать разные инструкции (например, x86 предоставляет отдельные инструкции in и out для доступа к пространству ввода-вывода, отличному от пространства памяти), это может быть довольно неудобно. Поэтому многие архитектуры набора команд (такие как RISC-V, ARM и MIPS) используют технологию MMIO (Memory Mapped I/O), чтобы отобразить периферийные устройства на определённый диапазон физических адресов. Таким образом, доступ к периферийным устройствам становится таким же, как и доступ к физической памяти.

Теперь давайте рассмотрим физическую память.

Обнаружение физической памяти

Как операционная система узнаёт о физическом адресе, где находится физическая память? В RISC-V это обычно выполняется загрузчиком, например, OpenSBI. Он сканирует все периферийные устройства, включая те, которые находятся внутри системы, и сохраняет результаты сканирования в формате DTB (Device Tree Blob) в определённом месте в физической памяти. Затем OpenSBI сохраняет его адрес в регистре a1, чтобы мы могли его использовать.

Результаты сканирования описывают информацию обо всех периферийных устройствах, включая физическую память в QEMU-симулированном компьютере RISC-V Virt.

[info] Физическая память в QEMU-симулированном компьютере RISC-V Virt

Изучив определение virt_memmap[] в коде QEMU (hw/riscv/virt.c), можно понять детали физической компоновки памяти в QEMU-симулированном RISC-V Virt компьютере. Можно увидеть, что в физической памяти есть много пустых пространств (то есть областей без отображения), а также множество специфических адресов для периферийных устройств. Сейчас мы не понимаем их значения, но позже мы будем постепенно обращаться к ним. На данный момент нас интересует только последняя область, которая представляет собой пространство DRAM размером 128 МБ, которое будет управляться ОС.

Начальный адрес Конечный адрес Значение
0x0 0x100 QEMU VIRT_DEBUG
0x100 0x1000 Неотображённое пространство
0x1000 0x12000 QEMU MROM
0x12000 0x100000 Неотображённое пространство
0x100000 0x101000 QEMU VIRT_TEST
0x101000 0x2000000 Неотображённое пространство
0x2000000 0x2010000 QEMU VIRT_CLINT
0x2010000 0x3000000 Неотображённое пространство
0x3000000 0x3010000 QEMU VIRT_PCIE_PIO
0x3010000 0xc000000 Неотображённое пространство
0xc000000 0x10000000 QEMU VIRT_PLIC
0x10000000 0x10000100 QEMU VIRT_UART0
0x10000100 0x10001000 Неотображённое пространство
0x10001000 0x10002000 QEMU VIRT_VIRTIO
0x10002000 0x20000000 Неотображённое пространство
0x20000000 0x24000000 QEMU VIRT_FLASH
0x24000000 0x30000000 Неотображённое пространство
0x30000000 0x40000000 QEMU VIRT_PCIE_ECAM
0x40000000 0x80000000 QEMU VIRT_PCIE_MMIO
0x80000000 0x88000000 DRAM по умолчанию размером 128 МБ (размер можно настроить)

Однако, чтобы упростить задачу, мы не собираемся анализировать этот результат самостоятельно. Мы знаем, что начальный физический адрес DRAM в QEMU составляет 0x80000000. В QEMU размер RAM можно указать с помощью опции -m, и по умолчанию он равен 128 MB. Следовательно, диапазон физических адресов DRAM по умолчанию составляет [0x80000000, 0x88000000).

Поскольку позже мы обсудим виртуальные адреса, физические страницы и виртуальные страницы, для дальнейшего различения вместо использования типа usize мы создаём класс PhysicalAddress. Затем мы реализуем для него ряд операций, таких как сложение, вычитание и вывод. Поскольку эта часть реализации больше ориентирована на Rust, чем на операционную систему, здесь не приводится код. Пожалуйста, обратитесь к файлу os/src/memory/address.rs.

Затем мы напрямую присваиваем конечный адрес DRAM физической памяти в ядре и одновременно записываем конечный адрес, используемый операционной системой (который указан в linker script как kernel_end).

lazy_static! {
    /// Конечный адрес кода ядра, который можно использовать для выделения памяти
    ///
    /// Из-за ограничений языка Rust мы можем только присвоить его как статическую переменную, вычисляемую во время выполнения, а не как константу
    pub static ref KERNEL_END_ADDRESS: PhysicalAddress = PhysicalAddress(kernel_end as usize);
}

extern "C" {
    /// Указан в `linker.ld` как конечный адрес кода ядра
    ///
    /// Как переменная существует в [`KERNEL_END_ADDRESS`]
    fn kernel_end();
}

Здесь используется макрос lazy_static, который помогает нам автоматически выполнять эти вычисления при первом использовании макроса lazy_static.

Наконец, мы добавляем вызовы модулей в различные файлы и пытаемся выполнить вывод в os/src/main.rs.

Опубликовать ( 0 )

Вы можете оставить комментарий после Вход в систему

1
https://api.gitlife.ru/oschina-mirror/rcore-os-rCore-Tutorial.git
git@api.gitlife.ru:oschina-mirror/rcore-os-rCore-Tutorial.git
oschina-mirror
rcore-os-rCore-Tutorial
rcore-os-rCore-Tutorial
master