ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

Akaban操作系统(4)-----中断控制器的初始化,来自UHCI的中断

2022-02-03 16:59:27  阅读:210  来源: 互联网

标签:PCI Akaban 中断 pci ----- APIC bit rax


相信你一定读了我的上一篇文章(总之应该只有IO APIC才能接受来自PCI的中断),没错,只要这次将中断驱动写出来就可以正式开始PCI的开发了!

APIC相对于8259A中断处理器那性能可谓是差了十万八千里,先不对比实际性能,先说说它们诞生的年代

8259A:

是为8085A和8086/8088这类16位,寻址能力只有20位(1MB左右)的处理器设计的,其中我所能查到的8086处理器(最大主频只有8MB的屑CPU),出场的年代也到达了1978年,这,啊,我知道了,改革开放的时候!显然,在运行速度已经快到惊人的现在几乎早已退出了世界舞台(当然大部分CPU和主板为了兼容古老的操作系统硬着头皮把它保留了下来)

再看看PCI的诞生时间1991年,由intel提出的

所以显然,要么8259a完全不兼容PCI,要么就要使用复杂的中断路由机制才能被处理器接收到,就算能,也会在中断大量爆发时使中断的传输性能呈指数级下降

所以,顺应时代潮流APIC(Advanced Programmable Interrupt Controller)诞生了!看,这名字听起来就很高级,就比pic多了个A就变得高级了不少,接下来在看看APIC的诞生年代:

自 1994 年的 Pentium P54c 开始Intel 已经将本机 APIC 建置在它们的处理器中。(摘自百度百科)

虽然也不知道为什么将local翻作本机而不是本地,但是,可以肯定,它比8259A晚16年推出!这简直是中断控制器的一次伟大飞跃

所以,综上所述,现代的操作系统几乎很少用8259a这种古老的中断控制器

那么,开始我们的apic驱动的开发吧!

像所有设备的驱动一样,运行初期必须要做一件事情,那便是,检测电脑是否存在这个设备,怎么检测呢?简单,只需要用CPUID指令检测即可,于是,我就又写了一个新的LIB,这个lib添加在开发文件夹的/lib中,名字叫libAsys.a(没有被官方认证或正式发布的库或头文件的名字都含大写字母!)其中的函数被包含在/include/SysAsmLib.h中,这里我简单地将cpuid的汇编指令封装了一下,返回的参数都用 (寄存器)_ 保存,虽然没有32位寄存器,但是可以完全可以直接用64位寄存器将内部的值读出来,以下便是cpuid_c的源码

;摘自./lib/reg_op.asm
cpuid_c: ;cpuid
	push	rax
	push	rbx
	push	rcx
	push	rdx

	mov	rax,rdi
	cpuid
	mov	[rel rax_],rax
	mov	[rel rbx_],rbx
	mov	[rel rcx_],rcx
	mov	[rel rdx_],rdx

	pop	rdx
	pop	rcx
	pop	rbx
	pop	rax
	ret
	

之后我们便可以使用它在c语言环境中读取cpuid了,当然除此之外还顺便将bts,btr,bt也打包成了c语言指令,原型如下

;./libs/bitoperate.asm
[bits 64]
test_bit:
	bt	rdi,rsi
	jc	bt_carry
		mov	rax,0
		ret
	bt_carry:
	mov	rax,1
	ret
set_bit:
	bts	rdi,rsi
	mov	rax,rdi
	ret
reset_bit:
	btr	rdi,rsi
	mov	rax,rdi
	ret

有了这几个函数我们便可以开始apic(x)和x2apic的检测了,检测函数如下所示

bool init_apic(void)
{
	cpuid_c(0x80000001);
	state_printk(PRINT_OK,"CPUID 0x80000001 returns ECX 0x%X EDX 0x%X\n",rcx_,rdx_);
	if(test_bit(rdx_,9))
	{
		state_printk(PRINT_OK,"APIC Support --- YES\n");
		if(test_bit(rcx_,21))
		{
			state_printk(PRINT_OK,"x2APIC Support --- YES\n");
		}
		else
		{
            //此处省略若干行
		}
		return true;
	}
	else state_printk(PRINT_ERR,"APIC Support --- NO\n");
	return false;
}

但正当我兴高采烈地将它放到虚拟机上运行后,它却告诉我

 啥玩意?没有版本?没事,这都不算什么(杰哥名言)。虚拟机算个啥,我还有这不真机没实验嘛。

于是带着期待的心情我重启了电脑,但是突然

Pawloader显示了一条error(这里不方便拍照就先用文字描述好了),不支持APIC,当然这时我是不信的,好端端一个64位的LGA775cpu怎么就不支持apic啦?于是,我又把CPUID抄录了下来0x1和0x20100800,带着怀疑的心情进入了ubuntu然后用计算器的程序员模式一看:

        确实不支持APIC

***(此处屏蔽一些文明用语),小丑竟是我自己,真的有64位支持pci的设备不支持APIC

不是吧,难怪这台电脑上的GT610正常跑分6500分到我的电脑上就只有3000多分,原来没有apic,性能打了50%的折扣(尽管如此还是能在低分辨率下流畅玩原神,原神YYDS!),G41主板YYDS!

但总不可能自己设计的系统自己的电脑都不支持吧?于是我又翻了一眼书,找到了一些奇妙的玩意

 好家伙!

这么一说PCI的中断是可以被8259a接收到的,并且会被分配到irq3,4,5,6,7,9,10,11,12,14,15这几根中断线上,具体分配到哪根只需要去读PCI配置空间即可,这里挂一下PCI设备配置空间的结构图

根据我在虚拟机和真机上的实验,我发现interrupt line 基本上都是3,4,5,6,7,9,10,11,12,14,15这一类数字(排除真机上出现的0x255这个特例),所以我大胆猜测,这玩意就是链接8259a的中断线号,哦,这意味着我们要准备共享中断号了!啊,我的头发,再多写几次这样超高难度的代码我的头发就要薅得和化学老师一样秃了(虽然我的头发仍然浓密得不得了,自然程序的bug哦不,特性就比较多)。但是我又在网上翻到了一些不得了的玩意,共享中断要轮询设备驱动效率高得感人,但这也没办法,谁叫我的电脑是几十年前的G41 pcie协议甚至都没有3.0(意味着不能使用MSI和MSI-X),

8259a也是支持PCI的可是上一章图像里8259a明明不支持pci中断,但是顺藤摸瓜,我又去网上搜了一下PIRQ MAPPING,更刺激的出现了

 没错,田宇书上的表省略了共享中断引脚的设备,之后再根据这篇文章

https://blog.csdn.net/weixin_30300225/article/details/99421416

我们便可以得知pci配置空间的pin实际上对应着哪个引脚,PIRQABCD...等引脚按次序依次从表中的irq3,4,5,6,7,9,10,11,12,14,15,绝,实在是绝,但是在我电脑bios启动时期我看到了bios给所有pci设备列了表,并分配了irq,也就是说我们只需要将pci配置空间的pci intr_line的值读出来就知道是哪个pirq了

当然具体pci的PIRQABCD是如何与irq链接的请见下面的文章(不能保证N年后它仍存在)

IRQ与APIC - it610.com

总之,这一章必须要让PCI设备给爷触发中断

于是,我就到网上翻了一段时间(拖更的原因出现了...),翻了个寂寞,开玩笑的,翻到了两个好宝贝UHCI Design guide和EHCI Design guide,两本手册在usb官网文档库中找不到,是在豆丁网还有另一个网站上找到的,上面介绍了UHCI(即USB1.1)的运行机制,数据结构和IO寄存器的使用方法(EHCI同理),没错,我今天就要让UHCI给我触发中断,于是我就先行将UHCI探测(初始化)程序写出来了,代码如下所示

//path = minefunction/PawLoader/driver/usb/uhci.c
bool probe_uhci(struct pci_info *dev)
{
	u32 class = in_pci_conf32(dev,PCI_REG_CLASS); //在minefunction/PawLoader/driver/pci/pci_conf.c中
	class >>=8;
	if(class!=PCI_USB_DEV)	return false;	//判断设备的class值来判断是否为USB根集线器
	
	driver_printk(PRINT_OK,DRIVER_NAME,"Hello UHCI !\n");
	
	//根据UHCI design guid的第10面可知 pci_config_space的bar4存着uhci的io基地址
	//注意,这个值一般在开机时就已经被bios初始化了,但是目前不能确定efi启动后是否会为其分配io地址
	u32 tmp_bit_map = in_pci_conf32(dev,PCI_REG_BAR_4_);
	if(test_bit(tmp_bit_map,0)!=true) return false;	//如果不占用io资源,则不是该程序支持的uhci
	tmp_bit_map >>= 4;	
	tmp_bit_map <<= 4;	//把它的属性洗掉
	if(tmp_bit_map == 0)	return false;	//暂不支持对pci设备的资源分配
	
	struct hc_device hc_dev;
	hc_dev.io_base = (u16)tmp_bit_map; //记下io寄存器的地址

	driver_printk(PRINT_OK,DRIVER_NAME,"UHCI IO PORT 0x%x\n",hc_dev.io_base);
	
	u16 intr_op = io_in2b(UHCI_REG_OFF_INTR+hc_dev.io_base);	//将中断控制寄存器读入
	intr_op = set_bit(intr_op,UHCI_INTR_SPIE_BIT);	//管它啥中断,一股脑开启就完了
	intr_op = set_bit(intr_op,UHCI_INTR_IOCE_BIT);
	intr_op = set_bit(intr_op,UHCI_INTR_RIE_BIT);
	intr_op = set_bit(intr_op,UHCI_INTR_CRCIE_BIT);
	io_out2b(UHCI_REG_OFF_INTR+hc_dev.io_base,intr_op);	//写回
	
	u16 cmd_reg = io_in2b(UHCI_REG_OFF_CMD+hc_dev.io_base);	//同理,开启设备
	cmd_reg = set_bit(cmd_reg,UHCI_CMD_RS_BIT);		
	io_out2b(UHCI_REG_OFF_CMD+hc_dev.io_base,cmd_reg);
	u16 *debug = (u16 *)0x500;	//debug数据指针,可以指向任何分配了的空闲内存
	for(int i=0;i<0x20;i++) debug[i] = io_in2b(hc_dev.io_base+i*2);	
	state_printk(PRINT_OK,"IO DATA :  0x%X 0x%X 0x%X 0x%X\n",debug[0],debug[1],debug[2],debug[3]);
	state_printk(PRINT_OK,"IO DATA :  0x%X 0x%X 0x%X 0x%X\n",debug[4],debug[5],debug[6],debug[7]);
	PAUSE;	//在bochs中运行到这会停止,之后用xp/40xw 0x500看uhci io寄存器的内容

	hc_dev.int_line = in_pci_conf32(dev,PCI_INT_LINE)&0xff;	//记下中断号 

	//将设备注册
	register_uhci_dev(&hc_dev);
	return true;
}

代码中还有一些宏,大部分定义在了usb.h中,可以自行阅读

当然在源码minefunction/usb_specific中我将20块钱买来的(不知道值不值),两份文档存在了里面,在baidu网盘的链接根目录也有,可下载下来自行阅读(虽然是全英文的但是有道翻译就很香)

于是我就将源码编译,运行了一遍,在虚拟机中结果如下

 虚拟机都不算什么,看看真机,啊,完美......的重启(后来发现是不是HCD的问题)了,Fantastic(Doctor狂喜)!怎么回事呢,请听下回分解......

就怪了,BUG,哦不,特性不好好修理一番不像我的风格(尽管还是有一大把特性),但是没有关系,无论如何先将uhci完全初始化(下一章细讲)一下康康

然后嘛,初始化是全都完成了,但是虚拟机上没有半点中断,如下图所示

 但是,虚拟机,能代表什么呢?重要的是真机!

啊,成功啦!个头啊!

随便写的HCD要是能成功我都能去当半仙算卦去了,细看图上STS_REG:0x30,啥意思?UHCI设备挂起,并且HC检查到了一个致命的错误,需要我们将设备停止防止HC使用错误的信息继续产生错误中断

哈,就知道要么是我的程序出错要么是bochs出错,这次不一样,都出错了,负负得正,就"成功"了,不过没关系,错误的中断总比没有好,下一章把它TD的队列头写好估计就没问题了

顺便把源码链接挂一下

链接: https://pan.baidu.com/s/1m9WZVL4zFlnsb7t2aL5kng 提取码: sdpk

标签:PCI,Akaban,中断,pci,-----,APIC,bit,rax
来源: https://blog.csdn.net/qq_57339294/article/details/122566719

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有