云题海 - 专业文章范例文档资料分享平台

当前位置:首页 > PMON的pci设备初始化

PMON的pci设备初始化

  • 62 次阅读
  • 3 次下载
  • 2025/5/24 23:44:59

第二章 PCI设备初始化

系统刚上电时,CPU从0xbfc0.0000开始执行。这个地址在Rom空间中,在完成TLB,Cache,UART等初始化后,CPU就将代码拷到0x8010.0000开始的RAM空间(这个地址是编译Pmon时分配符号_start的),然后跳转到initmips(),开始在内存空间的执行。

执行initmips之前,CPU做的初始化只是初步的,其作用只是为CPU在内存中运行做一些必要的准备。主要的初始化工作:PCI设备的扫描、空间映射、资源分配都是initmips()函数所完成的。

下面我们跟踪initmips的执行来观察系统初始化的过程。 void

initmips(unsigned int memsz) { /*

* Set up memory address decoders to map entire memory. * But first move away bootrom map to high memory. */

memorysize=(memsz&0x0000ffff) << 20;//recover to original size:256M memorysize_high=((memsz&0xffff0000)>>16) << 20;//0

/*

* Probe clock frequencys so delays will work properly. */

tgt_cpufreq();

SBD_DISPLAY(\ /*

* Init PMON and debug */

cpuinfotab[0] = &DBGREG; dbginit(NULL); /*

* Set up exception vectors. */

SBD_DISPLAY(\

bcopy(MipsException, (char *)TLB_MISS_EXC_VEC, MipsExceptionEnd - MipsException);

bcopy(MipsException, (char *)GEN_EXC_VEC, MipsExceptionEnd - MipsException);

CPU_FlushCache();

CPU_SetSR(0, SR_BOOT_EXC_VEC); SBD_DISPLAY(\ /* Launch! */

main(); }

首先是获取CPU的时钟频率,这是tgt_cpufreq()完成的。它定义在tgt_machdep.c中。主要的方法就是先读取COP0中的count寄存器,然后延时一段时间,再读取count寄存器。两次的差值乘以2就是这段时间内cpu的时钟周期数。另外,CMOS中有个实时钟,在延时前后读取当前时间该相减,就可以知道延时的准确时间。从而计算出cpu的时钟频率。全局变量md_cpufreq记录了cpu频率值,md_pipefreq是流水线的频率,它们的值分别是500MHZ和1000MHZ;

接着调用的是dbginit(),这是最要的一个函数,几乎所有的初始化代码都由他直接或间接调用。

? 构造函数(constructor)的执行。

Dbginit()调用的第一个函数是__init()。这个函数的过程很简单,它就是将所有的constructor的函数执行一遍,建立一些基本的数据结构。在pmon中有三类constructor函数,它们都是静态函数。

1) 命令处理初始化函数,位于pmon/cmds目录下,其名称都叫init_cmd()。 2) 文件系统初始化函数。pmon/fs目录下。函数名称叫init_fs()或者

init_xxxfs()。

3) 可执行文件类型初始化。在pmon/loader目录下。函数名称叫init_exec()

Pmon中定义了大量的命令,每个命令都对应一个Cmd类型的结构。该结构的含义如下。

typedef struct Cmd {

const char *name; //命令的名称 const char *opts; //参数

const Optdesc *optdesc; //命令参数的option const char *desc; //命令描述 int (*func) __P((int, char *[])); //处理函数 int minac; //最小参数个数 int maxac; //最大参数个数 int flag;

#define CMD_REPEAT 1 /* Command is repeatable */ #define CMD_HIDE 2 /* Command is hidden */

#define CMD_ALIAS 4 /* Alias for another command name */ } Cmd;

CmdTable是一个指针数组。对每一个命令,CmdTable中都有一个指针指向它对应的Cmd结构。Init_cmd()所作的就是将各个Cmd结构的地址填入CmdTable中。

Pmon中所支持的每一个文件系统都有一个相应的数据结构来表示。对于磁盘文件系统,这个结构是DiskFileSystem;对于其他文件系统,这个结构叫做FileSystem。这两个结构的成员主要是一些函数指针,分别指向文件系统的open,read,write,ioctl,lseek及close函数。

文件系统初始化就是代表各个文件系统的数据结构插入到相应链表。对于磁盘文件系统,链表的头指针式DiskFileSystems。对于其他的文件系统,头指针是FileSystems。这样当需要对某个文件操作(包括虚拟文件,如与用户交互的终端termio)。通过这两个链表可以找到相应的结构,在通过里面的函数指针就可以对文件进行具体操作了。

Pmon可以载入执行几种格式的文件。其中包括elf可执行文件,二进制文件(称为 Raw binary file)。对每一个支持的文件类型,有一个ExecType类型的的结构。这个结构定义如下:

typedef struct ExecType {

char *execname; /*文件类型,如bin ,elf 等*/

long (*loader) __P((int , char *, int *, int ));/*载入文件类型,并设置执行条 件*/ #define EXECFLAGS_NONE 0x0000 #define EXECFLAGS_NOAUTO 0x0001 /* Don't auto load */ int flags;

SLIST_ENTRY(ExecType) i_next; } ExecType;

由于每种执行文件的格式不一样,因此对它们的载入执行也不一样,函数指针loader就是文件的转载寒暑。对于二进制文件(bin),这个函数是load_bin。二进制文件是最简单的,load_bin所作的只不过就是将执行文件读入到指定地址。Elf文件比较复杂,它的载入函数是load_elf()。这个函数比较复杂,但过程还是很简单的,就是依据elf文件头的内容载入各个程序段的内容,并返回可执行文件开始执行的地址。

? 环境初始化

envint()设置所有的环境变量。最多可以设置64个环境变量。每个环境变量对应一个envpair结构。Envvar是一个envpair类型的数组。envinit()就是根据标准环境变量的值(数组stdenvtab)来初始化envvar数组。更改环境变量的值可以改变pmon中命令的行为以及一些系统参数。

? 设备初始化

设备初始化主要就是PCI设备的初始化。这是由tgt_devinit()完成的。tgt_devinit又调用了_pci_businit()。

PCI设备初始化分为两步,第一步是北桥初始化。第二步是设备初始化。在Pmon中,每个PCI设备都对应一个pci_device结构(包括pci-pci桥);每个pci总线都对应一个pci_bus结构;

struct pci_device {

struct pci_attach_args pa; //设备的一些信息,如id,class,中断线 // unsigned char min_gnt; unsigned char max_lat; unsigned char int_line; pcireg_t stat;

u_int8_t intr_routing[4]; struct pci_bridge bridge; struct pci_bus *pcibus; struct pci_device *next; struct pci_device *parent; };

Min_gnt,Max_lat是PCI设备和时间相关的参数。Min_gnt说明在33Mhz时钟频率下,一个burst period所要的时间。而Max_lat说明了设备访问PCI总线的频率。从它们的定义可以看出这两个参数和设备的带宽密切相关。

Stat则说明了设备所处的状态(是否可用,是否可以作为主设备等)。

由于所有的设备都连接在总线上,而总线又总是通过pci桥联在系统中,因此结构中还有一个pci_bridge结构bridge。如果该设备本身是一个pci桥,则bridge代表了它自身。

Pcibus指向设备所在的总线。所有的pci设备通过next指针形成一个链表。最后,parent指向该设备的父设备。

struct pci_bus {

struct pci_bus *next; /* next bus pointer */ u_int8_t min_gnt; /* largest min grant */ u_int8_t max_lat; /* smallest max latency */ u_int8_t devsel; /* slowest devsel */ u_int8_t fast_b2b; /* support fast b2b */ u_int8_t prefetch; /* support prefetch */ u_int8_t freq66; /* support 66MHz */ u_int8_t width64; /* 64 bit bus */ u_int8_t bus;

u_int8_t ndev; /* # devices on bus */ u_int8_t def_ltim; /* default ltim counter */ u_int8_t max_ltim; /* maximum ltim counter */ int32_t bandwidth; /* # of .25us ticks/sec @ 33MHz */ paddr_t minpcimemaddr; /* PCI allocation min mem for bus */ paddr_t nextpcimemaddr;/* PCI allocation max mem for bus */ paddr_t minpciioaddr; /* PCI allocation min i/o for bus */ paddr_t nextpciioaddr; /* PCI allocation max i/o for bus */ paddr_t pci_mem_base; paddr_t pci_io_base; };

可以看到pci_bus中很多成员和pci_device相同,这是因为pci_bus结构的信息是和它所连接的设备相关的。

对pci_bus结构要说明的地方是minpcimemadd,nextpcimemaddr,minpciioadd,nextpciioaddr。Pci设备所要的memory空间和IO空间都是有限的。Minpcimemaddr是PCI总线所能分配的最小memory地址;minpciioaddr是能分配的最小IO地址。Pmon才用的空间分配方法是从高地址到低地址。每次为设备分配mem空间都是从nextpcimemaddr开始往下分配,分配io空间同样是从

搜索更多关于: PMON的pci设备初始化 的文档
  • 收藏
  • 违规举报
  • 版权认领
下载文档10.00 元 加入VIP免费下载
推荐下载
本文作者:...

共分享92篇相关文档

文档简介:

第二章 PCI设备初始化 系统刚上电时,CPU从0xbfc0.0000开始执行。这个地址在Rom空间中,在完成TLB,Cache,UART等初始化后,CPU就将代码拷到0x8010.0000开始的RAM空间(这个地址是编译Pmon时分配符号_start的),然后跳转到initmips(),开始在内存空间的执行。 执行initmips之前,CPU做的初始化只是初步的,其作用只是为CPU在内存中运行做一些必要的准备。主要的初始化工作:PCI设备的扫描、空间映射、资源分配都是initmips()函数所完成的。 下面我们跟踪initmips的执行来观察系统初始化的过程。 void initmips(unsigned int memsz) { /* * Set up memory address decoders to

× 游客快捷下载通道(下载后可以自由复制和排版)
单篇付费下载
限时特价:10 元/份 原价:20元
VIP包月下载
特价:29 元/月 原价:99元
低至 0.3 元/份 每月下载150
全站内容免费自由复制
VIP包月下载
特价:29 元/月 原价:99元
低至 0.3 元/份 每月下载150
全站内容免费自由复制
注:下载文档有可能“只有目录或者内容不全”等情况,请下载之前注意辨别,如果您已付费且无法下载或内容有问题,请联系我们协助你处理。
微信:fanwen365 QQ:370150219
Copyright © 云题海 All Rights Reserved. 苏ICP备16052595号-3 网站地图 客服QQ:370150219 邮箱:370150219@qq.com