delorie.com/archives/browse.cgi   search  
Mail Archives: djgpp/1999/10/19/10:35:10

Message-ID: <005f01bf1a10$4d4d6560$293f8589@gv015029.bgo.nera.no>
From: "Gisle Vanem" <gvanem AT eunet DOT no>
To: <djgpp AT delorie DOT com>
Subject: Re: far call
Date: Tue, 19 Oct 1999 10:59:26 +0200
MIME-Version: 1.0
X-Priority: 3
X-MSMail-Priority: Normal
X-Mailer: Microsoft Outlook Express 4.72.3110.5
X-MIMEOLE: Produced By Microsoft MimeOLE V4.72.3110.3
Reply-To: djgpp AT delorie DOT com

Eli Zaretskii <eliz AT is DOT elta DOT co DOT il> said:


>>     bios32_api.offset32 = check.fields.entry;
>>     bios32_api.selector = selector;
>
>You have defined a special selector for the memory region, but didn't
>adjust the offset accordingly.  You need to subtract addr from
>check.fields.entry, to make it a segment-relative offset suitable to
>use with your selector.  Otherwise, bios32_api.offset32 is way above
>the 4K limit you've set up for bios32_api.selector.


Thanks for the tips, but it's still crashing. Here the symify output and revised code:

BIOS32: BIOS32 Service Directory structure at 000FDB60h
BIOS32: BIOS32 Service Directory entry at 000FDB70h
BIOS32: pmode entry at 01D7h:00000010h
Exiting due to signal SIGSEGV
General Protection Fault at eip=00001dcc, error=01d4
eax=49435024 ebx=00000000 ecx=00000000 edx=00000035 esi=00000054 edi=49435024
ebp=0008f6e4 esp=0008f6d4 program=D:\NET\TCPDUMP\PCAP\PM_DRVR\B32.EXE
cs: sel=01b7  base=022a0000  limit=0009ffff
ds: sel=01bf  base=022a0000  limit=0009ffff
es: sel=01bf  base=022a0000  limit=0009ffff
fs: sel=0187  base=0001c320  limit=0000ffff
gs: sel=01c7  base=00000000  limit=0010ffff
ss: sel=01bf  base=022a0000  limit=0009ffff
App stack: [0008f710..0000f710]  Exceptn stack: [0000f5f8..0000d6b8]

Call frame traceback EIPs:
  0x00001dcc   _bios32_service+16, line 44 of b32.c
  0x00002046   _main+22, line 132 of b32.c
  0x00002fde   ___crt1_startup+174

------------------------------- cut ---------------------------------------------
#include <stdio.h>
#include <string.h>
#include <dpmi.h>
#include <go32.h>

/* signatures: "_32_" + "$PCI"
 */
#define BIOS32_SIGNATURE  (('_'<<0) + ('3'<<8) + ('2'<<16) + ('_'<<24))
#define PCI_SERVICE       (('$'<<0) + ('P'<<8) + ('C'<<16) + ('I'<<24))

static __dpmi_paddr bios32_api;

#pragma pack(1)                      /* turn on packing, I'm sure this is equal to __attribute__((packed)) */

union bios32 {
      struct {
        unsigned long  signature;    /* "_32_" */
        unsigned long  entry;        /* 32 bit physical address */
        unsigned char  revision;     /* Revision level, 0 */
        unsigned char  length;       /* Length in paragraphs should be 01 */
        unsigned char  checksum;     /* All bytes must add up to zero */
        unsigned char  reserved[5];  /* Must be zero */
      } fields;
      char chars[16];
    };
#pragma pack()


/* Returns the entry point for the given service, NULL on error
 */
unsigned long bios32_service (unsigned long service)
{
  unsigned char return_code;    /* %al */
  unsigned long address;        /* %ebx */
  unsigned long length;         /* %ecx */
  unsigned long entry;          /* %edx */

#if 0
  __asm__ __volatile__ (
           "lcall (%%edi)"
           : "=a" (return_code), "=b" (address), "=c" (length), "=d" (entry)
           : "0" (service), "1" (0), "D" (&bios32_api) );
#else
  __asm__ __volatile__ (
           "lcall _bios32_api"      /* line 44, crashes here */
           : "=a" (return_code), "=b" (address), "=c" (length), "=d" (entry)
           : "0" (service), "1" (0) );
#endif

  switch (return_code)
  {
    case 0:
         return (address + entry);
    case 0x80:
         printf ("bios32_service(%08lX): not present\n", service);
         return (0);
    default:
         printf ("bios32_service(%08lX): returned %X\n",
                 service, return_code);
         return (0);
  }
}

int pcibios_init (void)
{
  unsigned char sum;
  unsigned long addr;
  int      i, length;

  for (addr = 0xe0000; addr <= 0xffff0; addr += 16)
  {
    union bios32 check;
    unsigned short selector;

    dosmemget (addr, sizeof(check), &check);
    if (check.fields.signature != BIOS32_SIGNATURE)
       continue;

    length = check.fields.length * 16;
    if (!length)
       continue;

    sum = 0;
    for (i = 0; i < length; ++i)
       sum += check.chars[i];
    if (sum != 0)
       continue;

    if (check.fields.revision != 0)
    {
      printf ("BIOS32: unsupported revision %d at %08lX\n",
              check.fields.revision, addr);
      continue;
    }

    printf ("BIOS32: BIOS32 Service Directory structure at %08lXh\n",
            addr);

    if (check.fields.entry >= 0x100000)
    {
      printf ("BIOS32: entry in high memory!\n");
      return (0);
    }

    selector = __dpmi_allocate_ldt_descriptors (1);

    printf ("BIOS32: BIOS32 Service Directory entry at %08lXh\n",
            check.fields.entry);

    if (selector <= 0)
    {
      printf ("BIOS32: failed to create selector\n");
      return (0);
    }
    __dpmi_set_segment_base_address (selector, addr);
    __dpmi_set_segment_limit (selector, 4096-1);

    bios32_api.offset32 = check.fields.entry - addr;
    bios32_api.selector = selector;

    printf ("BIOS32: pmode entry at %04Xh:%08lXh\n",
            bios32_api.selector, bios32_api.offset32);
    return (1);
  }
  return (0);
}

int main (void)
{
  if (pcibios_init())
     bios32_service (PCI_SERVICE);
  return (0);
}

------------------------------- cut ---------------------------------------------

Generating asm-output, the "lcall" looks okay. Unless 'bios32_api' is
wrongly aligned. I didn't see that <dpmi.h> packs  '__dpmi_paddr' in
any way.

Maybe I need to modify the selector for 'execute' ? (don't think so)

Gisle V.

- Raw text -


  webmaster     delorie software   privacy  
  Copyright © 2019   by DJ Delorie     Updated Jul 2019