Uso de memoria Base
Hola que tal, bueno pues primero que nada un saludo cordial espero me puedas ayudar en el problema que tengo, se trata de que quiero acceder a la memoria base que corresponde a un dispositivo PCI, si tengo el Vendor ID y el Device ID, ¿me servirá de algo?
Espero me esté dando a entender acerca de mi duda y sin más me despido esperando te encuentres bien.
Espero me esté dando a entender acerca de mi duda y sin más me despido esperando te encuentres bien.
1 Respuesta
Respuesta de luzrael
1
1
luzrael, Ingeniero de Telecomunicaciones
Pufff... Pues vale, si lo quieres saber allá tu, yo te respondo.
Antes de nada, lo que te voy a explicar vale SOLAMENTE para Windows NT 3.x, Windows NT 4.0, Windows 2000, Windows 2003 y XP.
NO VALE para W9x, pues esos sistemas usan un DDK distinto.
Asumo que estas familiarizado con el entorno del Kernel, y con la construcción de drivers de sistema. Por ello te describo solo el código explícito, para ello lo mejor es que metas el código en un device driver simple. Si lo que te estoy contando te suena a chino y no sabes hacer un driver de sistema, el tema se complica por que el acceso a la memoria de la tarjeta desde código de usuario se puede hacer, pero igualmente con el código que te describo y embebido en un driver al que llames desde tu aplicación y que pase la dirección de memoria física que has obtenido en el driver con el código que te comento y describo a tu aplicación. A continuación debes en tu aplicación mapear la memoria física a memoria virtual de tu aplicación (son dos llamadas más a otras funciones, éstas ya en tu código de usuario o aplicación) y acceder a esa memoria como si fuera de la aplicación.
Bueno vamos con el código que hace lo que tu pides. En primer lugar necesitas una función que te devuelva el numero de bus y el slot dentro del bus en el que se halla tu tarjate, a partir del VendorID y el DeviceID, que es lo que realmente conoce nuestro sistema. Ten en cuenta que el hardware típico de una placa madre comparte varios buses (ISA, PCI y AGP tipcamente, aunque dependiendo de la placa madre podría ser también VESA o el nuevo bus serie de las tarjetas gráficas).
Y por desgracia, no sabemos ni en que bus ni en en que slot se halla la tarjeta. Así pues habrá que buscarla dentro de cada bus y slot.
En principio, esto se puede obviar, si sabemos el bus y el slot. El bus ISA solo se muestra como un bus dentro de la tarjeta madre. Pero el bus PCI tiene la particularidad de que en el sistema se puede mostrar como uno, dos o más buses. Digamos el PCI A y el PCI B, y eventualmente PCI C, PCI D. Con lo que aunque sepamos el slot (el slot es el slot físico y real donde se enchufa la tarjeta), puede ocurrir que no sepamos en que bus PCI se halla. Eso depende de la tarjeta madre.
La función que hace la búsqueda que te comento es la siguiente:
NTSTATUS PciFindDevice(IN USHORT vendorID, IN USHORT deviceID, OUT PULONG pdwBusNumber, OUT PULONG pdwSlotNumber)
{
PCI_SLOT_NUMBER slotNumber;
PCI_COMMON_CONFIG pciData;
ULONG busNumber;
ULONG deviceNumber;
ULONG functionNumber;
// Recordemos ...
//
// typedef struct _PCI_SLOT_NUMBER {
// union {
// struct {
// ULONG DeviceNumber:5;
// ULONG FunctionNumber:3;
// ULONG Reserved:24;
// } bits;
// ULONG AsULONG;
// } u;
// } PCI_SLOT_NUMBER, *PPCI_SLOT_NUMBER;
//
slotNumber.u.AsULONG = 0;
// Scanea en todos los buses.
for (busNumber = 0; busNumber < 256; busNumber++)
{
// Scanea todos slots de cada bus
for (deviceNumber = 0; deviceNumber < PCI_MAX_DEVICES; deviceNumber++)
{
slotNumber.u.bits.DeviceNumber = deviceNumber;
// Scanea cada funcion
for (functionNumber = 0; functionNumber < PCI_MAX_FUNCTION; functionNumber++)
{
slotNumber.u.bits.FunctionNumber = functionNumber;
// Comprobamos si este bus es PCI y en si dicho slot contiene una tarjeta.
// Leemos los 256 bytes del área de configuración de la tarjeta que haya en ese bus/slot.
if (HalGetBusData(PCIConfiguration, busNumber, slotNumber.u.AsULONG, &pciData, sizeof(ULONG)) == 0)
{
// Vaya, este bus no es un bus PCI. Buscamos el siguiente bus asignando a DeviceNumber el máximo de dispositivos por bus.
// NOTA: Microsoft no nos garantiza que loa buses estén secuencialmnete ordenados.
deviceNumber = PCI_MAX_DEVICES;
break;
}
// Este bus/slot contiene una tarjeta. Comprobemos si es la que buscamos.
if ( (pciData.VendorID == vendorID) && (pciData.DeviceID == deviceID) )
{
// Hemos hallado nuestra tarjeta!!!!
*pdwBusNumber = busNumber;
*pdwSlotNumber = slotNumber.u.AsULONG;
// Pos salimos...
return STATUS_SUCCESS;
}
// Pos no era nuestra tarjeta, busca otra tarjeta.
} // functionNumber
} // deviceNumber
} // busNumber
return STATUS_DEVICE_DOES_NOT_EXIST;
}
Si la función devuelve STATUS_SUCCESS ya tenemos el bus y el slot donde se halla la tarjeta.
Ahora hemos de llamar a una función que te devuelva la dirección de memoria de la tarjeta que ocupa ese Bus y ese Slot.
Esa función es HalGetBusData().
Por ultimo te deberías hacer una función para mapear la memoria física a memoria virtual en el KERNEL. Memoria que ya puedes usar tranquilamente. Eso si en el RING0!
Esta función de mapeo es la siguiente:
PVOID MapSystemMemory(ULONG ulBusNumber, IN PVOID pPhysicalAddress, IN ULONG ulLength)
{
NTSTATUS ntStatus;
ntStatus = STATUS_SUCCESS;
PHYSICAL_ADDRESS translatedAddress;
PHYSICAL_ADDRESS busAddress;
ULONG addressSpace;
BOOLEAN bTranslate;
busAddress.LowPart = (ULONG)pPhysicalAddress; // | 8;
busAddress.HighPart = 0;
translatedAddress.LowPart = 0;
translatedAddress.HighPart = 0;
addressSpace = 0x00; // Memory space
bTranslate = HalTranslateBusAddress(PCIBus, ulBusNumber, busAddress, &addressSpace, &translatedAddress);
if ( !bTranslate || addressSpace )
{
return NULL;
}
//
// map memory to system space
//
return MmMapIoSpace(translatedAddress, ulLength, MmNonCached);
}
Y el codigo final es algo así como:
#include <ntddk.h>
/*
// Esta estructura esta descrita en ntddk.h
typedef struct _PCI_COMMON_CONFIG
{
USHORT VendorID; // (ro)
USHORT DeviceID; // (ro)
USHORT Command; // Device control
USHORT Status;
UCHAR RevisionID; // (ro)
UCHAR ProgIf; // (ro)
UCHAR SubClass; // (ro)
UCHAR BaseClass; // (ro)
UCHAR CacheLineSize; // (ro+)
UCHAR LatencyTimer; // (ro+)
UCHAR HeaderType; // (ro)
UCHAR BIST; // Built in self test
union {
struct _PCI_HEADER_TYPE_0 {
ULONG BaseAddresses[6];
ULONG CIS;
USHORT SubVendorID;
USHORT SubSystemID;
ULONG ROMBaseAddress;
ULONG Reserved2[2];
UCHAR InterruptLine; //
UCHAR InterruptPin; // (ro)
UCHAR MinimumGrant; // (ro)
UCHAR MaximumLatency; // (ro)
} type0;
} u;
UCHAR DeviceSpecific[192];
} PCI_COMMON_CONFIG, *PPCI_COMMON_CONFIG;
*/
ULONG ulBusNumber;
ULONG ulSlotNumber;
ULONG ulIrqNumber;
ULONG ulPhysicalAddress;
PVOID pMemRegister;
NTSTATUS status = STATUS_SUCCESS;
status = PciFindDevice(vendorID, deviceID, &ulBusNumber, &ulSlotNumber);
if ( status == STATUS_SUCCESS)
{
PCI_COMMON_CONFIG pciConfiguration;
status = HalGetBusData(PCIConfiguration, ulBusNumber, ulSlotNumber, &pciConfiguration, sizeof(pciConfiguration));
if ( status == STATUS_SUCCESS)
{
ulPhysicalAddress = pciConfiguration.u.type0.BaseAddresses[0] & 0xFFFFFFF0;
ulIrqNumber = pciConfiguration.u.type0.InterruptLine;
pMemRegister = MapSystemMemory(ulBusNumber, (PVOID)ulPhysicalAddress, 0x1000);
}
}
// Y ya esta... Para usar esa memoria en el ring 0, solo debes hacer algo asi como
PDWORD pData = (PDWORD)((PBYTE)pMemRegister + BT848_INT_STAT);
*pData = BT848_INT_RISCI;
Al finalizar de tu programa, o cuando no uses más esa memoria, no te olvides devolverla al sistema. Para ello llama a la función MmUnmapIoSpace(pMemRegister, ulPhysicalAddress); Estas usando recursos del Kernel, y en ese nivel Windows no controla ni libera la memoria mapeada como hace a nivel de usuario. Igualmente, si aquí haces algo mal y te da un trap, no te fallara la aplicación: Te saldrá la famosa ventana azul y fin de todo hasta que rearranques el ordenador.
Para cualquier tema o duda enviame un correo a [email protected]
Antes de nada, lo que te voy a explicar vale SOLAMENTE para Windows NT 3.x, Windows NT 4.0, Windows 2000, Windows 2003 y XP.
NO VALE para W9x, pues esos sistemas usan un DDK distinto.
Asumo que estas familiarizado con el entorno del Kernel, y con la construcción de drivers de sistema. Por ello te describo solo el código explícito, para ello lo mejor es que metas el código en un device driver simple. Si lo que te estoy contando te suena a chino y no sabes hacer un driver de sistema, el tema se complica por que el acceso a la memoria de la tarjeta desde código de usuario se puede hacer, pero igualmente con el código que te describo y embebido en un driver al que llames desde tu aplicación y que pase la dirección de memoria física que has obtenido en el driver con el código que te comento y describo a tu aplicación. A continuación debes en tu aplicación mapear la memoria física a memoria virtual de tu aplicación (son dos llamadas más a otras funciones, éstas ya en tu código de usuario o aplicación) y acceder a esa memoria como si fuera de la aplicación.
Bueno vamos con el código que hace lo que tu pides. En primer lugar necesitas una función que te devuelva el numero de bus y el slot dentro del bus en el que se halla tu tarjate, a partir del VendorID y el DeviceID, que es lo que realmente conoce nuestro sistema. Ten en cuenta que el hardware típico de una placa madre comparte varios buses (ISA, PCI y AGP tipcamente, aunque dependiendo de la placa madre podría ser también VESA o el nuevo bus serie de las tarjetas gráficas).
Y por desgracia, no sabemos ni en que bus ni en en que slot se halla la tarjeta. Así pues habrá que buscarla dentro de cada bus y slot.
En principio, esto se puede obviar, si sabemos el bus y el slot. El bus ISA solo se muestra como un bus dentro de la tarjeta madre. Pero el bus PCI tiene la particularidad de que en el sistema se puede mostrar como uno, dos o más buses. Digamos el PCI A y el PCI B, y eventualmente PCI C, PCI D. Con lo que aunque sepamos el slot (el slot es el slot físico y real donde se enchufa la tarjeta), puede ocurrir que no sepamos en que bus PCI se halla. Eso depende de la tarjeta madre.
La función que hace la búsqueda que te comento es la siguiente:
NTSTATUS PciFindDevice(IN USHORT vendorID, IN USHORT deviceID, OUT PULONG pdwBusNumber, OUT PULONG pdwSlotNumber)
{
PCI_SLOT_NUMBER slotNumber;
PCI_COMMON_CONFIG pciData;
ULONG busNumber;
ULONG deviceNumber;
ULONG functionNumber;
// Recordemos ...
//
// typedef struct _PCI_SLOT_NUMBER {
// union {
// struct {
// ULONG DeviceNumber:5;
// ULONG FunctionNumber:3;
// ULONG Reserved:24;
// } bits;
// ULONG AsULONG;
// } u;
// } PCI_SLOT_NUMBER, *PPCI_SLOT_NUMBER;
//
slotNumber.u.AsULONG = 0;
// Scanea en todos los buses.
for (busNumber = 0; busNumber < 256; busNumber++)
{
// Scanea todos slots de cada bus
for (deviceNumber = 0; deviceNumber < PCI_MAX_DEVICES; deviceNumber++)
{
slotNumber.u.bits.DeviceNumber = deviceNumber;
// Scanea cada funcion
for (functionNumber = 0; functionNumber < PCI_MAX_FUNCTION; functionNumber++)
{
slotNumber.u.bits.FunctionNumber = functionNumber;
// Comprobamos si este bus es PCI y en si dicho slot contiene una tarjeta.
// Leemos los 256 bytes del área de configuración de la tarjeta que haya en ese bus/slot.
if (HalGetBusData(PCIConfiguration, busNumber, slotNumber.u.AsULONG, &pciData, sizeof(ULONG)) == 0)
{
// Vaya, este bus no es un bus PCI. Buscamos el siguiente bus asignando a DeviceNumber el máximo de dispositivos por bus.
// NOTA: Microsoft no nos garantiza que loa buses estén secuencialmnete ordenados.
deviceNumber = PCI_MAX_DEVICES;
break;
}
// Este bus/slot contiene una tarjeta. Comprobemos si es la que buscamos.
if ( (pciData.VendorID == vendorID) && (pciData.DeviceID == deviceID) )
{
// Hemos hallado nuestra tarjeta!!!!
*pdwBusNumber = busNumber;
*pdwSlotNumber = slotNumber.u.AsULONG;
// Pos salimos...
return STATUS_SUCCESS;
}
// Pos no era nuestra tarjeta, busca otra tarjeta.
} // functionNumber
} // deviceNumber
} // busNumber
return STATUS_DEVICE_DOES_NOT_EXIST;
}
Si la función devuelve STATUS_SUCCESS ya tenemos el bus y el slot donde se halla la tarjeta.
Ahora hemos de llamar a una función que te devuelva la dirección de memoria de la tarjeta que ocupa ese Bus y ese Slot.
Esa función es HalGetBusData().
Por ultimo te deberías hacer una función para mapear la memoria física a memoria virtual en el KERNEL. Memoria que ya puedes usar tranquilamente. Eso si en el RING0!
Esta función de mapeo es la siguiente:
PVOID MapSystemMemory(ULONG ulBusNumber, IN PVOID pPhysicalAddress, IN ULONG ulLength)
{
NTSTATUS ntStatus;
ntStatus = STATUS_SUCCESS;
PHYSICAL_ADDRESS translatedAddress;
PHYSICAL_ADDRESS busAddress;
ULONG addressSpace;
BOOLEAN bTranslate;
busAddress.LowPart = (ULONG)pPhysicalAddress; // | 8;
busAddress.HighPart = 0;
translatedAddress.LowPart = 0;
translatedAddress.HighPart = 0;
addressSpace = 0x00; // Memory space
bTranslate = HalTranslateBusAddress(PCIBus, ulBusNumber, busAddress, &addressSpace, &translatedAddress);
if ( !bTranslate || addressSpace )
{
return NULL;
}
//
// map memory to system space
//
return MmMapIoSpace(translatedAddress, ulLength, MmNonCached);
}
Y el codigo final es algo así como:
#include <ntddk.h>
/*
// Esta estructura esta descrita en ntddk.h
typedef struct _PCI_COMMON_CONFIG
{
USHORT VendorID; // (ro)
USHORT DeviceID; // (ro)
USHORT Command; // Device control
USHORT Status;
UCHAR RevisionID; // (ro)
UCHAR ProgIf; // (ro)
UCHAR SubClass; // (ro)
UCHAR BaseClass; // (ro)
UCHAR CacheLineSize; // (ro+)
UCHAR LatencyTimer; // (ro+)
UCHAR HeaderType; // (ro)
UCHAR BIST; // Built in self test
union {
struct _PCI_HEADER_TYPE_0 {
ULONG BaseAddresses[6];
ULONG CIS;
USHORT SubVendorID;
USHORT SubSystemID;
ULONG ROMBaseAddress;
ULONG Reserved2[2];
UCHAR InterruptLine; //
UCHAR InterruptPin; // (ro)
UCHAR MinimumGrant; // (ro)
UCHAR MaximumLatency; // (ro)
} type0;
} u;
UCHAR DeviceSpecific[192];
} PCI_COMMON_CONFIG, *PPCI_COMMON_CONFIG;
*/
ULONG ulBusNumber;
ULONG ulSlotNumber;
ULONG ulIrqNumber;
ULONG ulPhysicalAddress;
PVOID pMemRegister;
NTSTATUS status = STATUS_SUCCESS;
status = PciFindDevice(vendorID, deviceID, &ulBusNumber, &ulSlotNumber);
if ( status == STATUS_SUCCESS)
{
PCI_COMMON_CONFIG pciConfiguration;
status = HalGetBusData(PCIConfiguration, ulBusNumber, ulSlotNumber, &pciConfiguration, sizeof(pciConfiguration));
if ( status == STATUS_SUCCESS)
{
ulPhysicalAddress = pciConfiguration.u.type0.BaseAddresses[0] & 0xFFFFFFF0;
ulIrqNumber = pciConfiguration.u.type0.InterruptLine;
pMemRegister = MapSystemMemory(ulBusNumber, (PVOID)ulPhysicalAddress, 0x1000);
}
}
// Y ya esta... Para usar esa memoria en el ring 0, solo debes hacer algo asi como
PDWORD pData = (PDWORD)((PBYTE)pMemRegister + BT848_INT_STAT);
*pData = BT848_INT_RISCI;
Al finalizar de tu programa, o cuando no uses más esa memoria, no te olvides devolverla al sistema. Para ello llama a la función MmUnmapIoSpace(pMemRegister, ulPhysicalAddress); Estas usando recursos del Kernel, y en ese nivel Windows no controla ni libera la memoria mapeada como hace a nivel de usuario. Igualmente, si aquí haces algo mal y te da un trap, no te fallara la aplicación: Te saldrá la famosa ventana azul y fin de todo hasta que rearranques el ordenador.
Para cualquier tema o duda enviame un correo a [email protected]
Bueno, la verdad apenas comienzo en esto del desarrollo de drivers para dispositivos, así que tengo algunos problemas que parecieran ser elementales pero necesito saber si algo tengo mal, porque a mi parecer sólo se trata de incluir un par de librerías:
windows.h y ntddk.h o en su lugar wdm.h, que tengo por entendido se trata de mas o menos lo mismo al menos para declarar tan sólo una variable del tipo PCI_COMMON_CONFIG, mas el compilador (que por cierto estoy usando el de Visual C++ de visual studio 6.0 mas no se si sea lo correcto) me marca una serie de errores que mas bien parecen conflictos por sentencias include de las mismas librerías de ddk, es esto mas bien un problema del compilador que estoy usando? o mas bien se trata de algo diferente?
Gracias.
windows.h y ntddk.h o en su lugar wdm.h, que tengo por entendido se trata de mas o menos lo mismo al menos para declarar tan sólo una variable del tipo PCI_COMMON_CONFIG, mas el compilador (que por cierto estoy usando el de Visual C++ de visual studio 6.0 mas no se si sea lo correcto) me marca una serie de errores que mas bien parecen conflictos por sentencias include de las mismas librerías de ddk, es esto mas bien un problema del compilador que estoy usando? o mas bien se trata de algo diferente?
Gracias.
Pues si te dan esos errores puede ser por que estés intentando incluir tanto windows. H como ntddk.h
Solo debes incluir NTDDK. H ya que windows. H incluye headers que están a nivel de usuario y tu estas en el kernel, no lo olvides. No tienes acceso a ventanas, ni a ficheros, ni a sistemas de IPC, ni a memoria de usuario y mucho menos a la consola. Todo eso esta icluido en el windows. H y en el kernel no tienes acceso a ello. Por eso solo puedes usar NTDDK.H
Ademas, no se si lo sabes, por si acaso no te olvides de que en modo kernel TODO es unicode. Si copias un string que quieres leer o grabar en el registry, por ejemplo, este string debe ser unicode.
Solo debes incluir NTDDK. H ya que windows. H incluye headers que están a nivel de usuario y tu estas en el kernel, no lo olvides. No tienes acceso a ventanas, ni a ficheros, ni a sistemas de IPC, ni a memoria de usuario y mucho menos a la consola. Todo eso esta icluido en el windows. H y en el kernel no tienes acceso a ello. Por eso solo puedes usar NTDDK.H
Ademas, no se si lo sabes, por si acaso no te olvides de que en modo kernel TODO es unicode. Si copias un string que quieres leer o grabar en el registry, por ejemplo, este string debe ser unicode.
Ahh, se me olvidaba. No se te ocurra modificar el NTDDK.H. Esta bien como esta, y si te da errores es porque te falta algo, no porque el include este mal. Así que intenta solucionar los problemas por otra vía, nunca modificando ese fichero. Lo que te puede ocurrir si lo haces es que las estructuras que termines usando no se correspondan con las del SO que usas, y en ese punto si que la cagas, porque no se te olvide que estas accediendo al KERNEL del SO. Y aunque te compile, luego la depuración será horrorosa, al no recibir las funciones los parámetros que necesitan en ese SO. Cada SO, cada maquina y procesador usa una arquitectura diferente. De ahí que el fichero NTDDK lleve tantas estructuras diferentes para un mismo nombre. Por ejemplo, la estructura que refleja el contexto de la máquina tiene campos distintos si usas una maquina INTEL o una MIPS, o un motorola. El DDK esta hecho para 3 arquitecturas diferentes. Y tu driver debe igualmente respetarlo. No estas en el nivel de usuario, donde el programa te va a funcionar lo compiles en la maquina que lo compiles.
También se me olvidaba, usa el ntddk. H para W2k o NT40. Y también las librerías de uno de los dos.
No uses VC++ 6.0 con el DDK de XP porque para que funcione tienes que hacer muchas más cosas que no vas ha soluciona tan rápidamente.
Ten en cuenta que un driver hecho para W2K o NT40 funciona tanto en esos dos SO como en XP, pero no al revés.
(Esto no es del todo cierto, pero para tu nivel asumamos que es así).
No uses VC++ 6.0 con el DDK de XP porque para que funcione tienes que hacer muchas más cosas que no vas ha soluciona tan rápidamente.
Ten en cuenta que un driver hecho para W2K o NT40 funciona tanto en esos dos SO como en XP, pero no al revés.
(Esto no es del todo cierto, pero para tu nivel asumamos que es así).
De antemano muchas gracias por tus prontas aclaraciones...
Sucede que ya cuando me aseguré de haber probado diversas versiones de bibliotecas de DDK, en todas tengo conflictos... y claro que ya no incluyo más librerías que la de ntddk.h o wdm.h, pero por ejemplo en DDK para XP, me marca que estoy utilizando una version no soportada por DDK XP el error a continuación tal como aparece:
#error : Compiler version not supported by Windows DDK
Otra, si utilizo el ntddk.h para W2k, me aparecen errores en estructuras porque no han sido definidas, me fijé en el contenido tanto de ntddk.h y wdm.h para NT, y si se encuentran definidas, por ejemplo las estrucutras son: KSYSTEM_TIME y CONTEXT, solo que se encuentran entre lineas #ifdef #endif's, y busca las definiciones de constantes que no se donde las podría encontrar definidas, tal como son: #ifndef _PORTABLE_32BIT_CONTEXT e #if defined(_X86_).
¿Cómo le hago para que directivas como esas sean ciertas y pueda tener las estructuras KSYSTEM_TIME y CONTEXT debidamente definidas?
He intentado alterando el código de ntddk, de tal manera que las definiciones no queden condicionadas pero me marca errores como: #error : "Target architecture not defined"
Te agradezco la atención...
Saludos cordiales
Sucede que ya cuando me aseguré de haber probado diversas versiones de bibliotecas de DDK, en todas tengo conflictos... y claro que ya no incluyo más librerías que la de ntddk.h o wdm.h, pero por ejemplo en DDK para XP, me marca que estoy utilizando una version no soportada por DDK XP el error a continuación tal como aparece:
#error : Compiler version not supported by Windows DDK
Otra, si utilizo el ntddk.h para W2k, me aparecen errores en estructuras porque no han sido definidas, me fijé en el contenido tanto de ntddk.h y wdm.h para NT, y si se encuentran definidas, por ejemplo las estrucutras son: KSYSTEM_TIME y CONTEXT, solo que se encuentran entre lineas #ifdef #endif's, y busca las definiciones de constantes que no se donde las podría encontrar definidas, tal como son: #ifndef _PORTABLE_32BIT_CONTEXT e #if defined(_X86_).
¿Cómo le hago para que directivas como esas sean ciertas y pueda tener las estructuras KSYSTEM_TIME y CONTEXT debidamente definidas?
He intentado alterando el código de ntddk, de tal manera que las definiciones no queden condicionadas pero me marca errores como: #error : "Target architecture not defined"
Te agradezco la atención...
Saludos cordiales
El problema que tienes ahora es que para usar el DDK debes declarar la arquitetura que estas usando.
Así, debes definer los siguientes valores:
_DEBUG,STD_CALL,CONDITION_HANDLING=1,NT_UP=1,NT_INST=0,_NT1X_=100,WINNT=1,_WIN32_WINNT=0x0400,WIN32_LEAN_AND_MEAN=1,DBG=1,DEVL=1,FPO=0,NDEBUG,_DLL=1,_X86_=1,_NTKERNEL_
Introduce esa linea en los settings del proyecto en la casilla "Preprocessor definitions" dentro de la categoria <Preprocessor>.
Por otro lado, deberías compilar más fácilmente en la linea de comandos, pero tampoco es obligatorio.
Así, debes definer los siguientes valores:
_DEBUG,STD_CALL,CONDITION_HANDLING=1,NT_UP=1,NT_INST=0,_NT1X_=100,WINNT=1,_WIN32_WINNT=0x0400,WIN32_LEAN_AND_MEAN=1,DBG=1,DEVL=1,FPO=0,NDEBUG,_DLL=1,_X86_=1,_NTKERNEL_
Introduce esa linea en los settings del proyecto en la casilla "Preprocessor definitions" dentro de la categoria <Preprocessor>.
Por otro lado, deberías compilar más fácilmente en la linea de comandos, pero tampoco es obligatorio.
Hola, espero que esta sea la última molestia que te causo ... al menos con este asunto.
Podrías decirme por favor donde se encuentran implementadas las funciones que están declaradas en ntddk. ¿h?
Pues tengo unos errores de enlazado que no me permiten producir el ejecutable...
Gracias.
Podrías decirme por favor donde se encuentran implementadas las funciones que están declaradas en ntddk. ¿h?
Pues tengo unos errores de enlazado que no me permiten producir el ejecutable...
Gracias.
Y como si de un juego se tratara (con estos obstáculos que has ido superando lo parecía ;-): ENHORABUENA, si has llegado hasta aquí es que entonces lo que asumo como tu PRIMER driver esta escrito y compilado sin problemas.
Ahora solo te falta 'linkar' con las siguientes librerías:
Int64. Lib
Ntoskrnl. Lib
Hal. Lib
Puede que necesites alguna más, depende de las funciones que uses. Si te falta alguna función házmelo saber y te digo la librería adicional que necesitas.
Y como ya te comente que el DDK esta hecho para varias arquitecturas, tienes que usar las librerías de la maquina que usas, que asumo sera la INTEL.
Esas tres librerias, y algunas mas, se hallan tanto en DDK_PATH\lib\i386\checked como en DDK_PATH\lib\i386\free
(Donde DDK_PATH es donde has instalado el DDK).
Las de un directorio llevan información para depurar y la otra no.
Así que debes incluir dentro de los settings del proyecto, en la carpeta <Link> y bajo la categoría <General> en la casilla <Objects/Library modules> lo siguiente:
DDK_PATH\lib\i386\checked\int64.lib
DDK_PATH\lib\i386\checked\ntoskrnl.lib
DDK_PATH\lib\i386\checked\hal.lib
Ahora solo te queda registrar tu driver o hacer que tu programa de modo usuario que accede a el lo cargue antes de usarlo.
Bueno, eso es lo que yo suelo hacer con mis programas. Que sea el propio programa que hace uso del driver el que lo cargue antes de usarlo y lo descargue tras su uso. Eso tiene la ventaja de que no está en memoria siempre, y por ejemplo si usas interrupciones pues que se ejecute el código de la IRQ, u otro código no deseado. También tiene la ventaja que no entra en conflicto con el posible driver original del fabricante, si es que esta instalado u otros programas también hacen uso de la misma tarjeta.
Oye por curiosidad: ¿Cómo lo vas a depurar? Supongo que sabes que con el VC6++ no puedes.
Ahora solo te falta 'linkar' con las siguientes librerías:
Int64. Lib
Ntoskrnl. Lib
Hal. Lib
Puede que necesites alguna más, depende de las funciones que uses. Si te falta alguna función házmelo saber y te digo la librería adicional que necesitas.
Y como ya te comente que el DDK esta hecho para varias arquitecturas, tienes que usar las librerías de la maquina que usas, que asumo sera la INTEL.
Esas tres librerias, y algunas mas, se hallan tanto en DDK_PATH\lib\i386\checked como en DDK_PATH\lib\i386\free
(Donde DDK_PATH es donde has instalado el DDK).
Las de un directorio llevan información para depurar y la otra no.
Así que debes incluir dentro de los settings del proyecto, en la carpeta <Link> y bajo la categoría <General> en la casilla <Objects/Library modules> lo siguiente:
DDK_PATH\lib\i386\checked\int64.lib
DDK_PATH\lib\i386\checked\ntoskrnl.lib
DDK_PATH\lib\i386\checked\hal.lib
Ahora solo te queda registrar tu driver o hacer que tu programa de modo usuario que accede a el lo cargue antes de usarlo.
Bueno, eso es lo que yo suelo hacer con mis programas. Que sea el propio programa que hace uso del driver el que lo cargue antes de usarlo y lo descargue tras su uso. Eso tiene la ventaja de que no está en memoria siempre, y por ejemplo si usas interrupciones pues que se ejecute el código de la IRQ, u otro código no deseado. También tiene la ventaja que no entra en conflicto con el posible driver original del fabricante, si es que esta instalado u otros programas también hacen uso de la misma tarjeta.
Oye por curiosidad: ¿Cómo lo vas a depurar? Supongo que sabes que con el VC6++ no puedes.
Bueno en realidad si, el código compila perfectamente...
Y bueno pues una vez incluidas las librerías al 'linkar' los errores persisten, yo se que ya fue mucho con este mismo problema pero en realidad no me explico que haya mal, y mira que he estado buscando... unos dicen que hay que quitar una de las opciones del proyecto (en Project settings, la pestaña C/C++) que dice: "/GZ" pero el error sigue... seguí buscando y encontré que otros más dicen que hay que cambiar (en la pestaña Link) también de las opciones del proyecto una instrucción que dice: "/subsystem:console" a "/subsystem:windows" aunque no lo creí del todo lo probé e incluso hay un error más... que creo es justificado porque el error que se agrega dice:
"error LNK2001: unresolved external symbol _WinMain@16"
Los errores que me muestra el VC++ 6 cuando todo compila bien son:
error LNK2001: unresolved external symbol "__declspec(dllimport) unsigned long __cdecl HalGetBusData(enum _BUS_DATA_TYPE,unsigned long,unsigned long,void *,unsigned long)" (__imp_?HalGetBusData@@YAKW4_BUS_DATA_TYPE@@KKPAXK@Z)
error LNK2001: unresolved external symbol "__declspec(dllimport) void * __cdecl MmMapIoSpace(union _LARGE_INTEGER,unsigned long,enum _MEMORY_CACHING_TYPE)" (__imp_?MmMapIoSpace@@YAPAXT_LARGE_INTEGER@@KW4_MEMORY_CACHING_TYPE@@@Z)
error LNK2001: unresolved external symbol "__declspec(dllimport) unsigned char __cdecl HalTranslateBusAddress(enum _INTERFACE_TYPE,unsigned long,union _LARGE_INTEGER,unsigned long *,union _LARGE_INTEGER *)" (__imp_?HalTranslateBusAddress@@Y
AEW4_INTERFACE_TYPE@@KT_LARGE_INTEGER@@PAKPAT2@@Z)
Y me imaginé que pudiera ser acaso porque en los directorios para búsqueda de librerías tengo "C:\Archivos de programa\Microsoft Visual Studio\VC98\Lib" porque también se comenta que no es bueno incluir librerías duplicadas... esto más que nada porque también hago uso de funciones estándar que el mismo directorio de DDK incluye.
Entonces omití esa línea y entonces al tratar de 'linkar' aparece un error que dice: fatal error LNK1104: cannot open file "OLDNAMES.lib"
Te agradecería mucho si me dices que esta faltando.
En cuanto a lo de la depurada del programa, primero que nada quisiera saber si el código se ejecuta, ya después averiguaré sobre eso.
Saludos
Y bueno pues una vez incluidas las librerías al 'linkar' los errores persisten, yo se que ya fue mucho con este mismo problema pero en realidad no me explico que haya mal, y mira que he estado buscando... unos dicen que hay que quitar una de las opciones del proyecto (en Project settings, la pestaña C/C++) que dice: "/GZ" pero el error sigue... seguí buscando y encontré que otros más dicen que hay que cambiar (en la pestaña Link) también de las opciones del proyecto una instrucción que dice: "/subsystem:console" a "/subsystem:windows" aunque no lo creí del todo lo probé e incluso hay un error más... que creo es justificado porque el error que se agrega dice:
"error LNK2001: unresolved external symbol _WinMain@16"
Los errores que me muestra el VC++ 6 cuando todo compila bien son:
error LNK2001: unresolved external symbol "__declspec(dllimport) unsigned long __cdecl HalGetBusData(enum _BUS_DATA_TYPE,unsigned long,unsigned long,void *,unsigned long)" (__imp_?HalGetBusData@@YAKW4_BUS_DATA_TYPE@@KKPAXK@Z)
error LNK2001: unresolved external symbol "__declspec(dllimport) void * __cdecl MmMapIoSpace(union _LARGE_INTEGER,unsigned long,enum _MEMORY_CACHING_TYPE)" (__imp_?MmMapIoSpace@@YAPAXT_LARGE_INTEGER@@KW4_MEMORY_CACHING_TYPE@@@Z)
error LNK2001: unresolved external symbol "__declspec(dllimport) unsigned char __cdecl HalTranslateBusAddress(enum _INTERFACE_TYPE,unsigned long,union _LARGE_INTEGER,unsigned long *,union _LARGE_INTEGER *)" (__imp_?HalTranslateBusAddress@@Y
AEW4_INTERFACE_TYPE@@KT_LARGE_INTEGER@@PAKPAT2@@Z)
Y me imaginé que pudiera ser acaso porque en los directorios para búsqueda de librerías tengo "C:\Archivos de programa\Microsoft Visual Studio\VC98\Lib" porque también se comenta que no es bueno incluir librerías duplicadas... esto más que nada porque también hago uso de funciones estándar que el mismo directorio de DDK incluye.
Entonces omití esa línea y entonces al tratar de 'linkar' aparece un error que dice: fatal error LNK1104: cannot open file "OLDNAMES.lib"
Te agradecería mucho si me dices que esta faltando.
En cuanto a lo de la depurada del programa, primero que nada quisiera saber si el código se ejecuta, ya después averiguaré sobre eso.
Saludos
El "error LNK2001: unresolved external symbol _WinMain@16" es debido a que estas intentando linkar con las librerias de modo usuario.
Un driver no entra por la función WinMain(), si no que entra por la función DriverEntry().
No se quien es el cateto que te puede decir que tienes que usar esas opciones que SOLO valen para programas en modo usuario, no para el modo kernel.
Claro, al que lo haya hecho le funcionan los drivers no por que sepan poner las cosas adecuadas, si no por que el linker, que está bien hecho, las omite al resolver las funciones. Si el linker fuera al estilo UNIX, que no perdona ni una, no tendrían más que errores, y el programa les iba a funcionar cuando los cerdos vuelen.
Así que vuelve a al modo en que tu dices que todo te compila bien y luego arregla lo demás.
Bueno, volviendo a tu situación me imagino que tu problema es que tu programa esta hecho en C++, y claro las funciones de C++ no se llaman igual que en C normal.
C++ Aplica un proceso de mangling que es, pa que tu y yo nos entendamos, algo así como cambiar el nombre de las funciones. Por ejemplo, una función declarada
como:
unsigned long __cdecl HalGetBusData(enum _BUS_DATA_TYPE,unsigned long,unsigned long,void *,unsigned long
En C normal genera una etiqueta para enlazar así:
_HalGetBusData
Mientras que en C++ genera una etiqueta para enlazar así:
__imp_?HalGetBusData@@YAKW4_BUS_DATA_TYPE@@KKPAXK@Z
En ningún momento me indicaste que tu programa estaba hecho en C++(Normalmente los drivers se hacen en C normal), pero me imagino que ese es tu problema.
No hay problema en hacer los drivers en C++, pero todo lo definido en los headers y las librerías del kernel están hechas en C normal.
Así que tienes 2 soluciones.
A) Renombras todo tus fuentes de *.cpp a *. C y compilas en c puro y duro.
B) Cuando incluyas en tus fuentes en C++ los headers del kernel, declares que estas están hechas para C. Lo que quiere decir que al hacer:
#include <ntddk.h>
lo sustituyas por:
extern "C"
{
#include <ntddk.h>
}
Y luego me dices...
Por cierto, después de todas las veces que me has consultado, y creo que en todas he acertado con todos y cada uno de los problemas que te han ido saliendo, no se por que has ido a resolver el problema en otras fuentes.
La cuestión que te trato de transitirte no es que me preguntes a mi solo. Eso me la trae floja.
Pero lo que ocurre es que si sigues varias lineas de actuación aparte de la que yo te estoy indicando, pues luego cuando te surge un problema nuevo la resolución que yo te de puede que ya no te funciones por que aparte de lo que yo te he ido explicando que hicieras, lo más probable es que tengas otra acción que alguien te ha explicado (como lo de los "/subsystem:windows" o lo de quitar /GZ, que solo es para añadir información del depurador, que ya hay que ser cateto el que lo diga...)
Y eso genera que por mucho que yo te diga que hagas esto o lo otro, el problema no es que te falte algo, si no que te sobre lo que alguien te ha dicho que añadas y yo como no se si lo has puesto, pues no podré resolverte el problema.
Un driver no entra por la función WinMain(), si no que entra por la función DriverEntry().
No se quien es el cateto que te puede decir que tienes que usar esas opciones que SOLO valen para programas en modo usuario, no para el modo kernel.
Claro, al que lo haya hecho le funcionan los drivers no por que sepan poner las cosas adecuadas, si no por que el linker, que está bien hecho, las omite al resolver las funciones. Si el linker fuera al estilo UNIX, que no perdona ni una, no tendrían más que errores, y el programa les iba a funcionar cuando los cerdos vuelen.
Así que vuelve a al modo en que tu dices que todo te compila bien y luego arregla lo demás.
Bueno, volviendo a tu situación me imagino que tu problema es que tu programa esta hecho en C++, y claro las funciones de C++ no se llaman igual que en C normal.
C++ Aplica un proceso de mangling que es, pa que tu y yo nos entendamos, algo así como cambiar el nombre de las funciones. Por ejemplo, una función declarada
como:
unsigned long __cdecl HalGetBusData(enum _BUS_DATA_TYPE,unsigned long,unsigned long,void *,unsigned long
En C normal genera una etiqueta para enlazar así:
_HalGetBusData
Mientras que en C++ genera una etiqueta para enlazar así:
__imp_?HalGetBusData@@YAKW4_BUS_DATA_TYPE@@KKPAXK@Z
En ningún momento me indicaste que tu programa estaba hecho en C++(Normalmente los drivers se hacen en C normal), pero me imagino que ese es tu problema.
No hay problema en hacer los drivers en C++, pero todo lo definido en los headers y las librerías del kernel están hechas en C normal.
Así que tienes 2 soluciones.
A) Renombras todo tus fuentes de *.cpp a *. C y compilas en c puro y duro.
B) Cuando incluyas en tus fuentes en C++ los headers del kernel, declares que estas están hechas para C. Lo que quiere decir que al hacer:
#include <ntddk.h>
lo sustituyas por:
extern "C"
{
#include <ntddk.h>
}
Y luego me dices...
Por cierto, después de todas las veces que me has consultado, y creo que en todas he acertado con todos y cada uno de los problemas que te han ido saliendo, no se por que has ido a resolver el problema en otras fuentes.
La cuestión que te trato de transitirte no es que me preguntes a mi solo. Eso me la trae floja.
Pero lo que ocurre es que si sigues varias lineas de actuación aparte de la que yo te estoy indicando, pues luego cuando te surge un problema nuevo la resolución que yo te de puede que ya no te funciones por que aparte de lo que yo te he ido explicando que hicieras, lo más probable es que tengas otra acción que alguien te ha explicado (como lo de los "/subsystem:windows" o lo de quitar /GZ, que solo es para añadir información del depurador, que ya hay que ser cateto el que lo diga...)
Y eso genera que por mucho que yo te diga que hagas esto o lo otro, el problema no es que te falte algo, si no que te sobre lo que alguien te ha dicho que añadas y yo como no se si lo has puesto, pues no podré resolverte el problema.
Bueno primero que nada... claro está que soy un primerizo en esto del desarrollo de drivers (aunque no diría que lo que pretendo desarrollar es precisamente un driver... puede ser que sí, finalmente la solución que me habías dado al principio resuelve en primera instancia mi verdadera bronca... acceder a la dirección base asignada a un dispositivo PCI en un equipo con W2k)
Cabe aclarar que las sugerencias que te comenté las he encontrado en mi afán por buscar no ser tan molesto y resulta que no resuelve nada... finalmente esos cambios que pruebo no se quedan. Así que puedo decirte con certeza que las broncas que han ido saliendo son en base a lo que he alcanzado a entender de lo que me dices.
Finalmente pasé a C, el código y compila correctamente, pero presenta un error al 'linkar' con las mismas funciones, lo mismo sucede si lo compilo como .CPP y le especifico que las funciones de cabecera están en C. (extern "C" ...)
Y aparte como en realidad si estaba utilizando main() pues al cambiar la función principal a:
NTSTATUS DriverEntry()
Hay un error de linkeo que se agrega
Ex.obj : error LNK2001: unresolved external symbol __imp__HalGetBusData
Ex.obj : error LNK2001: unresolved external symbol __imp__MmMapIoSpace
Ex.obj : error LNK2001: unresolved external symbol __imp__HalTranslateBusAddress
LIBCD.lib(crt0.obj) : error LNK2001: unresolved external symbol _main
Tengo por entendido que la función DriverEntry de alguna manera tiene uno que declararla antes, ¿es correcto?
Bueno yo creo que mejor pego el código tal como lo tengo, podrás ver que es el mismo que me dijiste en tu primer respuesta, no se si esté bien 'implementada' la función DriverEntry.
//#define WINVER 0x0400
#include <conio.h>
#include <ntddk.h>
#include <stdio.h>
NTSTATUS PciFindDevice(IN USHORT vendorID, IN USHORT deviceID, OUT PULONG pdwBusNumber, OUT PULONG pdwSlotNumber);
PVOID MapSystemMemory(ULONG ulBusNumber, IN PVOID pPhysicalAddress, IN ULONG ulLength);
//NTSTATUS ReadWriteConfigSpace(IN PDEVICE_OBJECT DeviceObject, IN ULONG ReadOrWrite,/* 0 for read 1 for write*/ IN PVOID Buffer, IN ULONG Offset, IN ULONG Length);
NTSTATUS DriverEntry (IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING RegistryPath);
#ifdef ALLOC_PRAGMA
#pragma alloc_text(INIT, DriverEntry)
#endif
NTSTATUS DriverEntry(
IN PDRIVER_OBJECT DriverObject,
IN PUNICODE_STRING RegistryPath
) {
ULONG ulBusNumber;
ULONG ulSlotNumber;
ULONG ulIrqNumber;
ULONG ulPhysicalAddress;
PVOID pMemRegister;
NTSTATUS status = STATUS_SUCCESS;
PCI_COMMON_CONFIG pciConfiguration;
//PAGED_CODE();
//UNREFERENCED_PARAMETER(RegistryPath);
status = PciFindDevice(0x10b5, 0x9030, &ulBusNumber, &ulSlotNumber);
if ( status == STATUS_SUCCESS) {
printf("Se encontró la tarjeta jaja!!\n");
status = HalGetBusData(PCIConfiguration, ulBusNumber, ulSlotNumber, &pciConfiguration, sizeof(pciConfiguration));
if ( status == STATUS_SUCCESS) {
ulPhysicalAddress = pciConfiguration.u.type0.BaseAddresses[0] & 0xFFFFFFF0;
ulIrqNumber = pciConfiguration.u.type0.InterruptLine;
pMemRegister = MapSystemMemory(ulBusNumber, (PVOID)ulPhysicalAddress, 0x1000);
}
}
return status;
}
Hasta luego.
Cabe aclarar que las sugerencias que te comenté las he encontrado en mi afán por buscar no ser tan molesto y resulta que no resuelve nada... finalmente esos cambios que pruebo no se quedan. Así que puedo decirte con certeza que las broncas que han ido saliendo son en base a lo que he alcanzado a entender de lo que me dices.
Finalmente pasé a C, el código y compila correctamente, pero presenta un error al 'linkar' con las mismas funciones, lo mismo sucede si lo compilo como .CPP y le especifico que las funciones de cabecera están en C. (extern "C" ...)
Y aparte como en realidad si estaba utilizando main() pues al cambiar la función principal a:
NTSTATUS DriverEntry()
Hay un error de linkeo que se agrega
Ex.obj : error LNK2001: unresolved external symbol __imp__HalGetBusData
Ex.obj : error LNK2001: unresolved external symbol __imp__MmMapIoSpace
Ex.obj : error LNK2001: unresolved external symbol __imp__HalTranslateBusAddress
LIBCD.lib(crt0.obj) : error LNK2001: unresolved external symbol _main
Tengo por entendido que la función DriverEntry de alguna manera tiene uno que declararla antes, ¿es correcto?
Bueno yo creo que mejor pego el código tal como lo tengo, podrás ver que es el mismo que me dijiste en tu primer respuesta, no se si esté bien 'implementada' la función DriverEntry.
//#define WINVER 0x0400
#include <conio.h>
#include <ntddk.h>
#include <stdio.h>
NTSTATUS PciFindDevice(IN USHORT vendorID, IN USHORT deviceID, OUT PULONG pdwBusNumber, OUT PULONG pdwSlotNumber);
PVOID MapSystemMemory(ULONG ulBusNumber, IN PVOID pPhysicalAddress, IN ULONG ulLength);
//NTSTATUS ReadWriteConfigSpace(IN PDEVICE_OBJECT DeviceObject, IN ULONG ReadOrWrite,/* 0 for read 1 for write*/ IN PVOID Buffer, IN ULONG Offset, IN ULONG Length);
NTSTATUS DriverEntry (IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING RegistryPath);
#ifdef ALLOC_PRAGMA
#pragma alloc_text(INIT, DriverEntry)
#endif
NTSTATUS DriverEntry(
IN PDRIVER_OBJECT DriverObject,
IN PUNICODE_STRING RegistryPath
) {
ULONG ulBusNumber;
ULONG ulSlotNumber;
ULONG ulIrqNumber;
ULONG ulPhysicalAddress;
PVOID pMemRegister;
NTSTATUS status = STATUS_SUCCESS;
PCI_COMMON_CONFIG pciConfiguration;
//PAGED_CODE();
//UNREFERENCED_PARAMETER(RegistryPath);
status = PciFindDevice(0x10b5, 0x9030, &ulBusNumber, &ulSlotNumber);
if ( status == STATUS_SUCCESS) {
printf("Se encontró la tarjeta jaja!!\n");
status = HalGetBusData(PCIConfiguration, ulBusNumber, ulSlotNumber, &pciConfiguration, sizeof(pciConfiguration));
if ( status == STATUS_SUCCESS) {
ulPhysicalAddress = pciConfiguration.u.type0.BaseAddresses[0] & 0xFFFFFFF0;
ulIrqNumber = pciConfiguration.u.type0.InterruptLine;
pMemRegister = MapSystemMemory(ulBusNumber, (PVOID)ulPhysicalAddress, 0x1000);
}
}
return status;
}
Hasta luego.
Puff... Vamos por partes.
En un driver, como ya te comenté, no puedes añadir ningún otro include, tal y como por ejemplo:
#include <stdio.h>
Pues declaran funciones a las que no tienes acceso.
No tienes acceso a nada de nada. Estas en la capa del SO, donde no hay teclado, pantalla, ficheros... Solo existe el hardware. Bueno en realidad existen algunas cosas como el sistema de archivos, el teclado y poco más, pero hay que hablar de driver a driver. Nada de CreateFile(), Open(), Sockets...
Y mucho menos la pantalla.
En cuanto al otro include:
#include <conio.h>
No se ni como no te da errores de compilación. La verdad, como nunca se me ocurrió meter esos includes pues ni sabía que no te daban errores de compilación.
Pero están prohibidos: NO PUEDES HACER NINGÚN INCLUDE DE NADA MÁS QUE LOS QUE TE VIENEN CON EL DDK.
No es que no tengas acceso a la consola. Es que no existe. La consola es un driver como el tuyo. Bueno mucho más complejo y compuesto de muchos múdulos.
Así que la función printf no solo no existe en el DDK si no que debería darte errores de linkaje al final. Si no te da es por la misma razón que por la que te busca la función main():
Por que estas linkando con la famosa LIBCD. LIB. De hecho es el error que te da:
LIBCD. Lib(crt0. Obj) : error LNK2001: unresolved external symbol _main
Así que vete a los project settings, yentro de la pestaña link del project settings, en la categoría <general> debes de eliminar de la entrada [Objects/Library Modules] TODO lo que haya, y añadir SOLO las librerías que yo te indique en la respuesta anterior, o sea:
DDK_PATH\lib\i386\checked\int64.lib
DDK_PATH\lib\i386\checked\ntoskrnl.lib
DDK_PATH\lib\i386\checked\hal.lib
Y donde DDK_PATH es donde has instalado el DDK.
En la categoría <input> debes marcar la casilla de [Ignore all default libraries].
Repito, no tienes acceso más que a la librería DDK.
En la categoría <output> la entrada [Base address] debes de poner 0x10000, y en la entrada [Entry-Point symbol] debes poner DriverEntry.
No te encuentra esas funciones porque me apostaría tu sueldo a que no has puesto la linea del linker con el contenido DDK_PATH\lib\i386\checked\int64.lib DDK_PATH\lib\i386\checked\ntoskrnl.lib DDK_PATH\lib\i386\checked\hal.lib
Y si lo has puesto, por alguna razón no está encontrando ninguna de esas librerías, porque es allí donde está el código de las funciones que busca.
En un driver, como ya te comenté, no puedes añadir ningún otro include, tal y como por ejemplo:
#include <stdio.h>
Pues declaran funciones a las que no tienes acceso.
No tienes acceso a nada de nada. Estas en la capa del SO, donde no hay teclado, pantalla, ficheros... Solo existe el hardware. Bueno en realidad existen algunas cosas como el sistema de archivos, el teclado y poco más, pero hay que hablar de driver a driver. Nada de CreateFile(), Open(), Sockets...
Y mucho menos la pantalla.
En cuanto al otro include:
#include <conio.h>
No se ni como no te da errores de compilación. La verdad, como nunca se me ocurrió meter esos includes pues ni sabía que no te daban errores de compilación.
Pero están prohibidos: NO PUEDES HACER NINGÚN INCLUDE DE NADA MÁS QUE LOS QUE TE VIENEN CON EL DDK.
No es que no tengas acceso a la consola. Es que no existe. La consola es un driver como el tuyo. Bueno mucho más complejo y compuesto de muchos múdulos.
Así que la función printf no solo no existe en el DDK si no que debería darte errores de linkaje al final. Si no te da es por la misma razón que por la que te busca la función main():
Por que estas linkando con la famosa LIBCD. LIB. De hecho es el error que te da:
LIBCD. Lib(crt0. Obj) : error LNK2001: unresolved external symbol _main
Así que vete a los project settings, yentro de la pestaña link del project settings, en la categoría <general> debes de eliminar de la entrada [Objects/Library Modules] TODO lo que haya, y añadir SOLO las librerías que yo te indique en la respuesta anterior, o sea:
DDK_PATH\lib\i386\checked\int64.lib
DDK_PATH\lib\i386\checked\ntoskrnl.lib
DDK_PATH\lib\i386\checked\hal.lib
Y donde DDK_PATH es donde has instalado el DDK.
En la categoría <input> debes marcar la casilla de [Ignore all default libraries].
Repito, no tienes acceso más que a la librería DDK.
En la categoría <output> la entrada [Base address] debes de poner 0x10000, y en la entrada [Entry-Point symbol] debes poner DriverEntry.
No te encuentra esas funciones porque me apostaría tu sueldo a que no has puesto la linea del linker con el contenido DDK_PATH\lib\i386\checked\int64.lib DDK_PATH\lib\i386\checked\ntoskrnl.lib DDK_PATH\lib\i386\checked\hal.lib
Y si lo has puesto, por alguna razón no está encontrando ninguna de esas librerías, porque es allí donde está el código de las funciones que busca.
Hola buen día desde aquí...
Ya verifiqué lo que me dices, y todo lo tengo de acuerdo a lo indicado. Eso si, las librerías de DDK, las tenía mezcladas con otras que no eran de DDK, pero bueno... las quité y agregué eso de Base Address y el Entry-Point symbol también lo establecí, los errores persisten... los mismos de que no encuentra las librerías.
Ex.obj : error LNK2001: unresolved external symbol __imp__HalGetBusData
Ex.obj : error LNK2001: unresolved external symbol __chkesp
Ex.obj : error LNK2001: unresolved external symbol __imp__MmMapIoSpace
Ex.obj : error LNK2001: unresolved external symbol __imp__HalTranslateBusAddress
Debug/Ex.exe : fatal error LNK1120: 4 unresolved externals
Error executing link.exe.
Será que tengo que hacer algo con uno de los Build Environments??
Sólo se que tengo varias opciones:
Win 2K Checked Build Environment
Win 2K Free Build Environment
Win Me Checked Build Environment
Win Me Free Build Environment
Win XP Checked 64 Bit Build Environment
Win XP Checked Build Environment
Win XP Free 64 Bit Build Environment
Win XP Free Build Environment
Saludos cordiales.
Ya verifiqué lo que me dices, y todo lo tengo de acuerdo a lo indicado. Eso si, las librerías de DDK, las tenía mezcladas con otras que no eran de DDK, pero bueno... las quité y agregué eso de Base Address y el Entry-Point symbol también lo establecí, los errores persisten... los mismos de que no encuentra las librerías.
Ex.obj : error LNK2001: unresolved external symbol __imp__HalGetBusData
Ex.obj : error LNK2001: unresolved external symbol __chkesp
Ex.obj : error LNK2001: unresolved external symbol __imp__MmMapIoSpace
Ex.obj : error LNK2001: unresolved external symbol __imp__HalTranslateBusAddress
Debug/Ex.exe : fatal error LNK1120: 4 unresolved externals
Error executing link.exe.
Será que tengo que hacer algo con uno de los Build Environments??
Sólo se que tengo varias opciones:
Win 2K Checked Build Environment
Win 2K Free Build Environment
Win Me Checked Build Environment
Win Me Free Build Environment
Win XP Checked 64 Bit Build Environment
Win XP Checked Build Environment
Win XP Free 64 Bit Build Environment
Win XP Free Build Environment
Saludos cordiales.
Disculpa la tardanza, y aun así no se si ya habrás podido likar todo sin problemas. No he tenido acceso a internet por que me he cambiado de proveedor de internet.
En cuanto a la opcion de los Build Environment, debe ser <Win 2K Free Build Environment> o <Win 2K Checked Build Environment>
Prueba con eso.
En cuanto a la opcion de los Build Environment, debe ser <Win 2K Free Build Environment> o <Win 2K Checked Build Environment>
Prueba con eso.
- Compartir respuesta
- Anónimo
ahora mismo