Форум программистов «Весельчак У»
  *
Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.
Вам не пришло письмо с кодом активации?

  • Рекомендуем проверить настройки временной зоны в вашем профиле (страница "Внешний вид форума", пункт "Часовой пояс:").
  • У нас больше нет рассылок. Если вам приходят письма от наших бывших рассылок mail.ru и subscribe.ru, то знайте, что это не мы рассылаем.
   Начало  
Наши сайты
Помощь Поиск Календарь Почта Войти Регистрация  
 
Страниц: [1]   Вниз
  Печать  
Автор Тема: Выделение памяти при передаче данных из Kernel Mode в User  (Прочитано 14613 раз)
0 Пользователей и 4 Гостей смотрят эту тему.
dvp
Гость
« : 28-08-2003 12:40 » 

Получаю я к примеру некую структуру из драйвера через IOCTL.
Одно из ее полей UNICODE_STRING. Так вот где мне надо под Buffer память выделять, в режиме ядра или пользовательском?
Записан
Гром
Птычк. Тьфу, птычник... Вот!
Готовлюсь к пенсии

il
Offline Offline
Пол: Мужской
Бодрый птах


« Ответ #1 : 28-08-2003 13:27 » 

А в чем собственно вопрос, куда получаешь там и выделяй, в драйвере получаешь - в kernel mod в программе в user mod
Записан

А птичку нашу прошу не обижать!!!
SlavaI
Главный специалист

ru
Offline Offline

« Ответ #2 : 28-08-2003 13:56 » 

Уточняем
UNICODE_STRING содержит указатель на буфер и тут два варианта-где этот буфер находится
1) Буфер находится в системном адресном пространстве. Это значит из пользовательского приложения его не достать.
2) Буфер в адресном пространстве пользовательского процесса. Тогда все нормально.
Далее конкретизируем.
3)Пользовательское приложение не может выделить память в системном адресном пространстве.
4)А код, работающий в режиме ядра, может выделить память как в системном адресном пространстве(пулы ядра), так и в пользовательском приложении, только надо учитывать контекст.

Соответсвенно если ты передаешь в пользовательское приложение указатель на буфер, то в соответствии с пунктом 1 и 2, буфер должен быть в пользовательском пространстве, а сделать это тебе позволяет пункт 4. Но более удобно так- из пользовательского пространства передать указатель на выделенную в нем память в драйвер и в него из драйвера писать, но только учесть, что делать это можно только в контексте процесса в котором выделен буфер.
Твой вопрос из разряда разделения памяти между юзер-модом и кернел модом .
Записан
SlavaI
Главный специалист

ru
Offline Offline

« Ответ #3 : 28-08-2003 14:02 » 

Также читай вот тут
http://www.osronline.com/article.cfm?id=39

А также тему "Передача данных в приложение" в старом форуме в разделе Drivers, он выложен в виде chm файла в FAQ.
Записан
dvp
Гость
« Ответ #4 : 29-08-2003 12:45 » 

Цитата

Соответсвенно если ты передаешь в пользовательское приложение указатель на буфер, то в соответствии с пунктом 1 и 2, буфер должен быть в пользовательском пространстве, а сделать это тебе позволяет пункт 4. Но более удобно так- из пользовательского пространства передать указатель на выделенную в нем память в драйвер и в него из драйвера писать, но только учесть, что делать это можно только в контексте процесса в котором выделен буфер.

А как из драйвера писать в переданный пользовательский буфер В КОНТЕКСТЕ ПОЛЬЗОВАТЕЛЬСКОГО ПРОЦЕССА
 
FILE_OBJECT FileObject;
FileObject.FileName.Buffer = malloc(1000);
if(DeviceIoControl(hDrv,IOCTL_GET_FILE_OBJ,&Addr,sizeof(Addr), &FileObject, sizeof(FILE_OBJECT), &nnn, NULL))
{
                     
}

В драйвере

case IOCTL_GET_FILE_OBJ:

FileAddress = *(PVOID*)Irp->AssociatedIrp.SystemBuffer;
fi = (PFILE_OBJECT)FileAddress;
fo = (PFILE_OBJECT)Irp->AssociatedIrp.SystemBuffer;
fo->Type           = fi->Type;
...
//RtlZeroMemory(fo->FileName.Buffer, MAX_FOBJ_FILE_LEN*2); -> BSOD
DbgPrint("input name %X",fi->FileName.Buffer);
DbgPrint("output name %X",fo->FileName.Buffer); -> выводит типа 0 или 80 ...
fo->FileName.Length = fi->FileName.Length;
fo->FileName.MaximumLength = fi->FileName.MaximumLength;
//RtlCopyMemory(fo->FileName.Buffer, fi->FileName.Buffer, ul);
Записан
SlavaI
Главный специалист

ru
Offline Offline

« Ответ #5 : 29-08-2003 13:04 » 

Цитата

А как из драйвера писать в переданный пользовательский буфер В КОНТЕКСТЕ ПОЛЬЗОВАТЕЛЬСКОГО ПРОЦЕССА


Формулировка несколько несколько не та- я бы сказал так- В контексте пользовательского процесса, создавшего буфер.

Вопрос про контекст- это СУПЕР вопрос при написании драйверов. Не поняв его можно забить на дальнейшую работу.

Под словом контекст я(да и другие тоже) понимают страницы памяти, которые представляют в данный момент пространство пользователя для данного процессора(подчеркну ПРОЦЕССОРА- кремниевая штучка такая). Так вот- при переключении процессов(а вернее потоков, принадлежащих разным процессам), эти страницы меняются(ведь у каждого процесса своя память!). В противоположность пространству пользователя- в Windows NT/2k/XP/2003 страницы памяти, представляющие пространство ядра(или системное, как я иногда пишу) одинаковы для всех процессов, выполняемых на данном процессоре, и для всех процессоров, за исключением нескольких участков памяти, которые отображаются для каждого процесса разными страницами(так называемое hyperspace и таблицы страниц). При переключении процессов страницы пространства ядра не заменяются и виртуальные адреса системных структур также не изменяются(так как верхние части PDE у всех процессов одинаковые).
  Так вот- при записи в пользовательский буфер из ядра, ты должен быть уверен, что страницы пространства пользователя принадлежат тому же процессу, в котором буфер выделен, а проще говоря- в данный момент выполняется на процессоре этот процесс. Гарантию этого тебе дают следующий факты
1) при вызове самого верхнего драйвера в стеке драйверов вызов в режиме ядра идет в контексте вызвавшего процесса. Рассматривай это как вызов обыкновенной ф-ции.
2) Вызов через IOCTL аналогичен пункту 1.

Главное пойми- единственный, кто может тебе испортить все дело, то есть изменить контекст, это другой драйвер, сидящий над твоим. Если над твоим никого нет- это 100% гарантия что контекст будет совпадать с контекстом вызвавшего процесса.
Теперь про твой код- если твой драйвер верхний в стеке, то контекст вызова совпадает с контекстом процесса, вызвавшего DeviceIoControl.
Записан
dorador
Гость
« Ответ #6 : 29-08-2003 13:52 » new

а в чем смысл передачи UNICODE_STRING в пользовательский режим ?
Ведь там эта структура, вроде, не определена или я ошибаюсь ?
Получается, что ее надо определять так же как в драйвере.
Может лучше в приложении определить к примеру
TCHAR Buf[128];
передать это дело в драйвер
а там скопировать, т.е. что-то вроде этого
PUCHAR pStrBuf;
UNICODE_STRING name;
pStrBuf = (PUCHAR)Irp->AssociatedIrp.SystemBuffer;
RtlInitUnicodeString(&name, NT_DEVICE_NAME);
RtlCopyBytes(pStrBuf, name.Buffer, name.Length + 1);
Irp->IoStatus.Information = name.Length + 1;
это кусок я добавил в пример статьи "Драйвер с нуля"
и он там прекрасно работает
в прикладной программе печатается NT_DEVICE_NAME
wprintf(L"%s\n",Buf);
только надо _UNICODE добавить в Preprocessor definitions
а еще можно из UNICODE_STRING сделать ANSI_STRING
RtlUnicodeStringToAnsiString(&nameAnsi, &name, 1);
может этот пост немного не по теме, но просто я как раз только что искал способы передачи строки из драйвера в приложение и остановился на последнем способе
может пригодиться автору темы
Записан
dvp
Гость
« Ответ #7 : 30-08-2003 11:05 » 

>SlavaI
то есть пока до моего драйвера доходит очередь, контекст пользовательского процесса меняется, и FileName.Buffer указывает уже на что-то в АП другого потока.
А если драйвер находтися на вершине стека, то процессор просто не успевает переключится на другой поток?
Спасибо за разъяснения.
То есть в данном варианте придется 2 раза обращаться к драйверу, сначала узнавать размер FileName.Buffer, а затем выделять буфер в User mode в и передавать уже его непосредственно.
Записан
dvp
Гость
« Ответ #8 : 01-09-2003 05:27 » 

И вдогонку,
когда происходит (когда гарантированно не происходит) переключение контекстов?
Кто переключает контексты(какой компонент ядра)?
Записан
SlavaI
Главный специалист

ru
Offline Offline

« Ответ #9 : 01-09-2003 06:45 » 

Цитата

то есть пока до моего драйвера доходит очередь, контекст пользовательского процесса меняется, и FileName.Buffer указывает уже на что-то в АП другого потока.
А если драйвер находтися на вершине стека, то процессор просто не успевает переключится на другой поток?


Никаких гонок нет. Успел- не успел. Не то.
Блин, когда же народ прекратит думать что ядро работает по каким-то особенным правилам! Нет там никаких гонок!
Если драйвер на вершине стека то он всегда в контексте вызываемого потока, пусть он хоть на час уйдет после этого в работу, его вызов аналогичен вызову любой ф-ции в юзер моде. Он вызывается в контексте юзерского потока и будет в нем ВСЕГДА! Только он сам может перевести обработку в другой контекст.
Если драйвер не на вершине, то все зависит от верхних драйверов. Только они могут изменить контекст вызова. Вот некоторые из случаев когда контекст меняется из-за верхних драйверов:
1) Откладывание отработки IRP в отдельный системный поток, и вызов нижележащего драйвера из него. Сюда же входят и системные очереди.
2) Отработка с использованием DPC.

Цитата

когда происходит (когда гарантированно не происходит) переключение контекстов?


Переключение контекстов происходит при IRQL<=APC_LEVEL в произвольный момент времени, при IRQL>=DISPATCH_LEVEL потоки не переключаются.
Также имей в виду, что если драйвер вызван из потока, а потом потоки переключили, то процедура драйвера не выполняется пока опять этот же поток не запланируют на выполнение. Процедура лрайвера работает по тем же правилам, что и пользовательский код.

Цитата

Кто переключает контексты


Планировщик потоков- это набор ф-ций, которые вызываются для определения того надо ли переключать потоки и если надо, то на какой переключится.
Переключение потоков производится в определенных точках ядра.
Ф-ция переключающая потоки-
KiSwapThread
а процессы-
KiSwapProcess
Вот в точках где они вызываются и происходит переключение контекстов.
Записан
Страниц: [1]   Вверх
  Печать  
 

Powered by SMF 1.1.21 | SMF © 2015, Simple Machines