Цитата:
Назначение ресурсов выполняется напрямую или через BIOS?
Обновляем ресурс:
setup-res.c:
Код:
void
pci_update_resource(struct pci_dev *dev, struct resource *res, int resno)
{
struct pci_bus_region region;
u32 new, check, mask;
int reg;
/*
* Ignore resources for unimplemented BARs and unused resource slots
* for 64 bit BARs.
*/
if (!res->flags)
return;
/*
* Ignore non-moveable resources. This might be legacy resources for
* which no functional BAR register exists or another important
* system resource we should better not move around in system address
* space.
*/
if (res->flags & IORESOURCE_PCI_FIXED)
return;
pcibios_resource_to_bus(dev, ®ion, res);
pr_debug(" got res [%llx:%llx] bus [%lx:%lx] flags %lx for "
"BAR %d of %sn", (unsigned long long)res->start,
(unsigned long long)res->end,
region.start, region.end, res->flags, resno, pci_name(dev));
new = region.start | (res->flags & PCI_REGION_FLAG_MASK);
if (res->flags & IORESOURCE_IO)
mask = (u32)PCI_BASE_ADDRESS_IO_MASK;
else
mask = (u32)PCI_BASE_ADDRESS_MEM_MASK;
if (resno < 6) {
reg = PCI_BASE_ADDRESS_0 + 4 * resno;
} else if (resno == PCI_ROM_RESOURCE) {
if (!(res->flags & IORESOURCE_ROM_ENABLE))
return;
new |= PCI_ROM_ADDRESS_ENABLE;
reg = dev->rom_base_reg;
} else {
/* Hmm, non-standard resource. */
return; /* kill uninitialised var warning */
}
pci_write_config_dword(dev, reg, new);
pci_read_config_dword(dev, reg, &check);
if ((new ^ check) & mask) {
printk(KERN_ERR "PCI: Error while updating region "
"%s/%d (%08x != %08x)n", pci_name(dev), resno,
new, check);
}
if ((new & (PCI_BASE_ADDRESS_SPACE|PCI_BASE_ADDRESS_MEM_TYPE_MASK)) ==
(PCI_BASE_ADDRESS_SPACE_MEMORY|PCI_BASE_ADDRESS_MEM_TYPE_64)) {
new = region.start >> 16 >> 16;
pci_write_config_dword(dev, reg + 4, new);
pci_read_config_dword(dev, reg + 4, &check);
if (check != new) {
printk(KERN_ERR "PCI: Error updating region "
"%s/%d (high %08x != %08x)n",
pci_name(dev), resno, new, check);
}
}
res->flags &= ~IORESOURCE_UNSET;
pr_debug("PCI: moved device %s resource %d (%lx) to %xn",
pci_name(dev), resno, res->flags,
new & ~PCI_REGION_FLAG_MASK);
}
При этом непосредственно установление параметров происходит с помощью функции pci_write_config_dword(dev, reg, new);
pci/access.c:
Код:
#define PCI_OP_WRITE(size,type,len)
int pci_bus_write_config##size
(struct pci_bus *bus, unsigned int devfn, int pos, type value)
{
int res;
unsigned long flags;
if (PCI##siz##_BAD) return PCIBIOS_BAD_REGISTER_NUMBER;
spin_lock_irqsave(&pci_lock, flags);
res = bus->ops->write(bus, devfn, pos, len, value);
spin_unlock_irqrestore(&pci_lock, flags);
return res;
}
bus->ops->write(bus, devfn, pos, len, value) -- вызов функции pci_write(struct pci_bus *bus, unsigned int devfn, int where, int size, u32 value);
Код:
static int pci_write(struct pci_bus *bus, unsigned int devfn, int where, int size, u32 value)
{
return raw_pci_ops->write(0, bus->number, devfn, where, size, value);
}
Ну а здесь происходит вызов следующего кода:
arch/i386/pci/pcbios.c:
Код:
static int pci_bios_write(unsigned int seg, unsigned int bus,
unsigned int devfn, int reg, int len, u32 value)
{
unsigned long result = 0;
unsigned long flags;
unsigned long bx = (bus << 8) | devfn;
if ((bus > 255) || (devfn > 255) || (reg > 255))
return -EINVAL;
spin_lock_irqsave(&pci_config_lock, flags);
switch (len) {
case 1:
__asm__("lcall *(%%esi); cldnt"
"jc 1fnt"
"xor %%ah, %%ahn"
"1:"
: "=a" (result)
: "0" (PCIBIOS_WRITE_CONFIG_BYTE),
"c" (value),
"b" (bx),
"D" ((long)reg),
"S" (&pci_indirect));
break;
case 2:
__asm__("lcall *(%%esi); cldnt"
"jc 1fnt"
"xor %%ah, %%ahn"
"1:"
: "=a" (result)
: "0" (PCIBIOS_WRITE_CONFIG_WORD),
"c" (value),
"b" (bx),
"D" ((long)reg),
"S" (&pci_indirect));
break;
case 4:
__asm__("lcall *(%%esi); cldnt"
"jc 1fnt"
"xor %%ah, %%ahn"
"1:"
: "=a" (result)
: "0" (PCIBIOS_WRITE_CONFIG_DWORD),
"c" (value),
"b" (bx),
"D" ((long)reg),
"S" (&pci_indirect));
break;
}
spin_unlock_irqrestore(&pci_config_lock, flags);
return (int)((result & 0xff00) >> 8);
}
Так что, можно считать, что назначение ресурсов выполняется через BIOS (данное утверждение справедливо для i386, другие платформы я не смотрел)
Однако, для i386 присутствует файлик, содержащий следующее упоминание:
arch/i386/pci/early.c:
Цитата:
/* Direct PCI access. This is used for PCI accesses in early boot before
the PCI subsystem works. */
и код, напрямую обращающийся к шине:
Код:
void write_pci_config_byte(u8 bus, u8 slot, u8 func, u8 offset, u8 val)
{
PDprintk("%x writing to %x: %xn", slot, offset, val);
outl(0x80000000 | (bus<<16) | (slot<<11) | (func<<8) | offset, 0xcf8);
outb(val, 0xcfc);
}
В какие именно моменты происходит использование данного кода, я не проверял.
Цитата:
Как Linux определяет, где находится SMRAM?
Насколько я понимаю, что работа с ним (точнее, с SMM) различается для разных машин. Вот, например, код для ноутбуков Toshiba:
Код:
/*
* Put the laptop into System Management Mode
*/
int tosh_smm(SMMRegisters *regs)
{
int eax;
asm (# load the values into the registersnt"
"pushl %%eaxnt"
"movl 0(%%eax),%%edxnt"
"push %%edxnt"
"movl 4(%%eax),%%ebxnt"
"movl 8(%%eax),%%ecxnt"
"movl 12(%%eax),%%edxnt"
"movl 16(%%eax),%%esint"
"movl 20(%%eax),%%edint"
"popl %%eaxnt"
# call the System Management modent"
"inb $0xb2,%%alnt"
# fill out the memory with the values in the registersnt"
"xchgl %%eax,(%%esp)nt"
"movl %%ebx,4(%%eax)nt"
"movl %%ecx,8(%%eax)nt"
"movl %%edx,12(%%eax)nt"
"movl %%esi,16(%%eax)nt"
"movl %%edi,20(%%eax)nt"
"popl %%edxnt"
"movl %%edx,0(%%eax)nt"
# setup the return value to the carry flagnt"
"lahfnt"
"shrl $8,%%eaxnt"
"andl $1,%%eaxn"
: "=a" (eax)
: "a" (regs)
: "%ebx", "%ecx", "%edx", "%esi", "%edi", "memory");
return eax;
}
Или, для ноутбуков DELL:
Код:
/*
* Call the System Management Mode BIOS. Code provided by Jonathan Buzzard.
*/
static int i8k_smm(struct smm_regs *regs)
{
int rc;
int eax = regs->eax;
asm("pushl %%eaxnt"
"movl 0(%%eax),%%edxnt"
"push %%edxnt"
"movl 4(%%eax),%%ebxnt"
"movl 8(%%eax),%%ecxnt"
"movl 12(%%eax),%%edxnt"
"movl 16(%%eax),%%esint"
"movl 20(%%eax),%%edint"
"popl %%eaxnt"
"out %%al,$0xb2nt"
"out %%al,$0x84nt"
"xchgl %%eax,(%%esp)nt"
"movl %%ebx,4(%%eax)nt"
"movl %%ecx,8(%%eax)nt"
"movl %%edx,12(%%eax)nt"
"movl %%esi,16(%%eax)nt"
"movl %%edi,20(%%eax)nt"
"popl %%edxnt"
"movl %%edx,0(%%eax)nt"
"lahfnt"
"shrl $8,%%eaxnt"
"andl $1,%%eaxn":"=a"(rc)
: "a"(regs)
: "%ebx", "%ecx", "%edx", "%esi", "%edi", "memory");
if (rc != 0 || (regs->eax & 0xffff) == 0xffff || regs->eax == eax)
return -EINVAL;
return 0;
}