summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorwpaul <wpaul@FreeBSD.org>2004-01-06 07:09:26 +0000
committerwpaul <wpaul@FreeBSD.org>2004-01-06 07:09:26 +0000
commit7452e76589c3544aeda69ca97dfcbd139dc08c09 (patch)
treee827295c0be7c812a4b4976153cb5f1f632e3216
parent7a30cbbe36c3da10547bc71289118de8e9bf0798 (diff)
downloadFreeBSD-src-7452e76589c3544aeda69ca97dfcbd139dc08c09.zip
FreeBSD-src-7452e76589c3544aeda69ca97dfcbd139dc08c09.tar.gz
- Add pe_get_message() and pe_get_messagetable() for processing
the RT_MESSAGETABLE resources that some driver binaries have. This allows us to print error messages in ndis_syslog(). - Correct the implementation of InterlockedIncrement() and InterlockedDecrement() -- they return uint32_t, not void. - Correct the declarations of the 64-bit arithmetic shift routines in subr_ntoskrnl.c (_allshr, allshl, etc...). These do not follow the _stdcall convention: instead, they appear to be __attribute__((regparm(3)). - Change the implementation of KeInitializeSpinLock(). There is no complementary KeFreeSpinLock() function, so creating a new mutex on each call to KeInitializeSpinLock() leaks resources when a driver is unloaded. For now, KeInitializeSpinLock() returns a handle to the ntoskrnl interlock mutex. - Use a driver's MiniportDisableInterrupt() and MiniportEnableInterrupt() routines if they exist. I'm not sure if I'm doing this right yet, but at the very least this shouldn't break any currently working drivers, and it makes the Intel PRO/1000 driver work. - In ndis_register_intr(), save some state that might be needed later, and save a pointer to the driver's interrupt structure in the ndis_miniport_block. - Save a pointer to the driver image for use by ndis_syslog() when it calls pe_get_message().
-rw-r--r--sys/compat/ndis/kern_ndis.c1
-rw-r--r--sys/compat/ndis/ndis_var.h1
-rw-r--r--sys/compat/ndis/pe_var.h101
-rw-r--r--sys/compat/ndis/subr_ndis.c12
-rw-r--r--sys/compat/ndis/subr_ntoskrnl.c66
-rw-r--r--sys/compat/ndis/subr_pe.c101
-rw-r--r--sys/dev/if_ndis/if_ndis.c31
7 files changed, 275 insertions, 38 deletions
diff --git a/sys/compat/ndis/kern_ndis.c b/sys/compat/ndis/kern_ndis.c
index 4e0ce26..4564e95 100644
--- a/sys/compat/ndis/kern_ndis.c
+++ b/sys/compat/ndis/kern_ndis.c
@@ -1179,6 +1179,7 @@ ndis_load_driver(img, arg)
block->nmb_ifp = &sc->arpcom.ac_if;
block->nmb_dev = sc->ndis_dev;
+ block->nmb_img = img;
return(0);
}
diff --git a/sys/compat/ndis/ndis_var.h b/sys/compat/ndis/ndis_var.h
index 9dc30a9..3a2f953 100644
--- a/sys/compat/ndis/ndis_var.h
+++ b/sys/compat/ndis/ndis_var.h
@@ -1280,6 +1280,7 @@ struct ndis_miniport_block {
ndis_status nmb_getstat;
ndis_status nmb_setstat;
struct nte_head nmb_timerlist;
+ vm_offset_t nmb_img;
};
typedef ndis_status (*ndis_init_handler)(ndis_status *, uint32_t *,
diff --git a/sys/compat/ndis/pe_var.h b/sys/compat/ndis/pe_var.h
index a0a2cc9..4eafc4c 100644
--- a/sys/compat/ndis/pe_var.h
+++ b/sys/compat/ndis/pe_var.h
@@ -230,6 +230,29 @@ typedef struct image_nt_header image_nt_header;
#define IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT 13
#define IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR 14
+/* Resource types */
+
+#define RT_CURSOR 1
+#define RT_BITMAP 2
+#define RT_ICON 3
+#define RT_MENU 4
+#define RT_DIALOG 5
+#define RT_STRING 6
+#define RT_FONTDIR 7
+#define RT_FONT 8
+#define RT_ACCELERATOR 9
+#define RT_RCDATA 10
+#define RT_MESSAGETABLE 11
+#define RT_GROUP_CURSOR 12
+#define RT_GROUP_ICON 14
+#define RT_VERSION 16
+#define RT_DLGINCLUDE 17
+#define RT_PLUGPLAY 19
+#define RT_VXD 20
+#define RT_ANICURSOR 21
+#define RT_ANIICON 22
+#define RT_HTML 23
+
/*
* Section header format.
*/
@@ -303,6 +326,80 @@ typedef struct image_base_reloc image_base_reloc;
#define IMAGE_REL_BASED_DIR64 10
#define IMAGE_REL_BASED_HIGH3ADJ 11
+struct image_resource_directory_entry {
+ uint32_t irde_name;
+ uint32_t irde_dataoff;
+};
+
+typedef struct image_resource_directory_entry image_resource_directory_entry;
+
+#define RESOURCE_NAME_STR 0x80000000
+#define RESOURCE_DIR_FLAG 0x80000000
+
+struct image_resource_directory {
+ uint32_t ird_characteristics;
+ uint32_t ird_timestamp;
+ uint16_t ird_majorver;
+ uint16_t ird_minorver;
+ uint16_t ird_named_entries;
+ uint16_t ird_id_entries;
+#ifdef notdef
+ image_resource_directory_entry ird_entries[1];
+#endif
+};
+
+typedef struct image_resource_directory image_resource_directory;
+
+struct image_resource_directory_string {
+ uint16_t irds_len;
+ char irds_name[1];
+};
+
+typedef struct image_resource_directory_string image_resource_directory_string;
+
+struct image_resource_directory_string_u {
+ uint16_t irds_len;
+ char irds_name[1];
+};
+
+typedef struct image_resource_directory_string_u
+ image_resource_directory_string_u;
+
+struct image_resource_data_entry {
+ uint32_t irde_offset;
+ uint32_t irde_size;
+ uint32_t irde_codepage;
+ uint32_t irde_rsvd;
+};
+
+typedef struct image_resource_data_entry image_resource_data_entry;
+
+struct message_resource_data {
+ uint32_t mrd_numblocks;
+#ifdef notdef
+ message_resource_block mrd_blocks[1];
+#endif
+};
+
+typedef struct message_resource_data message_resource_data;
+
+struct message_resource_block {
+ uint32_t mrb_lowid;
+ uint32_t mrb_highid;
+ uint32_t mrb_entryoff;
+};
+
+typedef struct message_resource_block message_resource_block;
+
+struct message_resource_entry {
+ uint16_t mre_len;
+ uint16_t mre_flags;
+ char mre_text[];
+};
+
+typedef struct message_resource_entry message_resource_entry;
+
+#define MESSAGE_RESOURCE_UNICODE 0x0001
struct image_patch_table {
char *ipt_name;
@@ -325,6 +422,10 @@ extern int pe_get_section(vm_offset_t, image_section_header *, const char *);
extern int pe_relocate(vm_offset_t);
extern int pe_get_import_descriptor(vm_offset_t, image_import_descriptor *, char *);
extern int pe_patch_imports(vm_offset_t, char *, image_patch_table *);
+#ifdef _KERNEL
+extern int pe_get_messagetable(vm_offset_t, message_resource_data **);
+extern int pe_get_message(vm_offset_t, uint32_t, char **, int *);
+#endif
__END_DECLS
#endif /* _PE_VAR_H_ */
diff --git a/sys/compat/ndis/subr_ndis.c b/sys/compat/ndis/subr_ndis.c
index 218445a..b25208d 100644
--- a/sys/compat/ndis/subr_ndis.c
+++ b/sys/compat/ndis/subr_ndis.c
@@ -796,10 +796,13 @@ ndis_syslog(ndis_handle adapter, ndis_error_code code,
ndis_miniport_block *block;
va_list ap;
int i;
+ char *str = NULL;
block = (ndis_miniport_block *)adapter;
- device_printf (block->nmb_dev, "NDIS ERROR: %x\n", code);
+ pe_get_message(block->nmb_img, code, &str, &i);
+ device_printf (block->nmb_dev, "NDIS ERROR: %x (%s)\n", code,
+ str == NULL ? "unknown error" : str);
device_printf (block->nmb_dev, "NDIS NUMERRORS: %x\n", numerrors);
va_start(ap, numerrors);
@@ -1894,7 +1897,14 @@ ndis_register_intr(intr, adapter, ivec, ilevel, reqisr, shared, imode)
uint8_t shared;
ndis_interrupt_mode imode;
{
+ ndis_miniport_block *block;
+
+ block = adapter;
+
intr->ni_block = adapter;
+ intr->ni_isrreq = reqisr;
+ intr->ni_shared = shared;
+ block->nmb_interrupt = intr;
return(NDIS_STATUS_SUCCESS);
}
diff --git a/sys/compat/ndis/subr_ntoskrnl.c b/sys/compat/ndis/subr_ntoskrnl.c
index c5f3c31..5278bc2 100644
--- a/sys/compat/ndis/subr_ntoskrnl.c
+++ b/sys/compat/ndis/subr_ntoskrnl.c
@@ -59,6 +59,8 @@ __FBSDID("$FreeBSD$");
#include <compat/ndis/ntoskrnl_var.h>
#define __stdcall __attribute__((__stdcall__))
+#define __regparm __attribute__((regparm(3)))
+
#define FUNC void(*)(void)
__stdcall static uint32_t ntoskrnl_unicode_equal(ndis_unicode_string *,
@@ -82,13 +84,13 @@ __stdcall static uint8_t ntoskrnl_readreg_uchar(uint8_t *);
__stdcall static int64_t _allmul(int64_t, int64_t);
__stdcall static int64_t _alldiv(int64_t, int64_t);
__stdcall static int64_t _allrem(int64_t, int64_t);
-__stdcall static int64_t _allshr(int64_t, int);
-__stdcall static int64_t _allshl(int64_t, int);
+__regparm static int64_t _allshr(int64_t, uint8_t);
+__regparm static int64_t _allshl(int64_t, uint8_t);
__stdcall static uint64_t _aullmul(uint64_t, uint64_t);
__stdcall static uint64_t _aulldiv(uint64_t, uint64_t);
__stdcall static uint64_t _aullrem(uint64_t, uint64_t);
-__stdcall static uint64_t _aullshr(uint64_t, int);
-__stdcall static uint64_t _aullshl(uint64_t, int);
+__regparm static uint64_t _aullshr(uint64_t, uint8_t);
+__regparm static uint64_t _aullshl(uint64_t, uint8_t);
__stdcall static void *ntoskrnl_allocfunc(uint32_t, size_t, uint32_t);
__stdcall static void ntoskrnl_freefunc(void *);
__stdcall static void ntoskrnl_init_lookaside(paged_lookaside_list *,
@@ -108,11 +110,13 @@ __stdcall static slist_entry *ntoskrnl_pop_slist_ex(/*slist_entry *,
kspin_lock * */void);
__stdcall static void ntoskrnl_lock_dpc(/*kspin_lock * */ void);
__stdcall static void ntoskrnl_unlock_dpc(/*kspin_lock * */ void);
-__stdcall static void ntoskrnl_interlock_inc(/*volatile uint32_t * */ void);
-__stdcall static void ntoskrnl_interlock_dec(/*volatile uint32_t * */ void);
+__stdcall static uint32_t
+ ntoskrnl_interlock_inc(/*volatile uint32_t * */ void);
+__stdcall static uint32_t
+ ntoskrnl_interlock_dec(/*volatile uint32_t * */ void);
__stdcall static void ntoskrnl_freemdl(ndis_buffer *);
__stdcall static void *ntoskrnl_mmaplockedpages(ndis_buffer *, uint8_t);
-__stdcall static void ntoskrnl_create_lock(kspin_lock *);
+__stdcall static void ntoskrnl_init_lock(kspin_lock *);
__stdcall static void dummy(void);
__stdcall static size_t ntoskrnl_memcmp(const void *, const void *, size_t);
@@ -121,7 +125,7 @@ static struct mtx ntoskrnl_interlock;
int
ntoskrnl_libinit()
{
- mtx_init(&ntoskrnl_interlock, "ntoskrnllock", MTX_NETWORK_LOCK,
+ mtx_init(&ntoskrnl_interlock, "ntoskrnllock", "ntoskrnl interlock",
MTX_DEF | MTX_RECURSE);
return(0);
@@ -333,34 +337,34 @@ _aullrem(a, b)
return (a % b);
}
-__stdcall static int64_t
+__regparm static int64_t
_allshl(a, b)
int64_t a;
- int b;
+ uint8_t b;
{
return (a << b);
}
-__stdcall static uint64_t
+__regparm static uint64_t
_aullshl(a, b)
uint64_t a;
- int b;
+ uint8_t b;
{
return (a << b);
}
-__stdcall static int64_t
+__regparm static int64_t
_allshr(a, b)
int64_t a;
- int b;
+ uint8_t b;
{
return (a >> b);
}
-__stdcall static uint64_t
+__regparm static uint64_t
_aullshr(a, b)
uint64_t a;
- int b;
+ uint8_t b;
{
return (a >> b);
}
@@ -567,7 +571,7 @@ ntoskrnl_unlock_dpc(/*lock*/ void)
return;
}
-__stdcall static void
+__stdcall static uint32_t
ntoskrnl_interlock_inc(/*addend*/ void)
{
volatile uint32_t *addend;
@@ -578,10 +582,10 @@ ntoskrnl_interlock_inc(/*addend*/ void)
(*addend)++;
mtx_unlock(&ntoskrnl_interlock);
- return;
+ return(*addend);
}
-__stdcall static void
+__stdcall static uint32_t
ntoskrnl_interlock_dec(/*addend*/ void)
{
volatile uint32_t *addend;
@@ -592,7 +596,7 @@ ntoskrnl_interlock_dec(/*addend*/ void)
(*addend)--;
mtx_unlock(&ntoskrnl_interlock);
- return;
+ return(*addend);
}
__stdcall static void
@@ -623,19 +627,19 @@ ntoskrnl_mmaplockedpages(buf, accessmode)
return(MDL_VA(buf));
}
+/*
+ * The KeInitializeSpinLock(), KefAcquireSpinLockAtDpcLevel()
+ * and KefReleaseSpinLockFromDpcLevel() appear to be analagous
+ * to splnet()/splx() in their use. We can't create a new mutex
+ * lock here because there is no complimentary KeFreeSpinLock()
+ * function. For now, what we do is initialize the lock with
+ * a pointer to the ntoskrnl interlock mutex.
+ */
__stdcall static void
-ntoskrnl_create_lock(lock)
+ntoskrnl_init_lock(lock)
kspin_lock *lock;
{
- struct mtx *mtx;
-
- mtx = malloc(sizeof(struct mtx), M_DEVBUF, M_NOWAIT|M_ZERO);
- if (mtx == NULL)
- return;
- mtx_init(mtx, "ntoslock", "ntoskrnl spinlock",
- MTX_DEF | MTX_RECURSE | MTX_DUPOK);
-
- *lock = (kspin_lock)mtx;
+ *lock = (kspin_lock)&ntoskrnl_interlock;
return;
}
@@ -715,7 +719,7 @@ image_patch_table ntoskrnl_functbl[] = {
{ "InterlockedDecrement", (FUNC)ntoskrnl_interlock_dec },
{ "IoFreeMdl", (FUNC)ntoskrnl_freemdl },
{ "MmMapLockedPages", (FUNC)ntoskrnl_mmaplockedpages },
- { "KeInitializeSpinLock", (FUNC)ntoskrnl_create_lock },
+ { "KeInitializeSpinLock", (FUNC)ntoskrnl_init_lock },
/*
* This last entry is a catch-all for any function we haven't
diff --git a/sys/compat/ndis/subr_pe.c b/sys/compat/ndis/subr_pe.c
index 340d669..3151598 100644
--- a/sys/compat/ndis/subr_pe.c
+++ b/sys/compat/ndis/subr_pe.c
@@ -61,6 +61,15 @@ __FBSDID("$FreeBSD$");
#endif
#include <compat/ndis/pe_var.h>
+#ifdef _KERNEL
+#include <machine/bus.h>
+#include <machine/resource.h>
+#include <sys/bus.h>
+#include <sys/rman.h>
+#include <compat/ndis/resource_var.h>
+#include <compat/ndis/ntoskrnl_var.h>
+#include <compat/ndis/ndis_var.h>
+#endif
static u_int32_t pe_functbl_match(image_patch_table *, char *);
@@ -456,6 +465,98 @@ pe_get_import_descriptor(imgbase, desc, module)
return (ENOENT);
}
+#ifdef _KERNEL
+int
+pe_get_messagetable(imgbase, md)
+ vm_offset_t imgbase;
+ message_resource_data **md;
+{
+ image_resource_directory *rdir, *rtype;
+ image_resource_directory_entry *dent, *dent2;
+ image_resource_data_entry *rent;
+ vm_offset_t offset;
+ int i;
+
+ if (imgbase == 0)
+ return(EINVAL);
+
+ offset = pe_directory_offset(imgbase, IMAGE_DIRECTORY_ENTRY_RESOURCE);
+ if (offset == 0)
+ return (ENOENT);
+
+ rdir = (image_resource_directory *)offset;
+
+ dent = (image_resource_directory_entry *)(offset +
+ sizeof(image_resource_directory));
+
+ for (i = 0; i < rdir->ird_id_entries; i++){
+ if (dent->irde_name != RT_MESSAGETABLE) {
+ dent++;
+ continue;
+ }
+ dent2 = dent;
+ while (dent2->irde_dataoff & RESOURCE_DIR_FLAG) {
+ rtype = (image_resource_directory *)(offset +
+ (dent2->irde_dataoff & ~RESOURCE_DIR_FLAG));
+ dent2 = (image_resource_directory_entry *)
+ ((uintptr_t)rtype +
+ sizeof(image_resource_directory));
+ }
+ rent = (image_resource_data_entry *)(offset +
+ dent2->irde_dataoff);
+ *md = (message_resource_data *)pe_translate_addr(imgbase,
+ rent->irde_offset);
+ return(0);
+ }
+
+ return(ENOENT);
+}
+
+int
+pe_get_message(imgbase, id, str, len)
+ vm_offset_t imgbase;
+ uint32_t id;
+ char **str;
+ int *len;
+{
+ message_resource_data *md = NULL;
+ message_resource_block *mb;
+ message_resource_entry *me;
+ int i;
+ char m[1024], *msg;
+
+ pe_get_messagetable(imgbase, &md);
+
+ if (md == NULL)
+ return(ENOENT);
+
+ mb = (message_resource_block *)((uintptr_t)md +
+ sizeof(message_resource_data));
+
+ for (i = 0; i < md->mrd_numblocks; i++) {
+ if (id >= mb->mrb_lowid && id <= mb->mrb_highid) {
+ me = (message_resource_entry *)((uintptr_t)md +
+ mb->mrb_entryoff);
+ for (i = id - mb->mrb_lowid; i > 0; i--)
+ me = (message_resource_entry *)((uintptr_t)me +
+ me->mre_len);
+ if (me->mre_flags == MESSAGE_RESOURCE_UNICODE) {
+ msg = m;
+ ndis_unicode_to_ascii((uint16_t *)me->mre_text,
+ me->mre_len, &msg);
+ *str = m;
+ } else
+ *str = me->mre_text;
+ *len = me->mre_len;
+ return(0);
+ }
+ mb++;
+ }
+
+ return(ENOENT);
+}
+#endif
+
/*
* Find the function that matches a particular name. This doesn't
* need to be particularly speedy since it's only run when loading
diff --git a/sys/dev/if_ndis/if_ndis.c b/sys/dev/if_ndis/if_ndis.c
index e4436d3..2870b4d 100644
--- a/sys/dev/if_ndis/if_ndis.c
+++ b/sys/dev/if_ndis/if_ndis.c
@@ -597,11 +597,12 @@ ndis_attach(dev)
fail:
if (error)
ndis_detach(dev);
-
- /* We're done talking to the NIC for now; halt it. */
- ifp->if_flags |= IFF_UP;
- ndis_halt_nic(sc);
- ifp->if_flags &= ~IFF_UP;
+ else {
+ /* We're done talking to the NIC for now; halt it. */
+ ifp->if_flags |= IFF_UP;
+ ndis_halt_nic(sc);
+ ifp->if_flags &= ~IFF_UP;
+ }
return(error);
}
@@ -841,6 +842,9 @@ ndis_intrtask(arg, pending)
ifp = &sc->arpcom.ac_if;
ndis_intrhand(sc);
+ mtx_lock(&sc->ndis_intrmtx);
+ ndis_enable_intr(sc);
+ mtx_unlock(&sc->ndis_intrmtx);
if (ifp->if_snd.ifq_head != NULL)
ndis_start(ifp);
@@ -864,7 +868,12 @@ ndis_intr(arg)
return;
mtx_lock(&sc->ndis_intrmtx);
- ndis_isr(sc, &is_our_intr, &call_isr);
+ if (sc->ndis_block.nmb_interrupt->ni_isrreq == TRUE)
+ ndis_isr(sc, &is_our_intr, &call_isr);
+ else {
+ ndis_disable_intr(sc);
+ call_isr = 1;
+ }
mtx_unlock(&sc->ndis_intrmtx);
if (is_our_intr || call_isr)
@@ -1098,12 +1107,22 @@ ndis_init(xsc)
sc->ndis_txpending = sc->ndis_maxpkts;
sc->ndis_link = 0;
+ ndis_enable_intr(sc);
+
if (sc->ndis_80211)
ndis_setstate_80211(sc);
ifp->if_flags |= IFF_RUNNING;
ifp->if_flags &= ~IFF_OACTIVE;
+ /*
+ * Some drivers don't set this value. The NDIS spec says
+ * the default checkforhang timeout is approximately 2
+ * seconds.
+ */
+ if (sc->ndis_block.nmb_checkforhangsecs == 0)
+ sc->ndis_block.nmb_checkforhangsecs = 2;
+
if (sc->ndis_chars.nmc_checkhang_func != NULL)
sc->ndis_stat_ch = timeout(ndis_tick, sc,
hz * sc->ndis_block.nmb_checkforhangsecs);
OpenPOWER on IntegriCloud