⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 bios32.cxx

📁 C++ 编写的EROS RTOS
💻 CXX
字号:
/* * Copyright (C) 1998, 1999, Jonathan S. Shapiro. * * This file is part of the EROS Operating System. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2, * or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *//* X86 implementation of the PCI BIOS interface.  Mostly, we just cop * out and pass the buck to the system BIOS. */#include <kerninc/kernel.hxx>#include <kerninc/util.h>#include <kerninc/PCI.hxx>#include <kerninc/IRQ.hxx>#include "Segment.hxx"#define dbg_bios32	0x1	/* steps in taking snapshot */#define dbg_pcibios	0x2	/* migration state machine *//* Following should be an OR of some of the above */#define dbg_flags   ( 0u )#define DBCOND(x) (dbg_##x & dbg_flags)#define DEBUG(x) if DBCOND(x)#define DEBUG2(x,y) if ((dbg_##x|dbg_##y) & dbg_flags)/* * Different versions of GAS implement different syntax for lcall. The * newer ones bitch about the old syntax, while the older ones barf on * the new syntax. Lovely. Really. */#ifdef __GNUC__#if (__GNUC__ >= 2) && (__GNUC_MINOR__ >= 96)#define LCALL(reg) "lcall *(" #reg ")"#else#define LCALL(reg) "lcall (" #reg ")"#endif#endif/* Issue: the PCI bios is called during hardware init, when CPL == 0, * and also at driver init, by which point CPL is 1.  For this reason * the descriptor table has TWO bios32 segments that are identical * except for CPL.  Every procedure in here must take care to set the * right one using the following macro */#define SET_SELECTOR(farptr) \  farptr.selector = \    (GetCPL() ? Selector::KProcBios32 : Selector::KernelBios32)/* These are derived from MindShare's PCI System Architecture: */#define PCIBIOSFUN(x) (0xb100 | (x))struct PciFn {  enum {    BiosPresent     = PCIBIOSFUN(0x1),    FindDevice      = PCIBIOSFUN(0x2),    FindClass       = PCIBIOSFUN(0x3),    SpecialCycle    = PCIBIOSFUN(0x6),    RdConfByte      = PCIBIOSFUN(0x8),    RdConfHalfWord  = PCIBIOSFUN(0x9),    RdConfWord      = PCIBIOSFUN(0xa),    WrConfByte      = PCIBIOSFUN(0xb),    WrConfHalfWord  = PCIBIOSFUN(0xc),    WrConfWord      = PCIBIOSFUN(0xd),    GetIrqRoute     = PCIBIOSFUN(0xe),    SetPciInterrupt = PCIBIOSFUN(0xf),  };} ;/* Various memory signatures we need to look for: */struct Signature {  enum {    bios32 = ('_' + ('3' << 8) + ('2' << 16) + ('_' << 24)),    pci    = ('P' + ('C' << 8) + ('I' << 16) + (' ' << 24)),    pcisvc = ('$' + ('P' << 8) + ('C' << 16) + ('I' << 24)),  };};union Bios32Entry {  struct {    uint32_t signature;		/* Signature::bios32 */    kpa_t entry;		/* physical address */    uint8_t revision;		/* revision level */    uint8_t length;		/* in paragraphs -- currently 1 */    uint8_t checksum;		/* bytewise checksum */    uint8_t reserved[5];		/* reserved for future use */  } fields;  uint8_t bytes[16];} ;/* Virtual address of the 32-bit BIOS service directory.  Some BIOS's * appear to have more than one.  We use only the first one for now. */static bool Bios32IsInit = false;static klva_t Bios32EntryPt = 0;static struct {  uint32_t offset;  uint16_t selector;} Bios32FarPtr = { 0, Selector::Null };inline uint32_tGetCPL(){  uint32_t cpl;    __asm__ ("movw %%cs,%w0\n\t"	   "andl $0x3,%0"	   : "=r" (cpl) /* output */	   : /* no input */);  return cpl;}/* Try to hunt down a 32 bit BIOS services directory: */static voidbios32_init(){  DEBUG(bios32)    dprintf(true, "Initializing BIOS32\n");  if (Bios32IsInit)    return;    Bios32Entry *b32bottom = (Bios32Entry *) 0xe0000;  Bios32Entry *b32top    = (Bios32Entry *) 0xffff0;  Bios32Entry *entry = 0;  for (entry = b32bottom; entry < b32top; entry++) {    if (entry->fields.signature != Signature::bios32)      continue;    uint32_t length = entry->fields.length * 16;    if (length == 0) {      printf("BIOS32: WARNING! bogus bios32 structure at 0x%08x\n", entry);      continue;    }    assert(length);    uint8_t sum = 0;    for (uint32_t i = 0; i < length; i++)      sum += entry->bytes[i];    if (sum != 0)      continue;    DEBUG(bios32)      dprintf(true, "BIOS32: structure found at 0x%08x\n", entry);    if (entry->fields.revision != 0x0)      fatal("Unsupported BIOS32 revision %d at 0x%08x\n",		    entry->fields.revision, entry);    if (Bios32EntryPt == 0) {      if (entry->fields.entry > 0x100000)	fatal("BIOS32 entry point in high memory at 0x%08x\n",		      entry->fields.entry);      Bios32EntryPt = Bios32FarPtr.offset = entry->fields.entry;      printf("BIOS32 Services Directory found at 0x%08x\n",		     entry->fields.entry);    }  }  Bios32IsInit = true;  DEBUG(bios32)    dprintf(true, "BIOS32 initialization completed: %s\n",		    Bios32IsInit ? "good" : "not present");}/* * Returns the entry point for the given service, NULL on error */static uint32_tBios32FindService(uint32_t service){  uint8_t returnCode;	/* %al */  uint32_t address;		/* %ebx */  uint32_t length;		/* %ecx */  uint32_t entry;		/* %edx */  SET_SELECTOR(Bios32FarPtr);		  IRQ::DISABLE();  __asm__(LCALL(%%edi)	  : "=a" (returnCode),	    "=b" (address),	    "=c" (length),	    "=d" (entry)	  : "0" (service),	    "1" (0),	    "D" (&Bios32FarPtr));  IRQ::ENABLE();  switch (returnCode) {  case 0:    return address + entry;  case 0x80:	/* Not present */    printf("Bios32FindService(%ld) : not present\n", service);    return 0;  default: /* Shouldn't happen */    fatal("Bios32FindService(%ld) : returned 0x%x\n",		  service, returnCode);    return 0;  }}bool PciBios::isInit = false;static klva_t PciBiosEntryPt = 0;static struct {  uint32_t offset;  uint16_t selector;} PciFarPtr = { 0, Selector::Null };voidPciBios::Init(){  if (isInit)    return;  DEBUG(pcibios)    dprintf(true,"Initializing PCI Bios\n");    bios32_init();  if (Bios32EntryPt == 0) {    printf("PciBios::Init(): no BIOS32 entry point\n");    return;  }  DEBUG(pcibios)    dprintf(true,"First call to Bios32FindService()\n");    PciBiosEntryPt = Bios32FindService(Signature::pcisvc);  DEBUG(pcibios)    dprintf(true,"First call to Bios32FindService() -- made it\n");    if (PciBiosEntryPt) {    uint32_t signature;    uint8_t status;    uint8_t majorRevision;    uint8_t minorRevision;    uint32_t pack;    SET_SELECTOR(PciFarPtr);    PciFarPtr.offset = PciBiosEntryPt;    IRQ::DISABLE();    __asm__(LCALL(%%edi) "\n\t"	    "jc 1f\n\t"	    "xor %%ah, %%ah\n"	    "1:\tshl $8, %%eax\n\t"	    "movw %%bx, %%ax"	    : "=d" (signature),	      "=a" (pack)	    : "1" (PciFn::BiosPresent),	      "D" (&PciFarPtr)	    : "bx", "cx");    IRQ::ENABLE();    status = (pack >> 16) & 0xff;    majorRevision = (pack >> 8) & 0xff;    minorRevision = pack & 0xff;#if 0    printf("Found PCI BIOS with signature 0x%08x (\"%c%c%c%c\")\n",		   signature,		   signature & 0xff,		   (signature >> 8) & 0xff,		   (signature >> 16) & 0xff,		   (signature >> 24) & 0xff);        printf("  status=%d\n", status);    printf("  majorRev=0x%x\n", majorRevision);    printf("  minorRev=0x%x\n", minorRevision);#endif    if (signature != Signature::pci) {      PciBiosEntryPt = 0;      printf("PCI BIOS signature is bad\n");      halt('B');    }    if (status)      printf("Unexpected status %d from PciFn::BiosPresent\n",		     status);    if (PciBiosEntryPt) {      printf("PCI BIOS revision %x.%02x entry at 0x%x\n",		     majorRevision, minorRevision, PciBiosEntryPt);    }  }  isInit = true;  return;}boolPciBios::Present(){  PciBios::Init();    if (PciBiosEntryPt)    return true;    return false;			/* just for now */}/* Patch brain-damaged card entries: */voidPciBios::Fixup(){}uint32_tPciBios::FindDevice (uint16_t vendor, uint16_t device_id,		     uint16_t index, uint8_t& bus, uint8_t& device_fn){  uint16_t bx = 0;  uint16_t ret = 0;  DEBUG(pcibios)    dprintf(true,"Call to PciBios::FindDevice()\n");    SET_SELECTOR(PciFarPtr);  IRQ::DISABLE();  __asm__(LCALL(%%edi) "\n\t"	  "jc 1f\n\t"	  "xor %%ah, %%ah\n"	  "1:"	  : "=b" (bx),	  "=a" (ret)	  : "1" (PciFn::FindDevice),	  "c" (device_id),	  "d" (vendor),	  "S" ((uint32_t) index),	  "D" (&PciFarPtr));  IRQ::ENABLE();  DEBUG(pcibios)    dprintf(true,"Call to PciBios::FindDevice() -- done\n");  bus = (bx >> 8) & 0xff;  device_fn = bx & 0xff;  return (uint32_t) (ret & 0xff00) >> 8;}uint32_tPciBios::FindClass (uint32_t devClass, uint16_t index,		    uint8_t &bus, uint8_t& device_fn){  uint16_t bx;  uint16_t ret;  SET_SELECTOR(PciFarPtr);  DEBUG(pcibios)    dprintf(true,"Call to PciBios::FindClass()\n");    IRQ::DISABLE();  __asm__ (LCALL(%%edi)"\n\t"	   "jc 1f\n\t"	   "xor %%ah, %%ah\n"	   "1:"	   : "=b" (bx),	   "=a" (ret)	   : "1" (PciFn::FindClass),	   "c" (devClass),	   "S" ((uint32_t) index),	   "D" (&PciFarPtr));  IRQ::ENABLE();  DEBUG(pcibios)    dprintf(true,"Call to PciBios::FindClass() -- done\n");  bus = (bx >> 8) & 0xff;  device_fn = bx & 0xff;  return (int) (ret & 0xff00) >> 8;}uint32_tPciBios::ReadConfig8 (uint8_t bus,		      uint8_t device_fn, uint8_t where, uint8_t& value){  uint32_t ret = 0;  uint32_t bx = (bus << 8) | device_fn;  SET_SELECTOR(PciFarPtr);  IRQ::DISABLE();  __asm__(LCALL(%%esi) "\n\t"	  "jc 1f\n\t"	  "xor %%ah, %%ah\n"	  "1:"	  : "=c" (value),	  "=a" (ret)	  : "1" (PciFn::RdConfByte),	  "b" (bx),	  "D" ((uint32_t) where),	  "S" (&PciFarPtr));  IRQ::ENABLE();  return (uint32_t) (ret & 0xff00) >> 8;}uint32_tPciBios::ReadConfig16 (uint8_t bus,		       uint8_t device_fn,		       uint8_t where, uint16_t& value){  uint32_t ret = 0;  uint32_t bx = (bus << 8) | device_fn;  SET_SELECTOR(PciFarPtr);  IRQ::DISABLE();  __asm__(LCALL(%%esi) "\n\t"	  "jc 1f\n\t"	  "xor %%ah, %%ah\n"	  "1:"	  : "=c" (value),	  "=a" (ret)	  : "1" (PciFn::RdConfHalfWord),	  "b" (bx),	  "D" ((uint32_t) where),	  "S" (&PciFarPtr));  IRQ::ENABLE();  return (uint32_t) (ret & 0xff00) >> 8;}uint32_tPciBios::ReadConfig32 (uint8_t bus,		       uint8_t device_fn, uint8_t where, uint32_t& value){  uint32_t ret = 0;  uint32_t bx = (bus << 8) | device_fn;  SET_SELECTOR(PciFarPtr);  IRQ::DISABLE();  __asm__(LCALL(%%esi) "\n\t"	  "jc 1f\n\t"	  "xor %%ah, %%ah\n"	  "1:"	  : "=c" (value),	  "=a" (ret)	  : "1" (PciFn::RdConfWord),	  "b" (bx),	  "D" ((uint32_t) where),	  "S" (&PciFarPtr));  IRQ::ENABLE();  return (uint32_t) (ret & 0xff00) >> 8;}uint32_tPciBios::WriteConfig8 (uint8_t bus,		       uint8_t device_fn, uint8_t where, uint8_t value){  uint32_t ret;  uint32_t bx = (bus << 8) | device_fn;  SET_SELECTOR(PciFarPtr);  IRQ::DISABLE();  __asm__(LCALL(%%esi) "\n\t"	  "jc 1f\n\t"	  "xor %%ah, %%ah\n"	  "1:"	  : "=a" (ret)	  : "0" (PciFn::WrConfByte),	  "c" (value),	  "b" (bx),	  "D" ((long) where),	  "S" (&PciFarPtr));  IRQ::ENABLE();  return (int) (ret & 0xff00) >> 8;}uint32_tPciBios::WriteConfig16 (uint8_t bus,			uint8_t device_fn, uint8_t where, uint16_t value){  uint32_t ret = 0;  uint32_t bx = (bus << 8) | device_fn;  SET_SELECTOR(PciFarPtr);  IRQ::DISABLE();  __asm__(LCALL(%%esi) "\n\t"	  "jc 1f\n\t"	  "xor %%ah, %%ah\n"	  "1:"	  : "=a" (ret)	  : "0" (PciFn::WrConfHalfWord),	  "c" (value),	  "b" (bx),	  "D" ((long) where),	  "S" (&PciFarPtr));  IRQ::ENABLE();  return (int) (ret & 0xff00) >> 8;}uint32_tPciBios::WriteConfig32 (uint8_t bus,			uint8_t device_fn, uint8_t where, uint32_t value){  uint32_t ret = 0;  uint32_t bx = (bus << 8) | device_fn;  SET_SELECTOR(PciFarPtr);  IRQ::DISABLE();  __asm__(LCALL(%%esi) "\n\t"	  "jc 1f\n\t"	  "xor %%ah, %%ah\n"	  "1:"	  : "=a" (ret)	  : "0" (PciFn::WrConfWord),	  "c" (value),	  "b" (bx),	  "D" ((uint32_t) where),	  "S" (&PciFarPtr));  IRQ::ENABLE();  return (uint32_t) (ret & 0xff00) >> 8;}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -