OSDev

для всех
Текущее время: 21 ноя 2017, 20:11

Часовой пояс: UTC + 3 часа




Начать новую тему Ответить на тему  [ Сообщений: 15 ]  На страницу 1, 2  След.
Автор Сообщение
 Заголовок сообщения: Драйвер PCI в Linux
СообщениеДобавлено: 13 июл 2007, 23:20 

Зарегистрирован: 13 июл 2007, 23:16
Сообщения: 23
Способен ли драйвер PCI в Linux изменять регионы адресов памяти, выделяемые для устройства (например, регион адресов видеопамяти)? Учитывает ли Linux существование SMRAM?


Вернуться к началу
 Профиль  
 
 Заголовок сообщения: Re: Драйвер PCI в Linux
СообщениеДобавлено: 14 июл 2007, 00:40 

Зарегистрирован: 26 апр 2007, 15:35
Сообщения: 366
Откуда: Saint-Petersburg
Судя по следующему коду из ядра Linux (из версии 2.6.20), способен
Цитата:
3.2 Request MMIO/IOP resources
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Memory (MMIO), and I/O port addresses should NOT be read directly
from the PCI device config space. Use the values in the pci_dev structure
as the PCI "bus address" might have been remapped to a "host physical"
address by the arch/chip-set specific kernel support.

See Documentation/IO-mapping.txt for how to access device registers
or device memory.

The device driver needs to call pci_request_region() to verify
no other device is already using the same address resource.
Conversely, drivers should call pci_release_region() AFTER
calling pci_disable_device().
The idea is to prevent two devices colliding on the same address range.

[ See OS BUG comment above. Currently (2.6.19), The driver can only
  determine MMIO and IO Port resource availability _after_ calling
  pci_enable_device(). ]

Generic flavors of pci_request_region() are request_mem_region()
(for MMIO ranges) and request_region() (for IO Port ranges).
Use these for address resources that are not described by "normal" PCI
BARs.

Also see pci_request_selected_regions() below.

drivers/pci/setup-res.c:
Код:
int pci_assign_resource(struct pci_dev *dev, int resno)
{
        struct pci_bus *bus = dev->bus;
        struct resource *res = dev->resource + resno;
        resource_size_t size, min, align;
        int ret;

        size = res->end - res->start + 1;
        min = (res->flags & IORESOURCE_IO) ? PCIBIOS_MIN_IO : PCIBIOS_MIN_MEM;
        /* The bridge resources are special, as their
           size != alignment. Sizing routines return
           required alignment in the "start" field. */
        align = (resno < PCI_BRIDGE_RESOURCES) ? size : res->start;

        /* First, try exact prefetching match.. */
        ret = pci_bus_alloc_resource(bus, res, size, align, min,
                                     IORESOURCE_PREFETCH,
                                     pcibios_align_resource, dev);

        if (ret < 0 && (res->flags & IORESOURCE_PREFETCH)) {
                /*
                 * That failed.
                 *
                 * But a prefetching area can handle a non-prefetching
                 * window (it will just not perform as well).
                 */
                ret = pci_bus_alloc_resource(bus, res, size, align, min, 0,
                                             pcibios_align_resource, dev);
        }

        if (ret) {
                printk(KERN_ERR "PCI: Failed to allocate %s resource "
                        #%d:%llx@%llx for %sn",
                        res->flags & IORESOURCE_IO ? "I/O" : "mem",
                        resno, (unsigned long long)size,
                        (unsigned long long)res->start, pci_name(dev));
        } else if (resno < PCI_BRIDGE_RESOURCES) {
                pci_update_resource(dev, res, resno);
        }

drivers/pci/bus.c:
Код:
/**
 * pci_bus_alloc_resource - allocate a resource from a parent bus
 * @bus: PCI bus
 * @res: resource to allocate
 * @size: size of resource to allocate
 * @align: alignment of resource to allocate
 * @min: minimum /proc/iomem address to allocate
 * @type_mask: IORESOURCE_* type flags
 * @alignf: resource alignment function
 * @alignf_data: data argument for resource alignment function
 *
 * Given the PCI bus a device resides on, the size, minimum address,
 * alignment and type, try to find an acceptable resource allocation
 * for a specific device resource.
 */
int
pci_bus_alloc_resource(struct pci_bus *bus, struct resource *res,
                resource_size_t size, resource_size_t align,
                resource_size_t min, unsigned int type_mask,
                void (*alignf)(void *, struct resource *, resource_size_t,
                                resource_size_t),
                void *alignf_data)
{
        int i, ret = -ENOMEM;

        type_mask |= IORESOURCE_IO | IORESOURCE_MEM;

        for (i = 0; i < PCI_BUS_NUM_RESOURCES; i++) {
                struct resource *r = bus->resource[i];
                if (!r)
                        continue;

                /* type_mask must match */
                if ((res->flags ^ r->flags) & type_mask)
                        continue;

                /* We cannot allocate a non-prefetching resource
                   from a pre-fetching area */
                if ((r->flags & IORESOURCE_PREFETCH) &&
                    !(res->flags & IORESOURCE_PREFETCH))
                        continue;

                /* Ok, try it out.. */
                ret = allocate_resource(r, res, size,
                                        r->start ? : min,
                                        -1, align,
                                        alignf, alignf_data);
                if (ret == 0)
                        break;
        }
        return ret;
}

Цитата:
Учитывает ли Linux существование SMRAM?

Да.


Вернуться к началу
 Профиль  
 
 Заголовок сообщения: Re: Драйвер PCI в Linux
СообщениеДобавлено: 14 июл 2007, 01:39 

Зарегистрирован: 13 июл 2007, 23:16
Сообщения: 23
Назначение ресурсов выполняется напрямую или через BIOS? Как Linux определяет, где находится SMRAM?


Вернуться к началу
 Профиль  
 
 Заголовок сообщения: Re: Драйвер PCI в Linux
СообщениеДобавлено: 14 июл 2007, 04:22 
Вылез на сайт интел ищу где прячиться SMRAM. В Intel хитрюги :)
SMRAM занимает диапозон 000A0000h–000BFFFFh. ДА, да вы не ошиблись это там где видео память. Северный чипсет(контролер памяти) предохроняет эту память от записи.
Также SMRAM может быть отоброжена на HSEG (0_FFEA_0000 to 0_FFEB_FFFF).

Есть еще ESMRAM(Extended System Management RAM) откушивается верхушка(128KБ-1МБ) от Основной памяти компьютера.
А также возможно что может откушиваться участок 100A0000h–100BFFFFh -

Насчет дырок в основной памяти. Тут узнать к каким адрессам имеет доступ ОС, а к каким нет можно через BIOS. Когда определяешь размер памяти. E820 - точно покажет с какой памятью можно работать с какой нет. Если E820 не поддерживается, то другии сервисы биоса покажут без верхних килобайт(мегабайта).

Насчет HSEG (0_FFEA_0000 to 0_FFEB_FFFF).
Через серивы BIOS'а такие как PNP или ACPI можно выяснить, что занят этот диапозон.

Теперь насчет назначения рессурсов. Идет в ядре resource.c там обыкновенный список. насколько мог мельком судить. Так что к BIOS на этом этапе не обращается. Хотя о занятых диапозонах Linux может выяснить заранее.


Вернуться к началу
  
 
 Заголовок сообщения: Re: Драйвер PCI в Linux
СообщениеДобавлено: 14 июл 2007, 04:40 

Зарегистрирован: 26 апр 2007, 15:35
Сообщения: 366
Откуда: Saint-Petersburg
Цитата:
Назначение ресурсов выполняется напрямую или через 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, &region, 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;
}


Вернуться к началу
 Профиль  
 
 Заголовок сообщения: Re: Драйвер PCI в Linux
СообщениеДобавлено: 14 июл 2007, 15:21 
legos, И где ты увидил вызов pci_bios_write ? Функция есть. Но при установки адресса она не учавствует.
BIOS задействован только при установки IRQ, так как IRQ устанавливается не только в каждом устройстве, а в ISA(LPC) мосте. И спецефично для каждого железа.


Вернуться к началу
  
 
 Заголовок сообщения: Re: Драйвер PCI в Linux
СообщениеДобавлено: 14 июл 2007, 15:27 

Зарегистрирован: 13 июл 2007, 23:16
Сообщения: 23
Может ли Linux работать напрямую с северным мостом (northbridge)?


Вернуться к началу
 Профиль  
 
 Заголовок сообщения: Re: Драйвер PCI в Linux
СообщениеДобавлено: 14 июл 2007, 15:39 
P_Aleksandrov, А что ему мешает? А во вторых что понимать под работой?
Ты лучше напиши что хочешь сделать.


Вернуться к началу
  
 
 Заголовок сообщения: Re: Драйвер PCI в Linux
СообщениеДобавлено: 14 июл 2007, 15:40 

Зарегистрирован: 13 июл 2007, 23:16
Сообщения: 23
Цитата:
P_Aleksandrov, А что ему мешает? А во вторых что понимать под работой?
Ты лучше напиши что хочешь сделать.
//_Pavia

Открыть SMRAM


Вернуться к началу
 Профиль  
 
 Заголовок сообщения: Re: Драйвер PCI в Linux
СообщениеДобавлено: 14 июл 2007, 15:52 
Это спецефично для кадого чипсета. Если у тебя Intel, то можно в его доках посмотреть.


Вернуться к началу
  
 
Показать сообщения за:  Поле сортировки  
Начать новую тему Ответить на тему  [ Сообщений: 15 ]  На страницу 1, 2  След.

Часовой пояс: UTC + 3 часа


Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 1


Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете добавлять вложения

Найти:
Перейти:  
cron
Создано на основе phpBB® Forum Software © phpBB Group
Русская поддержка phpBB