Комментарии 30
Довольно интересная статья, я так понимаю это начало цикла статей про программирование драйверов под дарвин?
Именно. Про IOKit я вкратце рассказывал здесь: habrahabr.ru/blogs/macosxdev/36875/
Статья просто супер.
Думаю, её можно рекомендовать всем, кто интересуется архитектурой компов.
Думаю, её можно рекомендовать всем, кто интересуется архитектурой компов.
НЛО прилетело и опубликовало эту надпись здесь
НЛО прилетело и опубликовало эту надпись здесь
У вас очень странная логика, как буд-то эти самые программы не люди пишут, а создают роботы, аля «Гамбургеры продаются в магазине».
А откуда берутся программы нужные?
да что вы спорите с toshirskij? посмотрите как он себя ведет, на его аватар… я не могу описать своего презрения к этому человеку!
Интересно, спасибо. Только я не нашел расшифровку PPU. И опечатка в части Contiguous DMA принцим->принцип.
Очень интересно. Только возник такой вопрос касательно алгоритма работы Scatter/gather DMA:
Сначала драйвер(кстати, чей дравер? ОС?) выделяет память под DMA буферы. Далее устройства имеют доступ к буферам через указатели в дескрипторах. Но кто следит за overhead'ами? Если буферов оказывается недостаточно, кем, как и когда данная ситуация распознаётся и как/на каком этапе решается?
И ещё вопрос касательно этого: «Драйвер ОС просматривает все дескрипторы DMA буферов, определяет какие из них были заполнены контроллером устройства, пересылает данные из буфера далее по стеку устройств и помечает буфер как готовый к DMA трансферу.»
Каков обычно размер этого односвязаного списка DMA-буферов? Это ведь нерационально каждый раз просматривать его. Причём я так понимаю под «пересылает данные из буфера» имеется ввиду копирование этих данных? Т.к. иначе блок не может быть помечен как «готовый к DMA трансферу» пока на эти данные кто-то ссылается.
Заранее спасибо, надеюсь понятно изложил.
Сначала драйвер(кстати, чей дравер? ОС?) выделяет память под DMA буферы. Далее устройства имеют доступ к буферам через указатели в дескрипторах. Но кто следит за overhead'ами? Если буферов оказывается недостаточно, кем, как и когда данная ситуация распознаётся и как/на каком этапе решается?
И ещё вопрос касательно этого: «Драйвер ОС просматривает все дескрипторы DMA буферов, определяет какие из них были заполнены контроллером устройства, пересылает данные из буфера далее по стеку устройств и помечает буфер как готовый к DMA трансферу.»
Каков обычно размер этого односвязаного списка DMA-буферов? Это ведь нерационально каждый раз просматривать его. Причём я так понимаю под «пересылает данные из буфера» имеется ввиду копирование этих данных? Т.к. иначе блок не может быть помечен как «готовый к DMA трансферу» пока на эти данные кто-то ссылается.
Заранее спасибо, надеюсь понятно изложил.
Понятно :) По порядку:
> Сначала драйвер(кстати, чей дравер? ОС?) выделяет память под DMA буферы.
Драйвер устройства, я его тут называл драйвером ОС, чтобы никто не запутался.
> Но кто следит за overhead'ами? Если буферов оказывается недостаточно, кем, как и когда данная ситуация распознаётся и как/на каком этапе решается?
Зависит от ситуации. Если у нас к примеру есть драйвер сетевой карты (я именно с ними имел достаточно много дела), то мы можем говорить о двух случаях:
1. overrun при отсылке пакета.
2. overrun при приеме.
Если имеет место первый случай, то очевидно, что overrun обнаруживает драйвер устройства в одной из своих процедур (например в Mac OS X, всмысле IOKit, это метод IOEthernetController:: outputPacket). overrun происходит из-за того, что устройство по какой-либо причине не успевает отправлять пакеты. Решение в данном случае, вернуть в процедуре драйвера код ошибки по типу output queue stalled. ОС просто перешлет этот пакет посже. Ну и если такая ситуация будет повторятся подряд на протяжении какого-либо времени, например контроллер повис, то значит нужно в драйвере это отслеживать и вовремя ресетнуть контроллер.
Если второй, то overrun обнаруживает сетевой контроллер. Он посылает прерывание и в регистре статуса прерываний выставляет какой-нибудь флажок, типа input queue overrun. Это сигнал драйверу, что нужно что-то делать. Как вариант, дропнуть старые пакеты в очереди и выставить в дескрипторе флажок, что буфер свободен, или же провести ресет контроллера.
> Каков обычно размер этого односвязаного списка DMA-буферов?
Зависит от конкретной железки. 64, 256 может быть. Может быть и больше.
> Это ведь нерационально каждый раз просматривать его.
Просмотреть 256 дескрипторов и проверить наличие установленного флага, что буфер был получен и его необходимо переслать на уровень выше — не такая уж и тяжелая задача. Есть разные методики. Например сетевые контроллеры от Realtek раньше просто писали подряд в каждый буфер в этом кольцевом списке дескрипторов, и после заполнения одного буфера давали прерывание. Посему драйвер мог хранить индекс текущего буфера и легко инкрементировать его после каждого прерывания.
> Причём я так понимаю под «пересылает данные из буфера» имеется ввиду копирование этих данных?
Верно, в случае сетевых драйверов, создается сетевой пакет (в Mac OS X — это mbuf, в линуксе — skb) и данные из буфера копируются в этот пакет.
> Сначала драйвер(кстати, чей дравер? ОС?) выделяет память под DMA буферы.
Драйвер устройства, я его тут называл драйвером ОС, чтобы никто не запутался.
> Но кто следит за overhead'ами? Если буферов оказывается недостаточно, кем, как и когда данная ситуация распознаётся и как/на каком этапе решается?
Зависит от ситуации. Если у нас к примеру есть драйвер сетевой карты (я именно с ними имел достаточно много дела), то мы можем говорить о двух случаях:
1. overrun при отсылке пакета.
2. overrun при приеме.
Если имеет место первый случай, то очевидно, что overrun обнаруживает драйвер устройства в одной из своих процедур (например в Mac OS X, всмысле IOKit, это метод IOEthernetController:: outputPacket). overrun происходит из-за того, что устройство по какой-либо причине не успевает отправлять пакеты. Решение в данном случае, вернуть в процедуре драйвера код ошибки по типу output queue stalled. ОС просто перешлет этот пакет посже. Ну и если такая ситуация будет повторятся подряд на протяжении какого-либо времени, например контроллер повис, то значит нужно в драйвере это отслеживать и вовремя ресетнуть контроллер.
Если второй, то overrun обнаруживает сетевой контроллер. Он посылает прерывание и в регистре статуса прерываний выставляет какой-нибудь флажок, типа input queue overrun. Это сигнал драйверу, что нужно что-то делать. Как вариант, дропнуть старые пакеты в очереди и выставить в дескрипторе флажок, что буфер свободен, или же провести ресет контроллера.
> Каков обычно размер этого односвязаного списка DMA-буферов?
Зависит от конкретной железки. 64, 256 может быть. Может быть и больше.
> Это ведь нерационально каждый раз просматривать его.
Просмотреть 256 дескрипторов и проверить наличие установленного флага, что буфер был получен и его необходимо переслать на уровень выше — не такая уж и тяжелая задача. Есть разные методики. Например сетевые контроллеры от Realtek раньше просто писали подряд в каждый буфер в этом кольцевом списке дескрипторов, и после заполнения одного буфера давали прерывание. Посему драйвер мог хранить индекс текущего буфера и легко инкрементировать его после каждого прерывания.
> Причём я так понимаю под «пересылает данные из буфера» имеется ввиду копирование этих данных?
Верно, в случае сетевых драйверов, создается сетевой пакет (в Mac OS X — это mbuf, в линуксе — skb) и данные из буфера копируются в этот пакет.
На линуксе количество дескрипторов можно посмотреть так:
root@eva00:~# ethtool -g eth0
Ring parameters for eth0:
Pre-set maximums:
RX: 4096
RX Mini: 0
RX Jumbo: 0
TX: 4096
Current hardware settings:
RX: 256
RX Mini: 0
RX Jumbo: 0
TX: 256
root@eva00:~# ethtool -g eth0
Ring parameters for eth0:
Pre-set maximums:
RX: 4096
RX Mini: 0
RX Jumbo: 0
TX: 4096
Current hardware settings:
RX: 256
RX Mini: 0
RX Jumbo: 0
TX: 256
Прекрасная статья! Хотя не очень интересуюсь тем, что происходит на таком низком уровне, однако, даже в обзеобразовательных целях было очень интересно почитать! Спасибо!
И, поправьте, пожалуйста: «следует передать операционной системы».
И, поправьте, пожалуйста: «следует передать операционной системы».
Кстати говоря, DMA используется не только для обмена данными между устройством и ОЗУ, но также между устройствами в системе, возможен DMA трансфер между двумя участками ОЗУ (хотя данный маневр не применим к x86 архитектуре)
Применим. DMA просто генерирует RD/WR запросы на шине. И, например, если в качестве места назначения указана видеопамять, то успешно можно загадить экран какими-нибудь кракозяблами. Хотя, конечно, PCI-E — это не общая шина. Возможно, там такой трюк не проходит. Но на PCI системах случалось ошибаться.
Также регистры устройства могут отображатся в ОЗУ (Memory Mapped Registers), т.е. физическую память системы. Данный метод имеет ряд преимуществ, а именно:
* Скорость доступа к физической памяти выше, нежели к IO портам.
* IO порты могут отображать не более 65535 байт регистров, в то время как размер ОЗУ современных компьютеров в разы больше.
* Читать регистры устройства из ОЗУ проще, нежели с помощью IO портов :)
Лучше написать: на физическое адресное пространство. Потому что память никуда не девается, просто host-контроллер перенаправляет запросы на чтение/запись по определённым адресам на шину PCI. На скорость доступа, кстати, это никак не влияет.
Применим. DMA просто генерирует RD/WR запросы на шине. И, например, если в качестве места назначения указана видеопамять, то успешно можно загадить экран какими-нибудь кракозяблами. Хотя, конечно, PCI-E — это не общая шина. Возможно, там такой трюк не проходит. Но на PCI системах случалось ошибаться.
Также регистры устройства могут отображатся в ОЗУ (Memory Mapped Registers), т.е. физическую память системы. Данный метод имеет ряд преимуществ, а именно:
* Скорость доступа к физической памяти выше, нежели к IO портам.
* IO порты могут отображать не более 65535 байт регистров, в то время как размер ОЗУ современных компьютеров в разы больше.
* Читать регистры устройства из ОЗУ проще, нежели с помощью IO портов :)
Лучше написать: на физическое адресное пространство. Потому что память никуда не девается, просто host-контроллер перенаправляет запросы на чтение/запись по определённым адресам на шину PCI. На скорость доступа, кстати, это никак не влияет.
> И, например, если в качестве места назначения указана видеопамять, то успешно можно загадить экран какими-нибудь кракозяблами.
Да, можно ошибится с адресами и запортить содержимое памяти по случайному адресу, но если честно я не знаю, как можно было бы копировать участок физической памяти с одного адреса, на другой. Я так понимаю для этого нужен какой-нибудь центральный DMA контроллер или аппаратный IO MMU, но x86 этого нет, вернее в PCI нету централизированного контроллера, вместо этого bus mastering и придумали ведь ;)
> Лучше написать: на физическое адресное пространство. Потому что память никуда не девается, просто host-контроллер перенаправляет запросы на чтение/запись по определённым адресам на шину PCI.
Согласен, изменил формулировку. Правда память от этого свободной не становится, и int 15h сообщает системе, что память занята. Кстати надо будет в этом месте дополнить статью о memory remap.
> На скорость доступа, кстати, это никак не влияет.
Это только так кажется. На самом деле на IO порты обязательно вешается в SMI хендлере IO Trap, для самых разных нужд, как-то эмулирование для приложений PS/2 мыши и клавиатуры, когда вместо них — USB. Перенаправлением запросов в этом случае занимается SMI хендлер. Так что тут тоже есть определенный оверхед, хоть и небольшой :)
Да, можно ошибится с адресами и запортить содержимое памяти по случайному адресу, но если честно я не знаю, как можно было бы копировать участок физической памяти с одного адреса, на другой. Я так понимаю для этого нужен какой-нибудь центральный DMA контроллер или аппаратный IO MMU, но x86 этого нет, вернее в PCI нету централизированного контроллера, вместо этого bus mastering и придумали ведь ;)
> Лучше написать: на физическое адресное пространство. Потому что память никуда не девается, просто host-контроллер перенаправляет запросы на чтение/запись по определённым адресам на шину PCI.
Согласен, изменил формулировку. Правда память от этого свободной не становится, и int 15h сообщает системе, что память занята. Кстати надо будет в этом месте дополнить статью о memory remap.
> На скорость доступа, кстати, это никак не влияет.
Это только так кажется. На самом деле на IO порты обязательно вешается в SMI хендлере IO Trap, для самых разных нужд, как-то эмулирование для приложений PS/2 мыши и клавиатуры, когда вместо них — USB. Перенаправлением запросов в этом случае занимается SMI хендлер. Так что тут тоже есть определенный оверхед, хоть и небольшой :)
На самом деле на IO порты обязательно вешается в SMI хендлере IO Trap, для самых разных нужд, как-то эмулирование для приложений PS/2 мыши и клавиатуры, когда вместо них — USB.
Ну. Я про железо говорил. А на что там SMI вешается — никому не известно. Его можно и на доступ в память повешать, если железо это поддерживает. Но для того, чтобы железо с in и out работало никакого SMI не нужно.
Ну. Я про железо говорил. А на что там SMI вешается — никому не известно. Его можно и на доступ в память повешать, если железо это поддерживает. Но для того, чтобы железо с in и out работало никакого SMI не нужно.
Ну и это. +1. Аффтар, пиши ещё :)
… возможен DMA трансфер между двумя участками ОЗУ (хотя данный маневр не применим к x86 архитектуре).
Ну давно уже применим, только не для всех SoC, конечно, а только в тех, где есть DMA контроллер с поддержкой такого режима.
В микроконтроллерах dma тоже есть и классические и scatter gather.
Зарегистрируйтесь на Хабре, чтобы оставить комментарий
DMA для новичков или то, что вам нужно знать