Я ссылаюсь на этот ответ о сбое, помогающий проанализировать этот фрагмент кода, который вызвал проблемы. Контекст для всех, я работаю над символьным драйвером, который будет действовать как переход из пользовательского пространства непосредственно к оборудованию для драйвера ahci. Для этого я соответствующим образом модифицирую драйвер ahci.
Я начинаю с малого. Я хочу заглянуть в регистры портов для порта 0 HBA HBA AHCI на моей виртуальной машине. Код ioctl моего персонажа:
switch (cmd) {
case AHCIP_GPORT_REG:
pPciDev = pci_get_device(0x8086, 0x2829, NULL);
if (pPciDev) {
/* This will set ret to the value that it needs to be. This
* is true of __put_user() too */
if ((ret = __get_user(off, (u32*)obj))) {
printk(KERN_INFO "unable to read from user space\n");
goto ioctl_quick_out;
}
reg = get_port_reg(&pPciDev->dev, off);
if ((ret = __put_user(reg, (u32*)obj)))
{
printk(KERN_INFO "Unable to write to user space\n");
}
pci_dev_put(pPciDev);
}
// This break wasn't in the code when it crashed
break;
default:
// POSIX compliance with this one (REF of LDD3)
ret = -ENOTTY;
}
Код из моей модифицированной версии ahci.c, который вызывает этот символьный драйвер:
u32 get_port_reg(struct device *dev, u32 off)
{
struct Scsi_Host *shost = class_to_shost(dev);
struct ata_port *ap = ata_shost_to_port(shost);
void __iomem *port_mmio = ahci_port_base(ap);
return ioread32(port_mmio + off);
}
EXPORT_SYMBOL(get_port_reg);
Ядро, которое это вызвало, произошло здесь:
PID: 3357 TASK: ffff88011c9b7500 CPU: 0 COMMAND: "peek"
#0 [ffff8800abfc79f0] machine_kexec at ffffffff8103b5bb
#1 [ffff8800abfc7a50] crash_kexec at ffffffff810c9852
#2 [ffff8800abfc7b20] oops_end at ffffffff8152e0f0
#3 [ffff8800abfc7b50] no_context at ffffffff8104c80b
#4 [ffff8800abfc7ba0] __bad_area_nosemaphore at ffffffff8104ca95
#5 [ffff8800abfc7bf0] bad_area at ffffffff8104cbbe
#6 [ffff8800abfc7c20] __do_page_fault at ffffffff8104d36f
#7 [ffff8800abfc7d40] do_page_fault at ffffffff8153003e
#8 [ffff8800abfc7d70] page_fault at ffffffff8152d3f5
[exception RIP: get_port_reg+18]
RIP: ffffffffa03c4cd2 RSP: ffff8800abfc7e28 RFLAGS: 00010246
RAX: 0000000000020101 RBX: 00007fff17273960 RCX: ffffffff812b0710
RDX: ffff88011ddd5000 RSI: 0000000000000000 RDI: ffff88011ddd5090
RBP: ffff8800abfc7e28 R8: 0000000000000000 R9: 0000000000000000
R10: 00000000000007d5 R11: 0000000000000006 R12: ffff88011ddd5000
R13: 0000000000000000 R14: 0000000000000000 R15: 0000000000000000
ORIG_RAX: ffffffffffffffff CS: 0010 SS: 0018
Как видите, указатель инструкции был get_port_reg+18
. Так как эта функция совсем небольшая, вот полная разборка
crash> dis get_port_reg
0xffffffffa03c4cc0 <get_port_reg>: push %rbp
0xffffffffa03c4cc1 <get_port_reg+1>: mov %rsp,%rbp
0xffffffffa03c4cc4 <get_port_reg+4>: nopl 0x0(%rax,%rax,1)
0xffffffffa03c4cc9 <get_port_reg+9>: mov 0x240(%rdi),%rax
0xffffffffa03c4cd0 <get_port_reg+16>: mov %esi,%esi
0xffffffffa03c4cd2 <get_port_reg+18>: mov 0x2838(%rax),%rdx
0xffffffffa03c4cd9 <get_port_reg+25>: mov 0x28(%rax),%eax
0xffffffffa03c4cdc <get_port_reg+28>: mov 0x10(%rdx),%rdx
0xffffffffa03c4ce0 <get_port_reg+32>: shl $0x7,%eax
0xffffffffa03c4ce3 <get_port_reg+35>: mov %eax,%eax
0xffffffffa03c4ce5 <get_port_reg+37>: add 0x28(%rdx),%rax
0xffffffffa03c4ce9 <get_port_reg+41>: lea 0x100(%rax,%rsi,1),%rdi
0xffffffffa03c4cf1 <get_port_reg+49>: callq 0xffffffff8129dde0 <ioread32>
0xffffffffa03c4cf6 <get_port_reg+54>: leaveq
0xffffffffa03c4cf7 <get_port_reg+55>: retq
0xffffffffa03c4cf8 <get_port_reg+56>: nopl 0x0(%rax,%rax,1)
Как вы уже догадались, я в некотором роде новичок в сборке. Какая строка кода будет get_port_reg+18
? Я озадачен, потому что я вызываю функции в каждой строке этой функции, но единственный вызов, который я вижу, - это ioread32()
.
Для справки, я смоделировал свою функцию get_port_reg
после ahci_show_port_cmd()
в том же файл. Я не мог придумать никаких других средств получения структуры struct pci_dev
, необходимой для ее работы. Я плохо использую get_pci_device()
и pci_dev_put()
? Разве это не проблема?
Спасибо за любую помощь
Энди
pci_get_device()
, вероятно, возвращает устройство pci, в то время как вам нужно соответствующее хост-устройство SCSI - они имеют разные классы. - person myaut   schedule 11.05.2015ata_pci_remove_one
: lxr.free-electrons.com/ source / drivers / ata / libata-core.c # L6314 показывает, как получитьata_host
с устройства PCI, и получениеata_port
с него должно быть простым. - person myaut   schedule 11.05.2015