c - 可编程中断控制器:PIC1 和 PIC2 在实模式下不返回零
问题描述
Hyper-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 应返回 0 0。现实:它们返回 184 (0xB8) 和 15 (0xF)。谁能告诉我为什么?
解决方案
Zack (The 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 DATA 端口返回的值
当您从 PIC DATA 端口读取数据时,您将读取用于确定哪些中断会导致 CPU 中断的当前掩码值。它有效地确定在每个 PIC 上启用和禁用哪些特定中断。一个位值0
表示启用并1
表示禁用。
如果两个值都为 0,那么 PIC1 和 PIC2 上的所有中断都将被启用。在某些环境中可能是这种情况,但不一定是这种情况。您读到的内容可能不是零,并且表明启用和禁用 BIOS 的中断是什么。
根据截图 PIC1 的值为184
(binary 10111000
) 而 PIC2 的值为15
(binary 00001111
)。如果这些实际上是从 PIC 读取的值,则表明 BIOS/固件启用了这些中断(其余的禁用):
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 和设备的系统上出现的常见中断。尽管您的值不为零,但它们实际上看起来确实合理,并且很可能是从两个 PIC 中读取的真实值
推荐阅读
- sql - 当我按日期过滤选择语句时出错
- julia - 如何根据任何 splatted args 的类型进行调度?
- java - While 循环中的运算符
- kotlin - 为不同用途制作相同的对象代码的最佳方法是什么
- c++ - Qt5.15:如何从 QtConcurrent 函数访问小部件对象
- python - 将 pandas if_exists = “append” 与新列一起使用
- python-3.8 - 他们有什么方法可以通过python将信息提供给给定模块中的java脚本吗?
- python - 用户注册在 Django 中完全不起作用
- java - jdbc.update 在数据库中成功,但 keyholder 没有内容返回
- java - 如何使用密码授予在 Spring Boot Oauth2 资源服务器中处理 CORS