delorie.com/archives/browse.cgi   search  
Mail Archives: djgpp/1999/10/18/18:32:40

Date: Mon, 18 Oct 1999 23:10:34 +0100 (MET)
From: Gisle Vanem <giva AT bryggen DOT bgnett DOT no>
To: djgpp AT delorie DOT com
Subject: far call
Message-ID: <Pine.UW2.3.95.991018230952.12654A-100000@bryggen.bgnett.no>
MIME-Version: 1.0
Reply-To: djgpp AT delorie DOT com

I'm porting some BIOS32 detection routine from Linux.
Now I've hit the wall trying to call the BIOS32 service.

I've used the procedure described in the FAQ and used in Allegro
(dpmi.c and vesa.c), but it crashes at the "lcall (%%edi)" line.

Someone please tell whats wrong with the __asm__ statement.

---------------------------- 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;

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];
    };

/* 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 */

  __asm__ __volatile__ (
           "lcall (%%edi)"
           : "=a" (return_code), "=b" (address), "=c" (length), "=d" (entry)
           : "0" (service), "1" (0), "D" (&bios32_api) );

  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;
    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 -----------------------------------

Gisle V.

- Raw text -


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