Запуск обычной версии под RPi
Запуск обычной версии под RPi
См. https://tvoygit.ru/budden/ja-o-s/src/br ... erry-pi.md,
http://вече.программирование-по-русски. ... ?f=5&t=485 - начало работы для кооп. версии.
ещё более старая тема - http://вече.программирование-по-русски. ... ?f=5&t=329
http://вече.программирование-по-русски. ... 6&start=20 - начало работы по QEMU
http://вече.программирование-по-русски. ... ?f=5&t=485 - начало работы для кооп. версии.
ещё более старая тема - http://вече.программирование-по-русски. ... ?f=5&t=329
http://вече.программирование-по-русски. ... 6&start=20 - начало работы по QEMU
Re: Запуск обычной версии под RPi
Читаем конфигурацию Zynq, видим модули:
Здесь я оставил большинство модулей для COOP.ARM { ARM.FPE64.Mod ARM.Builtins.Mod }
RPI и COOP { RPI.CPU.Mod }
ZYNQ и COOP { Zynq.CPU.Mod }
ARM и ~COOP { ARM.Initializer.Mod }
ZYNQ и ~COOP { Zynq.ARM.Platform.Mod }
ARM и ~COOP { ARM.BootConfig.Mod }
RPI и COOP { RPI.Processors.Mod RPI.Timer.Mod }
ZYNQ и COOP { Zynq.Processors.Mod Zynq.Timer.Mod }
COOP { Queues.Mod BaseTypes.Mod Activities.Mod ExclusiveBlocks.Mod Interrupts.Mod Runtime.Mod }
NATIVE и COOP { HeapManager.Mod }
BIOS и COOP { BIOS.Environment.Mod }
RPI и COOP { RPI.Environment.Mod }
ZYNQ и COOP { Zynq.Environment.Mod }
UNIX и COOP { Unix.Environment.Mod }
ZYNQ и ~COOP { Zynq.PsUartMin.Mod Zynq.TraceDevice.Mod Zynq.PrivateWatchdog.Mod ARM.Machine.Mod }
~COOP { Heaps.Mod }
Modules.Mod
ARM и ~COOP { ARM.Objects.Mod ARM.Kernel.Mod }
Re: Запуск обычной версии под RPi
Модуль ARM.Initializer содержит проц {INITIAL,NOPAF} Init;
https://tvoygit.ru/budden/ja-o-s/src/br ... -версии.md
Видимо, сопоставлять его надо с RPI.Environment.Mod/KernelBegin
Наверное, надо скопировать каждый файл от Zynq, к-рый будет меняться.
https://tvoygit.ru/budden/ja-o-s/src/br ... -версии.md
Видимо, сопоставлять его надо с RPI.Environment.Mod/KernelBegin
Наверное, надо скопировать каждый файл от Zynq, к-рый будет меняться.
Re: Запуск обычной версии под RPi
Код: Выделить всё
System.DoCommands
FSTools.DeleteFiles -i ЯОС:NewRPI2/* ~
Release.Build -b --path="ЯОС:NewRPi2/" RPi2 ~
Linker.Link --fileName=ЯОС:NewRPI2/kernel7.img --displacement=8000H -a
--path="ЯОС:NewRPi2/" Initializer Platform FPE64 ПримитивыСредыВыполнения
Ю32 ПереводыЭлементовКода Trace BootConfig PsUartMin TraceDevice PrivateWatchdog
Ю16 Ю16_2 Machine Heaps Modules Objects Kernel ЛогЯдра Plugins Streams Pipes
Commands Reals Clock Dates Strings Files Disks DiskCaches Reflection TrapWriters
Traps Locks Options ~
FSTools.CopyFiles -o ЯОС:NewRPI2/kernel7.img => C:/vb_share/a2/2/kernel7.img ~
FSTools.CopyFiles -o ЯОС:NewRPI2/kernel7.log => C:/vb_share/a2/2/kernel7.log ~~
Re: Запуск обычной версии под RPi
https://zen.yandex.ru/video/watch/62a79 ... 692a14250c - видео о том, как собрать и запустить в эмуляторе ядро, в т.ч. под отладчиком. До того момента, когда оно падает.
Последний раз редактировалось БудДен 03.09.22 17:56, всего редактировалось 1 раз.
Re: Запуск обычной версии под RPi
Падает на проверке
утв(memStackStop <= memIOStart);
участвующие в проверке величины назначаются в ARM.Machine.Mod:
утв(memStackStop <= memIOStart);
участвующие в проверке величины назначаются в ARM.Machine.Mod:
Код: Выделить всё
memConfigStop := Platform.DDRStart + СтрВЦел32(i, value);
ДайЗначениеКлючаКонфигурацииЯОС("ConfigSize", value);
i := 0;
memConfigStart := memConfigStop - СтрВЦел32(i, value);
memStackStart := memHeapStop;
memStackStop := memConfigStart;
memIOStart := Platform.IOStart;
memIOStop := memIOStart + Platform.IOSize;
Re: Запуск обычной версии под RPi
Теперь нам надо, похоже, запустить кооп. версию и в ней понять, чему равно memTag.size (можно с помощью TRACE, т.к. трассировка уже поднята).
Re: Запуск обычной версии под RPi
Код: Выделить всё
memTag^.size = 1006632960
RPI.Environment.Mod@5628 Environment.InitMemory:memTag^.start= 00000000H;
RPI.Environment.Mod@5654 Environment.InitMemory: операцияАдресОт KernelEnd= 00065EA0H;
Последний раз редактировалось БудДен 03.07.22 11:30, всего редактировалось 1 раз.
Re: Запуск обычной версии под RPi
теперь надо понять, что дальше происходит с этой памятью. Мы выяснили, что она мапится 1*1 в виртуальную память (если я всё правильно понял). Но дальше, очевидно, часть должна резервироваться под вектора прерываний, часть - это порты, а остальное должно инициализироваться с помощью менеджера памяти. Т.е. нужно дальше читать загрузку RPiC.
Может помочь картинка:
источник
Может помочь картинка:
источник
Последний раз редактировалось БудДен 03.07.22 12:24, всего редактировалось 1 раз.
Re: Запуск обычной версии под RPi
Вызывают интерес следующие строчки в кооперативной версии. Похоже, что всё, что за ядром, выкладывается в один непрерывный диапазон адресов. Остаётся вопрос, что с периферией? На картинке упоминается iobase. Такое слово в исходниках есть, но пока смысл не раскопал.
Код: Выделить всё
HeapManager.Initialize (heap, begin := операцияАдресОт KernelEnd, end := memTag.start + memTag.size);
memory := memTag.start + memTag.size - операцияАдресОт KernelEnd;
Re: Запуск обычной версии под RPi
Как же работает трассировка? А вот как:
В RPI.CPU.Mod написано:
- это 1059065904
А MemTag.size = 1006632960 = 3C000000, т.е. порты находятся ЗА пределами диапазона.
Видимо, неявным образом iobase = 3C000000 или что-то в этом роде. Уточним.
В примере c:\ob\RaspberryPi-baremetal\002-hello-lo-lo-lo\uart.S
видим:
В RPI.CPU.Mod написано:
Код: Выделить всё
конст UART_CR* = 03F201030H
А MemTag.size = 1006632960 = 3C000000, т.е. порты находятся ЗА пределами диапазона.
Видимо, неявным образом iobase = 3C000000 или что-то в этом роде. Уточним.
В примере c:\ob\RaspberryPi-baremetal\002-hello-lo-lo-lo\uart.S
видим:
Код: Выделить всё
#define PERIPHERAL_BASE 0x3F000000 // Raspberry Pi 2 Peripheral Base Address
Re: Запуск обычной версии под RPi
В файле для Zynq написано:
При том есть переменная sysVectorStart, которая равна FFFF0000, и которая нигде не используется. Странно это всё.
Код: Выделить всё
* Interrupt Vector. Located at 0FFFFFFF0H
Re: Запуск обычной версии под RPi
Теперь пытаемся понять, что такое sysFirstLvlPtStart и sysSecondLvlPtStart.
Это явно два каких-то куска.
GetSecondLevelEntry - испольузется в:
* ExtendStack
* GetStack
* AllocatePage/DeallocatePage
* TranslateVirtual
* ValidStack
* EnableDCacheRange/DisableDCacheRange (DCache - это кеш данных)
GetFirstLevelEntry - используется в:
* EnableDCacheRange/DisableDCacheRange
* TranslateVirtual
* AllocateHeap
Причём в EnableDCacheRange выглядит так, как будто FirstLevel главнее.
Теперь смотрим сюда:
Это явно два каких-то куска.
GetSecondLevelEntry - испольузется в:
* ExtendStack
* GetStack
* AllocatePage/DeallocatePage
* TranslateVirtual
* ValidStack
* EnableDCacheRange/DisableDCacheRange (DCache - это кеш данных)
GetFirstLevelEntry - используется в:
* EnableDCacheRange/DisableDCacheRange
* TranslateVirtual
* AllocateHeap
Причём в EnableDCacheRange выглядит так, как будто FirstLevel главнее.
Теперь смотрим сюда:
Re: Запуск обычной версии под RPi
https://programmersought.com/article/24173413930/
There are two cores of CORE0 and CORE1 in zynq. The two cores have independent L1 DCache and share the same L2 DCache.
Пазл складывается. Похоже, что FirstLevel/SecondLevel как-то относится к кешу и всё это - специфика Zynq. Для RPi - неактуально.
There are two cores of CORE0 and CORE1 in zynq. The two cores have independent L1 DCache and share the same L2 DCache.
Пазл складывается. Похоже, что FirstLevel/SecondLevel как-то относится к кешу и всё это - специфика Zynq. Для RPi - неактуально.
Re: Запуск обычной версии под RPi
Вроде выяснил, что TLB-это аппаратный кеш для трансляции страниц. Его нужно обновлять при изменении таблиц вирт. памяти. Т.е. в ЭВМ.AllocatePage понятен вызов InvalidateTLBEntry, осталось выяснить, есть ли аналогичное в RPi.
Что касается SecondLevelEntry, то вот кусок кода возле определения sysSecondLvlPtStart:
Что касается SecondLevelEntry, то вот кусок кода возле определения sysSecondLvlPtStart:
Код: Выделить всё
(* System Parameters *)
(* ... *)
(* First Level Page Table: size of 16 * k to map 4GB with 1MB pages. *)
sysFirstLvlPtStart,
sysFirstLvlPtStop,
(*
* Second Level Page Table:
* - 2 * 256 entries for the system area (first and last MB of VMem)
* - 256 entries for each MB of virtual stack space
* 256 entries take 1kB memory space.
*)
sysSecondLvlPtStart,
sysSecondLvlPtStop,
Re: Запуск обычной версии под RPi
Видимо, ARM.Machine.Mod/InvalidateDCache ~= RPI.CPU.Mod/Invalidate.
Также в RPI.CPU.Mod нашлась переменная:
Также в RPI.CPU.Mod нашлась переменная:
Код: Выделить всё
перем pageTable {выровнять (4000H)}: запись entry: массив 4096 из размерМЗ кон;
Re: Запуск обычной версии под RPi
Название RPI.CPU/IdentityMapMemory намекает на примитивность управления памятью в RPi.
Наверное, можно не расширять стек, а вот как насчёт выделения памяти? Пока неясно. Поскольку
мы хотим сузить интерфейс, придётся пересмотреть все использования вирт. памяти в Zynq
и понять, сможем ли мы их отобразить и как.
Наверное, можно не расширять стек, а вот как насчёт выделения памяти? Пока неясно. Поскольку
мы хотим сузить интерфейс, придётся пересмотреть все использования вирт. памяти в Zynq
и понять, сможем ли мы их отобразить и как.
Re: Запуск обычной версии под RPi
Перебираем всех, кто обращается к выделению страниц.
ExtendStack - в обычной версии,
Activities.ExpandStack - в кооперативной. Максимальный стек в 1000 раз больше изначального. Вероятно, у нас будут затруднения обойтись без расширения стека. Поэтому придётся разобраться, как работает ExpandStack во всех версиях и сможем ли мы его расширять при условии, что мы отображаем обычную память в виртуальную как 1 в 1.
BIOS.I386.Machine.Mod/ExtendStack - пользуется вирт. памятью (MapPage)
ARM обычный - то же.
Activities.Mod/ExpandStack - я ничего не понял, но похоже, что стек состоит из сегментов (записей). Загадочно то, что с одной стороны, стек вроде расширяется путём создания новой записи и на неё сохраняется ссылка. С другой, предпоследняя запись при создании последней явно удаляется.
Во всяком случае, не видно, чтобы тут работало отображение страниц.
Однако кооп. версия нам не нужна. Возможно всё же нужно перенести управление памятью (с вирт. памятью) из Zynq, перенастроив его. Попробуем концептуально понять это из https://habr.com/ru/post/422385/ и потом поискать примеры для RPi с конкретикой.
https://s-matyukevich.github.io/raspber ... pi-os.html
ExtendStack - в обычной версии,
Activities.ExpandStack - в кооперативной. Максимальный стек в 1000 раз больше изначального. Вероятно, у нас будут затруднения обойтись без расширения стека. Поэтому придётся разобраться, как работает ExpandStack во всех версиях и сможем ли мы его расширять при условии, что мы отображаем обычную память в виртуальную как 1 в 1.
BIOS.I386.Machine.Mod/ExtendStack - пользуется вирт. памятью (MapPage)
ARM обычный - то же.
Activities.Mod/ExpandStack - я ничего не понял, но похоже, что стек состоит из сегментов (записей). Загадочно то, что с одной стороны, стек вроде расширяется путём создания новой записи и на неё сохраняется ссылка. С другой, предпоследняя запись при создании последней явно удаляется.
Во всяком случае, не видно, чтобы тут работало отображение страниц.
Однако кооп. версия нам не нужна. Возможно всё же нужно перенести управление памятью (с вирт. памятью) из Zynq, перенастроив его. Попробуем концептуально понять это из https://habr.com/ru/post/422385/ и потом поискать примеры для RPi с конкретикой.
https://s-matyukevich.github.io/raspber ... pi-os.html
Re: Запуск обычной версии под RPi
В общем, похоже, что надо более агрессивно запихивать Zynq версию на RPi , со всеми прибамбасами, кроме отсутствующих. Для этого надо:
* прочитать, что уже сделано (сравнить главную ветку и RPI2-3)
* составить табличку всех параметров (чисел), участвующих в конфигурации ОС, с двумя колонками, Zybo и RPi
* найти эти параметры в коде
* подменить
* прочитать, что уже сделано (сравнить главную ветку и RPI2-3)
* составить табличку всех параметров (чисел), участвующих в конфигурации ОС, с двумя колонками, Zybo и RPi
* найти эти параметры в коде
* подменить
Re: Запуск обычной версии под RPi
Возвращаемся к вопросу про периферию. Судя по изучению упомянутого c:\ob\RaspberryPi-baremetal\002-hello-lo-lo-lo\uart.S , адрес периферии прибит гвоздями к модели RPi. Поскольку он у нас находится за пределами памяти (адрес больше 1гб), то и волноваться о его пересечении с обычной памятью у нас нет причин. Если нам тут о чём-то и стоит волноваться, так это про то, чтобы в Zynq эта периферия не оказалась где-то внутри адресного пространства и появились бы спец.костыли для её исключения. Попробуем это увидеть.
Re: Запуск обычной версии под RPi
Нашёл в Zynq.ARM.Platform.Mod
Код: Выделить всё
UartBase* = [адресВПамяти(0E0000000H),адресВПамяти(0E0001000H)]; (* base address for all UART controllers present in the system *)
Re: Запуск обычной версии под RPi
sysSecondLvlPtStart не влез куда надо, видимо, по той причине, что его пытались запихнуть в OCM, размером 192кб.
А это - специальная микросхема памяти, которая есть в Zynq, и, видимо, занимает адреса от 0 (Platform.OCMStart = 0).
Теперь всё же придётся разобраться, куда можно поместить таблицу страниц в RPi.
Имеем:
Далее, имеем такой код (RPI.CPU.Mod/EnableMemoryManagementUnit)
Здесь pageTable - это просто статическая переменная с каким-то (каким попало) адресом:
Хаа, такая же нашлась и в ARM.Machine.Mod, но она содержит адреса:
при этом ожидаемо (ARM.Machine.Mod):
Значит, раз в RPI нет какого-то особого (ускоряющего) места для этой таблицы, то нам нужно создать две переменных для таблиц
первого и второго уровня и передать их адреса. А переменные sysFirstLvlPt* упразднить.
А это - специальная микросхема памяти, которая есть в Zynq, и, видимо, занимает адреса от 0 (Platform.OCMStart = 0).
Теперь всё же придётся разобраться, куда можно поместить таблицу страниц в RPi.
Имеем:
P15 в ЯОС - как-то соотносится с CP15 (ищем в коде EnterCoprocessor(CP15, "P15");Для управления системой(в т.ч. блоком MMU) в архитектуре ARM предназначен специальный сопроцессор CP15. К управлению памятью относятся полтора десятка его регистов. Нас интересуют несколько из них — Control, TTBR0/1, TTBCR, ContextID.
Далее, имеем такой код (RPI.CPU.Mod/EnableMemoryManagementUnit)
Код: Выделить всё
проц EnableMemoryManagementUnit-;
машКод
load:
LDR R0, [PC, #page-$-8]
MCR P15, 0, R0, C2, C0, 0
B grant
page:
d32 pageTable
grant:
MOV R0, #0b11
MCR P15, 0, R0, C3, C0, 0
enable:
MRC P15, 0, R0, C1, C0, 0
ORR R0, R0, #0b1 ; memory protection
ORR R0, R0, #0b100 ; data and unified cache
ORR R0, R0, #0b100000000000 ; branch prediction
ORR R0, R0, #0b1000000000000 ; instruction cache
MCR P15, 0, R0, C1, C0, 0
кон EnableMemoryManagementUnit;
Код: Выделить всё
перем pageTable {выровнять (4000H)}: запись entry: массив 4096 из размерМЗ кон;
Код: Выделить всё
pageTable: запись virtual, memory: адресВПамяти кон;
Код: Выделить всё
pageTable.virtual := sysFirstLvlPtStart;
pageTable.memory := sysFirstLvlPtStart;
первого и второго уровня и передать их адреса. А переменные sysFirstLvlPt* упразднить.
Re: Запуск обычной версии под RPi
Теперь нам нужно узнать размеры таблиц для RPi, одна из них есть, а вторая? В Zynq она где-то лежит и имеет какой-то размер (0x390400, хотя кто знает, что это означает).
RPI.Environment.Mod/Allocate -> HeapManager.Allocate -> а дальше как-то не попадается ничего, похожего на таблицу 2-го уровня.
Тогда план будет такой: таблица первого уровня пусть имеет размер 0x1000, второго - 0x390400 (хз, что это, но пусть будет так пока что), memSysLowStart и memSysLowStop выкидываем, а под таблицы заводим две статических переменных (только надо понять, в чём измеряется размер).
RPI.Environment.Mod/Allocate -> HeapManager.Allocate -> а дальше как-то не попадается ничего, похожего на таблицу 2-го уровня.
Тогда план будет такой: таблица первого уровня пусть имеет размер 0x1000, второго - 0x390400 (хз, что это, но пусть будет так пока что), memSysLowStart и memSysLowStop выкидываем, а под таблицы заводим две статических переменных (только надо понять, в чём измеряется размер).
Re: Запуск обычной версии под RPi
поменял размер начальной системной области (поставил 1мб с запасом, как раз хватило до адреса загрузки ядра),
размер кучи (уменьшил)
размер стека (128мб, а не отсчитываю от конфига, который где-то далеко в небе)
Загрузка прошла чуть дальше.
размер кучи (уменьшил)
размер стека (128мб, а не отсчитываю от конфига, который где-то далеко в небе)
Загрузка прошла чуть дальше.
Re: Запуск обычной версии под RPi
Пытаемся изжить memSysHighStart/Stop, но внутри них находятся:
(* High system memory region. Within the last MB, contains: interrupt vector and reference counts
* for caching. *)
Это опять же кусок адресного пространства, к-рый в Zynq отвечает за OCM - on-chip memory, которой в RPi (наверное) нет.
Нужно выяснить, где в RPi вектор прерываний и что делать с "счётчиками ссылок для кеширования"
Вектор прерываний живёт по адресам около 0, а у нас в новой версии что там? Туда попал Config - его надо разместить получше (или вообще выкинуть,
ведь у нас есть константа для конфига). А в Zynq есть sysVectorStart и sysVectorsStop и он - где-то в верхних адресах. Посмотрим, где он используется. А нигде, кроме проверок.
ARM.Machine.Mod (ЭВМ для Zynq) InterruptVector == sysVectorStart, но совпадение не проверяется и называется почему-то по-другому. И написано так:
Поскольку у нас он будет в начале и мы мапим начало 1:1, то нет причины, почему он не является корректным в любое время (кроме времени, когда MMU включено, а отображение 1:1 ещё не сделано).
Ставим sysVectorStart = 1. Размер его равен PS (4кб, одна страница) - надесь, это нас не сломает, если мы поставим его в начале. Опробуем, но перед этим посмотрим, где используется InterruptVector. На беглый взгляд ничего страшного, но чую, что всё рухнет эпически.
(* High system memory region. Within the last MB, contains: interrupt vector and reference counts
* for caching. *)
Это опять же кусок адресного пространства, к-рый в Zynq отвечает за OCM - on-chip memory, которой в RPi (наверное) нет.
Нужно выяснить, где в RPi вектор прерываний и что делать с "счётчиками ссылок для кеширования"
Вектор прерываний живёт по адресам около 0, а у нас в новой версии что там? Туда попал Config - его надо разместить получше (или вообще выкинуть,
ведь у нас есть константа для конфига). А в Zynq есть sysVectorStart и sysVectorsStop и он - где-то в верхних адресах. Посмотрим, где он используется. А нигде, кроме проверок.
ARM.Machine.Mod (ЭВМ для Zynq) InterruptVector == sysVectorStart, но совпадение не проверяется и называется почему-то по-другому. И написано так:
Код: Выделить всё
(* Interrupt Vector base. Valid only after MMU is enabled *)
InterruptVector = 0FFFF0000H;
Ставим sysVectorStart = 1. Размер его равен PS (4кб, одна страница) - надесь, это нас не сломает, если мы поставим его в начале. Опробуем, но перед этим посмотрим, где используется InterruptVector. На беглый взгляд ничего страшного, но чую, что всё рухнет эпически.
Последний раз редактировалось БудДен 04.09.22 13:03, всего редактировалось 4 раза.
Re: Запуск обычной версии под RPi
Хм, оказывается в RPi тоже есть SDRAM, видимо, это аналог OCM (см. картинку в начале темы), и она ещё как-то может делиться на 2 части. Но пока мы это игнорируем.
Re: Запуск обычной версии под RPi
Надеемся, что счётчики для кеширования - это просто память, а не что-то аппаратное. Если окажется иначе, будем думать. sysCacheRefStart - ищем, как используется. Используется для переменной ARM.Machine.Mod/cacheRefs, она частная и в ассемблере не используется. Значение прибито гвоздями и равно 0FFFF1000H - это подозрительно. Запросы "zynq ffff1000 cache" и "zynq 0xffff1000 cache" ничего не показывают. Будем считать, что это просто число, а не особая железка в zynq. Также ищем во всех файлах исходников, ничего не находим.
Re: Запуск обычной версии под RPi
memConfigStart/memConfigStop - странно, но я не нашёл, где бы они использовались. В старой версии нашёл такой кусок кода:
ARM.BootConfig.Mod (версия Zynq):
Скорее всего, он как-то вычисляется статически из размера памяти, но я не нашёл такого значения в *. Значит, мы их выпилим, а инициализация у нас уже по-другому устроена (конфигурация у нас не берётся с платы, а впечатана в коде ядра):
ARM.BootConfig.Mod (версия RPi2):
ARM.BootConfig.Mod (версия Zynq):
Код: Выделить всё
проц Init *;
нач
НИЗКОУР.копируйПамять(Initializer.configBase, 1FFFF000H, Initializer.configSize);
Initializer.configBase := 1FFFF000H;
config := Initializer.configBase;
size := Initializer.configSize;
если size >= ConfigSize то size := ConfigSize-1; всё;
config[size] := CR;
кон Init;
ARM.BootConfig.Mod (версия RPi2):
Код: Выделить всё
проц Init *;
нач
(* НИЗКОУР.копируйПамять(Initializer.configBase, 1FFFF000H, Initializer.configSize);
Initializer.configBase := 1FFFF000H;
config := Initializer.configBase;
size := Initializer.configSize;
если size >= ConfigSize то size := ConfigSize-1; всё;
config[size] := CR; *)
cfg := "CpuClockHz=666666666
UartInputClockHz=50000000
KernelOutputUart=1
...
Re: Запуск обычной версии под RPi
Раскладка памяти выглядит так:
InitMemory падает только на последней строчке.
Из очевидного - нужно выкинуть SysHigh (или уточнить границы), а также поправить I/O Start/Stop (он явно другой в RPi)
Код: Выделить всё
System Start(memSysLowStart): 00000000
System Stop(memSysLowStop): 00100000
System Size: 00100000
Interrupt Vector Start(sysVectorStart): 00000000
Interrupt Vector Stop(sysVectorStop): 00001000
Interrupt Vector Size: 00001000
Interrupt Stack Start(sysIntStackStart): 00001000
Interrupt Stack Stop(sysIntStackStop): 00008000
Interrupt Stack Size: 00007000
Cache References Start(sysCacheRefStart): 00008000
Cache References Stop(sysCacheRefStop): 00010104
Cache References Size: 00008104
Cache References Stack Offset(sysCacheStackOfs): 00000100
Second Page Table Start(sysSecondLvlPtStart): 000DB800
Second Page Table Stop(sysSecondLvlPtStop): 000FC000
Second Page Table Size: 00020800
First Page Table Start(sysFirstLvlPtStart):000FC000
First Page Table Stop(sysFirstLvlPtStop): 00100000
First Page Table Size: 00004000
Heap Start(memHeapStart): 00100000
Heap Stop(memHeapStop): 10100000
Heap Size: 10000000
Stack Start(memStackStart): 10100000
Stack Stop(memStackStop): 18100000
Stack Size: 08000000
I/O Start(memIOStart): 40000000
I/O Stop(memIOStop): FE000000
I/O Size: BE000000
SysHigh Start(memSysHighStart): FFF00000
SysHigh Stop(memSysHighStop - 1): FFFFFFFE
Из очевидного - нужно выкинуть SysHigh (или уточнить границы), а также поправить I/O Start/Stop (он явно другой в RPi)
Re: Запуск обычной версии под RPi
Удалось создать согласованную раскладку памяти. Теперь пришли к той неприятности, что ядро в RPi загружается с адреса 8000H, а в Zynq - со 100000H, соответственно, при нашей раскладке памяти ядро будет затёрто. Ядро у нас - размером более 1 Мб, поэтому, если там где-то и есть быстрая память, то она вся будет занята ядром. Ну ок, для нашей задачи (просто работать) это некритично. Главное, чтобы вообще хоть как-то заработало.
Re: Запуск обычной версии под RPi
Начинаем кучу от 4Мб и тянем её до 256Мб + 4Мб (или просто до 256Мб). То, что раньше жило до мегабайта, ставим между 3Мб и 4Мб.
Re: Запуск обычной версии под RPi
Код: Выделить всё
ARM.Machine.Mod@88007 ЭВМ.SetFirstLevelEntry:virtual= 17F00000H;
ARM.Machine.Mod@88059 ЭВМ.SetFirstLevelEntry:physical= 003FB400H;
Re: Запуск обычной версии под RPi
* ARM paging - https://wiki.osdev.org/ARM_Paging - там описаны виды страниц.
* inner and outer shareable - см. https://community.arm.com/support-forum ... r-in-armv7
* isb - instruction synchronization barrier
* sy - то же, системного уровня
пытаемся сопоставить процедуры инвалидации кеша (требуется перед чтением из памяти, изменённой устройством) и его сброса (требуется перед тем, как устройство прочитает память). В RPI это делается цепочкой команд
И годится только для одного адреса.
В Zybo - по-другому (а может это и не одно и то же вообще)
* inner and outer shareable - см. https://community.arm.com/support-forum ... r-in-armv7
* isb - instruction synchronization barrier
* sy - то же, системного уровня
пытаемся сопоставить процедуры инвалидации кеша (требуется перед чтением из памяти, изменённой устройством) и его сброса (требуется перед тем, как устройство прочитает память). В RPI это делается цепочкой команд
Код: Выделить всё
проц (* RPI.CPU.Mod *) Invalidate- (address: адресВПамяти);
машКод
LDR R0, [FP, #address]
BIC R0, R0, #(CacheLineSize - 1)
MCR P15, 0, R0, C7, C6, 1
кон Invalidate;
В Zybo - по-другому (а может это и не одно и то же вообще)
Код: Выделить всё
проц (* ARM.Machine.Mod *) DisableDCacheRange * (adr: адресВПамяти; len: размерМЗ);
InvalidateTLBEntry(adr);
MCR p15, 0, R0, c8, c3, 1 ; invalidate address
FlushDCachePhysRange(adr - adr остОтДеленияНа M, M, range, 1);
если ~enableCaching и (len # 0) то
если len остОтДеленияНа cacheline # 0 то увел(len, cacheline - len остОтДеленияНа cacheline) всё;
(* Select cache L0 Data cache in CSSR *)
машКод
mov r0, #0
mcr p15, 2, r0, c0, c0, 0 (* mtcp(XREG_CP15_CACHE_SIZE_SEL, 0);*)
кон;
(* Flush all cache lines in the memory region *)
нцДля r := 0 до numRanges - 1 делай
cur := ranges[r].адр;
end := cur + ranges[r].разм;
нцПока (cur < end) делай
(* Flush L1 Data cache line with virtual address *)
машКод
ldr r3, [fp, #adr] (* load*)
mcr p15, 0, r3, c7, c14, 1; MCR XREG_CP15_CLEAN_INVAL_DC_LINE_MVA_POC :: "r" (adr));
кон;
(* Flush L2 cache line with physical address *)
НИЗКОУР.запишиОбъектПоАдресу(L2CCOffset, cur);
cur := cur + cacheline;
adr := adr + cacheline
кц
кц
всё;
(* Wait for L1 and L2 flush to complete *)
машКод
DSB
кон;
НИЗКОУР.запиши32битаПоАдресу(L2CCCacheSync, 1);
нцДо кцПри НИЗКОУР.прочти32битаПоАдресу(L2CCCacheSync) = 0;
Re: Запуск обычной версии под RPi
А это вообще одно и то же или разное? (ARM.Machine.Mod/)ИнвалидируйКешДанныхДляДиапазона используется в SD, т.е реально нужен. В RPI он не видно, чтобы был реализован, в Coop.arm.machine.mod, и в Coop.Machine.Mod он пустой.
А где используется RPI-шный Invalidate? В неработающем (или непостижимом для меня) RPI.DisplayLinear.Mod:
Код кратно проще, и может быть, прямо вот из него можно состряпать реализацию инвалидации кеша данных для диапазона?
А где используется RPI-шный Invalidate? В неработающем (или непостижимом для меня) RPI.DisplayLinear.Mod:
Код: Выделить всё
FOR address := ADDRESS OF buffer.size TO ADDRESS OF buffer.padding BY CPU.CacheLineSize DO CPU.Invalidate (address) EN
Re: Запуск обычной версии под RPi
Чтобы закончить с упрощением, нужно попытаться выкинуть мелкие страницы и обойтись крупными, как в RPI. Мелкие страницы, как я понял, нужны только для кеша.
Re: Запуск обычной версии под RPi
С повреждениями, но MMU инициализировался. Теперь падаем на инициализации таймера. Однако, т.к. мы упразднили второй уровень таблиц вирт. памяти, у нас теперь не работает
AllocatePage <- NewStack <- NewProcess <- ARM.Objects.Mod/CreateProcess
При этом, NewStack сам находит свободную страницу, поэтому можно не волноваться. Нужно волноваться лишь о:
* том, чтобы начало стека было выровнено под 1Мб
* предельный размер стека равен maxUserStackSize = 2Мб
*
здесь заменить на большую страницу. Выделять в AllocatePage большую, а не маленькую страницу.
Поменять порядок подсчёта во freeStack и т.п.
AllocatePage <- NewStack <- NewProcess <- ARM.Objects.Mod/CreateProcess
При этом, NewStack сам находит свободную страницу, поэтому можно не волноваться. Нужно волноваться лишь о:
* том, чтобы начало стека было выровнено под 1Мб
* предельный размер стека равен maxUserStackSize = 2Мб
*
Код: Выделить всё
InitStackSize = размерМаленькойСтраницы;
StackGuardSize = размерМаленькойСтраницы;
Поменять порядок подсчёта во freeStack и т.п.
Re: Запуск обычной версии под RPi
Пока стек отложим и разберёмся с таймером. GlobalTimerCounterRegister и иже с ним, используются в
ARM.Machine.Mod/ДайКвоТактовПроцессораСМоментаПерезапуска, а также в Zynq.Timer.Mod, параллельный которому в RPI называется RPI.Timer.Mod и там уже есть нужный код. Короче, наверное, тут ясно, что и как поправить, и на этом мы поставим точку с запятой.
ARM.Machine.Mod/ДайКвоТактовПроцессораСМоментаПерезапуска, а также в Zynq.Timer.Mod, параллельный которому в RPI называется RPI.Timer.Mod и там уже есть нужный код. Короче, наверное, тут ясно, что и как поправить, и на этом мы поставим точку с запятой.
Re: Запуск обычной версии под RPi
Дошёл до инициализации модуля Modules. В Init есть загадочные строчки о том, что что-то инициализируется компоновщиком и мы падаем до входа в тело модуля. Наверное, что-то там пошло не так - надо изучать код линкера. Как вариант, код, подмешанный линкером, выделяет динамическую память и это его губит.
Re: Запуск обычной версии под RPi
Ну вот, мы доехали до ситуации, когда оказалось, что ядро должно было быть внутри кучи. А мы разместили всяческие "убежища" выше ядра, но ниже кучи. Теперь нужно их перемещать и возникает снова две системных области - нижняя и верхняя. А мы уже это выпилили. Что ж, придётся обратно впилить.
Re: Запуск обычной версии под RPi
ндя, чем больше я всё это курочу, тем крепче убеждение, что придётся в какой-то момент всё начать заново.
Re: Запуск обычной версии под RPi
Дошёл до InitProcessors - стек вроде удалось выделить. Посоветовали такой источник знаний:
https://arm-software.github.io/CMSIS_5/ ... index.html
https://arm-software.github.io/CMSIS_5/ ... index.html
Re: Запуск обычной версии под RPi
Дмитрий Фролов накидал ссылок:
https://forums.raspberrypi.com/viewtopic.php?t=268543
https://github.com/s-matyukevich/raspbe ... /rpi-os.md
Вот тут загрузчик, может там есть что-то что нужно https://github.com/ultibohub/Core/blob/ ... otrpi2.pas
https://forums.raspberrypi.com/viewtopic.php?t=268543
https://github.com/s-matyukevich/raspbe ... /rpi-os.md
Вот тут загрузчик, может там есть что-то что нужно https://github.com/ultibohub/Core/blob/ ... otrpi2.pas
Re: Запуск обычной версии под RPi
Докатился до таймера. Таймер - это прерывание номер 27. В Zynq есть переменная - массив обработчиков, иииии тут нахожу, что тело процедуры InitInterrupts полностью пропущено, поставлен возврат в самом начале. А упёрся я в "distribution control register", который является частью какого-то там mpcore, о котором в кооп версии не написано ничего. Теперь нужно выяснить, есть ли такое вообще в RPi. Вспоминаю, что я уже начинал это делать, но решил отложить на потом. И вот, потом наступило.
https://www.macs.hw.ac.uk/~hwloidl/Cour ... p5_trm.pdf
https://www.macs.hw.ac.uk/~hwloidl/Cour ... p5_trm.pdf
Re: Запуск обычной версии под RPi
Ну вот, пропала прекрасная запись. В ultibo нашёл:
* TInitTimer - может быть полезной
* BCM2836 в RPi2, но модуль в ultibo сделан на базе BCM2835, т.к. информации по 2836 не было (и, видимо, нету по сей день)
* В модуле BCM2836 написано:
Это похоже на то, что в A2/ЯОС называется "таймером" (модуль RPI.Timer.Mod и далее
RPI.CPU.Mod:
Согласно пункту 14.1, именно этот таймер работает с фиксированной частотой, значит он-то нам и нужен. Конечно, есть ещё другие таймеры, работающие с системной частотой процессора, но будем надяеться, что нам пока нужен только один таймер. Будем верить это, пока не столкнёмся с обратным.
* TInitTimer - может быть полезной
* BCM2836 в RPi2, но модуль в ultibo сделан на базе BCM2835, т.к. информации по 2836 не было (и, видимо, нету по сей день)
* В модуле BCM2836 написано:
Код: Выделить всё
BCM2836_SYSTEM_TIMER_REGS_BASE = BCM2836_PERIPHERALS_BASE + $3000;
RPI.CPU.Mod:
Код: Выделить всё
конст STCLO* = 03F003004H; STCHI* = 03F003008H;
Re: Запуск обычной версии под RPi
В Ultibo нашёл файл BootRPI2, может быть, его чтение чем-то поможет.
А также в mrvn есть пример 7 именно про "тот" таймер и его прерывание.
https://github.com/mrvn/RaspberryPi-bar ... d-to-chill
А также в mrvn есть пример 7 именно про "тот" таймер и его прерывание.
https://github.com/mrvn/RaspberryPi-bar ... d-to-chill
Re: Запуск обычной версии под RPi
Философский вопрос: какой из таймеров отвечает за переключение задач?
ARM.Objects.Mod/InstallHandler при каких-то обстоятельствах назначает обработчик с помощью
ARM.Machine.Mod/InstallHandler, передавая ему обработчик, называемый FieldIRQ. Этот обработчик
вызывает Enter, содержит переменную preempt, а также вызывает Select. Т.е. гипотеза, что переключение
происходит по прерыванию таймера, вроде подтверждается. Но похоже, что не только таймер может приводить к переключению,
а и другие обработчики тоже. Но условие с FieldIRQ выглядит мутным и слёту кажется, что оно вообще не должно выполняться никогда.
Поищем, кто ещё вызывает Select и Enter...
ARM.Objects.Mod/Timeslice - "preempt the current process". Кто вызывает Timeslice? Прежде всего,
одноимённое поле Timeslice типа Handler (а Handler - процедура, принимающая состояние процессора, что бы это ни значило), и рядышком с ним - поле timer: EventHandler - оба, как написано, для вытесняющей многозадачности.
ARM.Objects.Mod/InstallHandler при каких-то обстоятельствах назначает обработчик с помощью
ARM.Machine.Mod/InstallHandler, передавая ему обработчик, называемый FieldIRQ. Этот обработчик
вызывает Enter, содержит переменную preempt, а также вызывает Select. Т.е. гипотеза, что переключение
происходит по прерыванию таймера, вроде подтверждается. Но похоже, что не только таймер может приводить к переключению,
а и другие обработчики тоже. Но условие с FieldIRQ выглядит мутным и слёту кажется, что оно вообще не должно выполняться никогда.
Поищем, кто ещё вызывает Select и Enter...
ARM.Objects.Mod/Timeslice - "preempt the current process". Кто вызывает Timeslice? Прежде всего,
одноимённое поле Timeslice типа Handler (а Handler - процедура, принимающая состояние процессора, что бы это ни значило), и рядышком с ним - поле timer: EventHandler - оба, как написано, для вытесняющей многозадачности.
Re: Запуск обычной версии под RPi
Код: Выделить всё
ARM.Objects.Mod/Timeslice
HandleMPTimer
Не используется
HandleUPTimer
InstallHandler(HandleUPTimer, PrivateTimerIRQ);
инициализация ARM.Kernel.Mod - присваивается ЭВМ.Timeslice := Objects.Timeslice;
ARM.Objects.Mod/timer
HandleMPTimer
HandleUPTimer
InstallEventHandler (присваивает переменной timer)
Итак, теперь нам нужно в ARMv9 понять, что такое Private Timer, и по возможности найти такой же в BCM2836 (и в QEMU).
Последний раз редактировалось БудДен 16.10.22 22:38, всего редактировалось 1 раз.
Re: Запуск обычной версии под RPi
Или хоть какой-нибудь таймер... https://forums.raspberrypi.com/viewtopi ... 3#p1315584 - тут пишут обнадёживающе:
О, и даже ссылки на примеры, это очень хорошо:
https://github.com/eggman/raspberrypi/t ... i2/timer01
Правда примеры работают только в QEMU, но не на железке, это уже хуже.
Осталось лишь, чтобы и наша QEMU это поддерживала.Looking at the QEMU source it seems it still does not support he System Timer device in the Raspberry Pi emulation.
However the -M raspi2 and -M raspi3 emulations do include the ARM generic timer device (per processor core) and it does appear to have the interrupts connected so you should be able to use that one instead.
See the appropriate ARM Architecture Reference Manual for details of programming the generic timer.
О, и даже ссылки на примеры, это очень хорошо:
https://github.com/eggman/raspberrypi/t ... i2/timer01
Правда примеры работают только в QEMU, но не на железке, это уже хуже.
Re: Запуск обычной версии под RPi
Поскольку есть аж два системных таймера и прерывания от них работают, можно отправить 2 ядра в простой, и сделать 2-ядерную ОС.
Re: Запуск обычной версии под RPi
https://forums.raspberrypi.com/viewtopi ... 1&p=922616 - вот тут вроде бы решение, хотя это ещё надо посмотреть.
Re: Запуск обычной версии под RPi
Дошёл до несуществующей инструкции cpsie i