可编程中断控制器:PIC1 和 PIC2 在实模式下不返回零
Programmable Interrupt Controller: PIC1 and PIC2 are not returning zeros in real mode
超 V 输出:
代码:
/*PIC Definition*/
#define PIC1 0x20 /* IO base address for master PIC */
#define PIC2 0xA0 /* IO base address for slave PIC */
#define PIC1_COMMAND PIC1
#define PIC1_DATA (PIC1+1)
#define PIC2_COMMAND PIC2
#define PIC2_DATA (PIC2+1)
#define ICW1_ICW4 0x01 /* ICW4 (not) needed */
#define ICW1_SINGLE 0x02 /* Single (cascade) mode */
#define ICW1_INTERVAL4 0x04 /* Call address interval 4 (8) */
#define ICW1_LEVEL 0x08 /* Level triggered (edge) mode */
#define ICW1_INIT 0x10 /* Initialization - required! */
#define ICW4_8086 0x01 /* 8086/88 (MCS-80/85) mode */
#define ICW4_AUTO 0x02 /* Auto (normal) EOI */
#define ICW4_BUF_SLAVE 0x08 /* Buffered mode/slave */
#define ICW4_BUF_MASTER 0x0C /* Buffered mode/master */
#define ICW4_SFNM 0x10 /* Special fully nested (not) */
#define inb(x,y) asm volatile ("inb %1, %0" : "=a"(x) : "d"(y));
void PIC_remap(BYTE offset1, BYTE offset2)
{
unsigned char a1, a2, cmd;
WORD portnum = PIC1_DATA;
inb(a1, portnum); // save masks
portnum = PIC2_DATA;
inb(a2, portnum);
WORD ret1 = a1, ret2 = a2;
printf("Response from PIC1 and PIC2: %d %d", ret1, ret2);
portnum = PIC1_COMMAND;
cmd = (ICW1_INIT | ICW1_ICW4);
outb(portnum, cmd); // starts the initialization sequence (in cascade mode)
io_wait();
portnum = PIC2_COMMAND;
outb(portnum, cmd);
io_wait();
portnum = PIC1_DATA;
outb(portnum, offset1); // ICW2: Master PIC vector offset
io_wait();
portnum = PIC2_DATA;
outb(portnum, offset2); // ICW2: Slave PIC vector offset
io_wait();
portnum = PIC1_DATA;
cmd = 4;
outb(portnum, cmd); // ICW3: tell Master PIC that there is a slave PIC at IRQ2 (0000 0100)
io_wait();
portnum = PIC2_DATA;
cmd = 2;
outb(portnum, cmd); // ICW3: tell Slave PIC its cascade identity (0000 0010)
io_wait();
portnum = PIC1_DATA;
cmd = ICW4_8086;
outb(portnum, cmd);
io_wait();
portnum = PIC2_DATA;
cmd = ICW4_8086;
outb(portnum, cmd);
io_wait();
outb(PIC1_DATA, a1); // restore saved masks.
outb(PIC2_DATA, a2);
}
我正在搜索可编程中断控制器在实模式下的行为。但是我遇到了一些问题。
预期行为:PIC1 和 PIC2 应 return 0 0。
现实:他们 return 184 (0xB8) 和 15 (0xF)。谁能告诉我为什么?
Zack(OP)提供了他们实施 inb
的更新,这个答案已经过修改以提供更具体的答案。 inb
被定义为 宏 这样:
#define inb(x,y) asm volatile ("inb %1, %0" : "=a"(x) : "d"(y));
用大写标识符命名宏可能更清楚,例如 INB
。从原始代码中我根本不清楚这是一个宏。宏的替代方法是在共享头文件中使 inb
成为 static
inline
函数。您甚至可以用 __attribute__((always_inline))
标记它,以便它在较低的优化级别上内联。该函数可以这样定义:
typedef unsigned short int WORD;
typedef unsigned char BYTE;
#define alwaysinline __attribute__((always_inline))
static inline alwaysinline BYTE inb (WORD portnum)
{
BYTE byteread;
asm volatile ("inb %1, %0"
: "=a"(byteread)
: "Nd"(portnum));
return byteread;
}
PIC 数据端口返回的值
当您从 PIC 数据端口读取时,您将读取当前掩码值,这些值用于确定哪些中断将导致 CPU 被中断。它有效地确定在每个 PIC 上启用和禁用哪些特定中断。 0
的位值表示 enabled 并且 1
表示 disabled.
如果两个值都为 0,则 PIC1 和 PIC2 上的所有中断都将被启用。在某些环境中可能是这种情况,但不一定非得如此。您读到的内容可能不为零,表示启用和禁用 BIOS 的中断。
根据屏幕截图,PIC1 的值为 184
(二进制 10111000
),PIC2 为 15
(二进制 00001111
)。如果这些实际上是从图片中读取的值,那么它会建议 BIOS/Firmware 启用这些 interrupts(其余禁用):
IRQ0 - Timer
IRQ1 - Keyboard
IRQ2 - Cascade interrupt
IRQ6 - Usually the Floppy controller
IRQ12 - Mouse/PS2
IRQ13 - Inter Processor interrupt (IPI) - in old days it was for the separate FPU
IRQ14 - Primary ATA Channel (HDD/CD-ROM etc)
IRQ15 - Secondary ATA Channel (HDD/CD-ROM etc)
这些是有道理的,因为它们是您预期会出现在支持旧版 BIOS 和设备的系统上的常见中断。尽管您的值不为零,但它们实际上看起来很合理,并且很可能是从两张图片中读取的真实值
超 V 输出:
代码:
/*PIC Definition*/
#define PIC1 0x20 /* IO base address for master PIC */
#define PIC2 0xA0 /* IO base address for slave PIC */
#define PIC1_COMMAND PIC1
#define PIC1_DATA (PIC1+1)
#define PIC2_COMMAND PIC2
#define PIC2_DATA (PIC2+1)
#define ICW1_ICW4 0x01 /* ICW4 (not) needed */
#define ICW1_SINGLE 0x02 /* Single (cascade) mode */
#define ICW1_INTERVAL4 0x04 /* Call address interval 4 (8) */
#define ICW1_LEVEL 0x08 /* Level triggered (edge) mode */
#define ICW1_INIT 0x10 /* Initialization - required! */
#define ICW4_8086 0x01 /* 8086/88 (MCS-80/85) mode */
#define ICW4_AUTO 0x02 /* Auto (normal) EOI */
#define ICW4_BUF_SLAVE 0x08 /* Buffered mode/slave */
#define ICW4_BUF_MASTER 0x0C /* Buffered mode/master */
#define ICW4_SFNM 0x10 /* Special fully nested (not) */
#define inb(x,y) asm volatile ("inb %1, %0" : "=a"(x) : "d"(y));
void PIC_remap(BYTE offset1, BYTE offset2)
{
unsigned char a1, a2, cmd;
WORD portnum = PIC1_DATA;
inb(a1, portnum); // save masks
portnum = PIC2_DATA;
inb(a2, portnum);
WORD ret1 = a1, ret2 = a2;
printf("Response from PIC1 and PIC2: %d %d", ret1, ret2);
portnum = PIC1_COMMAND;
cmd = (ICW1_INIT | ICW1_ICW4);
outb(portnum, cmd); // starts the initialization sequence (in cascade mode)
io_wait();
portnum = PIC2_COMMAND;
outb(portnum, cmd);
io_wait();
portnum = PIC1_DATA;
outb(portnum, offset1); // ICW2: Master PIC vector offset
io_wait();
portnum = PIC2_DATA;
outb(portnum, offset2); // ICW2: Slave PIC vector offset
io_wait();
portnum = PIC1_DATA;
cmd = 4;
outb(portnum, cmd); // ICW3: tell Master PIC that there is a slave PIC at IRQ2 (0000 0100)
io_wait();
portnum = PIC2_DATA;
cmd = 2;
outb(portnum, cmd); // ICW3: tell Slave PIC its cascade identity (0000 0010)
io_wait();
portnum = PIC1_DATA;
cmd = ICW4_8086;
outb(portnum, cmd);
io_wait();
portnum = PIC2_DATA;
cmd = ICW4_8086;
outb(portnum, cmd);
io_wait();
outb(PIC1_DATA, a1); // restore saved masks.
outb(PIC2_DATA, a2);
}
我正在搜索可编程中断控制器在实模式下的行为。但是我遇到了一些问题。 预期行为:PIC1 和 PIC2 应 return 0 0。 现实:他们 return 184 (0xB8) 和 15 (0xF)。谁能告诉我为什么?
Zack(OP)提供了他们实施 inb
的更新,这个答案已经过修改以提供更具体的答案。 inb
被定义为 宏 这样:
#define inb(x,y) asm volatile ("inb %1, %0" : "=a"(x) : "d"(y));
用大写标识符命名宏可能更清楚,例如 INB
。从原始代码中我根本不清楚这是一个宏。宏的替代方法是在共享头文件中使 inb
成为 static
inline
函数。您甚至可以用 __attribute__((always_inline))
标记它,以便它在较低的优化级别上内联。该函数可以这样定义:
typedef unsigned short int WORD;
typedef unsigned char BYTE;
#define alwaysinline __attribute__((always_inline))
static inline alwaysinline BYTE inb (WORD portnum)
{
BYTE byteread;
asm volatile ("inb %1, %0"
: "=a"(byteread)
: "Nd"(portnum));
return byteread;
}
PIC 数据端口返回的值
当您从 PIC 数据端口读取时,您将读取当前掩码值,这些值用于确定哪些中断将导致 CPU 被中断。它有效地确定在每个 PIC 上启用和禁用哪些特定中断。 0
的位值表示 enabled 并且 1
表示 disabled.
如果两个值都为 0,则 PIC1 和 PIC2 上的所有中断都将被启用。在某些环境中可能是这种情况,但不一定非得如此。您读到的内容可能不为零,表示启用和禁用 BIOS 的中断。
根据屏幕截图,PIC1 的值为 184
(二进制 10111000
),PIC2 为 15
(二进制 00001111
)。如果这些实际上是从图片中读取的值,那么它会建议 BIOS/Firmware 启用这些 interrupts(其余禁用):
IRQ0 - Timer
IRQ1 - Keyboard
IRQ2 - Cascade interrupt
IRQ6 - Usually the Floppy controller
IRQ12 - Mouse/PS2
IRQ13 - Inter Processor interrupt (IPI) - in old days it was for the separate FPU
IRQ14 - Primary ATA Channel (HDD/CD-ROM etc)
IRQ15 - Secondary ATA Channel (HDD/CD-ROM etc)
这些是有道理的,因为它们是您预期会出现在支持旧版 BIOS 和设备的系统上的常见中断。尽管您的值不为零,但它们实际上看起来很合理,并且很可能是从两张图片中读取的真实值