Я создаю 64-битное ядро x86-64 и тестирую его на своей реальной машине. В коде драйвера nvme я создаю очередь завершения ввода-вывода и вызываю функцию nvme_admin в строке №. 312 (см. 0 ).
Я проверяю очередь завершения администратора после отправки команд контроллеру. Я отправляю команды в очередь отправки администратора, начиная со строки №. 258, и я пишу новое хвостовое значение в строке №. 221. Затем я проверяю очередь завершения при вызове функции nvme_admin_wait в строке 234. Здесь цикл do- while в строке №. 206 — бесконечный цикл.
Как определить, почему запись администратора никогда не обрабатывалась? После записи в регистр дверного звонка бит паузы обработки (CSTS.PP) равен 0. Кроме того, контроллер включен, готов и исправен (CSTS.CFS). Что-то не так с командами, которые я отправил контроллеру nvme?
Обновлено: после исправления функции получения базового адреса nvme она работает на qemu, но все еще не на моей реальной машине.
Спасибо.
Как упомянул Андрей, каждый раз, когда вы получаете доступ к аппаратному регистру через указатель, на нем должен быть volatile. (например) val = *((volatile uint32_t *) addr); Для удобства вы можете обернуть это в макрос или встроенную функцию.
использование ключевого слова volatile не помогает ему работать на моей реальной машине. Я исправил функцию получения базового адреса nvme, и теперь она работает в qemu. Но как заставить его работать на моей реальной машине? Хотя спасибо за предложения.
@AndreyTurkin из моего последнего комментария от 27 мая, не могли бы вы рассказать мне, что еще я могу попробовать?
Уже сделал, ты просто проигнорировал. Барьеры памяти? Вы добавили volatiles... отлично, теперь ваш компилятор делает то, что вы хотите. Также есть процессор, который может свободно переупорядочивать/разделять/объединять операции чтения и записи в каком-то диком и удивительном порядке, и устройства MMIO не могут с этим жить (qemu - это эмуляция на основе процессора, поэтому он всего этого не видит). Работать с MMIO довольно сложно! Гуглите, как это сделать правильно. Вот прискорбно маленькое резюме на osdev: wiki.osdev.org/Memory_mapped_registers_in_C/C++ , а вот довольно умопомрачительная история о Linux: lwn.net/Articles/698014
Спасибо @AndreyTurkin. Раньше я не понимал, как использовать барьеры памяти. На этот раз по предоставленной вами ссылке osdev я добавил барьеры памяти GCC asm volatile ("": : :"memory"); в места, которые вы упомянули ранее. Он до сих пор не работает :(





Я решил эту проблему с драйвером NVMe. Я переписал драйвер с нуля, следуя вики и спецификации, и этот коммит (см. [0]) наконец заставил его работать.
Огромное спасибо за помощь в комментариях выше :) Я многому научился на этом пути.
[0]: https://github.com/robstat7/Raam/commit/eb9bd8c725808d963abd1c87ec2a5e2bcb899d9b
Я ожидаю увидеть очистку TLB после изменения PDE. Что еще более важно, я ожидаю увидеть там некоторые барьеры памяти, например. между заполнением команды и ее отправкой, а также между отправкой команды и проверкой статуса. Вдобавок ко всему, такие функции, как
nvme_init_identify, являются безумием с точки зрения языка C, если в них нет хотя бы какой-то изменчивости (см. godbolt.org/z/5z4eqW94d, чтобы узнать, как компилятор C это исказит).